diff --git a/backend/pkg/api/data_access/general.go b/backend/pkg/api/data_access/general.go new file mode 100644 index 000000000..eb4c73704 --- /dev/null +++ b/backend/pkg/api/data_access/general.go @@ -0,0 +1,47 @@ +package dataaccess + +import ( + "context" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/gobitfly/beaconchain/pkg/api/types" + "github.com/gobitfly/beaconchain/pkg/commons/db" +) + +func (d *DataAccessService) GetLabelsAndEnsForAddresses(ctx context.Context, addressMap map[string]*types.Address) error { + addresses := make([][]byte, 0, len(addressMap)) + ensMapping := make(map[string]string, len(addressMap)) + for address, data := range addressMap { + ensMapping[address] = "" + add, err := hexutil.Decode(address) + if err != nil { + return err + } + addresses = append(addresses, add) + if data == nil { + addressMap[address] = &types.Address{Hash: types.Hash(address)} + } + } + // determine ENS names + if err := db.GetEnsNamesForAddresses(ensMapping); err != nil { + return err + } + for address, ens := range ensMapping { + addressMap[address].Ens = ens + } + + // determine tags + tags := []struct { + Address []byte `db:"address"` + Tag string `db:"tag"` + }{} + err := d.alloyReader.SelectContext(ctx, &tags, `SELECT address, tag FROM address_tags WHERE address = ANY($1)`, addresses) + if err != nil { + return err + } + + for _, tag := range tags { + addressMap[hexutil.Encode(tag.Address)].Label = tag.Tag + } + return nil +} diff --git a/backend/pkg/api/data_access/vdb_blocks.go b/backend/pkg/api/data_access/vdb_blocks.go index 63c36a3f8..7af4193b8 100644 --- a/backend/pkg/api/data_access/vdb_blocks.go +++ b/backend/pkg/api/data_access/vdb_blocks.go @@ -348,7 +348,7 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das } data := make([]t.VDBBlocksTableRow, len(proposals)) - ensMapping := make(map[string]string) + addressMapping := make(map[string]*t.Address) contractStatusRequests := make([]db.ContractInteractionAtRequest, 0, len(proposals)) for i, proposal := range proposals { data[i].GroupId = proposal.Group @@ -386,7 +386,7 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das Hash: t.Hash(hexutil.Encode(proposal.FeeRecipient)), } data[i].RewardRecipient = &rewardRecp - ensMapping[hexutil.Encode(proposal.FeeRecipient)] = "" + addressMapping[hexutil.Encode(proposal.FeeRecipient)] = nil contractStatusRequests = append(contractStatusRequests, db.ContractInteractionAtRequest{ Address: string(proposal.FeeRecipient), Block: proposal.Block.Int64, @@ -403,10 +403,11 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das } // determine reward recipient ENS names startTime = time.Now() - if err := db.GetEnsNamesForAddresses(ensMapping); err != nil { + // determine ens/tags + if err := d.GetLabelsAndEnsForAddresses(ctx, addressMapping); err != nil { return nil, nil, err } - log.Debugf("=== getting ens names took %s", time.Since(startTime)) + log.Debugf("=== getting ens + labels names took %s", time.Since(startTime)) // determine contract statuses contractStatuses, err := d.bigtable.GetAddressContractInteractionsAt(contractStatusRequests) if err != nil { @@ -415,7 +416,7 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das var contractIdx int for _, resultRow := range data { if resultRow.RewardRecipient != nil { - resultRow.RewardRecipient.Ens = ensMapping[string(resultRow.RewardRecipient.Hash)] + resultRow.RewardRecipient = addressMapping[string(resultRow.RewardRecipient.Hash)] resultRow.RewardRecipient.IsContract = contractStatuses[contractIdx] == types.CONTRACT_CREATION || contractStatuses[contractIdx] == types.CONTRACT_PRESENT contractIdx += 1 } diff --git a/backend/pkg/api/data_access/vdb_deposits.go b/backend/pkg/api/data_access/vdb_deposits.go index afe38fa12..98305666e 100644 --- a/backend/pkg/api/data_access/vdb_deposits.go +++ b/backend/pkg/api/data_access/vdb_deposits.go @@ -123,7 +123,7 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context, } responseData := make([]t.VDBExecutionDepositsTableRow, len(data)) - ensMapping := make(map[string]string) + addressMapping := make(map[string]*t.Address) fromContractStatusRequests := make([]db.ContractInteractionAtRequest, len(data)) depositorContractStatusRequests := make([]db.ContractInteractionAtRequest, 0, len(data)) for i, row := range data { @@ -131,13 +131,12 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context, PublicKey: t.PubKey(pubkeys[i]), Block: uint64(row.BlockNumber), Timestamp: row.Timestamp.Unix(), - From: t.Address{Hash: t.Hash(hexutil.Encode(row.From))}, TxHash: t.Hash(hexutil.Encode(row.TxHash)), WithdrawalCredential: t.Hash(hexutil.Encode(row.WithdrawalCredentials)), Amount: utils.GWeiToWei(big.NewInt(row.Amount)), Valid: row.Valid, } - ensMapping[hexutil.Encode(row.From)] = "" + addressMapping[hexutil.Encode(row.From)] = nil fromContractStatusRequests[i] = db.ContractInteractionAtRequest{ Address: string(row.From), Block: row.BlockNumber, @@ -156,7 +155,7 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context, } if len(row.Depositor) > 0 { responseData[i].Depositor = t.Address{Hash: t.Hash(hexutil.Encode(row.Depositor))} - ensMapping[hexutil.Encode(row.Depositor)] = "" + addressMapping[hexutil.Encode(row.Depositor)] = nil depositorReq := fromContractStatusRequests[i] depositorReq.Address = string(row.Depositor) depositorContractStatusRequests = append(depositorContractStatusRequests, depositorReq) @@ -169,7 +168,7 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context, } // populate address data - if err := db.GetEnsNamesForAddresses(ensMapping); err != nil { + if err := d.GetLabelsAndEnsForAddresses(ctx, addressMapping); err != nil { return nil, nil, err } fromContractStatuses, err := d.bigtable.GetAddressContractInteractionsAt(fromContractStatusRequests) @@ -182,8 +181,7 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context, } var depositorIdx int for i := range data { - responseData[i].From.Ens = ensMapping[string(responseData[i].From.Hash)] - responseData[i].Depositor.Ens = ensMapping[string(responseData[i].Depositor.Hash)] + responseData[i].From = *addressMapping[string(responseData[i].From.Hash)] responseData[i].From.IsContract = fromContractStatuses[i] == types.CONTRACT_CREATION || fromContractStatuses[i] == types.CONTRACT_PRESENT responseData[i].Depositor.IsContract = responseData[i].From.IsContract if responseData[i].Depositor.Hash != responseData[i].From.Hash { diff --git a/backend/pkg/api/data_access/vdb_withdrawals.go b/backend/pkg/api/data_access/vdb_withdrawals.go index d68251f2f..4edbcf318 100644 --- a/backend/pkg/api/data_access/vdb_withdrawals.go +++ b/backend/pkg/api/data_access/vdb_withdrawals.go @@ -199,11 +199,11 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context } // Prepare the ENS map - addressEns := make(map[string]string) + addressMapping := make(map[string]*t.Address) contractStatusRequests := make([]db.ContractInteractionAtRequest, len(queryResult)) for i, withdrawal := range queryResult { address := hexutil.Encode(withdrawal.Address) - addressEns[address] = "" + addressMapping[address] = nil contractStatusRequests[i] = db.ContractInteractionAtRequest{ Address: string(withdrawal.Address), Block: int64(withdrawal.BlockNumber), @@ -213,7 +213,7 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context } // Get the ENS names for the addresses - if err := db.GetEnsNamesForAddresses(addressEns); err != nil { + if err := d.GetLabelsAndEnsForAddresses(ctx, addressMapping); err != nil { return nil, nil, err } @@ -228,17 +228,14 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context for i, withdrawal := range queryResult { address := hexutil.Encode(withdrawal.Address) result = append(result, t.VDBWithdrawalsTableRow{ - Epoch: withdrawal.BlockSlot / utils.Config.Chain.ClConfig.SlotsPerEpoch, - Slot: withdrawal.BlockSlot, - Index: withdrawal.ValidatorIndex, - GroupId: validatorGroupMap[withdrawal.ValidatorIndex], - Recipient: t.Address{ - Hash: t.Hash(address), - Ens: addressEns[address], - IsContract: contractStatuses[i] == types.CONTRACT_CREATION || contractStatuses[i] == types.CONTRACT_PRESENT, - }, - Amount: utils.GWeiToWei(big.NewInt(int64(withdrawal.Amount))), + Epoch: withdrawal.BlockSlot / utils.Config.Chain.ClConfig.SlotsPerEpoch, + Slot: withdrawal.BlockSlot, + Index: withdrawal.ValidatorIndex, + Recipient: *addressMapping[address], + GroupId: validatorGroupMap[withdrawal.ValidatorIndex], + Amount: utils.GWeiToWei(big.NewInt(int64(withdrawal.Amount))), }) + result[i].Recipient.IsContract = contractStatuses[i] == types.CONTRACT_CREATION || contractStatuses[i] == types.CONTRACT_PRESENT cursorData = append(cursorData, t.WithdrawalsCursor{ Slot: withdrawal.BlockSlot, WithdrawalIndex: withdrawal.WithdrawalIndex, @@ -273,7 +270,8 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context if nextData != nil { // Complete the next data nextData.GroupId = validatorGroupMap[nextData.Index] - nextData.Recipient.Ens = addressEns[string(nextData.Recipient.Hash)] + // TODO integrate label/ens data for "next" row + // nextData.Recipient.Ens = addressEns[string(nextData.Recipient.Hash)] } else { // If there is no next data, add a missing estimate row nextData = &t.VDBWithdrawalsTableRow{ diff --git a/backend/pkg/commons/db/migrations/postgres/20240822134034_add_address_tags.sql b/backend/pkg/commons/db/migrations/postgres/20240822134034_add_address_tags.sql new file mode 100644 index 000000000..852b708b4 --- /dev/null +++ b/backend/pkg/commons/db/migrations/postgres/20240822134034_add_address_tags.sql @@ -0,0 +1,15 @@ +-- +goose Up +-- +goose StatementBegin +SELECT('up SQL query - create address_tags table'); +CREATE TABLE address_tags ( + address bytea NOT NULL UNIQUE, + tag CHARACTER VARYING(100) NOT NULL, + PRIMARY KEY (address, tag) +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT('down SQL query - drop address_tags table'); +DROP TABLE execution_payloads; +-- +goose StatementEnd