diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 157d2e181d..ea021c3be2 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -57,6 +57,7 @@ const ( // Config includes all the configurations for pruning. type Config struct { Datadir string // The directory of the state database + Cachedir string // The directory of state clean cache BloomSize uint64 // The Megabytes of memory allocated to bloom-filter } @@ -261,7 +262,7 @@ func (p *Pruner) Prune(root common.Hash) error { } if stateBloomRoot != (common.Hash{}) { - return RecoverPruning(p.config.Datadir, p.db) + return RecoverPruning(p.config.Datadir, p.db, p.config.Cachedir) } // If the target state root is not specified, use the HEAD-127 as the // target. The reason for picking it is: @@ -286,8 +287,8 @@ func (p *Pruner) Prune(root common.Hash) error { // is the presence of root can indicate the presence of the // entire trie. if !rawdb.HasLegacyTrieNode(p.db, root) { - // The special case is for clique based networks(goerli - // and some other private networks), it's possible that two + // The special case is for clique based networks(goerli and + // some other private networks), it's possible that two // consecutive blocks will have same root. In this case snapshot // difflayer won't be created. So HEAD-127 may not paired with // head-127 layer. Instead the paired layer is higher than the @@ -324,6 +325,12 @@ func (p *Pruner) Prune(root common.Hash) error { log.Info("Selecting user-specified state as the pruning target", "root", root) } } + // Before start the pruning, delete the clean trie cache first. + // It's necessary otherwise in the next restart we will hit the + // deleted state root in the "clean cache" so that the incomplete + // state is picked for usage. + deleteCleanTrieCache(p.config.Cachedir) + // All the state roots of the middle layer should be forcibly pruned, // otherwise the dangling state will be left. middleRoots := make(map[common.Hash]struct{}) @@ -368,7 +375,7 @@ func (p *Pruner) Prune(root common.Hash) error { // pruning can be resumed. What's more if the bloom filter is constructed, the // pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left // in the disk. -func RecoverPruning(datadir string, db ethdb.Database) error { +func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) error { stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir) if err != nil { return err @@ -409,6 +416,12 @@ func RecoverPruning(datadir string, db ethdb.Database) error { log.Info("Loaded state bloom filter", "path", stateBloomPath) + // Before start the pruning, delete the clean trie cache first. + // It's necessary otherwise in the next restart we will hit the + // deleted state root in the "clean cache" so that the incomplete + // state is picked for usage. + deleteCleanTrieCache(trieCachePath) + // All the state roots of the middle layers should be forcibly pruned, // otherwise the dangling state will be left. var ( @@ -451,6 +464,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if err != nil { return err } + accIter, err := t.NodeIterator(nil) if err != nil { return err @@ -477,6 +491,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if err != nil { return err } + storageIter, err := storageTrie.NodeIterator(nil) if err != nil { return err @@ -536,3 +551,24 @@ func findBloomFilter(datadir string) (string, common.Hash, error) { return stateBloomPath, stateBloomRoot, nil } + +const warningLog = ` + +WARNING! + +The clean trie cache is not found. Please delete it by yourself after the +pruning. Remember don't start the Geth without deleting the clean trie cache +otherwise the entire database may be damaged! + +Check the command description "geth snapshot prune-state --help" for more details. +` + +func deleteCleanTrieCache(path string) { + if !common.FileExist(path) { + log.Warn(warningLog) + return + } + + os.RemoveAll(path) + log.Info("Deleted trie clean cache", "path", path) +}