mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 13:21:37 +00:00
core: re-enable the legacy snapshot after sync (#35163)
This commit is contained in:
parent
6ed112aee0
commit
7d74166d3d
3 changed files with 73 additions and 9 deletions
|
|
@ -1194,10 +1194,13 @@ func (bc *BlockChain) SnapSyncComplete(hash common.Hash, isSnapV2 bool) error {
|
|||
return fmt.Errorf("non existent state [%x..]", root[:4])
|
||||
}
|
||||
|
||||
// The legacy snapshot tree needs to be wiped and rebuilt from the trie
|
||||
// after a snap/1 sync.
|
||||
if !isSnapV2 && bc.snaps != nil {
|
||||
bc.snaps.Rebuild(root)
|
||||
// The legacy snapshot tree (hash scheme only) was persistently disabled
|
||||
// before the sync, re-enables it explicitly.
|
||||
//
|
||||
// For snap/2 the downloaded flat state is already complete and root-verified,
|
||||
// so the background generation is unnecessary.
|
||||
if bc.snaps != nil {
|
||||
bc.snaps.Rebuild(root, !isSnapV2)
|
||||
}
|
||||
|
||||
// If all checks out, manually set the head block.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
|
|
@ -721,3 +722,40 @@ func TestRecoverSnapshotFromWipingCrash(t *testing.T) {
|
|||
test.teardown()
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapSyncCompleteRebuildsSnapshot verifies that completing a snap sync
|
||||
// re-enables the legacy snapshot tree on the hash scheme for both syncer
|
||||
// versions: SnapSyncStart persistently disables the tree, and only the
|
||||
// rebuild on completion clears the marker again.
|
||||
func TestSnapSyncCompleteRebuildsSnapshot(t *testing.T) {
|
||||
for _, isSnapV2 := range []bool{false, true} {
|
||||
_, _, chain, err := newCanonical(ethash.NewFaker(), 8, true, rawdb.HashScheme)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create chain: %v", err)
|
||||
}
|
||||
if err := chain.SnapSyncStart(); err != nil {
|
||||
t.Fatalf("failed to start snap sync: %v", err)
|
||||
}
|
||||
if !rawdb.ReadSnapshotDisabled(chain.db) {
|
||||
t.Fatal("snapshot should be disabled during snap sync")
|
||||
}
|
||||
head := chain.CurrentBlock()
|
||||
if err := chain.SnapSyncComplete(head.Hash(), isSnapV2); err != nil {
|
||||
t.Fatalf("failed to complete snap sync (v2=%v): %v", isSnapV2, err)
|
||||
}
|
||||
if rawdb.ReadSnapshotDisabled(chain.db) {
|
||||
t.Fatalf("snapshot should be re-enabled after snap sync completion (v2=%v)", isSnapV2)
|
||||
}
|
||||
// snap/2 adopts the flat state without regeneration, so the snapshot
|
||||
// must be immediately usable; snap/1 schedules a background rebuild
|
||||
// instead (which may or may not have finished, no assertion there).
|
||||
if isSnapV2 {
|
||||
it, err := chain.snaps.AccountIterator(head.Root, common.Hash{})
|
||||
if err != nil {
|
||||
t.Fatalf("adopted snapshot not immediately usable: %v", err)
|
||||
}
|
||||
it.Release()
|
||||
}
|
||||
chain.Stop()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/VictoriaMetrics/fastcache"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -213,7 +214,7 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo
|
|||
if err != nil {
|
||||
log.Warn("Failed to load snapshot", "err", err)
|
||||
if !config.NoBuild {
|
||||
snap.Rebuild(root)
|
||||
snap.Rebuild(root, true)
|
||||
return snap, nil
|
||||
}
|
||||
return nil, err // Bail out the error, don't rebuild automatically.
|
||||
|
|
@ -683,10 +684,12 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) {
|
|||
return base, nil
|
||||
}
|
||||
|
||||
// Rebuild wipes all available snapshot data from the persistent database and
|
||||
// discard all caches and diff layers. Afterwards, it starts a new snapshot
|
||||
// generator with the given root hash.
|
||||
func (t *Tree) Rebuild(root common.Hash) {
|
||||
// Rebuild discards all caches and diff layers and re-enables the snapshot
|
||||
// feature. With generate set, it starts a new snapshot generator with the
|
||||
// given root hash, wiping and regenerating the persistent flat state in the
|
||||
// background. Without it, the on-disk flat state is adopted as the fully
|
||||
// generated disk layer directly.
|
||||
func (t *Tree) Rebuild(root common.Hash, generate bool) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
|
|
@ -715,6 +718,26 @@ func (t *Tree) Rebuild(root common.Hash) {
|
|||
panic(fmt.Sprintf("unknown layer type: %T", layer))
|
||||
}
|
||||
}
|
||||
// Adopt the existing flat state as the generated disk layer if
|
||||
// regeneration was not requested.
|
||||
if !generate {
|
||||
batch := t.diskdb.NewBatch()
|
||||
rawdb.WriteSnapshotRoot(batch, root)
|
||||
journalProgress(batch, nil, nil)
|
||||
if err := batch.Write(); err != nil {
|
||||
log.Crit("Failed to write snapshot completion marker", "err", err)
|
||||
}
|
||||
log.Info("Adopted state snapshot", "root", root)
|
||||
t.layers = map[common.Hash]snapshot{
|
||||
root: &diskLayer{
|
||||
diskdb: t.diskdb,
|
||||
triedb: t.triedb,
|
||||
cache: fastcache.New(t.config.CacheSize * 1024 * 1024),
|
||||
root: root,
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
// Start generating a new snapshot from scratch on a background thread. The
|
||||
// generator will run a wiper first if there's not one running right now.
|
||||
log.Info("Rebuilding state snapshot")
|
||||
|
|
|
|||
Loading…
Reference in a new issue