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 (
"errors"
"fmt"
"io"
"math"
"math/big"
"os"
"path"
......@@ -40,17 +41,29 @@ func MarkdownTracer() vm.EVMLogger {
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 {
env *vm.EVM
evmState *state.StateDB
addrs *Addresses
localOracle PreimageOracle
artifacts *Artifacts
// Track step execution for logging purposes
lastStep uint64
lastStepInput []byte
}
func NewMIPSEVM(artifacts *Artifacts, addrs *Addresses) *MIPSEVM {
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) {
......@@ -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.
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}
startingGas := uint64(30_000_000)
......@@ -78,6 +93,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte {
}
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)
require.NoError(t, err, "evm should not fail")
require.Len(t, ret, 32, "expecting 32-byte state hash")
......@@ -92,7 +108,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness) []byte {
require.Equal(t, stateHash, postHash, "logged state must be accurate")
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
}
......@@ -168,6 +184,7 @@ func TestEVM(t *testing.T) {
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
evm.SetLocalOracle(oracle)
logStepFailureAtCleanup(t, evm)
fn := path.Join("open_mips_tests/test/bin", f.Name())
programMem, err := os.ReadFile(fn)
......@@ -182,6 +199,7 @@ func TestEVM(t *testing.T) {
goState := NewInstrumentedState(state, oracle, os.Stdout, os.Stderr)
for i := 0; i < 1000; i++ {
curStep := goState.state.Step
if goState.state.Cpu.PC == endAddr {
break
}
......@@ -193,7 +211,7 @@ func TestEVM(t *testing.T) {
stepWitness, err := goState.Step(true)
require.NoError(t, err)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, curStep)
// verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
goPost, _ := goState.state.EncodeWitness()
......@@ -235,6 +253,7 @@ func TestEVMSingleStep(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
state := &State{Cpu: CpuScalars{PC: tt.pc, NextPC: tt.nextPC}, Memory: NewMemory()}
state.Memory.SetMemory(tt.pc, tt.insn)
curStep := state.Step
us := NewInstrumentedState(state, nil, os.Stdout, os.Stderr)
stepWitness, err := us.Step(true)
......@@ -242,7 +261,9 @@ func TestEVMSingleStep(t *testing.T) {
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
evmPost := evm.Step(t, stepWitness)
logStepFailureAtCleanup(t, evm)
evmPost := evm.Step(t, stepWitness, curStep)
goPost, _ := us.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -412,6 +433,7 @@ func TestEVMSysWriteHint(t *testing.T) {
err := state.Memory.SetMemoryRange(uint32(tt.memOffset), bytes.NewReader(tt.hintData))
require.NoError(t, err)
state.Memory.SetMemory(0, insn)
curStep := state.Step
us := NewInstrumentedState(state, &oracle, os.Stdout, os.Stderr)
stepWitness, err := us.Step(true)
......@@ -420,7 +442,9 @@ func TestEVMSysWriteHint(t *testing.T) {
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
evmPost := evm.Step(t, stepWitness)
logStepFailureAtCleanup(t, evm)
evmPost := evm.Step(t, stepWitness, curStep)
goPost, _ := us.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -478,6 +502,9 @@ func TestEVMFault(t *testing.T) {
func TestHelloEVM(t *testing.T) {
contracts, addrs := testContractsSetup(t)
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")
require.NoError(t, err, "open ELF file")
......@@ -494,6 +521,7 @@ func TestHelloEVM(t *testing.T) {
start := time.Now()
for i := 0; i < 400_000; i++ {
curStep := goState.state.Step
if goState.state.Exited {
break
}
......@@ -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)
}
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
stepWitness, err := goState.Step(true)
require.NoError(t, err)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, curStep)
// verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
goPost, _ := goState.state.EncodeWitness()
......@@ -528,6 +553,9 @@ func TestHelloEVM(t *testing.T) {
func TestClaimEVM(t *testing.T) {
contracts, addrs := testContractsSetup(t)
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")
require.NoError(t, err, "open ELF file")
......@@ -545,6 +573,7 @@ func TestClaimEVM(t *testing.T) {
goState := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr))
for i := 0; i < 2000_000; i++ {
curStep := goState.state.Step
if goState.state.Exited {
break
}
......@@ -557,9 +586,7 @@ func TestClaimEVM(t *testing.T) {
stepWitness, err := goState.Step(true)
require.NoError(t, err)
evm := NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, curStep)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
......
......@@ -60,7 +60,7 @@ func FuzzStateSyscallBrk(f *testing.F) {
require.Equal(t, preimageOffset, state.PreimageOffset)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -111,7 +111,7 @@ func FuzzStateSyscallClone(f *testing.F) {
require.Equal(t, preimageOffset, state.PreimageOffset)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -120,6 +120,7 @@ func FuzzStateSyscallClone(f *testing.F) {
func FuzzStateSyscallMmap(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32) {
state := &State{
Cpu: CpuScalars{
......@@ -133,7 +134,7 @@ func FuzzStateSyscallMmap(f *testing.F) {
Exited: false,
Memory: NewMemory(),
Registers: [32]uint32{2: sysMmap, 4: addr, 5: siz},
Step: 0,
Step: step,
PreimageOffset: 0,
}
state.Memory.SetMemory(0, syscallInsn)
......@@ -172,7 +173,7 @@ func FuzzStateSyscallMmap(f *testing.F) {
}
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -222,7 +223,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) {
require.Equal(t, uint32(0), state.PreimageOffset)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -231,6 +232,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) {
func FuzzStateSyscallFcntl(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, fd uint32, cmd uint32) {
state := &State{
Cpu: CpuScalars{
......@@ -244,7 +246,7 @@ func FuzzStateSyscallFcntl(f *testing.F) {
Exited: false,
Memory: NewMemory(),
Registers: [32]uint32{2: sysFcntl, 4: fd, 5: cmd},
Step: 0,
Step: step,
PreimageOffset: 0,
}
state.Memory.SetMemory(0, syscallInsn)
......@@ -287,7 +289,7 @@ func FuzzStateSyscallFcntl(f *testing.F) {
}
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -296,6 +298,7 @@ func FuzzStateSyscallFcntl(f *testing.F) {
func FuzzStateHintRead(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32) {
preimageData := []byte("hello world")
state := &State{
......@@ -310,7 +313,7 @@ func FuzzStateHintRead(f *testing.F) {
Exited: false,
Memory: NewMemory(),
Registers: [32]uint32{2: sysRead, 4: fdHintRead, 5: addr, 6: count},
Step: 0,
Step: step,
PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(),
PreimageOffset: 0,
}
......@@ -339,7 +342,7 @@ func FuzzStateHintRead(f *testing.F) {
require.Equal(t, expectedRegisters, state.Registers)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -348,6 +351,7 @@ func FuzzStateHintRead(f *testing.F) {
func FuzzStatePreimageRead(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32, preimageOffset uint32) {
preimageData := []byte("hello world")
if preimageOffset >= uint32(len(preimageData)) {
......@@ -365,7 +369,7 @@ func FuzzStatePreimageRead(f *testing.F) {
Exited: false,
Memory: NewMemory(),
Registers: [32]uint32{2: sysRead, 4: fdPreimageRead, 5: addr, 6: count},
Step: 0,
Step: step,
PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(),
PreimageOffset: preimageOffset,
}
......@@ -405,7 +409,7 @@ func FuzzStatePreimageRead(f *testing.F) {
require.Equal(t, preStatePreimageKey, state.PreimageKey)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -414,6 +418,7 @@ func FuzzStatePreimageRead(f *testing.F) {
func FuzzStateHintWrite(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32, randSeed int64) {
preimageData := []byte("hello world")
state := &State{
......@@ -428,7 +433,7 @@ func FuzzStateHintWrite(f *testing.F) {
Exited: false,
Memory: NewMemory(),
Registers: [32]uint32{2: sysWrite, 4: fdHintWrite, 5: addr, 6: count},
Step: 0,
Step: step,
PreimageKey: preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey(),
PreimageOffset: 0,
LastHint: nil,
......@@ -465,7 +470,7 @@ func FuzzStateHintWrite(f *testing.F) {
require.Equal(t, expectedRegisters, state.Registers)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......@@ -474,6 +479,7 @@ func FuzzStateHintWrite(f *testing.F) {
func FuzzStatePreimageWrite(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, count uint32) {
preimageData := []byte("hello world")
state := &State{
......@@ -520,7 +526,7 @@ func FuzzStatePreimageWrite(f *testing.F) {
require.Equal(t, expectedRegisters, state.Registers)
evm := NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness)
evmPost := evm.Step(t, stepWitness, step)
goPost, _ := goState.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
......
......@@ -19,6 +19,21 @@ contract MIPS_Test is CommonTest {
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 {
uint32[32] memory registers;
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