Skip to content

Commit 30e3a49

Browse files
shazam8253shantichanallightclient
authored
eth/tracers: apply block header overrides correctly (#32183)
Fixes #32175. This fixes the scenario where the blockhash opcode would return 0x0 during RPC simulations when using BlockOverrides with a future block number. The root cause was that BlockOverrides.Apply() only modified the vm.BlockContext, but GetHashFn() depends on the actual types.Header.Number to resolve valid historical block hashes. This caused a mismatch and resulted in incorrect behavior during trace and call simulations. --------- Co-authored-by: shantichanal <[email protected]> Co-authored-by: lightclient <[email protected]>
1 parent 66df1f2 commit 30e3a49

File tree

2 files changed

+44
-11
lines changed

2 files changed

+44
-11
lines changed

eth/tracers/api.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -953,40 +953,53 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
953953
}
954954
defer release()
955955

956-
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
956+
h := block.Header()
957+
blockContext := core.NewEVMBlockContext(h, api.chainContext(ctx), nil)
958+
957959
// Apply the customization rules if required.
958960
if config != nil {
959-
if overrideErr := config.BlockOverrides.Apply(&vmctx); overrideErr != nil {
960-
return nil, overrideErr
961+
if config.BlockOverrides != nil && config.BlockOverrides.Number.ToInt().Uint64() == h.Number.Uint64()+1 {
962+
// Overriding the block number to n+1 is a common way for wallets to
963+
// simulate transactions, however without the following fix, a contract
964+
// can assert it is being simulated by checking if blockhash(n) == 0x0 and
965+
// can behave differently during the simulation. (#32175 for more info)
966+
// --
967+
// Modify the parent hash and number so that downstream, blockContext's
968+
// GetHash function can correctly return n.
969+
h.ParentHash = h.Hash()
970+
h.Number.Add(h.Number, big.NewInt(1))
961971
}
962-
rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time)
963-
972+
if err := config.BlockOverrides.Apply(&blockContext); err != nil {
973+
return nil, err
974+
}
975+
rules := api.backend.ChainConfig().Rules(blockContext.BlockNumber, blockContext.Random != nil, blockContext.Time)
964976
precompiles = vm.ActivePrecompiledContracts(rules)
965977
if err := config.StateOverrides.Apply(statedb, precompiles); err != nil {
966978
return nil, err
967979
}
968980
}
969-
// Execute the trace
970-
if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
981+
982+
// Execute the trace.
983+
if err := args.CallDefaults(api.backend.RPCGasCap(), blockContext.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
971984
return nil, err
972985
}
973986
var (
974-
msg = args.ToMessage(vmctx.BaseFee, true, true)
987+
msg = args.ToMessage(blockContext.BaseFee, true, true)
975988
tx = args.ToTransaction(types.LegacyTxType)
976989
traceConfig *TraceConfig
977990
)
978991
// Lower the basefee to 0 to avoid breaking EVM
979992
// invariants (basefee < feecap).
980993
if msg.GasPrice.Sign() == 0 {
981-
vmctx.BaseFee = new(big.Int)
994+
blockContext.BaseFee = new(big.Int)
982995
}
983996
if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
984-
vmctx.BlobBaseFee = new(big.Int)
997+
blockContext.BlobBaseFee = new(big.Int)
985998
}
986999
if config != nil {
9871000
traceConfig = &config.TraceConfig
9881001
}
989-
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig, precompiles)
1002+
return api.traceTx(ctx, tx, msg, new(Context), blockContext, statedb, traceConfig, precompiles)
9901003
}
9911004

9921005
// traceTx configures a new tracer according to the provided configuration, and

eth/tracers/api_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ func TestTracingWithOverrides(t *testing.T) {
689689
Failed bool
690690
ReturnValue string
691691
}
692+
692693
var testSuite = []struct {
693694
blockNumber rpc.BlockNumber
694695
call ethapi.TransactionArgs
@@ -788,6 +789,25 @@ func TestTracingWithOverrides(t *testing.T) {
788789
},
789790
want: `{"gas":72666,"failed":false,"returnValue":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
790791
},
792+
{ // Override blocknumber with block n+1 and query a blockhash (resolves issue #32175)
793+
blockNumber: rpc.LatestBlockNumber,
794+
call: ethapi.TransactionArgs{
795+
From: &accounts[0].addr,
796+
Input: newRPCBytes([]byte{
797+
byte(vm.PUSH1), byte(genBlocks),
798+
byte(vm.BLOCKHASH),
799+
byte(vm.PUSH1), 0x00,
800+
byte(vm.MSTORE),
801+
byte(vm.PUSH1), 0x20,
802+
byte(vm.PUSH1), 0x00,
803+
byte(vm.RETURN),
804+
}),
805+
},
806+
config: &TraceCallConfig{
807+
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(int64(genBlocks + 1)))},
808+
},
809+
want: fmt.Sprintf(`{"gas":59590,"failed":false,"returnValue":"%s"}`, backend.chain.GetHeaderByNumber(uint64(genBlocks)).Hash().Hex()),
810+
},
791811
/*
792812
pragma solidity =0.8.12;
793813

0 commit comments

Comments
 (0)