Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExecutionResources + fix CairoRunner methods that received vm as an argument #300

Merged
merged 6 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 114 additions & 57 deletions pkg/runners/cairo_runner.go

Large diffs are not rendered by default.

104 changes: 73 additions & 31 deletions pkg/runners/cairo_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,11 +567,10 @@ func TestCheckRangeCheckUsagePermRangeLimitsNone(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

virtualMachine.Trace = make([]vm.TraceEntry, 0)
runner.Vm.Trace = make([]vm.TraceEntry, 0)

err = runner.CheckRangeCheckUsage(virtualMachine)
err = runner.CheckRangeCheckUsage()
if err != nil {
t.Errorf("Check Range Usage Failed With Error %s", err)
}
Expand All @@ -584,18 +583,17 @@ func TestCheckRangeCheckUsageWithoutBuiltins(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

virtualMachine.Trace = make([]vm.TraceEntry, 0)
virtualMachine.CurrentStep = 1000
virtualMachine.Segments.Memory.Insert(
runner.Vm.Trace = make([]vm.TraceEntry, 0)
runner.Vm.CurrentStep = 1000
runner.Vm.Segments.Memory.Insert(
memory.NewRelocatable(0, 0),
memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromHex("0x80FF80000530")),
)

virtualMachine.Trace = make([]vm.TraceEntry, 1)
virtualMachine.Trace[0] = vm.TraceEntry{Pc: memory.NewRelocatable(0, 0), Ap: memory.NewRelocatable(0, 0), Fp: memory.NewRelocatable(0, 0)}
err = runner.CheckRangeCheckUsage(virtualMachine)
runner.Vm.Trace = make([]vm.TraceEntry, 1)
runner.Vm.Trace[0] = vm.TraceEntry{Pc: memory.NewRelocatable(0, 0), Ap: memory.NewRelocatable(0, 0), Fp: memory.NewRelocatable(0, 0)}
err = runner.CheckRangeCheckUsage()
if err != nil {
t.Errorf("Check Range Usage Failed With Error %s", err)
}
Expand All @@ -620,7 +618,7 @@ func TestCheckRangeUsageInsufficientAllocatedCells(t *testing.T) {
runner.Vm.Trace = make([]vm.TraceEntry, 1)
runner.Vm.Trace[0] = vm.TraceEntry{Pc: memory.NewRelocatable(0, 0), Ap: memory.NewRelocatable(0, 0), Fp: memory.NewRelocatable(0, 0)}
runner.Vm.Segments.ComputeEffectiveSizes()
err = runner.CheckRangeCheckUsage(&runner.Vm)
err = runner.CheckRangeCheckUsage()
if err == nil {
t.Error("Check Range Usage Should Have Failed With Insufficient Allocated Cells Error")
}
Expand All @@ -633,11 +631,10 @@ func TestCheckDilutedCheckUsageWithoutPoolInstance(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

runner.Layout.DilutedPoolInstance = nil

err = runner.CheckDilutedCheckUsage(virtualMachine)
err = runner.CheckDilutedCheckUsage()
if err != nil {
t.Errorf("Check Diluted Check Usage Failed With Error %s", err)
}
Expand All @@ -650,12 +647,11 @@ func TestCheckDilutedCheckUsageWithoutBuiltinRunners(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

virtualMachine.CurrentStep = 10000
virtualMachine.BuiltinRunners = make([]builtins.BuiltinRunner, 0)
runner.Vm.CurrentStep = 10000
runner.Vm.BuiltinRunners = make([]builtins.BuiltinRunner, 0)

err = runner.CheckDilutedCheckUsage(virtualMachine)
err = runner.CheckDilutedCheckUsage()
if err != nil {
t.Errorf("Check Diluted Check Usage Failed With Error %s", err)
}
Expand All @@ -668,12 +664,11 @@ func TestCheckDilutedCheckUsageInsufficientAllocatedCells(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

virtualMachine.CurrentStep = 100
virtualMachine.BuiltinRunners = make([]builtins.BuiltinRunner, 0)
runner.Vm.CurrentStep = 100
runner.Vm.BuiltinRunners = make([]builtins.BuiltinRunner, 0)

err = runner.CheckDilutedCheckUsage(virtualMachine)
err = runner.CheckDilutedCheckUsage()
if err == nil {
t.Errorf("Check Diluted Check Usage Should Have failed With Insufficient Allocated Cells Error")
}
Expand All @@ -686,13 +681,12 @@ func TestCheckDilutedCheckUsage(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

virtualMachine.CurrentStep = 8192
virtualMachine.BuiltinRunners = make([]builtins.BuiltinRunner, 0)
virtualMachine.BuiltinRunners = append(virtualMachine.BuiltinRunners, builtins.NewBitwiseBuiltinRunner(256))
runner.Vm.CurrentStep = 8192
runner.Vm.BuiltinRunners = make([]builtins.BuiltinRunner, 0)
runner.Vm.BuiltinRunners = append(runner.Vm.BuiltinRunners, builtins.NewBitwiseBuiltinRunner(256))

err = runner.CheckDilutedCheckUsage(virtualMachine)
err = runner.CheckDilutedCheckUsage()
if err != nil {
t.Errorf("Check Diluted Check Usage Failed With Error %s", err)
}
Expand All @@ -706,14 +700,62 @@ func TestCheckUsedCellsDilutedCheckUsageError(t *testing.T) {
if err != nil {
t.Error("Could not initialize Cairo Runner")
}
virtualMachine := vm.NewVirtualMachine()

virtualMachine.Segments.SegmentUsedSizes = make(map[uint]uint)
virtualMachine.Segments.SegmentUsedSizes[0] = 4
virtualMachine.Trace = []vm.TraceEntry{}
runner.Vm.Segments.SegmentUsedSizes = make(map[uint]uint)
runner.Vm.Segments.SegmentUsedSizes[0] = 4
runner.Vm.Trace = []vm.TraceEntry{}

err = runner.CheckUsedCells(virtualMachine)
err = runner.CheckUsedCells()
if err == nil {
t.Errorf("Check Used Cells Should Have failed With Insufficient Allocated Cells Error")
}
}

func TestRunFibonacciGetExecutionResources(t *testing.T) {
cairoRunConfig := cairo_run.CairoRunConfig{Layout: "all_cairo", ProofMode: false}
runner, err := cairo_run.CairoRun("../../cairo_programs/fibonacci.json", cairoRunConfig)
if err != nil {
t.Errorf("Program execution failed with error: %s", err)
}
expectedExecutionResources := runners.ExecutionResources{
NSteps: 80,
BuiltinsInstanceCounter: make(map[string]uint),
}
executionResources, _ := runner.GetExecutionResources()
if !reflect.DeepEqual(executionResources, expectedExecutionResources) {
t.Errorf("Wong ExecutionResources.\n Expected : %+v, got: %+v", expectedExecutionResources, executionResources)
}
}

// This test will run the `fib` function in the fibonacci.json program
func TestRunFromEntryPointFibonacci(t *testing.T) {
compiledProgram, _ := parser.Parse("../../cairo_programs/fibonacci.json")
programJson := vm.DeserializeProgramJson(compiledProgram)

entrypoint := programJson.Identifiers["__main__.fib"].PC
args := []any{
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltOne()),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltOne()),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(10)),
}
runner, _ := runners.NewCairoRunner(programJson, "all_cairo", false)
hintProcessor := hints.CairoVmHintProcessor{}

runner.InitializeBuiltins()
runner.InitializeSegments()
err := runner.RunFromEntrypoint(uint(entrypoint), args, &hintProcessor)

if err != nil {
t.Errorf("Running fib entrypoint failed with error %s", err.Error())
}

// Check result
res, err := runner.Vm.GetReturnValues(1)
if err != nil {
t.Errorf("Failed to fetch return values from fib with error %s", err.Error())
}
if len(res) != 1 || !reflect.DeepEqual(res[0], *memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(144))) {
t.Errorf("Wrong value returned by fib entrypoint.\n Expected [144], got: %+v", res)
}

}
7 changes: 7 additions & 0 deletions pkg/runners/execution_resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package runners

type ExecutionResources struct {
NSteps uint
NMemoryHoles uint
BuiltinsInstanceCounter map[string]uint
}
6 changes: 3 additions & 3 deletions pkg/vm/cairo_run/cairo_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,18 @@ func CairoRun(programPath string, cairoRunConfig CairoRunConfig) (*runners.Cairo
if err != nil {
return nil, err
}
err = cairoRunner.EndRun(cairoRunConfig.DisableTracePadding, false, &cairoRunner.Vm, &hintProcessor)
err = cairoRunner.EndRun(cairoRunConfig.DisableTracePadding, false, &hintProcessor)
if err != nil {
return nil, err
}

err = cairoRunner.ReadReturnValues(&cairoRunner.Vm)
err = cairoRunner.ReadReturnValues()
if err != nil {
return nil, err
}

if cairoRunConfig.ProofMode {
cairoRunner.FinalizeSegments(cairoRunner.Vm)
cairoRunner.FinalizeSegments()
}

err = cairoRunner.Vm.Relocate()
Expand Down
38 changes: 38 additions & 0 deletions pkg/vm/memory/segments.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package memory

import (
"errors"

"github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
)

Expand Down Expand Up @@ -186,3 +188,39 @@ func (m *MemorySegmentManager) GetFeltRange(start Relocatable, size uint) ([]lam
}
return feltRange, nil
}

/*
Converts a generic argument into a MaybeRelocatable
If the argument is a slice, it loads it into memory in a new segment and returns its base
Accepts MaybeRelocatable, []MaybeRelocatable, [][]MaybeRelocatable
*/
func (m *MemorySegmentManager) GenArg(arg any) (MaybeRelocatable, error) {
// Attempt to cast to MaybeRelocatable
a, ok := arg.(MaybeRelocatable)
if ok {
return a, nil
}
// Attempt to cast to []MaybeRelocatable
data, ok := arg.([]MaybeRelocatable)
if ok {
base := m.AddSegment()
_, err := m.LoadData(base, &data)
return *NewMaybeRelocatableRelocatable(base), err
}
// Attempt to cast to [][]MaybeRelocatable
datas, ok := arg.([][]MaybeRelocatable)
if ok {
args := make([]MaybeRelocatable, 0)
for _, data = range datas {
dataBase, err := m.GenArg(data)
if err != nil {
return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), err
}
args = append(args, dataBase)
}
base := m.AddSegment()
_, err := m.LoadData(base, &args)
return *NewMaybeRelocatableRelocatable(base), err
}
return *NewMaybeRelocatableFelt(lambdaworks.FeltZero()), errors.New("GenArg: found argument of invalid type.")
}
49 changes: 49 additions & 0 deletions pkg/vm/memory/segments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,52 @@ func TestGetFeltRangeRelocatable(t *testing.T) {
t.Errorf("GetFeltRange should have failed")
}
}

func TestGenArgMaybeRelocatable(t *testing.T) {
segments := memory.NewMemorySegmentManager()
arg := any(*memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero()))
expectedArg := *memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero())
genedArg, err := segments.GenArg(arg)
if err != nil || !reflect.DeepEqual(expectedArg, genedArg) {
t.Error("GenArg failed or returned wrong value")
}
}

