From 88587aebbc8f77ef36db705a618e8dd11d8881a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carmen=20Irene=20Cabrera=20Rodr=C3=ADguez?= <49727740+cicr99@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:11:37 +0100 Subject: [PATCH] Allow multiple hints for the same pc (#193) * add multiple hints for the same pc * modify RunHint and hinter maps * fix linting errors --- pkg/hintrunner/hintrunner.go | 17 ++++++++++------- pkg/hintrunner/hintrunner_test.go | 8 ++++---- pkg/hintrunner/zero/zerohint.go | 20 ++++++++------------ pkg/runners/zero/zero.go | 2 +- pkg/runners/zero/zero_test.go | 8 ++++---- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/pkg/hintrunner/hintrunner.go b/pkg/hintrunner/hintrunner.go index 6023332d4..42b770d96 100644 --- a/pkg/hintrunner/hintrunner.go +++ b/pkg/hintrunner/hintrunner.go @@ -12,10 +12,10 @@ type HintRunner struct { // Execution context required by certain hints such as dictionaires context h.HintRunnerContext // A mapping from program counter to hint implementation - hints map[uint64]h.Hinter + hints map[uint64][]h.Hinter } -func NewHintRunner(hints map[uint64]h.Hinter) HintRunner { +func NewHintRunner(hints map[uint64][]h.Hinter) HintRunner { return HintRunner{ // Context for certain hints that require it. Each manager is // initialized only when required by the hint @@ -30,14 +30,17 @@ func NewHintRunner(hints map[uint64]h.Hinter) HintRunner { } func (hr *HintRunner) RunHint(vm *VM.VirtualMachine) error { - hint := hr.hints[vm.Context.Pc.Offset] - if hint == nil { + hints := hr.hints[vm.Context.Pc.Offset] + if len(hints) == 0 { return nil } - err := hint.Execute(vm, &hr.context) - if err != nil { - return fmt.Errorf("execute hint %s: %v", hint, err) + for _, hint := range hints { + err := hint.Execute(vm, &hr.context) + if err != nil { + return fmt.Errorf("execute hint %s: %v", hint, err) + } } + return nil } diff --git a/pkg/hintrunner/hintrunner_test.go b/pkg/hintrunner/hintrunner_test.go index 8cb0b8422..0e057de98 100644 --- a/pkg/hintrunner/hintrunner_test.go +++ b/pkg/hintrunner/hintrunner_test.go @@ -18,8 +18,8 @@ func TestExistingHint(t *testing.T) { var ap hinter.ApCellRef = 5 allocHint := core.AllocSegment{Dst: ap} - hr := NewHintRunner(map[uint64]hinter.Hinter{ - 10: &allocHint, + hr := NewHintRunner(map[uint64][]hinter.Hinter{ + 10: {&allocHint}, }) vm.Context.Pc = memory.MemoryAddress{ @@ -42,8 +42,8 @@ func TestNoHint(t *testing.T) { var ap hinter.ApCellRef = 5 allocHint := core.AllocSegment{Dst: ap} - hr := NewHintRunner(map[uint64]hinter.Hinter{ - 10: &allocHint, + hr := NewHintRunner(map[uint64][]hinter.Hinter{ + 10: {&allocHint}, }) vm.Context.Pc = memory.MemoryAddress{ diff --git a/pkg/hintrunner/zero/zerohint.go b/pkg/hintrunner/zero/zerohint.go index eb1ec2a3e..f137f1e1e 100644 --- a/pkg/hintrunner/zero/zerohint.go +++ b/pkg/hintrunner/zero/zerohint.go @@ -10,26 +10,22 @@ import ( zero "github.com/NethermindEth/cairo-vm-go/pkg/parsers/zero" ) -func GetZeroHints(cairoZeroJson *zero.ZeroProgram) (map[uint64]hinter.Hinter, error) { - hints := make(map[uint64]hinter.Hinter) +func GetZeroHints(cairoZeroJson *zero.ZeroProgram) (map[uint64][]hinter.Hinter, error) { + hints := make(map[uint64][]hinter.Hinter) for counter, rawHints := range cairoZeroJson.Hints { pc, err := strconv.ParseUint(counter, 10, 64) if err != nil { return nil, err } - // TODO: Check if it is possible to have more than one hint - if len(rawHints) != 1 { - return nil, fmt.Errorf("expected only 1 hint but got %d", len(rawHints)) - } - rawHint := rawHints[0] + for _, rawHint := range rawHints { + hint, err := GetHintFromCode(cairoZeroJson, rawHint, pc) + if err != nil { + return nil, err + } - hint, err := GetHintFromCode(cairoZeroJson, rawHint, pc) - if err != nil { - return nil, err + hints[pc] = append(hints[pc], hint) } - - hints[pc] = hint } return hints, nil diff --git a/pkg/runners/zero/zero.go b/pkg/runners/zero/zero.go index 05791f457..8c3948741 100644 --- a/pkg/runners/zero/zero.go +++ b/pkg/runners/zero/zero.go @@ -27,7 +27,7 @@ type ZeroRunner struct { } // Creates a new Runner of a Cairo Zero program -func NewRunner(program *Program, hints map[uint64]hinter.Hinter, proofmode bool, maxsteps uint64) (ZeroRunner, error) { +func NewRunner(program *Program, hints map[uint64][]hinter.Hinter, proofmode bool, maxsteps uint64) (ZeroRunner, error) { hintrunner := hintrunner.NewHintRunner(hints) return ZeroRunner{ diff --git a/pkg/runners/zero/zero_test.go b/pkg/runners/zero/zero_test.go index 0ccf38180..be238bced 100644 --- a/pkg/runners/zero/zero_test.go +++ b/pkg/runners/zero/zero_test.go @@ -26,7 +26,7 @@ func TestSimpleProgram(t *testing.T) { ret; `) - hints := make(map[uint64]hinter.Hinter) + hints := make(map[uint64][]hinter.Hinter) runner, err := NewRunner(program, hints, false, math.MaxUint64) require.NoError(t, err) @@ -73,7 +73,7 @@ func TestStepLimitExceeded(t *testing.T) { ret; `) - hints := make(map[uint64]hinter.Hinter) + hints := make(map[uint64][]hinter.Hinter) runner, err := NewRunner(program, hints, false, 3) require.NoError(t, err) @@ -132,7 +132,7 @@ func TestStepLimitExceededProofMode(t *testing.T) { t.Logf("Using maxstep: %d\n", maxstep) // when maxstep = 6, it fails executing the extra step required by proof mode // when maxstep = 7, it fails trying to get the trace to be a power of 2 - hints := make(map[uint64]hinter.Hinter) + hints := make(map[uint64][]hinter.Hinter) runner, err := NewRunner(program, hints, true, uint64(maxstep)) require.NoError(t, err) @@ -367,7 +367,7 @@ func TestEcOpBuiltin(t *testing.T) { func createRunner(code string, builtins ...sn.Builtin) ZeroRunner { program := createProgramWithBuiltins(code, builtins...) - hints := make(map[uint64]hinter.Hinter) + hints := make(map[uint64][]hinter.Hinter) runner, err := NewRunner(program, hints, false, math.MaxUint64) if err != nil { panic(err)