Skip to content

Commit

Permalink
cannon: Improve comments for serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
ajsutton committed Sep 5, 2024
1 parent dd07897 commit fa92040
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 59 deletions.
9 changes: 9 additions & 0 deletions cannon/mipsevm/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@ func (m *Memory) SetMemoryRange(addr uint32, r io.Reader) error {
}
}

// Serialize writes the memory in a simple binary format which can be read again using Deserialize
// The format is a simple concatenation of fields, with prefixed item count for repeating items and using big endian
// encoding for numbers.
//
// len(PageCount) uint32
// For each page (order is arbitrary):
//
// page index uint32
// page Data [PageSize]byte
func (m *Memory) Serialize(out io.Writer) error {
if err := binary.Write(out, binary.BigEndian, uint32(m.PageCount())); err != nil {
return err
Expand Down
54 changes: 23 additions & 31 deletions cannon/mipsevm/multithreaded/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,54 +222,65 @@ func (s *State) ThreadCount() int {
return len(s.LeftThreadStack) + len(s.RightThreadStack)
}

// Serialize writes the state in a simple binary format which can be read again using Deserialize
// The format is a simple concatenation of fields, with prefixed item count for repeating items and using big endian
// encoding for numbers.
//
// StateVersion uint8(1)
// Memory As per Memory.Serialize
// PreimageKey [32]byte
// PreimageOffset uint32
// Heap uint32
// ExitCode uint8
// Exited uint8 - 0 for false, 1 for true
// Step uint64
// StepsSinceLastContextSwitch uint64
// Wakeup uint32
// TraverseRight uint8 - 0 for false, 1 for true
// NextThreadId uint32
// len(LeftThreadStack) uint32
// LeftThreadStack entries as per ThreadState.Serialize
// len(RightThreadStack) uint32
// RightThreadStack entries as per ThreadState.Serialize
// len(LastHint) uint32 (0 when LastHint is nil)
// LastHint []byte
func (s *State) Serialize(out io.Writer) error {
// Write the version byte to the buffer.
if err := binary.Write(out, binary.BigEndian, StateVersion); err != nil {
return err
}

// Write memory
if err := s.Memory.Serialize(out); err != nil {
return err
}
// Write the preimage key as a 32-byte hash
if _, err := out.Write(s.PreimageKey[:]); err != nil {
return err
}
// Write the preimage offset as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.PreimageOffset); err != nil {
return err
}
// Write the Heap pointer as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Heap); err != nil {
return err
}
// Write the exit code as a single byte
if err := binary.Write(out, binary.BigEndian, s.ExitCode); err != nil {
return err
}
// Write the exited flag as a single byte
var exited uint8
if s.Exited {
exited = 1
}
if err := binary.Write(out, binary.BigEndian, exited); err != nil {
return err
}
// Write the step counter as a big endian uint64
if err := binary.Write(out, binary.BigEndian, s.Step); err != nil {
return err
}
// Write the step since last context switch counter as a big endian uint64
if err := binary.Write(out, binary.BigEndian, s.StepsSinceLastContextSwitch); err != nil {
return err
}
// Write wake up as big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Wakeup); err != nil {
return err
}

