diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 78c54e0454..98318a8e3c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -737,6 +737,7 @@ jobs: path: lcov-test-no_std#4-cairo-0-secp-hints.info key: codecov-cache-test-no_std#4-cairo-0-secp-hints-${{ github.sha }} fail-on-cache-miss: true + - name: Upload coverage to codecov.io uses: codecov/codecov-action@v3 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe623c736..dab70f72f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,32 +2,6 @@ #### Upcoming Changes -* feat: Use BTreeMap in PIE additional data [#2162](https://github.com/lambdaclass/cairo-vm/pull/2162) - -* feat: Remove prover input info struct and add getters instead [#2149](https://github.com/lambdaclass/cairo-vm/pull/2149) - -* feat: Added support for large files in PIE [#2136](https://github.com/lambdaclass/cairo-vm/pull/2136) - -* feat: Disable relocate trace with flag [#2133](https://github.com/lambdaclass/cairo-vm/pull/2133) - -* feat: Enable using secure run in proof mode [#2113](https://github.com/lambdaclass/cairo-vm/pull/2113) - -* [BREAKING] Compute missing builtin cells only in proof mode [#2088](https://github.com/lambdaclass/cairo-vm/pull/2088) - -* test: Add test for filling holes in builtin segments [#2087](https://github.com/lambdaclass/cairo-vm/pull/2087) - -* fix: Removed memory comparison test with Python VM in proof mode, since the new hole-filling logic causes divergence.[#2086](https://github.com/lambdaclass/cairo-vm/pull/2086) - -* refactor: Use BTreeMap for deterministic order of PIE keys [#2085](https://github.com/lambdaclass/cairo-vm/pull/2085) - -* fix: Fix zero offset output base assumption [#2068](https://github.com/lambdaclass/cairo-vm/pull/2068) - -* feat: Add perpetual and dex with bitwise layouts [#2067](https://github.com/lambdaclass/cairo-vm/pull/2067) - -* feat: Fill holes in builtins segments to save computation in the prover [#2036](https://github.com/lambdaclass/cairo-vm/pull/2036) - -* feat: Added hints felt unpacking for blake [#2032](https://github.com/lambdaclass/cairo-vm/pull/2032) - * dev: make `VirtualMachine::get_traceback_entries` pub * chore: Pin types-rs version to the one set in lockfile [#2140](https://github.com/lambdaclass/cairo-vm/pull/2140) diff --git a/cairo-vm-cli/src/main.rs b/cairo-vm-cli/src/main.rs index 49d51a5489..daaf1e1712 100644 --- a/cairo-vm-cli/src/main.rs +++ b/cairo-vm-cli/src/main.rs @@ -180,13 +180,12 @@ fn run(args: impl Iterator) -> Result<(), Error> { entrypoint: &args.entrypoint, trace_enabled, relocate_mem: args.memory_file.is_some() || args.air_public_input.is_some(), - relocate_trace: trace_enabled, layout: args.layout, proof_mode: args.proof_mode, secure_run: args.secure_run, allow_missing_builtins: args.allow_missing_builtins, dynamic_layout_params: cairo_layout_params, - disable_trace_padding: false, + ..Default::default() }; let mut cairo_runner = match if args.run_from_cairo_pie { diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index 51418afbc3..fbe0760d94 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -267,12 +267,7 @@ pub fn cairo_run_program( runner.run_for_steps(1, &mut hint_processor)?; } - runner.end_run( - false, - false, - &mut hint_processor, - cairo_run_config.proof_mode, - )?; + runner.end_run(false, false, &mut hint_processor)?; let result_inner_type_size = result_inner_type_size(return_type_id, &sierra_program_registry, &type_sizes); @@ -341,7 +336,7 @@ pub fn cairo_run_program( } } - runner.relocate(true, true)?; + runner.relocate(true)?; Ok((runner, return_values, serialized_output)) } diff --git a/cairo_programs/poseidon_builtin_hole.cairo b/cairo_programs/poseidon_builtin_hole.cairo deleted file mode 100644 index 7835eae950..0000000000 --- a/cairo_programs/poseidon_builtin_hole.cairo +++ /dev/null @@ -1,13 +0,0 @@ -%builtins poseidon -from starkware.cairo.common.cairo_builtins import PoseidonBuiltin -from starkware.cairo.common.poseidon_state import PoseidonBuiltinState - -func main{poseidon_ptr: PoseidonBuiltin*}() { - assert poseidon_ptr[0].input = PoseidonBuiltinState(1, 2, 3); - let result = poseidon_ptr[0].output; - let poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; - // Note that we are not accesing result.s1. - assert result.s0 = 442682200349489646213731521593476982257703159825582578145778919623645026501; - assert result.s2 = 2512222140811166287287541003826449032093371832913959128171347018667852712082; - return (); -} diff --git a/vm/src/cairo_run.rs b/vm/src/cairo_run.rs index b07f078de7..eb63334e4c 100644 --- a/vm/src/cairo_run.rs +++ b/vm/src/cairo_run.rs @@ -27,10 +27,7 @@ pub struct CairoRunConfig<'a> { #[cfg_attr(feature = "test_utils", arbitrary(value = "main"))] pub entrypoint: &'a str, pub trace_enabled: bool, - /// Relocate memory if `true`, otherwise memory is not relocated. pub relocate_mem: bool, - // When `relocate_trace` is set to `false`, the trace will not be relocated even if `trace_enabled` is `true`. - pub relocate_trace: bool, pub layout: LayoutName, /// The `dynamic_layout_params` argument should only be used with dynamic layout. /// It is ignored otherwise. @@ -54,8 +51,6 @@ impl Default for CairoRunConfig<'_> { entrypoint: "main", trace_enabled: false, relocate_mem: false, - // Set to true to match expected behavior: trace is relocated only if trace_enabled is true. - relocate_trace: true, layout: LayoutName::plain, proof_mode: false, secure_run: None, @@ -109,9 +104,9 @@ pub fn cairo_run_program_with_initial_scope( cairo_run_config.disable_trace_padding, false, hint_processor, - cairo_run_config.proof_mode, )?; + cairo_runner.vm.verify_auto_deductions()?; cairo_runner.read_return_values(allow_missing_builtins)?; if cairo_run_config.proof_mode { cairo_runner.finalize_segments()?; @@ -119,10 +114,7 @@ pub fn cairo_run_program_with_initial_scope( if secure_run { verify_secure_runner(&cairo_runner, true, None)?; } - cairo_runner.relocate( - cairo_run_config.relocate_mem, - cairo_run_config.relocate_trace, - )?; + cairo_runner.relocate(cairo_run_config.relocate_mem)?; Ok(cairo_runner) } @@ -221,9 +213,9 @@ pub fn cairo_run_pie( cairo_run_config.disable_trace_padding, false, hint_processor, - cairo_run_config.proof_mode, )?; + cairo_runner.vm.verify_auto_deductions()?; cairo_runner.read_return_values(allow_missing_builtins)?; if secure_run { @@ -231,10 +223,7 @@ pub fn cairo_run_pie( // Check that the Cairo PIE produced by this run is compatible with the Cairo PIE received cairo_runner.get_cairo_pie()?.check_pie_compatibility(pie)?; } - cairo_runner.relocate( - cairo_run_config.relocate_mem, - cairo_run_config.relocate_trace, - )?; + cairo_runner.relocate(cairo_run_config.relocate_mem)?; Ok(cairo_runner) } @@ -275,8 +264,9 @@ pub fn cairo_run_fuzzed_program( res.map_err(|err| VmException::from_vm_error(&cairo_runner, err))?; - cairo_runner.end_run(false, false, hint_processor, cairo_run_config.proof_mode)?; + cairo_runner.end_run(false, false, hint_processor)?; + cairo_runner.vm.verify_auto_deductions()?; cairo_runner.read_return_values(allow_missing_builtins)?; if cairo_run_config.proof_mode { cairo_runner.finalize_segments()?; @@ -284,10 +274,7 @@ pub fn cairo_run_fuzzed_program( if secure_run { verify_secure_runner(&cairo_runner, true, None)?; } - cairo_runner.relocate( - cairo_run_config.relocate_mem, - cairo_run_config.relocate_trace, - )?; + cairo_runner.relocate(cairo_run_config.relocate_mem)?; Ok(cairo_runner) } @@ -388,7 +375,7 @@ mod tests { let end = cairo_runner.initialize(false).unwrap(); assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_ok()); - assert!(cairo_runner.relocate(true, true).is_ok()); + assert!(cairo_runner.relocate(true).is_ok()); // `main` returns without doing nothing, but `not_main` sets `[ap]` to `1` // Memory location was found empirically and simply hardcoded assert_eq!(cairo_runner.relocated_memory[2], Some(Felt252::from(123))); @@ -454,7 +441,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = run_test_program(program_content, &mut hint_processor).unwrap(); - assert!(cairo_runner.relocate(false, true).is_ok()); + assert!(cairo_runner.relocate(false).is_ok()); let trace_entries = cairo_runner.relocated_trace.unwrap(); let mut buffer = [0; 24]; @@ -478,7 +465,7 @@ mod tests { let mut cairo_runner = run_test_program(program_content, &mut hint_processor).unwrap(); // relocate memory so we can dump it to file - assert!(cairo_runner.relocate(true, true).is_ok()); + assert!(cairo_runner.relocate(true).is_ok()); let mut buffer = [0; 120]; let mut buff_writer = SliceWriter::new(&mut buffer); @@ -502,7 +489,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program); let end = cairo_runner.initialize(false).unwrap(); assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_ok()); - assert!(cairo_runner.relocate(false, false).is_ok()); + assert!(cairo_runner.relocate(false).is_ok()); assert!(cairo_runner.relocated_trace.is_none()); } diff --git a/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs b/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs index 8dfcedf030..3251cff0e8 100644 --- a/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs @@ -1,4 +1,3 @@ -use crate::hint_processor::hint_processor_utils::felt_to_usize; use crate::stdlib::{borrow::Cow, collections::HashMap, prelude::*}; use crate::types::errors::math_errors::MathError; @@ -18,11 +17,9 @@ use crate::{ vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, }; -use num_bigint::BigUint; -use num_integer::Integer; use num_traits::ToPrimitive; -use super::hint_utils::{get_integer_from_var_name, insert_value_into_ap}; +use super::hint_utils::get_integer_from_var_name; fn get_fixed_size_u32_array( h_range: &Vec>, @@ -245,84 +242,6 @@ pub fn blake2s_add_uint256_bigend( Ok(()) } -/* Implements Hint: -memory[ap] = (ids.end != ids.packed_values) and (memory[ids.packed_values] < 2**63) -*/ -pub fn is_less_than_63_bits_and_not_end( - vm: &mut VirtualMachine, - ids_data: &HashMap, - ap_tracking: &ApTracking, -) -> Result<(), HintError> { - let end = get_ptr_from_var_name("end", vm, ids_data, ap_tracking)?; - let packed_values = get_ptr_from_var_name("packed_values", vm, ids_data, ap_tracking)?; - - if end == packed_values { - insert_value_into_ap(vm, 0)? - } else { - let val = vm.get_integer(packed_values)?; - insert_value_into_ap( - vm, - (val.to_biguint() < (BigUint::from(1_u32) << 63)) as usize, - )? - } - Ok(()) -} - -/* Implements Hint: -offset = 0 -for i in range(ids.packed_values_len): - val = (memory[ids.packed_values + i] % PRIME) - val_len = 2 if val < 2**63 else 8 - if val_len == 8: - val += 2**255 - for i in range(val_len - 1, -1, -1): - val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32) - assert val == 0 - offset += val_len -*/ -pub fn blake2s_unpack_felts( - vm: &mut VirtualMachine, - ids_data: &HashMap, - ap_tracking: &ApTracking, -) -> Result<(), HintError> { - let packed_values_len = - get_integer_from_var_name("packed_values_len", vm, ids_data, ap_tracking)?; - let packed_values = get_ptr_from_var_name("packed_values", vm, ids_data, ap_tracking)?; - let unpacked_u32s = get_ptr_from_var_name("unpacked_u32s", vm, ids_data, ap_tracking)?; - - let vals = vm.get_integer_range(packed_values, felt_to_usize(&packed_values_len)?)?; - let pow2_32 = BigUint::from(1_u32) << 32; - let pow2_63 = BigUint::from(1_u32) << 63; - let pow2_255 = BigUint::from(1_u32) << 255; - - // Split value into either 2 or 8 32-bit limbs. - let out: Vec = vals - .into_iter() - .map(|val| val.to_biguint()) - .flat_map(|val| { - if val < pow2_63 { - let (high, low) = val.div_rem(&pow2_32); - vec![high, low] - } else { - let mut limbs = vec![BigUint::from(0_u32); 8]; - let mut val: BigUint = val + &pow2_255; - for limb in limbs.iter_mut().rev() { - let (q, r) = val.div_rem(&pow2_32); - *limb = r; - val = q; - } - limbs - } - }) - .map(Felt252::from) - .map(MaybeRelocatable::from) - .collect(); - - vm.load_data(unpacked_u32s, &out) - .map_err(HintError::Memory)?; - Ok(()) -} - /* Implements Hint: %{ from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress @@ -685,103 +604,6 @@ mod tests { .is_none()); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn is_less_than_63_bits_and_not_end_ends() { - let hint_code = hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END; - //Create vm - let mut vm = vm!(); - //Insert ids into memory - vm.segments = segments![((1, 0), (1, 2)), ((1, 1), (1, 2)), ((1, 2), 123)]; - vm.set_fp(3); - vm.set_ap(3); - let ids_data = ids_data!["end", "packed_values", "value"]; - //Execute the hint - assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(())); - //Check data ptr - check_memory![vm.segments.memory, ((1, 3), 0)]; - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn is_less_than_63_bits_and_not_end_small() { - let hint_code = hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END; - //Create vm - let mut vm = vm!(); - //Insert ids into memory - vm.segments = segments![((1, 0), (1, 3)), ((1, 1), (1, 2)), ((1, 2), 123)]; - vm.set_fp(3); - vm.set_ap(3); - let ids_data = ids_data!["end", "packed_values", "value"]; - //Execute the hint - assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(())); - //Check data ptr - check_memory![vm.segments.memory, ((1, 3), 1)]; - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn is_less_than_63_bits_and_not_end_big() { - let hint_code = hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END; - //Create vm - let mut vm = vm!(); - //Insert ids into memory - vm.segments = segments![ - ((1, 0), (1, 3)), - ((1, 1), (1, 2)), - ((1, 2), 0x10000000000000000) - ]; - vm.set_fp(3); - vm.set_ap(3); - let ids_data = ids_data!["end", "packed_values", "value"]; - //Execute the hint - assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(())); - //Check data ptr - check_memory![vm.segments.memory, ((1, 3), 0)]; - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn blake2s_unpack_felts() { - let hint_code = hint_code::BLAKE2S_UNPACK_FELTS; - //Create vm - let mut vm = vm!(); - //Insert ids into memory - vm.segments = segments![ - ((1, 0), 2), - ((1, 1), (1, 3)), - ((1, 2), (2, 0)), - ((1, 3), 0x123456781234), - ((1, 4), 0x1234abcd5678efab1234abcd) - ]; - vm.set_fp(5); - vm.set_ap(5); - let ids_data = ids_data![ - "packed_values_len", - "packed_values", - "unpacked_u32s", - "small_value", - "big_value" - ]; - vm.segments.add(); - //Execute the hint - assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(())); - //Check data ptr - check_memory![ - vm.segments.memory, - ((2, 0), 0x1234), - ((2, 1), 0x56781234), - ((2, 2), 0x80000000), - ((2, 3), 0), - ((2, 4), 0), - ((2, 5), 0), - ((2, 6), 0), - ((2, 7), 0x1234abcd), - ((2, 8), 0x5678efab), - ((2, 9), 0x1234abcd) - ]; - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn blake2s_add_uint256_bigend_valid_non_zero() { diff --git a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index ea4cfc272e..e96e1de372 100644 --- a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -1,6 +1,6 @@ use super::blake2s_utils::example_blake2s_compress; use super::{ - blake2s_utils::{blake2s_unpack_felts, finalize_blake2s_v3, is_less_than_63_bits_and_not_end}, + blake2s_utils::finalize_blake2s_v3, ec_recover::{ ec_recover_divmod_n_packed, ec_recover_product_div_m, ec_recover_product_mod, ec_recover_sub_a_b, @@ -362,12 +362,6 @@ impl HintProcessorLogic for BuiltinHintProcessor { hint_code::BLAKE2S_ADD_UINT256_BIGEND => { blake2s_add_uint256_bigend(vm, &hint_data.ids_data, &hint_data.ap_tracking) } - hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END => { - is_less_than_63_bits_and_not_end(vm, &hint_data.ids_data, &hint_data.ap_tracking) - } - hint_code::BLAKE2S_UNPACK_FELTS => { - blake2s_unpack_felts(vm, &hint_data.ids_data, &hint_data.ap_tracking) - } hint_code::UNSAFE_KECCAK => { unsafe_keccak(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } diff --git a/vm/src/hint_processor/builtin_hint_processor/hint_code.rs b/vm/src/hint_processor/builtin_hint_processor/hint_code.rs index 5d0919e0c8..addb4e007f 100644 --- a/vm/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/vm/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -426,17 +426,6 @@ segments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4) MASK = 2 ** 32 - 1 segments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)]) segments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])"#}), -(IS_LESS_THAN_63_BITS_AND_NOT_END, indoc! {r#"memory[ap] = to_felt_or_relocatable((ids.end != ids.packed_values) and (memory[ids.packed_values] < 2**63))"#}), -(BLAKE2S_UNPACK_FELTS, indoc! {r#"offset = 0 -for i in range(ids.packed_values_len): - val = (memory[ids.packed_values + i] % PRIME) - val_len = 2 if val < 2**63 else 8 - if val_len == 8: - val += 2**255 - for i in range(val_len - 1, -1, -1): - val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32) - assert val == 0 - offset += val_len"#}), (EXAMPLE_BLAKE2S_COMPRESS, indoc! {r#"from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS) diff --git a/vm/src/tests/cairo_pie_test.rs b/vm/src/tests/cairo_pie_test.rs index 33f3b22993..e6de72ea28 100644 --- a/vm/src/tests/cairo_pie_test.rs +++ b/vm/src/tests/cairo_pie_test.rs @@ -9,7 +9,7 @@ use wasm_bindgen_test::*; use crate::{ cairo_run::{cairo_run, CairoRunConfig}, hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor, - stdlib::collections::BTreeMap, + stdlib::collections::HashMap, types::relocatable::Relocatable, vm::runners::{ cairo_pie::{ @@ -45,7 +45,7 @@ fn pedersen_test() { // ret_pc_segment assert_eq!(pie_metadata.ret_pc_segment, SegmentInfo::from((6, 0))); // builtin_segments - let expected_builtin_segments = BTreeMap::from([ + let expected_builtin_segments = HashMap::from([ (BuiltinName::output, SegmentInfo::from((2, 1))), (BuiltinName::pedersen, SegmentInfo::from((3, 3))), (BuiltinName::range_check, SegmentInfo::from((4, 0))), @@ -71,7 +71,7 @@ fn pedersen_test() { let expected_execution_resources = ExecutionResources { n_steps: 14, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([ + builtin_instance_counter: HashMap::from([ (BuiltinName::range_check, 0), (BuiltinName::output, 1), (BuiltinName::pedersen, 1), @@ -79,12 +79,12 @@ fn pedersen_test() { }; assert_eq!(cairo_pie.execution_resources, expected_execution_resources); // additional_data - let expected_additional_data = BTreeMap::from([ + let expected_additional_data = HashMap::from([ ( BuiltinName::output, BuiltinAdditionalData::Output(OutputBuiltinAdditionalData { - pages: BTreeMap::new(), - attributes: BTreeMap::new(), + pages: HashMap::new(), + attributes: HashMap::new(), }), ), ( @@ -128,7 +128,7 @@ fn common_signature() { assert_eq!(pie_metadata.ret_pc_segment, SegmentInfo::from((4, 0))); // builtin_segments let expected_builtin_segments = - BTreeMap::from([(BuiltinName::ecdsa, SegmentInfo::from((2, 2)))]); + HashMap::from([(BuiltinName::ecdsa, SegmentInfo::from((2, 2)))]); assert_eq!(pie_metadata.builtin_segments, expected_builtin_segments); // program_segment assert_eq!(pie_metadata.program_segment, SegmentInfo::from((0, 21))); @@ -150,13 +150,13 @@ fn common_signature() { let expected_execution_resources = ExecutionResources { n_steps: 11, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([(BuiltinName::ecdsa, 1)]), + builtin_instance_counter: HashMap::from([(BuiltinName::ecdsa, 1)]), }; assert_eq!(cairo_pie.execution_resources, expected_execution_resources); // additional_data - let expected_additional_data = BTreeMap::from([( + let expected_additional_data = HashMap::from([( BuiltinName::ecdsa, - BuiltinAdditionalData::Signature(BTreeMap::from([( + BuiltinAdditionalData::Signature(HashMap::from([( Relocatable::from((2, 0)), ( felt_str!( @@ -223,7 +223,7 @@ fn relocate_segments() { let expected_execution_resources = ExecutionResources { n_steps: 22, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::default(), + builtin_instance_counter: HashMap::default(), }; assert_eq!(cairo_pie.execution_resources, expected_execution_resources); // additional_data diff --git a/vm/src/tests/cairo_run_test.rs b/vm/src/tests/cairo_run_test.rs index b33a08535f..1eaa469f9a 100644 --- a/vm/src/tests/cairo_run_test.rs +++ b/vm/src/tests/cairo_run_test.rs @@ -1241,7 +1241,6 @@ fn run_program_with_custom_mod_builtin_params( cairo_run_config.disable_trace_padding, false, &mut hint_processor, - cairo_run_config.proof_mode, ) .unwrap(); diff --git a/vm/src/tests/compare_factorial_outputs_all_layouts.sh b/vm/src/tests/compare_factorial_outputs_all_layouts.sh index c6c784069a..e634fbb9d4 100755 --- a/vm/src/tests/compare_factorial_outputs_all_layouts.sh +++ b/vm/src/tests/compare_factorial_outputs_all_layouts.sh @@ -21,6 +21,15 @@ for layout in "plain" "small" "dex" "recursive" "starknet" "starknet_with_keccak else passed_tests=$((passed_tests + 1)) fi + # Compare memory + echo "Running memory comparison for layout $layout" + if ! ./vm/src/tests/memory_comparator.py factorial_rs.memory factorial_py.memory; then + echo "Memory differs for layout $layout" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi # Compare air public input echo "Running air public input comparison for layout $layout" if ! ./vm/src/tests/air_public_input_comparator.py factorial_rs.air_public_input factorial_py.air_public_input; then diff --git a/vm/src/tests/compare_outputs_dynamic_layouts.sh b/vm/src/tests/compare_outputs_dynamic_layouts.sh index 8346d4ba39..41c7bf0f17 100755 --- a/vm/src/tests/compare_outputs_dynamic_layouts.sh +++ b/vm/src/tests/compare_outputs_dynamic_layouts.sh @@ -207,6 +207,15 @@ for case in "${CASES[@]}"; do passed_tests=$((passed_tests + 1)) fi + # Compare memory + echo "Running memory comparison for case: $case" + if ! ./vm/src/tests/memory_comparator.py program_rs.memory program_py.memory; then + echo "Memory differs for case: $case" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi # Compare air public input echo "Running air public input comparison for case: $case" diff --git a/vm/src/tests/compare_vm_state.sh b/vm/src/tests/compare_vm_state.sh index bac9aa8cb6..34c7486663 100755 --- a/vm/src/tests/compare_vm_state.sh +++ b/vm/src/tests/compare_vm_state.sh @@ -65,7 +65,7 @@ for file in $(ls $tests_path | grep .cairo$ | sed -E 's/\.cairo$//'); do fi fi - if $memory && -z $proof_tests_path; then + if $memory; then if ! ./memory_comparator.py $path_file.memory $path_file.rs.memory; then echo "Memory differs for $file" exit_code=1 diff --git a/vm/src/types/builtin_name.rs b/vm/src/types/builtin_name.rs index 4f11488c5b..5490f439a1 100644 --- a/vm/src/types/builtin_name.rs +++ b/vm/src/types/builtin_name.rs @@ -32,7 +32,7 @@ const MUL_MOD_BUILTIN_NAME_WITH_SUFFIX: &str = "mul_mod_builtin"; /// Enum representing the name of a cairo builtin #[cfg_attr(feature = "test_utils", derive(Arbitrary))] -#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone, Eq, Hash, Ord, PartialOrd)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone, Eq, Hash)] #[allow(non_camel_case_types)] pub enum BuiltinName { output, @@ -179,11 +179,11 @@ impl core::fmt::Display for BuiltinName { // Implementation of custom serialization & deserialization for maps using builtin names with suffixes as keys pub(crate) mod serde_generic_map_impl { use super::BuiltinName; - use crate::stdlib::{collections::BTreeMap, string::String}; + use crate::stdlib::{collections::HashMap, string::String}; use serde::{de::Error, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; pub fn serialize( - values: &BTreeMap, + values: &HashMap, serializer: S, ) -> Result where @@ -199,13 +199,13 @@ pub(crate) mod serde_generic_map_impl { pub fn deserialize<'de, D: Deserializer<'de>, V: Deserialize<'de>>( d: D, - ) -> Result, D::Error> { + ) -> Result, D::Error> { // First deserialize keys into String - let map = BTreeMap::::deserialize(d)?; + let map = HashMap::::deserialize(d)?; // Then match keys to BuiltinName and handle invalid names map.into_iter() .map(|(k, v)| BuiltinName::from_str_with_suffix(&k).map(|k| (k, v))) - .collect::>>() + .collect::>>() .ok_or(D::Error::custom("Invalid builtin name")) } } diff --git a/vm/src/types/instance_definitions/builtins_instance_def.rs b/vm/src/types/instance_definitions/builtins_instance_def.rs index ab04a3272d..d98b3b3a3f 100644 --- a/vm/src/types/instance_definitions/builtins_instance_def.rs +++ b/vm/src/types/instance_definitions/builtins_instance_def.rs @@ -282,38 +282,6 @@ impl BuiltinsInstanceDef { mul_mod, } } - - pub(crate) fn perpetual() -> BuiltinsInstanceDef { - BuiltinsInstanceDef { - output: true, - pedersen: Some(PedersenInstanceDef::new(Some(32))), - range_check: Some(RangeCheckInstanceDef::new(Some(16))), - ecdsa: Some(EcdsaInstanceDef::new(Some(2048))), - bitwise: None, - ec_op: None, - keccak: None, - poseidon: None, - range_check96: None, - add_mod: None, - mul_mod: None, - } - } - - pub(crate) fn dex_with_bitwise() -> BuiltinsInstanceDef { - BuiltinsInstanceDef { - output: true, - pedersen: Some(PedersenInstanceDef::default()), - range_check: Some(RangeCheckInstanceDef::default()), - ecdsa: Some(EcdsaInstanceDef::default()), - bitwise: Some(BitwiseInstanceDef::new(Some(64))), - ec_op: None, - keccak: None, - poseidon: None, - range_check96: None, - add_mod: None, - mul_mod: None, - } - } } #[cfg(test)] diff --git a/vm/src/types/layout.rs b/vm/src/types/layout.rs index 30d920ef36..1c7fe138a8 100644 --- a/vm/src/types/layout.rs +++ b/vm/src/types/layout.rs @@ -169,30 +169,6 @@ impl CairoLayout { builtins: BuiltinsInstanceDef::dynamic(params), } } - - pub(crate) fn perpetual_instance() -> CairoLayout { - CairoLayout { - name: LayoutName::perpetual, - rc_units: 4, - cpu_component_step: DEFAULT_CPU_COMPONENT_STEP, - memory_units_per_step: DEFAULT_MEMORY_UNITS_PER_STEP, - builtins: BuiltinsInstanceDef::perpetual(), - public_memory_fraction: 4, - diluted_pool_instance_def: None, - } - } - - pub(crate) fn dex_with_bitwise_instance() -> CairoLayout { - CairoLayout { - name: LayoutName::dex_with_bitwise, - rc_units: 4, - cpu_component_step: DEFAULT_CPU_COMPONENT_STEP, - memory_units_per_step: DEFAULT_MEMORY_UNITS_PER_STEP, - builtins: BuiltinsInstanceDef::dex_with_bitwise(), - public_memory_fraction: 4, - diluted_pool_instance_def: Some(DilutedPoolInstanceDef::new(2, 4, 16)), - } - } } #[cfg(feature = "test_utils")] @@ -520,31 +496,6 @@ mod tests { ); } - #[test] - fn get_perpetual_instance() { - let layout = CairoLayout::perpetual_instance(); - let builtins = BuiltinsInstanceDef::perpetual(); - assert_eq!(layout.name, LayoutName::perpetual); - assert_eq!(layout.rc_units, 4); - assert_eq!(layout.builtins, builtins); - assert_eq!(layout.public_memory_fraction, 4); - assert_eq!(layout.diluted_pool_instance_def, None); - } - - #[test] - fn get_dex_with_bitwise_instance() { - let layout = CairoLayout::dex_with_bitwise_instance(); - let builtins = BuiltinsInstanceDef::dex_with_bitwise(); - assert_eq!(layout.name, LayoutName::dex_with_bitwise); - assert_eq!(layout.rc_units, 4); - assert_eq!(layout.builtins, builtins); - assert_eq!(layout.public_memory_fraction, 4); - assert_eq!( - layout.diluted_pool_instance_def, - Some(DilutedPoolInstanceDef::new(2, 4, 16)) - ); - } - #[test] fn get_dynamic_instance() { // dummy cairo layout params diff --git a/vm/src/types/layout_name.rs b/vm/src/types/layout_name.rs index 24addc4507..0d3e13c021 100644 --- a/vm/src/types/layout_name.rs +++ b/vm/src/types/layout_name.rs @@ -22,8 +22,6 @@ pub enum LayoutName { all_cairo, dynamic, all_cairo_stwo, - perpetual, - dex_with_bitwise, } impl LayoutName { @@ -41,8 +39,6 @@ impl LayoutName { LayoutName::all_cairo => "all_cairo", LayoutName::dynamic => "dynamic", LayoutName::all_cairo_stwo => "all_cairo_stwo", - LayoutName::perpetual => "perpetual", - LayoutName::dex_with_bitwise => "dex_with_bitwise", } } } @@ -69,8 +65,6 @@ impl ValueEnum for LayoutName { Self::all_cairo, Self::dynamic, Self::all_cairo_stwo, - Self::perpetual, - Self::dex_with_bitwise, ] } diff --git a/vm/src/vm/runners/builtin_runner/mod.rs b/vm/src/vm/runners/builtin_runner/mod.rs index 77e6de07da..a8cb0a6d06 100644 --- a/vm/src/vm/runners/builtin_runner/mod.rs +++ b/vm/src/vm/runners/builtin_runner/mod.rs @@ -401,7 +401,7 @@ impl BuiltinRunner { } } - pub fn cells_per_instance(&self) -> u32 { + fn cells_per_instance(&self) -> u32 { match self { BuiltinRunner::Bitwise(_) => CELLS_PER_BITWISE, BuiltinRunner::EcOp(_) => CELLS_PER_EC_OP, diff --git a/vm/src/vm/runners/builtin_runner/modulo.rs b/vm/src/vm/runners/builtin_runner/modulo.rs index 6d0d711945..85a8fe8070 100644 --- a/vm/src/vm/runners/builtin_runner/modulo.rs +++ b/vm/src/vm/runners/builtin_runner/modulo.rs @@ -821,25 +821,15 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let program = Program::from_bytes(program_data, Some("main")).unwrap(); - let proof_mode = true; - let mut runner = CairoRunner::new( - &program, - LayoutName::all_cairo, - None, - proof_mode, - false, - false, - ) - .unwrap(); + let mut runner = + CairoRunner::new(&program, LayoutName::all_cairo, None, true, false, false).unwrap(); let end = runner.initialize(false).unwrap(); // Modify add_mod & mul_mod params runner.run_until_pc(end, &mut hint_processor).unwrap(); runner.run_for_steps(1, &mut hint_processor).unwrap(); - runner - .end_run(false, false, &mut hint_processor, proof_mode) - .unwrap(); + runner.end_run(false, false, &mut hint_processor).unwrap(); runner.read_return_values(false).unwrap(); runner.finalize_segments().unwrap(); diff --git a/vm/src/vm/runners/builtin_runner/output.rs b/vm/src/vm/runners/builtin_runner/output.rs index 8b84f38fa8..ae54908565 100644 --- a/vm/src/vm/runners/builtin_runner/output.rs +++ b/vm/src/vm/runners/builtin_runner/output.rs @@ -1,4 +1,4 @@ -use crate::stdlib::{collections::BTreeMap, prelude::*}; +use crate::stdlib::{collections::HashMap, prelude::*}; use crate::types::builtin_name::BuiltinName; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::MemoryError; @@ -12,7 +12,6 @@ use crate::vm::vm_memory::memory_segments::MemorySegmentManager; #[derive(Debug, Clone, PartialEq)] pub struct OutputBuiltinState { pub base: usize, - pub base_offset: usize, pub pages: Pages, pub attributes: Attributes, } @@ -20,7 +19,6 @@ pub struct OutputBuiltinState { #[derive(Debug, Clone)] pub struct OutputBuiltinRunner { base: usize, - pub base_offset: usize, pub(crate) pages: Pages, pub(crate) attributes: Attributes, pub(crate) stop_ptr: Option, @@ -31,19 +29,17 @@ impl OutputBuiltinRunner { pub fn new(included: bool) -> OutputBuiltinRunner { OutputBuiltinRunner { base: 0, - base_offset: 0, - pages: BTreeMap::default(), - attributes: BTreeMap::default(), + pages: HashMap::default(), + attributes: HashMap::default(), stop_ptr: None, included, } } - pub fn new_state(&mut self, base: usize, base_offset: usize, included: bool) { + pub fn new_state(&mut self, base: usize, included: bool) { self.base = base; - self.base_offset = base_offset; - self.pages = BTreeMap::default(); - self.attributes = BTreeMap::default(); + self.pages = HashMap::default(); + self.attributes = HashMap::default(); self.stop_ptr = None; self.included = included; } @@ -147,7 +143,6 @@ impl OutputBuiltinRunner { pub fn set_state(&mut self, new_state: OutputBuiltinState) { self.base = new_state.base; - self.base_offset = new_state.base_offset; self.pages = new_state.pages; self.attributes = new_state.attributes; } @@ -155,7 +150,6 @@ impl OutputBuiltinRunner { pub fn get_state(&mut self) -> OutputBuiltinState { OutputBuiltinState { base: self.base, - base_offset: self.base_offset, pages: self.pages.clone(), attributes: self.attributes.clone(), } @@ -174,7 +168,7 @@ impl OutputBuiltinRunner { self.pages.insert( page_id, PublicMemoryPage { - start: page_start.offset - self.base_offset, + start: page_start.offset, size: page_size, }, ); @@ -209,6 +203,7 @@ impl Default for OutputBuiltinRunner { mod tests { use super::*; use crate::relocatable; + use crate::stdlib::collections::HashMap; use crate::{ utils::test_utils::*, @@ -476,8 +471,8 @@ mod tests { assert_eq!( builtin.get_additional_data(), BuiltinAdditionalData::Output(OutputBuiltinAdditionalData { - pages: BTreeMap::default(), - attributes: BTreeMap::default() + pages: HashMap::default(), + attributes: HashMap::default() }) ) } @@ -498,9 +493,8 @@ mod tests { let new_state = OutputBuiltinState { base: 10, - base_offset: 0, - pages: BTreeMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), - attributes: BTreeMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), + pages: HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), + attributes: HashMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), }; builtin.set_state(new_state.clone()); @@ -516,19 +510,17 @@ mod tests { fn new_state() { let mut builtin = OutputBuiltinRunner { base: 10, - base_offset: 0, - pages: BTreeMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), - attributes: BTreeMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), + pages: HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), + attributes: HashMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), stop_ptr: Some(10), included: true, }; let new_base = 11; let new_included = false; - builtin.new_state(new_base, 2, new_included); + builtin.new_state(new_base, new_included); assert_eq!(builtin.base, new_base); - assert_eq!(builtin.base_offset, 2); assert!(builtin.pages.is_empty()); assert!(builtin.attributes.is_empty()); assert_eq!(builtin.stop_ptr, None); @@ -552,7 +544,7 @@ mod tests { assert_eq!( builtin.pages, - BTreeMap::from([(1, PublicMemoryPage { start: 0, size: 3 }),]) + HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 }),]) ) } @@ -579,7 +571,7 @@ mod tests { let values = vec![0, 12, 30]; builtin.add_attribute(name.clone(), values.clone()); - assert_eq!(builtin.attributes, BTreeMap::from([(name, values)])); + assert_eq!(builtin.attributes, HashMap::from([(name, values)])); } #[test] @@ -622,16 +614,14 @@ mod tests { fn get_and_extend_additional_data() { let builtin_a = OutputBuiltinRunner { base: 0, - base_offset: 0, - pages: BTreeMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), - attributes: BTreeMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), + pages: HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), + attributes: HashMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), stop_ptr: None, included: true, }; let additional_data = builtin_a.get_additional_data(); let mut builtin_b = OutputBuiltinRunner { base: 0, - base_offset: 0, pages: Default::default(), attributes: Default::default(), stop_ptr: None, diff --git a/vm/src/vm/runners/builtin_runner/signature.rs b/vm/src/vm/runners/builtin_runner/signature.rs index bdd7a95a0c..8f2bda7510 100644 --- a/vm/src/vm/runners/builtin_runner/signature.rs +++ b/vm/src/vm/runners/builtin_runner/signature.rs @@ -1,11 +1,6 @@ use crate::air_private_input::{PrivateInput, PrivateInputSignature, SignatureInput}; use crate::math_utils::div_mod; -use crate::stdlib::{ - cell::RefCell, - collections::{BTreeMap, HashMap}, - prelude::*, - rc::Rc, -}; +use crate::stdlib::{cell::RefCell, collections::HashMap, prelude::*, rc::Rc}; use crate::types::builtin_name::BuiltinName; use crate::types::instance_definitions::ecdsa_instance_def::CELLS_PER_SIGNATURE; @@ -167,7 +162,7 @@ impl SignatureBuiltinRunner { pub fn get_additional_data(&self) -> BuiltinAdditionalData { // Convert signatures to Felt tuple - let signatures: BTreeMap = self + let signatures: HashMap = self .signatures .borrow() .iter() @@ -528,7 +523,7 @@ mod tests { }, )]); builtin.signatures = Rc::new(RefCell::new(signatures)); - let signatures = BTreeMap::from([( + let signatures = HashMap::from([( Relocatable::from((4, 0)), (felt_str!("45678"), felt_str!("1239")), )]); diff --git a/vm/src/vm/runners/cairo_pie.rs b/vm/src/vm/runners/cairo_pie.rs index a545ef2237..b839be06f3 100644 --- a/vm/src/vm/runners/cairo_pie.rs +++ b/vm/src/vm/runners/cairo_pie.rs @@ -3,10 +3,7 @@ use crate::stdlib::prelude::{String, Vec}; use crate::types::builtin_name::BuiltinName; use crate::vm::errors::cairo_pie_errors::CairoPieValidationError; use crate::{ - stdlib::{ - collections::{BTreeMap, HashMap}, - prelude::*, - }, + stdlib::{collections::HashMap, prelude::*}, types::relocatable::{MaybeRelocatable, Relocatable}, Felt252, }; @@ -75,8 +72,8 @@ impl From<&Vec> for PublicMemoryPage { } // HashMap value based on starknet/core/os/output.cairo usage -pub type Attributes = BTreeMap>; -pub type Pages = BTreeMap; +pub type Attributes = HashMap>; +pub type Pages = HashMap; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct OutputBuiltinAdditionalData { @@ -96,7 +93,7 @@ pub enum BuiltinAdditionalData { Output(OutputBuiltinAdditionalData), // Signatures are composed of (r, s) tuples #[serde(with = "serde_impl::signature_additional_data")] - Signature(BTreeMap), + Signature(HashMap), None, } @@ -128,7 +125,7 @@ impl PartialEq for BuiltinAdditionalData { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct CairoPieAdditionalData( #[serde(with = "crate::types::builtin_name::serde_generic_map_impl")] - pub BTreeMap, + pub HashMap, ); #[derive(Serialize, Clone, Debug, PartialEq, Eq)] @@ -148,7 +145,7 @@ pub struct CairoPieMetadata { pub ret_fp_segment: SegmentInfo, pub ret_pc_segment: SegmentInfo, #[serde(serialize_with = "serde_impl::serialize_builtin_segments")] - pub builtin_segments: BTreeMap, + pub builtin_segments: HashMap, pub extra_segments: Vec, } @@ -324,9 +321,8 @@ impl CairoPie { let file = File::create(file_path)?; let mut zip_writer = ZipWriter::new(file); - let options = zip::write::FileOptions::default() - .compression_method(zip::CompressionMethod::Deflated) - .large_file(true); + let options = + zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated); zip_writer.start_file("version.json", options)?; serde_json::to_writer(&mut zip_writer, &self.version)?; @@ -439,7 +435,7 @@ impl CairoPie { } pub(super) mod serde_impl { - use crate::stdlib::collections::{BTreeMap, HashMap}; + use crate::stdlib::collections::HashMap; use crate::types::builtin_name::BuiltinName; use num_traits::Num; @@ -765,7 +761,7 @@ pub(super) mod serde_impl { use super::*; pub fn serialize( - values: &BTreeMap, + values: &HashMap, serializer: S, ) -> Result where @@ -787,30 +783,30 @@ pub(super) mod serde_impl { pub fn deserialize<'de, D>( d: D, - ) -> Result, D::Error> + ) -> Result, D::Error> where D: Deserializer<'de>, { let number_map = Vec::<((Number, Number), (Number, Number))>::deserialize(d)?; - number_map - .into_iter() - .map(|((index, offset), (r, s))| { - let idx = index + let mut res = HashMap::with_capacity(number_map.len()); + for ((index, offset), (r, s)) in number_map.into_iter() { + let addr = Relocatable::from(( + index .as_u64() .ok_or_else(|| D::Error::custom("Invalid address"))? - as isize; - let off = offset + as isize, + offset .as_u64() .ok_or_else(|| D::Error::custom("Invalid address"))? - as usize; - let addr = Relocatable::from((idx, off)); - let r = Felt252::from_dec_str(r.as_str()) - .map_err(|_| D::Error::custom("Invalid Felt252 value"))?; - let s = Felt252::from_dec_str(s.as_str()) - .map_err(|_| D::Error::custom("Invalid Felt252 value"))?; - Ok((addr, (r, s))) - }) - .collect::, D::Error>>() + as usize, + )); + let r = Felt252::from_dec_str(r.as_str()) + .map_err(|_| D::Error::custom("Invalid Felt252 value"))?; + let s = Felt252::from_dec_str(s.as_str()) + .map_err(|_| D::Error::custom("Invalid Felt252 value"))?; + res.insert(addr, (r, s)); + } + Ok(res) } } @@ -844,7 +840,7 @@ pub(super) mod serde_impl { } pub fn serialize_builtin_segments( - values: &BTreeMap, + values: &HashMap, serializer: S, ) -> Result where diff --git a/vm/src/vm/runners/cairo_runner.rs b/vm/src/vm/runners/cairo_runner.rs index b9ee5701a4..a54cff333d 100644 --- a/vm/src/vm/runners/cairo_runner.rs +++ b/vm/src/vm/runners/cairo_runner.rs @@ -1,4 +1,3 @@ -use crate::vm::trace::trace_entry::TraceEntry; use crate::{ air_private_input::AirPrivateInput, air_public_input::{PublicInput, PublicInputError}, @@ -12,7 +11,7 @@ use crate::{ types::{builtin_name::BuiltinName, layout::CairoLayoutParams, layout_name::LayoutName}, vm::{ runners::builtin_runner::SegmentArenaBuiltinRunner, - trace::trace_entry::{relocate_trace_register, RelocatedTraceEntry}, + trace::trace_entry::{relocate_trace_register, RelocatedTraceEntry, TraceEntry}, }, Felt252, }; @@ -191,8 +190,6 @@ impl CairoRunner { LayoutName::all_cairo => CairoLayout::all_cairo_instance(), LayoutName::all_cairo_stwo => CairoLayout::all_cairo_stwo_instance(), LayoutName::all_solidity => CairoLayout::all_solidity_instance(), - LayoutName::perpetual => CairoLayout::perpetual_instance(), - LayoutName::dex_with_bitwise => CairoLayout::dex_with_bitwise_instance(), LayoutName::dynamic => { let params = dynamic_layout_params.ok_or(RunnerError::MissingDynamicLayoutParams)?; @@ -892,14 +889,13 @@ impl CairoRunner { disable_trace_padding: bool, disable_finalize_all: bool, hint_processor: &mut dyn HintProcessor, - proof_mode: bool, ) -> Result<(), VirtualMachineError> { if self.run_ended { return Err(RunnerError::EndRunCalledTwice.into()); } self.vm.segments.memory.relocate_memory()?; - self.vm.end_run(&self.exec_scopes, proof_mode)?; + self.vm.end_run(&self.exec_scopes)?; if disable_finalize_all { return Ok(()); @@ -985,9 +981,9 @@ impl CairoRunner { Ok(()) } - pub fn relocate(&mut self, relocate_mem: bool, relocate_trace: bool) -> Result<(), TraceError> { + pub fn relocate(&mut self, relocate_mem: bool) -> Result<(), TraceError> { self.vm.segments.compute_effective_sizes(); - if !relocate_mem && (self.vm.trace.is_none() || !relocate_trace) { + if !relocate_mem && self.vm.trace.is_none() { return Ok(()); } // relocate_segments can fail if compute_effective_sizes is not called before. @@ -1003,39 +999,25 @@ impl CairoRunner { return Err(TraceError::MemoryError(memory_error)); } } - if self.vm.trace.is_some() && relocate_trace { + if self.vm.trace.is_some() { self.relocate_trace(&relocation_table)?; } self.vm.relocation_table = Some(relocation_table); Ok(()) } - /// Returns a tuple of builtin base's segment index and stop_ptr offset - /// Aka the builtin's segment number and its maximum offset + // Returns a map from builtin base's segment index to stop_ptr offset + // Aka the builtin's segment number and its maximum offset pub fn get_builtin_segments_info(&self) -> Result, RunnerError> { - let proof_mode = self.is_proof_mode(); let mut builtin_segment_info = Vec::new(); for builtin in &self.vm.builtin_runners { let (index, stop_ptr) = builtin.get_memory_segment_addresses(); - match (proof_mode, stop_ptr) { - // Segment present (same handling in both modes). - (_, Some(sp)) => builtin_segment_info.push((index, sp)), - - // If non proof-mode, only builtins in the program are present and they must - // point to a segment (so `stop_ptr` must be set). Throw an error if not. - (false, None) => { - return Err(RunnerError::NoStopPointer(Box::new( - builtin.name().to_owned(), - ))); - } - - // In proof‐mode there are builtin runners for all builtins in the layout, but only - // the ones that are in the program point to a segment (so `stop_ptr` is set). - // Only collect those and silently ignore the rest. - (true, None) => {} - } + builtin_segment_info.push(( + index, + stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))?, + )); } Ok(builtin_segment_info) @@ -1073,7 +1055,7 @@ impl CairoRunner { .unwrap_or(self.vm.current_step); let n_memory_holes = self.get_memory_holes()?; - let mut builtin_instance_counter = BTreeMap::new(); + let mut builtin_instance_counter = HashMap::new(); for builtin_runner in &self.vm.builtin_runners { builtin_instance_counter.insert( builtin_runner.name(), @@ -1172,7 +1154,7 @@ impl CairoRunner { self.run_until_pc(end, hint_processor) .map_err(|err| VmException::from_vm_error(self, err))?; - self.end_run(true, false, hint_processor, self.is_proof_mode())?; + self.end_run(true, false, hint_processor)?; if verify_secure { verify_secure_runner(self, false, program_segment_size)?; @@ -1432,7 +1414,7 @@ impl CairoRunner { execution_segment: (execution_base.segment_index, execution_size).into(), ret_fp_segment: (return_fp.segment_index, 0).into(), ret_pc_segment: (return_pc.segment_index, 0).into(), - builtin_segments: builtin_segments.into_iter().collect(), + builtin_segments, extra_segments, }; @@ -1506,38 +1488,79 @@ impl CairoRunner { .collect() } - /// Returns a reference to the relocatable trace. - pub fn get_relocatable_trace(&self) -> Result<&[TraceEntry], RunnerError> { - self.vm + /// Collects relevant information for the prover from the runner, including the + /// relocatable form of the trace, memory, public memory, and built-ins. + pub fn get_prover_input_info(&self) -> Result { + let relocatable_trace = self + .vm .trace - .as_deref() - .ok_or(RunnerError::Trace(TraceError::TraceNotEnabled)) - } + .as_ref() + .ok_or(RunnerError::Trace(TraceError::TraceNotEnabled))? + .clone(); - /// Returns a vector of segments, where each segment is a vector of Option values, representing the relocatble memory values. - pub fn get_relocatable_memory(&self) -> Vec>> { - self.vm + let relocatable_memory = self + .vm .segments .memory .data .iter() .map(|segment| segment.iter().map(|cell| cell.get_value()).collect()) - .collect() - } + .collect(); - /// Returns a map from the builtin segment index into its name. - pub fn get_builtin_segments(&self) -> BTreeMap { - self.vm + let public_memory_offsets = self + .vm + .segments + .public_memory_offsets + .iter() + .map(|(segment, offset_page)| { + let offsets: Vec = offset_page.iter().map(|(offset, _)| *offset).collect(); + (*segment, offsets) + }) + .collect(); + + let builtins_segments: BTreeMap = self + .vm .builtin_runners .iter() + .filter(|builtin| { + // Those segments are not treated as builtins by the prover. + !matches!( + builtin, + BuiltinRunner::SegmentArena(_) | BuiltinRunner::Output(_) + ) + }) .map(|builtin| { let (index, _) = builtin.get_memory_segment_addresses(); (index, builtin.name()) }) - .collect() + .collect(); + + Ok(ProverInputInfo { + relocatable_trace, + relocatable_memory, + public_memory_offsets, + builtins_segments, + }) } } +//* ---------------------- +//* ProverInputInfo +//* ---------------------- +/// This struct contains all relevant data for the prover. +/// All addresses are relocatable. +#[derive(Deserialize, Serialize)] +pub struct ProverInputInfo { + /// A vector of trace entries, i.e. pc, ap, fp, where pc is relocatable. + pub relocatable_trace: Vec, + /// A vector of segments, where each segment is a vector of maybe relocatable values or holes (`None`). + pub relocatable_memory: Vec>>, + /// A map from segment index to a vector of offsets within the segment, representing the public memory addresses. + pub public_memory_offsets: BTreeMap>, + /// A map from the builtin segment index into its name. + pub builtins_segments: BTreeMap, +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct SegmentInfo { pub index: isize, @@ -1553,7 +1576,7 @@ pub struct ExecutionResources { pub n_steps: usize, pub n_memory_holes: usize, #[serde(with = "crate::types::builtin_name::serde_generic_map_impl")] - pub builtin_instance_counter: BTreeMap, + pub builtin_instance_counter: HashMap, } /// Returns a copy of the execution resources where all the builtins with a usage counter @@ -1642,8 +1665,6 @@ mod tests { use crate::air_private_input::{PrivateInput, PrivateInputSignature, SignatureInput}; use crate::cairo_run::{cairo_run, CairoRunConfig}; use crate::stdlib::collections::{HashMap, HashSet}; - use crate::types::instance_definitions::bitwise_instance_def::CELLS_PER_BITWISE; - use crate::types::instance_definitions::keccak_instance_def::CELLS_PER_KECCAK; use crate::vm::vm_memory::memory::MemoryCell; use crate::felt_hex; @@ -3830,7 +3851,7 @@ mod tests { cairo_runner.run_ended = true; assert_matches!( - cairo_runner.end_run(true, false, &mut hint_processor, false), + cairo_runner.end_run(true, false, &mut hint_processor), Err(VirtualMachineError::RunnerError( RunnerError::EndRunCalledTwice )) @@ -3846,14 +3867,14 @@ mod tests { let mut cairo_runner = cairo_runner!(program); assert_matches!( - cairo_runner.end_run(true, false, &mut hint_processor, false), + cairo_runner.end_run(true, false, &mut hint_processor), Ok(()) ); cairo_runner.run_ended = false; cairo_runner.relocated_memory.clear(); assert_matches!( - cairo_runner.end_run(true, true, &mut hint_processor, false), + cairo_runner.end_run(true, true, &mut hint_processor), Ok(()) ); assert!(!cairo_runner.run_ended); @@ -3867,16 +3888,16 @@ mod tests { Some("main"), ) .unwrap(); - let proof_mode = true; + let mut hint_processor = BuiltinHintProcessor::new_empty(); - let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, proof_mode, true); + let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true, true); let end = cairo_runner.initialize(false).unwrap(); cairo_runner .run_until_pc(end, &mut hint_processor) .expect("Call to `CairoRunner::run_until_pc()` failed."); assert_matches!( - cairo_runner.end_run(false, false, &mut hint_processor, proof_mode), + cairo_runner.end_run(false, false, &mut hint_processor), Ok(()) ); } @@ -3906,49 +3927,6 @@ mod tests { ); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_builtin_segments_info_non_proof_mode() { - let program_data = - include_bytes!("../../../../cairo_programs/proof_programs/assert_nn.json"); - let cairo_run_config = CairoRunConfig { - entrypoint: "main", - trace_enabled: false, - relocate_mem: false, - layout: LayoutName::small, - proof_mode: false, - secure_run: Some(true), - ..Default::default() - }; - let mut hint_executor = BuiltinHintProcessor::new_empty(); - let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap(); - // Only the range_check builtin is used in this program, and in non-proof mode, it will - // be the first and only builtin segment initialized (and used). - assert_eq!(runner.get_builtin_segments_info(), Ok(vec![(2, 6)])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_builtin_segments_info_proof_mode() { - let program_data = - include_bytes!("../../../../cairo_programs/proof_programs/assert_nn.json"); - let cairo_run_config = CairoRunConfig { - entrypoint: "main", - trace_enabled: false, - relocate_mem: false, - layout: LayoutName::small, - proof_mode: true, - secure_run: Some(true), - ..Default::default() - }; - let mut hint_executor = BuiltinHintProcessor::new_empty(); - let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap(); - // Only the range_check builtin is used in this program, and in proof mode, it will - // be the first and only builtin segment used, but initialized after the other builtins - // in the layout. - assert_eq!(runner.get_builtin_segments_info(), Ok(vec![(4, 6)])); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_execution_resources_trace_not_enabled() { @@ -3963,7 +3941,7 @@ mod tests { Ok(ExecutionResources { n_steps: 10, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::new(), + builtin_instance_counter: HashMap::new(), }), ); } @@ -4018,7 +3996,7 @@ mod tests { Ok(ExecutionResources { n_steps: 10, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::new(), + builtin_instance_counter: HashMap::new(), }), ); } @@ -4043,7 +4021,7 @@ mod tests { Ok(ExecutionResources { n_steps: 10, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([(BuiltinName::output, 4)]), + builtin_instance_counter: HashMap::from([(BuiltinName::output, 4)]), }), ); } @@ -4991,7 +4969,7 @@ mod tests { } fn setup_execution_resources() -> (ExecutionResources, ExecutionResources) { - let mut builtin_instance_counter: BTreeMap = BTreeMap::new(); + let mut builtin_instance_counter: HashMap = HashMap::new(); builtin_instance_counter.insert(BuiltinName::output, 8); let execution_resources_1 = ExecutionResources { @@ -5182,7 +5160,7 @@ mod tests { let execution_resources_1 = ExecutionResources { n_steps: 800, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([ + builtin_instance_counter: HashMap::from([ (BuiltinName::pedersen, 7), (BuiltinName::range_check, 16), ]), @@ -5193,7 +5171,7 @@ mod tests { ExecutionResources { n_steps: 1600, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([ + builtin_instance_counter: HashMap::from([ (BuiltinName::pedersen, 14), (BuiltinName::range_check, 32) ]) @@ -5203,7 +5181,7 @@ mod tests { let execution_resources_2 = ExecutionResources { n_steps: 545, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([(BuiltinName::range_check, 17)]), + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 17)]), }; assert_eq!( @@ -5211,14 +5189,14 @@ mod tests { ExecutionResources { n_steps: 4360, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::from([(BuiltinName::range_check, 136)]) + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 136)]) } ); let execution_resources_3 = ExecutionResources { n_steps: 42, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::new(), + builtin_instance_counter: HashMap::new(), }; assert_eq!( @@ -5226,7 +5204,7 @@ mod tests { ExecutionResources { n_steps: 756, n_memory_holes: 0, - builtin_instance_counter: BTreeMap::new() + builtin_instance_counter: HashMap::new() } ); } @@ -5542,7 +5520,7 @@ mod tests { } #[test] - fn test_get_relocatable_trace() { + fn get_prover_input_info() { let program_content = include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json"); let runner = crate::cairo_run::cairo_run( @@ -5555,7 +5533,7 @@ mod tests { &mut BuiltinHintProcessor::new_empty(), ) .unwrap(); - let relocatable_trace = runner.get_relocatable_trace().unwrap(); + let prover_info = runner.get_prover_input_info().unwrap(); let expected_trace = vec![ TraceEntry { pc: (0, 15).into(), @@ -5613,117 +5591,46 @@ mod tests { fp: 3, }, ]; - assert_eq!(relocatable_trace, expected_trace); - } - - #[test] - fn test_get_relocatable_memory() { - let program_content = - include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json"); - let runner = crate::cairo_run::cairo_run( - program_content, - &CairoRunConfig { - layout: LayoutName::all_cairo, - ..Default::default() - }, - &mut BuiltinHintProcessor::new_empty(), - ) - .unwrap(); - let relocatable_memory = runner.get_relocatable_memory(); - let expected_in_memory_0_3 = MaybeRelocatable::Int(13.into()); let expected_in_memory_1_0 = MaybeRelocatable::RelocatableValue(Relocatable { segment_index: 2, offset: 0, }); - - assert_eq!(relocatable_memory[0][3], Some(expected_in_memory_0_3)); - assert_eq!(relocatable_memory[1][0], Some(expected_in_memory_1_0)); + assert_eq!(prover_info.relocatable_trace, expected_trace); + assert_eq!( + prover_info.relocatable_memory[0][3], + Some(expected_in_memory_0_3) + ); + assert_eq!( + prover_info.relocatable_memory[1][0], + Some(expected_in_memory_1_0) + ); + assert!(prover_info.public_memory_offsets.is_empty()); + assert_eq!( + prover_info.builtins_segments, + BTreeMap::from([(2, BuiltinName::ecdsa)]) + ); } #[test] - fn test_get_builtin_segments() { + fn test_output_not_builtin_segment() { let program_content = - include_bytes!("../../../../cairo_programs/proof_programs/bitwise_builtin_test.json"); + include_bytes!("../../../../cairo_programs/proof_programs/split_felt.json"); let runner = crate::cairo_run::cairo_run( program_content, &CairoRunConfig { + trace_enabled: true, layout: LayoutName::all_cairo, ..Default::default() }, &mut BuiltinHintProcessor::new_empty(), ) .unwrap(); - let builtin_segments = runner.get_builtin_segments(); - - assert_eq!(builtin_segments[&2], BuiltinName::bitwise); - } - - #[test] - fn end_run_fill_builtins() { - let program = Program::from_bytes( - include_bytes!("../../../../cairo_programs/proof_programs/keccak_uint256.json"), - Some("main"), - ) - .unwrap(); - - let mut hint_processor = BuiltinHintProcessor::new_empty(); - let proof_mode = true; - let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, proof_mode, true); - - let end = cairo_runner.initialize(false).unwrap(); - cairo_runner - .run_until_pc(end, &mut hint_processor) - .expect("Call to `CairoRunner::run_until_pc()` failed."); - - // Before end run - assert!(cairo_runner.vm.segments.memory.data[6].len() as u32 % CELLS_PER_BITWISE != 0); - assert!(cairo_runner.vm.segments.memory.data[8].len() as u32 % CELLS_PER_KECCAK != 0); - - assert_matches!( - cairo_runner.end_run(false, false, &mut hint_processor, proof_mode), - Ok(()) - ); - - // After end run - assert!(cairo_runner.vm.segments.memory.data[6].len() as u32 % CELLS_PER_BITWISE == 0); - assert!(cairo_runner.vm.segments.memory.data[8].len() as u32 % CELLS_PER_KECCAK == 0); - assert!(cairo_runner.vm.segments.memory.data[6].last().is_some()); - assert!(cairo_runner.vm.segments.memory.data[8].last().is_some()); - - let builtin_segments = cairo_runner.get_builtin_segments(); - assert!(builtin_segments.get(&6) == Some(&BuiltinName::bitwise)); - assert!(builtin_segments.get(&8) == Some(&BuiltinName::keccak)); - } - - #[test] - fn end_run_fill_middle_holes() { - let program = Program::from_bytes( - include_bytes!("../../../../cairo_programs/proof_programs/poseidon_builtin_hole.json"), - Some("main"), - ) - .unwrap(); - - let mut hint_processor = BuiltinHintProcessor::new_empty(); - let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true, true); - - let end = cairo_runner.initialize(false).unwrap(); - cairo_runner - .run_until_pc(end, &mut hint_processor) - .expect("Call to `CairoRunner::run_until_pc()` failed."); - - // Before end run - // In 'poseidon_builtin_hole.cairo' we are not accessing result.s1, so there is a hole in that builtin segment. - assert!(cairo_runner.vm.segments.memory.data[9][4].is_none()); - assert_matches!( - cairo_runner.end_run(false, false, &mut hint_processor, true), - Ok(()) - ); - - // After end run - assert!(!cairo_runner.vm.segments.memory.data[9][4].is_none()); + let prover_info = runner.get_prover_input_info().unwrap(); - let builtin_segments = cairo_runner.get_builtin_segments(); - assert!(builtin_segments.get(&9) == Some(&BuiltinName::poseidon)); + assert!(!prover_info + .builtins_segments + .values() + .any(|v| *v == BuiltinName::output)); } } diff --git a/vm/src/vm/security.rs b/vm/src/vm/security.rs index 08abc03198..0dfdda8f23 100644 --- a/vm/src/vm/security.rs +++ b/vm/src/vm/security.rs @@ -150,9 +150,7 @@ mod test { runner.initialize(false).unwrap(); // runner.vm.segments.compute_effective_sizes(); let mut hint_processor = BuiltinHintProcessor::new_empty(); - runner - .end_run(false, false, &mut hint_processor, false) - .unwrap(); + runner.end_run(false, false, &mut hint_processor).unwrap(); // At the end of the run, the ret_fp should be the base of the new ret_fp segment we added // to the stack at the start of the run. runner.vm.run_context.fp = 0; @@ -217,9 +215,7 @@ mod test { runner.initialize(false).unwrap(); let mut hint_processor = BuiltinHintProcessor::new_empty(); - runner - .end_run(false, false, &mut hint_processor, false) - .unwrap(); + runner.end_run(false, false, &mut hint_processor).unwrap(); runner.vm.builtin_runners[0].set_stop_ptr(1); // Adding ((1, 1), (3, 0)) to the memory segment to simulate the ret_fp_segment. runner.vm.segments.memory = memory![((2, 0), 1), ((1, 1), (3, 0))]; diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index fcd8f9dac9..2adcf47b09 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -3,7 +3,6 @@ use crate::stdlib::{any::Any, borrow::Cow, collections::HashMap, prelude::*}; use crate::types::builtin_name::BuiltinName; #[cfg(feature = "extensive_hints")] use crate::types::program::HintRange; -use crate::vm::vm_memory::memory::MemoryCell; use crate::{ hint_processor::{ builtin_hint_processor::blake2s_hash::blake2s_compress, @@ -749,66 +748,6 @@ impl VirtualMachine { )) } - /// Updates the memory with missing built-in deductions and verifies the existing ones. - pub fn complete_builtin_auto_deductions(&mut self) -> Result<(), VirtualMachineError> { - for builtin in self.builtin_runners.iter() { - let builtin_index: usize = builtin.base(); - - // Output and SegmentArena do not need to be auto-deduced in the memory. - if matches!( - builtin, - BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) - ) { - continue; - } - - // Extend the segment size to a multiple of the number of cells per instance. - let current_builtin_segment = &mut self.segments.memory.data[builtin_index]; - let len = current_builtin_segment.len(); - let cells_per_instance = builtin.cells_per_instance() as usize; - current_builtin_segment.resize( - len.div_ceil(cells_per_instance) * cells_per_instance, - MemoryCell::NONE, - ); - - let mut missing_values: Vec<(usize, MemoryCell)> = vec![]; - - for (offset, cell) in self.segments.memory.data[builtin_index].iter().enumerate() { - if let Some(deduced_memory_cell) = builtin - .deduce_memory_cell( - Relocatable::from((builtin_index as isize, offset)), - &self.segments.memory, - ) - .map_err(VirtualMachineError::RunnerError)? - { - match cell.get_value() { - Some(memory_value) => { - // Checks that the value in the memory is correct. - if memory_value != deduced_memory_cell { - return Err(VirtualMachineError::InconsistentAutoDeduction( - Box::new(( - builtin.name(), - deduced_memory_cell, - Some(memory_value), - )), - )); - } - } - None => { - // Collect value to be stored in memory. - missing_values.push((offset, MemoryCell::new(deduced_memory_cell))); - } - } - } - } - - for (offset, value) in missing_values { - self.segments.memory.data[builtin_index][offset] = value; - } - } - Ok(()) - } - ///Makes sure that all assigned memory cells are consistent with their auto deduction rules. pub fn verify_auto_deductions(&self) -> Result<(), VirtualMachineError> { for builtin in self.builtin_runners.iter() { @@ -859,16 +798,8 @@ impl VirtualMachine { Ok(()) } - pub fn end_run( - &mut self, - exec_scopes: &ExecutionScopes, - proof_mode: bool, - ) -> Result<(), VirtualMachineError> { - if proof_mode { - self.complete_builtin_auto_deductions()?; - } else { - self.verify_auto_deductions()?; - } + pub fn end_run(&mut self, exec_scopes: &ExecutionScopes) -> Result<(), VirtualMachineError> { + self.verify_auto_deductions()?; self.run_finished = true; match exec_scopes.data.len() { 1 => Ok(()), @@ -4629,7 +4560,7 @@ mod tests { scopes.enter_scope(HashMap::new()); assert_matches!( - vm.end_run(scopes, false), + vm.end_run(scopes), Err(VirtualMachineError::MainScopeError( ExecScopeError::NoScopeError ))