Skip to content

Commit

Permalink
refactor: remove cairo flag and add a unified program parser and Cair…
Browse files Browse the repository at this point in the history
…oRunner constructor
  • Loading branch information
zmalatrax committed Jul 15, 2024
1 parent f975466 commit 02405a8
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 60 deletions.
1 change: 0 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ program
})
)
.option('-s, --silent', 'silent all logs')
.option('--cairo', 'Run a Cairo program')
.addOption(
new Option('--fn <NAME>', 'Function to be executed').default('main')
)
Expand Down
84 changes: 35 additions & 49 deletions src/runners/cairoRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { RangeCheckOutOfBounds } from 'errors/builtins';

import { Felt } from 'primitives/felt';
import { Relocatable } from 'primitives/relocatable';
import { parseCairoZeroProgram } from 'vm/program';
import { parseProgram } from 'vm/program';
import { CairoRunner, RunOptions } from './cairoRunner';

const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cairo-vm-ts-'));
Expand Down Expand Up @@ -77,33 +77,27 @@ const BAD_RANGE_CHECK96_PROGRAM_STRING = fs.readFileSync(
'utf8'
);

const FIBONACCI_PROGRAM = parseCairoZeroProgram(FIBONACCI_PROGRAM_STRING);
const BITWISE_PROGRAM = parseCairoZeroProgram(BITWISE_PROGRAM_STRING);
const EC_OP_PROGRAM = parseCairoZeroProgram(EC_OP_PROGRAM_STRING);
const PEDERSEN_PROGRAM = parseCairoZeroProgram(PEDERSEN_PROGRAM_STRING);
const POSEIDON_PROGRAM = parseCairoZeroProgram(POSEIDON_PROGRAM_STRING);
const KECCAK_SEED_PROGRAM = parseCairoZeroProgram(KECCAK_SEED_PROGRAM_STRING);
const KECCAK_PROGRAM = parseCairoZeroProgram(KECCAK_PROGRAM_STRING);
const JMP_PROGRAM = parseCairoZeroProgram(JMP_PROGRAM_STRING);
const BITWISE_OUTPUT_PROGRAM = parseCairoZeroProgram(
BITWISE_OUTPUT_PROGRAM_STRING
);
const RANGE_CHECK_PROGRAM = parseCairoZeroProgram(RANGE_CHECK_PROGRAM_STRING);
const RANGE_CHECK96_PROGRAM = parseCairoZeroProgram(
RANGE_CHECK96_PROGRAM_STRING
);

