@ -445,12 +445,11 @@ func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *Tra
// EVM against a block pulled from the pool of bad ones and returns them as a JSON
// object.
func ( api * API ) TraceBadBlock ( ctx context . Context , hash common . Hash , config * TraceConfig ) ( [ ] * txTraceResult , error ) {
for _ , block := range rawdb . ReadAllBadBlocks ( api . backend . ChainDb ( ) ) {
if block . Hash ( ) == hash {
return api . traceBlock ( ctx , block , config )
}
}
block := rawdb . ReadBadBlock ( api . backend . ChainDb ( ) , hash )
if block == nil {
return nil , fmt . Errorf ( "bad block %#x not found" , hash )
}
return api . traceBlock ( ctx , block , config )
}
// StandardTraceBlockToFile dumps the structured logs created during the
@ -464,16 +463,72 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash,
return api . standardTraceBlockToFile ( ctx , block , config )
}
// IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
// of intermediate roots: the stateroot after each transaction.
func ( api * API ) IntermediateRoots ( ctx context . Context , hash common . Hash , config * TraceConfig ) ( [ ] common . Hash , error ) {
block , _ := api . blockByHash ( ctx , hash )
if block == nil {
// Check in the bad blocks
block = rawdb . ReadBadBlock ( api . backend . ChainDb ( ) , hash )
}
if block == nil {
return nil , fmt . Errorf ( "block %#x not found" , hash )
}
if block . NumberU64 ( ) == 0 {
return nil , errors . New ( "genesis is not traceable" )
}
parent , err := api . blockByNumberAndHash ( ctx , rpc . BlockNumber ( block . NumberU64 ( ) - 1 ) , block . ParentHash ( ) )
if err != nil {
return nil , err
}
reexec := defaultTraceReexec
if config != nil && config . Reexec != nil {
reexec = * config . Reexec
}
statedb , err := api . backend . StateAtBlock ( ctx , parent , reexec , nil , true )
if err != nil {
return nil , err
}
var (
roots [ ] common . Hash
signer = types . MakeSigner ( api . backend . ChainConfig ( ) , block . Number ( ) )
chainConfig = api . backend . ChainConfig ( )
vmctx = core . NewEVMBlockContext ( block . Header ( ) , api . chainContext ( ctx ) , nil )
deleteEmptyObjects = chainConfig . IsEIP158 ( block . Number ( ) )
)
for i , tx := range block . Transactions ( ) {
var (
msg , _ = tx . AsMessage ( signer , block . BaseFee ( ) )
txContext = core . NewEVMTxContext ( msg )
vmenv = vm . NewEVM ( vmctx , txContext , statedb , chainConfig , vm . Config { } )
)
statedb . Prepare ( tx . Hash ( ) , i )
if _ , err := core . ApplyMessage ( vmenv , msg , new ( core . GasPool ) . AddGas ( msg . Gas ( ) ) ) ; err != nil {
log . Warn ( "Tracing intermediate roots did not complete" , "txindex" , i , "txhash" , tx . Hash ( ) , "err" , err )
// We intentionally don't return the error here: if we do, then the RPC server will not
// return the roots. Most likely, the caller already knows that a certain transaction fails to
// be included, but still want the intermediate roots that led to that point.
// It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
// executable.
// N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
return roots , nil
}
// calling IntermediateRoot will internally call Finalize on the state
// so any modifications are written to the trie
roots = append ( roots , statedb . IntermediateRoot ( deleteEmptyObjects ) )
}
return roots , nil
}
// StandardTraceBadBlockToFile dumps the structured logs created during the
// execution of EVM against a block pulled from the pool of bad ones to the
// local file system and returns a list of files to the caller.
func ( api * API ) StandardTraceBadBlockToFile ( ctx context . Context , hash common . Hash , config * StdTraceConfig ) ( [ ] string , error ) {
for _ , block := range rawdb . ReadAllBadBlocks ( api . backend . ChainDb ( ) ) {
if block . Hash ( ) == hash {
return api . standardTraceBlockToFile ( ctx , block , config )
}
}
block := rawdb . ReadBadBlock ( api . backend . ChainDb ( ) , hash )
if block == nil {
return nil , fmt . Errorf ( "bad block %#x not found" , hash )
}
return api . standardTraceBlockToFile ( ctx , block , config )
}
// traceBlock configures a new tracer according to the provided configuration, and