diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 83452c25ff..390d212339 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -724,3 +724,43 @@ jobs: - name: Run script run: ./vm/src/tests/compare_factorial_outputs_all_layouts.sh + + compare-run-from-cairo-pie-all-outputs: + name: Compare all outputs from running Cairo PIEs + needs: [ build-programs, build-release, run-cairo-release ] + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Python3 Build + uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pip' + + - name: Install cairo-lang and deps + run: pip install -r requirements.txt + + - name: Fetch release binary + uses: actions/cache/restore@v3 + with: + key: cli-bin-rel-${{ github.sha }} + path: target/release/cairo-vm-cli + fail-on-cache-miss: true + + - name: Fetch traces for cairo-vm + uses: actions/cache/restore@v3 + with: + path: | + cairo_programs/**/*.memory + cairo_programs/**/*.trace + cairo_programs/**/*.air_public_input + cairo_programs/**/*.air_private_input + cairo_programs/**/*.pie.zip + key: cairo_test_programs-release-trace-cache-${{ github.sha }} + fail-on-cache-miss: true + + - name: Run comparison + run: ./vm/src/tests/compare_all_pie_outputs.sh + diff --git a/.gitignore b/.gitignore index 2e1f8ff93e..69a905dfdf 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ **/*.air_public_input **/*.air_private_input **/*.pie.zip +**/*.pie **/*.swp bench/results .python-version diff --git a/CHANGELOG.md b/CHANGELOG.md index aec7c7db9b..fd630557ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* feat: Add `--run_from_cairo_pie` to `cairo-vm-cli` + workflow [#1730](https://github.com/lambdaclass/cairo-vm/pull/1730) + * Serialize directly into writer in `CairoPie::write_zip_file`[#1736](https://github.com/lambdaclass/cairo-vm/pull/1736) * feat: Add support for cairo1 run with segements arena validation. diff --git a/Makefile b/Makefile index 86b6d7d7df..a1d80ebadc 100644 --- a/Makefile +++ b/Makefile @@ -329,6 +329,9 @@ compare_air_private_input: $(CAIRO_RS_AIR_PRIVATE_INPUT) $(CAIRO_AIR_PRIVATE_INP compare_pie: $(CAIRO_RS_PIE) $(CAIRO_PIE) cd vm/src/tests; ./compare_vm_state.sh pie +compare_all_pie_outputs: $(CAIRO_RS_PIE) + cd vm/src/tests; ./compare_all_pie_outputs.sh + # Run with nightly enable the `doc_cfg` feature wich let us provide clear explaination about which parts of the code are behind a feature flag docs: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --verbose --release --locked --no-deps --all-features --open @@ -338,6 +341,7 @@ clean: rm -f $(TEST_DIR)/*.memory rm -f $(TEST_DIR)/*.trace rm -f $(TEST_DIR)/*.pie.zip + rm -f $(TEST_DIR)/*.pie rm -f $(BENCH_DIR)/*.json rm -f $(BAD_TEST_DIR)/*.json rm -f $(PRINT_TEST_DIR)/*.json diff --git a/README.md b/README.md index de1d3b9ede..7835eb70e6 100644 --- a/README.md +++ b/README.md @@ -174,10 +174,12 @@ The cairo-vm-cli supports the following optional arguments: - `--air_private_input `: Receives the name of a file and outputs the AIR private inputs into it. Can only be used if proof_mode, trace_file & memory_file are also enabled. -- `--cairo_pie_output `: Receives the name of a file and outputs the Cairo PIE into it. Can only be used if proof_mode, is not enabled. +- `--cairo_pie_output `: Receives the name of a file and outputs the Cairo PIE into it. Can only be used if proof_mode is not enabled. - `--allow_missing_builtins`: Disables the check that all builtins used by the program need to be included in the selected layout. Enabled by default when in proof_mode. +- `run_from_cairo_pie`: Runs a Cairo PIE instead of a compiled json file. The name of the file will be the first argument received by the CLI (as if it were to run a normal compiled program). Can only be used if proof_mode is not enabled. + For example, to obtain the air public inputs from a fibonacci program run, we can run : ```bash diff --git a/cairo-vm-cli/src/main.rs b/cairo-vm-cli/src/main.rs index 9ca039dbaa..376fd2e371 100644 --- a/cairo-vm-cli/src/main.rs +++ b/cairo-vm-cli/src/main.rs @@ -10,8 +10,10 @@ use cairo_vm::types::layout_name::LayoutName; use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; use cairo_vm::vm::errors::trace_errors::TraceError; use cairo_vm::vm::errors::vm_errors::VirtualMachineError; +use cairo_vm::vm::runners::cairo_pie::CairoPie; #[cfg(feature = "with_tracer")] use cairo_vm::vm::runners::cairo_runner::CairoRunner; +use cairo_vm::vm::runners::cairo_runner::RunResources; #[cfg(feature = "with_tracer")] use cairo_vm::vm::vm_core::VirtualMachine; #[cfg(feature = "with_tracer")] @@ -68,6 +70,13 @@ struct Args { #[structopt(long = "tracer")] #[cfg(feature = "with_tracer")] tracer: bool, + #[structopt( + long = "run_from_cairo_pie", + // We need to add these air_private_input & air_public_input or else + // passing run_from_cairo_pie + either of these without proof_mode will not fail + conflicts_with_all = ["proof_mode", "air_private_input", "air_public_input"] + )] + run_from_cairo_pie: bool, } #[derive(Debug, Error)] @@ -153,7 +162,7 @@ fn run(args: impl Iterator) -> Result<(), Error> { let args = Args::try_parse_from(args)?; let trace_enabled = args.trace_file.is_some() || args.air_public_input.is_some(); - let mut hint_executor = BuiltinHintProcessor::new_empty(); + let cairo_run_config = cairo_run::CairoRunConfig { entrypoint: &args.entrypoint, trace_enabled, @@ -165,16 +174,26 @@ fn run(args: impl Iterator) -> Result<(), Error> { ..Default::default() }; - let program_content = std::fs::read(args.filename).map_err(Error::IO)?; - - let (cairo_runner, mut vm) = - match cairo_run::cairo_run(&program_content, &cairo_run_config, &mut hint_executor) { - Ok(runner) => runner, - Err(error) => { - eprintln!("{error}"); - return Err(Error::Runner(error)); - } - }; + let (cairo_runner, mut vm) = match { + if args.run_from_cairo_pie { + let pie = CairoPie::read_zip_file(&args.filename)?; + let mut hint_processor = BuiltinHintProcessor::new( + Default::default(), + RunResources::new(pie.execution_resources.n_steps), + ); + cairo_run::cairo_run_pie(&pie, &cairo_run_config, &mut hint_processor) + } else { + let program_content = std::fs::read(args.filename).map_err(Error::IO)?; + let mut hint_processor = BuiltinHintProcessor::new_empty(); + cairo_run::cairo_run(&program_content, &cairo_run_config, &mut hint_processor) + } + } { + Ok(runner) => runner, + Err(error) => { + eprintln!("{error}"); + return Err(Error::Runner(error)); + } + }; if args.print_output { let mut output_buffer = "Program Output:\n".to_string(); diff --git a/vm/src/tests/cairo_pie_comparator.py b/vm/src/tests/cairo_pie_comparator.py index ab604beaa4..de518ec186 100755 --- a/vm/src/tests/cairo_pie_comparator.py +++ b/vm/src/tests/cairo_pie_comparator.py @@ -23,5 +23,3 @@ # Compare binary files with cairo_lang_pie_zip.open("memory.bin", 'r') as f1, cairo_vm_pie_zip.open("memory.bin", 'r') as f2: memory_comparator.compare_memory_file_contents(f1.read(), f2.read()) - - print(f"Comparison succesful for {filename1} vs {filename2}") diff --git a/vm/src/tests/compare_all_pie_outputs.sh b/vm/src/tests/compare_all_pie_outputs.sh new file mode 100755 index 0000000000..b7b0614d77 --- /dev/null +++ b/vm/src/tests/compare_all_pie_outputs.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env sh + +# move to the directory where the script is located +cd $(dirname "$0") + +tests_path="../../../cairo_programs/" +exit_code=0 +passed_tests=0 +failed_tests=0 + +files=$(ls $tests_path) +EXIT_CODE=$? +if [ ${EXIT_CODE} != 0 ]; then + exit ${EXIT_CODE} +fi + +for file in $(ls $tests_path | grep .rs.pie.zip$ | sed -E 's/\.rs.pie.zip$//'); do + path_file="$tests_path/$file" + + # Run Cairo PIE using cairo_lang + echo "Running $file PIE with cairo_lang" + if ! cairo-run --run_from_cairo_pie $path_file.rs.pie.zip --trace_file $path_file.trace.pie --memory_file $path_file.memory.pie --cairo_pie_output $path_file.pie.zip.pie --layout starknet_with_keccak 2> /dev/null; then + echo "Skipping $file.pie as it fails validations in cairo_lang" + break + fi + echo "Running $file PIE with cairo-vm" + cargo run -p cairo-vm-cli --release $path_file.rs.pie.zip --run_from_cairo_pie --trace_file $path_file.rs.trace.pie --memory_file $path_file.rs.memory.pie --cairo_pie_output $path_file.rs.pie.zip.pie --layout starknet_with_keccak + # Compare PIE outputs + echo "Comparing $file.pie outputs" + + # Compare trace + if ! diff -q $path_file.trace.pie $path_file.rs.trace.pie; then + echo "Traces for $file differ" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi + + # Compare Memory + if ! ./memory_comparator.py $path_file.memory.pie $path_file.rs.memory.pie; then + echo "Memory differs for $file" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi + + # Compare PIE + if ! ./cairo_pie_comparator.py $path_file.pie.zip.pie $path_file.rs.pie.zip.pie; then + echo "Cairo PIE differs for $file" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi +done + +if test $failed_tests != 0; then + echo "Comparisons: $failed_tests failed, $passed_tests passed, $((failed_tests + passed_tests)) total" +elif test $passed_tests = 0; then + echo "No tests ran!" + exit_code=2 +else + echo "All $passed_tests tests passed; no discrepancies found" +fi + +exit "${exit_code}" diff --git a/vm/src/vm/runners/cairo_pie.rs b/vm/src/vm/runners/cairo_pie.rs index e1392be88a..cca0bcb8fd 100644 --- a/vm/src/vm/runners/cairo_pie.rs +++ b/vm/src/vm/runners/cairo_pie.rs @@ -270,7 +270,6 @@ impl CairoPie { #[cfg(feature = "std")] pub fn read_zip_file(file_path: &Path) -> Result { use std::io::Read; - use zip::ZipArchive; let file = File::open(file_path)?;