core/state, triedb/database: refactor state reader (#30712)

Co-authored-by: Martin HS <martin@swende.se>
This commit is contained in:
rjl493456442 2024-11-09 08:08:06 +08:00 committed by Martin HS
parent 2b53182c92
commit ba882b6b4d
3 changed files with 50 additions and 26 deletions

View File

@ -186,9 +186,9 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
// is optional and may be partially useful if it's not fully
// generated.
if db.snap != nil {
sr, err := newStateReader(stateRoot, db.snap)
if err == nil {
readers = append(readers, sr) // snap reader is optional
snap := db.snap.Snapshot(stateRoot)
if snap != nil {
readers = append(readers, newStateReader(snap)) // snap reader is optional
}
}
// Set up the trie reader, which is expected to always be available

View File

@ -21,13 +21,13 @@ import (
"maps"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/ethereum/go-ethereum/triedb"
"github.com/ethereum/go-ethereum/triedb/database"
)
// Reader defines the interface for accessing accounts and storage slots
@ -52,23 +52,18 @@ type Reader interface {
Copy() Reader
}
// stateReader is a wrapper over the state snapshot and implements the Reader
// interface. It provides an efficient way to access flat state.
// stateReader wraps a database state reader.
type stateReader struct {
snap snapshot.Snapshot
buff crypto.KeccakState
reader database.StateReader
buff crypto.KeccakState
}
// newStateReader constructs a flat state reader with on the specified state root.
func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) {
snap := snaps.Snapshot(root)
if snap == nil {
return nil, errors.New("snapshot is not available")
}
// newStateReader constructs a state reader with on the given state root.
func newStateReader(reader database.StateReader) *stateReader {
return &stateReader{
snap: snap,
buff: crypto.NewKeccakState(),
}, nil
reader: reader,
buff: crypto.NewKeccakState(),
}
}
// Account implements Reader, retrieving the account specified by the address.
@ -78,18 +73,18 @@ func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error
//
// The returned account might be nil if it's not existent.
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes()))
account, err := r.reader.Account(crypto.HashData(r.buff, addr.Bytes()))
if err != nil {
return nil, err
}
if ret == nil {
if account == nil {
return nil, nil
}
acct := &types.StateAccount{
Nonce: ret.Nonce,
Balance: ret.Balance,
CodeHash: ret.CodeHash,
Root: common.BytesToHash(ret.Root),
Nonce: account.Nonce,
Balance: account.Balance,
CodeHash: account.CodeHash,
Root: common.BytesToHash(account.Root),
}
if len(acct.CodeHash) == 0 {
acct.CodeHash = types.EmptyCodeHash.Bytes()
@ -110,7 +105,7 @@ func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error)
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
addrHash := crypto.HashData(r.buff, addr.Bytes())
slotHash := crypto.HashData(r.buff, key.Bytes())
ret, err := r.snap.Storage(addrHash, slotHash)
ret, err := r.reader.Storage(addrHash, slotHash)
if err != nil {
return common.Hash{}, err
}
@ -131,8 +126,8 @@ func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash
// Copy implements Reader, returning a deep-copied snap reader.
func (r *stateReader) Copy() Reader {
return &stateReader{
snap: r.snap,
buff: crypto.NewKeccakState(),
reader: r.reader,
buff: crypto.NewKeccakState(),
}
}

View File

@ -18,6 +18,7 @@ package database
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// NodeReader wraps the Node method of a backing trie reader.
@ -37,3 +38,31 @@ type NodeDatabase interface {
// An error will be returned if the specified state is not available.
NodeReader(stateRoot common.Hash) (NodeReader, error)
}
// StateReader wraps the Account and Storage method of a backing state reader.
type StateReader interface {
// Account directly retrieves the account associated with a particular hash in
// the slim data format. An error will be returned if the read operation exits
// abnormally. Specifically, if the layer is already stale.
//
// Note:
// - the returned account object is safe to modify
// - no error will be returned if the requested account is not found in database
Account(hash common.Hash) (*types.SlimAccount, error)
// Storage directly retrieves the storage data associated with a particular hash,
// within a particular account. An error will be returned if the read operation
// exits abnormally.
//
// Note:
// - the returned storage data is not a copy, please don't modify it
// - no error will be returned if the requested slot is not found in database
Storage(accountHash, storageHash common.Hash) ([]byte, error)
}
// StateDatabase wraps the methods of a backing state store.
type StateDatabase interface {
// StateReader returns a state reader associated with the specific state.
// An error will be returned if the specified state is not available.
StateReader(stateRoot common.Hash) (StateReader, error)
}