mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
core/state, eth/protocols/snap: rework code interface
This commit is contained in:
parent
f2d1a11aaf
commit
e049615dc6
4 changed files with 38 additions and 69 deletions
|
|
@ -344,10 +344,7 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
|
||||||
|
|
||||||
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
|
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
|
||||||
// hash either from ephemeral in-memory cache, or from persistent storage.
|
// hash either from ephemeral in-memory cache, or from persistent storage.
|
||||||
//
|
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte {
|
||||||
// If the code doesn't exist in the in-memory cache, check the storage with
|
|
||||||
// new code scheme.
|
|
||||||
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
|
||||||
// TODO(rjl493456442) The associated account address is also required
|
// TODO(rjl493456442) The associated account address is also required
|
||||||
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
||||||
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
|
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -174,11 +173,7 @@ func NewDatabaseForTesting() *CachingDB {
|
||||||
|
|
||||||
// Reader returns a state reader associated with the specified state root.
|
// Reader returns a state reader associated with the specified state root.
|
||||||
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
var readers []Reader
|
var readers []StateReader
|
||||||
|
|
||||||
// Construct the code reader with retained caches. These caches are
|
|
||||||
// thread safe.
|
|
||||||
cReader := newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache)
|
|
||||||
|
|
||||||
// Set up the state snapshot reader if available. This feature
|
// Set up the state snapshot reader if available. This feature
|
||||||
// is optional and may be partially useful if it's not fully
|
// is optional and may be partially useful if it's not fully
|
||||||
|
|
@ -186,7 +181,7 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
if db.snap != nil {
|
if db.snap != nil {
|
||||||
snap := db.snap.Snapshot(stateRoot)
|
snap := db.snap.Snapshot(stateRoot)
|
||||||
if snap != nil {
|
if snap != nil {
|
||||||
readers = append(readers, newSingleReader(cReader, newFlatReader(snap)))
|
readers = append(readers, newFlatReader(snap))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set up the trie reader, which is expected to always be available
|
// Set up the trie reader, which is expected to always be available
|
||||||
|
|
@ -195,9 +190,13 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
readers = append(readers, newSingleReader(cReader, tr))
|
readers = append(readers, tr)
|
||||||
|
|
||||||
return newMultiReader(readers...)
|
combined, err := newMultiStateReader(readers...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenTrie opens the main account trie at a specific root hash.
|
// OpenTrie opens the main account trie at a specific root hash.
|
||||||
|
|
@ -230,18 +229,17 @@ func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
|
||||||
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
||||||
// code can't be found in the cache, then check the existence with **new**
|
// code can't be found in the cache, then check the existence with **new**
|
||||||
// db scheme.
|
// db scheme.
|
||||||
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) []byte {
|
||||||
code, _ := db.codeCache.Get(codeHash)
|
code, _ := db.codeCache.Get(codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
return code, nil
|
return code
|
||||||
}
|
}
|
||||||
code = rawdb.ReadCodeWithPrefix(db.disk, codeHash)
|
code = rawdb.ReadCodeWithPrefix(db.disk, codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
db.codeCache.Add(codeHash, code)
|
db.codeCache.Add(codeHash, code)
|
||||||
db.codeSizeCache.Add(codeHash, len(code))
|
db.codeSizeCache.Add(codeHash, len(code))
|
||||||
return code, nil
|
|
||||||
}
|
}
|
||||||
return nil, errors.New("not found")
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrieDB retrieves any intermediate trie-node caching layer.
|
// TrieDB retrieves any intermediate trie-node caching layer.
|
||||||
|
|
|
||||||
|
|
@ -290,46 +290,32 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash,
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// singleReader is the wrapper of ContractCodeReader and StateReader interface.
|
// multiStateReader is the aggregation of a list of StateReader interface,
|
||||||
type singleReader struct {
|
// providing state access by leveraging all readers. The checking priority
|
||||||
ContractCodeReader
|
// is determined by the position in the reader list.
|
||||||
StateReader
|
type multiStateReader struct {
|
||||||
|
readers []StateReader // List of state readers, sorted by checking priority
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSingleReader constructs a reader with the supplied code reader and state reader.
|
// newMultiStateReader constructs a multiStateReader instance with the given
|
||||||
func newSingleReader(codeReader ContractCodeReader, stateReader StateReader) *singleReader {
|
// readers. The priority among readers is assumed to be sorted. Note, it must
|
||||||
return &singleReader{
|
// contain at least one reader for constructing a multiStateReader.
|
||||||
ContractCodeReader: codeReader,
|
func newMultiStateReader(readers ...StateReader) (*multiStateReader, error) {
|
||||||
StateReader: stateReader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiReader is the aggregation of a list of Reader interface, providing state
|
|
||||||
// access by leveraging all readers. The checking priority is determined by the
|
|
||||||
// position in the reader list.
|
|
||||||
type multiReader struct {
|
|
||||||
readers []Reader // List of readers, sorted by checking priority
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMultiReader constructs a multiReader instance with the given readers. The
|
|
||||||
// priority among readers is assumed to be sorted. Note, it must contain at least
|
|
||||||
// one reader for constructing a multiReader.
|
|
||||||
func newMultiReader(readers ...Reader) (*multiReader, error) {
|
|
||||||
if len(readers) == 0 {
|
if len(readers) == 0 {
|
||||||
return nil, errors.New("empty reader set")
|
return nil, errors.New("empty reader set")
|
||||||
}
|
}
|
||||||
return &multiReader{
|
return &multiStateReader{
|
||||||
readers: readers,
|
readers: readers,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implementing Reader interface, retrieving the account associated with
|
// Account implementing StateReader interface, retrieving the account associated
|
||||||
// a particular address.
|
// with a particular address.
|
||||||
//
|
//
|
||||||
// - Returns a nil account if it does not exist
|
// - Returns a nil account if it does not exist
|
||||||
// - Returns an error only if an unexpected issue occurs
|
// - Returns an error only if an unexpected issue occurs
|
||||||
// - The returned account is safe to modify after the call
|
// - The returned account is safe to modify after the call
|
||||||
func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) {
|
func (r *multiStateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
var errs []error
|
var errs []error
|
||||||
for _, reader := range r.readers {
|
for _, reader := range r.readers {
|
||||||
acct, err := reader.Account(addr)
|
acct, err := reader.Account(addr)
|
||||||
|
|
@ -341,13 +327,13 @@ func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error)
|
||||||
return nil, errors.Join(errs...)
|
return nil, errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage implementing Reader interface, retrieving the storage slot associated
|
// Storage implementing StateReader interface, retrieving the storage slot
|
||||||
// with a particular account address and slot key.
|
// associated with a particular account address and slot key.
|
||||||
//
|
//
|
||||||
// - Returns an empty slot if it does not exist
|
// - Returns an empty slot if it does not exist
|
||||||
// - Returns an error only if an unexpected issue occurs
|
// - Returns an error only if an unexpected issue occurs
|
||||||
// - The returned storage slot is safe to modify after the call
|
// - The returned storage slot is safe to modify after the call
|
||||||
func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
var errs []error
|
var errs []error
|
||||||
for _, reader := range r.readers {
|
for _, reader := range r.readers {
|
||||||
slot, err := reader.Storage(addr, slot)
|
slot, err := reader.Storage(addr, slot)
|
||||||
|
|
@ -359,28 +345,16 @@ func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Has
|
||||||
return common.Hash{}, errors.Join(errs...)
|
return common.Hash{}, errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCode implements Reader, retrieving a particular contract's code.
|
// reader is the wrapper of ContractCodeReader and StateReader interface.
|
||||||
func (r *multiReader) Code(addr common.Address, codeHash common.Hash) ([]byte, error) {
|
type reader struct {
|
||||||
var errs []error
|
ContractCodeReader
|
||||||
for _, reader := range r.readers {
|
StateReader
|
||||||
code, err := reader.Code(addr, codeHash)
|
|
||||||
if err == nil {
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
return nil, errors.Join(errs...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCodeSize implements Reader, retrieving a particular contracts code's size.
|
// newReader constructs a reader with the supplied code reader and state reader.
|
||||||
func (r *multiReader) CodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
func newReader(codeReader ContractCodeReader, stateReader StateReader) *reader {
|
||||||
var errs []error
|
return &reader{
|
||||||
for _, reader := range r.readers {
|
ContractCodeReader: codeReader,
|
||||||
size, err := reader.CodeSize(addr, codeHash)
|
StateReader: stateReader,
|
||||||
if err == nil {
|
|
||||||
return size, nil
|
|
||||||
}
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
}
|
||||||
return 0, errors.Join(errs...)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [
|
||||||
// Peers should not request the empty code, but if they do, at
|
// Peers should not request the empty code, but if they do, at
|
||||||
// least sent them back a correct response without db lookups
|
// least sent them back a correct response without db lookups
|
||||||
codes = append(codes, []byte{})
|
codes = append(codes, []byte{})
|
||||||
} else if blob, err := chain.ContractCodeWithPrefix(hash); err == nil {
|
} else if blob := chain.ContractCodeWithPrefix(hash); len(blob) > 0 {
|
||||||
codes = append(codes, blob)
|
codes = append(codes, blob)
|
||||||
bytes += uint64(len(blob))
|
bytes += uint64(len(blob))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue