github.com/ethereum/go-ethereum@v1.16.1/core/state/reader.go (about)

     1  // Copyright 2024 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package state
    18  
    19  import (
    20  	"errors"
    21  	"sync"
    22  	"sync/atomic"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/common/lru"
    26  	"github.com/ethereum/go-ethereum/core/rawdb"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/crypto"
    29  	"github.com/ethereum/go-ethereum/ethdb"
    30  	"github.com/ethereum/go-ethereum/rlp"
    31  	"github.com/ethereum/go-ethereum/trie"
    32  	"github.com/ethereum/go-ethereum/trie/utils"
    33  	"github.com/ethereum/go-ethereum/triedb"
    34  	"github.com/ethereum/go-ethereum/triedb/database"
    35  )
    36  
    37  // ContractCodeReader defines the interface for accessing contract code.
    38  type ContractCodeReader interface {
    39  	// Code retrieves a particular contract's code.
    40  	//
    41  	// - Returns nil code along with nil error if the requested contract code
    42  	//   doesn't exist
    43  	// - Returns an error only if an unexpected issue occurs
    44  	Code(addr common.Address, codeHash common.Hash) ([]byte, error)
    45  
    46  	// CodeSize retrieves a particular contracts code's size.
    47  	//
    48  	// - Returns zero code size along with nil error if the requested contract code
    49  	//   doesn't exist
    50  	// - Returns an error only if an unexpected issue occurs
    51  	CodeSize(addr common.Address, codeHash common.Hash) (int, error)
    52  }
    53  
    54  // StateReader defines the interface for accessing accounts and storage slots
    55  // associated with a specific state.
    56  //
    57  // StateReader is assumed to be thread-safe and implementation must take care
    58  // of the concurrency issue by themselves.
    59  type StateReader interface {
    60  	// Account retrieves the account associated with a particular address.
    61  	//
    62  	// - Returns a nil account if it does not exist
    63  	// - Returns an error only if an unexpected issue occurs
    64  	// - The returned account is safe to modify after the call
    65  	Account(addr common.Address) (*types.StateAccount, error)
    66  
    67  	// Storage retrieves the storage slot associated with a particular account
    68  	// address and slot key.
    69  	//
    70  	// - Returns an empty slot if it does not exist
    71  	// - Returns an error only if an unexpected issue occurs
    72  	// - The returned storage slot is safe to modify after the call
    73  	Storage(addr common.Address, slot common.Hash) (common.Hash, error)
    74  }
    75  
    76  // Reader defines the interface for accessing accounts, storage slots and contract
    77  // code associated with a specific state.
    78  //
    79  // Reader is assumed to be thread-safe and implementation must take care of the
    80  // concurrency issue by themselves.
    81  type Reader interface {
    82  	ContractCodeReader
    83  	StateReader
    84  }
    85  
    86  // ReaderStats wraps the statistics of reader.
    87  type ReaderStats struct {
    88  	AccountHit  int64
    89  	AccountMiss int64
    90  	StorageHit  int64
    91  	StorageMiss int64
    92  }
    93  
    94  // ReaderWithStats wraps the additional method to retrieve the reader statistics from.
    95  type ReaderWithStats interface {
    96  	Reader
    97  	GetStats() ReaderStats
    98  }
    99  
   100  // cachingCodeReader implements ContractCodeReader, accessing contract code either in
   101  // local key-value store or the shared code cache.
   102  //
   103  // cachingCodeReader is safe for concurrent access.
   104  type cachingCodeReader struct {
   105  	db ethdb.KeyValueReader
   106  
   107  	// These caches could be shared by multiple code reader instances,
   108  	// they are natively thread-safe.
   109  	codeCache     *lru.SizeConstrainedCache[common.Hash, []byte]
   110  	codeSizeCache *lru.Cache[common.Hash, int]
   111  }
   112  
   113  // newCachingCodeReader constructs the code reader.
   114  func newCachingCodeReader(db ethdb.KeyValueReader, codeCache *lru.SizeConstrainedCache[common.Hash, []byte], codeSizeCache *lru.Cache[common.Hash, int]) *cachingCodeReader {
   115  	return &cachingCodeReader{
   116  		db:            db,
   117  		codeCache:     codeCache,
   118  		codeSizeCache: codeSizeCache,
   119  	}
   120  }
   121  
   122  // Code implements ContractCodeReader, retrieving a particular contract's code.
   123  // If the contract code doesn't exist, no error will be returned.
   124  func (r *cachingCodeReader) Code(addr common.Address, codeHash common.Hash) ([]byte, error) {
   125  	code, _ := r.codeCache.Get(codeHash)
   126  	if len(code) > 0 {
   127  		return code, nil
   128  	}
   129  	code = rawdb.ReadCode(r.db, codeHash)
   130  	if len(code) > 0 {
   131  		r.codeCache.Add(codeHash, code)
   132  		r.codeSizeCache.Add(codeHash, len(code))
   133  	}
   134  	return code, nil
   135  }
   136  
   137  // CodeSize implements ContractCodeReader, retrieving a particular contracts code's size.
   138  // If the contract code doesn't exist, no error will be returned.
   139  func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash) (int, error) {
   140  	if cached, ok := r.codeSizeCache.Get(codeHash); ok {
   141  		return cached, nil
   142  	}
   143  	code, err := r.Code(addr, codeHash)
   144  	if err != nil {
   145  		return 0, err
   146  	}
   147  	return len(code), nil
   148  }
   149  
   150  // flatReader wraps a database state reader and is safe for concurrent access.
   151  type flatReader struct {
   152  	reader database.StateReader
   153  }
   154  
   155  // newFlatReader constructs a state reader with on the given state root.
   156  func newFlatReader(reader database.StateReader) *flatReader {
   157  	return &flatReader{reader: reader}
   158  }
   159  
   160  // Account implements StateReader, retrieving the account specified by the address.
   161  //
   162  // An error will be returned if the associated snapshot is already stale or
   163  // the requested account is not yet covered by the snapshot.
   164  //
   165  // The returned account might be nil if it's not existent.
   166  func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) {
   167  	account, err := r.reader.Account(crypto.Keccak256Hash(addr.Bytes()))
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	if account == nil {
   172  		return nil, nil
   173  	}
   174  	acct := &types.StateAccount{
   175  		Nonce:    account.Nonce,
   176  		Balance:  account.Balance,
   177  		CodeHash: account.CodeHash,
   178  		Root:     common.BytesToHash(account.Root),
   179  	}
   180  	if len(acct.CodeHash) == 0 {
   181  		acct.CodeHash = types.EmptyCodeHash.Bytes()
   182  	}
   183  	if acct.Root == (common.Hash{}) {
   184  		acct.Root = types.EmptyRootHash
   185  	}
   186  	return acct, nil
   187  }
   188  
   189  // Storage implements StateReader, retrieving the storage slot specified by the
   190  // address and slot key.
   191  //
   192  // An error will be returned if the associated snapshot is already stale or
   193  // the requested storage slot is not yet covered by the snapshot.
   194  //
   195  // The returned storage slot might be empty if it's not existent.
   196  func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
   197  	addrHash := crypto.Keccak256Hash(addr.Bytes())
   198  	slotHash := crypto.Keccak256Hash(key.Bytes())
   199  	ret, err := r.reader.Storage(addrHash, slotHash)
   200  	if err != nil {
   201  		return common.Hash{}, err
   202  	}
   203  	if len(ret) == 0 {
   204  		return common.Hash{}, nil
   205  	}
   206  	// Perform the rlp-decode as the slot value is RLP-encoded in the state
   207  	// snapshot.
   208  	_, content, _, err := rlp.Split(ret)
   209  	if err != nil {
   210  		return common.Hash{}, err
   211  	}
   212  	var value common.Hash
   213  	value.SetBytes(content)
   214  	return value, nil
   215  }
   216  
   217  // trieReader implements the StateReader interface, providing functions to access
   218  // state from the referenced trie.
   219  //
   220  // trieReader is safe for concurrent read.
   221  type trieReader struct {
   222  	root common.Hash      // State root which uniquely represent a state
   223  	db   *triedb.Database // Database for loading trie
   224  
   225  	// Main trie, resolved in constructor. Note either the Merkle-Patricia-tree
   226  	// or Verkle-tree is not safe for concurrent read.
   227  	mainTrie Trie
   228  
   229  	subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
   230  	subTries map[common.Address]Trie        // Group of storage tries, cached when it's resolved
   231  	lock     sync.Mutex                     // Lock for protecting concurrent read
   232  }
   233  
   234  // trieReader constructs a trie reader of the specific state. An error will be
   235  // returned if the associated trie specified by root is not existent.
   236  func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) {
   237  	var (
   238  		tr  Trie
   239  		err error
   240  	)
   241  	if !db.IsVerkle() {
   242  		tr, err = trie.NewStateTrie(trie.StateTrieID(root), db)
   243  	} else {
   244  		tr, err = trie.NewVerkleTrie(root, db, cache)
   245  	}
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	return &trieReader{
   250  		root:     root,
   251  		db:       db,
   252  		mainTrie: tr,
   253  		subRoots: make(map[common.Address]common.Hash),
   254  		subTries: make(map[common.Address]Trie),
   255  	}, nil
   256  }
   257  
   258  // account is the inner version of Account and assumes the r.lock is already held.
   259  func (r *trieReader) account(addr common.Address) (*types.StateAccount, error) {
   260  	account, err := r.mainTrie.GetAccount(addr)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  	if account == nil {
   265  		r.subRoots[addr] = types.EmptyRootHash
   266  	} else {
   267  		r.subRoots[addr] = account.Root
   268  	}
   269  	return account, nil
   270  }
   271  
   272  // Account implements StateReader, retrieving the account specified by the address.
   273  //
   274  // An error will be returned if the trie state is corrupted. An nil account
   275  // will be returned if it's not existent in the trie.
   276  func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
   277  	r.lock.Lock()
   278  	defer r.lock.Unlock()
   279  
   280  	return r.account(addr)
   281  }
   282  
   283  // Storage implements StateReader, retrieving the storage slot specified by the
   284  // address and slot key.
   285  //
   286  // An error will be returned if the trie state is corrupted. An empty storage
   287  // slot will be returned if it's not existent in the trie.
   288  func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
   289  	r.lock.Lock()
   290  	defer r.lock.Unlock()
   291  
   292  	var (
   293  		tr    Trie
   294  		found bool
   295  		value common.Hash
   296  	)
   297  	if r.db.IsVerkle() {
   298  		tr = r.mainTrie
   299  	} else {
   300  		tr, found = r.subTries[addr]
   301  		if !found {
   302  			root, ok := r.subRoots[addr]
   303  
   304  			// The storage slot is accessed without account caching. It's unexpected
   305  			// behavior but try to resolve the account first anyway.
   306  			if !ok {
   307  				_, err := r.account(addr)
   308  				if err != nil {
   309  					return common.Hash{}, err
   310  				}
   311  				root = r.subRoots[addr]
   312  			}
   313  			var err error
   314  			tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.Keccak256Hash(addr.Bytes()), root), r.db)
   315  			if err != nil {
   316  				return common.Hash{}, err
   317  			}
   318  			r.subTries[addr] = tr
   319  		}
   320  	}
   321  	ret, err := tr.GetStorage(addr, key.Bytes())
   322  	if err != nil {
   323  		return common.Hash{}, err
   324  	}
   325  	value.SetBytes(ret)
   326  	return value, nil
   327  }
   328  
   329  // multiStateReader is the aggregation of a list of StateReader interface,
   330  // providing state access by leveraging all readers. The checking priority
   331  // is determined by the position in the reader list.
   332  //
   333  // multiStateReader is safe for concurrent read and assumes all underlying
   334  // readers are thread-safe as well.
   335  type multiStateReader struct {
   336  	readers []StateReader // List of state readers, sorted by checking priority
   337  }
   338  
   339  // newMultiStateReader constructs a multiStateReader instance with the given
   340  // readers. The priority among readers is assumed to be sorted. Note, it must
   341  // contain at least one reader for constructing a multiStateReader.
   342  func newMultiStateReader(readers ...StateReader) (*multiStateReader, error) {
   343  	if len(readers) == 0 {
   344  		return nil, errors.New("empty reader set")
   345  	}
   346  	return &multiStateReader{
   347  		readers: readers,
   348  	}, nil
   349  }
   350  
   351  // Account implementing StateReader interface, retrieving the account associated
   352  // with a particular address.
   353  //
   354  // - Returns a nil account if it does not exist
   355  // - Returns an error only if an unexpected issue occurs
   356  // - The returned account is safe to modify after the call
   357  func (r *multiStateReader) Account(addr common.Address) (*types.StateAccount, error) {
   358  	var errs []error
   359  	for _, reader := range r.readers {
   360  		acct, err := reader.Account(addr)
   361  		if err == nil {
   362  			return acct, nil
   363  		}
   364  		errs = append(errs, err)
   365  	}
   366  	return nil, errors.Join(errs...)
   367  }
   368  
   369  // Storage implementing StateReader interface, retrieving the storage slot
   370  // associated with a particular account address and slot key.
   371  //
   372  // - Returns an empty slot if it does not exist
   373  // - Returns an error only if an unexpected issue occurs
   374  // - The returned storage slot is safe to modify after the call
   375  func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
   376  	var errs []error
   377  	for _, reader := range r.readers {
   378  		slot, err := reader.Storage(addr, slot)
   379  		if err == nil {
   380  			return slot, nil
   381  		}
   382  		errs = append(errs, err)
   383  	}
   384  	return common.Hash{}, errors.Join(errs...)
   385  }
   386  
   387  // reader is the wrapper of ContractCodeReader and StateReader interface.
   388  type reader struct {
   389  	ContractCodeReader
   390  	StateReader
   391  }
   392  
   393  // newReader constructs a reader with the supplied code reader and state reader.
   394  func newReader(codeReader ContractCodeReader, stateReader StateReader) *reader {
   395  	return &reader{
   396  		ContractCodeReader: codeReader,
   397  		StateReader:        stateReader,
   398  	}
   399  }
   400  
   401  // readerWithCache is a wrapper around Reader that maintains additional state caches
   402  // to support concurrent state access.
   403  type readerWithCache struct {
   404  	Reader // safe for concurrent read
   405  
   406  	// Previously resolved state entries.
   407  	accounts    map[common.Address]*types.StateAccount
   408  	accountLock sync.RWMutex
   409  
   410  	// List of storage buckets, each of which is thread-safe.
   411  	// This reader is typically used in scenarios requiring concurrent
   412  	// access to storage. Using multiple buckets helps mitigate
   413  	// the overhead caused by locking.
   414  	storageBuckets [16]struct {
   415  		lock     sync.RWMutex
   416  		storages map[common.Address]map[common.Hash]common.Hash
   417  	}
   418  }
   419  
   420  // newReaderWithCache constructs the reader with local cache.
   421  func newReaderWithCache(reader Reader) *readerWithCache {
   422  	r := &readerWithCache{
   423  		Reader:   reader,
   424  		accounts: make(map[common.Address]*types.StateAccount),
   425  	}
   426  	for i := range r.storageBuckets {
   427  		r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash)
   428  	}
   429  	return r
   430  }
   431  
   432  // account retrieves the account specified by the address along with a flag
   433  // indicating whether it's found in the cache or not. The returned account
   434  // might be nil if it's not existent.
   435  //
   436  // An error will be returned if the state is corrupted in the underlying reader.
   437  func (r *readerWithCache) account(addr common.Address) (*types.StateAccount, bool, error) {
   438  	// Try to resolve the requested account in the local cache
   439  	r.accountLock.RLock()
   440  	acct, ok := r.accounts[addr]
   441  	r.accountLock.RUnlock()
   442  	if ok {
   443  		return acct, true, nil
   444  	}
   445  	// Try to resolve the requested account from the underlying reader
   446  	acct, err := r.Reader.Account(addr)
   447  	if err != nil {
   448  		return nil, false, err
   449  	}
   450  	r.accountLock.Lock()
   451  	r.accounts[addr] = acct
   452  	r.accountLock.Unlock()
   453  	return acct, false, nil
   454  }
   455  
   456  // Account implements StateReader, retrieving the account specified by the address.
   457  // The returned account might be nil if it's not existent.
   458  //
   459  // An error will be returned if the state is corrupted in the underlying reader.
   460  func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) {
   461  	account, _, err := r.account(addr)
   462  	return account, err
   463  }
   464  
   465  // storage retrieves the storage slot specified by the address and slot key, along
   466  // with a flag indicating whether it's found in the cache or not. The returned
   467  // storage slot might be empty if it's not existent.
   468  func (r *readerWithCache) storage(addr common.Address, slot common.Hash) (common.Hash, bool, error) {
   469  	var (
   470  		value  common.Hash
   471  		ok     bool
   472  		bucket = &r.storageBuckets[addr[0]&0x0f]
   473  	)
   474  	// Try to resolve the requested storage slot in the local cache
   475  	bucket.lock.RLock()
   476  	slots, ok := bucket.storages[addr]
   477  	if ok {
   478  		value, ok = slots[slot]
   479  	}
   480  	bucket.lock.RUnlock()
   481  	if ok {
   482  		return value, true, nil
   483  	}
   484  	// Try to resolve the requested storage slot from the underlying reader
   485  	value, err := r.Reader.Storage(addr, slot)
   486  	if err != nil {
   487  		return common.Hash{}, false, err
   488  	}
   489  	bucket.lock.Lock()
   490  	slots, ok = bucket.storages[addr]
   491  	if !ok {
   492  		slots = make(map[common.Hash]common.Hash)
   493  		bucket.storages[addr] = slots
   494  	}
   495  	slots[slot] = value
   496  	bucket.lock.Unlock()
   497  
   498  	return value, false, nil
   499  }
   500  
   501  // Storage implements StateReader, retrieving the storage slot specified by the
   502  // address and slot key. The returned storage slot might be empty if it's not
   503  // existent.
   504  //
   505  // An error will be returned if the state is corrupted in the underlying reader.
   506  func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
   507  	value, _, err := r.storage(addr, slot)
   508  	return value, err
   509  }
   510  
   511  type readerWithCacheStats struct {
   512  	*readerWithCache
   513  	accountHit  atomic.Int64
   514  	accountMiss atomic.Int64
   515  	storageHit  atomic.Int64
   516  	storageMiss atomic.Int64
   517  }
   518  
   519  // newReaderWithCacheStats constructs the reader with additional statistics tracked.
   520  func newReaderWithCacheStats(reader *readerWithCache) *readerWithCacheStats {
   521  	return &readerWithCacheStats{
   522  		readerWithCache: reader,
   523  	}
   524  }
   525  
   526  // Account implements StateReader, retrieving the account specified by the address.
   527  // The returned account might be nil if it's not existent.
   528  //
   529  // An error will be returned if the state is corrupted in the underlying reader.
   530  func (r *readerWithCacheStats) Account(addr common.Address) (*types.StateAccount, error) {
   531  	account, incache, err := r.readerWithCache.account(addr)
   532  	if err != nil {
   533  		return nil, err
   534  	}
   535  	if incache {
   536  		r.accountHit.Add(1)
   537  	} else {
   538  		r.accountMiss.Add(1)
   539  	}
   540  	return account, nil
   541  }
   542  
   543  // Storage implements StateReader, retrieving the storage slot specified by the
   544  // address and slot key. The returned storage slot might be empty if it's not
   545  // existent.
   546  //
   547  // An error will be returned if the state is corrupted in the underlying reader.
   548  func (r *readerWithCacheStats) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
   549  	value, incache, err := r.readerWithCache.storage(addr, slot)
   550  	if err != nil {
   551  		return common.Hash{}, err
   552  	}
   553  	if incache {
   554  		r.storageHit.Add(1)
   555  	} else {
   556  		r.storageMiss.Add(1)
   557  	}
   558  	return value, nil
   559  }
   560  
   561  // GetStats implements ReaderWithStats, returning the statistics of state reader.
   562  func (r *readerWithCacheStats) GetStats() ReaderStats {
   563  	return ReaderStats{
   564  		AccountHit:  r.accountHit.Load(),
   565  		AccountMiss: r.accountMiss.Load(),
   566  		StorageHit:  r.storageHit.Load(),
   567  		StorageMiss: r.storageMiss.Load(),
   568  	}
   569  }