From 3173d137ff70ba296d643b065dacae10ab62b45a Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 11:13:20 -0300 Subject: [PATCH 01/10] Implement dict squash copy dict hint --- pkg/hints/dict_hint_codes.go | 2 ++ pkg/hints/dict_hints.go | 23 +++++++++++++++++++++++ pkg/hints/hint_processor.go | 2 ++ 3 files changed, 27 insertions(+) diff --git a/pkg/hints/dict_hint_codes.go b/pkg/hints/dict_hint_codes.go index cf9b3ebe..0d94a380 100644 --- a/pkg/hints/dict_hint_codes.go +++ b/pkg/hints/dict_hint_codes.go @@ -25,3 +25,5 @@ const SQUASH_DICT_INNER_LEN_ASSERT = "assert len(current_access_indices) == 0" const SQUASH_DICT_INNER_USED_ACCESSES_ASSERT = "assert ids.n_used_accesses == len(access_indices[key])" const SQUASH_DICT_INNER_NEXT_KEY = "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'\nids.next_key = key = keys.pop()" + +const DICT_SQUASH_COPY_DICT = "Prepare arguments for dict_new. In particular, the same dictionary values should be copied\n# to the new (squashed) dictionary.\nvm_enter_scope({\n # Make __dict_manager accessible.\n '__dict_manager': __dict_manager,\n # Create a copy of the dict, in case it changes in the future.\n 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),\n})" diff --git a/pkg/hints/dict_hints.go b/pkg/hints/dict_hints.go index 82159553..d659ffb0 100644 --- a/pkg/hints/dict_hints.go +++ b/pkg/hints/dict_hints.go @@ -141,3 +141,26 @@ func dictUpdate(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine) err tracker.CurrentPtr.Offset += DICT_ACCESS_SIZE return nil } + +func dictSquashCopyDict(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine) error { + // Extract Variables + dictManager, ok := FetchDictManager(scopes) + if !ok { + return errors.New("Variable __dict_manager not present in current execution scope") + } + dictAccessEnd, err := ids.GetRelocatable("dict_accesses_end", vm) + if err != nil { + return err + } + // Hint logic + tracker, err := dictManager.GetTracker(dictAccessEnd) + if err != nil { + return err + } + initialDict := tracker.CopyDictionary() + scopes.EnterScope(map[string]interface{}{ + "__dict_manager": dictManager, + "initial_dict": initialDict, + }) + return nil +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 776228c8..26c4b6a4 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -73,6 +73,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return squashDictInnerUsedAccessesAssert(data.Ids, execScopes, vm) case SQUASH_DICT_INNER_NEXT_KEY: return squashDictInnerNextKey(data.Ids, execScopes, vm) + case DICT_SQUASH_COPY_DICT: + return dictSquashCopyDict(data.Ids, execScopes, vm) case VM_EXIT_SCOPE: return vm_exit_scope(execScopes) case ASSERT_NOT_EQUAL: From 17fb3f1f7b1b3a02bed000c122ea184d7e0d448d Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 11:56:08 -0300 Subject: [PATCH 02/10] Add test --- pkg/hints/dict_hints_test.go | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index 76e5de9d..85ffffac 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -1,6 +1,7 @@ package hints_test import ( + "reflect" "testing" . "github.com/lambdaclass/cairo-vm.go/pkg/hints" @@ -413,3 +414,42 @@ func TestDictUpdateErr(t *testing.T) { t.Error("DICT_UPDATE hint test should have failed") } } + +func TestDictSqushCopyDictOkEmptyDict(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := types.NewExecutionScopes() + + // Create dictManager & add it to scope + dictManager := dict_manager.NewDictManager() + dictManagerRef := &dictManager + initialDict := map[MaybeRelocatable]MaybeRelocatable{ + *NewMaybeRelocatableFelt(FeltZero()): *NewMaybeRelocatableFelt(FeltOne()), + } + dict_ptr := dictManager.NewDictionary(&initialDict, vm) + scopes.AssignOrUpdateVariable("__dict_manager", dictManagerRef) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "dict_accesses_end": {NewMaybeRelocatableRelocatable(dict_ptr)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_SQUASH_COPY_DICT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DICT_SQUASH_COPY_DICT hint test failed with error %s", err) + } + // Check new scope + new_scope, _ := scopes.GetLocalVariables() + if !reflect.DeepEqual(new_scope, map[string]interface{}{ + "__dict_manager": dictManagerRef, + "initial_dict": initialDict, + }) { + t.Errorf("DICT_SQUASH_COPY_DICT hint test wrong new sope created") + } +} From 025234f97011e8d230fb444fa5c46290dd4fb257 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 11:59:10 -0300 Subject: [PATCH 03/10] Add test --- pkg/hints/dict_hints_test.go | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index 85ffffac..be3de9cf 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -420,11 +420,49 @@ func TestDictSqushCopyDictOkEmptyDict(t *testing.T) { vm.Segments.AddSegment() scopes := types.NewExecutionScopes() + // Create dictManager & add it to scope + dictManager := dict_manager.NewDictManager() + dictManagerRef := &dictManager + initialDict := map[MaybeRelocatable]MaybeRelocatable{} + dict_ptr := dictManager.NewDictionary(&initialDict, vm) + scopes.AssignOrUpdateVariable("__dict_manager", dictManagerRef) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "dict_accesses_end": {NewMaybeRelocatableRelocatable(dict_ptr)}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_SQUASH_COPY_DICT, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DICT_SQUASH_COPY_DICT hint test failed with error %s", err) + } + // Check new scope + new_scope, _ := scopes.GetLocalVariables() + if !reflect.DeepEqual(new_scope, map[string]interface{}{ + "__dict_manager": dictManagerRef, + "initial_dict": initialDict, + }) { + t.Errorf("DICT_SQUASH_COPY_DICT hint test wrong new sope created") + } +} + +func TestDictSqushCopyDictOkNonEmptyDict(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := types.NewExecutionScopes() + // Create dictManager & add it to scope dictManager := dict_manager.NewDictManager() dictManagerRef := &dictManager initialDict := map[MaybeRelocatable]MaybeRelocatable{ *NewMaybeRelocatableFelt(FeltZero()): *NewMaybeRelocatableFelt(FeltOne()), + *NewMaybeRelocatableFelt(FeltOne()): *NewMaybeRelocatableFelt(FeltOne()), } dict_ptr := dictManager.NewDictionary(&initialDict, vm) scopes.AssignOrUpdateVariable("__dict_manager", dictManagerRef) From 422eed9bee9616f86d1a26e5640343677f2d82ae Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:06:31 -0300 Subject: [PATCH 04/10] Add hint --- pkg/hints/dict_hint_codes.go | 2 ++ pkg/hints/dict_hints.go | 27 +++++++++++++++++++++++++++ pkg/hints/hint_processor.go | 2 ++ 3 files changed, 31 insertions(+) diff --git a/pkg/hints/dict_hint_codes.go b/pkg/hints/dict_hint_codes.go index 0d94a380..a55f6982 100644 --- a/pkg/hints/dict_hint_codes.go +++ b/pkg/hints/dict_hint_codes.go @@ -27,3 +27,5 @@ const SQUASH_DICT_INNER_USED_ACCESSES_ASSERT = "assert ids.n_used_accesses == le const SQUASH_DICT_INNER_NEXT_KEY = "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'\nids.next_key = key = keys.pop()" const DICT_SQUASH_COPY_DICT = "Prepare arguments for dict_new. In particular, the same dictionary values should be copied\n# to the new (squashed) dictionary.\nvm_enter_scope({\n # Make __dict_manager accessible.\n '__dict_manager': __dict_manager,\n # Create a copy of the dict, in case it changes in the future.\n 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),\n})" + +const DICT_SQUASH_UPDATE_PTR = "Update the DictTracker's current_ptr to point to the end of the squashed dict.\n__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\\n ids.squashed_dict_end.address_" diff --git a/pkg/hints/dict_hints.go b/pkg/hints/dict_hints.go index d659ffb0..cbf1914f 100644 --- a/pkg/hints/dict_hints.go +++ b/pkg/hints/dict_hints.go @@ -164,3 +164,30 @@ func dictSquashCopyDict(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMach }) return nil } + +// "Update the DictTracker's current_ptr to point to the end of the squashed dict. +// +// __dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\ +// ids.squashed_dict_end.address_" +func dictSquashUpdatePtr(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine) error { + // Extract Variables + dictManager, ok := FetchDictManager(scopes) + if !ok { + return errors.New("Variable __dict_manager not present in current execution scope") + } + squashedDictStart, err := ids.GetRelocatable("squashed_dict_start", vm) + if err != nil { + return err + } + squashedDictEnd, err := ids.GetRelocatable("squashed_dict_end", vm) + if err != nil { + return err + } + // Hint logic + tracker, err := dictManager.GetTracker(squashedDictStart) + if err != nil { + return err + } + tracker.CurrentPtr = squashedDictEnd + return nil +} diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 26c4b6a4..45d3f476 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -75,6 +75,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return squashDictInnerNextKey(data.Ids, execScopes, vm) case DICT_SQUASH_COPY_DICT: return dictSquashCopyDict(data.Ids, execScopes, vm) + case DICT_SQUASH_UPDATE_PTR: + return dictSquashUpdatePtr(data.Ids, execScopes, vm) case VM_EXIT_SCOPE: return vm_exit_scope(execScopes) case ASSERT_NOT_EQUAL: From 34fce0736d7ab579ec3e85c4347c7d4e90c2f884 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:15:56 -0300 Subject: [PATCH 05/10] Add test --- pkg/hints/dict_hints_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index be3de9cf..a1b6584f 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -491,3 +491,38 @@ func TestDictSqushCopyDictOkNonEmptyDict(t *testing.T) { t.Errorf("DICT_SQUASH_COPY_DICT hint test wrong new sope created") } } + +func TestDictSquashUpdatePtrOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := types.NewExecutionScopes() + initialDict := make(map[MaybeRelocatable]MaybeRelocatable) + // Create dictManager & add it to scope + dictManager := dict_manager.NewDictManager() + dict_ptr := dictManager.NewDictionary(&initialDict, vm) + // Keep a reference to the tracker to check that it was updated after the hint + tracker, _ := dictManager.GetTracker(dict_ptr) + scopes.AssignOrUpdateVariable("__dict_manager", &dictManager) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "squashed_dict_start": {NewMaybeRelocatableRelocatable(dict_ptr)}, + "squashed_dict_end": {NewMaybeRelocatableRelocatable(dict_ptr.AddUint(5))}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_SQUASH_UPDATE_PTR, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DICT_SQUASH_UPDATE_PTR hint test failed with error %s", err) + } + // Check updated ptr + if tracker.CurrentPtr != dict_ptr.AddUint(5) { + t.Error("DICT_SQUASH_UPDATE_PTR hint test failed: Wrong updated tracker.CurrentPtr") + } + +} From 3ecf99edf2223872b47dbb15c17a4f69097e7806 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:29:13 -0300 Subject: [PATCH 06/10] Add hint --- pkg/hints/dict_hint_codes.go | 2 ++ pkg/hints/dict_hints.go | 25 +++++++++++++++++++++---- pkg/hints/dict_hints_test.go | 27 +++++++++++++++++++++++++++ pkg/hints/hint_processor.go | 2 ++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/pkg/hints/dict_hint_codes.go b/pkg/hints/dict_hint_codes.go index a55f6982..bf37e624 100644 --- a/pkg/hints/dict_hint_codes.go +++ b/pkg/hints/dict_hint_codes.go @@ -29,3 +29,5 @@ const SQUASH_DICT_INNER_NEXT_KEY = "assert len(keys) > 0, 'No keys left but rema const DICT_SQUASH_COPY_DICT = "Prepare arguments for dict_new. In particular, the same dictionary values should be copied\n# to the new (squashed) dictionary.\nvm_enter_scope({\n # Make __dict_manager accessible.\n '__dict_manager': __dict_manager,\n # Create a copy of the dict, in case it changes in the future.\n 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),\n})" const DICT_SQUASH_UPDATE_PTR = "Update the DictTracker's current_ptr to point to the end of the squashed dict.\n__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\\n ids.squashed_dict_end.address_" + +const DICT_NEW = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_dict(segments, initial_dict)\ndel initial_dict" diff --git a/pkg/hints/dict_hints.go b/pkg/hints/dict_hints.go index cbf1914f..f6750355 100644 --- a/pkg/hints/dict_hints.go +++ b/pkg/hints/dict_hints.go @@ -165,10 +165,6 @@ func dictSquashCopyDict(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMach return nil } -// "Update the DictTracker's current_ptr to point to the end of the squashed dict. -// -// __dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\ -// ids.squashed_dict_end.address_" func dictSquashUpdatePtr(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine) error { // Extract Variables dictManager, ok := FetchDictManager(scopes) @@ -191,3 +187,24 @@ func dictSquashUpdatePtr(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMac tracker.CurrentPtr = squashedDictEnd return nil } + +func dictNew(ids IdsManager, scopes *ExecutionScopes, vm *VirtualMachine) error { + // Fetch scope variables + initialDictAny, err := scopes.Get("initial_dict") + if err != nil { + return err + } + initialDict, ok := initialDictAny.(map[memory.MaybeRelocatable]memory.MaybeRelocatable) + if !ok { + return errors.New("initial_dict not in scope") + } + // Hint Logic + dictManager, ok := FetchDictManager(scopes) + if !ok { + newDictManager := NewDictManager() + dictManager = &newDictManager + scopes.AssignOrUpdateVariable("__dict_manager", dictManager) + } + dict_ptr := dictManager.NewDictionary(&initialDict, vm) + return vm.Segments.Memory.Insert(vm.RunContext.Ap, memory.NewMaybeRelocatableRelocatable(dict_ptr)) +} diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index a1b6584f..2494f447 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -524,5 +524,32 @@ func TestDictSquashUpdatePtrOk(t *testing.T) { if tracker.CurrentPtr != dict_ptr.AddUint(5) { t.Error("DICT_SQUASH_UPDATE_PTR hint test failed: Wrong updated tracker.CurrentPtr") } +} + +func TestDictSquashUpdatePtrMismatchedPtr(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + scopes := types.NewExecutionScopes() + initialDict := make(map[MaybeRelocatable]MaybeRelocatable) + // Create dictManager & add it to scope + dictManager := dict_manager.NewDictManager() + dict_ptr := dictManager.NewDictionary(&initialDict, vm) + scopes.AssignOrUpdateVariable("__dict_manager", &dictManager) + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "squashed_dict_start": {NewMaybeRelocatableRelocatable(dict_ptr.AddUint(3))}, + "squashed_dict_end": {NewMaybeRelocatableRelocatable(dict_ptr.AddUint(5))}, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_SQUASH_UPDATE_PTR, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err == nil { + t.Errorf("DICT_SQUASH_UPDATE_PTR hint test should have failed") + } } diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 45d3f476..e789601c 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -77,6 +77,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return dictSquashCopyDict(data.Ids, execScopes, vm) case DICT_SQUASH_UPDATE_PTR: return dictSquashUpdatePtr(data.Ids, execScopes, vm) + case DICT_NEW: + return dictNew(data.Ids, execScopes, vm) case VM_EXIT_SCOPE: return vm_exit_scope(execScopes) case ASSERT_NOT_EQUAL: From 03ff2e2ba4f51c50de6752d6a65d8af99e3be925 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:34:53 -0300 Subject: [PATCH 07/10] Add test --- pkg/hints/dict_hints_test.go | 72 +++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index 2494f447..0c77b1a8 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -71,7 +71,7 @@ func TestDefaultDictNewHasManager(t *testing.T) { if err != nil { t.Errorf("DEFAULT_DICT_NEW hint test failed with error %s", err) } - // Check that the manager wan't replaced by a new one + // Check that the manager wasn't replaced by a new one dictManagerPtr, ok := FetchDictManager(scopes) if !ok || dictManagerPtr != dictManagerRef { t.Error("DEFAULT_DICT_NEW DictManager replaced") @@ -553,3 +553,73 @@ func TestDictSquashUpdatePtrMismatchedPtr(t *testing.T) { t.Errorf("DICT_SQUASH_UPDATE_PTR hint test should have failed") } } + +func TestDictNewCreateManager(t *testing.T) { + vm := NewVirtualMachine() + scopes := types.NewExecutionScopes() + initialDict := make(map[MaybeRelocatable]MaybeRelocatable) + scopes.AssignOrUpdateVariable("initial_dict", initialDict) + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{}, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_NEW, + }) + // Advance AP so that values don't clash with FP-based ids + vm.RunContext.Ap = NewRelocatable(0, 5) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DICT_NEW hint test failed with error %s", err) + } + // Check that a manager was created in the scope + _, ok := FetchDictManager(scopes) + if !ok { + t.Error("DICT_NEW No DictManager created") + } + // Check that the correct base was inserted into ap + val, _ := vm.Segments.Memory.Get(vm.RunContext.Ap) + if val == nil || *val != *NewMaybeRelocatableRelocatable(NewRelocatable(1, 0)) { + t.Error("DICT_NEW Wrong/No base inserted into ap") + } +} + +func TestDictNewHasManager(t *testing.T) { + vm := NewVirtualMachine() + scopes := types.NewExecutionScopes() + // Create initialDict & dictManager & add them to scope + initialDict := make(map[MaybeRelocatable]MaybeRelocatable) + scopes.AssignOrUpdateVariable("initial_dict", initialDict) + dictManager := dict_manager.NewDictManager() + dictManagerRef := &dictManager + scopes.AssignOrUpdateVariable("__dict_manager", dictManagerRef) + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{}, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_NEW, + }) + // Advance AP so that values don't clash with FP-based ids + vm.RunContext.Ap = NewRelocatable(0, 5) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DICT_NEW hint test failed with error %s", err) + } + // Check that the manager wasn't replaced by a new one + dictManagerPtr, ok := FetchDictManager(scopes) + if !ok || dictManagerPtr != dictManagerRef { + t.Error("DICT_NEW DictManager replaced") + } + // Check that the correct base was inserted into ap + val, _ := vm.Segments.Memory.Get(vm.RunContext.Ap) + if val == nil || *val != *NewMaybeRelocatableRelocatable(NewRelocatable(1, 0)) { + t.Error("DICT_NEW Wrong/No base inserted into ap") + } +} From 6cd396278ce47d244b5fe033cf5b5580a54c38a9 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:47:52 -0300 Subject: [PATCH 08/10] Add test, fix string --- pkg/hints/dict_hint_codes.go | 4 ++-- pkg/hints/dict_hints_test.go | 25 +++++++++++++++++++++++++ pkg/vm/cairo_run/cairo_run_test.go | 8 ++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/pkg/hints/dict_hint_codes.go b/pkg/hints/dict_hint_codes.go index bf37e624..62407b89 100644 --- a/pkg/hints/dict_hint_codes.go +++ b/pkg/hints/dict_hint_codes.go @@ -26,8 +26,8 @@ const SQUASH_DICT_INNER_USED_ACCESSES_ASSERT = "assert ids.n_used_accesses == le const SQUASH_DICT_INNER_NEXT_KEY = "assert len(keys) > 0, 'No keys left but remaining_accesses > 0.'\nids.next_key = key = keys.pop()" -const DICT_SQUASH_COPY_DICT = "Prepare arguments for dict_new. In particular, the same dictionary values should be copied\n# to the new (squashed) dictionary.\nvm_enter_scope({\n # Make __dict_manager accessible.\n '__dict_manager': __dict_manager,\n # Create a copy of the dict, in case it changes in the future.\n 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),\n})" +const DICT_SQUASH_COPY_DICT = "# Prepare arguments for dict_new. In particular, the same dictionary values should be copied\n# to the new (squashed) dictionary.\nvm_enter_scope({\n # Make __dict_manager accessible.\n '__dict_manager': __dict_manager,\n # Create a copy of the dict, in case it changes in the future.\n 'initial_dict': dict(__dict_manager.get_dict(ids.dict_accesses_end)),\n})" -const DICT_SQUASH_UPDATE_PTR = "Update the DictTracker's current_ptr to point to the end of the squashed dict.\n__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\\n ids.squashed_dict_end.address_" +const DICT_SQUASH_UPDATE_PTR = "# Update the DictTracker's current_ptr to point to the end of the squashed dict.\n__dict_manager.get_tracker(ids.squashed_dict_start).current_ptr = \\\n ids.squashed_dict_end.address_" const DICT_NEW = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_dict(segments, initial_dict)\ndel initial_dict" diff --git a/pkg/hints/dict_hints_test.go b/pkg/hints/dict_hints_test.go index 0c77b1a8..8bfa94b2 100644 --- a/pkg/hints/dict_hints_test.go +++ b/pkg/hints/dict_hints_test.go @@ -623,3 +623,28 @@ func TestDictNewHasManager(t *testing.T) { t.Error("DICT_NEW Wrong/No base inserted into ap") } } + +func TestDictNewHasManagerNoInitialDict(t *testing.T) { + vm := NewVirtualMachine() + scopes := types.NewExecutionScopes() + // Create dictManager & add it to scope + dictManager := dict_manager.NewDictManager() + dictManagerRef := &dictManager + scopes.AssignOrUpdateVariable("__dict_manager", dictManagerRef) + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{}, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DICT_NEW, + }) + // Advance AP so that values don't clash with FP-based ids + vm.RunContext.Ap = NewRelocatable(0, 5) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err == nil { + t.Errorf("DICT_NEW hint test should have failed") + } +} diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index c4606410..c255c761 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -194,3 +194,11 @@ func TestSquashDict(t *testing.T) { t.Errorf("Program execution failed with error: %s", err) } } + +func TestDictSquash(t *testing.T) { + cairoRunConfig := cairo_run.CairoRunConfig{DisableTracePadding: false, Layout: "small", ProofMode: false} + _, err := cairo_run.CairoRun("../../../cairo_programs/dict_squash.json", cairoRunConfig) + if err != nil { + t.Errorf("Program execution failed with error: %s", err) + } +} From 358753e0a4dabe77ed37d7f04595541520c078aa Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:48:05 -0300 Subject: [PATCH 09/10] Add test file --- cairo_programs/dict_squash.cairo | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 cairo_programs/dict_squash.cairo diff --git a/cairo_programs/dict_squash.cairo b/cairo_programs/dict_squash.cairo new file mode 100644 index 00000000..bc706a85 --- /dev/null +++ b/cairo_programs/dict_squash.cairo @@ -0,0 +1,29 @@ +%builtins range_check + +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.dict import dict_write, dict_update, dict_squash +from starkware.cairo.common.default_dict import default_dict_new + +func main{range_check_ptr}() -> () { + let (dict_start) = default_dict_new(17); + let dict_end = dict_start; + dict_write{dict_ptr=dict_end}(0, 1); + dict_write{dict_ptr=dict_end}(1, 10); + dict_write{dict_ptr=dict_end}(2, -2); + dict_update{dict_ptr=dict_end}(0, 1, 2); + dict_update{dict_ptr=dict_end}(0, 2, 3); + dict_update{dict_ptr=dict_end}(0, 3, 4); + dict_update{dict_ptr=dict_end}(1, 10, 15); + dict_update{dict_ptr=dict_end}(1, 15, 20); + dict_update{dict_ptr=dict_end}(1, 20, 25); + dict_update{dict_ptr=dict_end}(2, -2, -4); + dict_update{dict_ptr=dict_end}(2, -4, -8); + dict_update{dict_ptr=dict_end}(2, -8, -16); + let (squashed_dict_start, squashed_dict_end) = dict_squash{range_check_ptr=range_check_ptr}( + dict_start, dict_end + ); + assert squashed_dict_end[0] = DictAccess(key=0, prev_value=1, new_value=4); + assert squashed_dict_end[1] = DictAccess(key=1, prev_value=10, new_value=25); + assert squashed_dict_end[2] = DictAccess(key=2, prev_value=-2, new_value=-16); + return (); +} \ No newline at end of file From 159e6533938f29a705399a38b3032aa3781b434f Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 18 Sep 2023 12:51:53 -0300 Subject: [PATCH 10/10] Add newline at eof --- cairo_programs/dict_squash.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cairo_programs/dict_squash.cairo b/cairo_programs/dict_squash.cairo index bc706a85..05816c63 100644 --- a/cairo_programs/dict_squash.cairo +++ b/cairo_programs/dict_squash.cairo @@ -26,4 +26,4 @@ func main{range_check_ptr}() -> () { assert squashed_dict_end[1] = DictAccess(key=1, prev_value=10, new_value=25); assert squashed_dict_end[2] = DictAccess(key=2, prev_value=-2, new_value=-16); return (); -} \ No newline at end of file +}