Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add available gas and user args #677

Merged
merged 21 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b6f59e0
Add parsing logic for input user args
MaksymMalicki Dec 13, 2024
3cce170
Add flags for available gas, input user args, writing args to memory
MaksymMalicki Dec 13, 2024
9e2d84b
Fix unit tests for user arguments parsing
MaksymMalicki Dec 13, 2024
316a872
Lint the PR
MaksymMalicki Dec 13, 2024
7753686
Add user args to hint context
MaksymMalicki Dec 16, 2024
9c4fb34
Refactor the code
MaksymMalicki Dec 16, 2024
5869a28
Fix unconditional append of ExternalWriteArgsToMemory, bug fixes in i…
MaksymMalicki Dec 16, 2024
2948824
Add fixes of the call size calculation and include ExternalWriteArgsT…
MaksymMalicki Dec 17, 2024
1adfe24
Add layouts for integration tests
MaksymMalicki Dec 17, 2024
73480e3
Add error handling
MaksymMalicki Dec 17, 2024
747e93d
Fixes in entry code generation
MaksymMalicki Dec 17, 2024
3d3a537
Address changes mentioned in a discussion
MaksymMalicki Dec 20, 2024
5ff5874
Add comment regarding writing to memory in a hint for the future refe…
MaksymMalicki Dec 20, 2024
77d8516
Changes in calculations of the initial PC offset, CALL opcode offset …
MaksymMalicki Dec 25, 2024
e8b9615
Turn back VM config to private field
MaksymMalicki Dec 25, 2024
dc209dc
Add error handling on assign of `userArgs` to the initial scope
MaksymMalicki Dec 25, 2024
d8b6e64
Lint project
MaksymMalicki Dec 25, 2024
4941781
Bump go version from 1.20 -> 1.21 (#678)
MaksymMalicki Dec 25, 2024
03f3f22
Simplify the Makefile
MaksymMalicki Dec 25, 2024
236f757
Merge branch 'add_available_gas_and_user_args' of https://github.com/…
MaksymMalicki Dec 25, 2024
f6e723e
Correction in the makefile
MaksymMalicki Dec 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet"
zero "github.com/NethermindEth/cairo-vm-go/pkg/parsers/zero"
"github.com/NethermindEth/cairo-vm-go/pkg/runner"
"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
"github.com/urfave/cli/v2"
)

Expand All @@ -26,6 +27,8 @@ func main() {
var layoutName string
var airPublicInputLocation string
var airPrivateInputLocation string
var args string
var availableGas uint64
app := &cli.App{
Name: "cairo-vm",
Usage: "A cairo virtual machine",
Expand Down Expand Up @@ -122,7 +125,7 @@ func main() {
if proofmode {
runnerMode = runner.ProofModeCairo0
}
return runVM(*program, proofmode, maxsteps, entrypointOffset, collectTrace, traceLocation, buildMemory, memoryLocation, layoutName, airPublicInputLocation, airPrivateInputLocation, hints, runnerMode)
return runVM(*program, proofmode, maxsteps, entrypointOffset, collectTrace, traceLocation, buildMemory, memoryLocation, layoutName, airPublicInputLocation, airPrivateInputLocation, hints, runnerMode, nil)
},
},
{
Expand Down Expand Up @@ -191,6 +194,18 @@ func main() {
Required: false,
Destination: &airPrivateInputLocation,
},
&cli.StringFlag{
Name: "args",
Usage: "input arguments for the `main` function in the cairo progran",
Required: false,
Destination: &args,
},
&cli.Uint64Flag{
Name: "available_gas",
Usage: "available gas for the VM execution",
Required: false,
Destination: &availableGas,
},
},
Action: func(ctx *cli.Context) error {
pathToFile := ctx.Args().Get(0)
Expand All @@ -210,7 +225,19 @@ func main() {
if proofmode {
runnerMode = runner.ProofModeCairo1
}
return runVM(program, proofmode, maxsteps, entrypointOffset, collectTrace, traceLocation, buildMemory, memoryLocation, layoutName, airPublicInputLocation, airPrivateInputLocation, hints, runnerMode)
userArgs, err := starknet.ParseCairoProgramArgs(args)
if err != nil {
return fmt.Errorf("cannot parse args: %w", err)
}
if availableGas > 0 {
// The first argument is the available gas
availableGasArg := starknet.CairoFuncArgs{
Single: new(fp.Element).SetUint64(availableGas),
Array: nil,
}
userArgs = append([]starknet.CairoFuncArgs{availableGasArg}, userArgs...)
}
return runVM(program, proofmode, maxsteps, entrypointOffset, collectTrace, traceLocation, buildMemory, memoryLocation, layoutName, airPublicInputLocation, airPrivateInputLocation, hints, runnerMode, userArgs)
},
},
},
Expand All @@ -236,9 +263,10 @@ func runVM(
airPrivateInputLocation string,
hints map[uint64][]hinter.Hinter,
runnerMode runner.RunnerMode,
userArgs []starknet.CairoFuncArgs,
) error {
fmt.Println("Running....")
runner, err := runner.NewRunner(&program, hints, runnerMode, collectTrace, maxsteps, layoutName)
runner, err := runner.NewRunner(&program, hints, runnerMode, collectTrace, maxsteps, layoutName, userArgs)
if err != nil {
return fmt.Errorf("cannot create runner: %w", err)
}
Expand Down
8 changes: 5 additions & 3 deletions integration_tests/cairo_vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,16 +459,18 @@ func runVm(path, layout string, zero bool) (time.Duration, string, string, strin
}
args := []string{
cliCommand,
"--proofmode",
// "--proofmode",
"--tracefile",
traceOutput,
"--memoryfile",
memoryOutput,
"--layout",
layout,
path,
}

if !zero {
args = append(args, "--available_gas", "9999999")
}
args = append(args, path)
cmd := exec.Command(
"../bin/cairo-vm",
args...,
Expand Down
35 changes: 35 additions & 0 deletions pkg/hintrunner/core/hint.go
Original file line number Diff line number Diff line change
Expand Up @@ -1929,3 +1929,38 @@ func (hint *FieldSqrt) Execute(vm *VM.VirtualMachine, _ *hinter.HintRunnerContex

return vm.Memory.WriteToAddress(&sqrtAddr, &sqrtVal)
}

type ExternalWriteArgsToMemory struct{}

func (hint *ExternalWriteArgsToMemory) String() string {
return "ExternalWriteToMemory"
}

func (hint *ExternalWriteArgsToMemory) Execute(vm *VM.VirtualMachine, ctx *hinter.HintRunnerContext) error {
userArgsVar, err := ctx.ScopeManager.GetVariableValue("userArgs")
if err != nil {
return fmt.Errorf("get user args: %v", err)
}
userArgs, ok := userArgsVar.([]starknet.CairoFuncArgs)
if !ok {
return fmt.Errorf("expected user args to be a list of CairoFuncArgs")
}
for _, arg := range userArgs {
if arg.Single != nil {
mv := mem.MemoryValueFromFieldElement(arg.Single)
err := vm.Memory.Write(1, vm.Context.Ap-uint64(len(userArgs)), &mv)
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("write single arg: %v", err)
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
}
} else if arg.Array != nil {
arrayBase := vm.Memory.AllocateEmptySegment()
mv := mem.MemoryValueFromMemoryAddress(&arrayBase)
err := vm.Memory.Write(1, vm.Context.Ap, &mv)
if err != nil {
return fmt.Errorf("write array base: %v", err)
}
// TODO: Implement array writing
}
}
return nil
}
13 changes: 11 additions & 2 deletions pkg/hintrunner/hintrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

h "github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
"github.com/NethermindEth/cairo-vm-go/pkg/parsers/starknet"
VM "github.com/NethermindEth/cairo-vm-go/pkg/vm"
)

Expand All @@ -14,11 +15,19 @@ type HintRunner struct {
hints map[uint64][]h.Hinter
}

func NewHintRunner(hints map[uint64][]h.Hinter) HintRunner {
func NewHintRunner(hints map[uint64][]h.Hinter, userArgs []starknet.CairoFuncArgs) HintRunner {
context := *h.InitializeDefaultContext()
if userArgs != nil {
context = *h.SetContextWithScope(
map[string]any{
"userArgs": userArgs,
},
)
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
}
return HintRunner{
// Context for certain hints that require it. Each manager is
// initialized only when required by the hint
context: *h.InitializeDefaultContext(),
context: context,
hints: hints,
}
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/hintrunner/hintrunner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestExistingHint(t *testing.T) {

hr := NewHintRunner(map[uint64][]hinter.Hinter{
10: {&allocHint},
})
}, nil)

vm.Context.Pc = memory.MemoryAddress{
SegmentIndex: 0,
Expand All @@ -44,7 +44,7 @@ func TestNoHint(t *testing.T) {

hr := NewHintRunner(map[uint64][]hinter.Hinter{
10: {&allocHint},
})
}, nil)

vm.Context.Pc = memory.MemoryAddress{
SegmentIndex: 0,
Expand Down
40 changes: 40 additions & 0 deletions pkg/parsers/starknet/starknet.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"fmt"
"os"
"regexp"
"strings"

"github.com/NethermindEth/cairo-vm-go/pkg/vm/builtins"
"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
Expand Down Expand Up @@ -95,3 +97,41 @@ func StarknetProgramFromJSON(content json.RawMessage) (*StarknetProgram, error)
var starknet StarknetProgram
return &starknet, json.Unmarshal(content, &starknet)
}

type CairoFuncArgs struct {
Single *fp.Element
Array []fp.Element
}

func ParseCairoProgramArgs(input string) ([]CairoFuncArgs, error) {
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
re := regexp.MustCompile(`\[[^\]]*\]|\S+`)
tokens := re.FindAllString(input, -1)
var result []CairoFuncArgs
for _, token := range tokens {
if single, err := new(fp.Element).SetString(token); err == nil {
result = append(result, CairoFuncArgs{
Single: single,
Array: nil,
})
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
} else if strings.HasPrefix(token, "[") && strings.HasSuffix(token, "]") {
arrayStr := strings.Trim(token, "[]")
arrayParts := strings.Fields(arrayStr)
var array []fp.Element
for _, part := range arrayParts {
single, err := new(fp.Element).SetString(part)
if err != nil {
return nil, fmt.Errorf("invalid felt value in array: %v", err)
}
array = append(array, *single)
}
result = append(result, CairoFuncArgs{
Single: nil,
Array: array,
})
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
} else {
return nil, fmt.Errorf("invalid token: %s", token)
}
}

return result, nil
}
93 changes: 93 additions & 0 deletions pkg/parsers/starknet/starknet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package starknet
import (
"testing"

"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
"github.com/go-playground/validator/v10"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -170,3 +171,95 @@ func TestInvalidBuiltin(t *testing.T) {
_, err := StarknetProgramFromJSON(testData)
assert.Error(t, err)
}

func TestParseStarknetProgramArgs(t *testing.T) {
cicr99 marked this conversation as resolved.
Show resolved Hide resolved
testCases := []struct {
name string
args string
expected []CairoFuncArgs
}{
{
name: "single arg",
args: "1",
expected: []CairoFuncArgs{
{
Single: new(fp.Element).SetUint64(1),
Array: nil,
},
},
},
{
name: "single array arg",
args: "[1 2 3 4]",
expected: []CairoFuncArgs{
{
Single: nil,
Array: []fp.Element{
*new(fp.Element).SetUint64(1),
*new(fp.Element).SetUint64(2),
*new(fp.Element).SetUint64(3),
*new(fp.Element).SetUint64(4),
},
},
},
},
{
name: "mixed args",
args: "1 [2 3 4] 5 [6 7 8] [1] 9 9 [12341341234 0]",
expected: []CairoFuncArgs{
{
Single: new(fp.Element).SetUint64(1),
Array: nil,
},
{
Single: nil,
Array: []fp.Element{
*new(fp.Element).SetUint64(2),
*new(fp.Element).SetUint64(3),
*new(fp.Element).SetUint64(4),
},
},
{
Single: new(fp.Element).SetUint64(5),
Array: nil,
},
{
Single: nil,
Array: []fp.Element{
*new(fp.Element).SetUint64(6),
*new(fp.Element).SetUint64(7),
*new(fp.Element).SetUint64(8),
},
},
{
Single: nil,
Array: []fp.Element{
*new(fp.Element).SetUint64(1),
},
},
{
Single: new(fp.Element).SetUint64(9),
Array: nil,
},
{
Single: new(fp.Element).SetUint64(9),
Array: nil,
},
{
Single: nil,
Array: []fp.Element{
*new(fp.Element).SetUint64(12341341234),
*new(fp.Element).SetUint64(0),
},
},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
args, err := ParseCairoProgramArgs(testCase.args)
require.NoError(t, err)
assert.Equal(t, testCase.expected, args)
})
}
}
Loading
Loading