diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index f31400f9..cf8181a6 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -29,7 +29,7 @@ func (p *CairoVmHintProcessor) CompileHint(hintParams *parser.HintParams, refere name = split[len(split)-1] references[name] = ParseHintReference(referenceManager.References[n]) } - ids := NewIdsManager(references, hintParams.FlowTrackingData.APTracking) + ids := NewIdsManager(references, hintParams.FlowTrackingData.APTracking, hintParams.AccessibleScopes) return HintData{Ids: ids, Code: hintParams.Code}, nil } diff --git a/pkg/hints/hint_utils/ids_manager.go b/pkg/hints/hint_utils/ids_manager.go index 06ed7d33..f883ac5c 100644 --- a/pkg/hints/hint_utils/ids_manager.go +++ b/pkg/hints/hint_utils/ids_manager.go @@ -12,8 +12,9 @@ import ( // Identifier Manager // Provides methods that allow hints to interact with cairo variables given their identifier name type IdsManager struct { - References map[string]HintReference - HintApTracking parser.ApTrackingData + References map[string]HintReference + HintApTracking parser.ApTrackingData + AccessibleScopes []string } func ErrIdsManager(err error) error { @@ -24,13 +25,30 @@ func ErrUnknownIdentifier(name string) error { return ErrIdsManager(errors.Errorf("Unknow identifier %s", name)) } -func NewIdsManager(references map[string]HintReference, hintApTracking parser.ApTrackingData) IdsManager { +func NewIdsManager(references map[string]HintReference, hintApTracking parser.ApTrackingData, accessibleScopes []string) IdsManager { return IdsManager{ - References: references, - HintApTracking: hintApTracking, + References: references, + HintApTracking: hintApTracking, + AccessibleScopes: accessibleScopes, } } +// Fetches a constant used by the hint +// Searches inner modules first for name-matching constants +func (ids *IdsManager) GetConst(name string, constants *map[string]lambdaworks.Felt) (lambdaworks.Felt, error) { + // Hints should always have accessible scopes + if len(ids.AccessibleScopes) != 0 { + // Accessible scopes are listed from outer to inner + for i := len(ids.AccessibleScopes) - 1; i >= 0; i-- { + constant, ok := (*constants)[ids.AccessibleScopes[i]+"."+name] + if ok { + return constant, nil + } + } + } + return lambdaworks.FeltZero(), errors.Errorf("Missing constant %s", name) +} + // Inserts value into memory given its identifier name func (ids *IdsManager) Insert(name string, value *MaybeRelocatable, vm *VirtualMachine) error { diff --git a/pkg/hints/hint_utils/ids_manager_test.go b/pkg/hints/hint_utils/ids_manager_test.go index 6fd3f234..5dc69b12 100644 --- a/pkg/hints/hint_utils/ids_manager_test.go +++ b/pkg/hints/hint_utils/ids_manager_test.go @@ -285,3 +285,55 @@ func TestIdsManagerGetStructFieldTest(t *testing.T) { t.Errorf("IdsManager.GetStructFieldFelt returned wrong values") } } + +func TestIdsManagerGetConst(t *testing.T) { + ids := IdsManager{ + AccessibleScopes: []string{ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_250_bit", + }, + } + upperBound := lambdaworks.FeltFromUint64(250) + constants := map[string]lambdaworks.Felt{ + "starkware.cairo.common.math.assert_250_bit.UPPER_BOUND": upperBound, + } + constant, err := ids.GetConst("UPPER_BOUND", &constants) + if err != nil || constant != upperBound { + t.Errorf("IdsManager.GetConst returned wrong/no constant") + } +} + +func TestIdsManagerGetConstPrioritizeInnerModule(t *testing.T) { + ids := IdsManager{ + AccessibleScopes: []string{ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_250_bit", + }, + } + upperBound := lambdaworks.FeltFromUint64(250) + constants := map[string]lambdaworks.Felt{ + "starkware.cairo.common.math.assert_250_bit.UPPER_BOUND": upperBound, + "starkware.cairo.common.math.UPPER_BOUND": lambdaworks.FeltZero(), + } + constant, err := ids.GetConst("UPPER_BOUND", &constants) + if err != nil || constant != upperBound { + t.Errorf("IdsManager.GetConst returned wrong/no constant") + } +} + +func TestIdsManagerGetConstNoMConst(t *testing.T) { + ids := IdsManager{ + AccessibleScopes: []string{ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_250_bit", + }, + } + lowerBound := lambdaworks.FeltFromUint64(250) + constants := map[string]lambdaworks.Felt{ + "starkware.cairo.common.math.assert_250_bit.LOWER_BOUND": lowerBound, + } + _, err := ids.GetConst("UPPER_BOUND", &constants) + if err == nil { + t.Errorf("IdsManager.GetConst should have failed") + } +} diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index ab2470cd..8c7f1f5c 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -1,6 +1,7 @@ package hint_utils import ( + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" "github.com/lambdaclass/cairo-vm.go/pkg/parser" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" @@ -17,7 +18,7 @@ import ( // All references will be FP-based, so please don't update the value of FP after calling this function, // and make sure that the memory at fp's segment is clear from its current offset onwards func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachine) IdsManager { - manager := NewIdsManager(make(map[string]HintReference), parser.ApTrackingData{}) + manager := NewIdsManager(make(map[string]HintReference), parser.ApTrackingData{}, []string{}) base_addr := vm.RunContext.Fp current_offset := 0 for name, elems := range ids { @@ -43,3 +44,14 @@ func SetupIdsForTest(ids map[string][]*memory.MaybeRelocatable, vm *VirtualMachi } return manager } + +// Returns a constants map accoring to the new_constants map received +// Adds a path to each constant and a matching path to the hint's accessible scopes +func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids *IdsManager) map[string]lambdaworks.Felt { + constants := make(map[string]lambdaworks.Felt) + ids.AccessibleScopes = append(ids.AccessibleScopes, "path") + for name, constant := range new_constants { + constants["path."+name] = constant + } + return constants +} diff --git a/pkg/hints/hint_utils/testing_utils_test.go b/pkg/hints/hint_utils/testing_utils_test.go index a9c19945..4875a1a1 100644 --- a/pkg/hints/hint_utils/testing_utils_test.go +++ b/pkg/hints/hint_utils/testing_utils_test.go @@ -108,3 +108,24 @@ func TestSetupIdsForTestStructWithGap(t *testing.T) { t.Error("Failed to insert ids") } } + +func TestSetupConstantsForTest(t *testing.T) { + constA := FeltOne() + constB := FeltZero() + IdsManager := IdsManager{} + constants := SetupConstantsForTest(map[string]Felt{ + "A": constA, + "B": constB, + }, + &IdsManager, + ) + // Check that we can fetch the constants + a, err := IdsManager.GetConst("A", &constants) + if err != nil || a != constA { + t.Error("SetupConstantsForTest wrong/no A") + } + b, err := IdsManager.GetConst("B", &constants) + if err != nil || b != constB { + t.Error("SetupConstantsForTest wrong/no B") + } +}