fix: need to pass block_hash to StateObject and Database
This commit is contained in:
parent
ede0af3c26
commit
6b25cde9dd
28
database.go
28
database.go
@ -5,14 +5,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/statediff/indexer/ipld"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/jackc/pgx/pgxpool"
|
"github.com/jackc/pgx/pgxpool"
|
||||||
)
|
)
|
||||||
@ -35,29 +31,29 @@ var (
|
|||||||
type Database interface {
|
type Database interface {
|
||||||
ContractCode(addrHash common.Hash, codeHash common.Hash) ([]byte, error)
|
ContractCode(addrHash common.Hash, codeHash common.Hash) ([]byte, error)
|
||||||
ContractCodeSize(addrHash common.Hash, codeHash common.Hash) (int, error)
|
ContractCodeSize(addrHash common.Hash, codeHash common.Hash) (int, error)
|
||||||
StateAccount(address common.Address) (*types.StateAccount, error)
|
StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error)
|
||||||
StorageSlot(addressHash, slotHash common.Hash) ([]byte, error)
|
StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Database = &stateDatabase{}
|
var _ Database = &stateDatabase{}
|
||||||
|
|
||||||
type stateDatabase struct {
|
type stateDatabase struct {
|
||||||
pgdb *pgxpool.Pool
|
pgdb *pgxpool.Pool
|
||||||
trieDB *trie.Database
|
|
||||||
codeSizeCache *lru.Cache
|
codeSizeCache *lru.Cache
|
||||||
codeCache *fastcache.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)
|
csc, _ := lru.New(codeSizeCacheSize)
|
||||||
return &stateDatabase{
|
return &stateDatabase{
|
||||||
pgdb: pgdb,
|
pgdb: pgdb,
|
||||||
trieDB: trie.NewDatabaseWithConfig(ethdb, config),
|
|
||||||
codeSizeCache: csc,
|
codeSizeCache: csc,
|
||||||
codeCache: fastcache.New(codeCacheSize),
|
codeCache: fastcache.New(codeCacheSize),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContractCode satisfies Database, it returns the contract code for a give codehash
|
||||||
func (sd *stateDatabase) ContractCode(_, codeHash common.Hash) ([]byte, error) {
|
func (sd *stateDatabase) ContractCode(_, codeHash common.Hash) ([]byte, error) {
|
||||||
if code := sd.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
|
if code := sd.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
|
||||||
return code, nil
|
return code, nil
|
||||||
@ -75,6 +71,7 @@ func (sd *stateDatabase) ContractCode(_, codeHash common.Hash) ([]byte, error) {
|
|||||||
return nil, errNotFound
|
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) {
|
func (sd *stateDatabase) ContractCodeSize(_, codeHash common.Hash) (int, error) {
|
||||||
if cached, ok := sd.codeSizeCache.Get(codeHash); ok {
|
if cached, ok := sd.codeSizeCache.Get(codeHash); ok {
|
||||||
return cached.(int), nil
|
return cached.(int), nil
|
||||||
@ -83,10 +80,11 @@ func (sd *stateDatabase) ContractCodeSize(_, codeHash common.Hash) (int, error)
|
|||||||
return len(code), err
|
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{}
|
res := StateAccountResult{}
|
||||||
key := crypto.Keccak256Hash(address.Bytes())
|
err := sd.pgdb.QueryRow(context.Background(), GetStateAccount, addressHash.Hex(), blockHash.Hex()).Scan(&res)
|
||||||
if err := sd.pgdb.QueryRow(context.Background(), GetStateAccount, key.Hex()).Scan(&res); err != nil {
|
if err != nil {
|
||||||
return nil, errNotFound
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
if res.Removed {
|
if res.Removed {
|
||||||
@ -103,9 +101,11 @@ func (sd *stateDatabase) StateAccount(address common.Address) (*types.StateAccou
|
|||||||
}, nil
|
}, 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{}
|
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
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
if res.Removed {
|
if res.Removed {
|
||||||
|
3
sql.go
3
sql.go
@ -21,6 +21,9 @@ const (
|
|||||||
)
|
)
|
||||||
WHERE state_leaf_key = $1
|
WHERE state_leaf_key = $1
|
||||||
AND storage_leaf_key = $2
|
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))
|
AND header_cids.block_hash = (SELECT canonical_header_hash(header_cids.block_number))
|
||||||
ORDER BY header_cids.block_number DESC
|
ORDER BY header_cids.block_number DESC
|
||||||
LIMIT 1`
|
LIMIT 1`
|
||||||
|
@ -56,6 +56,7 @@ func (s Storage) Copy() Storage {
|
|||||||
type stateObject struct {
|
type stateObject struct {
|
||||||
address common.Address
|
address common.Address
|
||||||
addrHash common.Hash // hash of ethereum address of the account
|
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
|
data types.StateAccount
|
||||||
db *StateDB
|
db *StateDB
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ func (s *stateObject) empty() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newObject creates a state object.
|
// 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 {
|
if data.Balance == nil {
|
||||||
data.Balance = new(big.Int)
|
data.Balance = new(big.Int)
|
||||||
}
|
}
|
||||||
@ -102,6 +103,7 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st
|
|||||||
db: db,
|
db: db,
|
||||||
address: address,
|
address: address,
|
||||||
addrHash: crypto.Keccak256Hash(address[:]),
|
addrHash: crypto.Keccak256Hash(address[:]),
|
||||||
|
blockHash: blockHash,
|
||||||
data: data,
|
data: data,
|
||||||
originStorage: make(Storage),
|
originStorage: make(Storage),
|
||||||
pendingStorage: 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
|
// If no live objects are available, load from database
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
enc, err := db.StorageSlot(s.addrHash, key)
|
enc, err := db.StorageValue(s.addrHash, key, s.blockHash)
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
s.db.StorageReads += time.Since(start)
|
s.db.StorageReads += time.Since(start)
|
||||||
}
|
}
|
||||||
|
16
statedb.go
16
statedb.go
@ -50,9 +50,8 @@ type StateDB struct {
|
|||||||
db Database
|
db Database
|
||||||
hasher crypto.KeccakState
|
hasher crypto.KeccakState
|
||||||
|
|
||||||
// originalRoot is the pre-state root, before any changes were made.
|
// originBlockHash is the blockhash for the state we are working on top of
|
||||||
// It will be updated when the Commit is called.
|
originBlockHash common.Hash
|
||||||
originalRoot common.Hash
|
|
||||||
|
|
||||||
snaps *snapshot.Tree
|
snaps *snapshot.Tree
|
||||||
snapDestructs map[common.Hash]struct{}
|
snapDestructs map[common.Hash]struct{}
|
||||||
@ -110,10 +109,10 @@ type StateDB struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new state from a given trie.
|
// 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{
|
sdb := &StateDB{
|
||||||
db: db,
|
db: db,
|
||||||
originalRoot: root,
|
originBlockHash: blockHash,
|
||||||
snaps: snaps,
|
snaps: snaps,
|
||||||
stateObjects: make(map[common.Address]*stateObject),
|
stateObjects: make(map[common.Address]*stateObject),
|
||||||
stateObjectsPending: make(map[common.Address]struct{}),
|
stateObjectsPending: make(map[common.Address]struct{}),
|
||||||
@ -348,7 +347,8 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
// TODO: REPLACE TRIE ACCESS HERE
|
// TODO: REPLACE TRIE ACCESS HERE
|
||||||
// can add a fallback option to use ipfsethdb to do the trie access if direct access fails
|
// can add a fallback option to use ipfsethdb to do the trie access if direct access fails
|
||||||
start := time.Now()
|
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 {
|
if metrics.EnabledExpensive {
|
||||||
s.AccountReads += time.Since(start)
|
s.AccountReads += time.Since(start)
|
||||||
}
|
}
|
||||||
@ -360,7 +360,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Insert into the live set
|
// Insert into the live set
|
||||||
obj := newObject(s, addr, *data)
|
obj := newObject(s, addr, *data, s.originBlockHash)
|
||||||
s.setStateObject(obj)
|
s.setStateObject(obj)
|
||||||
return 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.
|
// the given address, it is overwritten and returned as the second return value.
|
||||||
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
||||||
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
|
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 {
|
if prev == nil {
|
||||||
s.journal.append(createObjectChange{account: &addr})
|
s.journal.append(createObjectChange{account: &addr})
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user