diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 62b3b2f397..3698de3310 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -353,7 +353,7 @@ var ( } StateSchemeFlag = &cli.StringFlag{ Name: "state.scheme", - Usage: "Scheme to use for storing ethereum state ('hash' or 'path')", + Usage: "Scheme to use for storing ethereum state ('hash', 'path', 'version')", Category: flags.StateCategory, } PathDBSyncFlag = &cli.BoolFlag{ @@ -1953,11 +1953,16 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(StateHistoryFlag.Name) { cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name) } - scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme) - if err != nil { - Fatalf("%v", err) + if ctx.String(StateSchemeFlag.Name) != rawdb.VersionScheme { + scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme) + if err != nil { + Fatalf("%v", err) + } + cfg.StateScheme = scheme + } else { + cfg.StateScheme = rawdb.VersionScheme } - cfg.StateScheme = scheme + // Parse transaction history flag, if user is still using legacy config // file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'. if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit { diff --git a/core/blockchain.go b/core/blockchain.go index e19c73dc5a..5119129596 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1169,6 +1169,9 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // SnapSyncCommitHead sets the current head block to the one defined by the hash // irrelevant what the chain contents were prior. func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { + if bc.triedb.Scheme() == rawdb.VersionScheme { + panic("version db not support snap sync") + } // Make sure that both the block as well at its state trie exists block := bc.GetBlockByHash(hash) if block == nil { @@ -1380,48 +1383,50 @@ func (bc *BlockChain) Stop() { } bc.snaps.Release() } - if bc.triedb.Scheme() == rawdb.PathScheme { - // Ensure that the in-memory trie nodes are journaled to disk properly. - if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil { - log.Info("Failed to journal in-memory trie nodes", "err", err) - } - } else { - // Ensure the state of a recent block is also stored to disk before exiting. - // We're writing three different states to catch different restart scenarios: - // - HEAD: So we don't need to reprocess any blocks in the general case - // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle - // - HEAD-127: So we have a hard limit on the number of blocks reexecuted - if !bc.cacheConfig.TrieDirtyDisabled { - triedb := bc.triedb - var once sync.Once - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { - if number := bc.CurrentBlock().Number.Uint64(); number > offset { - recent := bc.GetBlockByNumber(number - offset) - log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) - if err := triedb.Commit(recent.Root(), true); err != nil { + if bc.triedb.Scheme() != rawdb.VersionScheme { + if bc.triedb.Scheme() == rawdb.PathScheme { + // Ensure that the in-memory trie nodes are journaled to disk properly. + if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil { + log.Info("Failed to journal in-memory trie nodes", "err", err) + } + } else { + // Ensure the state of a recent block is also stored to disk before exiting. + // We're writing three different states to catch different restart scenarios: + // - HEAD: So we don't need to reprocess any blocks in the general case + // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle + // - HEAD-127: So we have a hard limit on the number of blocks reexecuted + if !bc.cacheConfig.TrieDirtyDisabled { + triedb := bc.triedb + var once sync.Once + for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + if number := bc.CurrentBlock().Number.Uint64(); number > offset { + recent := bc.GetBlockByNumber(number - offset) + log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) + if err := triedb.Commit(recent.Root(), true); err != nil { + log.Error("Failed to commit recent state trie", "err", err) + } else { + rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64()) + once.Do(func() { + rawdb.WriteHeadBlockHash(bc.db.BlockStore(), recent.Hash()) + }) + } + } + } + + if snapBase != (common.Hash{}) { + log.Info("Writing snapshot state to disk", "root", snapBase) + if err := triedb.Commit(snapBase, true); err != nil { log.Error("Failed to commit recent state trie", "err", err) } else { - rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64()) - once.Do(func() { - rawdb.WriteHeadBlockHash(bc.db.BlockStore(), recent.Hash()) - }) + rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64()) } } - } - - if snapBase != (common.Hash{}) { - log.Info("Writing snapshot state to disk", "root", snapBase) - if err := triedb.Commit(snapBase, true); err != nil { - log.Error("Failed to commit recent state trie", "err", err) - } else { - rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64()) + for !bc.triegc.Empty() { + triedb.Dereference(bc.triegc.PopItem()) + } + if _, size, _, _ := triedb.Size(); size != 0 { + log.Error("Dangling trie nodes after full cleanup") } - } - for !bc.triegc.Empty() { - triedb.Dereference(bc.triegc.PopItem()) - } - if _, size, _, _ := triedb.Size(); size != 0 { - log.Error("Dangling trie nodes after full cleanup") } } } @@ -1817,7 +1822,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // If node is running in path mode, skip explicit gc operation // which is unnecessary in this mode. - if bc.triedb.Scheme() == rawdb.PathScheme { + if bc.triedb.Scheme() != rawdb.HashScheme { return nil } diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index 7c56696223..02fbda8bdd 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -316,7 +316,7 @@ func ReadStateScheme(db ethdb.Reader) string { // ValidateStateScheme used to check state scheme whether is valid. // Valid state scheme: hash and path. func ValidateStateScheme(stateScheme string) bool { - if stateScheme == HashScheme || stateScheme == PathScheme { + if stateScheme == HashScheme || stateScheme == PathScheme || stateScheme == VersionScheme { return true } return false diff --git a/core/state/statedb.go b/core/state/statedb.go index a26a541f95..f7a43b2d65 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -175,6 +175,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) if db.Scheme() == rawdb.VersionScheme && snaps != nil { panic("statedb snapshot must be nil in version db.") } + log.Info("new statedb with type", "scheme", db.Scheme()) // clean up previous traces db.Reset()