// Write traverse right flag as a single byte
var traverseRight uint8
if s.TraverseRight {
traverseRight = 1
Expand All @@ -278,27 +289,22 @@ func (s *State) Serialize(out io.Writer) error {
return err
}

// Write next thread ID as big endian uint32
if err := binary.Write(out, binary.BigEndian, s.NextThreadId); err != nil {
return err
}

// Write size of left thread stack as big endian uint32
if err := binary.Write(out, binary.BigEndian, uint32(len(s.LeftThreadStack))); err != nil {
return err
}
// Write the left thread stack states
for _, stack := range s.LeftThreadStack {
if err := stack.Serialize(out); err != nil {
return err
}
}

// Write size of right thread stack as big endian uint32
if err := binary.Write(out, binary.BigEndian, uint32(len(s.RightThreadStack))); err != nil {
return err
}
// Write the right thread stack states
for _, stack := range s.RightThreadStack {
if err := stack.Serialize(out); err != nil {
return err
Expand Down Expand Up @@ -329,7 +335,6 @@ func (s *State) Serialize(out io.Writer) error {
}

func (s *State) Deserialize(in io.Reader) error {
// Read the version byte from the buffer.
var version uint8
if err := binary.Read(in, binary.BigEndian, &version); err != nil {
return err
Expand All @@ -341,25 +346,20 @@ func (s *State) Deserialize(in io.Reader) error {
if err := s.Memory.Deserialize(in); err != nil {
return err
}
// Read the preimage key as a 32-byte hash
if _, err := io.ReadFull(in, s.PreimageKey[:]); err != nil {
return err
}
// Read the preimage offset as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.PreimageOffset); err != nil {
return err
}
// Read the Heap pointer as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Heap); err != nil {
return err
}
// Read the exit code as a single byte
var exitCode uint8
if err := binary.Read(in, binary.BigEndian, &exitCode); err != nil {
return err
}
s.ExitCode = exitCode
// Read the exited flag as a single byte
var exited uint8
if err := binary.Read(in, binary.BigEndian, &exited); err != nil {
return err
Expand All @@ -369,32 +369,26 @@ func (s *State) Deserialize(in io.Reader) error {
} else {
s.Exited = false
}
// Read the step counter as a big endian uint64
if err := binary.Read(in, binary.BigEndian, &s.Step); err != nil {
return err
}
// Read the steps since last context switch counter as a big endian uint64
if err := binary.Read(in, binary.BigEndian, &s.StepsSinceLastContextSwitch); err != nil {
return err
}
// Read the wakeup counter as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Wakeup); err != nil {
return err
}

// Read traverse right flag as single byte
var traverseRight uint8
if err := binary.Read(in, binary.BigEndian, &traverseRight); err != nil {
return nil
}
s.TraverseRight = traverseRight != 0

// Read the next thread ID as big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.NextThreadId); err != nil {
return err
}

// Read length of left thread stack as big endian uint32
var leftThreadStackSize uint32
if err := binary.Read(in, binary.BigEndian, &leftThreadStackSize); err != nil {
return err
Expand All @@ -407,7 +401,6 @@ func (s *State) Deserialize(in io.Reader) error {
}
}

// Read length of right thread stack as big endian uint32
var rightThreadStackSize uint32
if err := binary.Read(in, binary.BigEndian, &rightThreadStackSize); err != nil {
return err
Expand All @@ -420,8 +413,7 @@ func (s *State) Deserialize(in io.Reader) error {
}
}

// Read the length of the last hint as a big endian uint32.
// Note that the length is set to 0 even if the hint is nil.
// Note that a zero length is always interpreted as nil
var lastHintLen uint32
if err := binary.Read(in, binary.BigEndian, &lastHintLen); err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions cannon/mipsevm/multithreaded/thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ func (t *ThreadState) serializeThread() []byte {
return out
}

// Serialize writes the ThreadState in a simple binary format which can be read again using Deserialize
// The format exactly matches the serialization generated by serializeThread used for thread proofs.
func (t *ThreadState) Serialize(out io.Writer) error {
_, err := out.Write(t.serializeThread())
return err
Expand Down
48 changes: 20 additions & 28 deletions cannon/mipsevm/singlethreaded/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,68 +180,73 @@ func (s *State) EncodeWitness() ([]byte, common.Hash) {
return out, stateHashFromWitness(out)
}

// Serialize writes the state in a simple binary format which can be read again using Deserialize
// The format is a simple concatenation of fields, with prefixed item count for repeating items and using big endian
// encoding for numbers.
//
// StateVersion uint8(0)
// Memory As per Memory.Serialize
// PreimageKey [32]byte
// PreimageOffset uint32
// Cpu.PC uint32
// Cpu.NextPC uint32
// Cpu.LO uint32
// Cpu.HI uint32
// Heap uint32
// ExitCode uint8
// Exited uint8 - 0 for false, 1 for true
// Step uint64
// Registers [32]uint32
// len(LastHint) uint32 (0 when LastHint is nil)
// LastHint []byte
func (s *State) Serialize(out io.Writer) error {
// Write the version byte to the buffer.
if err := binary.Write(out, binary.BigEndian, StateVersion); err != nil {
return err
}

// Write memory
if err := s.Memory.Serialize(out); err != nil {
return err
}
// Write the preimage key as a 32-byte hash
if _, err := out.Write(s.PreimageKey[:]); err != nil {
return err
}
// Write the preimage offset as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.PreimageOffset); err != nil {
return err
}
// Write the PC as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Cpu.PC); err != nil {
return err
}
// Write the NextPC as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Cpu.NextPC); err != nil {
return err
}
// Write the LO register as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Cpu.LO); err != nil {
return err
}
// Write the HI register as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Cpu.HI); err != nil {
return err
}
// Write the Heap pointer as a big endian uint32
if err := binary.Write(out, binary.BigEndian, s.Heap); err != nil {
return err
}
// Write the exit code as a single byte
if err := binary.Write(out, binary.BigEndian, s.ExitCode); err != nil {
return err
}
// Write the exited flag as a single byte
var exited uint8
if s.Exited {
exited = 1
}
if err := binary.Write(out, binary.BigEndian, exited); err != nil {
return err
}
// Write the step counter as a big endian uint64
if err := binary.Write(out, binary.BigEndian, s.Step); err != nil {
return err
}
// Write the registers as big endian uint32s
for _, r := range s.Registers {
if err := binary.Write(out, binary.BigEndian, r); err != nil {
return err
}
}

