Skip to content

Commit 985a84e

Browse files
committed
core, triedb/pathdb: integrate state snapshot inth pathdb
1 parent 341647f commit 985a84e

26 files changed

+2577
-207
lines changed

core/blockchain.go

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,13 @@ func (c *CacheConfig) triedbConfig(isVerkle bool) *triedb.Config {
160160
}
161161
if c.StateScheme == rawdb.PathScheme {
162162
config.PathDB = &pathdb.Config{
163-
StateHistory: c.StateHistory,
164-
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
163+
StateHistory: c.StateHistory,
164+
TrieCleanSize: c.TrieCleanLimit * 1024 * 1024,
165+
StateCleanSize: c.SnapshotLimit * 1024 * 1024,
166+
167+
// TODO(rjl493456442): The write buffer represents the memory limit used
168+
// for flushing both trie data and state data to disk. The config name
169+
// should be updated to eliminate the confusion.
165170
WriteBufferSize: c.TrieDirtyLimit * 1024 * 1024,
166171
}
167172
}
@@ -349,11 +354,14 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
349354
// Do nothing here until the state syncer picks it up.
350355
log.Info("Genesis state is missing, wait state sync")
351356
} else {
352-
// Head state is missing, before the state recovery, find out the
353-
// disk layer point of snapshot(if it's enabled). Make sure the
354-
// rewound point is lower than disk layer.
357+
// Head state is missing, before the state recovery, find out the disk
358+
// layer point of snapshot(if it's enabled). Make sure the rewound point
359+
// is lower than disk layer.
360+
//
361+
// Note it's unnecessary in path mode which always keep trie data and
362+
// state data consistent.
355363
var diskRoot common.Hash
356-
if bc.cacheConfig.SnapshotLimit > 0 {
364+
if bc.cacheConfig.SnapshotLimit > 0 && bc.cacheConfig.StateScheme == rawdb.HashScheme {
357365
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
358366
}
359367
if diskRoot != (common.Hash{}) {
@@ -426,15 +434,39 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
426434
bc.logger.OnGenesisBlock(bc.genesisBlock, alloc)
427435
}
428436
}
437+
bc.setupSnapshot()
438+
439+
// Rewind the chain in case of an incompatible config upgrade.
440+
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
441+
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
442+
if compat.RewindToTime > 0 {
443+
bc.SetHeadWithTimestamp(compat.RewindToTime)
444+
} else {
445+
bc.SetHead(compat.RewindToBlock)
446+
}
447+
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
448+
}
449+
450+
// Start tx indexer if it's enabled.
451+
if txLookupLimit != nil {
452+
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
453+
}
454+
return bc, nil
455+
}
429456

457+
func (bc *BlockChain) setupSnapshot() {
458+
// Short circuit if the chain is established with path scheme, as the
459+
// state snapshot has been integrated into path database natively.
460+
if bc.cacheConfig.StateScheme == rawdb.PathScheme {
461+
return
462+
}
430463
// Load any existing snapshot, regenerating it if loading failed
431464
if bc.cacheConfig.SnapshotLimit > 0 {
432465
// If the chain was rewound past the snapshot persistent layer (causing
433466
// a recovery block number to be persisted to disk), check if we're still
434467
// in recovery mode and in that case, don't invalidate the snapshot on a
435468
// head mismatch.
436469
var recover bool
437-
438470
head := bc.CurrentBlock()
439471
if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.Number.Uint64() {
440472
log.Warn("Enabling snapshot recovery", "chainhead", head.Number, "diskbase", *layer)
@@ -451,23 +483,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
451483
// Re-initialize the state database with snapshot
452484
bc.statedb = state.NewDatabase(bc.triedb, bc.snaps)
453485
}
454-
455-
// Rewind the chain in case of an incompatible config upgrade.
456-
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
457-
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
458-
if compat.RewindToTime > 0 {
459-
bc.SetHeadWithTimestamp(compat.RewindToTime)
460-
} else {
461-
bc.SetHead(compat.RewindToBlock)
462-
}
463-
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
464-
}
465-
466-
// Start tx indexer if it's enabled.
467-
if txLookupLimit != nil {
468-
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
469-
}
470-
return bc, nil
471486
}
472487

