fix: need to pass block_hash to StateObject and Database

This commit is contained in:
i-norden 2023-02-28 12:07:03 -06:00
parent ede0af3c26
commit 6b25cde9dd
4 changed files with 33 additions and 28 deletions

View File

@ -5,14 +5,10 @@ import (
"errors"
"math/big"
"github.com/ethereum/go-ethereum/crypto"
"github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
"github.com/ethereum/go-ethereum/trie"
lru "github.com/hashicorp/golang-lru"
"github.com/jackc/pgx/pgxpool"
)
@ -35,29 +31,29 @@ var (
type Database interface {
ContractCode(addrHash common.Hash, codeHash common.Hash) ([]byte, error)
ContractCodeSize(addrHash common.Hash, codeHash common.Hash) (int, error)
StateAccount(address common.Address) (*types.StateAccount, error)
StorageSlot(addressHash, slotHash common.Hash) ([]byte, error)
StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error)
StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error)
}
var _ Database = &stateDatabase{}
type stateDatabase struct {
pgdb *pgxpool.Pool
trieDB *trie.Database
codeSizeCache *lru.Cache
codeCache *fastcache.Cache
}
func NewStateDatabase(pgdb *pgxpool.Pool, ethdb ethdb.Database, config *trie.Config) (*stateDatabase, error) {
// NewStateDatabase returns a new Database implementation using the provided postgres connection pool
func NewStateDatabase(pgdb *pgxpool.Pool) (*stateDatabase, error) {
csc, _ := lru.New(codeSizeCacheSize)
return &stateDatabase{
pgdb: pgdb,
trieDB: trie.NewDatabaseWithConfig(ethdb, config),
codeSizeCache: csc,
codeCache: fastcache.New(codeCacheSize),
}, nil
}
// ContractCode satisfies Database, it returns the contract code for a give codehash
func (sd *stateDatabase) ContractCode(_, codeHash common.Hash) ([]byte, error) {
if code := sd.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
return code, nil
@ -75,6 +71,7 @@ func (sd *stateDatabase) ContractCode(_, codeHash common.Hash) ([]byte, error) {
return nil, errNotFound
}
// ContractCodeSize satisfies Database, it returns the length of the code for a provided codehash
func (sd *stateDatabase) ContractCodeSize(_, codeHash common.Hash) (int, error) {
if cached, ok := sd.codeSizeCache.Get(codeHash); ok {
return cached.(int), nil
@ -83,10 +80,11 @@ func (sd *stateDatabase) ContractCodeSize(_, codeHash common.Hash) (int, error)
return len(code), err
}
func (sd *stateDatabase) StateAccount(address common.Address) (*types.StateAccount, error) {
// StateAccount satisfies Database, it returns the types.StateAccount for a provided address and block hash
func (sd *stateDatabase) StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error) {
res := StateAccountResult{}
key := crypto.Keccak256Hash(address.Bytes())
if err := sd.pgdb.QueryRow(context.Background(), GetStateAccount, key.Hex()).Scan(&res); err != nil {
err := sd.pgdb.QueryRow(context.Background(), GetStateAccount, addressHash.Hex(), blockHash.Hex()).Scan(&res)
if err != nil {
return nil, errNotFound
}
if res.Removed {
@ -103,9 +101,11 @@ func (sd *stateDatabase) StateAccount(address common.Address) (*types.StateAccou
}, nil
}
func (sd *stateDatabase) StorageSlot(addressHash, slotHash common.Hash) ([]byte, error) {
// StorageValue satisfies Database, it returns the storage value for the provided address, slot, and block hash
func (sd *stateDatabase) StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error) {
res := StorageSlotResult{}
if err := sd.pgdb.QueryRow(context.Background(), GetStorageSlot, addressHash.Hex(), slotHash.Hex()).Scan(&res); err != nil {
err := sd.pgdb.QueryRow(context.Background(), GetStorageSlot, addressHash.Hex(), slotHash.Hex(), blockHash.Hex()).Scan(&res)
if err != nil {
return nil, errNotFound
}
if res.Removed {

3
sql.go
View File

@ -21,6 +21,9 @@ const (
)
WHERE state_leaf_key = $1
AND storage_leaf_key = $2
AND header_cids.block_number <= (SELECT block_number
FROM eth.header_cids
WHERE block_hash = $3)
AND header_cids.block_hash = (SELECT canonical_header_hash(header_cids.block_number))
ORDER BY header_cids.block_number DESC
LIMIT 1`

View File

@ -54,10 +54,11 @@ func (s Storage) Copy() Storage {
// First you need to obtain a state object.
// Account values can be accessed and modified through the object.
type stateObject struct {
address common.Address
addrHash common.Hash // hash of ethereum address of the account
data types.StateAccount
db *StateDB
address common.Address
addrHash common.Hash // hash of ethereum address of the account
blockHash common.Hash // hash of the block this state object exists at or is being applied on top of
data types.StateAccount
db *StateDB
// DB error.
// State objects are used by the consensus core and VM which are
@ -88,7 +89,7 @@ func (s *stateObject) empty() bool {
}
// newObject creates a state object.
func newObject(db *StateDB, address common.Address, data types.StateAccount) *stateObject {
func newObject(db *StateDB, address common.Address, data types.StateAccount, blockHash common.Hash) *stateObject {
if data.Balance == nil {
data.Balance = new(big.Int)
}
@ -102,6 +103,7 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
blockHash: blockHash,
data: data,
originStorage: make(Storage),
pendingStorage: make(Storage),
@ -161,7 +163,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
}
// If no live objects are available, load from database
start := time.Now()
enc, err := db.StorageSlot(s.addrHash, key)
enc, err := db.StorageValue(s.addrHash, key, s.blockHash)
if metrics.EnabledExpensive {
s.db.StorageReads += time.Since(start)
}

View File

@ -50,9 +50,8 @@ type StateDB struct {
db Database
hasher crypto.KeccakState
// originalRoot is the pre-state root, before any changes were made.
// It will be updated when the Commit is called.
originalRoot common.Hash
// originBlockHash is the blockhash for the state we are working on top of
originBlockHash common.Hash
snaps *snapshot.Tree
snapDestructs map[common.Hash]struct{}
@ -110,10 +109,10 @@ type StateDB struct {
}
// New creates a new state from a given trie.
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
func New(blockHash common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
sdb := &StateDB{
db: db,
originalRoot: root,
originBlockHash: blockHash,
snaps: snaps,
stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
@ -348,7 +347,8 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
// TODO: REPLACE TRIE ACCESS HERE
// can add a fallback option to use ipfsethdb to do the trie access if direct access fails
start := time.Now()
data, err := s.db.StateAccount(addr)
addrHash := crypto.Keccak256Hash(addr.Bytes())
data, err := s.db.StateAccount(addrHash, s.originBlockHash)
if metrics.EnabledExpensive {
s.AccountReads += time.Since(start)
}
@ -360,7 +360,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
return nil
}
// Insert into the live set
obj := newObject(s, addr, *data)
obj := newObject(s, addr, *data, s.originBlockHash)
s.setStateObject(obj)
return obj
}
@ -382,7 +382,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
// the given address, it is overwritten and returned as the second return value.
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
newobj = newObject(s, addr, types.StateAccount{})
newobj = newObject(s, addr, types.StateAccount{}, s.originBlockHash)
if prev == nil {
s.journal.append(createObjectChange{account: &addr})
} else {