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
# Conflicts:
#	eth/api.go
#	eth/api_tracer.go
This commit is contained in:
Marius van der Wijden 2020-09-07 10:52:01 +02:00 committed by Igor Mandrigin
parent 451f2a59ac
commit 369c868f9b
3 changed files with 49 additions and 0 deletions

View File

@ -378,7 +378,12 @@ func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, sta
// StorageRangeAt returns the storage at the given block height and transaction index. // StorageRangeAt returns the storage at the given block height and transaction index.
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
// Retrieve the block
_, _, _, dbstate, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, txIndex) _, _, _, dbstate, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, txIndex)
if block == nil {
return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash)
}
_, _, statedb, err := api.computeTxEnv(block, txIndex, 0)
if err != nil { if err != nil {
return StorageRangeResult{}, err return StorageRangeResult{}, err
} }

View File

@ -604,6 +604,10 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
return nil, fmt.Errorf("transaction %#x not found", hash) return nil, fmt.Errorf("transaction %#x not found", hash)
} }
msg, vmctx, statedb, _, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, index) msg, vmctx, statedb, _, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, index)
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 { if err != nil {
return nil, err return nil, err
} }
@ -611,6 +615,40 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
return api.traceTx(ctx, msg, vmctx, statedb, config) 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 // traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will // executes the given message in the provided environment. The return value will
// be tracer dependent. // be tracer dependent.

View File

@ -429,6 +429,12 @@ web3._extend({
params: 2, params: 2,
inputFormatter: [null, null] inputFormatter: [null, null]
}), }),
new web3._extend.Method({
name: 'traceCall',
call: 'debug_traceCall',
params: 3,
inputFormatter: [null, null, null]
}),
new web3._extend.Method({ new web3._extend.Method({
name: 'preimage', name: 'preimage',
call: 'debug_preimage', call: 'debug_preimage',