473488
// empty returns an indicator whether the blockchain is empty.

core/blockchain_repair_test.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,7 +1791,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
17911791
}
17921792
)
17931793
defer engine.Close()
1794-
if snapshots {
1794+
if snapshots && scheme == rawdb.HashScheme {
17951795
config.SnapshotLimit = 256
17961796
config.SnapshotWait = true
17971797
}
@@ -1820,7 +1820,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
18201820
if err := chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false); err != nil {
18211821
t.Fatalf("Failed to flush trie state: %v", err)
18221822
}
1823-
if snapshots {
1823+
if snapshots && scheme == rawdb.HashScheme {
18241824
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
18251825
t.Fatalf("Failed to flatten snapshots: %v", err)
18261826
}
@@ -1952,8 +1952,10 @@ func testIssue23496(t *testing.T, scheme string) {
19521952
if _, err := chain.InsertChain(blocks[1:2]); err != nil {
19531953
t.Fatalf("Failed to import canonical chain start: %v", err)
19541954
}
1955-
if err := chain.snaps.Cap(blocks[1].Root(), 0); err != nil {
1956-
t.Fatalf("Failed to flatten snapshots: %v", err)
1955+
if scheme == rawdb.HashScheme {
1956+
if err := chain.snaps.Cap(blocks[1].Root(), 0); err != nil {
1957+
t.Fatalf("Failed to flatten snapshots: %v", err)
1958+
}
19571959
}
19581960

19591961
// Insert block B3 and commit the state into disk
@@ -1997,15 +1999,21 @@ func testIssue23496(t *testing.T, scheme string) {
19971999
}
19982000
expHead := uint64(1)
19992001
if scheme == rawdb.PathScheme {
2000-
expHead = uint64(2)
2002+
expHead = uint64(3)
20012003
}
20022004
if head := chain.CurrentBlock(); head.Number.Uint64() != expHead {
20032005
t.Errorf("Head block mismatch: have %d, want %d", head.Number, expHead)
20042006
}
2005-
2006-
// Reinsert B2-B4
2007-
if _, err := chain.InsertChain(blocks[1:]); err != nil {
2008-
t.Fatalf("Failed to import canonical chain tail: %v", err)
2007+
if scheme == rawdb.PathScheme {
2008+
// Reinsert B3-B4
2009+
if _, err := chain.InsertChain(blocks[2:]); err != nil {
2010+
t.Fatalf("Failed to import canonical chain tail: %v", err)
2011+
}
2012+
} else {
2013+
// Reinsert B2-B4
2014+
if _, err := chain.InsertChain(blocks[1:]); err != nil {
2015+
t.Fatalf("Failed to import canonical chain tail: %v", err)
2016+
}
20092017
}
20102018
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
20112019
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
@@ -2016,7 +2024,9 @@ func testIssue23496(t *testing.T, scheme string) {
20162024
if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(4) {
20172025
t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(4))
20182026
}
2019-
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
2020-
t.Error("Failed to regenerate the snapshot of known state")
2027+
if scheme == rawdb.HashScheme {
2028+
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
2029+
t.Error("Failed to regenerate the snapshot of known state")
2030+
}
20212031
}
20222032
}

core/blockchain_sethead_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2023,7 +2023,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
20232023
}
20242024
if tt.commitBlock > 0 {
20252025
chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false)
2026-
if snapshots {
2026+
if snapshots && scheme == rawdb.HashScheme {
20272027
if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil {
20282028
t.Fatalf("Failed to flatten snapshots: %v", err)
20292029
}

core/blockchain_snapshot_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
105105
if basic.commitBlock > 0 && basic.commitBlock == point {
106106
chain.TrieDB().Commit(blocks[point-1].Root(), false)
107107
}
108-
if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
108+
if basic.snapshotBlock > 0 && basic.snapshotBlock == point && basic.scheme == rawdb.HashScheme {
109109
// Flushing the entire snap tree into the disk, the
110110
// relevant (a) snapshot root and (b) snapshot generator
111111
// will be persisted atomically.
@@ -149,13 +149,17 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [
149149
block := chain.GetBlockByNumber(basic.expSnapshotBottom)
150150
if block == nil {
151151
t.Errorf("The corresponding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
152-
} else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) {
153-
t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot())
152+
} else if basic.scheme == rawdb.HashScheme {
153+
if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) {
154+
t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot())
155+
}
154156
}
155157

156158
// Check the snapshot, ensure it's integrated
157-
if err := chain.snaps.Verify(block.Root()); err != nil {
158-
t.Errorf("The disk layer is not integrated %v", err)
159+
if basic.scheme == rawdb.HashScheme {
160+
if err := chain.snaps.Verify(block.Root()); err != nil {
161+
t.Errorf("The disk layer is not integrated %v", err)
162+
}
159163
}
160164
}
161165

@@ -570,7 +574,7 @@ func TestHighCommitCrashWithNewSnapshot(t *testing.T) {
570574
for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} {
571575
expHead := uint64(0)
572576
if scheme == rawdb.PathScheme {
573-
expHead = uint64(4)
577+
expHead = uint64(6)
574578
}
575579
test := &crashSnapshotTest{
576580
snapshotTestBasic{

core/state/database.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
186186
readers = append(readers, newFlatReader(snap))
187187
}
188188
} else {
189-
// If standalone state snapshot is not available, try to construct
190-
// the state reader with database.
189+
// If standalone state snapshot is not available (path scheme
190+
// or the state snapshot is explicitly disabled in hash mode),
191+
// try to construct the state reader with database.
191192
reader, err := db.triedb.StateReader(stateRoot)
192193
if err == nil {
193194
readers = append(readers, newFlatReader(reader)) // state reader is optional

core/state/snapshot/generate_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ func newHelper(scheme string) *testHelper {
166166
diskdb := rawdb.NewMemoryDatabase()
167167
config := &triedb.Config{}
168168
if scheme == rawdb.PathScheme {
169-
config.PathDB = &pathdb.Config{} // disable caching
169+
config.PathDB = &pathdb.Config{
170+
SnapshotNoBuild: true,
171+
} // disable caching
170172
} else {
171173
config.HashDB = &hashdb.Config{} // disable caching
172174
}

core/state/statedb_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,8 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
979979
)
980980
if scheme == rawdb.PathScheme {
981981
tdb = triedb.NewDatabase(memDb, &triedb.Config{PathDB: &pathdb.Config{
982-
CleanCacheSize: 0,
982+
TrieCleanSize: 0,
983+
StateCleanSize: 0,
983984
WriteBufferSize: 0,
984985
}}) // disable caching
985986
} else {

eth/handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/ethereum/go-ethereum/common"
2828
"github.com/ethereum/go-ethereum/core"
2929
"github.com/ethereum/go-ethereum/core/forkid"
30+
"github.com/ethereum/go-ethereum/core/rawdb"
3031
"github.com/ethereum/go-ethereum/core/txpool"
3132
"github.com/ethereum/go-ethereum/core/types"
3233
"github.com/ethereum/go-ethereum/crypto"
@@ -175,7 +176,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
175176
}
176177
}
177178
// If snap sync is requested but snapshots are disabled, fail loudly
178-
if h.snapSync.Load() && config.Chain.Snapshots() == nil {
179+
if h.snapSync.Load() && (config.Chain.Snapshots() == nil && config.Chain.TrieDB().Scheme() == rawdb.HashScheme) {
179180
return nil, errors.New("snap sync not supported with snapshots disabled")
180181
}
181182
// Construct the downloader (long sync)

eth/protocols/snap/handler.go

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323

2424
"github.com/ethereum/go-ethereum/common"
2525
"github.com/ethereum/go-ethereum/core"
26+
"github.com/ethereum/go-ethereum/core/rawdb"
27+
"github.com/ethereum/go-ethereum/core/state/snapshot"
2628
"github.com/ethereum/go-ethereum/core/types"
2729
"github.com/ethereum/go-ethereum/log"
2830
"github.com/ethereum/go-ethereum/metrics"
@@ -31,6 +33,7 @@ import (
3133
"github.com/ethereum/go-ethereum/p2p/enr"
3234
"github.com/ethereum/go-ethereum/trie"
3335
"github.com/ethereum/go-ethereum/trie/trienode"
36+
"github.com/ethereum/go-ethereum/triedb/database"
3437
)
3538

3639
const (
@@ -279,7 +282,16 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac
279282
if err != nil {
280283
return nil, nil
281284
}
282-
it, err := chain.Snapshots().AccountIterator(req.Root, req.Origin)
285+
// Temporary solution: using the snapshot interface for both cases.
286+
// This can be removed once the hash scheme is deprecated.
287+
var it snapshot.AccountIterator
288+
if chain.TrieDB().Scheme() == rawdb.HashScheme {
289+
// The snapshot is assumed to be available in hash mode if
290+
// the SNAP protocol is enabled.
291+
it, err = chain.Snapshots().AccountIterator(req.Root, req.Origin)
292+
} else {
293+
it, err = chain.TrieDB().AccountIterator(req.Root, req.Origin)
294+
}
283295
if err != nil {
284296
return nil, nil
285297
}
@@ -359,7 +371,19 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP
359371
limit, req.Limit = common.BytesToHash(req.Limit), nil
360372
}
361373
// Retrieve the requested state and bail out if non existent
362-
it, err := chain.Snapshots().StorageIterator(req.Root, account, origin)
374+
var (
375+
err error
376+
it snapshot.StorageIterator
377+
)
378+
// Temporary solution: using the snapshot interface for both cases.
379+
// This can be removed once the hash scheme is deprecated.
380+
if chain.TrieDB().Scheme() == rawdb.HashScheme {
381+
// The snapshot is assumed to be available in hash mode if
382+
// the SNAP protocol is enabled.
383+
it, err = chain.Snapshots().StorageIterator(req.Root, account, origin)
384+
} else {
385+
it, err = chain.TrieDB().StorageIterator(req.Root, account, origin)
386+
}
363387
if err != nil {
364388
return nil, nil
365389
}
@@ -479,8 +503,15 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s
479503
// We don't have the requested state available, bail out
480504
return nil, nil
481505
}
482-
// The 'snap' might be nil, in which case we cannot serve storage slots.
483-
snap := chain.Snapshots().Snapshot(req.Root)
506+
// The 'reader' might be nil, in which case we cannot serve storage slots
507+
// via snapshot.
508+
var reader database.StateReader
509+
if chain.Snapshots() != nil {
510+
reader = chain.Snapshots().Snapshot(req.Root)
511+
}
512+
if reader == nil {
513+
reader, _ = triedb.StateReader(req.Root)
514+
}
484515
// Retrieve trie nodes until the packet size limit is reached
485516
var (
486517
nodes [][]byte
@@ -505,8 +536,9 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s
505536

506537
default:
507538
var stRoot common.Hash
539+
508540
// Storage slots requested, open the storage trie and retrieve from there
509-
if snap == nil {
541+
if reader == nil {
510542
// We don't have the requested state snapshotted yet (or it is stale),
511543
// but can look up the account via the trie instead.
512544
account, err := accTrie.GetAccountByHash(common.BytesToHash(pathset[0]))
@@ -516,7 +548,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s
516548
}
517549
stRoot = account.Root
518550
} else {
519-
account, err := snap.Account(common.BytesToHash(pathset[0]))
551+
account, err := reader.Account(common.BytesToHash(pathset[0]))
520552
loads++ // always account database reads, even for failures
521553
if err != nil || account == nil {
522554
break

eth/protocols/snap/sync_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,5 +1962,5 @@ func newDbConfig(scheme string) *triedb.Config {
19621962
if scheme == rawdb.HashScheme {
19631963
return &triedb.Config{}
19641964
}
1965-
return &triedb.Config{PathDB: pathdb.Defaults}
1965+
return &triedb.Config{PathDB: &pathdb.Config{SnapshotNoBuild: true}}
19661966
}

tests/block_test_util.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,10 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t
187187
}
188188
// Cross-check the snapshot-to-hash against the trie hash
189189
if snapshotter {
190-
if err := chain.Snapshots().Verify(chain.CurrentBlock().Root); err != nil {
191-
return err
190+
if chain.Snapshots() != nil {
191+
if err := chain.Snapshots().Verify(chain.CurrentBlock().Root); err != nil {
192+
return err
193+
}
192194
}
193195
}
194196
return t.validateImportedHeaders(chain, validBlocks)

0 commit comments

Comments
 (0)