const BAD_RANGE_CHECK_PROGRAM = parseCairoZeroProgram(
BAD_RANGE_CHECK_PROGRAM_STRING
);
const BAD_RANGE_CHECK96_PROGRAM = parseCairoZeroProgram(
const FIBONACCI_PROGRAM = parseProgram(FIBONACCI_PROGRAM_STRING);
const BITWISE_PROGRAM = parseProgram(BITWISE_PROGRAM_STRING);
const EC_OP_PROGRAM = parseProgram(EC_OP_PROGRAM_STRING);
const PEDERSEN_PROGRAM = parseProgram(PEDERSEN_PROGRAM_STRING);
const POSEIDON_PROGRAM = parseProgram(POSEIDON_PROGRAM_STRING);
const KECCAK_SEED_PROGRAM = parseProgram(KECCAK_SEED_PROGRAM_STRING);
const KECCAK_PROGRAM = parseProgram(KECCAK_PROGRAM_STRING);
const JMP_PROGRAM = parseProgram(JMP_PROGRAM_STRING);
const BITWISE_OUTPUT_PROGRAM = parseProgram(BITWISE_OUTPUT_PROGRAM_STRING);
const RANGE_CHECK_PROGRAM = parseProgram(RANGE_CHECK_PROGRAM_STRING);
const RANGE_CHECK96_PROGRAM = parseProgram(RANGE_CHECK96_PROGRAM_STRING);

const BAD_RANGE_CHECK_PROGRAM = parseProgram(BAD_RANGE_CHECK_PROGRAM_STRING);
const BAD_RANGE_CHECK96_PROGRAM = parseProgram(
BAD_RANGE_CHECK96_PROGRAM_STRING
);

describe('cairoRunner', () => {
describe('constructor', () => {
test('should construct', () => {
const runner = CairoRunner.fromCairoZeroProgram(FIBONACCI_PROGRAM);
const runner = CairoRunner.fromProgram(FIBONACCI_PROGRAM);
expect(runner.programBase).toEqual(new Relocatable(0, 0));
expect(runner.executionBase).toEqual(new Relocatable(1, 0));
expect(runner.vm.pc).toEqual(new Relocatable(0, 0));
Expand All @@ -115,7 +109,7 @@ describe('cairoRunner', () => {

describe('run', () => {
test('should return the value of the 10th fibonacci number', () => {
const runner = CairoRunner.fromCairoZeroProgram(FIBONACCI_PROGRAM);
const runner = CairoRunner.fromProgram(FIBONACCI_PROGRAM);
const config: RunOptions = { relocate: true, offset: 0 };
runner.run(config);
const executionSize = runner.vm.memory.getSegmentSize(1);
Expand All @@ -129,7 +123,7 @@ describe('cairoRunner', () => {
* It should be removed if reading the file, to avoid race conditions
*/
test('should export encoded trace', () => {
const runner = CairoRunner.fromCairoZeroProgram(FIBONACCI_PROGRAM);
const runner = CairoRunner.fromProgram(FIBONACCI_PROGRAM);
const config: RunOptions = { relocate: false, offset: 1 };
runner.run(config);
const trace_filename = 'fibonacci_trace_ts.bin';
Expand All @@ -143,7 +137,7 @@ describe('cairoRunner', () => {
});

test('should export encoded memory', () => {
const runner = CairoRunner.fromCairoZeroProgram(FIBONACCI_PROGRAM);
const runner = CairoRunner.fromProgram(FIBONACCI_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const memoryFilename = 'fibonacci_memory_ts.bin';
Expand All @@ -160,7 +154,7 @@ describe('cairoRunner', () => {
describe('builtins', () => {
describe('bitwise', () => {
test('should compute bitwise operations 12 & 10, 12 ^10 and 12 | 10', () => {
const runner = CairoRunner.fromCairoZeroProgram(BITWISE_PROGRAM);
const runner = CairoRunner.fromProgram(BITWISE_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const executionSize = runner.vm.memory.getSegmentSize(1);
Expand All @@ -175,7 +169,7 @@ describe('cairoRunner', () => {

describe('ec_op', () => {
test('should properly compute R = P + 34Q', () => {
const runner = CairoRunner.fromCairoZeroProgram(EC_OP_PROGRAM);
const runner = CairoRunner.fromProgram(EC_OP_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);

Expand All @@ -195,7 +189,7 @@ describe('cairoRunner', () => {

describe('pedersen', () => {
test('should properly compute Pedersen hashes of (0, 0), (0, 1), (1, 0) and (54, 1249832432) tuples', () => {
const runner = CairoRunner.fromCairoZeroProgram(PEDERSEN_PROGRAM);
const runner = CairoRunner.fromProgram(PEDERSEN_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);

Expand Down Expand Up @@ -224,7 +218,7 @@ describe('cairoRunner', () => {

describe('poseidon', () => {
test('should properly compute Poseidon states from initial states (1, 2, 3) and (13, 40, 36)', () => {
const runner = CairoRunner.fromCairoZeroProgram(POSEIDON_PROGRAM);
const runner = CairoRunner.fromProgram(POSEIDON_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);

Expand Down Expand Up @@ -268,7 +262,7 @@ describe('cairoRunner', () => {

describe('keccak', () => {
test('Should properly compute state from input state KeccakBuiltinState(0, 0, 0, 0, 0, 0, 0, 0)', () => {
const runner = CairoRunner.fromCairoZeroProgram(KECCAK_SEED_PROGRAM);
const runner = CairoRunner.fromProgram(KECCAK_SEED_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);

Expand All @@ -294,7 +288,7 @@ describe('cairoRunner', () => {
});

test('Should properly compute state from input state KeccakBuiltinState(1, 2, 3, 4, 5, 6, 7, 8)', () => {
const runner = CairoRunner.fromCairoZeroProgram(KECCAK_PROGRAM);
const runner = CairoRunner.fromProgram(KECCAK_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);

Expand Down Expand Up @@ -322,7 +316,7 @@ describe('cairoRunner', () => {

describe('output', () => {
test('Should properly store the jmp dest value in the output segment', () => {
const runner = CairoRunner.fromCairoZeroProgram(JMP_PROGRAM);
const runner = CairoRunner.fromProgram(JMP_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const output = runner.getOutput();
Expand All @@ -331,7 +325,7 @@ describe('cairoRunner', () => {
});

test('Should properly write the result of bitwise 1 & 2 to output segment', () => {
const runner = CairoRunner.fromCairoZeroProgram(BITWISE_OUTPUT_PROGRAM);
const runner = CairoRunner.fromProgram(BITWISE_OUTPUT_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const output = runner.getOutput();
Expand All @@ -342,7 +336,7 @@ describe('cairoRunner', () => {

describe('range_check', () => {
test('should properly write 2 ** 128 - 1 to the range check segment', () => {
const runner = CairoRunner.fromCairoZeroProgram(RANGE_CHECK_PROGRAM);
const runner = CairoRunner.fromProgram(RANGE_CHECK_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const executionSize = runner.vm.memory.getSegmentSize(1);
Expand All @@ -353,9 +347,7 @@ describe('cairoRunner', () => {
});

test('should crash the VM when trying to assert -1 to the range check segment', () => {
const runner = CairoRunner.fromCairoZeroProgram(
BAD_RANGE_CHECK_PROGRAM
);
const runner = CairoRunner.fromProgram(BAD_RANGE_CHECK_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
expect(() => runner.run(config)).toThrow(
new RangeCheckOutOfBounds(new Felt(-1n), 128n)
Expand All @@ -365,7 +357,7 @@ describe('cairoRunner', () => {

describe('range_check96', () => {
test('should properly write 2 ** 96 - 1 to the range check segment', () => {
const runner = CairoRunner.fromCairoZeroProgram(RANGE_CHECK96_PROGRAM);
const runner = CairoRunner.fromProgram(RANGE_CHECK96_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const executionSize = runner.vm.memory.getSegmentSize(1);
Expand All @@ -376,9 +368,7 @@ describe('cairoRunner', () => {
});

test('should crash the VM when trying to assert 2 ** 96 to the range check segment', () => {
const runner = CairoRunner.fromCairoZeroProgram(
BAD_RANGE_CHECK96_PROGRAM
);
const runner = CairoRunner.fromProgram(BAD_RANGE_CHECK96_PROGRAM);
const config: RunOptions = { relocate: true, offset: 1 };
expect(() => runner.run(config)).toThrow(
new RangeCheckOutOfBounds(new Felt(2n ** 96n), 96n)
Expand All @@ -393,10 +383,8 @@ describe('cairoRunner', () => {
const pyMemoryPath = path.join(tmpDir, 'memory_python.bin');
await $`poetry run cairo-run --layout=starknet --program=${programPath} --memory_file ${pyMemoryPath}`;

const program = parseCairoZeroProgram(
fs.readFileSync(programPath, 'utf8')
);
const runner = CairoRunner.fromCairoZeroProgram(program);
const program = parseProgram(fs.readFileSync(programPath, 'utf8'));
const runner = CairoRunner.fromProgram(program);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const tsMemoryPath = path.join(tmpDir, 'memory_ts.bin');
Expand All @@ -413,10 +401,8 @@ describe('cairoRunner', () => {
const pyTracePath = path.join(tmpDir, 'trace_python.bin');
await $`poetry run cairo-run --layout=starknet --program=${programPath} --trace_file ${pyTracePath}`;

const program = parseCairoZeroProgram(
fs.readFileSync(programPath, 'utf8')
);
const runner = CairoRunner.fromCairoZeroProgram(program);
const program = parseProgram(fs.readFileSync(programPath, 'utf8'));
const runner = CairoRunner.fromProgram(program);
const config: RunOptions = { relocate: true, offset: 1 };
runner.run(config);
const tsTracePath = path.join(tmpDir, 'trace_ts.bin');
Expand Down
10 changes: 10 additions & 0 deletions src/runners/cairoRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ export class CairoRunner {
);
}

static fromProgram(program: Program, fnName: string = 'main') {
if (program.compiler_version.split('.')[0] == '0') {
return CairoRunner.fromCairoZeroProgram(
program as CairoZeroProgram,
fnName
);
}
return CairoRunner.fromCairoProgram(program as CairoProgram, fnName);
}

/**
* Run the loaded program with the given config
*/
Expand Down
12 changes: 3 additions & 9 deletions src/scripts/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as fs from 'fs';
import { ConsolaInstance, LogLevels } from 'consola';

import { TraceEntry } from 'vm/virtualMachine';
import { parseCairoProgram, parseCairoZeroProgram } from 'vm/program';
import { parseProgram } from 'vm/program';
import { CairoRunner, RunOptions } from 'runners/cairoRunner';

export const run = (
Expand All @@ -16,7 +16,6 @@ export const run = (
try {
const {
silent,
cairo,
fn,
relocate,
offset,
Expand Down Expand Up @@ -45,13 +44,8 @@ export const run = (

const file = fs.readFileSync(String(path), 'utf-8');

if (cairo) {
const program = parseCairoProgram(file);
runner = CairoRunner.fromCairoProgram(program, fn);
} else {
const program = parseCairoZeroProgram(file);
runner = CairoRunner.fromCairoZeroProgram(program, fn);
}
const program = parseProgram(file);
runner = CairoRunner.fromProgram(program, fn);
const config: RunOptions = { relocate: relocate, offset: offset };
runner.run(config);
consola.success('Execution finished!');
Expand Down
2 changes: 1 addition & 1 deletion src/vm/program.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('program', () => {
describe('parseCairo1Program', () => {
test('should correctly parse the program', () => {
const programContent = fs.readFileSync(
'cairo_programs/cairo/hints/test_less_than_true.casm.json',
'cairo_programs/cairo/hints/test_less_than_true.json',
'utf8'
);
const programJson = JSON.parse(programContent);
Expand Down
11 changes: 11 additions & 0 deletions src/vm/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,14 @@ export function parseCairoZeroProgram(prgm: string): CairoZeroProgram {
export function parseCairoProgram(program: string): CairoProgram {
return cairoProgram.parse(JSON.parse(program));
}

export function parseProgram(prgm: string): Program {
const jsonPrgm = JSON.parse(prgm);
if (
jsonPrgm.compiler_version &&
jsonPrgm.compiler_version.split('.')[0] == '0'
) {
return cairoZeroProgram.parse(jsonPrgm);
}
return cairoProgram.parse(jsonPrgm);
}

0 comments on commit 02405a8

Please sign in to comment.