mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-17 20:31:35 +00:00
eth/tracers: remove reexec from tracer config and internal plumbing
reexec was a geth-specific, hash-scheme-only implementation detail that let callers cap how many ancestor blocks the node would re-execute to reconstruct missing historical state. It was never part of the execution API spec, and path-scheme nodes ignored it entirely. Remove Reexec from TraceConfig and StdTraceConfig so it is no longer accepted over JSON-RPC. Drop the parameter from the Backend interface (StateAtBlock, StateAtTransaction) and all the way down through EthAPIBackend and state_accessor. A local constant reexecLimit = 128 replaces the old defaultTraceReexec inside hashState, preserving the existing non-archive hash-scheme behaviour.
This commit is contained in:
parent
c787778ed4
commit
82b5b7337a
5 changed files with 31 additions and 61 deletions
|
|
@ -484,12 +484,12 @@ func (b *EthAPIBackend) CurrentHeader() *types.Header {
|
||||||
return b.eth.blockchain.CurrentHeader()
|
return b.eth.blockchain.CurrentHeader()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
|
func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
return b.eth.stateAtBlock(ctx, block, base, readOnly, preferDisk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
return b.eth.stateAtTransaction(ctx, block, txIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) RPCTxSyncDefaultTimeout() time.Duration {
|
func (b *EthAPIBackend) RPCTxSyncDefaultTimeout() time.Duration {
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.Block
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash)
|
return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash)
|
||||||
}
|
}
|
||||||
_, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0)
|
_, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StorageRangeResult{}, err
|
return StorageRangeResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,11 @@ import (
|
||||||
// for releasing state.
|
// for releasing state.
|
||||||
var noopReleaser = tracers.StateReleaseFunc(func() {})
|
var noopReleaser = tracers.StateReleaseFunc(func() {})
|
||||||
|
|
||||||
func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
|
// reexecLimit is the maximum number of ancestor blocks to walk back when
|
||||||
|
// attempting to reconstruct missing historical state for hash-scheme nodes.
|
||||||
|
const reexecLimit = uint64(128)
|
||||||
|
|
||||||
|
func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
|
||||||
var (
|
var (
|
||||||
current *types.Block
|
current *types.Block
|
||||||
database state.Database
|
database state.Database
|
||||||
|
|
@ -99,7 +103,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Database does not have the state for the given block, try to regenerate
|
// Database does not have the state for the given block, try to regenerate
|
||||||
for i := uint64(0); i < reexec; i++ {
|
for i := uint64(0); i < reexecLimit; i++ {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +124,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case *trie.MissingNodeError:
|
case *trie.MissingNodeError:
|
||||||
return nil, nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec)
|
return nil, nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexecLimit)
|
||||||
default:
|
default:
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -190,10 +194,9 @@ func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateAtBlock retrieves the state database associated with a certain block.
|
// stateAtBlock retrieves the state database associated with a certain block.
|
||||||
// If no state is locally available for the given block, a number of blocks
|
// If no state is locally available for the given block, up to reexecLimit ancestor
|
||||||
// are attempted to be reexecuted to generate the desired state. The optional
|
// blocks are reexecuted to generate the desired state. The optional base layer
|
||||||
// base layer statedb can be provided which is regarded as the statedb of the
|
// statedb can be provided which is regarded as the statedb of the parent block.
|
||||||
// parent block.
|
|
||||||
//
|
//
|
||||||
// An additional release function will be returned if the requested state is
|
// An additional release function will be returned if the requested state is
|
||||||
// available. Release is expected to be invoked when the returned state is no
|
// available. Release is expected to be invoked when the returned state is no
|
||||||
|
|
@ -202,7 +205,6 @@ func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), erro
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// - block: The block for which we want the state(state = block.Root)
|
// - block: The block for which we want the state(state = block.Root)
|
||||||
// - 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
|
// - base: If the caller is tracing multiple blocks, the caller can provide the parent
|
||||||
// state continuously from the callsite.
|
// state continuously from the callsite.
|
||||||
// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should
|
// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should
|
||||||
|
|
@ -211,9 +213,9 @@ func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), erro
|
||||||
// - preferDisk: This arg can be used by the caller to signal that even though the 'base' is
|
// - preferDisk: This arg can be used by the caller to signal that even though the 'base' is
|
||||||
// provided, it would be preferable to start from a fresh state, if we have it
|
// provided, it would be preferable to start from a fresh state, if we have it
|
||||||
// on disk.
|
// on disk.
|
||||||
func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
|
func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
|
||||||
if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme {
|
if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme {
|
||||||
return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk)
|
return eth.hashState(ctx, block, base, readOnly, preferDisk)
|
||||||
}
|
}
|
||||||
return eth.pathState(block)
|
return eth.pathState(block)
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +227,7 @@ func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexe
|
||||||
// function will return the state of block after the pre-block operations have
|
// function will return the state of block after the pre-block operations have
|
||||||
// been completed (e.g. updating system contracts), but before post-block
|
// been completed (e.g. updating system contracts), but before post-block
|
||||||
// operations are completed (e.g. processing withdrawals).
|
// operations are completed (e.g. processing withdrawals).
|
||||||
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
// Short circuit if it's genesis block.
|
// Short circuit if it's genesis block.
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||||
|
|
@ -237,7 +239,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
}
|
}
|
||||||
// Lookup the statedb of parent block from the live database,
|
// Lookup the statedb of parent block from the live database,
|
||||||
// otherwise regenerate it on the flight.
|
// otherwise regenerate it on the flight.
|
||||||
statedb, release, err := eth.stateAtBlock(ctx, parent, reexec, nil, true, false)
|
statedb, release, err := eth.stateAtBlock(ctx, parent, nil, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, err
|
return nil, vm.BlockContext{}, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,6 @@ const (
|
||||||
// by default before being forcefully aborted.
|
// by default before being forcefully aborted.
|
||||||
defaultTraceTimeout = 5 * time.Second
|
defaultTraceTimeout = 5 * time.Second
|
||||||
|
|
||||||
// defaultTraceReexec is the number of blocks the tracer is willing to go back
|
|
||||||
// and reexecute to produce missing historical state necessary to run a specific
|
|
||||||
// trace.
|
|
||||||
defaultTraceReexec = uint64(128)
|
|
||||||
|
|
||||||
// defaultTracechainMemLimit is the size of the triedb, at which traceChain
|
// defaultTracechainMemLimit is the size of the triedb, at which traceChain
|
||||||
// switches over and tries to use a disk-backed database instead of building
|
// switches over and tries to use a disk-backed database instead of building
|
||||||
// on top of memory.
|
// on top of memory.
|
||||||
|
|
@ -89,8 +84,8 @@ type Backend interface {
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
ChainDb() ethdb.Database
|
ChainDb() ethdb.Database
|
||||||
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
StateAtBlock(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
||||||
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
||||||
|
|
@ -156,7 +151,6 @@ type TraceConfig struct {
|
||||||
*logger.Config
|
*logger.Config
|
||||||
Tracer *string
|
Tracer *string
|
||||||
Timeout *string
|
Timeout *string
|
||||||
Reexec *uint64
|
|
||||||
// Config specific to given tracer. Note struct logger
|
// Config specific to given tracer. Note struct logger
|
||||||
// config are historically embedded in main object.
|
// config are historically embedded in main object.
|
||||||
TracerConfig json.RawMessage
|
TracerConfig json.RawMessage
|
||||||
|
|
@ -174,7 +168,6 @@ type TraceCallConfig struct {
|
||||||
// StdTraceConfig holds extra parameters to standard-json trace functions.
|
// StdTraceConfig holds extra parameters to standard-json trace functions.
|
||||||
type StdTraceConfig struct {
|
type StdTraceConfig struct {
|
||||||
logger.Config
|
logger.Config
|
||||||
Reexec *uint64
|
|
||||||
TxHash common.Hash
|
TxHash common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,10 +238,6 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf
|
||||||
// transaction, dependent on the requested tracer.
|
// transaction, dependent on the requested tracer.
|
||||||
// The tracing procedure should be aborted in case the closed signal is received.
|
// The tracing procedure should be aborted in case the closed signal is received.
|
||||||
func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan error) chan *blockTraceResult {
|
func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan error) chan *blockTraceResult {
|
||||||
reexec := defaultTraceReexec
|
|
||||||
if config != nil && config.Reexec != nil {
|
|
||||||
reexec = *config.Reexec
|
|
||||||
}
|
|
||||||
blocks := int(end.NumberU64() - start.NumberU64())
|
blocks := int(end.NumberU64() - start.NumberU64())
|
||||||
threads := runtime.NumCPU()
|
threads := runtime.NumCPU()
|
||||||
if threads > blocks {
|
if threads > blocks {
|
||||||
|
|
@ -374,7 +363,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||||
s1, s2, s3 := statedb.Database().TrieDB().Size()
|
s1, s2, s3 := statedb.Database().TrieDB().Size()
|
||||||
preferDisk = s1+s2+s3 > defaultTracechainMemLimit
|
preferDisk = s1+s2+s3 > defaultTracechainMemLimit
|
||||||
}
|
}
|
||||||
statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk)
|
statedb, release, err = api.backend.StateAtBlock(ctx, block, statedb, false, preferDisk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break
|
break
|
||||||
|
|
@ -522,11 +511,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reexec := defaultTraceReexec
|
statedb, release, err := api.backend.StateAtBlock(ctx, parent, nil, true, false)
|
||||||
if config != nil && config.Reexec != nil {
|
|
||||||
reexec = *config.Reexec
|
|
||||||
}
|
|
||||||
statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -591,11 +576,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reexec := defaultTraceReexec
|
statedb, release, err := api.backend.StateAtBlock(ctx, parent, nil, true, false)
|
||||||
if config != nil && config.Reexec != nil {
|
|
||||||
reexec = *config.Reexec
|
|
||||||
}
|
|
||||||
statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -743,11 +724,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reexec := defaultTraceReexec
|
statedb, release, err := api.backend.StateAtBlock(ctx, parent, nil, true, false)
|
||||||
if config != nil && config.Reexec != nil {
|
|
||||||
reexec = *config.Reexec
|
|
||||||
}
|
|
||||||
statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -877,15 +854,11 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
||||||
if blockNumber == 0 {
|
if blockNumber == 0 {
|
||||||
return nil, errors.New("genesis is not traceable")
|
return nil, errors.New("genesis is not traceable")
|
||||||
}
|
}
|
||||||
reexec := defaultTraceReexec
|
|
||||||
if config != nil && config.Reexec != nil {
|
|
||||||
reexec = *config.Reexec
|
|
||||||
}
|
|
||||||
block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
|
block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tx, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
|
tx, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -939,15 +912,10 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// try to recompute the state
|
// try to recompute the state
|
||||||
reexec := defaultTraceReexec
|
|
||||||
if config != nil && config.Reexec != nil {
|
|
||||||
reexec = *config.Reexec
|
|
||||||
}
|
|
||||||
|
|
||||||
if config != nil && config.TxIndex != nil {
|
if config != nil && config.TxIndex != nil {
|
||||||
_, _, statedb, release, err = api.backend.StateAtTransaction(ctx, block, int(*config.TxIndex), reexec)
|
_, _, statedb, release, err = api.backend.StateAtTransaction(ctx, block, int(*config.TxIndex))
|
||||||
} else {
|
} else {
|
||||||
statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
|
statedb, release, err = api.backend.StateAtBlock(ctx, block, nil, true, false)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ func (b *testBackend) teardown() {
|
||||||
b.chain.Stop()
|
b.chain.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) {
|
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) {
|
||||||
statedb, err := b.chain.StateAt(block.Root())
|
statedb, err := b.chain.StateAt(block.Root())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errStateNotFound
|
return nil, nil, errStateNotFound
|
||||||
|
|
@ -167,12 +167,12 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex
|
||||||
return statedb, release, nil
|
return statedb, release, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
||||||
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
||||||
}
|
}
|
||||||
statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
statedb, release, err := b.StateAtBlock(ctx, parent, nil, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errStateNotFound
|
return nil, vm.BlockContext{}, nil, nil, errStateNotFound
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue