From c713512ffbfbb3b6dde36b8d4625cf6fe81194f7 Mon Sep 17 00:00:00 2001 From: Malatrax <71888134+zmalatrax@users.noreply.github.com> Date: Wed, 12 Jun 2024 10:51:38 +0200 Subject: [PATCH] feat: add basic cli (#85) * dev: add cli packages * feat: add basic cli * dev: remove figlet * feat: add error handling and flag conflicts * doc: add telegram group to README * chore: downgrade trunk check to python 3.10 for consistency with tests action * doc: add CLI usage to README * chore: move Usage after Cairo presentation * doc: add cli usage example * doc: add state of builtins implem * fix: use Op1Src enum for instruction initialization * chore: remove unused local variable * feat: add package build script * chore: add types to print trace variables * chore: remove empty cli file * chore: rename memory error to avoid export conflicts * feat: add build script with type declaration transforms * refactor: export argument json validation to argument argParser * doc: update doc for local dependency use * feat: rename cli to cairo * refactor: rename relocateOffset to offset * doc: use updated cli command name * chore: remove unused scripts * chore: format RunOptions * refactor: wrap cli action in a global try catch clause --- .github/workflows/trunk-check.yaml | 8 +- .gitignore | 1 + README.md | 55 ++++++++++-- bun.lockb | Bin 4992 -> 26646 bytes package.json | 38 ++++++-- src/cli.ts | 137 +++++++++++++++++++++++++++++ src/errors/cairoRunner.ts | 3 + src/errors/memory.ts | 2 +- src/index.ts | 41 +++++++++ src/runners/cairoRunner.test.ts | 89 ++++--------------- src/runners/cairoRunner.ts | 16 ++-- src/vm/virtualMachine.test.ts | 29 +++--- src/vm/virtualMachine.ts | 12 +-- tsconfig.json | 39 ++++---- tsconfig.types.json | 21 +++++ 15 files changed, 357 insertions(+), 134 deletions(-) create mode 100755 src/cli.ts create mode 100644 src/errors/cairoRunner.ts create mode 100644 tsconfig.types.json diff --git a/.github/workflows/trunk-check.yaml b/.github/workflows/trunk-check.yaml index d3f0ec10..1db3fc33 100644 --- a/.github/workflows/trunk-check.yaml +++ b/.github/workflows/trunk-check.yaml @@ -18,13 +18,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Adding cairo-format - - name: Set up Python 3.11 - uses: actions/setup-python@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.10' cache: pip - run: pip install cairo-lang diff --git a/.gitignore b/.gitignore index 5da719c6..92f900e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules +dist cairo_programs/**/*.json diff --git a/README.md b/README.md index 0a969407..f1219e81 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ -# TypeScript Cairo VM +# Cairo VM Typescript
-

TypeScript Cairo VM

+

Cairo VM TypeScript

An implementation of the Cairo VM in TypeScript, focusing on education -[Github](https://github.com/kkrt-labs/cairo-vm-ts) +[Github](https://github.com/kkrt-labs/cairo-vm-ts) · +[Telegram](https://t.me/cairovmts) Built with 🥕 by KKRT Labs @@ -92,13 +93,44 @@ performance and safety. While the ones of our TypeScript implementation is - Deliberate design choices to further improve readability and simplicity - Extensive documentation: JSDoc, diagrams, explainers, etc. +## Usage + +### CLI + +You can install the CLI `cairo-vm-ts` by doing the following: + +1. Clone this repo: `git clone git@github.com:kkrt-labs/cairo-vm-ts.git` +2. Go to the cloned directory: `cd cairo-vm-ts` +3. Install the dependencies: `bun install` +4. Register the package as a _linkable_ package: `bun link` + +Example usage: + +```bash +cairo run fibonacci.json --export-memory fib_mem.bin --print-memory --print-output +``` + +### As a dependency + +No package release has been done yet. + +You can still add it as a dependency with a local copy: + +1. Clone this repo: `git clone git@github.com:kkrt-labs/cairo-vm-ts.git` +2. Go to the cloned directory: `cd cairo-vm-ts` +3. Install the dependencies: `bun install` +4. Build the project: `bun run build` +5. Go to your project `cd ~/my-project` +6. Add `cairo-vm-ts` to your project dependency: + ` add ~/path/to/cairo-vm-ts` + ## State of the VM | Goals | Done? | | ---------------------------- | ------- | | Run basic Cairo Zero program | ☑ | | Run basic Cairo program | ☐ | -| Add [builtins](#builtins) | ☐ | +| Add [builtins](#builtins) | ☑ | | Add [hints](#hints) | ☐ | | Run StarkNet contracts | ☐ | | Benchmark against other VMs | ☐ | @@ -107,7 +139,20 @@ performance and safety. While the ones of our TypeScript implementation is ### Builtins - +| Builtin | Done? | +| -------------------------------------------------------------------- | ------- | +| [Output](https://github.com/kkrt-labs/cairo-vm-ts/issues/65) | ☑ | +| [Pedersen](https://github.com/kkrt-labs/cairo-vm-ts/issues/70) | ☑ | +| [Range Check](https://github.com/kkrt-labs/cairo-vm-ts/issues/68) | ☑ | +| [ECDSA](https://github.com/kkrt-labs/cairo-vm-ts/issues/67) | ☑ | +| [Bitwise](https://github.com/kkrt-labs/cairo-vm-ts/issues/62) | ☑ | +| [EcOp](https://github.com/kkrt-labs/cairo-vm-ts/issues/66) | ☑ | +| [Keccak](https://github.com/kkrt-labs/cairo-vm-ts/issues/69) | ☑ | +| [Poseidon](https://github.com/kkrt-labs/cairo-vm-ts/issues/71) | ☑ | +| [Range Check 96](https://github.com/kkrt-labs/cairo-vm-ts/issues/81) | ☑ | +| Segment Arena | ☐ | +| AddMod | ☐ | +| MulMod | ☐ | ### Hints diff --git a/bun.lockb b/bun.lockb index cb5e0703add4ff87783096d44e08a5ccd712c4e3..bd72c0ec44fc90b812fad70e79cfed58c2a784d0 100755 GIT binary patch literal 26646 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 V?dH6xsursNX{~Kj=MJ9{z5^_e(xU(X diff --git a/package.json b/package.json index 656c5118..de7b4a33 100644 --- a/package.json +++ b/package.json @@ -2,18 +2,27 @@ "name": "cairo-vm-ts", "version": "1.0.0", "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "echo \"Error: no entrypoint yet\" && exit 1" - }, "keywords": [], "author": "Clément Walter ", "license": "Apache-2.0", - "devDependencies": { - "bun-types": "^1.1.12", - "typescript": "^5.2.2" + "main": "dist/index.js", + "types": "dist/types/index.d.ts", + "scripts": { + "clean": "rimraf dist", + "prebuild": "bun run clean", + "build": "bun build --target=node ./src/index.ts --outfile=dist/index.js && bun run build:declaration", + "build:declaration": "tspc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo" }, + "repository": { + "type": "git", + "url": "https://github.com/kkrt-labs/cairo-vm-ts" + }, + "files": [ + "src/**/*.ts", + "dist/*.js", + "dist/types/**/*.d.ts" + ], "prettier": { "proseWrap": "always", "trailingComma": "es5", @@ -23,8 +32,21 @@ "printWidth": 80 }, "dependencies": { + "@commander-js/extra-typings": "^12.1.0", "@noble/curves": "^1.4.0", "@scure/starknet": "^1.0.0", + "commander": "^12.1.0", + "consola": "^3.2.3", + "rimraf": "^5.0.7", "zod": "canary" + }, + "devDependencies": { + "bun-types": "^1.1.12", + "ts-patch": "^3.2.0", + "typescript": "^5.2.2", + "typescript-transform-paths": "^3.4.7" + }, + "bin": { + "cairo": "./src/cli.ts" } } diff --git a/src/cli.ts b/src/cli.ts new file mode 100755 index 00000000..f3db9ec1 --- /dev/null +++ b/src/cli.ts @@ -0,0 +1,137 @@ +#! /usr/bin/env bun + +import * as fs from 'fs'; +import { Command, Option } from '@commander-js/extra-typings'; + +import { consola } from 'consola'; +import { parseProgram } from 'vm/program'; +import { CairoRunner, RunOptions } from 'runners/cairoRunner'; +import { TraceEntry } from 'vm/virtualMachine'; +import { Argument } from 'commander'; + +consola.options = { + ...consola.options, + formatOptions: { + date: false, + }, +}; + +const VERSION_CLI = '0.1.0'; + +const program = new Command().name('cairo').version(VERSION_CLI); + +program + .command('run', { isDefault: true }) + .description('Run a compiled Cairo program') + .addArgument( + new Argument( + '', + 'path to Cairo compilation artifacts' + ).argParser((path) => { + if (!path.match(/\.json$/)) + throw new Error('Provided file is not a JSON'); + return path; + }) + ) + .option('--no-relocate', 'do not relocate memory') + .addOption( + new Option( + '--offset ', + 'start address of the relocated memory\nStarkWare verifier expects offset to be 1' + ) + .default(0, '0') + .argParser(parseInt) + ) + .option( + '--export-trace ', + 'export the trace, little-endian encoded' + ) + .option( + '--export-memory ', + 'export the relocated memory, little-endian encoded' + ) + .option('--print-trace', 'print the trace') + .option('--print-memory', 'print the non-relocated memory') + .option('--print-relocated-memory', 'print the relocated memory') + .option('--print-output', 'print the output segment') + .action(async (path, options) => { + try { + const { + relocate, + offset, + exportMemory, + exportTrace, + printOutput, + printMemory, + printRelocatedMemory, + printTrace, + } = options; + + if ( + (!relocate && !!offset) || + (!relocate && exportMemory) || + (!relocate && printRelocatedMemory) + ) { + consola.log( + "option '--no-relocate' cannot be used with options '--offset ', '--export-memory ' or '--print-relocated-memory'" + ); + process.exit(1); + } + + consola.info(`Cairo VM TS ${VERSION_CLI} - Execution Mode`); + + const program = parseProgram(fs.readFileSync(String(path), 'utf-8')); + const runner = new CairoRunner(program); + const config: RunOptions = { relocate: relocate, offset: offset }; + runner.run(config); + consola.success('Execution finished!'); + + if (exportMemory) { + consola.info('Exporting memory...'); + runner.exportMemory(exportMemory, offset); + consola.success(`Memory exported to ${exportMemory}`); + } + if (exportTrace) { + consola.info('Exporting trace...'); + runner.exportTrace(exportTrace); + consola.success(`Trace exported to ${exportTrace}`); + } + + if (printMemory) consola.log(runner.vm.memory.toString()); + if (printRelocatedMemory) + consola.log(runner.vm.relocatedMemoryToString()); + if (printTrace) + consola.log( + '\nTRACE:', + runner.vm.trace + .map((entry: TraceEntry, index: number) => + [ + `\nSTEP: ${index}`, + `pc: ${entry.pc.toString()}`, + `ap: ${entry.ap.toString()}`, + `fp: ${entry.fp.toString()}\n`, + ].join('\n') + ) + .join('\n') + ); + if (printOutput) { + const output = runner.getOutput(); + if (output.length) { + consola.log('Program output: '); + output.forEach((value) => consola.log(value.toString())); + } else { + consola.log('Output segment is empty'); + } + } + } catch (err) { + consola.fail(`Execution failed`); + throw err; + } + }); + +program.addHelpText( + 'beforeAll', + '\nGitHub: https://github.com/kkrt-labs/cairo-vm-ts\nTelegram: https://t.me/cairovmts\n' +); +program.showHelpAfterError(); +program.parse(); diff --git a/src/errors/cairoRunner.ts b/src/errors/cairoRunner.ts new file mode 100644 index 00000000..ce32834d --- /dev/null +++ b/src/errors/cairoRunner.ts @@ -0,0 +1,3 @@ +class CairoRunnerError extends Error {} + +export class EmptyRelocatedMemory extends CairoRunnerError {} diff --git a/src/errors/memory.ts b/src/errors/memory.ts index 86fbc768..68901090 100644 --- a/src/errors/memory.ts +++ b/src/errors/memory.ts @@ -34,4 +34,4 @@ export class SegmentOutOfBounds extends MemoryError { } /** Instruction must be a Field Element */ -export class InstructionError extends MemoryError {} +export class InvalidInstruction extends MemoryError {} diff --git a/src/index.ts b/src/index.ts index e69de29b..af945b46 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,41 @@ +export * as PrimitiveErrors from 'errors/primitives'; +export * as MemoryErrors from 'errors/memory'; +export * as InstructionErrors from 'errors/instruction'; +export * as VirtualMachineErrors from 'errors/virtualMachine'; +export * as BuiltinErrors from 'errors/builtins'; +export * as CairoRunnerErrors from 'errors/cairoRunner'; + +export { Felt } from 'primitives/felt'; +export { Relocatable } from 'primitives/relocatable'; +export { SegmentValue, isFelt, isRelocatable } from 'primitives/segmentValue'; + +export { Memory } from 'memory/memory'; +export { + Instruction, + Register, + Op1Src, + ResLogic, + Opcode, + PcUpdate, + ApUpdate, + FpUpdate, +} from 'vm/instruction'; +export { + VirtualMachine, + TraceEntry, + RelocatedMemory, + RelocatedTraceEntry, +} from 'vm/virtualMachine'; +export { parseProgram, Program, Identifier } from 'vm/program'; + +export { BuiltinHandler, getBuiltin } from 'builtins/builtin'; +export { outputHandler } from 'builtins/output'; +export { pedersenHandler } from 'builtins/pedersen'; +export { rangeCheckHandler } from 'builtins/rangeCheck'; +export { ecdsaHandler, EcdsaSegment, EcdsaSignature } from 'builtins/ecdsa'; +export { bitwiseHandler } from 'builtins/bitwise'; +export { ecOpHandler } from 'builtins/ecop'; +export { keccakHandler } from 'builtins/keccak'; +export { poseidonHandler } from 'builtins/poseidon'; + +export { CairoRunner, RunOptions } from 'runners/cairoRunner'; diff --git a/src/runners/cairoRunner.test.ts b/src/runners/cairoRunner.test.ts index 7e516d43..55267768 100644 --- a/src/runners/cairoRunner.test.ts +++ b/src/runners/cairoRunner.test.ts @@ -109,10 +109,7 @@ describe('cairoRunner', () => { describe('run', () => { test('should return the value of the 10th fibonacci number', () => { const runner = new CairoRunner(FIBONACCI_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 0, - }; + const config: RunOptions = { relocate: true, offset: 0 }; runner.run(config); const executionSize = runner.vm.memory.getSegmentSize(1); const executionEnd = runner.executionBase.add(executionSize); @@ -126,10 +123,7 @@ describe('cairoRunner', () => { */ test('should export encoded trace', () => { const runner = new CairoRunner(FIBONACCI_PROGRAM); - const config: RunOptions = { - relocate: false, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: false, offset: 1 }; runner.run(config); const trace_filename = 'fibonacci_trace_ts.bin'; const trace_path = path.join(tmpDir, trace_filename); @@ -143,14 +137,11 @@ describe('cairoRunner', () => { test('should export encoded memory', () => { const runner = new CairoRunner(FIBONACCI_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const memoryFilename = 'fibonacci_memory_ts.bin'; const memoryPath = path.join(tmpDir, memoryFilename); - runner.exportMemory(memoryPath, config.relocateOffset); + runner.exportMemory(memoryPath, config.offset); expect(() => fs.access(memoryPath, (err) => { if (err) throw err; @@ -163,10 +154,7 @@ describe('cairoRunner', () => { describe('bitwise', () => { test('should compute bitwise 12 & 10', () => { const runner = new CairoRunner(BITWISE_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const executionSize = runner.vm.memory.getSegmentSize(1); const executionEnd = runner.executionBase.add(executionSize); @@ -177,10 +165,7 @@ describe('cairoRunner', () => { describe('ec_op', () => { test('should properly compute R = P + 34Q', () => { const runner = new CairoRunner(EC_OP_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const expectedRx = new Felt( @@ -200,10 +185,7 @@ describe('cairoRunner', () => { describe('pedersen', () => { test('should properly compute Pedersen hashes of (0, 0), (0, 1), (1, 0) and (54, 1249832432) tuples', () => { const runner = new CairoRunner(PEDERSEN_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const expectedHashes = [ @@ -232,10 +214,7 @@ describe('cairoRunner', () => { describe('poseidon', () => { test('should properly compute Poseidon states from initial states (1, 2, 3) and (13, 40, 36)', () => { const runner = new CairoRunner(POSEIDON_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const expectedStates = [ @@ -279,10 +258,7 @@ describe('cairoRunner', () => { describe('keccak', () => { test('Should properly compute state from input state KeccakBuiltinState(0, 0, 0, 0, 0, 0, 0, 0)', () => { const runner = new CairoRunner(KECCAK_SEED_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const expectedState = [ @@ -308,10 +284,7 @@ describe('cairoRunner', () => { test('Should properly compute state from input state KeccakBuiltinState(1, 2, 3, 4, 5, 6, 7, 8)', () => { const runner = new CairoRunner(KECCAK_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const expectedState = [ @@ -339,10 +312,7 @@ describe('cairoRunner', () => { describe('output', () => { test('Should properly store the jmp dest value in the output segment', () => { const runner = new CairoRunner(JMP_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const output = runner.getOutput(); expect(output.length).toEqual(1); @@ -351,10 +321,7 @@ describe('cairoRunner', () => { test('Should properly write the result of bitwise 1 & 2 to output segment', () => { const runner = new CairoRunner(BITWISE_OUTPUT_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const output = runner.getOutput(); expect(output.length).toEqual(1); @@ -365,10 +332,7 @@ describe('cairoRunner', () => { describe('range_check', () => { test('should properly write 2 ** 128 - 1 to the range check segment', () => { const runner = new CairoRunner(RANGE_CHECK_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const executionSize = runner.vm.memory.getSegmentSize(1); const executionEnd = runner.executionBase.add(executionSize); @@ -379,10 +343,7 @@ describe('cairoRunner', () => { test('should crash the VM when trying to assert -1 to the range check segment', () => { const runner = new CairoRunner(BAD_RANGE_CHECK_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; expect(() => runner.run(config)).toThrow(new RangeCheckOutOfBounds()); }); }); @@ -390,10 +351,7 @@ describe('cairoRunner', () => { describe('range_check96', () => { test('should properly write 2 ** 96 - 1 to the range check segment', () => { const runner = new CairoRunner(RANGE_CHECK96_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const executionSize = runner.vm.memory.getSegmentSize(1); const executionEnd = runner.executionBase.add(executionSize); @@ -404,10 +362,7 @@ describe('cairoRunner', () => { test('should crash the VM when trying to assert 2 ** 96 to the range check segment', () => { const runner = new CairoRunner(BAD_RANGE_CHECK96_PROGRAM); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; expect(() => runner.run(config)).toThrow(new RangeCheckOutOfBounds()); }); }); @@ -421,13 +376,10 @@ describe('cairoRunner', () => { const program = parseProgram(fs.readFileSync(programPath, 'utf8')); const runner = new CairoRunner(program); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const tsMemoryPath = path.join(tmpDir, 'memory_ts.bin'); - runner.exportMemory(tsMemoryPath, config.relocateOffset); + runner.exportMemory(tsMemoryPath, config.offset); const tsMemory = fs.readFileSync(tsMemoryPath); @@ -442,10 +394,7 @@ describe('cairoRunner', () => { const program = parseProgram(fs.readFileSync(programPath, 'utf8')); const runner = new CairoRunner(program); - const config: RunOptions = { - relocate: true, - relocateOffset: 1, - }; + const config: RunOptions = { relocate: true, offset: 1 }; runner.run(config); const tsTracePath = path.join(tmpDir, 'trace_ts.bin'); runner.exportTrace(tsTracePath); diff --git a/src/runners/cairoRunner.ts b/src/runners/cairoRunner.ts index 4273a109..480b3802 100644 --- a/src/runners/cairoRunner.ts +++ b/src/runners/cairoRunner.ts @@ -1,18 +1,20 @@ import * as fs from 'fs'; +import { EmptyRelocatedMemory } from 'errors/cairoRunner'; + import { Relocatable } from 'primitives/relocatable'; -import { VirtualMachine } from 'vm/virtualMachine'; import { Program } from 'vm/program'; +import { VirtualMachine } from 'vm/virtualMachine'; import { getBuiltin } from 'builtins/builtin'; /** * Configuration of the run * - relocate: Flag to relocate the memory and the trace - * - relocateOffset: Start address of the relocated memory + * - offset: Start address of the relocated memory */ export type RunOptions = { relocate: boolean; - relocateOffset: number; + offset: number; }; export class CairoRunner { @@ -24,7 +26,7 @@ export class CairoRunner { static readonly defaultRunOptions: RunOptions = { relocate: false, - relocateOffset: 0, + offset: 0, }; constructor(program: Program) { @@ -58,8 +60,8 @@ export class CairoRunner { while (!this.vm.pc.eq(this.finalPc)) { this.vm.step(); } - const { relocate, relocateOffset } = config; - if (relocate) this.vm.relocate(relocateOffset); + const { relocate, offset } = config; + if (relocate) this.vm.relocate(offset); } /** @@ -91,6 +93,8 @@ export class CairoRunner { * @dev DataView must be used to enforce little-endianness */ exportMemory(filename: string = 'encoded_memory', offset: number = 0) { + if (!this.vm.relocatedMemory.length) throw new EmptyRelocatedMemory(); + const buffer = new ArrayBuffer(this.vm.relocatedMemory.length * 5 * 8); const view = new DataView(buffer); diff --git a/src/vm/virtualMachine.test.ts b/src/vm/virtualMachine.test.ts index 9f15e608..a9cdd6a5 100644 --- a/src/vm/virtualMachine.test.ts +++ b/src/vm/virtualMachine.test.ts @@ -16,6 +16,7 @@ import { PcUpdate, ApUpdate, FpUpdate, + Op1Src, } from './instruction'; import { VirtualMachine } from './virtualMachine'; @@ -26,7 +27,7 @@ const instructions = { 3, Register.Fp, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Add, PcUpdate.Regular, ApUpdate.Ap, @@ -39,7 +40,7 @@ const instructions = { 3, Register.Fp, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Add, PcUpdate.Regular, ApUpdate.Ap, @@ -52,7 +53,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Regular, ApUpdate.Ap, @@ -65,7 +66,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Pc, + Op1Src.Pc, ResLogic.Unused, PcUpdate.Regular, ApUpdate.Ap, @@ -78,7 +79,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Jump, ApUpdate.Ap, @@ -91,7 +92,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.JumpRel, ApUpdate.Ap, @@ -104,7 +105,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.JumpRel, ApUpdate.Add2, @@ -117,7 +118,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Jnz, ApUpdate.Ap, @@ -130,7 +131,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Pc, + Op1Src.Pc, ResLogic.Unused, PcUpdate.Jnz, ApUpdate.Ap, @@ -143,7 +144,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Regular, ApUpdate.Ap, @@ -156,7 +157,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Regular, ApUpdate.Ap, @@ -169,7 +170,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Regular, ApUpdate.Add2, @@ -182,7 +183,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Regular, ApUpdate.Add1, @@ -195,7 +196,7 @@ const instructions = { 0, Register.Ap, Register.Ap, - Register.Ap, + Op1Src.Ap, ResLogic.Unused, PcUpdate.Regular, ApUpdate.AddRes, diff --git a/src/vm/virtualMachine.ts b/src/vm/virtualMachine.ts index 6d4b2cb7..669bca12 100644 --- a/src/vm/virtualMachine.ts +++ b/src/vm/virtualMachine.ts @@ -7,7 +7,7 @@ import { UndefinedInstruction, InvalidOp0, } from 'errors/virtualMachine'; -import { InstructionError } from 'errors/memory'; +import { InvalidInstruction } from 'errors/memory'; import { Relocatable } from 'primitives/relocatable'; import { Felt } from 'primitives/felt'; @@ -24,19 +24,19 @@ import { ResLogic, } from './instruction'; -type TraceEntry = { +export type TraceEntry = { pc: Relocatable; ap: Relocatable; fp: Relocatable; }; -type RelocatedTraceEntry = { +export type RelocatedTraceEntry = { pc: Felt; ap: Felt; fp: Felt; }; -type RelocatedMemory = { +export type RelocatedMemory = { address: number; value: Felt; }; @@ -75,7 +75,7 @@ export class VirtualMachine { } if (!isFelt(maybeEncodedInstruction)) { - throw new InstructionError(); + throw new InvalidInstruction(); } const encodedInstruction = maybeEncodedInstruction.toBigInt(); @@ -93,7 +93,7 @@ export class VirtualMachine { * for more details */ runInstruction(instruction: Instruction): void { - const { op0, op1, res, dst } = this.computeStepValues(instruction); + const { op1, res, dst } = this.computeStepValues(instruction); this.trace.push({ pc: this.pc, ap: this.ap, fp: this.fp }); diff --git a/tsconfig.json b/tsconfig.json index eb0acfd8..384c831a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,28 @@ { "compilerOptions": { - // add Bun type definitions - "types": ["bun-types"], - - // enable latest features + "outDir": "./dist", + "baseUrl": ".", + "paths": { + "*": ["./src/*"] + }, "lib": ["esnext"], "module": "esnext", "target": "esnext", - - "baseUrl": "./src", - - // if TS 5.x+ - "moduleResolution": "bundler", - "noEmit": true, - "allowImportingTsExtensions": true, + "moduleResolution": "node", "moduleDetection": "force", - // if TS 4.x or earlier - // "moduleResolution": "nodenext", - - "allowJs": false, // disallow importing `.js` from `.ts` - "esModuleInterop": true, // allow default imports for CommonJS modules - - // best practices + "allowImportingTsExtensions": true, + "noEmit": true, "strict": true, + "allowJs": false, + "skipLibCheck": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "noUnusedParameters": true, "forceConsistentCasingInFileNames": true, - "skipLibCheck": true - } + "types": ["bun-types"], + "esModuleInterop": true // allow default imports for CommonJS modules + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] } diff --git a/tsconfig.types.json b/tsconfig.types.json new file mode 100644 index 00000000..1b489557 --- /dev/null +++ b/tsconfig.types.json @@ -0,0 +1,21 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist/types", + "rootDir": "./src", + "plugins": [ + { + "transform": "typescript-transform-paths" + }, + { + "transform": "typescript-transform-paths", + "afterDeclarations": true + } + ] + }, + "include": ["./src/**/*.ts"], + "exclude": ["node_modules", "./src/**/*.test.ts"] +}