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

     1  // Copyright 2025 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  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/common/lru"
    24  	"github.com/ethereum/go-ethereum/core/state/snapshot"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/ethdb"
    27  	"github.com/ethereum/go-ethereum/rlp"
    28  	"github.com/ethereum/go-ethereum/trie/utils"
    29  	"github.com/ethereum/go-ethereum/triedb"
    30  	"github.com/ethereum/go-ethereum/triedb/pathdb"
    31  )
    32  
    33  // historicReader wraps a historical state reader defined in path database,
    34  // providing historic state serving over the path scheme.
    35  //
    36  // TODO(rjl493456442): historicReader is not thread-safe and does not fully
    37  // comply with the StateReader interface requirements, needs to be fixed.
    38  // Currently, it is only used in a non-concurrent context, so it is safe for now.
    39  type historicReader struct {
    40  	reader *pathdb.HistoricalStateReader
    41  }
    42  
    43  // newHistoricReader constructs a reader for historic state serving.
    44  func newHistoricReader(r *pathdb.HistoricalStateReader) *historicReader {
    45  	return &historicReader{reader: r}
    46  }
    47  
    48  // Account implements StateReader, retrieving the account specified by the address.
    49  //
    50  // An error will be returned if the associated snapshot is already stale or
    51  // the requested account is not yet covered by the snapshot.
    52  //
    53  // The returned account might be nil if it's not existent.
    54  func (r *historicReader) Account(addr common.Address) (*types.StateAccount, error) {
    55  	account, err := r.reader.Account(addr)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	if account == nil {
    60  		return nil, nil
    61  	}
    62  	acct := &types.StateAccount{
    63  		Nonce:    account.Nonce,
    64  		Balance:  account.Balance,
    65  		CodeHash: account.CodeHash,
    66  		Root:     common.BytesToHash(account.Root),
    67  	}
    68  	if len(acct.CodeHash) == 0 {
    69  		acct.CodeHash = types.EmptyCodeHash.Bytes()
    70  	}
    71  	if acct.Root == (common.Hash{}) {
    72  		acct.Root = types.EmptyRootHash
    73  	}
    74  	return acct, nil
    75  }
    76  
    77  // Storage implements StateReader, retrieving the storage slot specified by the
    78  // address and slot key.
    79  //
    80  // An error will be returned if the associated snapshot is already stale or
    81  // the requested storage slot is not yet covered by the snapshot.
    82  //
    83  // The returned storage slot might be empty if it's not existent.
    84  func (r *historicReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
    85  	blob, err := r.reader.Storage(addr, key)
    86  	if err != nil {
    87  		return common.Hash{}, err
    88  	}
    89  	if len(blob) == 0 {
    90  		return common.Hash{}, nil
    91  	}
    92  	_, content, _, err := rlp.Split(blob)
    93  	if err != nil {
    94  		return common.Hash{}, err
    95  	}
    96  	var slot common.Hash
    97  	slot.SetBytes(content)
    98  	return slot, nil
    99  }
   100  
   101  // HistoricDB is the implementation of Database interface, with the ability to
   102  // access historical state.
   103  type HistoricDB struct {
   104  	disk          ethdb.KeyValueStore
   105  	triedb        *triedb.Database
   106  	codeCache     *lru.SizeConstrainedCache[common.Hash, []byte]
   107  	codeSizeCache *lru.Cache[common.Hash, int]
   108  	pointCache    *utils.PointCache
   109  }
   110  
   111  // NewHistoricDatabase creates a historic state database.
   112  func NewHistoricDatabase(disk ethdb.KeyValueStore, triedb *triedb.Database) *HistoricDB {
   113  	return &HistoricDB{
   114  		disk:          disk,
   115  		triedb:        triedb,
   116  		codeCache:     lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
   117  		codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
   118  		pointCache:    utils.NewPointCache(pointCacheSize),
   119  	}
   120  }
   121  
   122  // Reader implements Database interface, returning a reader of the specific state.
   123  func (db *HistoricDB) Reader(stateRoot common.Hash) (Reader, error) {
   124  	hr, err := db.triedb.HistoricReader(stateRoot)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), newHistoricReader(hr)), nil
   129  }
   130  
   131  // OpenTrie opens the main account trie. It's not supported by historic database.
   132  func (db *HistoricDB) OpenTrie(root common.Hash) (Trie, error) {
   133  	return nil, errors.New("not implemented")
   134  }
   135  
   136  // OpenStorageTrie opens the storage trie of an account. It's not supported by
   137  // historic database.
   138  func (db *HistoricDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error) {
   139  	return nil, errors.New("not implemented")
   140  }
   141  
   142  // PointCache returns the cache holding points used in verkle tree key computation
   143  func (db *HistoricDB) PointCache() *utils.PointCache {
   144  	return db.pointCache
   145  }
   146  
   147  // TrieDB returns the underlying trie database for managing trie nodes.
   148  func (db *HistoricDB) TrieDB() *triedb.Database {
   149  	return db.triedb
   150  }
   151  
   152  // Snapshot returns the underlying state snapshot.
   153  func (db *HistoricDB) Snapshot() *snapshot.Tree {
   154  	return nil
   155  }