Skip to content

Commit 07328dc

Browse files
core, eth, trie: abstract node scheme ethereum#25532 (XinFinOrg#1123)
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 Co-authored-by: rjl493456442 <garyrong0905@gmail.com>
1 parent a4fbda2 commit 07328dc

22 files changed

+400
-206
lines changed

cmd/XDC/chaincmd.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
xdc_genesis "github.com/XinFinOrg/XDPoSChain/genesis"
4040
"github.com/XinFinOrg/XDPoSChain/log"
4141
"github.com/XinFinOrg/XDPoSChain/node"
42+
"github.com/XinFinOrg/XDPoSChain/trie"
4243
"github.com/urfave/cli/v2"
4344
)
4445

@@ -48,7 +49,10 @@ var (
4849
Name: "init",
4950
Usage: "Bootstrap and initialize a new genesis block",
5051
ArgsUsage: "<genesisPath>",
51-
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
52+
Flags: slices.Concat(
53+
[]cli.Flag{utils.CachePreimagesFlag},
54+
utils.NetworkFlags,
55+
utils.DatabaseFlags),
5256
Description: `
5357
The init command initializes a new genesis block and definition for the network.
5458
This is a destructive action and changes the network in which you will be
@@ -424,7 +428,10 @@ func dump(ctx *cli.Context) error {
424428
if err != nil {
425429
return err
426430
}
427-
state, err := state.New(root, state.NewDatabase(db))
431+
config := &trie.Config{
432+
Preimages: true, // always enable preimage lookup
433+
}
434+
state, err := state.New(root, state.NewDatabaseWithConfig(db, config))
428435
if err != nil {
429436
return err
430437
}

core/blockchain.go

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

170-
db ethdb.Database // Low level persistent database to store final content in
171-
XDCxDb ethdb.XDCxDatabase
172-
triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
173-
gcproc time.Duration // Accumulates canonical block processing for trie dumping
170+
db ethdb.Database // Low level persistent database to store final content in
171+
XDCxDb ethdb.XDCxDatabase // XDCx database
172+
triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
173+
gcproc time.Duration // Accumulates canonical block processing for trie dumping
174+
triedb *trie.Database // The database handler for maintaining trie nodes.
175+
stateCache state.Database // State database to reuse between imports (contains state cache)
174176

175177
hc *HeaderChain
176178
rmLogsFeed event.Feed
@@ -188,8 +190,6 @@ type BlockChain struct {
188190
currentBlock atomic.Value // Current head of the block chain
189191
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
190192

191-
stateCache state.Database // State database to reuse between imports (contains state cache)
192-
193193
bodyCache *lru.Cache[common.Hash, *types.Body] // Cache for the most recent block bodies
194194
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] // Cache for the most recent block bodies in RLP encoded format
195195
receiptsCache *lru.Cache[common.Hash, types.Receipts] // Cache for the most recent block receipts
@@ -239,10 +239,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
239239
}
240240
}
241241

242+
// Open trie database with provided config
243+
triedb := trie.NewDatabaseWithConfig(db, &trie.Config{
244+
Cache: cacheConfig.TrieCleanLimit,
245+
Preimages: cacheConfig.Preimages,
246+
})
242247
bc := &BlockChain{
243248
chainConfig: chainConfig,
244249
cacheConfig: cacheConfig,
245250
db: db,
251+
triedb: triedb,
246252
triegc: prque.New[int64, common.Hash](nil),
247253
stateCache: state.NewDatabaseWithConfig(db, &trie.Config{
248254
Cache: cacheConfig.TrieCleanLimit,
@@ -268,6 +274,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
268274
rejectedLendingItem: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
269275
finalizedTrade: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit),
270276
}
277+
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
271278
bc.validator = NewBlockValidator(chainConfig, bc, engine)
272279
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
273280
bc.processor = NewStateProcessor(chainConfig, bc, engine)
@@ -373,8 +380,7 @@ func (bc *BlockChain) loadLastState() error {
373380
}
374381
// Make sure the state associated with the block is available
375382
repair := false
376-
_, err := state.New(currentBlock.Root(), bc.stateCache)
377-
if err != nil {
383+
if !bc.HasState(currentBlock.Root()) {
378384
repair = true
379385
} else {
380386
engine, ok := bc.Engine().(*XDPoS.XDPoS)
@@ -487,7 +493,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64) error {
487493
if newHeadBlock == nil {
488494
newHeadBlock = bc.genesisBlock
489495
} else {
490-
if _, err := state.New(newHeadBlock.Root(), bc.stateCache); err != nil {
496+
if !bc.HasState(newHeadBlock.Root()) {
491497
// Rewound state missing, rolled back to before pivot, reset to genesis
492498
newHeadBlock = bc.genesisBlock
493499
}
@@ -712,7 +718,7 @@ func (bc *BlockChain) repair(head **types.Block) error {
712718
for {
713719
// Abort if we've rewound to a head block that does have associated state
714720
if (common.RollbackNumber == 0) || ((*head).Number().Uint64() < common.RollbackNumber) {
715-
if _, err := state.New((*head).Root(), bc.stateCache); err == nil {
721+
if bc.HasState((*head).Root()) {
716722
log.Info("Rewound blockchain to past state", "number", (*head).Number(), "hash", (*head).Hash())
717723
engine, ok := bc.Engine().(*XDPoS.XDPoS)
718724
if ok {
@@ -1082,10 +1088,10 @@ func (bc *BlockChain) saveData() {
10821088
if !bc.cacheConfig.TrieDirtyDisabled {
10831089
var tradingTriedb *trie.Database
10841090
var lendingTriedb *trie.Database
1085-
engine, _ := bc.Engine().(*XDPoS.XDPoS)
1086-
triedb := bc.stateCache.TrieDB()
10871091
var tradingService utils.TradingService
10881092
var lendingService utils.LendingService
1093+
triedb := bc.triedb
1094+
engine, _ := bc.Engine().(*XDPoS.XDPoS)
10891095
if bc.Config().IsTIPXDCX(bc.CurrentBlock().Number()) && bc.chainConfig.XDPoS != nil && bc.CurrentBlock().NumberU64() > bc.chainConfig.XDPoS.Epoch && engine != nil {
10901096
tradingService = engine.GetXDCXService()
10911097
if tradingService != nil && tradingService.GetStateCache() != nil {
@@ -1439,7 +1445,6 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
14391445
if err != nil {
14401446
return NonStatTy, err
14411447
}
1442-
triedb := bc.stateCache.TrieDB()
14431448

14441449
tradingRoot := common.Hash{}
14451450
if tradingState != nil {
@@ -1474,7 +1479,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
14741479

14751480
// If we're running an archive node, always flush
14761481
if bc.cacheConfig.TrieDirtyDisabled {
1477-
if err := triedb.Commit(root, false); err != nil {
1482+
if err := bc.triedb.Commit(root, false); err != nil {
14781483
return NonStatTy, err
14791484
}
14801485
if tradingTrieDb != nil {
@@ -1489,7 +1494,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
14891494
}
14901495
} else {
14911496
// Full but not archive node, do proper garbage collection
1492-
triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive
1497+
bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive
14931498
bc.triegc.Push(root, -int64(block.NumberU64()))
14941499
if tradingTrieDb != nil {
14951500
tradingTrieDb.Reference(tradingRoot, common.Hash{})
@@ -1516,11 +1521,11 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
15161521
// size = size + lendingTrieDb.Size()
15171522
//}
15181523
var (
1519-
nodes, imgs = triedb.Size()
1524+
nodes, imgs = bc.triedb.Size()
15201525
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
15211526
)
15221527
if nodes > limit || imgs > 4*1024*1024 {
1523-
triedb.Cap(limit - ethdb.IdealBatchSize)
1528+
bc.triedb.Cap(limit - ethdb.IdealBatchSize)
15241529
}
15251530
if bc.gcproc > bc.cacheConfig.TrieTimeLimit || chosen > lastWrite+triesInMemory {
15261531
// If the header is missing (canonical chain behind), we're reorging a low
@@ -1535,7 +1540,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
15351540
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory)
15361541
}
15371542
// Flush an entire trie and restart the counters
1538-
triedb.Commit(header.Root, true)
1543+
bc.triedb.Commit(header.Root, true)
15391544
lastWrite = chosen
15401545
bc.gcproc = 0
15411546
if tradingTrieDb != nil && lendingTrieDb != nil {
@@ -1555,7 +1560,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
15551560
bc.triegc.Push(root, number)
15561561
break
15571562
}
1558-
triedb.Dereference(root)
1563+
bc.triedb.Dereference(root)
15591564
}
15601565
if tradingService != nil {
15611566
for !tradingService.GetTriegc().Empty() {
@@ -1831,7 +1836,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []
18311836
bc.UpdateBlocksHashCache(block)
18321837
}
18331838

1834-
dirty, _ := bc.stateCache.TrieDB().Size()
1839+
dirty, _ := bc.triedb.Size()
18351840
stats.report(chain, it.index, dirty)
18361841
if bc.chainConfig.XDPoS != nil {
18371842
engine, _ := bc.Engine().(*XDPoS.XDPoS)
@@ -2287,7 +2292,7 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L
22872292
}
22882293
stats.processed++
22892294
stats.usedGas += result.usedGas
2290-
dirty, _ := bc.stateCache.TrieDB().Size()
2295+
dirty, _ := bc.triedb.Size()
22912296
stats.report(types.Blocks{block}, 0, dirty)
22922297
if bc.chainConfig.XDPoS != nil {
22932298
// epoch block

core/blockchain_reader.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2021 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 core
18+
19+
import (
20+
"github.com/XinFinOrg/XDPoSChain/trie"
21+
)
22+
23+
// TrieDB retrieves the low level trie database used for data storage.
24+
func (bc *BlockChain) TrieDB() *trie.Database {
25+
return bc.triedb
26+
}

core/state/database.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,23 +130,33 @@ func NewDatabase(db ethdb.Database) Database {
130130
// large memory cache.
131131
func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
132132
return &cachingDB{
133-
db: trie.NewDatabaseWithConfig(db, config),
134133
disk: db,
134+
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
135135
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
136+
triedb: trie.NewDatabaseWithConfig(db, config),
137+
}
138+
}
139+
140+
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
141+
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database {
142+
return &cachingDB{
143+
disk: db,
136144
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
145+
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
146+
triedb: triedb,
137147
}
138148
}
139149

140150
type cachingDB struct {
141-
db *trie.Database
142151
disk ethdb.KeyValueStore
143-
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
144152
codeSizeCache *lru.Cache[common.Hash, int]
153+
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
154+
triedb *trie.Database
145155
}
146156

147157
// OpenTrie opens the main account trie at a specific root hash.
148158
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
149-
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.db)
159+
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
150160
if err != nil {
151161
return nil, err
152162
}
@@ -155,7 +165,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
155165

156166
// OpenStorageTrie opens the storage trie of an account.
157167
func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) {
158-
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.db)
168+
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.triedb)
159169
if err != nil {
160170
return nil, err
161171
}
@@ -218,5 +228,5 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
218228

219229
// TrieDB retrieves any intermediate trie-node caching layer.
220230
func (db *cachingDB) TrieDB() *trie.Database {
221-
return db.db
231+
return db.triedb
222232
}

core/state/iterator_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ import (
2121
"testing"
2222

2323
"github.com/XinFinOrg/XDPoSChain/common"
24-
"github.com/XinFinOrg/XDPoSChain/ethdb"
2524
)
2625

2726
// Tests that the node iterator indeed walks over the entire database contents.
2827
func TestNodeIteratorCoverage(t *testing.T) {
2928
// Create some arbitrary test state to iterate
30-
db, root, _ := makeTestState()
29+
db, sdb, root, _ := makeTestState()
30+
sdb.TrieDB().Commit(root, false)
3131

32-
state, err := New(root, db)
32+
state, err := New(root, sdb)
3333
if err != nil {
3434
t.Fatalf("failed to create state trie at %x: %v", root, err)
3535
}
@@ -42,19 +42,19 @@ func TestNodeIteratorCoverage(t *testing.T) {
4242
}
4343
// Cross check the iterated hashes and the database/nodepool content
4444
for hash := range hashes {
45-
if _, err = db.TrieDB().Node(hash); err != nil {
46-
_, err = db.ContractCode(common.Hash{}, hash)
45+
if _, err = sdb.TrieDB().Node(hash); err != nil {
46+
_, err = sdb.ContractCode(common.Hash{}, hash)
4747
}
4848
if err != nil {
4949
t.Errorf("failed to retrieve reported node %x", hash)
5050
}
5151
}
52-
for _, hash := range db.TrieDB().Nodes() {
52+
for _, hash := range sdb.TrieDB().Nodes() {
5353
if _, ok := hashes[hash]; !ok {
5454
t.Errorf("state entry not reported %x", hash)
5555
}
5656
}
57-
it := db.DiskDB().(ethdb.Database).NewIterator(nil, nil)
57+
it := db.NewIterator(nil, nil)
5858
for it.Next() {
5959
key := it.Key()
6060
if bytes.HasPrefix(key, []byte("secure-key-")) {

core/state/sync.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
)
2828

2929
// NewStateSync create a new state trie download scheduler.
30-
func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error) *trie.Sync {
30+
func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme trie.NodeScheme) *trie.Sync {
3131
// Register the storage slot callback if the external callback is specified.
3232
var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error
3333
if onLeaf != nil {
@@ -52,6 +52,6 @@ func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(k
5252
syncer.AddCodeEntry(common.BytesToHash(obj.CodeHash), path, parent, parentPath)
5353
return nil
5454
}
55-
syncer = trie.NewSync(root, database, onAccount)
55+
syncer = trie.NewSync(root, database, onAccount, scheme)
5656
return syncer
5757
}

0 commit comments

Comments
 (0)