Skip to content

Commit 623b17b

Browse files
authored
core/state: state reader abstraction (ethereum#29761)
This pull request introduces a state.Reader interface for state accessing. The interface could be implemented in various ways. It can be pure trie only reader, or the combination of trie and state snapshot. What's more, this interface allows us to have more flexibility in the future, e.g. the archive reader (for accessing archive state). Additionally, this pull request removes the following metrics - `chain/snapshot/account/reads` - `chain/snapshot/storage/reads`
1 parent 23973bd commit 623b17b

35 files changed

+661
-414
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
403403
}
404404
// Re-create statedb instance with new root upon the updated database
405405
// for accessing latest states.
406-
statedb, err = state.New(root, statedb.Database(), nil)
406+
statedb, err = state.New(root, statedb.Database())
407407
if err != nil {
408408
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
409409
}
@@ -412,8 +412,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
412412
}
413413

414414
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
415-
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
416-
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
415+
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
416+
sdb := state.NewDatabase(tdb, nil)
417+
statedb, _ := state.New(types.EmptyRootHash, sdb)
417418
for addr, a := range accounts {
418419
statedb.SetCode(addr, a.Code)
419420
statedb.SetNonce(addr, a.Nonce)
@@ -424,7 +425,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
424425
}
425426
// Commit and re-open to start with a clean state.
426427
root, _ := statedb.Commit(0, false)
427-
statedb, _ = state.New(root, sdb, nil)
428+
statedb, _ = state.New(root, sdb)
428429
return statedb
429430
}
430431

cmd/evm/runner.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ func runCmd(ctx *cli.Context) error {
155155
})
156156
defer triedb.Close()
157157
genesis := genesisConfig.MustCommit(db, triedb)
158-
sdb := state.NewDatabaseWithNodeDB(db, triedb)
159-
statedb, _ = state.New(genesis.Root(), sdb, nil)
158+
sdb := state.NewDatabase(triedb, nil)
159+
statedb, _ = state.New(genesis.Root(), sdb)
160160
chainConfig = genesisConfig.Config
161161

162162
if ctx.String(SenderFlag.Name) != "" {
@@ -277,7 +277,7 @@ func runCmd(ctx *cli.Context) error {
277277
fmt.Printf("Failed to commit changes %v\n", err)
278278
return err
279279
}
280-
dumpdb, err := state.New(root, sdb, nil)
280+
dumpdb, err := state.New(root, sdb)
281281
if err != nil {
282282
fmt.Printf("Failed to open statedb %v\n", err)
283283
return err

cmd/evm/staterunner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
107107
result.Root = &root
108108
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
109109
if dump { // Dump any state to aid debugging
110-
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
110+
cpy, _ := state.New(root, tstate.StateDB.Database())
111111
dump := cpy.RawDump(nil)
112112
result.State = &dump
113113
}

cmd/geth/chaincmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ func dump(ctx *cli.Context) error {
584584
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
585585
defer triedb.Close()
586586

587-
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
587+
state, err := state.New(root, state.NewDatabase(triedb, nil))
588588
if err != nil {
589589
return err
590590
}

core/blockchain.go

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,11 @@ var (
7272
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
7373
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
7474

75-
snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil)
76-
snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil)
77-
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
78-
7975
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
8076
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
8177

82-
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
78+
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
79+
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
8380

8481
blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil)
8582
blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil)
@@ -220,7 +217,7 @@ type BlockChain struct {
220217
lastWrite uint64 // Last block when the state was flushed
221218
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
222219
triedb *triedb.Database // The database handler for maintaining trie nodes.
223-
stateCache state.Database // State database to reuse between imports (contains state cache)
220+
statedb *state.CachingDB // State database to reuse between imports (contains state cache)
224221
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
225222

226223
hc *HeaderChain
@@ -311,7 +308,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
311308
return nil, err
312309
}
313310
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
314-
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
311+
bc.statedb = state.NewDatabase(bc.triedb, nil)
315312
bc.validator = NewBlockValidator(chainConfig, bc)
316313
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
317314
bc.processor = NewStateProcessor(chainConfig, bc.hc)
@@ -449,7 +446,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
449446
AsyncBuild: !bc.cacheConfig.SnapshotWait,
450447
}
451448
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root)
449+
450+
// Re-initialize the state database with snapshot
451+
bc.statedb = state.NewDatabase(bc.triedb, bc.snaps)
452452
}
453+
453454
// Rewind the chain in case of an incompatible config upgrade.
454455
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
455456
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
@@ -1767,7 +1768,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
17671768
if parent == nil {
17681769
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
17691770
}
1770-
statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps)
1771+
statedb, err := state.New(parent.Root, bc.statedb)
17711772
if err != nil {
17721773
return it.index, err
17731774
}
@@ -1793,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
17931794
var followupInterrupt atomic.Bool
17941795
if !bc.cacheConfig.TrieCleanNoPrefetch {
17951796
if followup, err := it.peek(); followup != nil && err == nil {
1796-
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
1797+
throwaway, _ := state.New(parent.Root, bc.statedb)
17971798

17981799
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
17991800
// Disable tracing for prefetcher executions.
@@ -1914,26 +1915,21 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
19141915
proctime := time.Since(start) // processing + validation
19151916

19161917
// Update the metrics touched during block processing and validation
1917-
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
1918-
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
1919-
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
1920-
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
1921-
1922-
accountRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
1923-
storageRead := statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
1918+
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
1919+
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
19241920
if statedb.AccountLoaded != 0 {
1925-
accountReadSingleTimer.Update(accountRead / time.Duration(statedb.AccountLoaded))
1921+
accountReadSingleTimer.Update(statedb.AccountReads / time.Duration(statedb.AccountLoaded))
19261922
}
19271923
if statedb.StorageLoaded != 0 {
1928-
storageReadSingleTimer.Update(storageRead / time.Duration(statedb.StorageLoaded))
1929-
}
1930-
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
1931-
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
1932-
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
1933-
triehash := statedb.AccountHashes // The time spent on tries hashing
1934-
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
1935-
blockExecutionTimer.Update(ptime - (accountRead + storageRead)) // The time spent on EVM processing
1936-
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
1924+
storageReadSingleTimer.Update(statedb.StorageReads / time.Duration(statedb.StorageLoaded))
1925+
}
1926+
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
1927+
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
1928+
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
1929+
triehash := statedb.AccountHashes // The time spent on tries hashing
1930+
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
1931+
blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing
1932+
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
19371933

19381934
// Write the block to the chain and get the status.
19391935
var (

core/blockchain_reader.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
308308

309309
// HasState checks if state trie is fully present in the database or not.
310310
func (bc *BlockChain) HasState(hash common.Hash) bool {
311-
_, err := bc.stateCache.OpenTrie(hash)
311+
_, err := bc.statedb.OpenTrie(hash)
312312
return err == nil
313313
}
314314

@@ -341,12 +341,9 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
341341
// If the code doesn't exist in the in-memory cache, check the storage with
342342
// new code scheme.
343343
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
344-
type codeReader interface {
345-
ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error)
346-
}
347344
// TODO(rjl493456442) The associated account address is also required
348345
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
349-
return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash)
346+
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
350347
}
351348

