From 74ef47462f2a9daea04e81687c4d0b4598826ca2 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Sat, 9 Nov 2024 08:08:06 +0800 Subject: [PATCH] core/state, triedb/database: refactor state reader (#30712) Co-authored-by: Martin HS --- core/state/database.go | 6 +++--- core/state/reader.go | 41 ++++++++++++++++--------------------- triedb/database/database.go | 29 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index de61dee036..0d8acec35a 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -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 diff --git a/core/state/reader.go b/core/state/reader.go index 6bddefc2a7..85842adde8 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -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(), } } diff --git a/triedb/database/database.go b/triedb/database/database.go index cde8390756..cd7ec1d931 100644 --- a/triedb/database/database.go +++ b/triedb/database/database.go @@ -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) +}