Commit fa0df456 authored by mbaxter's avatar mbaxter Committed by GitHub

cannon: Add forge debug test (#11037)

* cannon: Add forge debug test

* cannon: Add assertion on the expected return value

* cannon: Add more logging to MIPS tests

* cannon: Only log step input on test failure
parent 42dd604b
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math"
"math/big" "math/big"
"os" "os"
"path" "path"
...@@ -40,17 +41,29 @@ func MarkdownTracer() vm.EVMLogger { ...@@ -40,17 +41,29 @@ func MarkdownTracer() vm.EVMLogger {
return logger.NewMarkdownLogger(&logger.Config{}, os.Stdout) return logger.NewMarkdownLogger(&logger.Config{}, os.Stdout)
} }
func logStepFailureAtCleanup(t *testing.T, mipsEvm *MIPSEVM) {
t.Cleanup(func() {
if t.Failed() {
// Note: For easier debugging of a failing step, see MIPS.t.sol#test_step_debug_succeeds()
t.Logf("Failed while executing step %d with input: %x", mipsEvm.lastStep, mipsEvm.lastStepInput)
}
})
}
type MIPSEVM struct { type MIPSEVM struct {
env *vm.EVM env *vm.EVM
evmState *state.StateDB evmState *state.StateDB
addrs *Addresses addrs *Addresses
localOracle PreimageOracle localOracle PreimageOracle
artifacts *Artifacts artifacts *Artifacts
// Track step execution for logging purposes
lastStep uint64
lastStepInput []byte
} }
func NewMIPSEVM(artifacts *Artifacts, addrs *Addresses) *MIPSEVM { func NewMIPSEVM(artifacts *Artifacts, addrs *Addresses) *MIPSEVM {
env, evmState := NewEVMEnv(artifacts, addrs) env, evmState := NewEVMEnv(artifacts, addrs)
return &MIPSEVM{env, evmState, addrs, nil, artifacts} return &MIPSEVM{env, evmState, addrs, nil, artifacts, math.MaxUint64, nil}
} }
func (m *MIPSEVM) SetTracer(tracer vm.EVMLogger) { func (m *MIPSEVM) SetTracer(tracer vm.EVMLogger) {
...@@ -62,7 +75,9 @@ func (m *MIPSEVM) SetLocalOracle(oracle PreimageOracle) { ...@@ -62,7 +75,9 @@ func (m *MIPSEVM) SetLocalOracle(oracle PreimageOracle) {
} }
// Step is a pure function that computes the poststate from the VM state encoded in the StepWitness. // Step is a pure function that computes the poststate from the VM state encoded in the StepWitness.
func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte { func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness, step uint64) []byte {
m.lastStep = step
m.lastStepInput = nil
sender := common.Address{0x13, 0x37} sender := common.Address{0x13, 0x37}
startingGas := uint64(30_000_000) startingGas := uint64(30_000_000)
...@@ -78,6 +93,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte { ...@@ -78,6 +93,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte {
} }
input := encodeStepInput(t, stepWitness, LocalContext{}, m.artifacts.MIPS) input := encodeStepInput(t, stepWitness, LocalContext{}, m.artifacts.MIPS)
m.lastStepInput = input
ret, leftOverGas, err := m.env.Call(vm.AccountRef(sender), m.addrs.MIPS, input, startingGas, common.U2560) ret, leftOverGas, err := m.env.Call(vm.AccountRef(sender), m.addrs.MIPS, input, startingGas, common.U2560)
require.NoError(t, err, "evm should not fail") require.NoError(t, err, "evm should not fail")
require.Len(t, ret, 32, "expecting 32-byte state hash") require.Len(t, ret, 32, "expecting 32-byte state hash")
...@@ -92,7 +108,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte { ...@@ -92,7 +108,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte {
require.Equal(t, stateHash, postHash, "logged state must be accurate") require.Equal(t, stateHash, postHash, "logged state must be accurate")
m.env.StateDB.RevertToSnapshot(snap) m.env.StateDB.RevertToSnapshot(snap)
t.Logf("EVM step took %d gas, and returned stateHash %s", startingGas-leftOverGas, postHash) t.Logf("EVM step %d took %d gas, and returned stateHash %s", step, startingGas-leftOverGas, postHash)
return evmPost return evmPost
} }
...@@ -168,6 +184,7 @@ func TestEVM(t *testing.T) { ...@@ -168,6 +184,7 @@ func TestEVM(t *testing.T) {
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer) evm.SetTracer(tracer)
evm.SetLocalOracle(oracle) evm.SetLocalOracle(oracle)
logStepFailureAtCleanup(t, evm)
fn := path.Join("open_mips_tests/test/bin", f.Name()) fn := path.Join("open_mips_tests/test/bin", f.Name())
programMem, err := os.ReadFile(fn) programMem, err := os.ReadFile(fn)
...@@ -182,6 +199,7 @@ func TestEVM(t *testing.T) { ...@@ -182,6 +199,7 @@ func TestEVM(t *testing.T) {
goState := NewInstrumentedState(state, oracle, os.Stdout, os.Stderr) goState := NewInstrumentedState(state, oracle, os.Stdout, os.Stderr)
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
curStep := goState.state.Step
if goState.state.Cpu.PC == endAddr { if goState.state.Cpu.PC == endAddr {
break break
} }
...@@ -193,7 +211,7 @@ func TestEVM(t *testing.T) { ...@@ -193,7 +211,7 @@ func TestEVM(t *testing.T) {
stepWitness, err := goState.Step(true) stepWitness, err := goState.Step(true)
require.NoError(t, err) require.NoError(t, err)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, curStep)
// verify the post-state matches. // verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison. // TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
...@@ -235,6 +253,7 @@ func TestEVMSingleStep(t *testing.T) { ...@@ -235,6 +253,7 @@ func TestEVMSingleStep(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
state := &State{Cpu: CpuScalars{PC: tt.pc, NextPC: tt.nextPC}, Memory: NewMemory()} state := &State{Cpu: CpuScalars{PC: tt.pc, NextPC: tt.nextPC}, Memory: NewMemory()}
state.Memory.SetMemory(tt.pc, tt.insn) state.Memory.SetMemory(tt.pc, tt.insn)
curStep := state.Step
us := NewInstrumentedState(state, nil, os.Stdout, os.Stderr) us := NewInstrumentedState(state, nil, os.Stdout, os.Stderr)
stepWitness, err := us.Step(true) stepWitness, err := us.Step(true)
...@@ -242,7 +261,9 @@ func TestEVMSingleStep(t *testing.T) { ...@@ -242,7 +261,9 @@ func TestEVMSingleStep(t *testing.T) {
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer) evm.SetTracer(tracer)
evmPost := evm.Step(t, stepWitness) logStepFailureAtCleanup(t, evm)
evmPost := evm.Step(t, stepWitness, curStep)
goPost, _ := us.state.EncodeWitness() goPost, _ := us.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -412,6 +433,7 @@ func TestEVMSysWriteHint(t *testing.T) { ...@@ -412,6 +433,7 @@ func TestEVMSysWriteHint(t *testing.T) {
err := state.Memory.SetMemoryRange(uint32(tt.memOffset), bytes.NewReader(tt.hintData)) err := state.Memory.SetMemoryRange(uint32(tt.memOffset), bytes.NewReader(tt.hintData))
require.NoError(t, err) require.NoError(t, err)
state.Memory.SetMemory(0, insn) state.Memory.SetMemory(0, insn)
curStep := state.Step
us := NewInstrumentedState(state, &oracle, os.Stdout, os.Stderr) us := NewInstrumentedState(state, &oracle, os.Stdout, os.Stderr)
stepWitness, err := us.Step(true) stepWitness, err := us.Step(true)
...@@ -420,7 +442,9 @@ func TestEVMSysWriteHint(t *testing.T) { ...@@ -420,7 +442,9 @@ func TestEVMSysWriteHint(t *testing.T) {
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer) evm.SetTracer(tracer)
evmPost := evm.Step(t, stepWitness) logStepFailureAtCleanup(t, evm)
evmPost := evm.Step(t, stepWitness, curStep)
goPost, _ := us.state.EncodeWitness() goPost, _ := us.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -478,6 +502,9 @@ func TestEVMFault(t *testing.T) { ...@@ -478,6 +502,9 @@ func TestEVMFault(t *testing.T) {
func TestHelloEVM(t *testing.T) { func TestHelloEVM(t *testing.T) {
contracts, addrs := testContractsSetup(t) contracts, addrs := testContractsSetup(t)
var tracer vm.EVMLogger // no-tracer by default, but see MarkdownTracer var tracer vm.EVMLogger // no-tracer by default, but see MarkdownTracer
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
logStepFailureAtCleanup(t, evm)
elfProgram, err := elf.Open("../example/bin/hello.elf") elfProgram, err := elf.Open("../example/bin/hello.elf")
require.NoError(t, err, "open ELF file") require.NoError(t, err, "open ELF file")
...@@ -494,6 +521,7 @@ func TestHelloEVM(t *testing.T) { ...@@ -494,6 +521,7 @@ func TestHelloEVM(t *testing.T) {
start := time.Now() start := time.Now()
for i := 0; i < 400_000; i++ { for i := 0; i < 400_000; i++ {
curStep := goState.state.Step
if goState.state.Exited { if goState.state.Exited {
break break
} }
...@@ -502,12 +530,9 @@ func TestHelloEVM(t *testing.T) { ...@@ -502,12 +530,9 @@ func TestHelloEVM(t *testing.T) {
t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.Cpu.PC, insn) t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.Cpu.PC, insn)
} }
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
stepWitness, err := goState.Step(true) stepWitness, err := goState.Step(true)
require.NoError(t, err) require.NoError(t, err)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, curStep)
// verify the post-state matches. // verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison. // TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
...@@ -528,6 +553,9 @@ func TestHelloEVM(t *testing.T) { ...@@ -528,6 +553,9 @@ func TestHelloEVM(t *testing.T) {
func TestClaimEVM(t *testing.T) { func TestClaimEVM(t *testing.T) {
contracts, addrs := testContractsSetup(t) contracts, addrs := testContractsSetup(t)
var tracer vm.EVMLogger // no-tracer by default, but see MarkdownTracer var tracer vm.EVMLogger // no-tracer by default, but see MarkdownTracer
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
logStepFailureAtCleanup(t, evm)
elfProgram, err := elf.Open("../example/bin/claim.elf") elfProgram, err := elf.Open("../example/bin/claim.elf")
require.NoError(t, err, "open ELF file") require.NoError(t, err, "open ELF file")
...@@ -545,6 +573,7 @@ func TestClaimEVM(t *testing.T) { ...@@ -545,6 +573,7 @@ func TestClaimEVM(t *testing.T) {
goState := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr)) goState := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr))
for i := 0; i < 2000_000; i++ { for i := 0; i < 2000_000; i++ {
curStep := goState.state.Step
if goState.state.Exited { if goState.state.Exited {
break break
} }
...@@ -557,9 +586,7 @@ func TestClaimEVM(t *testing.T) { ...@@ -557,9 +586,7 @@ func TestClaimEVM(t *testing.T) {
stepWitness, err := goState.Step(true) stepWitness, err := goState.Step(true)
require.NoError(t, err) require.NoError(t, err)
evm := NewMIPSEVM(contracts, addrs) evmPost := evm.Step(t, stepWitness, curStep)
evm.SetTracer(tracer)
evmPost := evm.Step(t, stepWitness)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
......
...@@ -60,7 +60,7 @@ func FuzzStateSyscallBrk(f *testing.F) { ...@@ -60,7 +60,7 @@ func FuzzStateSyscallBrk(f *testing.F) {
require.Equal(t, preimageOffset, state.PreimageOffset) require.Equal(t, preimageOffset, state.PreimageOffset)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -111,7 +111,7 @@ func FuzzStateSyscallClone(f *testing.F) { ...@@ -111,7 +111,7 @@ func FuzzStateSyscallClone(f *testing.F) {
require.Equal(t, preimageOffset, state.PreimageOffset) require.Equal(t, preimageOffset, state.PreimageOffset)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -120,6 +120,7 @@ func FuzzStateSyscallClone(f *testing.F) { ...@@ -120,6 +120,7 @@ func FuzzStateSyscallClone(f *testing.F) {
func FuzzStateSyscallMmap(f *testing.F) { func FuzzStateSyscallMmap(f *testing.F) {
contracts, addrs := testContractsSetup(f) contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32) { f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32) {
state := &State{ state := &State{
Cpu: CpuScalars{ Cpu: CpuScalars{
...@@ -133,7 +134,7 @@ func FuzzStateSyscallMmap(f *testing.F) { ...@@ -133,7 +134,7 @@ func FuzzStateSyscallMmap(f *testing.F) {
Exited: false, Exited: false,
Memory: NewMemory(), Memory: NewMemory(),
Registers: [32]uint32{2: sysMmap, 4: addr, 5: siz}, Registers: [32]uint32{2: sysMmap, 4: addr, 5: siz},
Step: 0, Step: step,
PreimageOffset: 0, PreimageOffset: 0,
} }
state.Memory.SetMemory(0, syscallInsn) state.Memory.SetMemory(0, syscallInsn)
...@@ -172,7 +173,7 @@ func FuzzStateSyscallMmap(f *testing.F) { ...@@ -172,7 +173,7 @@ func FuzzStateSyscallMmap(f *testing.F) {
} }
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -222,7 +223,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) { ...@@ -222,7 +223,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) {
require.Equal(t, uint32(0), state.PreimageOffset) require.Equal(t, uint32(0), state.PreimageOffset)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -231,6 +232,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) { ...@@ -231,6 +232,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) {
func FuzzStateSyscallFcntl(f *testing.F) { func FuzzStateSyscallFcntl(f *testing.F) {
contracts, addrs := testContractsSetup(f) contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, fd uint32, cmd uint32) { f.Fuzz(func(t *testing.T, fd uint32, cmd uint32) {
state := &State{ state := &State{
Cpu: CpuScalars{ Cpu: CpuScalars{
...@@ -244,7 +246,7 @@ func FuzzStateSyscallFcntl(f *testing.F) { ...@@ -244,7 +246,7 @@ func FuzzStateSyscallFcntl(f *testing.F) {
Exited: false, Exited: false,
Memory: NewMemory(), Memory: NewMemory(),
Registers: [32]uint32{2: sysFcntl, 4: fd, 5: cmd}, Registers: [32]uint32{2: sysFcntl, 4: fd, 5: cmd},
Step: 0, Step: step,
PreimageOffset: 0, PreimageOffset: 0,
} }
state.Memory.SetMemory(0, syscallInsn) state.Memory.SetMemory(0, syscallInsn)
...@@ -287,7 +289,7 @@ func FuzzStateSyscallFcntl(f *testing.F) { ...@@ -287,7 +289,7 @@ func FuzzStateSyscallFcntl(f *testing.F) {
} }
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -296,6 +298,7 @@ func FuzzStateSyscallFcntl(f *testing.F) { ...@@ -296,6 +298,7 @@ func FuzzStateSyscallFcntl(f *testing.F) {
func FuzzStateHintRead(f *testing.F) { func FuzzStateHintRead(f *testing.F) {
contracts, addrs := testContractsSetup(f) contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32) { f.Fuzz(func(t *testing.T, addr uint32, count uint32) {
preimageData := []byte("hello world") preimageData := []byte("hello world")
state := &State{ state := &State{
...@@ -310,7 +313,7 @@ func FuzzStateHintRead(f *testing.F) { ...@@ -310,7 +313,7 @@ func FuzzStateHintRead(f *testing.F) {
Exited: false, Exited: false,
Memory: NewMemory(), Memory: NewMemory(),
Registers: [32]uint32{2: sysRead, 4: fdHintRead, 5: addr, 6: count}, Registers: [32]uint32{2: sysRead, 4: fdHintRead, 5: addr, 6: count},
Step: 0, Step: step,
PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(),
PreimageOffset: 0, PreimageOffset: 0,
} }
...@@ -339,7 +342,7 @@ func FuzzStateHintRead(f *testing.F) { ...@@ -339,7 +342,7 @@ func FuzzStateHintRead(f *testing.F) {
require.Equal(t, expectedRegisters, state.Registers) require.Equal(t, expectedRegisters, state.Registers)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -348,6 +351,7 @@ func FuzzStateHintRead(f *testing.F) { ...@@ -348,6 +351,7 @@ func FuzzStateHintRead(f *testing.F) {
func FuzzStatePreimageRead(f *testing.F) { func FuzzStatePreimageRead(f *testing.F) {
contracts, addrs := testContractsSetup(f) contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32, preimageOffset uint32) { f.Fuzz(func(t *testing.T, addr uint32, count uint32, preimageOffset uint32) {
preimageData := []byte("hello world") preimageData := []byte("hello world")
if preimageOffset >= uint32(len(preimageData)) { if preimageOffset >= uint32(len(preimageData)) {
...@@ -365,7 +369,7 @@ func FuzzStatePreimageRead(f *testing.F) { ...@@ -365,7 +369,7 @@ func FuzzStatePreimageRead(f *testing.F) {
Exited: false, Exited: false,
Memory: NewMemory(), Memory: NewMemory(),
Registers: [32]uint32{2: sysRead, 4: fdPreimageRead, 5: addr, 6: count}, Registers: [32]uint32{2: sysRead, 4: fdPreimageRead, 5: addr, 6: count},
Step: 0, Step: step,
PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(),
PreimageOffset: preimageOffset, PreimageOffset: preimageOffset,
} }
...@@ -405,7 +409,7 @@ func FuzzStatePreimageRead(f *testing.F) { ...@@ -405,7 +409,7 @@ func FuzzStatePreimageRead(f *testing.F) {
require.Equal(t, preStatePreimageKey, state.PreimageKey) require.Equal(t, preStatePreimageKey, state.PreimageKey)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -414,6 +418,7 @@ func FuzzStatePreimageRead(f *testing.F) { ...@@ -414,6 +418,7 @@ func FuzzStatePreimageRead(f *testing.F) {
func FuzzStateHintWrite(f *testing.F) { func FuzzStateHintWrite(f *testing.F) {
contracts, addrs := testContractsSetup(f) contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32, randSeed int64) { f.Fuzz(func(t *testing.T, addr uint32, count uint32, randSeed int64) {
preimageData := []byte("hello world") preimageData := []byte("hello world")
state := &State{ state := &State{
...@@ -428,7 +433,7 @@ func FuzzStateHintWrite(f *testing.F) { ...@@ -428,7 +433,7 @@ func FuzzStateHintWrite(f *testing.F) {
Exited: false, Exited: false,
Memory: NewMemory(), Memory: NewMemory(),
Registers: [32]uint32{2: sysWrite, 4: fdHintWrite, 5: addr, 6: count}, Registers: [32]uint32{2: sysWrite, 4: fdHintWrite, 5: addr, 6: count},
Step: 0, Step: step,
PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(), PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(),
PreimageOffset: 0, PreimageOffset: 0,
LastHint: nil, LastHint: nil,
...@@ -465,7 +470,7 @@ func FuzzStateHintWrite(f *testing.F) { ...@@ -465,7 +470,7 @@ func FuzzStateHintWrite(f *testing.F) {
require.Equal(t, expectedRegisters, state.Registers) require.Equal(t, expectedRegisters, state.Registers)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
...@@ -474,6 +479,7 @@ func FuzzStateHintWrite(f *testing.F) { ...@@ -474,6 +479,7 @@ func FuzzStateHintWrite(f *testing.F) {
func FuzzStatePreimageWrite(f *testing.F) { func FuzzStatePreimageWrite(f *testing.F) {
contracts, addrs := testContractsSetup(f) contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32) { f.Fuzz(func(t *testing.T, addr uint32, count uint32) {
preimageData := []byte("hello world") preimageData := []byte("hello world")
state := &State{ state := &State{
...@@ -520,7 +526,7 @@ func FuzzStatePreimageWrite(f *testing.F) { ...@@ -520,7 +526,7 @@ func FuzzStatePreimageWrite(f *testing.F) {
require.Equal(t, expectedRegisters, state.Registers) require.Equal(t, expectedRegisters, state.Registers)
evm := NewMIPSEVM(contracts, addrs) evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness) evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness() goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
......
...@@ -19,6 +19,21 @@ contract MIPS_Test is CommonTest { ...@@ -19,6 +19,21 @@ contract MIPS_Test is CommonTest {
vm.label(address(mips), "MIPS"); vm.label(address(mips), "MIPS");
} }
/// @notice Used to debug step() behavior given a specific input.
/// This is useful to more easily debug non-forge tests.
/// For example, in cannon/mipsevm/evm_test.go step input can be pulled here:
/// https://github.com/ethereum-optimism/optimism/blob/1f64dd6db5561f3bb76ed1d1ffdaff0cde9b7c4b/cannon/mipsevm/evm_test.go#L80-L80
function test_step_debug_succeeds() external {
bytes memory input =
hex"e14ced3200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e29d9267b33909f55f0cac54cca6427fc17fe0b9efe6c34350ca86605145633fe60000000000000000000000000000000000000000000000000000000000000000000000000008a82c0008a8300000000000000000050000000000000000000000000a000000000008a82c0000000000000000000000007fffd00400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fffd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007008fbc00601000ffbd00000000afbffffc27bdfffcafbf000027bdfff4afa400048fb000408fb100448fb200488fb3004c8fb400508fb600548fb800588fb9005caf0ea4ff7928d10f76bc70a73c867e2c9232b35112b060285aedb7b33533e5253d8c8392c902f20c8314d10a807c7bc5de8126736a03c2bdb47667bbfa710375ac2064c969079ba2acbb688f31cd2bdd4cbe18111a8e733c487884d541f1366231e3c23a71546c755f18517db871301ffe7b08676258520720f4cb2fcc23642ddb778fcfd0cfc38a190d5b8bf0bea4e1ce7d2f35d6a068b94cf6d925e0a024d571f505296c77e19f2ea496d88d90cd342189bdedb389ac959bb9b82db9e324d150eb233dbfa0746469950cec5d4f6360fa49f835403946268bf6fa7472bc4a1320e6a7387a6272dcbf4f8280ff680ccedd4b79f02c78eaef3218c1e78f9e266b3b1c7c1c24e7d04470d63c4e1df858f2e7bf9c7cdad07ed51bc383f80a4d3ded70f2c60642ed3c85483b60ea68b5ed606b2f84d90ac876c01c4d01ba58c431390bd20a29a10d408854c7f62a262860ebd3e4af402fa2dcc0662dfa36fd3e85cbab4da3e3d0907392666337a62e5a663c04bc0a3e16d559f825ba2d40a1c81f4d3844b6cfb2e084a80eb9338fad62b25cf83f4738b5c4df1a0ef019e8ebb9d03d8c7e091f91c853d19da08da2245b01b806c73dc0b200672d04e78982eaed71ea20929c6c472715d5c74a31176a5663348a3c02c89ff5edb7cf3041110e8fe44e2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd95a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3774df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef6834d8ef8faaf96b7b45235297538a266eb882b8b5680f621aab3417d43cdc2eb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d3021ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a193440eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968a60155a81a637d8581c4d275380f7dd05bd2dd27ac3fb7ca905e7aec4e0a1cd99867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756afcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf8923490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99cc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8beccda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d22733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd95a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3774df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619eff0eb509051ae684fe17ee4373a3c82e88f970dab89cc0915d21b63cb96415cc2b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0";
(bool success, bytes memory retVal) = address(mips).call(input);
bytes memory expectedRetVal = hex"03611b9f88f952fea10b9330e85fbe7b8ddd0d457d3f31e647434a5330789212";
assertTrue(success);
assertEq(retVal.length, 32, "Expect a bytes32 hash of the post-state to be returned");
assertEq(retVal, expectedRetVal);
}
function test_step_abi_succeeds() external { function test_step_abi_succeeds() external {
uint32[32] memory registers; uint32[32] memory registers;
registers[16] = 0xbfff0000; registers[16] = 0xbfff0000;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment