From 4baa387be899dd4472503f6c665c7f3685882cf6 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Mon, 17 Apr 2023 10:19:23 -0300 Subject: [PATCH] perf!: refactor `Program` to reduce `clone` time Extract most fields (see the code for the details) in `Program` into a new `SharedProgramData` structure, then add a field `shared_program_data: Arc` to `Program`, so cloning doesn't deep copy them. These were selected based on how often the runner needed to access them directly, as the indirection and heap access proved to come with a runtime cost. Frequently accessed fields are still copied because of that. The break comes from hiding some symbols (as they were moved to the new structure), but those shouldn't have been exposed in the first place, so I expect no breakage for real-world programs (cue Hyrum's law). --- CHANGELOG.md | 4 + src/serde/deserialize_program.rs | 60 +++++++-------- src/types/program.rs | 125 ++++++++++++++++++------------- src/utils.rs | 96 +++++++++++++++++------- src/vm/errors/vm_exception.rs | 13 +++- src/vm/runners/cairo_runner.rs | 79 ++++++++++++------- src/vm/security.rs | 3 +- 7 files changed, 235 insertions(+), 145 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9547c94333..f645f40414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ #### Upcoming Changes +<<<<<<< HEAD +* BREAKING CHANGE: refactor `Program` to optimize `Program::clone` [#999](https://github.com/lambdaclass/cairo-rs/pull/999) + * Breaking change: many fields that were (unnecessarily) public become hidden by the refactor. + * BREAKING CHANGE: Add _builtin suffix to builtin names e.g.: output -> output_builtin [#1005](https://github.com/lambdaclass/cairo-rs/pull/1005) * Implement hint on uint384_extension lib [#983](https://github.com/lambdaclass/cairo-rs/pull/983) diff --git a/src/serde/deserialize_program.rs b/src/serde/deserialize_program.rs index 51d8d69829..95b3204d96 100644 --- a/src/serde/deserialize_program.rs +++ b/src/serde/deserialize_program.rs @@ -1,9 +1,11 @@ -use crate::stdlib::{collections::HashMap, fmt, prelude::*}; +use crate::stdlib::{collections::HashMap, fmt, prelude::*, sync::Arc}; use crate::{ serde::deserialize_utils, types::{ - errors::program_errors::ProgramError, instruction::Register, program::Program, + errors::program_errors::ProgramError, + instruction::Register, + program::{Program, SharedProgramData}, relocatable::MaybeRelocatable, }, vm::runners::builtin_runner::{ @@ -373,10 +375,24 @@ pub fn parse_program_json( None => None, }; - Ok(Program { + let shared_program_data = SharedProgramData { builtins: program_json.builtins, - prime: PRIME_STR.to_string(), data: program_json.data, + hints: program_json.hints, + main: entrypoint_pc, + start, + end, + error_message_attributes: program_json + .attributes + .into_iter() + .filter(|attr| attr.name == "error_message") + .collect(), + instruction_locations: program_json + .debug_info + .map(|debug_info| debug_info.instruction_locations), + }; + Ok(Program { + shared_program_data: Arc::new(shared_program_data), constants: { let mut constants = HashMap::new(); for (key, value) in program_json.identifiers.iter() { @@ -391,20 +407,8 @@ pub fn parse_program_json( constants }, - main: entrypoint_pc, - start, - end, - hints: program_json.hints, reference_manager: program_json.reference_manager, identifiers: program_json.identifiers, - error_message_attributes: program_json - .attributes - .into_iter() - .filter(|attr| attr.name == "error_message") - .collect(), - instruction_locations: program_json - .debug_info - .map(|debug_info| debug_info.instruction_locations), }) } @@ -805,14 +809,10 @@ mod tests { }], ); - assert_eq!( - program.prime, - "0x800000000000011000000000000000000000000000000000000000000000001".to_string() - ); - assert_eq!(program.builtins, builtins); - assert_eq!(program.data, data); - assert_eq!(program.main, Some(0)); - assert_eq!(program.hints, hints); + assert_eq!(program.shared_program_data.builtins, builtins); + assert_eq!(program.shared_program_data.data, data); + assert_eq!(program.shared_program_data.main, Some(0)); + assert_eq!(program.shared_program_data.hints, hints); } /// Deserialize a program without an entrypoint. @@ -867,14 +867,10 @@ mod tests { }], ); - assert_eq!( - program.prime, - "0x800000000000011000000000000000000000000000000000000000000000001".to_string() - ); - assert_eq!(program.builtins, builtins); - assert_eq!(program.data, data); - assert_eq!(program.main, None); - assert_eq!(program.hints, hints); + assert_eq!(program.shared_program_data.builtins, builtins); + assert_eq!(program.shared_program_data.data, data); + assert_eq!(program.shared_program_data.main, None); + assert_eq!(program.shared_program_data.hints, hints); } #[test] diff --git a/src/types/program.rs b/src/types/program.rs index 75b9f3de0e..858eefcd1c 100644 --- a/src/types/program.rs +++ b/src/types/program.rs @@ -1,4 +1,4 @@ -use crate::stdlib::{collections::HashMap, prelude::*}; +use crate::stdlib::{collections::HashMap, prelude::*, sync::Arc}; use crate::{ serde::deserialize_program::{ @@ -7,34 +7,57 @@ use crate::{ }, types::{errors::program_errors::ProgramError, relocatable::MaybeRelocatable}, }; -use felt::{Felt252, PRIME_STR}; -use serde::{Deserialize, Serialize}; +use felt::Felt252; #[cfg(feature = "std")] use std::path::Path; -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Program { +// NOTE: `Program` has been split in two containing some data that will be deep-copied +// and some that will be allocated on the heap inside an `Arc<_>`. +// This is because it has been reported that cloning the whole structure when creating +// a `CairoRunner` becomes a bottleneck, but the following solutions were tried and +// discarded: +// - Store only a reference in `CairoRunner` rather than cloning; this doesn't work +// because then we need to introduce explicit lifetimes, which broke `cairo-rs-py` +// since PyO3 doesn't support Python objects containing structures with lifetimes. +// - Directly pass an `Arc` to `CairoRunner::new()` and simply copy that: +// there was a prohibitive performance hit of 10-15% when doing so, most likely +// either because of branch mispredictions or the extra level of indirection going +// through a random location on the heap rather than the likely-to-be-cached spot +// on the stack. +// +// So, the compromise was to identify which data was less used and avoid copying that, +// using `Arc<_>`, while the most accessed fields remain on the stack for the main +// loop to access. The fields in `SharedProgramData` are either preprocessed and +// copied explicitly (_in addition_ to the clone of `Program`) or are used only in +// exceptional circumstances, such as when reconstructing a backtrace on execution +// failures. +// Fields in `Program` (other than `SharedProgramData` itself) are used by the main logic. +#[derive(Clone, Default, Debug, PartialEq, Eq)] +pub(crate) struct SharedProgramData { pub builtins: Vec, - pub prime: String, pub data: Vec, - pub constants: HashMap, + pub hints: HashMap>, pub main: Option, //start and end labels will only be used in proof-mode pub start: Option, pub end: Option, - pub hints: HashMap>, - pub reference_manager: ReferenceManager, - pub identifiers: HashMap, pub error_message_attributes: Vec, pub instruction_locations: Option>, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Program { + pub(crate) shared_program_data: Arc, + pub constants: HashMap, + pub reference_manager: ReferenceManager, + pub identifiers: HashMap, +} + impl Program { #[allow(clippy::too_many_arguments)] pub fn new( builtins: Vec, - prime: String, data: Vec, main: Option, hints: HashMap>, @@ -43,10 +66,18 @@ impl Program { error_message_attributes: Vec, instruction_locations: Option>, ) -> Result { - Ok(Self { + let shared_program_data = SharedProgramData { builtins, - prime, data, + hints, + main, + start: None, + end: None, + error_message_attributes, + instruction_locations, + }; + Ok(Self { + shared_program_data: Arc::new(shared_program_data), constants: { let mut constants = HashMap::new(); for (key, value) in identifiers.iter() { @@ -61,14 +92,8 @@ impl Program { constants }, - main, - start: None, - end: None, - hints, reference_manager, identifiers, - error_message_attributes, - instruction_locations, }) } @@ -85,21 +110,13 @@ impl Program { impl Default for Program { fn default() -> Self { - Program { - builtins: Vec::new(), - prime: PRIME_STR.to_string(), - data: Vec::new(), + Self { + shared_program_data: Arc::new(SharedProgramData::default()), constants: HashMap::new(), - main: None, - start: None, - end: None, - hints: HashMap::new(), reference_manager: ReferenceManager { references: Vec::new(), }, identifiers: HashMap::new(), - error_message_attributes: Vec::new(), - instruction_locations: None, } } } @@ -133,7 +150,6 @@ mod tests { let program = Program::new( builtins.clone(), - felt::PRIME_STR.to_string(), data.clone(), None, HashMap::new(), @@ -144,9 +160,9 @@ mod tests { ) .unwrap(); - assert_eq!(program.builtins, builtins); - assert_eq!(program.data, data); - assert_eq!(program.main, None); + assert_eq!(program.shared_program_data.builtins, builtins); + assert_eq!(program.shared_program_data.data, data); + assert_eq!(program.shared_program_data.main, None); assert_eq!(program.identifiers, HashMap::new()); } @@ -196,7 +212,6 @@ mod tests { let program = Program::new( builtins.clone(), - felt::PRIME_STR.to_string(), data.clone(), None, HashMap::new(), @@ -207,9 +222,9 @@ mod tests { ) .unwrap(); - assert_eq!(program.builtins, builtins); - assert_eq!(program.data, data); - assert_eq!(program.main, None); + assert_eq!(program.shared_program_data.builtins, builtins); + assert_eq!(program.shared_program_data.data, data); + assert_eq!(program.shared_program_data.main, None); assert_eq!(program.identifiers, identifiers); assert_eq!( program.constants, @@ -266,7 +281,6 @@ mod tests { let program = Program::new( builtins, - felt::PRIME_STR.to_string(), data, None, HashMap::new(), @@ -356,10 +370,9 @@ mod tests { }, ); - assert_eq!(program.prime, PRIME_STR.to_string()); - assert_eq!(program.builtins, builtins); - assert_eq!(program.data, data); - assert_eq!(program.main, Some(0)); + assert_eq!(program.shared_program_data.builtins, builtins); + assert_eq!(program.shared_program_data.data, data); + assert_eq!(program.shared_program_data.main, Some(0)); assert_eq!(program.identifiers, identifiers); } @@ -456,12 +469,14 @@ mod tests { }, ); - assert_eq!(program.prime, PRIME_STR.to_string()); - assert_eq!(program.builtins, builtins); - assert_eq!(program.data, data); - assert_eq!(program.main, None); + assert_eq!(program.shared_program_data.builtins, builtins); + assert_eq!(program.shared_program_data.data, data); + assert_eq!(program.shared_program_data.main, None); assert_eq!(program.identifiers, identifiers); - assert_eq!(program.error_message_attributes, error_message_attributes) + assert_eq!( + program.shared_program_data.error_message_attributes, + error_message_attributes + ) } #[test] @@ -506,23 +521,25 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn default_program() { - let program = Program { + let shared_program_data = SharedProgramData { builtins: Vec::new(), - prime: PRIME_STR.to_string(), data: Vec::new(), - constants: HashMap::new(), + hints: HashMap::new(), main: None, start: None, end: None, - hints: HashMap::new(), + error_message_attributes: Vec::new(), + instruction_locations: None, + }; + let program = Program { + shared_program_data: Arc::new(shared_program_data), + constants: HashMap::new(), reference_manager: ReferenceManager { references: Vec::new(), }, identifiers: HashMap::new(), - error_message_attributes: Vec::new(), - instruction_locations: None, }; - assert_eq!(program, Program::default()) + assert_eq!(program, Program::default()); } } diff --git a/src/utils.rs b/src/utils.rs index 5df7791258..574b34959e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -236,39 +236,72 @@ pub mod test_utils { } pub(crate) use cairo_runner; + pub(crate) use crate::stdlib::sync::Arc; + pub(crate) use crate::types::program::Program; + pub(crate) use crate::types::program::SharedProgramData; macro_rules! program { //Empty program () => { Program::default() }; //Program with builtins - ( $( $builtin_name: expr ),* ) => { - Program { + ( $( $builtin_name: expr ),* ) => {{ + let shared_program_data = SharedProgramData { builtins: vec![$( $builtin_name ),*], - prime: "0x800000000000011000000000000000000000000000000000000000000000001".to_string(), data: crate::stdlib::vec::Vec::new(), - constants: crate::stdlib::collections::HashMap::new(), + hints: crate::stdlib::collections::HashMap::new(), main: None, start: None, end: None, - hints: crate::stdlib::collections::HashMap::new(), + error_message_attributes: crate::stdlib::vec::Vec::new(), + instruction_locations: None, + }; + Program { + shared_program_data: Arc::new(shared_program_data), + constants: crate::stdlib::collections::HashMap::new(), reference_manager: ReferenceManager { references: crate::stdlib::vec::Vec::new(), }, identifiers: crate::stdlib::collections::HashMap::new(), - error_message_attributes: crate::stdlib::vec::Vec::new(), - instruction_locations: None, } - }; + }}; // Custom program definition - ($($field:ident = $value:expr),* $(,)?) => { + ($(constants = $value:expr),* $(,)?) => { + Program { + $( + constants: $value, + )* + ..Default::default() + } + }; + ($(refence_manager = $value:expr),* $(,)?) => { Program { + $( + reference_manager: $value, + )* + ..Default::default() + } + }; + ($(identifiers = $value:expr),* $(,)?) => { + Program { + $( + identifiers: $value, + )* + ..Default::default() + } + }; + ($($field:ident = $value:expr),* $(,)?) => {{ + let shared_data = SharedProgramData { $( $field: $value, )* ..Default::default() + }; + Program { + shared_program_data: Arc::new(shared_data), + ..Default::default() } - } + }}; } pub(crate) use program; @@ -841,44 +874,47 @@ mod test { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn program_macro() { - let program = Program { + let shared_data = SharedProgramData { builtins: Vec::new(), - prime: "0x800000000000011000000000000000000000000000000000000000000000001".to_string(), data: Vec::new(), - constants: HashMap::new(), + hints: HashMap::new(), main: None, start: None, end: None, - hints: HashMap::new(), + error_message_attributes: Vec::new(), + instruction_locations: None, + }; + let program = Program { + shared_program_data: Arc::new(shared_data), + constants: HashMap::new(), reference_manager: ReferenceManager { references: Vec::new(), }, identifiers: HashMap::new(), - error_message_attributes: Vec::new(), - instruction_locations: None, }; - assert_eq!(program, program!()) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn program_macro_with_builtin() { - let program = Program { + let shared_data = SharedProgramData { builtins: vec![BuiltinName::range_check], - prime: "0x800000000000011000000000000000000000000000000000000000000000001".to_string(), data: Vec::new(), - constants: HashMap::new(), + hints: HashMap::new(), main: None, start: None, end: None, - hints: HashMap::new(), + error_message_attributes: Vec::new(), + instruction_locations: None, + }; + let program = Program { + shared_program_data: Arc::new(shared_data), + constants: HashMap::new(), reference_manager: ReferenceManager { references: Vec::new(), }, identifiers: HashMap::new(), - error_message_attributes: Vec::new(), - instruction_locations: None, }; assert_eq!(program, program![BuiltinName::range_check]) @@ -887,21 +923,23 @@ mod test { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn program_macro_custom_definition() { - let program = Program { + let shared_data = SharedProgramData { builtins: vec![BuiltinName::range_check], - prime: "0x800000000000011000000000000000000000000000000000000000000000001".to_string(), data: Vec::new(), - constants: HashMap::new(), + hints: HashMap::new(), main: Some(2), start: None, end: None, - hints: HashMap::new(), + error_message_attributes: Vec::new(), + instruction_locations: None, + }; + let program = Program { + shared_program_data: Arc::new(shared_data), + constants: HashMap::new(), reference_manager: ReferenceManager { references: Vec::new(), }, identifiers: HashMap::new(), - error_message_attributes: Vec::new(), - instruction_locations: None, }; assert_eq!( diff --git a/src/vm/errors/vm_exception.rs b/src/vm/errors/vm_exception.rs index a3a67aefa8..1949d19460 100644 --- a/src/vm/errors/vm_exception.rs +++ b/src/vm/errors/vm_exception.rs @@ -58,7 +58,7 @@ pub fn get_error_attr_value( vm: &VirtualMachine, ) -> Option { let mut errors = String::new(); - for attribute in &runner.program.error_message_attributes { + for attribute in &runner.program.shared_program_data.error_message_attributes { if attribute.start_pc <= pc && attribute.end_pc > pc { errors.push_str(&format!( "Error message: {}\n", @@ -78,7 +78,12 @@ pub fn get_location( runner: &CairoRunner, hint_index: Option, ) -> Option { - let instruction_location = runner.program.instruction_locations.as_ref()?.get(&pc)?; + let instruction_location = runner + .program + .shared_program_data + .instruction_locations + .as_ref()? + .get(&pc)?; if let Some(index) = hint_index { instruction_location .hints @@ -931,7 +936,7 @@ cairo_programs/bad_programs/bad_usort.cairo:64:5: (pc=0:60) // This reference should be rejected when substituting the error attribute references let runner = cairo_runner!(program); let vm = vm!(); - let attribute = &program.error_message_attributes[0]; + let attribute = &program.shared_program_data.error_message_attributes[0]; assert_eq!( substitute_error_message_references(attribute, &runner, &vm), format!( @@ -972,7 +977,7 @@ cairo_programs/bad_programs/bad_usort.cairo:64:5: (pc=0:60) // This reference should be rejected when substituting the error attribute references let runner = cairo_runner!(program); let vm = vm!(); - let attribute = &program.error_message_attributes[0]; + let attribute = &program.shared_program_data.error_message_attributes[0]; assert_eq!( substitute_error_message_references(attribute, &runner, &vm), format!( diff --git a/src/vm/runners/cairo_runner.rs b/src/vm/runners/cairo_runner.rs index 7410b7a6f3..66085e9163 100644 --- a/src/vm/runners/cairo_runner.rs +++ b/src/vm/runners/cairo_runner.rs @@ -79,6 +79,7 @@ pub struct CairoRunner { final_pc: Option, pub program_base: Option, execution_base: Option, + entrypoint: Option, initial_ap: Option, initial_fp: Option, initial_pc: Option, @@ -115,6 +116,7 @@ impl CairoRunner { final_pc: None, program_base: None, execution_base: None, + entrypoint: program.shared_program_data.main, initial_ap: None, initial_fp: None, initial_pc: None, @@ -147,10 +149,14 @@ impl CairoRunner { BuiltinName::keccak, BuiltinName::poseidon, ]; - if !is_subsequence(&self.program.builtins, &builtin_ordered_list) { + if !is_subsequence( + &self.program.shared_program_data.builtins, + &builtin_ordered_list, + ) { return Err(RunnerError::DisorderedBuiltins); }; - let mut program_builtins: HashSet<&BuiltinName> = self.program.builtins.iter().collect(); + let mut program_builtins: HashSet<&BuiltinName> = + self.program.shared_program_data.builtins.iter().collect(); let mut builtin_runners = Vec::::new(); if self.layout.builtins.output { @@ -275,11 +281,16 @@ impl CairoRunner { } } - for builtin_name in &self.program.builtins { + for builtin_name in &self.program.shared_program_data.builtins { initialize_builtin(*builtin_name, vm); } for builtin_name in starknet_preset_builtins { - if !self.program.builtins.contains(&builtin_name) { + if !self + .program + .shared_program_data + .builtins + .contains(&builtin_name) + { initialize_builtin(builtin_name, vm) } } @@ -319,14 +330,14 @@ impl CairoRunner { }; self.initial_pc = Some(initial_pc); vm.segments - .load_data(prog_base, &self.program.data) + .load_data(prog_base, &self.program.shared_program_data.data) .map_err(RunnerError::MemoryInitializationError)?; // Mark all addresses from the program segment as accessed let base = self .program_base .unwrap_or_else(|| Relocatable::from((0, 0))); - for i in 0..self.program.data.len() { + for i in 0..self.program.shared_program_data.data.len() { vm.segments.memory.mark_as_accessed((base + i)?); } } @@ -393,7 +404,10 @@ impl CairoRunner { self.execution_public_memory = Some(Vec::from_iter(0..stack_prefix.len())); self.initialize_state( vm, - self.program.start.ok_or(RunnerError::NoProgramStart)?, + self.program + .shared_program_data + .start + .ok_or(RunnerError::NoProgramStart)?, stack_prefix, )?; self.initial_fp = Some( @@ -404,10 +418,14 @@ impl CairoRunner { ); self.initial_ap = self.initial_fp; return Ok(self.program_base.as_ref().ok_or(RunnerError::NoProgBase)? - + self.program.end.ok_or(RunnerError::NoProgramEnd)?); + + self + .program + .shared_program_data + .end + .ok_or(RunnerError::NoProgramEnd)?); } let return_fp = vm.segments.add(); - if let Some(main) = &self.program.main { + if let Some(main) = &self.entrypoint { let main_clone = *main; Ok(self.initialize_function_entrypoint( vm, @@ -473,7 +491,7 @@ impl CairoRunner { hint_executor: &mut dyn HintProcessor, ) -> Result>>, VirtualMachineError> { let mut hint_data_dictionary = HashMap::>>::new(); - for (hint_index, hints) in self.program.hints.iter() { + for (hint_index, hints) in self.program.shared_program_data.hints.iter() { for hint in hints { let hint_data = hint_executor.compile_hint( &hint.code, @@ -495,7 +513,7 @@ impl CairoRunner { } pub fn get_program_builtins(&self) -> &Vec { - &self.program.builtins + &self.program.shared_program_data.builtins } pub fn run_until_pc( @@ -822,7 +840,7 @@ impl CairoRunner { if !self.run_ended { return Err(RunnerError::FinalizeNoEndRun); } - let size = self.program.data.len(); + let size = self.program.shared_program_data.data.len(); let mut public_memory = Vec::with_capacity(size); for i in 0..size { public_memory.push((i, 0_usize)) @@ -965,7 +983,7 @@ impl CairoRunner { /// is specified. pub fn set_entrypoint(&mut self, new_entrypoint: Option<&str>) -> Result<(), ProgramError> { let new_entrypoint = new_entrypoint.unwrap_or("main"); - self.program.main = Some( + self.entrypoint = Some( self.program .identifiers .get(&format!("__main__.{new_entrypoint}")) @@ -3532,7 +3550,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn finalize_segments_run_ended_not_emptyproof_mode_empty_execution_public_memory() { let mut program = program!(); - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "plain", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -3565,7 +3584,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn finalize_segments_run_ended_not_emptyproof_mode_with_execution_public_memory() { let mut program = program!(); - program.data = vec_data![(1), (2), (3), (4)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4)]; //Program data len = 4 let mut cairo_runner = cairo_runner!(program, "plain", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -4131,7 +4151,10 @@ mod tests { ); let runner = cairo_runner!(program); - assert_eq!(&program.builtins, runner.get_program_builtins()); + assert_eq!( + &program.shared_program_data.builtins, + runner.get_program_builtins() + ); } #[test] @@ -4158,7 +4181,7 @@ mod tests { cairo_runner .set_entrypoint(None) .expect("Call to `set_entrypoint()` failed."); - assert_eq!(cairo_runner.program.main, Some(0)); + assert_eq!(cairo_runner.entrypoint, Some(0)); } #[test] @@ -4198,7 +4221,7 @@ mod tests { cairo_runner .set_entrypoint(Some("alternate_main")) .expect("Call to `set_entrypoint()` failed."); - assert_eq!(cairo_runner.program.main, Some(1)); + assert_eq!(cairo_runner.entrypoint, Some(1)); } /// Test that set_entrypoint() fails when the entrypoint doesn't exist. @@ -4226,14 +4249,15 @@ mod tests { cairo_runner .set_entrypoint(Some("nonexistent_main")) .expect_err("Call to `set_entrypoint()` succeeded (should've failed)."); - assert_eq!(cairo_runner.program.main, None); + assert_eq!(cairo_runner.entrypoint, None); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn read_return_values_test() { let mut program = program!(); - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "plain", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -4256,7 +4280,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn read_return_values_test_with_run_not_ended() { let mut program = program!(); - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "plain", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -4273,7 +4298,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn read_return_values_test_with_segments_finalized() { let mut program = program!(); - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "plain", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -4291,7 +4317,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn read_return_values_updates_builtin_stop_ptr_one_builtin_empty() { let mut program = program![BuiltinName::output]; - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "all_cairo", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -4321,7 +4348,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn read_return_values_updates_builtin_stop_ptr_one_builtin_one_element() { let mut program = program![BuiltinName::output]; - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "all_cairo", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); @@ -4351,7 +4379,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn read_return_values_updates_builtin_stop_ptr_two_builtins() { let mut program = program![BuiltinName::output, BuiltinName::bitwise]; - program.data = vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; + Arc::get_mut(&mut program.shared_program_data).unwrap().data = + vec_data![(1), (2), (3), (4), (5), (6), (7), (8)]; //Program data len = 8 let mut cairo_runner = cairo_runner!(program, "all_cairo", true); cairo_runner.program_base = Some(Relocatable::from((0, 0))); diff --git a/src/vm/security.rs b/src/vm/security.rs index d5c0c9107c..29b38371e6 100644 --- a/src/vm/security.rs +++ b/src/vm/security.rs @@ -48,7 +48,8 @@ pub fn verify_secure_runner( .program_base .and_then(|rel| rel.segment_index.to_usize()) .ok_or(RunnerError::NoProgBase)?; - let program_segment_size = program_segment_size.unwrap_or(runner.program.data.len()); + let program_segment_size = + program_segment_size.unwrap_or(runner.program.shared_program_data.data.len()); let program_length = vm .segments .memory