// Write the length of the last hint as a big endian uint32.
// Note that the length is set to 0 even if the hint is nil.
if s.LastHint == nil {
if err := binary.Write(out, binary.BigEndian, uint32(0)); err != nil {
Expand All @@ -265,7 +270,6 @@ func (s *State) Serialize(out io.Writer) error {
}

func (s *State) Deserialize(in io.Reader) error {
// Read the version byte from the buffer.
var version uint8
if err := binary.Read(in, binary.BigEndian, &version); err != nil {
return err
Expand All @@ -277,41 +281,32 @@ func (s *State) Deserialize(in io.Reader) error {
if err := s.Memory.Deserialize(in); err != nil {
return err
}
// Read the preimage key as a 32-byte hash
if _, err := io.ReadFull(in, s.PreimageKey[:]); err != nil {
return err
}
// Read the preimage offset as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.PreimageOffset); err != nil {
return err
}
// Read the PC as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Cpu.PC); err != nil {
return err
}
// Read the NextPC as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Cpu.NextPC); err != nil {
return err
}
// Read the LO register as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Cpu.LO); err != nil {
return err
}
// Read the HI register as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Cpu.HI); err != nil {
return err
}
// Read the Heap pointer as a big endian uint32
if err := binary.Read(in, binary.BigEndian, &s.Heap); err != nil {
return err
}
// Read the exit code as a single byte
var exitCode uint8
if err := binary.Read(in, binary.BigEndian, &exitCode); err != nil {
return err
}
s.ExitCode = exitCode
// Read the exited flag as a single byte
var exited uint8
if err := binary.Read(in, binary.BigEndian, &exited); err != nil {
return err
Expand All @@ -321,19 +316,16 @@ func (s *State) Deserialize(in io.Reader) error {
} else {
s.Exited = false
}
// Read the step counter as a big endian uint64
if err := binary.Read(in, binary.BigEndian, &s.Step); err != nil {
return err
}
// Read the registers as big endian uint32s
for i := range s.Registers {
if err := binary.Read(in, binary.BigEndian, &s.Registers[i]); err != nil {
return err
}
}

// Read the length of the last hint as a big endian uint32.
// Note that the length is set to 0 even if the hint is nil.
// Note that a zero length is always interpreted as nil
var lastHintLen uint32
if err := binary.Read(in, binary.BigEndian, &lastHintLen); err != nil {
return err
Expand Down

0 comments on commit fa92040

Please sign in to comment.