func TestGenArgSliceMaybeRelocatable(t *testing.T) {
segments := memory.NewMemorySegmentManager()
arg := any([]memory.MaybeRelocatable{*memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero())})

expectedBase := memory.NewRelocatable(0, 0)
expectedArg := *memory.NewMaybeRelocatableRelocatable(expectedBase)
genedArg, err := segments.GenArg(arg)
if err != nil || !reflect.DeepEqual(expectedArg, genedArg) {
t.Error("GenArg failed or returned wrong value")
}
val, err := segments.Memory.GetFelt(expectedBase)
if err != nil || !val.IsZero() {
t.Error("GenArg inserted wrong value into memory")
}
}

func TestGenArgSliceSliceMaybeRelocatable(t *testing.T) {
segments := memory.NewMemorySegmentManager()
arg := any([][]memory.MaybeRelocatable{{*memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero())}})

expectedBaseA := memory.NewRelocatable(1, 0)
expectedBaseB := memory.NewRelocatable(0, 0)
expectedArg := *memory.NewMaybeRelocatableRelocatable(expectedBaseA)
genedArg, err := segments.GenArg(arg)

if err != nil || !reflect.DeepEqual(expectedArg, genedArg) {
t.Error("GenArg failed or returned wrong value")
}
valA, err := segments.Memory.GetRelocatable(expectedBaseA)
if err != nil || valA != expectedBaseB {
t.Error("GenArg inserted wrong value into memory")
}

