From aa37bd063dd82edad32072171d8e34faf6694194 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 22 Sep 2025 14:48:18 +0800 Subject: [PATCH] cmd, tests: fix snapshot dump and export-preimages (#32650) Address #32646 --- cmd/geth/snapshot.go | 22 ++++---------- cmd/utils/cmd.go | 62 ++++++++++++++++++++++++++++++++++++++-- tests/state_test.go | 4 +-- tests/state_test_util.go | 2 +- 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 994cb149ce..7621dfa93c 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -561,17 +561,11 @@ func dumpState(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false) defer triedb.Close() - snapConfig := snapshot.Config{ - CacheSize: 256, - Recovery: false, - NoBuild: true, - AsyncBuild: false, - } - snaptree, err := snapshot.New(snapConfig, db, triedb, root) + stateIt, err := utils.NewStateIterator(triedb, db, root) if err != nil { return err } - accIt, err := snaptree.AccountIterator(root, common.BytesToHash(conf.Start)) + accIt, err := stateIt.AccountIterator(root, common.BytesToHash(conf.Start)) if err != nil { return err } @@ -605,7 +599,7 @@ func dumpState(ctx *cli.Context) error { if !conf.SkipStorage { da.Storage = make(map[common.Hash]string) - stIt, err := snaptree.StorageIterator(root, accIt.Hash(), common.Hash{}) + stIt, err := stateIt.StorageIterator(root, accIt.Hash(), common.Hash{}) if err != nil { return err } @@ -658,17 +652,11 @@ func snapshotExportPreimages(ctx *cli.Context) error { } root = headBlock.Root() } - snapConfig := snapshot.Config{ - CacheSize: 256, - Recovery: false, - NoBuild: true, - AsyncBuild: false, - } - snaptree, err := snapshot.New(snapConfig, chaindb, triedb, root) + stateIt, err := utils.NewStateIterator(triedb, chaindb, root) if err != nil { return err } - return utils.ExportSnapshotPreimages(chaindb, snaptree, ctx.Args().First(), root) + return utils.ExportSnapshotPreimages(chaindb, stateIt, ctx.Args().First(), root) } // checkAccount iterates the snap data layers, and looks up the given account diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index b332a060de..db7bd691d8 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -48,6 +48,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/triedb" "github.com/urfave/cli/v2" ) @@ -567,9 +568,64 @@ func ExportPreimages(db ethdb.Database, fn string) error { return nil } +// StateIterator is a temporary structure for traversing state in order. It serves +// as an aggregator for both path scheme and hash scheme implementations and should +// be removed once the hash scheme is fully deprecated. +type StateIterator struct { + scheme string + root common.Hash + triedb *triedb.Database + snapshots *snapshot.Tree +} + +// NewStateIterator constructs the state iterator with the specific root. +func NewStateIterator(triedb *triedb.Database, db ethdb.Database, root common.Hash) (*StateIterator, error) { + if triedb.Scheme() == rawdb.PathScheme { + return &StateIterator{ + scheme: rawdb.PathScheme, + root: root, + triedb: triedb, + }, nil + } + config := snapshot.Config{ + CacheSize: 256, + Recovery: false, + NoBuild: true, + AsyncBuild: false, + } + snapshots, err := snapshot.New(config, db, triedb, root) + if err != nil { + return nil, err + } + return &StateIterator{ + scheme: rawdb.HashScheme, + root: root, + triedb: triedb, + snapshots: snapshots, + }, nil +} + +// AccountIterator creates a new account iterator for the specified root hash and +// seeks to a starting account hash. +func (it *StateIterator) AccountIterator(root common.Hash, start common.Hash) (snapshot.AccountIterator, error) { + if it.scheme == rawdb.PathScheme { + return it.triedb.AccountIterator(root, start) + } + return it.snapshots.AccountIterator(root, start) +} + +// StorageIterator creates a new storage iterator for the specified root hash and +// account. The iterator will be moved to the specific start position. +func (it *StateIterator) StorageIterator(root common.Hash, accountHash common.Hash, start common.Hash) (snapshot.StorageIterator, error) { + if it.scheme == rawdb.PathScheme { + return it.triedb.StorageIterator(root, accountHash, start) + } + return it.snapshots.StorageIterator(root, accountHash, start) +} + // ExportSnapshotPreimages exports the preimages corresponding to the enumeration of // the snapshot for a given root. -func ExportSnapshotPreimages(chaindb ethdb.Database, snaptree *snapshot.Tree, fn string, root common.Hash) error { +func ExportSnapshotPreimages(chaindb ethdb.Database, stateIt *StateIterator, fn string, root common.Hash) error { log.Info("Exporting preimages", "file", fn) fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) @@ -602,7 +658,7 @@ func ExportSnapshotPreimages(chaindb ethdb.Database, snaptree *snapshot.Tree, fn ) go func() { defer close(hashCh) - accIt, err := snaptree.AccountIterator(root, common.Hash{}) + accIt, err := stateIt.AccountIterator(root, common.Hash{}) if err != nil { log.Error("Failed to create account iterator", "error", err) return @@ -619,7 +675,7 @@ func ExportSnapshotPreimages(chaindb ethdb.Database, snaptree *snapshot.Tree, fn hashCh <- hashAndPreimageSize{Hash: accIt.Hash(), Size: common.AddressLength} if acc.Root != (common.Hash{}) && acc.Root != types.EmptyRootHash { - stIt, err := snaptree.StorageIterator(root, accIt.Hash(), common.Hash{}) + stIt, err := stateIt.StorageIterator(root, accIt.Hash(), common.Hash{}) if err != nil { log.Error("Failed to create storage iterator", "error", err) return diff --git a/tests/state_test.go b/tests/state_test.go index 301bc3a7a9..f80bda4372 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -156,8 +156,8 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, state *StateTestState) { - if state.Snapshots != nil && state.StateDB != nil { - if _, err := state.Snapshots.Journal(state.StateDB.IntermediateRoot(false)); err != nil { + if state.TrieDB != nil && state.StateDB != nil { + if err := state.TrieDB.Journal(state.StateDB.IntermediateRoot(false)); err != nil { result = err return } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index ec7eec1f39..b8d3c4fb92 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -523,7 +523,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo // If snapshot is requested, initialize the snapshotter and use it in state. var snaps *snapshot.Tree - if snapshotter { + if snapshotter && scheme == rawdb.HashScheme { snapconfig := snapshot.Config{ CacheSize: 1, Recovery: false,