eth: make traceChain avoid OOM on long-running tracing (#23736)
This PR changes long-running chain tracing, so that it at some points releases the memory trie db, and switch over to a fresh disk-backed trie.
This commit is contained in:
committed by
GitHub
parent
53b94f135a
commit
3bbeb94c1c
@ -35,7 +35,17 @@ import (
|
||||
// are attempted to be reexecuted to generate the desired state. The optional
|
||||
// base layer statedb can be passed then it's regarded as the statedb of the
|
||||
// parent block.
|
||||
func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (statedb *state.StateDB, err error) {
|
||||
// Parameters:
|
||||
// - block: The block for which we want the state (== state at the stateRoot of the parent)
|
||||
// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state
|
||||
// - base: If the caller is tracing multiple blocks, the caller can provide the parent state
|
||||
// continuously from the callsite.
|
||||
// - checklive: if true, then the live 'blockchain' state database is used. If the caller want to
|
||||
// perform Commit or other 'save-to-disk' changes, this should be set to false to avoid
|
||||
// storing trash persistently
|
||||
// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is provided,
|
||||
// it would be preferrable to start from a fresh state, if we have it on disk.
|
||||
func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
|
||||
var (
|
||||
current *types.Block
|
||||
database state.Database
|
||||
@ -50,6 +60,15 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state
|
||||
}
|
||||
}
|
||||
if base != nil {
|
||||
if preferDisk {
|
||||
// Create an ephemeral trie.Database for isolating the live one. Otherwise
|
||||
// the internal junks created by tracing will be persisted into the disk.
|
||||
database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16})
|
||||
if statedb, err = state.New(block.Root(), database, nil); err == nil {
|
||||
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
|
||||
return statedb, nil
|
||||
}
|
||||
}
|
||||
// The optional base statedb is given, mark the start point as parent block
|
||||
statedb, database, report = base, base.Database(), false
|
||||
current = eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
@ -152,7 +171,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
|
||||
}
|
||||
// Lookup the statedb of parent block from the live database,
|
||||
// otherwise regenerate it on the flight.
|
||||
statedb, err := eth.stateAtBlock(parent, reexec, nil, true)
|
||||
statedb, err := eth.stateAtBlock(parent, reexec, nil, true, false)
|
||||
if err != nil {
|
||||
return nil, vm.BlockContext{}, nil, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user