Skip to content

Commit dc1c80e

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into develop
2 parents ba9f281 + 185fb80 commit dc1c80e

File tree

155 files changed

+8913
-4042
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

155 files changed

+8913
-4042
lines changed

.semgrepignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ tests/
1818
# Semgrep-action log folder
1919
.semgrep_logs/
2020

21+
op-chain-ops/script/testdata
2122

2223
packages/*/node_modules
2324
packages/*/test

cannon/mipsevm/exec/mips_instructions.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ func ExecuteMipsInstruction(insn, opcode, fun, rs, rt, mem uint32) uint32 {
153153
case 0x06: // srlv
154154
return rt >> (rs & 0x1F)
155155
case 0x07: // srav
156-
return SignExtend(rt>>rs, 32-rs)
156+
shamt := rs & 0x1F
157+
return SignExtend(rt>>shamt, 32-shamt)
157158
// functs in range [0x8, 0x1b] are handled specially by other functions
158159
case 0x08: // jr
159160
return rs

cannon/mipsevm/exec/mips_syscalls.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
1111
"github.com/ethereum-optimism/optimism/cannon/mipsevm/memory"
12+
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
1213
)
1314

1415
// Syscall codes
@@ -132,7 +133,6 @@ const (
132133
// Other constants
133134
const (
134135
SchedQuantum = 100_000
135-
BrkStart = 0x40000000
136136
)
137137

138138
func GetSyscallArgs(registers *[32]uint32) (syscallNum, a0, a1, a2, a3 uint32) {
@@ -158,6 +158,12 @@ func HandleSysMmap(a0, a1, heap uint32) (v0, v1, newHeap uint32) {
158158
v0 = heap
159159
//fmt.Printf("mmap heap 0x%x size 0x%x\n", v0, sz)
160160
newHeap += sz
161+
// Fail if new heap exceeds memory limit, newHeap overflows around to low memory, or sz overflows
162+
if newHeap > program.HEAP_END || newHeap < heap || sz < a1 {
163+
v0 = SysErrorSignal
164+
v1 = MipsEINVAL
165+
return v0, v1, heap
166+
}
161167
} else {
162168
v0 = a0
163169
//fmt.Printf("mmap hint 0x%x size 0x%x\n", v0, sz)

cannon/mipsevm/multithreaded/mips.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
1212
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
13+
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
1314
)
1415

1516
func (m *InstrumentedState) handleSyscall() error {
@@ -26,7 +27,7 @@ func (m *InstrumentedState) handleSyscall() error {
2627
v0, v1, newHeap = exec.HandleSysMmap(a0, a1, m.state.Heap)
2728
m.state.Heap = newHeap
2829
case exec.SysBrk:
29-
v0 = exec.BrkStart
30+
v0 = program.PROGRAM_BREAK
3031
case exec.SysClone: // clone
3132
// a0 = flag bitmask, a1 = stack pointer
3233
if exec.ValidCloneFlags != a0 {

cannon/mipsevm/program/load.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ import (
99
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
1010
)
1111

12-
const HEAP_START = 0x05000000
12+
const (
13+
HEAP_START = 0x05_00_00_00
14+
HEAP_END = 0x60_00_00_00
15+
PROGRAM_BREAK = 0x40_00_00_00
16+
)
1317

1418
type CreateInitialFPVMState[T mipsevm.FPVMState] func(pc, heapStart uint32) T
1519

cannon/mipsevm/singlethreaded/mips.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"github.com/ethereum/go-ethereum/common/hexutil"
66

77
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
8+
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
89
)
910

1011
func (m *InstrumentedState) handleSyscall() error {
@@ -20,7 +21,7 @@ func (m *InstrumentedState) handleSyscall() error {
2021
v0, v1, newHeap = exec.HandleSysMmap(a0, a1, m.state.Heap)
2122
m.state.Heap = newHeap
2223
case exec.SysBrk:
23-
v0 = exec.BrkStart
24+
v0 = program.PROGRAM_BREAK
2425
case exec.SysClone: // clone (not supported)
2526
v0 = 1
2627
case exec.SysExitGroup:

cannon/mipsevm/tests/evm_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io"
66
"os"
77
"path"
8+
"strings"
89
"testing"
910
"time"
1011

@@ -18,6 +19,7 @@ import (
1819
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
1920
"github.com/ethereum-optimism/optimism/cannon/mipsevm/memory"
2021
"github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded"
22+
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
2123
"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
2224
"github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil"
2325
)
@@ -48,6 +50,7 @@ func TestEVM(t *testing.T) {
4850
oracle := testutil.SelectOracleFixture(t, f.Name())
4951
// Short-circuit early for exit_group.bin
5052
exitGroup := f.Name() == "exit_group.bin"
53+
expectPanic := strings.HasSuffix(f.Name(), "panic.bin")
5154

5255
evm := testutil.NewMIPSEVM(contracts, addrs)
5356
evm.SetTracer(tracer)
@@ -66,6 +69,17 @@ func TestEVM(t *testing.T) {
6669

6770
goState := singlethreaded.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr, nil)
6871

72+
// Catch panics and check if they are expected
73+
defer func() {
74+
if r := recover(); r != nil {
75+
if expectPanic {
76+
// Success
77+
} else {
78+
t.Errorf("unexpected panic: %v", r)
79+
}
80+
}
81+
}()
82+
6983
for i := 0; i < 1000; i++ {
7084
curStep := goState.GetState().GetStep()
7185
if goState.GetState().GetPC() == testutil.EndAddr {
@@ -90,6 +104,8 @@ func TestEVM(t *testing.T) {
90104
require.NotEqual(t, uint32(testutil.EndAddr), goState.GetState().GetPC(), "must not reach end")
91105
require.True(t, goState.GetState().GetExited(), "must set exited state")
92106
require.Equal(t, uint8(1), goState.GetState().GetExitCode(), "must exit with 1")
107+
} else if expectPanic {
108+
require.NotEqual(t, uint32(testutil.EndAddr), goState.GetState().GetPC(), "must not reach end")
93109
} else {
94110
require.Equal(t, uint32(testutil.EndAddr), state.Cpu.PC, "must reach end")
95111
// inspect test result
@@ -193,6 +209,88 @@ func TestEVMSingleStep(t *testing.T) {
193209
}
194210
}
195211

212+
func TestEVM_MMap(t *testing.T) {
213+
contracts, addrs := testContractsSetup(t)
214+
var tracer *tracing.Hooks
215+
216+
cases := []struct {
217+
name string
218+
heap uint32
219+
address uint32
220+
size uint32
221+
shouldFail bool
222+
expectedHeap uint32
223+
}{
224+
{name: "Increment heap by max value", heap: program.HEAP_START, address: 0, size: ^uint32(0), shouldFail: true},
225+
{name: "Increment heap to 0", heap: program.HEAP_START, address: 0, size: ^uint32(0) - program.HEAP_START + 1, shouldFail: true},
226+
{name: "Increment heap to previous page", heap: program.HEAP_START, address: 0, size: ^uint32(0) - program.HEAP_START - memory.PageSize + 1, shouldFail: true},
227+
{name: "Increment max page size", heap: program.HEAP_START, address: 0, size: ^uint32(0) & ^uint32(memory.PageAddrMask), shouldFail: true},
228+
{name: "Increment max page size from 0", heap: 0, address: 0, size: ^uint32(0) & ^uint32(memory.PageAddrMask), shouldFail: true},
229+
{name: "Increment heap at limit", heap: program.HEAP_END, address: 0, size: 1, shouldFail: true},
230+
{name: "Increment heap to limit", heap: program.HEAP_END - memory.PageSize, address: 0, size: 1, shouldFail: false, expectedHeap: program.HEAP_END},
231+
{name: "Increment heap within limit", heap: program.HEAP_END - 2*memory.PageSize, address: 0, size: 1, shouldFail: false, expectedHeap: program.HEAP_END - memory.PageSize},
232+
{name: "Request specific address", heap: program.HEAP_START, address: 0x50_00_00_00, size: 0, shouldFail: false, expectedHeap: program.HEAP_START},
233+
}
234+
235+
for _, c := range cases {
236+
t.Run(c.name, func(t *testing.T) {
237+
state := singlethreaded.CreateEmptyState()
238+
state.Heap = c.heap
239+
state.Memory.SetMemory(state.GetPC(), syscallInsn)
240+
state.Registers = testutil.RandomRegisters(77)
241+
state.Registers[2] = exec.SysMmap
242+
state.Registers[4] = c.address
243+
state.Registers[5] = c.size
244+
step := state.Step
245+
246+
expectedRegisters := state.Registers
247+
expectedHeap := state.Heap
248+
expectedMemoryRoot := state.Memory.MerkleRoot()
249+
if c.shouldFail {
250+
expectedRegisters[2] = exec.SysErrorSignal
251+
expectedRegisters[7] = exec.MipsEINVAL
252+
} else {
253+
expectedHeap = c.expectedHeap
254+
if c.address == 0 {
255+
expectedRegisters[2] = state.Heap
256+
expectedRegisters[7] = 0
257+
} else {
258+
expectedRegisters[2] = c.address
259+
expectedRegisters[7] = 0
260+
}
261+
}
262+
263+
us := singlethreaded.NewInstrumentedState(state, nil, os.Stdout, os.Stderr, nil)
264+
stepWitness, err := us.Step(true)
265+
require.NoError(t, err)
266+
267+
// Check expectations
268+
require.Equal(t, step+1, state.Step)
269+
require.Equal(t, expectedHeap, state.Heap)
270+
require.Equal(t, expectedRegisters, state.Registers)
271+
require.Equal(t, expectedMemoryRoot, state.Memory.MerkleRoot())
272+
require.Equal(t, common.Hash{}, state.PreimageKey)
273+
require.Equal(t, uint32(0), state.PreimageOffset)
274+
require.Equal(t, uint32(4), state.Cpu.PC)
275+
require.Equal(t, uint32(8), state.Cpu.NextPC)
276+
require.Equal(t, uint32(0), state.Cpu.HI)
277+
require.Equal(t, uint32(0), state.Cpu.LO)
278+
require.Equal(t, false, state.Exited)
279+
require.Equal(t, uint8(0), state.ExitCode)
280+
require.Equal(t, hexutil.Bytes(nil), state.LastHint)
281+
282+
evm := testutil.NewMIPSEVM(contracts, addrs)
283+
evm.SetTracer(tracer)
284+
testutil.LogStepFailureAtCleanup(t, evm)
285+
286+
evmPost := evm.Step(t, stepWitness, step, singlethreaded.GetStateHashFn())
287+
goPost, _ := us.GetState().EncodeWitness()
288+
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
289+
"mipsevm produced different state than EVM")
290+
})
291+
}
292+
}
293+
196294
func TestEVMSysWriteHint(t *testing.T) {
197295
contracts, addrs := testContractsSetup(t)
198296
var tracer *tracing.Hooks

cannon/mipsevm/tests/fuzz_evm_test.go

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
1515
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
1616
"github.com/ethereum-optimism/optimism/cannon/mipsevm/memory"
17+
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
1718
"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
1819
"github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil"
1920
preimage "github.com/ethereum-optimism/optimism/op-preimage"
@@ -45,7 +46,7 @@ func FuzzStateSyscallBrk(f *testing.F) {
4546
state.Memory.SetMemory(pc, syscallInsn)
4647
preStateRoot := state.Memory.MerkleRoot()
4748
expectedRegisters := state.Registers
48-
expectedRegisters[2] = 0x4000_0000
49+
expectedRegisters[2] = program.PROGRAM_BREAK
4950

5051
goState := singlethreaded.NewInstrumentedState(state, nil, os.Stdout, os.Stderr, nil)
5152
stepWitness, err := goState.Step(true)
@@ -127,7 +128,14 @@ func FuzzStateSyscallClone(f *testing.F) {
127128
func FuzzStateSyscallMmap(f *testing.F) {
128129
contracts, addrs := testContractsSetup(f)
129130
step := uint64(0)
130-
f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32) {
131+
132+
// Add special cases for large memory allocation
133+
f.Add(uint32(0), uint32(0x1000), uint32(program.HEAP_END), int64(1))
134+
f.Add(uint32(0), uint32(1<<31), uint32(program.HEAP_START), int64(2))
135+
// Check edge case - just within bounds
136+
f.Add(uint32(0), uint32(0x1000), uint32(program.HEAP_END-4096), int64(3))
137+
138+
f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32, seed int64) {
131139
state := &singlethreaded.State{
132140
Cpu: mipsevm.CpuScalars{
133141
PC: 0,
@@ -139,11 +147,14 @@ func FuzzStateSyscallMmap(f *testing.F) {
139147
ExitCode: 0,
140148
Exited: false,
141149
Memory: memory.NewMemory(),
142-
Registers: [32]uint32{2: exec.SysMmap, 4: addr, 5: siz},
150+
Registers: testutil.RandomRegisters(seed),
143151
Step: step,
144152
PreimageOffset: 0,
145153
}
146154
state.Memory.SetMemory(0, syscallInsn)
155+
state.Registers[2] = exec.SysMmap
156+
state.Registers[4] = addr
157+
state.Registers[5] = siz
147158
preStateRoot := state.Memory.MerkleRoot()
148159
preStateRegisters := state.Registers
149160

@@ -152,32 +163,42 @@ func FuzzStateSyscallMmap(f *testing.F) {
152163
require.NoError(t, err)
153164
require.False(t, stepWitness.HasPreimage())
154165

155-
require.Equal(t, uint32(4), state.Cpu.PC)
156-
require.Equal(t, uint32(8), state.Cpu.NextPC)
157-
require.Equal(t, uint32(0), state.Cpu.LO)
158-
require.Equal(t, uint32(0), state.Cpu.HI)
159-
require.Equal(t, uint8(0), state.ExitCode)
160-
require.Equal(t, false, state.Exited)
161-
require.Equal(t, preStateRoot, state.Memory.MerkleRoot())
162-
require.Equal(t, uint64(1), state.Step)
163-
require.Equal(t, common.Hash{}, state.PreimageKey)
164-
require.Equal(t, uint32(0), state.PreimageOffset)
166+
var expectedHeap uint32
167+
expectedRegisters := preStateRegisters
165168
if addr == 0 {
166-
expectedRegisters := preStateRegisters
167-
expectedRegisters[2] = heap
168-
require.Equal(t, expectedRegisters, state.Registers)
169169
sizAlign := siz
170170
if sizAlign&memory.PageAddrMask != 0 { // adjust size to align with page size
171171
sizAlign = siz + memory.PageSize - (siz & memory.PageAddrMask)
172172
}
173-
require.Equal(t, uint32(heap+sizAlign), state.Heap)
173+
newHeap := heap + sizAlign
174+
if newHeap > program.HEAP_END || newHeap < heap || sizAlign < siz {
175+
expectedHeap = heap
176+
expectedRegisters[2] = exec.SysErrorSignal
177+
expectedRegisters[7] = exec.MipsEINVAL
178+
} else {
179+
expectedRegisters[2] = heap
180+
expectedRegisters[7] = 0 // no error
181+
expectedHeap = heap + sizAlign
182+
}
174183
} else {
175-
expectedRegisters := preStateRegisters
176184
expectedRegisters[2] = addr
177-
require.Equal(t, expectedRegisters, state.Registers)
178-
require.Equal(t, uint32(heap), state.Heap)
185+
expectedRegisters[7] = 0 // no error
186+
expectedHeap = heap
179187
}
180188

189+
require.Equal(t, uint32(4), state.Cpu.PC)
190+
require.Equal(t, uint32(8), state.Cpu.NextPC)
191+
require.Equal(t, uint32(0), state.Cpu.LO)
192+
require.Equal(t, uint32(0), state.Cpu.HI)
193+
require.Equal(t, preStateRoot, state.Memory.MerkleRoot())
194+
require.Equal(t, uint64(1), state.Step)
195+
require.Equal(t, common.Hash{}, state.PreimageKey)
196+
require.Equal(t, uint32(0), state.PreimageOffset)
197+
require.Equal(t, expectedHeap, state.Heap)
198+
require.Equal(t, uint8(0), state.ExitCode)
199+
require.Equal(t, false, state.Exited)
200+
require.Equal(t, expectedRegisters, state.Registers)
201+
181202
evm := testutil.NewMIPSEVM(contracts, addrs)
182203
evmPost := evm.Step(t, stepWitness, step, singlethreaded.GetStateHashFn())
183204
goPost, _ := goState.GetState().EncodeWitness()
0 Bytes
Binary file not shown.
60 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)