valB, err := segments.Memory.GetFelt(expectedBaseB)
if err != nil || !valB.IsZero() {
t.Error("GenArg inserted wrong value into memory")
}
}
9 changes: 9 additions & 0 deletions pkg/vm/vm_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,3 +642,12 @@ func (vm *VirtualMachine) GetRangeCheckBound() (lambdaworks.Felt, error) {

return rcBuiltin.Bound(), nil
}

// Gets `nRet` return values from memory
func (vm *VirtualMachine) GetReturnValues(nRet uint) ([]memory.MaybeRelocatable, error) {
ptr, err := vm.RunContext.Ap.SubUint(nRet)
if err != nil {
return nil, err
}
return vm.Segments.Memory.GetRange(ptr, nRet)
}
28 changes: 28 additions & 0 deletions pkg/vm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1088,3 +1088,31 @@ func TestGetFooBuiltinReturnsNilAndError(t *testing.T) {
t.Error("Obtained a non existant builtin, or didn't raise an error")
}
}

func TestReadReturnValuesOk(t *testing.T) {
vm := vm.NewVirtualMachine()
vm.Segments.AddSegment()
// Load data at ap and advance ap
data := []memory.MaybeRelocatable{
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(1)),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(2)),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(3)),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(4)),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(5)),
}
vm.RunContext.Ap, _ = vm.Segments.LoadData(vm.RunContext.Ap, &data)
// Fetch 3 return values
expectedReturnValues := []memory.MaybeRelocatable{
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(3)),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(4)),
*memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromUint(5)),
}
returnValues, err := vm.GetReturnValues(3)
if err != nil {
t.Errorf("GetReturnValues failed with error: %s", err.Error())
}

if !reflect.DeepEqual(expectedReturnValues, returnValues) {
t.Errorf("Wrong return values.\n Expected: %+v, got: %+v", expectedReturnValues, returnValues)
}
}