From fae330d2872fdae9deb044c482bfe89d5c5df9d0 Mon Sep 17 00:00:00 2001 From: MaksymMalicki <81577596+MaksymMalicki@users.noreply.github.com> Date: Tue, 14 Jan 2025 09:16:07 -0500 Subject: [PATCH] Missing dict functionalities (#680) * Fixes for the generation of entry code, fixes of hints parsing * Add modifications to the runner * Add fixes for the entrycode generation * Refactor main CLI, offset the hints indexes by entry code size, load arguments and initial gas to the memory * Add available gas and user args (#677) * Add parsing logic for input user args * Add flags for available gas, input user args, writing args to memory * Fix unit tests for user arguments parsing * Lint the PR * Add user args to hint context * Refactor the code * Fix unconditional append of ExternalWriteArgsToMemory, bug fixes in integration tests * Add fixes of the call size calculation and include ExternalWriteArgsToMemory hint when gas present * Add layouts for integration tests * Add error handling * Fixes in entry code generation * Address changes mentioned in a discussion * Add comment regarding writing to memory in a hint for the future reference in the integration tests with args * Changes in calculations of the initial PC offset, CALL opcode offset incremented by mainFuncOffset, writing user args to the AP in the hint * Turn back VM config to private field * Add error handling on assign of `userArgs` to the initial scope * Lint project * Bump go version from 1.20 -> 1.21 (#678) * Bump go version from 1.20 -> 1.21 * Update golangci-lint * Simplify the Makefile * Correction in the makefile * Fix the integration tests * Fixes in the runner * Fixes in the runner * Fix the unit tests, uncomment pythonVm execution in integration tests, code cleanups * Add writing tokens gas cost to memory * Proper builtins initialization for cairo mode * Address comments in the PR * Fix bugs regarding dicts * Remove prints * Fixes of the last tests for the dicts * Add dict_non_squashed dir to the integration tests * Address all the comments --- integration_tests/cairo_vm_test.go | 1 + pkg/hintrunner/core/hint.go | 25 ++++++++++++------ pkg/runner/gas.go | 4 +-- pkg/runner/runner.go | 42 ++++++++++++++++++++++++++---- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/integration_tests/cairo_vm_test.go b/integration_tests/cairo_vm_test.go index 1ae4e157..d6822065 100644 --- a/integration_tests/cairo_vm_test.go +++ b/integration_tests/cairo_vm_test.go @@ -180,6 +180,7 @@ func TestCairoFiles(t *testing.T) { {"./cairo_zero_file_tests/", true}, {"./builtin_tests/", true}, // {"./cairo_1_programs/", false}, + // {"./cairo_1_programs/dict_non_squashed", false}, } // filter is for debugging purposes diff --git a/pkg/hintrunner/core/hint.go b/pkg/hintrunner/core/hint.go index d1540ae0..6667335b 100644 --- a/pkg/hintrunner/core/hint.go +++ b/pkg/hintrunner/core/hint.go @@ -1143,7 +1143,8 @@ func (hint *Felt252DictEntryInit) Execute(vm *VM.VirtualMachine, ctx *hinter.Hin prevValue, err := ctx.DictionaryManager.At(dictPtr, key) if err != nil { - return fmt.Errorf("get dictionary entry: %w", err) + mv := mem.MemoryValueFromFieldElement(&utils.FeltZero) + prevValue = &mv } if prevValue == nil { mv := mem.EmptyMemoryValueAsFelt() @@ -1234,10 +1235,10 @@ func (hint *InitSquashData) String() string { } func (hint *InitSquashData) Execute(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error { - // todo(rodro): Don't know if it could be called multiple times, or err := hinter.InitializeSquashedDictionaryManager(ctx) if err != nil { - return err + ctx.SquashedDictionaryManager = hinter.SquashedDictionaryManager{} + _ = hinter.InitializeSquashedDictionaryManager(ctx) } dictAccessPtr, err := hinter.ResolveAsAddress(vm, hint.DictAccesses) @@ -1272,7 +1273,7 @@ func (hint *InitSquashData) Execute(vm *VM.VirtualMachine, ctx *hinter.HintRunne // sort the keys in descending order sort.Slice(ctx.SquashedDictionaryManager.Keys, func(i, j int) bool { - return ctx.SquashedDictionaryManager.Keys[i].Cmp(&ctx.SquashedDictionaryManager.Keys[j]) < 0 + return ctx.SquashedDictionaryManager.Keys[i].Cmp(&ctx.SquashedDictionaryManager.Keys[j]) > 0 }) // if the first key is bigger than 2^128, signal it @@ -1401,11 +1402,15 @@ func (hint *ShouldContinueSquashLoop) Execute(vm *VM.VirtualMachine, ctx *hinter } var shouldContinueLoop f.Element - if lastIndices, err := ctx.SquashedDictionaryManager.LastIndices(); err == nil && len(lastIndices) <= 1 { - shouldContinueLoop.SetOne() - } else if err != nil { + lastIndices, err := ctx.SquashedDictionaryManager.LastIndices() + if err != nil { return fmt.Errorf("get last indices: %w", err) } + if len(lastIndices) > 1 { + shouldContinueLoop.SetOne() + } else { + shouldContinueLoop.SetZero() + } mv := mem.MemoryValueFromFieldElement(&shouldContinueLoop) return vm.Memory.WriteToAddress(&shouldContinuePtr, &mv) @@ -1425,11 +1430,15 @@ func (hint *GetNextDictKey) Execute(vm *VM.VirtualMachine, ctx *hinter.HintRunne return fmt.Errorf("get next key address: %w", err) } - nextKey, err := ctx.SquashedDictionaryManager.PopKey() + _, err = ctx.SquashedDictionaryManager.PopKey() if err != nil { return fmt.Errorf("pop key: %w", err) } + nextKey, err := ctx.SquashedDictionaryManager.LastKey() + if err != nil { + return fmt.Errorf("get last key: %w", err) + } mv := mem.MemoryValueFromFieldElement(&nextKey) return vm.Memory.WriteToAddress(&nextKeyAddr, &mv) } diff --git a/pkg/runner/gas.go b/pkg/runner/gas.go index 57446b8a..f825cd7a 100644 --- a/pkg/runner/gas.go +++ b/pkg/runner/gas.go @@ -50,8 +50,8 @@ func gasInitialization(memory *mem.Memory) error { if err != nil { return err } - - preCostTokenTypes := []TokenGasCost{PedersenToken, BitwiseToken, EcOpToken, PoseidonToken, AddModToken, MulModToken} + // The order of the tokens is relevant, source: https://github.com/starkware-libs/cairo/blob/f6aaaa306804257bfc15d65b5ab6b90e141b54ec/crates/cairo-lang-sierra/src/extensions/modules/gas.rs#L194 + preCostTokenTypes := []TokenGasCost{PedersenToken, PoseidonToken, BitwiseToken, EcOpToken, AddModToken, MulModToken} for _, token := range preCostTokenTypes { cost, err := getTokenGasCost(token) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index b5cfa851..225f9266 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -541,13 +541,47 @@ func GetEntryCodeInstructions(function starknet.EntryPointByFunction, finalizeFo } ctx := &InlineCasmContext{} + + gotSegmentArena := false + for _, builtin := range function.Builtins { + if builtin == builtins.SegmentArenaType { + gotSegmentArena = true + } + } + + hints := make(map[uint64][]hinter.Hinter) + + if gotSegmentArena { + hints[uint64(ctx.currentCodeOffset)] = []hinter.Hinter{ + &core.AllocSegment{ + Dst: hinter.ApCellRef(0), + }, + &core.AllocSegment{ + Dst: hinter.ApCellRef(1), + }, + } + ctx.AddInlineCASM( + "[ap+2] = 0, ap++;", + ) + ctx.AddInlineCASM( + "[ap] = [[ap-1]], ap++;", + ) + ctx.AddInlineCASM( + ` + [ap] = [[ap-2]+1], ap++; + [ap-1] = [[ap-3]+2]; + `, + ) + apOffset += 3 + } + paramsSize := 0 for _, param := range paramTypes { paramsSize += param.Size } apOffset += paramsSize usedArgs := 0 - var hints map[uint64][]hinter.Hinter + for _, builtin := range function.Builtins { if offset, isBuiltin := builtinsOffsetsMap[builtin]; isBuiltin { ctx.AddInlineCASM( @@ -561,10 +595,8 @@ func GetEntryCodeInstructions(function starknet.EntryPointByFunction, finalizeFo ) apOffset += 1 } else if builtin == builtins.GasBuiltinType { - hints = map[uint64][]hinter.Hinter{ - uint64(ctx.currentCodeOffset): { - &core.ExternalWriteArgsToMemory{}, - }, + hints[uint64(ctx.currentCodeOffset)] = []hinter.Hinter{ + &core.ExternalWriteArgsToMemory{}, } ctx.AddInlineCASM("ap += 1;") apOffset += 1