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+
196294func TestEVMSysWriteHint (t * testing.T ) {
197295 contracts , addrs := testContractsSetup (t )
198296 var tracer * tracing.Hooks
0 commit comments