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

feat: add basic cli #85

Merged
merged 25 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ed751b4
dev: add cli packages
zmalatrax Jun 10, 2024
c5c9f36
feat: add basic cli
zmalatrax Jun 10, 2024
4088eb1
dev: remove figlet
zmalatrax Jun 10, 2024
4a6c28c
feat: add error handling and flag conflicts
zmalatrax Jun 10, 2024
de6bbd9
doc: add telegram group to README
zmalatrax Jun 10, 2024
25b0d68
chore: downgrade trunk check to python 3.10 for consistency with test…
zmalatrax Jun 11, 2024
f754906
doc: add CLI usage to README
zmalatrax Jun 11, 2024
99c6a17
chore: move Usage after Cairo presentation
zmalatrax Jun 11, 2024
58fc3f5
doc: add cli usage example
zmalatrax Jun 11, 2024
09fc201
doc: add state of builtins implem
zmalatrax Jun 11, 2024
8186a76
fix: use Op1Src enum for instruction initialization
zmalatrax Jun 11, 2024
b73bd21
chore: remove unused local variable
zmalatrax Jun 11, 2024
154af96
feat: add package build script
zmalatrax Jun 11, 2024
66a76ee
chore: add types to print trace variables
zmalatrax Jun 11, 2024
5b16fbf
chore: remove empty cli file
zmalatrax Jun 11, 2024
492d497
chore: rename memory error to avoid export conflicts
zmalatrax Jun 11, 2024
3c52fd4
feat: add build script with type declaration transforms
zmalatrax Jun 11, 2024
8fe8a74
refactor: export argument json validation to argument argParser
zmalatrax Jun 11, 2024
c7b20f3
doc: update doc for local dependency use
zmalatrax Jun 11, 2024
69e279a
feat: rename cli to cairo
zmalatrax Jun 11, 2024
0edccba
refactor: rename relocateOffset to offset
zmalatrax Jun 11, 2024
df4caab
doc: use updated cli command name
zmalatrax Jun 11, 2024
ca9bf65
chore: remove unused scripts
zmalatrax Jun 12, 2024
673c17e
chore: format RunOptions
zmalatrax Jun 12, 2024
65f51df
refactor: wrap cli action in a global try catch clause
zmalatrax Jun 12, 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
8 changes: 4 additions & 4 deletions .github/workflows/trunk-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist

cairo_programs/**/*.json
55 changes: 50 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# TypeScript Cairo VM
# Cairo VM Typescript

<div align="center">
<h1><code>TypeScript Cairo VM</code></h1>
<h1><code>Cairo VM TypeScript</code></h1>

<strong>An implementation of the Cairo VM in TypeScript, focusing on
education</strong>

[Github](https://github.com/kkrt-labs/cairo-vm-ts)
[Github](https://github.com/kkrt-labs/cairo-vm-ts) ·
[Telegram](https://t.me/cairovmts)

<sub>Built with 🥕 by <a href="https://twitter.com/KakarotZkEvm">KKRT
Labs</a></sub>
Expand Down Expand Up @@ -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 [email protected]: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 [email protected]: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:
`<bun | yarn | npm> add ~/path/to/cairo-vm-ts`

## State of the VM

| Goals | Done? |
| ---------------------------- | ------- |
| Run basic Cairo Zero program | &#9745; |
| Run basic Cairo program | &#9744; |
| Add [builtins](#builtins) | &#9744; |
| Add [builtins](#builtins) | &#9745; |
| Add [hints](#hints) | &#9744; |
| Run StarkNet contracts | &#9744; |
| Benchmark against other VMs | &#9744; |
Expand All @@ -107,7 +139,20 @@ performance and safety. While the ones of our TypeScript implementation is

### Builtins

<!-- Add a table with the builtin list and state done/to be done -->
| Builtin | Done? |
| -------------------------------------------------------------------- | ------- |
| [Output](https://github.com/kkrt-labs/cairo-vm-ts/issues/65) | &#9745; |
| [Pedersen](https://github.com/kkrt-labs/cairo-vm-ts/issues/70) | &#9745; |
| [Range Check](https://github.com/kkrt-labs/cairo-vm-ts/issues/68) | &#9745; |
| [ECDSA](https://github.com/kkrt-labs/cairo-vm-ts/issues/67) | &#9745; |
| [Bitwise](https://github.com/kkrt-labs/cairo-vm-ts/issues/62) | &#9745; |
| [EcOp](https://github.com/kkrt-labs/cairo-vm-ts/issues/66) | &#9745; |
| [Keccak](https://github.com/kkrt-labs/cairo-vm-ts/issues/69) | &#9745; |
| [Poseidon](https://github.com/kkrt-labs/cairo-vm-ts/issues/71) | &#9745; |
| [Range Check 96](https://github.com/kkrt-labs/cairo-vm-ts/issues/81) | &#9745; |
| Segment Arena | &#9744; |
| AddMod | &#9744; |
| MulMod | &#9744; |

### Hints

Expand Down
Binary file modified bun.lockb
Binary file not shown.
38 changes: 30 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>",
"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",
Expand All @@ -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"
}
}
137 changes: 137 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -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(
'<program.json>',
'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 <OFFSET>',
'start address of the relocated memory\nStarkWare verifier expects offset to be 1'
)
.default(0, '0')
.argParser(parseInt)
)
.option(
'--export-trace <TRACE_FILENAME>',
'export the trace, little-endian encoded'
)
.option(
'--export-memory <MEMORY_FILENAME>',
'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 <OFFSET>', '--export-memory <MEMORY_FILENAME>' 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();
3 changes: 3 additions & 0 deletions src/errors/cairoRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class CairoRunnerError extends Error {}

export class EmptyRelocatedMemory extends CairoRunnerError {}
2 changes: 1 addition & 1 deletion src/errors/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
41 changes: 41 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Loading
Loading