Skip to content

Commit 743e404

Browse files
authored
core, eth, les, tests, trie: abstract node scheme (#25532)
This PR introduces a node scheme abstraction. The interface is only implemented by `hashScheme` at the moment, but will be extended by `pathScheme` very soon. Apart from that, a few changes are also included which is worth mentioning: - port the changes in the stacktrie, tracking the path prefix of nodes during commit - use ethdb.Database for constructing trie.Database. This is not necessary right now, but it is required for path-based used to open reverse diff freezer
1 parent 0e06735 commit 743e404

36 files changed

+613
-353
lines changed

cmd/geth/chaincmd.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/ethereum/go-ethereum/log"
4040
"github.com/ethereum/go-ethereum/metrics"
4141
"github.com/ethereum/go-ethereum/node"
42+
"github.com/ethereum/go-ethereum/trie"
4243
"github.com/urfave/cli/v2"
4344
)
4445

@@ -48,7 +49,7 @@ var (
4849
Name: "init",
4950
Usage: "Bootstrap and initialize a new genesis block",
5051
ArgsUsage: "<genesisPath>",
51-
Flags: utils.DatabasePathFlags,
52+
Flags: flags.Merge([]cli.Flag{utils.CachePreimagesFlag}, utils.DatabasePathFlags),
5253
Description: `
5354
The init command initializes a new genesis block and definition for the network.
5455
This is a destructive action and changes the network in which you will be
@@ -188,12 +189,16 @@ func initGenesis(ctx *cli.Context) error {
188189
// Open and initialise both full and light databases
189190
stack, _ := makeConfigNode(ctx)
190191
defer stack.Close()
192+
191193
for _, name := range []string{"chaindata", "lightchaindata"} {
192194
chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false)
193195
if err != nil {
194196
utils.Fatalf("Failed to open database: %v", err)
195197
}
196-
_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
198+
triedb := trie.NewDatabaseWithConfig(chaindb, &trie.Config{
199+
Preimages: ctx.Bool(utils.CachePreimagesFlag.Name),
200+
})
201+
_, hash, err := core.SetupGenesisBlock(chaindb, triedb, genesis)
197202
if err != nil {
198203
utils.Fatalf("Failed to write genesis block: %v", err)
199204
}
@@ -460,7 +465,10 @@ func dump(ctx *cli.Context) error {
460465
if err != nil {
461466
return err
462467
}
463-
state, err := state.New(root, state.NewDatabase(db), nil)
468+
config := &trie.Config{
469+
Preimages: true, // always enable preimage lookup
470+
}
471+
state, err := state.New(root, state.NewDatabaseWithConfig(db, config), nil)
464472
if err != nil {
465473
return err
466474
}

core/blockchain.go

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,12 @@ type BlockChain struct {
169169
chainConfig *params.ChainConfig // Chain & network configuration
170170
cacheConfig *CacheConfig // Cache configuration for pruning
171171

172-
db ethdb.Database // Low level persistent database to store final content in
173-
snaps *snapshot.Tree // Snapshot tree for fast trie leaf access
174-
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
175-
gcproc time.Duration // Accumulates canonical block processing for trie dumping
172+
db ethdb.Database // Low level persistent database to store final content in
173+
snaps *snapshot.Tree // Snapshot tree for fast trie leaf access
174+
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
175+
gcproc time.Duration // Accumulates canonical block processing for trie dumping
176+
triedb *trie.Database // The database handler for maintaining trie nodes.
177+
stateCache state.Database // State database to reuse between imports (contains state cache)
176178

177179
// txLookupLimit is the maximum number of blocks from head whose tx indices
178180
// are reserved:
@@ -200,7 +202,6 @@ type BlockChain struct {
200202
currentFinalizedBlock atomic.Value // Current finalized head
201203
currentSafeBlock atomic.Value // Current safe head
202204

203-
stateCache state.Database // State database to reuse between imports (contains state cache)
204205
bodyCache *lru.Cache[common.Hash, *types.Body]
205206
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
206207
receiptsCache *lru.Cache[common.Hash, []*types.Receipt]
@@ -231,10 +232,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
231232
cacheConfig = defaultCacheConfig
232233
}
233234

235+
// Open trie database with provided config
236+
triedb := trie.NewDatabaseWithConfig(db, &trie.Config{
237+
Cache: cacheConfig.TrieCleanLimit,
238+
Journal: cacheConfig.TrieCleanJournal,
239+
Preimages: cacheConfig.Preimages,
240+
})
234241
// Setup the genesis block, commit the provided genesis specification
235242
// to database if the genesis block is not present yet, or load the
236243
// stored one from database.
237-
chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, genesis, overrides)
244+
chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides)
238245
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
239246
return nil, genesisErr
240247
}
@@ -247,15 +254,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
247254
log.Info("")
248255

249256
bc := &BlockChain{
250-
chainConfig: chainConfig,
251-
cacheConfig: cacheConfig,
252-
db: db,
253-
triegc: prque.New(nil),
254-
stateCache: state.NewDatabaseWithConfig(db, &trie.Config{
255-
Cache: cacheConfig.TrieCleanLimit,
256-
Journal: cacheConfig.TrieCleanJournal,
257-
Preimages: cacheConfig.Preimages,
258-
}),
257+
chainConfig: chainConfig,
258+
cacheConfig: cacheConfig,
259+
db: db,
260+
triedb: triedb,
261+
triegc: prque.New(nil),
259262
quit: make(chan struct{}),
260263
chainmu: syncx.NewClosableMutex(),
261264
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
@@ -268,6 +271,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
268271
vmConfig: vmConfig,
269272
}
270273
bc.forker = NewForkChoice(bc, shouldPreserve)
274+
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
271275
bc.validator = NewBlockValidator(chainConfig, bc, engine)
272276
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
273277
bc.processor = NewStateProcessor(chainConfig, bc, engine)
@@ -300,7 +304,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
300304
}
301305
// Make sure the state associated with the block is available
302306
head := bc.CurrentBlock()
303-
if _, err := state.New(head.Root(), bc.stateCache, bc.snaps); err != nil {
307+
if !bc.HasState(head.Root()) {
304308
// Head state is missing, before the state recovery, find out the
305309
// disk layer point of snapshot(if it's enabled). Make sure the
306310
// rewound point is lower than disk layer.
@@ -388,7 +392,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
388392
var recover bool
389393

390394
head := bc.CurrentBlock()
391-
if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer > head.NumberU64() {
395+
if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.NumberU64() {
392396
log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer)
393397
recover = true
394398
}
@@ -398,7 +402,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
398402
NoBuild: bc.cacheConfig.SnapshotNoBuild,
399403
AsyncBuild: !bc.cacheConfig.SnapshotWait,
400404
}
401-
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.stateCache.TrieDB(), head.Root())
405+
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root())
402406
}
403407

404408
// Start future block processor.
@@ -411,11 +415,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
411415
log.Warn("Sanitizing invalid trie cache journal time", "provided", bc.cacheConfig.TrieCleanRejournal, "updated", time.Minute)
412416
bc.cacheConfig.TrieCleanRejournal = time.Minute
413417
}
414-
triedb := bc.stateCache.TrieDB()
415418
bc.wg.Add(1)
416419
go func() {
417420
defer bc.wg.Done()
418-
triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit)
421+
bc.triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit)
419422
}()
420423
}
421424
// Rewind the chain in case of an incompatible config upgrade.
@@ -594,7 +597,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
594597
if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root {
595598
beyondRoot, rootNumber = true, newHeadBlock.NumberU64()
596599
}
597-
if _, err := state.New(newHeadBlock.Root(), bc.stateCache, bc.snaps); err != nil {
600+
if !bc.HasState(newHeadBlock.Root()) {
598601
log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash())
599602
if pivot == nil || newHeadBlock.NumberU64() > *pivot {
600603
parent := bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1)
@@ -617,7 +620,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
617620
// if the historical chain pruning is enabled. In that case the logic
618621
// needs to be improved here.
619622
if !bc.HasState(bc.genesisBlock.Root()) {
620-
if err := CommitGenesisState(bc.db, bc.genesisBlock.Hash()); err != nil {
623+
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
621624
log.Crit("Failed to commit genesis state", "err", err)
622625
}
623626
log.Debug("Recommitted genesis state to disk")
@@ -900,7 +903,7 @@ func (bc *BlockChain) Stop() {
900903
// - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle
901904
// - HEAD-127: So we have a hard limit on the number of blocks reexecuted
902905
if !bc.cacheConfig.TrieDirtyDisabled {
903-
triedb := bc.stateCache.TrieDB()
906+
triedb := bc.triedb
904907

905908
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
906909
if number := bc.CurrentBlock().NumberU64(); number > offset {
@@ -932,8 +935,7 @@ func (bc *BlockChain) Stop() {
932935
// Ensure all live cached entries be saved into disk, so that we can skip
933936
// cache warmup when node restarts.
934937
if bc.cacheConfig.TrieCleanJournal != "" {
935-
triedb := bc.stateCache.TrieDB()
936-
triedb.SaveCache(bc.cacheConfig.TrieCleanJournal)
938+
bc.triedb.SaveCache(bc.cacheConfig.TrieCleanJournal)
937939
}
938940
log.Info("Blockchain stopped")
939941
}
@@ -1306,24 +1308,22 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13061308
if err != nil {
13071309
return err
13081310
}
1309-
triedb := bc.stateCache.TrieDB()
1310-
13111311
// If we're running an archive node, always flush
13121312
if bc.cacheConfig.TrieDirtyDisabled {
1313-
return triedb.Commit(root, false, nil)
1313+
return bc.triedb.Commit(root, false, nil)
13141314
} else {
13151315
// Full but not archive node, do proper garbage collection
1316-
triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive
1316+
bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive
13171317
bc.triegc.Push(root, -int64(block.NumberU64()))
13181318

13191319
if current := block.NumberU64(); current > TriesInMemory {
13201320
// If we exceeded our memory allowance, flush matured singleton nodes to disk
13211321
var (
1322-
nodes, imgs = triedb.Size()
1322+
nodes, imgs = bc.triedb.Size()
13231323
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
13241324
)
13251325
if nodes > limit || imgs > 4*1024*1024 {
1326-
triedb.Cap(limit - ethdb.IdealBatchSize)
1326+
bc.triedb.Cap(limit - ethdb.IdealBatchSize)
13271327
}
13281328
// Find the next state trie we need to commit
13291329
chosen := current - TriesInMemory
@@ -1342,7 +1342,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13421342
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory)
13431343
}
13441344
// Flush an entire trie and restart the counters
1345-
triedb.Commit(header.Root, true, nil)
1345+
bc.triedb.Commit(header.Root, true, nil)
13461346
lastWrite = chosen
13471347
bc.gcproc = 0
13481348
}
@@ -1354,7 +1354,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13541354
bc.triegc.Push(root, number)
13551355
break
13561356
}
1357-
triedb.Dereference(root.(common.Hash))
1357+
bc.triedb.Dereference(root.(common.Hash))
13581358
}
13591359
}
13601360
}
@@ -1760,7 +1760,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
17601760
stats.processed++
17611761
stats.usedGas += usedGas
17621762

1763-
dirty, _ := bc.stateCache.TrieDB().Size()
1763+
dirty, _ := bc.triedb.Size()
17641764
stats.report(chain, it.index, dirty, setHead)
17651765

17661766
if !setHead {

core/blockchain_reader.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/ethereum/go-ethereum/event"
3030
"github.com/ethereum/go-ethereum/params"
3131
"github.com/ethereum/go-ethereum/rlp"
32+
"github.com/ethereum/go-ethereum/trie"
3233
)
3334

3435
// CurrentHeader retrieves the current head header of the canonical chain. The
@@ -375,6 +376,11 @@ func (bc *BlockChain) TxLookupLimit() uint64 {
375376
return bc.txLookupLimit
376377
}
377378

379+
// TrieDB retrieves the low level trie database used for data storage.
380+
func (bc *BlockChain) TrieDB() *trie.Database {
381+
return bc.triedb
382+
}
383+
378384
// SubscribeRemovedLogsEvent registers a subscription of RemovedLogsEvent.
379385
func (bc *BlockChain) SubscribeRemovedLogsEvent(ch chan<- RemovedLogsEvent) event.Subscription {
380386
return bc.scope.Track(bc.rmLogsFeed.Subscribe(ch))

core/chain_makers.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/ethereum/go-ethereum/core/vm"
3030
"github.com/ethereum/go-ethereum/ethdb"
3131
"github.com/ethereum/go-ethereum/params"
32+
"github.com/ethereum/go-ethereum/trie"
3233
)
3334

3435
// BlockGen creates blocks for testing.
@@ -308,7 +309,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
308309
// then generate chain on top.
309310
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
310311
db := rawdb.NewMemoryDatabase()
311-
_, err := genesis.Commit(db)
312+
_, err := genesis.Commit(db, trie.NewDatabase(db))
312313
if err != nil {
313314
panic(err)
314315
}

0 commit comments

Comments
 (0)