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
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							f86324edb7
						
					
				
				
					commit
					de971cc845
				
			| @@ -412,7 +412,12 @@ type storageEntry struct { | ||||
|  | ||||
| // StorageRangeAt returns the storage at the given block height and transaction index. | ||||
| func (api *PrivateDebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { | ||||
| 	_, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0) | ||||
| 	// Retrieve the block | ||||
| 	block := api.eth.blockchain.GetBlockByHash(blockHash) | ||||
| 	if block == nil { | ||||
| 		return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash) | ||||
| 	} | ||||
| 	_, _, statedb, err := api.computeTxEnv(block, txIndex, 0) | ||||
| 	if err != nil { | ||||
| 		return StorageRangeResult{}, err | ||||
| 	} | ||||
|   | ||||
| @@ -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()) | ||||
| } | ||||
|   | ||||
| @@ -429,6 +429,12 @@ web3._extend({ | ||||
| 			params: 2, | ||||
| 			inputFormatter: [null, null] | ||||
| 		}), | ||||
| 		new web3._extend.Method({ | ||||
| 			name: 'traceCall', | ||||
| 			call: 'debug_traceCall', | ||||
| 			params: 3, | ||||
| 			inputFormatter: [null, null, null] | ||||
| 		}), | ||||
| 		new web3._extend.Method({ | ||||
| 			name: 'preimage', | ||||
| 			call: 'debug_preimage', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user