Skip to content

Commit

Permalink
Simplify error handling in hintrunner
Browse files Browse the repository at this point in the history
  • Loading branch information
joshklop committed Sep 5, 2023
1 parent 411782a commit 6c70b55
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 109 deletions.
56 changes: 0 additions & 56 deletions pkg/hintrunner/error.go

This file was deleted.

38 changes: 23 additions & 15 deletions pkg/hintrunner/hint.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,73 @@
package hintrunner

import (
"fmt"

VM "github.com/NethermindEth/cairo-vm-go/pkg/vm"
"github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)

type Hinter interface {
Execute(vm *VM.VirtualMachine) *HintError
}
fmt.Stringer

const allocSegmentName = "AllocSegment"
Execute(vm *VM.VirtualMachine) error
}

type AllocSegment struct {
dst CellRefer
}

func (hint AllocSegment) Execute(vm *VM.VirtualMachine) *HintError {
func (hint AllocSegment) String() string {
return "AllocSegment"
}

func (hint AllocSegment) Execute(vm *VM.VirtualMachine) error {
segmentIndex := vm.MemoryManager.Memory.AllocateEmptySegment()
memAddress := memory.MemoryValueFromSegmentAndOffset(segmentIndex, 0)

cell, err := hint.dst.Get(vm)
if err != nil {
return NewHintError(allocSegmentName, err)
return fmt.Errorf("get destination cell: %v", err)
}

err = cell.Write(memAddress)
if err != nil {
return NewHintError(allocSegmentName, err)
return fmt.Errorf("write cell: %v", err)
}

return nil
}

const testLessThanName = "TestLessThan"

type TestLessThan struct {
dst CellRefer
lhs ResOperander
rhs ResOperander
}

func (hint TestLessThan) Execute(vm *VM.VirtualMachine) *HintError {
func (hint TestLessThan) String() string {
return "TestLessThan"
}

func (hint TestLessThan) Execute(vm *VM.VirtualMachine) error {
lhsVal, err := hint.lhs.Resolve(vm)
if err != nil {
return NewHintError(testLessThanName, err)
return fmt.Errorf("resolve lhs: %v", err)
}

rhsVal, err := hint.rhs.Resolve(vm)
if err != nil {
return NewHintError(testLessThanName, err)
return fmt.Errorf("resolve rhs: %v", err)
}

lhsFelt, err := lhsVal.ToFieldElement()
if err != nil {
return NewHintError(testLessThanName, err)
return err
}

rhsFelt, err := rhsVal.ToFieldElement()
if err != nil {
return NewHintError(testLessThanName, err)
return err
}

resFelt := f.Element{}
Expand All @@ -69,12 +77,12 @@ func (hint TestLessThan) Execute(vm *VM.VirtualMachine) *HintError {

dstCell, err := hint.dst.Get(vm)
if err != nil {
return NewHintError(testLessThanName, err)
return fmt.Errorf("get destination cell: %v", err)
}

err = dstCell.Write(memory.MemoryValueFromFieldElement(&resFelt))
if err != nil {
return NewHintError(testLessThanName, err)
return fmt.Errorf("write cell: %v", err)
}

return nil
Expand Down
6 changes: 4 additions & 2 deletions pkg/hintrunner/hintrunner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package hintrunner

import (
"fmt"

VM "github.com/NethermindEth/cairo-vm-go/pkg/vm"
)

Expand All @@ -14,15 +16,15 @@ func CreateHintRunner(hints map[uint64]Hinter) HintRunner {
return HintRunner{hints}
}

func (hr HintRunner) RunHint(vm *VM.VirtualMachine) *HintRunnerError {
func (hr HintRunner) RunHint(vm *VM.VirtualMachine) error {
hint := hr.hints[vm.Context.Pc]
if hint == nil {
return nil
}

err := hint.Execute(vm)
if err != nil {
return NewHintRunnerError(err)
return fmt.Errorf("execute hint %s: %v", hint, err)
}
return nil
}
79 changes: 43 additions & 36 deletions pkg/hintrunner/operand.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,68 @@ import (
f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)

const (
apCellRefName = "ApCellRef"
fpCellRefName = "FpCellRef"
derefName = "Deref"
doubleDerefName = "DoubleDeref"
immediateName = "Immediate"
binOpName = "BinaryOperator"
)

//
// All CellRef definitions

type CellRefer interface {
fmt.Stringer

Get(vm *VM.VirtualMachine) (*memory.Cell, error)
}

func cellRefErr(c CellRefer, err error) error {

Check failure on line 22 in pkg/hintrunner/operand.go

View workflow job for this annotation

GitHub Actions / lint

func `cellRefErr` is unused (unused)
return fmt.Errorf("%s: %v", c, err)
}

type ApCellRef int16

func (ap ApCellRef) String() string {
return "ApCellRef"
}

func (ap ApCellRef) Get(vm *VM.VirtualMachine) (*memory.Cell, error) {
res, overflow := safemath.SafeOffset(vm.Context.Ap, int16(ap))
if overflow {
return nil, NewOperandError(
apCellRefName,
fmt.Errorf("%d + %d is outside of the [0, 2**64) range", vm.Context.Ap, ap),
)
return nil, safemath.NewSafeOffsetError(vm.Context.Ap, int16(ap))
}
return vm.MemoryManager.Memory.Peek(VM.ExecutionSegment, res)
}

type FpCellRef int16

func (fp FpCellRef) String() string {
return "FpCellRef"
}

func (fp FpCellRef) Get(vm *VM.VirtualMachine) (*memory.Cell, error) {
res, overflow := safemath.SafeOffset(vm.Context.Fp, int16(fp))
if overflow {
return nil, NewOperandError(
fpCellRefName,
fmt.Errorf("%d + %d is outside of the [0, 2**64) range", vm.Context.Ap, fp),
)
return nil, safemath.NewSafeOffsetError(vm.Context.Ap, int16(fp))
}
return vm.MemoryManager.Memory.Peek(VM.ExecutionSegment, res)
}

//
// All ResOperand definitions

type ResOperander interface {
fmt.Stringer

Resolve(vm *VM.VirtualMachine) (*memory.MemoryValue, error)
}

type Deref struct {
deref CellRefer
}

func (deref Deref) String() string {
return "Deref"
}

func (deref Deref) Resolve(vm *VM.VirtualMachine) (*memory.MemoryValue, error) {
cell, err := deref.deref.Get(vm)
if err != nil {
return nil, NewOperandError(derefName, err)
return nil, fmt.Errorf("get cell: %v", err)
}
return cell.Read(), nil
}
Expand All @@ -75,35 +84,36 @@ type DoubleDeref struct {
func (dderef DoubleDeref) Resolve(vm *VM.VirtualMachine) (*memory.MemoryValue, error) {
cell, err := dderef.deref.Get(vm)
if err != nil {
return nil, NewOperandError(doubleDerefName, err)
return nil, fmt.Errorf("get cell: %v", err)
}
lhs := cell.Read()

// Double deref implies the first value read must be an address
address, err := lhs.ToMemoryAddress()
if err != nil {
return nil, NewOperandError(doubleDerefName, err)
return nil, err
}

newOffset, overflow := safemath.SafeOffset(address.Offset, dderef.offset)
if overflow {
return nil, NewOperandError(
doubleDerefName,
safemath.NewSafeOffsetError(address.Offset, dderef.offset),
)
return nil, safemath.NewSafeOffsetError(address.Offset, dderef.offset)
}
resAddr := memory.NewMemoryAddress(address.SegmentIndex, newOffset)

value, err := vm.MemoryManager.Memory.ReadFromAddress(resAddr)
if err != nil {
return nil, NewOperandError(doubleDerefName, err)
return nil, fmt.Errorf("read cell: %v", err)
}

return value, nil
}

type Immediate big.Int

func (imm Immediate) String() string {
return "Immediate"
}

// todo(rodro): Specs from Starkware stablish this can be uint256 and not a felt.
// Should we respect that, or go straight to felt?
func (imm Immediate) Resolve(vm *VM.VirtualMachine) (*memory.MemoryValue, error) {
Expand All @@ -123,37 +133,34 @@ const (
Mul
)

type ResOperander interface {
Resolve(vm *VM.VirtualMachine) (*memory.MemoryValue, error)
}

type BinaryOp struct {
operator Operator
lhs CellRefer
rhs ResOperander // (except DoubleDeref and BinaryOp)
}

func (bop BinaryOp) String() string {
return "BinaryOperator"
}

func (bop BinaryOp) Resolve(vm *VM.VirtualMachine) (*memory.MemoryValue, error) {
cell, err := bop.lhs.Get(vm)
if err != nil {
return nil, err
return nil, fmt.Errorf("get lhs op %d: %v", bop.lhs, err)
}
lhs := cell.Read()

rhs, err := bop.rhs.Resolve(vm)
if err != nil {
return nil, err
return nil, fmt.Errorf("resolve rhs op %s: %v", rhs, err)
}

switch bop.operator {
case Add:
return memory.EmptyMemoryValueAs(lhs.IsAddress()).Add(lhs, rhs)
case Mul:
return memory.EmptyMemoryValueAsFelt().Mul(lhs, rhs)
default:
return nil, fmt.Errorf("unknown binary operator: %d", bop.operator)
}

return nil, NewOperandError(
"BinaryOp",
fmt.Errorf("unknown binary operator id: %d", bop.operator),
)
}

0 comments on commit 6c70b55

Please sign in to comment.