forked from cerc-io/ipld-eth-server
optimize GetTransactionCount, GetBalance, and GetCode to use secondary indexes instead of operating through ethdb where we have to iterate down trie from root to leaf (multiple db lookups) to access account info
This commit is contained in:
+92
-1
@@ -19,6 +19,7 @@ package eth
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
@@ -38,6 +40,8 @@ import (
|
||||
ipfsethdb "github.com/vulcanize/pg-ipfs-ethdb"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
shared2 "github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
)
|
||||
|
||||
@@ -59,6 +63,12 @@ const (
|
||||
WHERE blocks.key = transaction_cids.mh_key
|
||||
AND transaction_cids.header_id = header_cids.id
|
||||
AND transaction_cids.tx_hash = $1`
|
||||
RetrieveCodeHashByLeafKeyAndBlockHash = `SELECT code_hash FROM eth.state_accounts, eth.state_cids, eth.header_cids
|
||||
WHERE state_accounts.state_id = state_cids.id
|
||||
AND state_cids.header_id = header_cids.id
|
||||
AND state_leaf_key = $1
|
||||
AND block_hash = $2`
|
||||
RetrieveCodeByMhKey = `SELECT data FROM public.blocks WHERE key = $1`
|
||||
)
|
||||
|
||||
type Backend struct {
|
||||
@@ -417,7 +427,7 @@ func (b *Backend) GetReceipts(ctx context.Context, hash common.Hash) (types.Rece
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rcts := make(types.Receipts, 0, len(receiptBytes))
|
||||
rcts := make(types.Receipts, len(receiptBytes))
|
||||
for i, rctBytes := range receiptBytes {
|
||||
rct := new(types.Receipt)
|
||||
if err := rlp.DecodeBytes(rctBytes, rct); err != nil {
|
||||
@@ -512,6 +522,87 @@ func (b *Backend) GetEVM(ctx context.Context, msg core.Message, state *state.Sta
|
||||
return vm.NewEVM(c, state, b.Config.ChainConfig, b.Config.VmConfig), nil
|
||||
}
|
||||
|
||||
// GetAccountByNumberOrHash returns the account object for the provided address at the block corresponding to the provided number or hash
|
||||
func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*state.Account, error) {
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
return b.GetAccountByNumber(ctx, address, uint64(blockNr.Int64()))
|
||||
}
|
||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||
return b.GetAccountByHash(ctx, address, hash)
|
||||
}
|
||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||
}
|
||||
|
||||
// GetAccountByNumber returns the account object for the provided address at the canonical block at the provided height
|
||||
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, number uint64) (*state.Account, error) {
|
||||
hash := b.GetCanonicalHash(number)
|
||||
if hash == (common.Hash{}) {
|
||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
||||
}
|
||||
return b.GetAccountByHash(ctx, address, hash)
|
||||
}
|
||||
|
||||
// GetAccountByHash returns the account object for the provided address at the block with the provided hash
|
||||
func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address, hash common.Hash) (*state.Account, error) {
|
||||
_, accountRlp, err := b.IPLDRetriever.RetrieveAccountByAddressAndBlockHash(address, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acct := new(state.Account)
|
||||
return acct, rlp.DecodeBytes(accountRlp, acct)
|
||||
}
|
||||
|
||||
// GetCodeByNumberOrHash returns the byte code for the contract deployed at the provided address at the block with the provided hash or block number
|
||||
func (b *Backend) GetCodeByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) ([]byte, error) {
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
return b.GetCodeByNumber(ctx, address, uint64(blockNr.Int64()))
|
||||
}
|
||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||
return b.GetCodeByHash(ctx, address, hash)
|
||||
}
|
||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||
}
|
||||
|
||||
// GetCodeByNumber returns the byte code for the contract deployed at the provided address at the canonical block with the provided block number
|
||||
func (b *Backend) GetCodeByNumber(ctx context.Context, address common.Address, number uint64) ([]byte, error) {
|
||||
hash := b.GetCanonicalHash(number)
|
||||
if hash == (common.Hash{}) {
|
||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
||||
}
|
||||
return b.GetCodeByHash(ctx, address, hash)
|
||||
}
|
||||
|
||||
// GetCodeByHash returns the byte code for the contract deployed at the provided address at the block with the provided hash
|
||||
func (b *Backend) GetCodeByHash(ctx context.Context, address common.Address, hash common.Hash) ([]byte, error) {
|
||||
codeHash := make([]byte, 0)
|
||||
leafKey := crypto.Keccak256Hash(address.Bytes())
|
||||
// Begin tx
|
||||
tx, err := b.DB.Beginx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
shared.Rollback(tx)
|
||||
panic(p)
|
||||
} else if err != nil {
|
||||
shared.Rollback(tx)
|
||||
} else {
|
||||
err = tx.Commit()
|
||||
}
|
||||
}()
|
||||
if err := tx.Get(&codeHash, RetrieveCodeHashByLeafKeyAndBlockHash, leafKey.Hex(), hash.Hex()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mhKey, err := shared2.MultihashKeyFromKeccak256(common.BytesToHash(codeHash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code := make([]byte, 0)
|
||||
err = tx.Get(&code, RetrieveCodeByMhKey, mhKey)
|
||||
return code, err
|
||||
}
|
||||
|
||||
// Engine satisfied the ChainContext interface
|
||||
func (b *Backend) Engine() consensus.Engine {
|
||||
// TODO: we need to support more than just ethash based engines
|
||||
|
||||
Reference in New Issue
Block a user