eth/tracers: fix precompile move feat for debug_traceCall (#31348)

`debug_traceCall` was ignoring the override `movePrecompileToAddress`. Now it is
at feature-parity with eth_call.
This commit is contained in:
Shahar Rosenberg 2025-03-18 11:05:12 +00:00 committed by GitHub
parent d85f796356
commit 40ad6bedf6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 11 deletions

View file

@ -279,7 +279,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config, nil)
if err != nil {
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@ -632,7 +632,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config)
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config, nil)
if err != nil {
return nil, err
}
@ -676,7 +676,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
// concurrent use.
// See: https://github.com/ethereum/go-ethereum/issues/29114
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config, nil)
if err != nil {
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
continue
@ -894,7 +894,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
TxIndex: int(index),
TxHash: hash,
}
return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config)
return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config, nil)
}
// TraceCall lets you trace a given eth_call. It collects the structured logs
@ -907,10 +907,11 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
// Try to retrieve the specified block
var (
err error
block *types.Block
statedb *state.StateDB
release StateReleaseFunc
err error
block *types.Block
statedb *state.StateDB
release StateReleaseFunc
precompiles vm.PrecompiledContracts
)
if hash, ok := blockNrOrHash.Hash(); ok {
block, err = api.blockByHash(ctx, hash)
@ -952,7 +953,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
config.BlockOverrides.Apply(&vmctx)
rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time)
precompiles := vm.ActivePrecompiledContracts(rules)
precompiles = vm.ActivePrecompiledContracts(rules)
if err := config.StateOverrides.Apply(statedb, precompiles); err != nil {
return nil, err
}
@ -977,13 +978,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil {
traceConfig = &config.TraceConfig
}
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig, precompiles)
}
// 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.
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, precompiles vm.PrecompiledContracts) (interface{}, error) {
var (
tracer *Tracer
err error
@ -1009,6 +1010,9 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
}
tracingStateDB := state.NewHookedState(statedb, tracer.Hooks)
evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
if precompiles != nil {
evm.SetPrecompiles(precompiles)
}
// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {

View file

@ -642,6 +642,7 @@ func TestTracingWithOverrides(t *testing.T) {
t.Parallel()
// Initialize test accounts
accounts := newAccounts(3)
ecRecoverAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
storageAccount := common.Address{0x13, 37}
genesis := &core.Genesis{
Config: params.TestChainConfig,
@ -940,6 +941,48 @@ func TestTracingWithOverrides(t *testing.T) {
},
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`,
},
{ // Call to precompile ECREC (0x01), but code was modified to add 1 to input
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &ecRecoverAddress,
Data: newRPCBytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")),
},
config: &TraceCallConfig{
StateOverrides: &override.StateOverride{
randomAccounts[0].addr: override.OverrideAccount{
Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))),
},
ecRecoverAddress: override.OverrideAccount{
// The code below adds one to input
Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")),
MovePrecompileTo: &randomAccounts[2].addr,
},
},
},
want: `{"gas":21167,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000002"}`,
},
{ // Call to ECREC Precompiled on a different address, expect the original behaviour of ECREC precompile
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &randomAccounts[2].addr, // Moved EcRecover
Data: newRPCBytes(common.Hex2Bytes("82f3df49d3645876de6313df2bbe9fbce593f21341a7b03acdb9423bc171fcc9000000000000000000000000000000000000000000000000000000000000001cba13918f50da910f2d55a7ea64cf716ba31dad91856f45908dde900530377d8a112d60f36900d18eb8f9d3b4f85a697b545085614509e3520e4b762e35d0d6bd")),
},
config: &TraceCallConfig{
StateOverrides: &override.StateOverride{
randomAccounts[0].addr: override.OverrideAccount{
Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))),
},
ecRecoverAddress: override.OverrideAccount{
// The code below adds one to input
Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")),
MovePrecompileTo: &randomAccounts[2].addr, // Move EcRecover to this address
},
},
},
want: `{"gas":25664,"failed":false,"returnValue":"000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074"}`,
},
}
for i, tc := range testSuite {
result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)