From 9cd63b62d1798831502dc9ce50bcedf05ddc7c98 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 8 Aug 2023 10:22:40 -0400 Subject: [PATCH] General fixes and improvements --- pkg/vm/memory/memory.go | 59 +++++++++++++++++++++++++++------ pkg/vm/memory/memory_segment.go | 20 ++++++----- pkg/vm/vm.go | 15 ++++++--- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/pkg/vm/memory/memory.go b/pkg/vm/memory/memory.go index cfa58fe9..debe2f94 100644 --- a/pkg/vm/memory/memory.go +++ b/pkg/vm/memory/memory.go @@ -6,6 +6,12 @@ import ( f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) +const ( + programSegment = iota + executionSegment + userSegment +) + // Represents a write-once Memory Cell type Cell struct { Value *MemoryValue @@ -13,16 +19,27 @@ type Cell struct { } type Segment struct { - Data map[f.Element]Cell + Data []Cell +} + +func EmptySegment() *Segment { + return &Segment{ + Data: make([]Cell, 0), + } } -func EmptySegment() Segment { +func EmptySegmentWithCapacity(capacity int) Segment { return Segment{ - Data: make(map[f.Element]Cell), + Data: make([]Cell, 0, capacity), } } -func (segment *Segment) Write(index f.Element, value *MemoryValue) error { +func EmptySegmentWithLength(length int) Segment { + return Segment{ + Data: make([]Cell, length), + } +} +func (segment *Segment) Write(index uint64, value *MemoryValue) error { cell := segment.Data[index] if cell.Accessed { return fmt.Errorf("rewriting cell at %d, old value: %d new value: %d", index, &cell.Value, &value) @@ -32,7 +49,7 @@ func (segment *Segment) Write(index f.Element, value *MemoryValue) error { return nil } -func (segment *Segment) Read(index f.Element) *MemoryValue { +func (segment *Segment) Read(index uint64) *MemoryValue { cell := segment.Data[index] cell.Accessed = true return cell.Value @@ -41,17 +58,30 @@ func (segment *Segment) Read(index f.Element) *MemoryValue { // todo(rodro): Check out temprary segments // Represents the whole VM memory divided into segments type Memory struct { - Segments []Segment + Segments []*Segment } // todo(rodro): can the amount of segments be known before hand? -func InitializeEmptyMemory() Memory { - return Memory{ +func InitializeEmptyMemory() *Memory { + return &Memory{ // size 4 should be enough for the minimum amount of segments - Segments: make([]Segment, 4), + Segments: make([]*Segment, 4), } } +func (memory *Memory) LoadBytecode(bytecode *[]f.Element) error { + bytecodeSegment := EmptySegmentWithLength(len(*bytecode)) + for i := range *bytecode { + memVal := MemoryValueFromFieldElement(&(*bytecode)[i]) + err := bytecodeSegment.Write(uint64(i), memVal) + if err != nil { + return fmt.Errorf("cannot load bytecode: %w", err) + } + } + memory.Segments[programSegment] = &bytecodeSegment + return nil +} + // Allocates a new segment and returns its index func (memory *Memory) AllocateNewSegment() int { memory.Segments = append(memory.Segments, EmptySegment()) @@ -62,13 +92,20 @@ func (memory *Memory) Write(address *MemoryAddress, value *MemoryValue) error { if address.SegmentIndex > uint64(len(memory.Segments)) { return fmt.Errorf("writing to unallocated segment %d", address.SegmentIndex) } + if !address.Offset.IsUint64() { + return fmt.Errorf("writing index is too big: %s", address.Offset.String()) + } - return memory.Segments[address.SegmentIndex].Write(*address.Offset, value) + return memory.Segments[address.SegmentIndex].Write(address.Offset.Uint64(), value) } func (memory *Memory) Read(address *MemoryAddress) (*MemoryValue, error) { if address.SegmentIndex > uint64(len(memory.Segments)) { return nil, fmt.Errorf("reading from unallocated segment %d", address.SegmentIndex) } - return memory.Segments[address.SegmentIndex].Read(*address.Offset), nil + if !address.Offset.IsUint64() { + return nil, fmt.Errorf("reading index is too big: %s", address.Offset.String()) + } + + return memory.Segments[address.SegmentIndex].Read(address.Offset.Uint64()), nil } diff --git a/pkg/vm/memory/memory_segment.go b/pkg/vm/memory/memory_segment.go index 69002940..ee46f879 100644 --- a/pkg/vm/memory/memory_segment.go +++ b/pkg/vm/memory/memory_segment.go @@ -1,11 +1,13 @@ package memory import ( + "fmt" + f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) type MemoryManager struct { - Memory Memory + Memory *Memory // where the program byte code is stored // ProgramSegment *MemorySegment //// stores the function callstack (fp, ap, local variables) @@ -16,13 +18,15 @@ type MemoryManager struct { // BuiltinSegments *[]MemorySegment } -func CreateMemoryManager(programBytecode *[]f.Element) MemoryManager { - // memory := InitializeEmptyMemory() +func CreateMemoryManager(programBytecode *[]f.Element) (*MemoryManager, error) { + memory := InitializeEmptyMemory() - return MemoryManager{ - //ProgramSegment: &MemorySegment{Cells: *programBytecode}, - //ExecutionSegment: nil, - //UserSegment: nil, - //BuiltinSegments: nil, + err := memory.LoadBytecode(programBytecode) + if err != nil { + return nil, fmt.Errorf("error creating MemoryManager: %w", err) } + + return &MemoryManager{ + Memory: memory, + }, nil } diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 34b7c820..33e7231a 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1,6 +1,8 @@ package vm import ( + "fmt" + mem "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory" f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" ) @@ -19,17 +21,22 @@ type VirtualMachineConfig struct { type VirtualMachine struct { Context Context - MemoryManager mem.MemoryManager + MemoryManager *mem.MemoryManager Config VirtualMachineConfig } // NewVirtualMachine creates a VM from the program bytecode using a specified config. -func NewVirtualMachine(programBytecode *[]f.Element, config VirtualMachineConfig) *VirtualMachine { +func NewVirtualMachine(programBytecode *[]f.Element, config VirtualMachineConfig) (*VirtualMachine, error) { + manager, err := mem.CreateMemoryManager(programBytecode) + if err != nil { + return nil, fmt.Errorf("error creating new virtual machine: %w", err) + } + return &VirtualMachine{ Context{Fp: 0, Ap: 0, Pc: 0}, - mem.CreateMemoryManager(programBytecode), + manager, config, - } + }, nil } // RunInstructionFrom executes the program starting at the specified Program Counter.