Skip to content

Commit f5221f4

Browse files
authored
cannon: Add basic types for MTCannon (ethereum-optimism#11109)
* cannon: Rename StepWitness.MemProofs to ProofData * cannon: Add MTState type (in progress) * cannon: Tweak MtState tests to cover more ground * cannon: Add test for MTState.UpdateCurrentThread() * cannon: Use constants for byte size vars, set byte slice capacities * cannon: Add StepsSinceLastContextSwitch field * cannon: Rename witness offset constants * cannon: Rename ThreadContext to ThreadState * cannon: Panic on unimplemented method calls * cannon: Compute thread stack roots lazily * cannon: Push initial thread to left stack
1 parent ddc37da commit f5221f4

10 files changed

Lines changed: 462 additions & 45 deletions

File tree

cannon/cmd/load_elf.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func LoadELF(ctx *cli.Context) error {
4646
if elfProgram.Machine != elf.EM_MIPS {
4747
return fmt.Errorf("ELF is not big-endian MIPS R3000, but got %q", elfProgram.Machine.String())
4848
}
49-
state, err := mipsevm.LoadELF(elfProgram)
49+
state, err := mipsevm.LoadELF(elfProgram, mipsevm.CreateInitialState)
5050
if err != nil {
5151
return fmt.Errorf("failed to load ELF data into VM state: %w", err)
5252
}

cannon/cmd/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func Run(ctx *cli.Context) error {
446446
Pre: witness.StateHash,
447447
Post: postStateHash,
448448
StateData: witness.State,
449-
ProofData: witness.MemProof,
449+
ProofData: witness.ProofData,
450450
}
451451
if witness.HasPreimage() {
452452
proof.OracleKey = witness.PreimageKey[:]

cannon/mipsevm/evm_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func (m *MIPSEVM) Step(t *testing.T, stepWitness *StepWitness, step uint64) []by
113113
}
114114

115115
func encodeStepInput(t *testing.T, wit *StepWitness, localContext LocalContext, mips *foundry.Artifact) []byte {
116-
input, err := mips.ABI.Pack("step", wit.State, wit.MemProof, localContext)
116+
input, err := mips.ABI.Pack("step", wit.State, wit.ProofData, localContext)
117117
require.NoError(t, err)
118118
return input
119119
}
@@ -485,8 +485,8 @@ func TestEVMFault(t *testing.T) {
485485
insnProof := initialState.Memory.MerkleProof(0)
486486
encodedWitness, _ := initialState.EncodeWitness()
487487
stepWitness := &StepWitness{
488-
State: encodedWitness,
489-
MemProof: insnProof[:],
488+
State: encodedWitness,
489+
ProofData: insnProof[:],
490490
}
491491
input := encodeStepInput(t, stepWitness, LocalContext{}, contracts.MIPS)
492492
startingGas := uint64(30_000_000)
@@ -509,7 +509,7 @@ func TestHelloEVM(t *testing.T) {
509509
elfProgram, err := elf.Open("../example/bin/hello.elf")
510510
require.NoError(t, err, "open ELF file")
511511

512-
state, err := LoadELF(elfProgram)
512+
state, err := LoadELF(elfProgram, CreateInitialState)
513513
require.NoError(t, err, "load ELF into state")
514514

515515
err = PatchGo(elfProgram, state)
@@ -560,7 +560,7 @@ func TestClaimEVM(t *testing.T) {
560560
elfProgram, err := elf.Open("../example/bin/claim.elf")
561561
require.NoError(t, err, "open ELF file")
562562

563-
state, err := LoadELF(elfProgram)
563+
state, err := LoadELF(elfProgram, CreateInitialState)
564564
require.NoError(t, err, "load ELF into state")
565565

566566
err = PatchGo(elfProgram, state)

cannon/mipsevm/instrumented.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func (m *InstrumentedState) Step(proof bool) (wit *StepWitness, err error) {
8383
wit = &StepWitness{
8484
State: encodedWitness,
8585
StateHash: stateHash,
86-
MemProof: insnProof[:],
86+
ProofData: insnProof[:],
8787
}
8888
}
8989
err = m.mipsStep()
@@ -92,7 +92,7 @@ func (m *InstrumentedState) Step(proof bool) (wit *StepWitness, err error) {
9292
}
9393

9494
if proof {
95-
wit.MemProof = append(wit.MemProof, m.memProof[:]...)
95+
wit.ProofData = append(wit.ProofData, m.memProof[:]...)
9696
if m.lastPreimageOffset != ^uint32(0) {
9797
wit.PreimageOffset = m.lastPreimageOffset
9898
wit.PreimageKey = m.lastPreimageKey

cannon/mipsevm/patch.go

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,11 @@ import (
1010

1111
const HEAP_START = 0x05000000
1212

13-
func LoadELF(f *elf.File) (*State, error) {
14-
s := &State{
15-
Cpu: CpuScalars{
16-
PC: uint32(f.Entry),
17-
NextPC: uint32(f.Entry + 4),
18-
LO: 0,
19-
HI: 0,
20-
},
21-
Heap: HEAP_START,
22-
Registers: [32]uint32{},
23-
Memory: NewMemory(),
24-
ExitCode: 0,
25-
Exited: false,
26-
Step: 0,
27-
}
13+
type CreateFPVMState[T FPVMState] func(pc, heapStart uint32) T
14+
15+
func LoadELF[T FPVMState](f *elf.File, initState CreateFPVMState[T]) (T, error) {
16+
var empty T
17+
s := initState(uint32(f.Entry), HEAP_START)
2818

2919
for i, prog := range f.Progs {
3020
if prog.Type == 0x70000003 { // MIPS_ABIFLAGS
@@ -37,21 +27,21 @@ func LoadELF(f *elf.File) (*State, error) {
3727
if prog.Filesz < prog.Memsz {
3828
r = io.MultiReader(r, bytes.NewReader(make([]byte, prog.Memsz-prog.Filesz)))
3929
} else {
40-
return nil, fmt.Errorf("invalid PT_LOAD program segment %d, file size (%d) > mem size (%d)", i, prog.Filesz, prog.Memsz)
30+
return empty, fmt.Errorf("invalid PT_LOAD program segment %d, file size (%d) > mem size (%d)", i, prog.Filesz, prog.Memsz)
4131
}
4232
} else {
43-
return nil, fmt.Errorf("program segment %d has different file size (%d) than mem size (%d): filling for non PT_LOAD segments is not supported", i, prog.Filesz, prog.Memsz)
33+
return empty, fmt.Errorf("program segment %d has different file size (%d) than mem size (%d): filling for non PT_LOAD segments is not supported", i, prog.Filesz, prog.Memsz)
4434
}
4535
}
4636

4737
if prog.Vaddr+prog.Memsz >= uint64(1<<32) {
48-
return nil, fmt.Errorf("program %d out of 32-bit mem range: %x - %x (size: %x)", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz)
38+
return empty, fmt.Errorf("program %d out of 32-bit mem range: %x - %x (size: %x)", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz)
4939
}
5040
if prog.Vaddr+prog.Memsz >= HEAP_START {
51-
return nil, fmt.Errorf("program %d overlaps with heap: %x - %x (size: %x). The heap start offset must be reconfigured", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz)
41+
return empty, fmt.Errorf("program %d overlaps with heap: %x - %x (size: %x). The heap start offset must be reconfigured", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz)
5242
}
53-
if err := s.Memory.SetMemoryRange(uint32(prog.Vaddr), r); err != nil {
54-
return nil, fmt.Errorf("failed to read program segment %d: %w", i, err)
43+
if err := s.GetMemory().SetMemoryRange(uint32(prog.Vaddr), r); err != nil {
44+
return empty, fmt.Errorf("failed to read program segment %d: %w", i, err)
5545
}
5646
}
5747

cannon/mipsevm/state.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
"github.com/ethereum/go-ethereum/crypto"
1111
)
1212

13-
// StateWitnessSize is the size of the state witness encoding in bytes.
14-
var StateWitnessSize = 226
13+
// STATE_WITNESS_SIZE is the size of the state witness encoding in bytes.
14+
const STATE_WITNESS_SIZE = 226
1515

1616
type CpuScalars struct {
1717
PC uint32 `json:"pc"`
@@ -48,6 +48,32 @@ type State struct {
4848
LastHint hexutil.Bytes `json:"lastHint,omitempty"`
4949
}
5050

51+
func CreateEmptyState() *State {
52+
return &State{
53+
Cpu: CpuScalars{
54+
PC: 0,
55+
NextPC: 0,
56+
LO: 0,
57+
HI: 0,
58+
},
59+
Heap: 0,
60+
Registers: [32]uint32{},
61+
Memory: NewMemory(),
62+
ExitCode: 0,
63+
Exited: false,
64+
Step: 0,
65+
}
66+
}
67+
68+
func CreateInitialState(pc, heapStart uint32) *State {
69+
state := CreateEmptyState()
70+
state.Cpu.PC = pc
71+
state.Cpu.NextPC = pc + 4
72+
state.Heap = heapStart
73+
74+
return state
75+
}
76+
5177
type stateMarshaling struct {
5278
Memory *Memory `json:"memory"`
5379
PreimageKey common.Hash `json:"preimageKey"`
@@ -121,7 +147,7 @@ func (s *State) GetMemory() *Memory {
121147
}
122148

123149
func (s *State) EncodeWitness() ([]byte, common.Hash) {
124-
out := make([]byte, 0)
150+
out := make([]byte, 0, STATE_WITNESS_SIZE)
125151
memRoot := s.Memory.MerkleRoot()
126152
out = append(out, memRoot[:]...)
127153
out = append(out, s.PreimageKey[:]...)
@@ -132,11 +158,7 @@ func (s *State) EncodeWitness() ([]byte, common.Hash) {
132158
out = binary.BigEndian.AppendUint32(out, s.Cpu.HI)
133159
out = binary.BigEndian.AppendUint32(out, s.Heap)
134160
out = append(out, s.ExitCode)
135-
if s.Exited {
136-
out = append(out, 1)
137-
} else {
138-
out = append(out, 0)
139-
}
161+
out = AppendBoolToWitness(out, s.Exited)
140162
out = binary.BigEndian.AppendUint64(out, s.Step)
141163
for _, r := range s.Registers {
142164
out = binary.BigEndian.AppendUint32(out, r)
@@ -154,14 +176,14 @@ const (
154176
)
155177

156178
func (sw StateWitness) StateHash() (common.Hash, error) {
157-
if len(sw) != 226 {
158-
return common.Hash{}, fmt.Errorf("Invalid witness length. Got %d, expected 226", len(sw))
179+
if len(sw) != STATE_WITNESS_SIZE {
180+
return common.Hash{}, fmt.Errorf("Invalid witness length. Got %d, expected %d", len(sw), STATE_WITNESS_SIZE)
159181
}
160182
return stateHashFromWitness(sw), nil
161183
}
162184

163185
func stateHashFromWitness(sw []byte) common.Hash {
164-
if len(sw) != 226 {
186+
if len(sw) != STATE_WITNESS_SIZE {
165187
panic("Invalid witness length")
166188
}
167189
hash := crypto.Keccak256Hash(sw)

0 commit comments

Comments
 (0)