352349
// State returns a new mutable state based on the current HEAD block.
@@ -356,7 +353,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) {
356353

357354
// StateAt returns a new mutable state based on a particular point in time.
358355
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
359-
return state.New(root, bc.stateCache, bc.snaps)
356+
return state.New(root, bc.statedb)
360357
}
361358

362359
// Config retrieves the chain's fork configuration.
@@ -382,7 +379,7 @@ func (bc *BlockChain) Processor() Processor {
382379

383380
// StateCache returns the caching database underpinning the blockchain instance.
384381
func (bc *BlockChain) StateCache() state.Database {
385-
return bc.stateCache
382+
return bc.statedb
386383
}
387384

388385
// GasLimit returns the gas limit of the current HEAD block.

core/blockchain_sethead_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2040,7 +2040,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
20402040
dbconfig.HashDB = hashdb.Defaults
20412041
}
20422042
chain.triedb = triedb.NewDatabase(chain.db, dbconfig)
2043-
chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb)
2043+
chain.statedb = state.NewDatabase(chain.triedb, chain.snaps)
20442044

20452045
// Force run a freeze cycle
20462046
type freezer interface {

core/blockchain_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
160160
}
161161
return err
162162
}
163-
statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.stateCache, nil)
163+
statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.statedb)
164164
if err != nil {
165165
return err
166166
}

core/chain_makers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
379379
defer triedb.Close()
380380

381381
for i := 0; i < n; i++ {
382-
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
382+
statedb, err := state.New(parent.Root(), state.NewDatabase(triedb, nil))
383383
if err != nil {
384384
panic(err)
385385
}
@@ -485,7 +485,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
485485
}
486486

487487
for i := 0; i < n; i++ {
488-
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, trdb), nil)
488+
statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil))
489489
if err != nil {
490490
panic(err)
491491
}

core/genesis.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
127127
}
128128
// Create an ephemeral in-memory database for computing hash,
129129
// all the derived states will be discarded to not pollute disk.
130-
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
131-
statedb, err := state.New(types.EmptyRootHash, db, nil)
130+
db := rawdb.NewMemoryDatabase()
131+
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil))
132132
if err != nil {
133133
return common.Hash{}, err
134134
}
@@ -147,8 +147,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
147147

148148
// flushAlloc is very similar with hash, but the main difference is all the
149149
// generated states will be persisted into the given database.
150-
func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database) (common.Hash, error) {
151-
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
150+
func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) {
151+
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil))
152152
if err != nil {
153153
return common.Hash{}, err
154154
}
@@ -497,7 +497,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
497497
return nil, errors.New("can't start clique chain without signers")
498498
}
499499
// flush the data to disk and compute the state root
500-
root, err := flushAlloc(&g.Alloc, db, triedb)
500+
root, err := flushAlloc(&g.Alloc, triedb)
501501
if err != nil {
502502
return nil, err
503503
}

0 commit comments

Comments
 (0)