|
|
|
@ -711,7 +711,12 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha |
|
|
|
|
if config != nil && config.Reexec != nil { |
|
|
|
|
reexec = *config.Reexec |
|
|
|
|
} |
|
|
|
|
msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec) |
|
|
|
|
// Retrieve the block
|
|
|
|
|
block := api.eth.blockchain.GetBlockByHash(blockHash) |
|
|
|
|
if block == nil { |
|
|
|
|
return nil, fmt.Errorf("block %#x not found", blockHash) |
|
|
|
|
} |
|
|
|
|
msg, vmctx, statedb, err := api.computeTxEnv(block, int(index), reexec) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
@ -719,6 +724,40 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha |
|
|
|
|
return api.traceTx(ctx, msg, vmctx, statedb, config) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TraceCall lets you trace a given eth_call. It collects the structured logs created during the execution of EVM
|
|
|
|
|
// if the given transaction was added on top of the provided block and returns them as a JSON object.
|
|
|
|
|
// You can provide -2 as a block number to trace on top of the pending block.
|
|
|
|
|
func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (interface{}, error) { |
|
|
|
|
// First try to retrieve the state
|
|
|
|
|
statedb, header, err := api.eth.APIBackend.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) |
|
|
|
|
if err != nil { |
|
|
|
|
// Try to retrieve the specified block
|
|
|
|
|
var block *types.Block |
|
|
|
|
if hash, ok := blockNrOrHash.Hash(); ok { |
|
|
|
|
block = api.eth.blockchain.GetBlockByHash(hash) |
|
|
|
|
} else if number, ok := blockNrOrHash.Number(); ok { |
|
|
|
|
block = api.eth.blockchain.GetBlockByNumber(uint64(number)) |
|
|
|
|
} |
|
|
|
|
if block == nil { |
|
|
|
|
return nil, fmt.Errorf("block %v not found: %v", blockNrOrHash, err) |
|
|
|
|
} |
|
|
|
|
// try to recompute the state
|
|
|
|
|
reexec := defaultTraceReexec |
|
|
|
|
if config != nil && config.Reexec != nil { |
|
|
|
|
reexec = *config.Reexec |
|
|
|
|
} |
|
|
|
|
_, _, statedb, err = api.computeTxEnv(block, 0, reexec) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Execute the trace
|
|
|
|
|
msg := args.ToMessage(api.eth.APIBackend.RPCGasCap()) |
|
|
|
|
vmctx := core.NewEVMContext(msg, header, api.eth.blockchain, nil) |
|
|
|
|
return api.traceTx(ctx, msg, vmctx, statedb, config) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// traceTx configures a new tracer according to the provided configuration, and
|
|
|
|
|
// executes the given message in the provided environment. The return value will
|
|
|
|
|
// be tracer dependent.
|
|
|
|
@ -786,12 +825,8 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// computeTxEnv returns the execution environment of a certain transaction.
|
|
|
|
|
func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) { |
|
|
|
|
func (api *PrivateDebugAPI) computeTxEnv(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) { |
|
|
|
|
// Create the parent state database
|
|
|
|
|
block := api.eth.blockchain.GetBlockByHash(blockHash) |
|
|
|
|
if block == nil { |
|
|
|
|
return nil, vm.Context{}, nil, fmt.Errorf("block %#x not found", blockHash) |
|
|
|
|
} |
|
|
|
|
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) |
|
|
|
|
if parent == nil { |
|
|
|
|
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 |
|
|
|
|
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
|
|
|
|
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) |
|
|
|
|
} |
|
|
|
|
return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, blockHash) |
|
|
|
|
return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) |
|
|
|
|
} |
|
|
|
|