diff --git a/core/blockchain.go b/core/blockchain.go index c97897cd70..e443f5d791 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -994,6 +994,15 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // and the current freezer limit to start nuking it's underflown. pivot = rawdb.ReadLastPivotNumber(bc.db) ) + const truncateInterval = 100 + truncateFn := func() { + // Truncate triedb to align the state histories with the current state. + if bc.triedb.Scheme() == rawdb.PathScheme { + if err := bc.triedb.TruncateHead(); err != nil { + log.Crit("Failed to truncate trie database", "err", err) + } + } + } updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) { // Rewind the blockchain, ensuring we don't end up with a stateless head // block. Note, depth equality is permitted to allow using SetHead as a @@ -1003,6 +1012,11 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha newHeadBlock, rootNumber = bc.rewindHead(header, root) rawdb.WriteHeadBlockHash(db, newHeadBlock.Hash()) + // The truncate costs a lot of time, no need to run for each block + if header.Number.Uint64()%truncateInterval == 0 { + truncateFn() + } + // Degrade the chain markers if they are explicitly reverted. // In theory we should update all in-memory markers in the // last step, however the direction of SetHead is from high @@ -1096,6 +1110,9 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha bc.blockCache.Purge() bc.txLookupCache.Purge() + // Truncate to align the state histories with the current state. + truncateFn() + // Clear safe block, finalized block if needed if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() { log.Warn("SetHead invalidated safe block") diff --git a/triedb/database.go b/triedb/database.go index 0d7397ba42..dfebd2d2c9 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -281,7 +281,7 @@ func (db *Database) Recover(target common.Hash) error { } // TruncateHead truncates all state histories in the freezer above the bottom state layer. -// This operation is only supported by path-based database It's typically used during +// This operation is only supported by path-based database. It's typically used during // state recovery to align the state histories with the current state. func (db *Database) TruncateHead() error { pdb, ok := db.backend.(*pathdb.Database)