Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(BEDS-155) Data Access: adjusted address struct #733

Merged
merged 10 commits into from
Sep 18, 2024
47 changes: 47 additions & 0 deletions backend/pkg/api/data_access/general.go
Original file line number Diff line number Diff line change
@@ -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
}
27 changes: 22 additions & 5 deletions backend/pkg/api/data_access/vdb_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/gobitfly/beaconchain/pkg/commons/cache"
"github.com/gobitfly/beaconchain/pkg/commons/db"
"github.com/gobitfly/beaconchain/pkg/commons/log"
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"github.com/shopspring/decimal"
)
Expand Down Expand Up @@ -345,7 +346,8 @@ 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
if dashboardId.AggregateGroups {
Expand Down Expand Up @@ -382,7 +384,13 @@ 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: fmt.Sprintf("%x", proposal.FeeRecipient),
Block: proposal.Block.Int64,
TxIdx: -1,
TraceIdx: -1,
})
reward.El = proposal.ElReward.Decimal.Mul(decimal.NewFromInt(1e18))
}
if proposal.ClReward.Valid {
Expand All @@ -393,13 +401,22 @@ 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 {
return nil, nil, err
}
var contractIdx int
for i := range data {
if data[i].RewardRecipient != nil {
data[i].RewardRecipient.Ens = ensMapping[string(data[i].RewardRecipient.Hash)]
data[i].RewardRecipient = addressMapping[string(data[i].RewardRecipient.Hash)]
data[i].RewardRecipient.IsContract = contractStatuses[contractIdx] == types.CONTRACT_CREATION || contractStatuses[contractIdx] == types.CONTRACT_PRESENT
contractIdx += 1
}
}
if !moreDataFlag && !currentCursor.IsValid() {
Expand Down
41 changes: 40 additions & 1 deletion backend/pkg/api/data_access/vdb_deposits.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/gobitfly/beaconchain/pkg/api/enums"
t "github.com/gobitfly/beaconchain/pkg/api/types"
"github.com/gobitfly/beaconchain/pkg/commons/db"
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"github.com/lib/pq"
"github.com/shopspring/decimal"
Expand Down Expand Up @@ -121,17 +122,27 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context,
}

responseData := make([]t.VDBExecutionDepositsTableRow, len(data))
addressMapping := make(map[string]*t.Address)
fromContractStatusRequests := make([]db.ContractInteractionAtRequest, len(data))
depositorContractStatusRequests := make([]db.ContractInteractionAtRequest, 0, len(data))
for i, row := range data {
responseData[i] = t.VDBExecutionDepositsTableRow{
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,
}
addressMapping[hexutil.Encode(row.From)] = nil
fromContractStatusRequests[i] = db.ContractInteractionAtRequest{
Address: fmt.Sprintf("%x", row.From),
Block: row.BlockNumber,
// TODO not entirely correct, would need to determine tx index and itx index of tx. But good enough for now
TxIdx: -1,
TraceIdx: -1,
}
if row.GroupId.Valid {
if dashboardId.AggregateGroups {
responseData[i].GroupId = t.DefaultGroupId
Expand All @@ -143,13 +154,41 @@ func (d *DataAccessService) GetValidatorDashboardElDeposits(ctx context.Context,
}
if len(row.Depositor) > 0 {
responseData[i].Depositor = t.Address{Hash: t.Hash(hexutil.Encode(row.Depositor))}
addressMapping[hexutil.Encode(row.Depositor)] = nil
depositorReq := fromContractStatusRequests[i]
depositorReq.Address = fmt.Sprintf("%x", row.Depositor)
depositorContractStatusRequests = append(depositorContractStatusRequests, depositorReq)
} else {
responseData[i].Depositor = responseData[i].From
}
if v, ok := mapping.ValidatorIndices[pubkeys[i]]; ok {
responseData[i].Index = &v
}
}

// populate address data
if err := d.GetLabelsAndEnsForAddresses(ctx, addressMapping); err != nil {
return nil, nil, err
}
fromContractStatuses, err := d.bigtable.GetAddressContractInteractionsAt(fromContractStatusRequests)
if err != nil {
return nil, nil, err
}
depositorContractStatuses, err := d.bigtable.GetAddressContractInteractionsAt(depositorContractStatusRequests)
if err != nil {
return nil, nil, err
}
var depositorIdx int
for i := range data {
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 {
responseData[i].Depositor.IsContract = depositorContractStatuses[depositorIdx] == types.CONTRACT_CREATION || depositorContractStatuses[depositorIdx] == types.CONTRACT_PRESENT
depositorIdx += 1
}
}

var paging t.Paging

moreDataFlag := len(responseData) > int(limit)
Expand Down
63 changes: 47 additions & 16 deletions backend/pkg/api/data_access/vdb_withdrawals.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
t "github.com/gobitfly/beaconchain/pkg/api/types"
"github.com/gobitfly/beaconchain/pkg/commons/cache"
"github.com/gobitfly/beaconchain/pkg/commons/db"
"github.com/gobitfly/beaconchain/pkg/commons/types"
"github.com/gobitfly/beaconchain/pkg/commons/utils"
"github.com/lib/pq"
"github.com/pkg/errors"
Expand Down Expand Up @@ -111,6 +112,7 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context
// Get the withdrawals for the validators
queryResult := []struct {
BlockSlot uint64 `db:"block_slot"`
BlockNumber uint64 `db:"exec_block_number"`
WithdrawalIndex uint64 `db:"withdrawalindex"`
ValidatorIndex uint64 `db:"validatorindex"`
Address []byte `db:"address"`
Expand All @@ -121,6 +123,7 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context
withdrawalsQuery := `
SELECT
w.block_slot,
b.exec_block_number,
w.withdrawalindex,
w.validatorindex,
w.address,
Expand Down Expand Up @@ -196,32 +199,43 @@ func (d *DataAccessService) GetValidatorDashboardWithdrawals(ctx context.Context
}

// Prepare the ENS map
addressEns := make(map[string]string)
for _, withdrawal := range queryResult {
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: fmt.Sprintf("%x", withdrawal.Address),
Block: int64(withdrawal.BlockNumber),
TxIdx: -1,
TraceIdx: -1,
}
}

// 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
}

// Get the contract status for the addresses
contractStatuses, err := d.bigtable.GetAddressContractInteractionsAt(contractStatusRequests)
if err != nil {
return nil, nil, err
}

// Create the result
cursorData := make([]t.WithdrawalsCursor, 0)
for _, withdrawal := range queryResult {
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],
},
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,
Expand Down Expand Up @@ -256,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{
Expand Down Expand Up @@ -393,12 +408,28 @@ func (d *DataAccessService) getNextWithdrawalRow(queryValidators []t.VDBValidato
withdrawalAmount = 0
}

ens_name, err := db.GetEnsNameForAddress(*address, utils.SlotToTime(nextWithdrawalSlot))
if err != sql.ErrNoRows {
return nil, err
}

contractStatusReq := []db.ContractInteractionAtRequest{{
Address: fmt.Sprintf("%x", address),
Block: -1,
}}
contractStatus, err := d.bigtable.GetAddressContractInteractionsAt(contractStatusReq)
if err != nil {
return nil, err
}

nextData := &t.VDBWithdrawalsTableRow{
Epoch: nextWithdrawalSlot / utils.Config.Chain.ClConfig.SlotsPerEpoch,
Slot: nextWithdrawalSlot,
Index: *nextValidator,
Recipient: t.Address{
Hash: t.Hash(address.String()),
Hash: t.Hash(address.String()),
Ens: ens_name,
IsContract: contractStatus[0] == types.CONTRACT_CREATION || contractStatus[0] == types.CONTRACT_PRESENT,
},
Amount: utils.GWeiToWei(big.NewInt(int64(withdrawalAmount))),
}
Expand Down
6 changes: 4 additions & 2 deletions backend/pkg/api/types/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ type PubKey string
type Hash string // blocks, txs etc.

type Address struct {
Hash Hash `json:"hash"`
Ens string `json:"ens,omitempty"`
Hash Hash `json:"hash"`
IsContract bool `json:"is_contract"`
Ens string `json:"ens,omitempty"`
Label string `json:"label,omitempty"`
}

type LuckItem struct {
Expand Down
Loading
Loading