@@ -429,6 +429,71 @@ func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *Tra
429429 return api .TraceBlock (ctx , blob , config )
430430}
431431
432+ // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list
433+ // of intermediate roots: the stateroot after each transaction.
434+ func (api * API ) IntermediateRoots (ctx context.Context , hash common.Hash , config * TraceConfig ) ([]common.Hash , error ) {
435+ block , _ := api .blockByHash (ctx , hash )
436+ if block == nil {
437+ return nil , fmt .Errorf ("block %#x not found" , hash )
438+ }
439+ if block .NumberU64 () == 0 {
440+ return nil , errors .New ("genesis is not traceable" )
441+ }
442+ parent , err := api .blockByNumberAndHash (ctx , rpc .BlockNumber (block .NumberU64 ()- 1 ), block .ParentHash ())
443+ if err != nil {
444+ return nil , err
445+ }
446+ reexec := defaultTraceReexec
447+ if config != nil && config .Reexec != nil {
448+ reexec = * config .Reexec
449+ }
450+ statedb , err := api .backend .StateAtBlock (ctx , parent , reexec , nil , true )
451+ if err != nil {
452+ return nil , err
453+ }
454+ var (
455+ roots []common.Hash
456+ signer = types .MakeSigner (api .backend .ChainConfig (), block .Number ())
457+ chainConfig = api .backend .ChainConfig ()
458+ vmctx = core .NewEVMBlockContext (block .Header (), api .chainContext (ctx ), nil )
459+ deleteEmptyObjects = chainConfig .IsEIP158 (block .Number ())
460+ )
461+ feeCapacity := state .GetTRC21FeeCapacityFromState (statedb )
462+ for i , tx := range block .Transactions () {
463+ var balance * big.Int
464+ if tx .To () != nil {
465+ // Bypass the validation for trading and lending transactions as their nonce are not incremented
466+ if tx .IsSkipNonceTransaction () {
467+ continue
468+ }
469+ if value , ok := feeCapacity [* tx .To ()]; ok {
470+ balance = value
471+ }
472+ }
473+ var (
474+ msg , _ = tx .AsMessage (signer , balance , block .Number (), block .BaseFee ())
475+ txContext = core .NewEVMTxContext (msg )
476+ vmenv = vm .NewEVM (vmctx , txContext , statedb , nil , chainConfig , vm.Config {})
477+ )
478+ statedb .SetTxContext (tx .Hash (), i )
479+ owner := common.Address {}
480+ if _ , err := core .ApplyMessage (vmenv , msg , new (core.GasPool ).AddGas (msg .Gas ()), owner ); err != nil {
481+ log .Warn ("Tracing intermediate roots did not complete" , "txindex" , i , "txhash" , tx .Hash (), "err" , err )
482+ // We intentionally don't return the error here: if we do, then the RPC server will not
483+ // return the roots. Most likely, the caller already knows that a certain transaction fails to
484+ // be included, but still want the intermediate roots that led to that point.
485+ // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be
486+ // executable.
487+ // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks.
488+ return roots , nil
489+ }
490+ // calling IntermediateRoot will internally call Finalize on the state
491+ // so any modifications are written to the trie
492+ roots = append (roots , statedb .IntermediateRoot (deleteEmptyObjects ))
493+ }
494+ return roots , nil
495+ }
496+
432497// traceBlock configures a new tracer according to the provided configuration, and
433498// executes all the transactions contained within. The return value will be one item
434499// per transaction, dependent on the requestd tracer.
0 commit comments