eth/tracers/native: panic on memory read in prestateTracer #27691 (#1339)

Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
This commit is contained in:
Daniel Liu 2025-09-09 15:26:12 +08:00 committed by GitHub
parent ef3be2cdac
commit b0e3d4118c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 83 additions and 56 deletions

View file

@ -301,13 +301,13 @@ func TestInternals(t *testing.T) {
byte(vm.CALL), byte(vm.CALL),
}, },
tracer: mkTracer("callTracer", nil), tracer: mkTracer("callTracer", nil),
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0xe01a","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`,
}, },
{ {
name: "Stack depletion in LOG0", name: "Stack depletion in LOG0",
code: []byte{byte(vm.LOG3)}, code: []byte{byte(vm.LOG3)},
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`,
}, },
{ {
name: "Mem expansion in LOG0", name: "Mem expansion in LOG0",
@ -320,61 +320,81 @@ func TestInternals(t *testing.T) {
byte(vm.LOG0), byte(vm.LOG0),
}, },
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`,
},
{
// Leads to OOM on the prestate tracer
name: "Prestate-tracer - CREATE2 OOM",
code: []byte{
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.MSTORE),
byte(vm.PUSH1), 0x1,
byte(vm.PUSH5), 0xff, 0xff, 0xff, 0xff, 0xff,
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.CREATE2),
byte(vm.PUSH1), 0xff,
byte(vm.PUSH1), 0x0,
byte(vm.LOG0),
},
tracer: mkTracer("prestateTracer", nil),
want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`,
},
{
// CREATE2 which requires padding memory by prestate tracer
name: "Prestate-tracer - CREATE2 Memory padding",
code: []byte{
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.MSTORE),
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0xff,
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.CREATE2),
byte(vm.PUSH1), 0xff,
byte(vm.PUSH1), 0x0,
byte(vm.LOG0),
},
tracer: mkTracer("prestateTracer", nil),
want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"0x91ff9a805d36f54e3e272e230f3e3f5c1b330804":{"balance":"0x0"}}`,
}, },
// TODO(daniel): make this test case pass, ref: PR #26848
// {
// // Leads to OOM on the prestate tracer
// name: "Prestate-tracer - mem expansion in CREATE2",
// code: []byte{
// byte(vm.PUSH1), 0x1,
// byte(vm.PUSH1), 0x0,
// byte(vm.MSTORE),
// byte(vm.PUSH1), 0x1,
// byte(vm.PUSH5), 0xff, 0xff, 0xff, 0xff, 0xff,
// byte(vm.PUSH1), 0x1,
// byte(vm.PUSH1), 0x0,
// byte(vm.CREATE2),
// byte(vm.PUSH1), 0xff,
// byte(vm.PUSH1), 0x0,
// byte(vm.LOG0),
// },
// tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)),
// want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`,
// },
} { } {
statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), t.Run(tc.name, func(t *testing.T) {
types.GenesisAlloc{ statedb := tests.MakePreState(rawdb.NewMemoryDatabase(),
to: types.Account{ types.GenesisAlloc{
Code: tc.code, to: types.Account{
}, Code: tc.code,
origin: types.Account{ },
Balance: big.NewInt(500000000000000), origin: types.Account{
}, Balance: big.NewInt(500000000000000),
}) },
evm := vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) })
msg := &core.Message{ evm := vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
To: &to, msg := &core.Message{
From: origin, To: &to,
Value: big.NewInt(0), From: origin,
GasLimit: 50000, Value: big.NewInt(0),
GasPrice: big.NewInt(0), GasLimit: 80000,
GasFeeCap: big.NewInt(0), GasPrice: big.NewInt(0),
GasTipCap: big.NewInt(0), GasFeeCap: big.NewInt(0),
SkipAccountChecks: false, GasTipCap: big.NewInt(0),
} SkipAccountChecks: false,
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) }
if _, err := st.TransitionDb(common.Address{}); err != nil { st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) if _, err := st.TransitionDb(common.Address{}); err != nil {
} t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err)
// Retrieve the trace result and compare against the expected }
res, err := tc.tracer.GetResult() // Retrieve the trace result and compare against the expected
if err != nil { res, err := tc.tracer.GetResult()
t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err) if err != nil {
} t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err)
if string(res) != tc.want { }
t.Fatalf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want) if string(res) != tc.want {
} t.Errorf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want)
}
})
} }
} }

View file

@ -27,6 +27,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/eth/tracers" "github.com/XinFinOrg/XDPoSChain/eth/tracers"
"github.com/XinFinOrg/XDPoSChain/log"
) )
//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go
@ -183,6 +184,7 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64())) data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64()))
if err != nil { if err != nil {
// mSize was unrealistically large // mSize was unrealistically large
log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "callTracer", "offset", mStart, "size", mSize)
return return
} }

View file

@ -27,6 +27,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/eth/tracers" "github.com/XinFinOrg/XDPoSChain/eth/tracers"
"github.com/XinFinOrg/XDPoSChain/log"
) )
//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go //go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go
@ -165,7 +166,11 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
case stackLen >= 4 && op == vm.CREATE2: case stackLen >= 4 && op == vm.CREATE2:
offset := stackData[stackLen-2] offset := stackData[stackLen-2]
size := stackData[stackLen-3] size := stackData[stackLen-3]
init := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) init, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(offset.Uint64()), int64(size.Uint64()))
if err != nil {
log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "prestateTracer", "offset", offset, "size", size)
return
}
inithash := crypto.Keccak256(init) inithash := crypto.Keccak256(init)
salt := stackData[stackLen-4] salt := stackData[stackLen-4]
addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash) addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash)