diff --git a/pkg/vm/program.go b/pkg/vm/program.go index 09025055..a601fddc 100644 --- a/pkg/vm/program.go +++ b/pkg/vm/program.go @@ -2,20 +2,102 @@ package vm import ( "encoding/json" + "fmt" "os" + "strconv" f "github.com/NethermindEth/juno/core/felt" ) +type Builtin uint8 + +const ( + Output Builtin = iota + 1 + RangeCheck + Pedersen + ECDSA + Keccak + Bitwise + ECOP + Poseidon + SegmentArena +) + +func (b Builtin) MarshalJSON() ([]byte, error) { + switch b { + case Output: + return []byte("output"), nil + case RangeCheck: + return []byte("range_check"), nil + case Pedersen: + return []byte("pedersen"), nil + case ECDSA: + return []byte("ecdsa"), nil + case Keccak: + return []byte("keccak"), nil + case Bitwise: + return []byte("bitwise"), nil + case ECOP: + return []byte("ec_op"), nil + case Poseidon: + return []byte("poseidon"), nil + case SegmentArena: + return []byte("segment_arena"), nil + + } + return nil, fmt.Errorf("error marshaling builtin with unknow identifer: %d", uint8(b)) +} + +func (b *Builtin) UnmarshalJSON(data []byte) error { + builtinName, err := strconv.Unquote(string(data)) + if err != nil { + return fmt.Errorf("error unmarsahling builtin: %w", err) + } + + switch builtinName { + case "output": + *b = Output + case "range_check": + *b = RangeCheck + case "pedersen": + *b = Pedersen + case "ecdsa": + *b = ECDSA + case "keccak": + *b = Keccak + case "bitwise": + *b = Bitwise + case "ec_op": + *b = ECOP + case "poseidon": + *b = Poseidon + case "segment_arena": + *b = SegmentArena + default: + return fmt.Errorf("error unmarsahling unknwon builtin name: %s", builtinName) + } + return nil +} + +type EntryPointInfo struct { + Selector f.Felt `json:"selector"` + Offset f.Felt `json:"offset"` + Builtins []Builtin `json:"builtins"` +} + +type EntryPointByType struct { + External []EntryPointInfo `json:"EXTERNAL"` + L1Handler []EntryPointInfo `json:"L1_HANDLER"` + Constructor []EntryPointInfo `json:"CONSTRUCTOR"` +} + type Program struct { // Prime is fixed to be 0x800000000000011000000000000000000000000000000000000000000000001 and wont fit in a f.Felt - Bytecode []f.Felt `json:"bytecode"` - CompilerVersion string `json:"compiler_version"` - // todo(rodro): Add remaining Json fields + Bytecode []f.Felt `json:"bytecode"` + CompilerVersion string `json:"compiler_version"` + EntryPoints EntryPointByType `json:"entry_points_by_type"` + // todo(rodro): Add remaining Json field // Hints - // EntryPointsByType - // Contructors - // L1 Headers } func ProgramFromFile(pathToFile string) (*Program, error) { diff --git a/pkg/vm/program_test.go b/pkg/vm/program_test.go index 2fc48320..e1687e2d 100644 --- a/pkg/vm/program_test.go +++ b/pkg/vm/program_test.go @@ -7,10 +7,20 @@ import ( "github.com/stretchr/testify/require" ) -func TestValidPrime(t *testing.T) { +func TestCompilerVersionParsing(t *testing.T) { + testData := []byte(` + { + "compiler_version": "2.1.0" + } + `) + program, err := ProgramFromJSON(testData) + require.NoError(t, err) + assert.Equal(t, "2.1.0", program.CompilerVersion) +} + +func TestByteCodeParsing(t *testing.T) { testData := []byte(` { - "compiler_version": "2.1.0", "bytecode": [ "0xa0680017fff8000", "0x7", @@ -21,12 +31,92 @@ func TestValidPrime(t *testing.T) { `) program, err := ProgramFromJSON(testData) require.NoError(t, err) - assert.Equal(t, "2.1.0", program.CompilerVersion) assert.Len(t, program.Bytecode, 4) assert.Equal(t, "0x482680017ffa8000", program.Bytecode[2].String()) } -func TestInvalidPrime(t *testing.T) { +func TestEmptyEntryPointTypeParsing(t *testing.T) { + testData := []byte(` + { + "entry_points_by_selector": { + "EXTERNAL": [], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + } + } + `) + program, err := ProgramFromJSON(testData) + require.NoError(t, err) + + entryPoints := program.EntryPoints + assert.Empty(t, entryPoints.External) + assert.Empty(t, entryPoints.L1Handler) + assert.Empty(t, entryPoints.Constructor) + +} + +func TestEntryPointInfoParsing(t *testing.T) { + testData := []byte(` + { + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0xabcdef0123456789", + "offset": 14, + "builtins": [ + "output", + "range_check", + "pedersen", + "ecdsa", + "keccak", + "bitwise", + "ec_op", + "poseidon", + "segment_arena" + ] + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + } + } + `) + program, err := ProgramFromJSON(testData) + require.NoError(t, err) + + entryPoints := program.EntryPoints + assert.Len(t, entryPoints.External, 1) + + entryPointInfo := entryPoints.External[0] + assert.Equal(t, entryPointInfo.Selector.String(), "0xabcdef0123456789") + assert.Equal(t, entryPointInfo.Offset.String(), "0xe") + + assert.Len(t, entryPointInfo.Builtins, 9) + for i := 0; i < 9; i++ { + assert.Equal(t, Builtin(i+1), entryPointInfo.Builtins[i]) + } +} + +func TestInvalidBuiltin(t *testing.T) { + testData := []byte(` + { + "entry_points_by_type": { + "EXTERNAL": [ + { + "selector": "0xabcdef0123456789", + "offset": 14, + "builtins": [ + "pedrsen", + ] + } + ], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + } + } + `) + _, err := ProgramFromJSON(testData) + assert.Error(t, err) }