Skip to content

Commit de971cc

Browse files
eth: added trace_call to trace on top of arbitrary blocks (#21338)
* eth: Added TraceTransactionPending * eth: Implement Trace_Call, remove traceTxPending * eth: debug_call -> debug_traceCall, recompute tx environment if pruned * eth: fix nil panic * eth: improve block retrieving logic in tracers * internal/web3ext: add debug_traceCall to console
1 parent f86324e commit de971cc

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

eth/api.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,12 @@ type storageEntry struct {
412412

413413
// StorageRangeAt returns the storage at the given block height and transaction index.
414414
func (api *PrivateDebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
415-
_, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
415+
// Retrieve the block
416+
block := api.eth.blockchain.GetBlockByHash(blockHash)
417+
if block == nil {
418+
return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash)
419+
}
420+
_, _, statedb, err := api.computeTxEnv(block, txIndex, 0)
416421
if err != nil {
417422
return StorageRangeResult{}, err
418423
}

eth/api_tracer.go

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -711,14 +711,53 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
711711
if config != nil && config.Reexec != nil {
712712
reexec = *config.Reexec
713713
}
714-
msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec)
714+
// Retrieve the block
715+
block := api.eth.blockchain.GetBlockByHash(blockHash)
716+
if block == nil {
717+
return nil, fmt.Errorf("block %#x not found", blockHash)
718+
}
719+
msg, vmctx, statedb, err := api.computeTxEnv(block, int(index), reexec)
715720
if err != nil {
716721
return nil, err
717722
}
718723
// Trace the transaction and return
719724
return api.traceTx(ctx, msg, vmctx, statedb, config)
720725
}
721726

727+
// TraceCall lets you trace a given eth_call. It collects the structured logs created during the execution of EVM
728+
// if the given transaction was added on top of the provided block and returns them as a JSON object.
729+
// You can provide -2 as a block number to trace on top of the pending block.
730+
func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (interface{}, error) {
731+
// First try to retrieve the state
732+
statedb, header, err := api.eth.APIBackend.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
733+
if err != nil {
734+
// Try to retrieve the specified block
735+
var block *types.Block
736+
if hash, ok := blockNrOrHash.Hash(); ok {
737+
block = api.eth.blockchain.GetBlockByHash(hash)
738+
} else if number, ok := blockNrOrHash.Number(); ok {
739+
block = api.eth.blockchain.GetBlockByNumber(uint64(number))
740+
}
741+
if block == nil {
742+
return nil, fmt.Errorf("block %v not found: %v", blockNrOrHash, err)
743+
}
744+
// try to recompute the state
745+
reexec := defaultTraceReexec
746+
if config != nil && config.Reexec != nil {
747+
reexec = *config.Reexec
748+
}
749+
_, _, statedb, err = api.computeTxEnv(block, 0, reexec)
750+
if err != nil {
751+
return nil, err
752+
}
753+
}
754+
755+
// Execute the trace
756+
msg := args.ToMessage(api.eth.APIBackend.RPCGasCap())
757+
vmctx := core.NewEVMContext(msg, header, api.eth.blockchain, nil)
758+
return api.traceTx(ctx, msg, vmctx, statedb, config)
759+
}
760+
722761
// traceTx configures a new tracer according to the provided configuration, and
723762
// executes the given message in the provided environment. The return value will
724763
// be tracer dependent.
@@ -786,12 +825,8 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
786825
}
787826

788827
// computeTxEnv returns the execution environment of a certain transaction.
789-
func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) {
828+
func (api *PrivateDebugAPI) computeTxEnv(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) {
790829
// Create the parent state database
791-
block := api.eth.blockchain.GetBlockByHash(blockHash)
792-
if block == nil {
793-
return nil, vm.Context{}, nil, fmt.Errorf("block %#x not found", blockHash)
794-
}
795830
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
796831
if parent == nil {
797832
return nil, vm.Context{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
@@ -824,5 +859,5 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
824859
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
825860
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
826861
}
827-
return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, blockHash)
862+
return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
828863
}

internal/web3ext/web3ext.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,12 @@ web3._extend({
429429
params: 2,
430430
inputFormatter: [null, null]
431431
}),
432+
new web3._extend.Method({
433+
name: 'traceCall',
434+
call: 'debug_traceCall',
435+
params: 3,
436+
inputFormatter: [null, null, null]
437+
}),
432438
new web3._extend.Method({
433439
name: 'preimage',
434440
call: 'debug_preimage',

0 commit comments

Comments
 (0)