diff --git a/core/state/database.go b/core/state/database.go index 0d8acec35a..3f92aebdf4 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -193,7 +193,7 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { } // Set up the trie reader, which is expected to always be available // as the gatekeeper unless the state is corrupted. - tr, err := newTrieReader(stateRoot, db.triedb, db.pointCache) + tr, err := newTrieReader(stateRoot, db.triedb, db, db.pointCache) if err != nil { return nil, err } diff --git a/core/state/reader.go b/core/state/reader.go index 85842adde8..9ec6ca19ac 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -48,6 +48,19 @@ type Reader interface { // - The returned storage slot is safe to modify after the call Storage(addr common.Address, slot common.Hash) (common.Hash, error) + // ContractCode returns the code associated with a particular account. + // + // - Returns an empty code if it does not exist + // - It can return an error to indicate code doesn't exist + // - The returned code is safe to modify after the call + ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) + + // ContractCodeSize returns the size of the code associated with a particular account. + // + // - Returns 0 if the code does not exist + // - It can return an error to indicate code doesn't exist + ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) + // Copy returns a deep-copied state reader. Copy() Reader } @@ -123,6 +136,16 @@ func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash return value, nil } +// ContractCode implements Reader, retrieving the code associated with a particular account. +func (r *stateReader) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) { + return nil, nil +} + +// ContractCodeSize implements Reader, returning the size of the code associated with a particular account. +func (r *stateReader) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + return 0, nil +} + // Copy implements Reader, returning a deep-copied snap reader. func (r *stateReader) Copy() Reader { return &stateReader{ @@ -134,17 +157,18 @@ func (r *stateReader) Copy() Reader { // trieReader implements the Reader interface, providing functions to access // state from the referenced trie. type trieReader struct { - root common.Hash // State root which uniquely represent a state - db *triedb.Database // Database for loading trie - buff crypto.KeccakState // Buffer for keccak256 hashing - mainTrie Trie // Main trie, resolved in constructor - subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved - subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved + root common.Hash // State root which uniquely represent a state + db *triedb.Database // Database for loading trie + contractDB Database // Database for loading code + buff crypto.KeccakState // Buffer for keccak256 hashing + mainTrie Trie // Main trie, resolved in constructor + subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved + subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved } // trieReader constructs a trie reader of the specific state. An error will be // returned if the associated trie specified by root is not existent. -func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) { +func newTrieReader(root common.Hash, db *triedb.Database, contractDB Database, cache *utils.PointCache) (*trieReader, error) { var ( tr Trie err error @@ -158,12 +182,13 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach return nil, err } return &trieReader{ - root: root, - db: db, - buff: crypto.NewKeccakState(), - mainTrie: tr, - subRoots: make(map[common.Address]common.Hash), - subTries: make(map[common.Address]Trie), + root: root, + db: db, + contractDB: contractDB, + buff: crypto.NewKeccakState(), + mainTrie: tr, + subRoots: make(map[common.Address]common.Hash), + subTries: make(map[common.Address]Trie), }, nil } @@ -227,6 +252,16 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, return value, nil } +// ContractCode implements Reader, retrieving the code associated with a particular account. +func (r *trieReader) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) { + return r.contractDB.ContractCode(addr, codeHash) +} + +// ContractCodeSize implements Reader, returning the size of the code associated with a particular account. +func (r *trieReader) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + return r.contractDB.ContractCodeSize(addr, codeHash) +} + // Copy implements Reader, returning a deep-copied trie reader. func (r *trieReader) Copy() Reader { tries := make(map[common.Address]Trie) @@ -298,6 +333,30 @@ func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Has return common.Hash{}, errors.Join(errs...) } +// ContractCode implements Reader, retrieving the code associated with a particular account. +func (r *multiReader) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) { + var errs []error + for _, reader := range r.readers { + code, err := reader.ContractCode(addr, codeHash) + if err == nil { + return code, nil + } + } + return nil, errors.Join(errs...) +} + +// ContractCodeSize implements Reader, returning the size of the code associated with a particular account. +func (r *multiReader) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + var errs []error + for _, reader := range r.readers { + size, err := reader.ContractCodeSize(addr, codeHash) + if err == nil { + return size, nil + } + } + return 0, errors.Join(errs...) +} + // Copy implementing Reader interface, returning a deep-copied state reader. func (r *multiReader) Copy() Reader { var readers []Reader diff --git a/core/state/state_object.go b/core/state/state_object.go index b659bf7ff2..172d6c5f5e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -510,7 +510,7 @@ func (s *stateObject) Code() []byte { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } - code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash())) + code, err := s.db.reader.ContractCode(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } @@ -528,7 +528,7 @@ func (s *stateObject) CodeSize() int { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } - size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) + size, err := s.db.reader.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) }