From 8883eae26327af110a50a1016b4aa838c490087a Mon Sep 17 00:00:00 2001 From: Ori Ziv Date: Tue, 21 May 2024 10:34:01 +0300 Subject: [PATCH 01/11] Merged hint temporary segments by cheatcode hint. --- Cargo.lock | 1 + cairo1-run/Cargo.toml | 1 + cairo1-run/src/cairo_run.rs | 34 +++++++++--- .../cairo_1_hint_processor/dict_manager.rs | 53 ++++++++----------- .../cairo_1_hint_processor/hint_processor.rs | 18 ++++++- 5 files changed, 66 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6976dd01ec..274768bae7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -995,6 +995,7 @@ dependencies = [ "clap", "itertools 0.11.0", "mimalloc", + "num-bigint", "num-traits 0.2.18", "rstest", "serde_json", diff --git a/cairo1-run/Cargo.toml b/cairo1-run/Cargo.toml index 43bc52d019..d7d3d7ce02 100644 --- a/cairo1-run/Cargo.toml +++ b/cairo1-run/Cargo.toml @@ -29,6 +29,7 @@ assert_matches = "1.5.0" rstest = "0.17.0" mimalloc = { version = "0.1.37", default-features = false, optional = true } num-traits = { version = "0.2", default-features = false } +num-bigint.workspace = true [features] default = ["with_mimalloc"] diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index ed91397a7c..a333615d9f 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -4,7 +4,7 @@ use cairo_lang_casm::{ casm, casm_build_extend, cell_expression::CellExpression, deref, deref_or_immediate, - hints::Hint, + hints::{Hint, StarknetHint}, inline::CasmContext, instructions::{Instruction, InstructionBody}, }; @@ -31,7 +31,9 @@ use cairo_lang_sierra_to_casm::{ metadata::calc_metadata_ap_change_only, }; use cairo_lang_sierra_type_size::get_type_size_map; -use cairo_lang_utils::{casts::IntoOrPanic, unordered_hash_map::UnorderedHashMap}; +use cairo_lang_utils::{ + bigint::BigIntAsHex, casts::IntoOrPanic, unordered_hash_map::UnorderedHashMap, +}; use cairo_vm::{ hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor, math_utils::signed_felt, @@ -48,6 +50,7 @@ use cairo_vm::{ Felt252, }; use itertools::{chain, Itertools}; +use num_bigint::{BigInt, Sign}; use num_traits::{cast::ToPrimitive, Zero}; use std::{collections::HashMap, iter::Peekable}; @@ -230,7 +233,6 @@ pub fn cairo_run_program( cairo_run_config.trace_enabled, )?; let end = runner.initialize(cairo_run_config.proof_mode)?; - load_arguments(&mut runner, &cairo_run_config, main_func)?; // Run it until the end / infinite loop in proof_mode runner.run_until_pc(end, &mut hint_processor)?; @@ -722,12 +724,28 @@ fn create_entry_code( let output_ptr = ctx.add_var(CellExpression::Deref(deref!([ap - 1]))); let local = ctx.add_var(CellExpression::Deref(deref!([fp]))); casm_build_extend!(ctx, assert local = output_ptr;); - if got_segment_arena { - // We re-scoped when serializing the output so we have to create a var for the segment arena - // len(builtins) + len(builtins - output) + segment_arena_ptr + info_segment + 0 - let off = 2 * builtins.len() + 2; - let segment_arena_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + off as i16]))); + // We re-scoped when serializing the output so we have to create a var for the segment arena + // len(builtins) + len(builtins - output) + segment_arena_ptr + info_segment + 0 + let off = 2 * builtins.len() + 2; + let segment_arena_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + off as i16]))); + // Call the hint that will relocate all dictionaries + ctx.add_hint( + |[ignored_in], [ignored_out]| StarknetHint::Cheatcode { + selector: BigIntAsHex { + value: BigInt::from_bytes_be( + Sign::Plus, + "FinalizeDictionarySegments".as_bytes(), + ), + }, + input_start: ignored_in.clone(), + input_end: ignored_in, + output_start: ignored_out, + output_end: ignored_out, + }, + [segment_arena_ptr], + [segment_arena_ptr], + ); // Validating the segment arena's segments are one after the other. casm_build_extend! {ctx, tempvar n_segments = segment_arena_ptr[-2]; diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index 87f646d3dd..92492fc748 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -14,8 +14,8 @@ pub struct DictTrackerExecScope { data: HashMap, /// The start of the segment of the dictionary. start: Relocatable, - /// The start of the next segment in the segment arena, if finalized. - next_start: Option, + /// The end of this segment, if finalized. + end: Option, } /// Helper object to allocate, track and destruct all dictionaries in the run. @@ -33,7 +33,7 @@ impl DictTrackerExecScope { Self { data: HashMap::default(), start, - next_start: None, + end: None, } } } @@ -43,19 +43,12 @@ impl DictManagerExecScope { /// Allocates a new segment for a new dictionary and return the start of the segment. pub fn new_default_dict(&mut self, vm: &mut VirtualMachine) -> Result { - let dict_segment = match self.trackers.last() { - // This is the first dict - a totally new segment is required. - None => vm.add_memory_segment(), - // New dict segment should be appended to the last segment. - // Appending by a temporary segment, if the last segment is not finalized. - Some(last) => last - .next_start - .unwrap_or_else(|| vm.add_temporary_segment()), - }; + let dict_segment = vm.add_temporary_segment(); let tracker = DictTrackerExecScope::new(dict_segment); - // Not checking if overriding - since overriding is allowed. - self.segment_to_tracker - .insert(dict_segment.segment_index, self.trackers.len()); + assert!(self + .segment_to_tracker + .insert(dict_segment.segment_index, self.trackers.len()) + .is_none()); self.trackers.push(tracker); Ok(dict_segment) @@ -85,31 +78,29 @@ impl DictManagerExecScope { } /// Finalizes a segment of a dictionary. - pub fn finalize_segment( - &mut self, - vm: &mut VirtualMachine, - dict_end: Relocatable, - ) -> Result<(), HintError> { + pub fn finalize_segment(&mut self, dict_end: Relocatable) -> Result<(), HintError> { let tracker_idx = self.get_dict_infos_index(dict_end).unwrap(); let tracker = &mut self.trackers[tracker_idx]; - let next_start = (dict_end + 1u32).unwrap(); - if let Some(prev) = tracker.next_start { + if let Some(prev) = tracker.end { return Err(HintError::CustomHint( format!( "The segment is already finalized. \ - Attempting to override next start {prev}, with: {next_start}.", + Attempting to override next start {prev}, with: {dict_end}.", ) .into_boxed_str(), )); } - tracker.next_start = Some(next_start); - if let Some(next) = self.trackers.get(tracker_idx + 1) { - // Merging the next temporary segment with the closed segment. - vm.add_relocation_rule(next.start, next_start).unwrap(); - // Updating the segment to point to tracker the next segment points to. - let next_tracker_idx = self.segment_to_tracker[&next.start.segment_index]; - self.segment_to_tracker - .insert(dict_end.segment_index, next_tracker_idx); + tracker.end = Some(dict_end); + Ok(()) + } + + /// Finalizes all segments of dictionaries by adding relocation rules to merge them. + pub fn finalize_all_segments(&mut self, vm: &mut VirtualMachine) -> Result<(), HintError> { + let mut prev_end = vm.add_memory_segment(); + for tracker in &self.trackers { + vm.add_relocation_rule(tracker.start, prev_end)?; + prev_end += (tracker.end.unwrap() - tracker.start)?; + prev_end += 1; } Ok(()) } diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index d05006912a..4e8bd25e09 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -17,7 +17,7 @@ use crate::{ use ark_ff::fields::{Fp256, MontBackend, MontConfig}; use ark_ff::{Field, PrimeField}; use ark_std::UniformRand; -use cairo_lang_casm::hints::{CoreHintBase, DeprecatedHint}; +use cairo_lang_casm::hints::{CoreHintBase, DeprecatedHint, StarknetHint}; use cairo_lang_casm::{ hints::{CoreHint, Hint}, operand::{CellRef, ResOperand}, @@ -266,6 +266,20 @@ impl Cairo1HintProcessor { t_or_k0, t_or_k1, ), + Hint::Starknet(StarknetHint::Cheatcode { selector, .. }) => { + let selector = &selector.value.to_bytes_be().1; + let selector = std::str::from_utf8(selector).map_err(|_| { + HintError::CustomHint(Box::from("failed to parse selector".to_string())) + })?; + match selector { + "FinalizeDictionarySegments" => { + let dict_manager_exec_scope = exec_scopes + .get_mut_ref::("dict_manager_exec_scope")?; + dict_manager_exec_scope.finalize_all_segments(vm) + } + _ => Err(HintError::UnknownHint(selector.into())), + } + } hint => Err(HintError::UnknownHint( format!("{:?}", hint).into_boxed_str(), @@ -418,7 +432,7 @@ impl Cairo1HintProcessor { vm.insert_value(cell_ref_to_relocatable(dict_index, vm)?, dict_infos_index) .map_err(HintError::from)?; // The hint is only for dictionary finalization, so can be called. - dict_manager_exec_scope.finalize_segment(vm, dict_address) + dict_manager_exec_scope.finalize_segment(dict_address) } #[allow(clippy::too_many_arguments)] From 6d04be40615898a653f2a58f604074c5a8b2a668 Mon Sep 17 00:00:00 2001 From: Ori Ziv Date: Tue, 21 May 2024 16:46:29 +0300 Subject: [PATCH 02/11] Added line removed by mistake. --- cairo1-run/src/cairo_run.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index a333615d9f..4f78cfdb30 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -233,6 +233,7 @@ pub fn cairo_run_program( cairo_run_config.trace_enabled, )?; let end = runner.initialize(cairo_run_config.proof_mode)?; + load_arguments(&mut runner, &cairo_run_config, main_func)?; // Run it until the end / infinite loop in proof_mode runner.run_until_pc(end, &mut hint_processor)?; From 147b1fdc11ef076c871545116e071f98dae94403 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:11:38 -0300 Subject: [PATCH 03/11] Remove std import --- vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index 4e8bd25e09..21e2e735fb 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -268,7 +268,7 @@ impl Cairo1HintProcessor { ), Hint::Starknet(StarknetHint::Cheatcode { selector, .. }) => { let selector = &selector.value.to_bytes_be().1; - let selector = std::str::from_utf8(selector).map_err(|_| { + let selector = crate::stdlib::str::from_utf8(selector).map_err(|_| { HintError::CustomHint(Box::from("failed to parse selector".to_string())) })?; match selector { From f0b16d1faf8de850bfd0d534b55733fbbc794893 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:20:38 -0300 Subject: [PATCH 04/11] Rename Cheatcode for clarity + remove unwrap --- cairo1-run/src/cairo_run.rs | 2 +- .../hint_processor/cairo_1_hint_processor/dict_manager.rs | 6 +++--- .../hint_processor/cairo_1_hint_processor/hint_processor.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index 4f78cfdb30..59cce6347b 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -736,7 +736,7 @@ fn create_entry_code( selector: BigIntAsHex { value: BigInt::from_bytes_be( Sign::Plus, - "FinalizeDictionarySegments".as_bytes(), + "RelocateAllDictionaries".as_bytes(), ), }, input_start: ignored_in.clone(), diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index 92492fc748..eca5d10b42 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -79,7 +79,7 @@ impl DictManagerExecScope { /// Finalizes a segment of a dictionary. pub fn finalize_segment(&mut self, dict_end: Relocatable) -> Result<(), HintError> { - let tracker_idx = self.get_dict_infos_index(dict_end).unwrap(); + let tracker_idx = self.get_dict_infos_index(dict_end)?; let tracker = &mut self.trackers[tracker_idx]; if let Some(prev) = tracker.end { return Err(HintError::CustomHint( @@ -94,8 +94,8 @@ impl DictManagerExecScope { Ok(()) } - /// Finalizes all segments of dictionaries by adding relocation rules to merge them. - pub fn finalize_all_segments(&mut self, vm: &mut VirtualMachine) -> Result<(), HintError> { + /// Relocates all dictionaries into a single segment + pub fn relocate_all_dictionaries(&mut self, vm: &mut VirtualMachine) -> Result<(), HintError> { let mut prev_end = vm.add_memory_segment(); for tracker in &self.trackers { vm.add_relocation_rule(tracker.start, prev_end)?; diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index 21e2e735fb..75cb5d51bd 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -272,10 +272,10 @@ impl Cairo1HintProcessor { HintError::CustomHint(Box::from("failed to parse selector".to_string())) })?; match selector { - "FinalizeDictionarySegments" => { + "RelocateAllDictionaries" => { let dict_manager_exec_scope = exec_scopes .get_mut_ref::("dict_manager_exec_scope")?; - dict_manager_exec_scope.finalize_all_segments(vm) + dict_manager_exec_scope.relocate_all_dictionaries(vm) } _ => Err(HintError::UnknownHint(selector.into())), } From 879b6aac9d18ea63511b8308e9c653c73ae7d4c7 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:32:04 -0300 Subject: [PATCH 05/11] use real or temporary based on flag --- cairo1-run/src/cairo_run.rs | 8 +-- .../cairo_1_hint_processor/dict_manager.rs | 53 +++++++++++++------ .../cairo_1_hint_processor/hint_processor.rs | 8 +-- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index 59cce6347b..67b5d9ca17 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -726,10 +726,10 @@ fn create_entry_code( let local = ctx.add_var(CellExpression::Deref(deref!([fp]))); casm_build_extend!(ctx, assert local = output_ptr;); if got_segment_arena { - // We re-scoped when serializing the output so we have to create a var for the segment arena - // len(builtins) + len(builtins - output) + segment_arena_ptr + info_segment + 0 - let off = 2 * builtins.len() + 2; - let segment_arena_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + off as i16]))); + // We re-scoped when serializing the output so we have to create a var for the segment arena + // len(builtins) + len(builtins - output) + segment_arena_ptr + info_segment + 0 + let off = 2 * builtins.len() + 2; + let segment_arena_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + off as i16]))); // Call the hint that will relocate all dictionaries ctx.add_hint( |[ignored_in], [ignored_out]| StarknetHint::Cheatcode { diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index eca5d10b42..2d47c5a29d 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -25,6 +25,9 @@ pub struct DictManagerExecScope { segment_to_tracker: HashMap, /// The actual trackers of the dictionaries, in the order of allocation. trackers: Vec, + // If set to true, dictionaries will be created on temporary segments and will then be relocated into a single segment by the end of the run + // If set to false, each dictionary will use a single real segment + use_temporary_segments: bool, } impl DictTrackerExecScope { @@ -41,9 +44,21 @@ impl DictTrackerExecScope { impl DictManagerExecScope { pub const DICT_DEFAULT_VALUE: usize = 0; + // Creates a new DictManagerExecScope + pub fn new(use_temporary_segments: bool) -> Self { + Self { + use_temporary_segments, + ..Default::default() + } + } + /// Allocates a new segment for a new dictionary and return the start of the segment. pub fn new_default_dict(&mut self, vm: &mut VirtualMachine) -> Result { - let dict_segment = vm.add_temporary_segment(); + let dict_segment = if self.use_temporary_segments { + vm.add_temporary_segment() + } else { + vm.add_memory_segment() + }; let tracker = DictTrackerExecScope::new(dict_segment); assert!(self .segment_to_tracker @@ -78,29 +93,35 @@ impl DictManagerExecScope { } /// Finalizes a segment of a dictionary. + /// Does nothing if use_temporary_segments is set to false pub fn finalize_segment(&mut self, dict_end: Relocatable) -> Result<(), HintError> { - let tracker_idx = self.get_dict_infos_index(dict_end)?; - let tracker = &mut self.trackers[tracker_idx]; - if let Some(prev) = tracker.end { - return Err(HintError::CustomHint( - format!( - "The segment is already finalized. \ + if self.use_temporary_segments { + let tracker_idx = self.get_dict_infos_index(dict_end)?; + let tracker = &mut self.trackers[tracker_idx]; + if let Some(prev) = tracker.end { + return Err(HintError::CustomHint( + format!( + "The segment is already finalized. \ Attempting to override next start {prev}, with: {dict_end}.", - ) - .into_boxed_str(), - )); + ) + .into_boxed_str(), + )); + } + tracker.end = Some(dict_end); } - tracker.end = Some(dict_end); Ok(()) } /// Relocates all dictionaries into a single segment + /// Does nothing if use_temporary_segments is set to false pub fn relocate_all_dictionaries(&mut self, vm: &mut VirtualMachine) -> Result<(), HintError> { - let mut prev_end = vm.add_memory_segment(); - for tracker in &self.trackers { - vm.add_relocation_rule(tracker.start, prev_end)?; - prev_end += (tracker.end.unwrap() - tracker.start)?; - prev_end += 1; + if self.use_temporary_segments { + let mut prev_end = vm.add_memory_segment(); + for tracker in &self.trackers { + vm.add_relocation_rule(tracker.start, prev_end)?; + prev_end += (tracker.end.unwrap() - tracker.start)?; + prev_end += 1; + } } Ok(()) } diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index 75cb5d51bd..53a8073b54 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -54,6 +54,7 @@ fn get_beta() -> Felt252 { pub struct Cairo1HintProcessor { hints: HashMap>, run_resources: RunResources, + segment_arena_validations: bool, } impl Cairo1HintProcessor { @@ -61,6 +62,7 @@ impl Cairo1HintProcessor { Self { hints: hints.iter().cloned().collect(), run_resources, + segment_arena_validations: false, } } // Runs a single Hint @@ -166,7 +168,7 @@ impl Cairo1HintProcessor { })) => self.linear_split(vm, value, scalar, max_x, x, y), Hint::Core(CoreHintBase::Core(CoreHint::AllocFelt252Dict { segment_arena_ptr })) => { - self.alloc_felt_256_dict(vm, segment_arena_ptr, exec_scopes) + self.alloc_felt_252_dict(vm, segment_arena_ptr, exec_scopes) } Hint::Core(CoreHintBase::Core(CoreHint::AssertLeFindSmallArcs { @@ -562,7 +564,7 @@ impl Cairo1HintProcessor { Err(HintError::KeyNotFound) } - fn alloc_felt_256_dict( + fn alloc_felt_252_dict( &self, vm: &mut VirtualMachine, segment_arena_ptr: &ResOperand, @@ -591,7 +593,7 @@ impl Cairo1HintProcessor { Err(_) => { exec_scopes.assign_or_update_variable( "dict_manager_exec_scope", - Box::::default(), + Box::new(DictManagerExecScope::new(self.segment_arena_validations)), ); exec_scopes.get_mut_ref::("dict_manager_exec_scope")? } From 7c49c560f969fb851857d98710a2c7baf4fffdee Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:34:46 -0300 Subject: [PATCH 06/11] Remove assert --- .../cairo_1_hint_processor/dict_manager.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index 2d47c5a29d..ad04d4613d 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -60,10 +60,15 @@ impl DictManagerExecScope { vm.add_memory_segment() }; let tracker = DictTrackerExecScope::new(dict_segment); - assert!(self + if self .segment_to_tracker .insert(dict_segment.segment_index, self.trackers.len()) - .is_none()); + .is_some() + { + return Err(HintError::CantCreateDictionaryOnTakenSegment( + dict_segment.segment_index, + )); + } self.trackers.push(tracker); Ok(dict_segment) From 94d2a7435b90714302dd618a20a85c962dbebb66 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:35:38 -0300 Subject: [PATCH 07/11] Remove unwrap --- vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index ad04d4613d..9e36d27d88 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -124,7 +124,7 @@ impl DictManagerExecScope { let mut prev_end = vm.add_memory_segment(); for tracker in &self.trackers { vm.add_relocation_rule(tracker.start, prev_end)?; - prev_end += (tracker.end.unwrap() - tracker.start)?; + prev_end += (tracker.end.unwrap_or_default() - tracker.start)?; prev_end += 1; } } From e64cd6d081b6f2a9dda07444078826ee58dffeff Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:41:34 -0300 Subject: [PATCH 08/11] Add flag to HintProcessor --- cairo1-run/src/cairo_run.rs | 2 +- .../hint_processor/cairo_1_hint_processor/hint_processor.rs | 6 ++++-- vm/src/tests/cairo_1_run_from_entrypoint_tests.rs | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index 67b5d9ca17..500a601d3e 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -181,7 +181,7 @@ pub fn cairo_run_program( let (processor_hints, program_hints) = build_hints_vec(instructions.clone()); - let mut hint_processor = Cairo1HintProcessor::new(&processor_hints, RunResources::default()); + let mut hint_processor = Cairo1HintProcessor::new(&processor_hints, RunResources::default(), cairo_run_config.append_return_values || cairo_run_config.proof_mode); let data: Vec = instructions .flat_map(|inst| inst.assemble().encode()) diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index 53a8073b54..726b3b7420 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -54,15 +54,17 @@ fn get_beta() -> Felt252 { pub struct Cairo1HintProcessor { hints: HashMap>, run_resources: RunResources, + /// If set to true, uses a single segment for dictionaries to aid in segment arena validations + /// WARNING: The program must call the "RelocateAllDictionaries" Cheatcode if the flag is enabled segment_arena_validations: bool, } impl Cairo1HintProcessor { - pub fn new(hints: &[(usize, Vec)], run_resources: RunResources) -> Self { + pub fn new(hints: &[(usize, Vec)], run_resources: RunResources, segment_arena_validations: bool) -> Self { Self { hints: hints.iter().cloned().collect(), run_resources, - segment_arena_validations: false, + segment_arena_validations, } } // Runs a single Hint diff --git a/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs b/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs index 7f42e94529..9ca8eb0828 100644 --- a/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs +++ b/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs @@ -604,7 +604,7 @@ fn fibonacci_with_run_resources_ok() { let contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); // Program takes 621 steps let mut hint_processor = - Cairo1HintProcessor::new(&contract_class.hints, RunResources::new(621)); + Cairo1HintProcessor::new(&contract_class.hints, RunResources::new(621), false); assert_matches!( run_cairo_1_entrypoint_with_run_resources( serde_json::from_slice(program_data.as_slice()).unwrap(), @@ -625,7 +625,7 @@ fn fibonacci_with_run_resources_2_ok() { let contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); // Program takes 621 steps let mut hint_processor = - Cairo1HintProcessor::new(&contract_class.hints, RunResources::new(1000)); + Cairo1HintProcessor::new(&contract_class.hints, RunResources::new(1000), false); assert_matches!( run_cairo_1_entrypoint_with_run_resources( contract_class, @@ -648,7 +648,7 @@ fn fibonacci_with_run_resources_error() { let contract_class: CasmContractClass = serde_json::from_slice(program_data).unwrap(); // Program takes 621 steps let mut hint_processor = - Cairo1HintProcessor::new(&contract_class.hints, RunResources::new(100)); + Cairo1HintProcessor::new(&contract_class.hints, RunResources::new(100), false); assert!(run_cairo_1_entrypoint_with_run_resources( contract_class, 0, From 3105310bbd1ddb5d5f9eab53eb9fb4cc63889818 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 17:42:50 -0300 Subject: [PATCH 09/11] Update test util --- vm/src/tests/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/tests/mod.rs b/vm/src/tests/mod.rs index d1558730c1..daff9ce61c 100644 --- a/vm/src/tests/mod.rs +++ b/vm/src/tests/mod.rs @@ -108,7 +108,7 @@ fn run_cairo_1_entrypoint( ) { let contract_class: CasmContractClass = serde_json::from_slice(program_content).unwrap(); let mut hint_processor = - Cairo1HintProcessor::new(&contract_class.hints, RunResources::default()); + Cairo1HintProcessor::new(&contract_class.hints, RunResources::default(), false); let mut runner = CairoRunner::new( &(contract_class.clone().try_into().unwrap()), From 0fade4b9c5a41aafe94e9bff690fecfa11f0b963 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 18:01:15 -0300 Subject: [PATCH 10/11] Add Changelog Entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8e35b7f08..3779f76610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ #### Upcoming Changes +* feat(BREAKING): Use a cheatcode to relocate all dicts + Make temporary segment usage configurable [#1776](https://github.com/lambdaclass/cairo-vm/pull/1776) + * Add the flags `segment_arena_validation` & `use_temporary_segments` to the `Cairo1HintProcessor` & `DictManagerExecScope` respectively. These flags will determine if real segments or temporary segments will be used when creating dictionaries. + * `DictManagerExecScope::finalize_segment` no longer performs relocation and is ignored if `use_temporary_segments` is set to false. + * Add method `DictManagerExecScope::relocate_all_dictionaries` that adds relocation rules for all tracked dictionaries, relocating them one next to the other in a new segment. + * Add cheatcode `RelocateAllDictionaries` to the `Cairo1HintProcessor`, which calls the aforementioned method. + * Add casm instruction to call the aforementioned cheatcode in `create_entry_code` if either `proof_mode` or `append_return_values` are set to true, and segment arena is present. + * feat(BREAKING): Serialize inputs into output segment in cairo1-run crate: * Checks that only `Array` can be received by the program main function when running with with either `--proof_mode` or `--append_return_values`. * Copies the input value to the output segment right after the output in the format `[array_len, arr[0], arr[1],.., arr[n]]`. From 99ac4e2756375093139118773113982be303a72b Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 27 May 2024 18:04:21 -0300 Subject: [PATCH 11/11] Fmt + clarity --- cairo1-run/src/cairo_run.rs | 7 ++++++- .../hint_processor/cairo_1_hint_processor/dict_manager.rs | 2 +- .../cairo_1_hint_processor/hint_processor.rs | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs index 500a601d3e..7cb887b9cc 100644 --- a/cairo1-run/src/cairo_run.rs +++ b/cairo1-run/src/cairo_run.rs @@ -181,7 +181,11 @@ pub fn cairo_run_program( let (processor_hints, program_hints) = build_hints_vec(instructions.clone()); - let mut hint_processor = Cairo1HintProcessor::new(&processor_hints, RunResources::default(), cairo_run_config.append_return_values || cairo_run_config.proof_mode); + let mut hint_processor = Cairo1HintProcessor::new( + &processor_hints, + RunResources::default(), + cairo_run_config.append_return_values || cairo_run_config.proof_mode, + ); let data: Vec = instructions .flat_map(|inst| inst.assemble().encode()) @@ -725,6 +729,7 @@ fn create_entry_code( let output_ptr = ctx.add_var(CellExpression::Deref(deref!([ap - 1]))); let local = ctx.add_var(CellExpression::Deref(deref!([fp]))); casm_build_extend!(ctx, assert local = output_ptr;); + if got_segment_arena { // We re-scoped when serializing the output so we have to create a var for the segment arena // len(builtins) + len(builtins - output) + segment_arena_ptr + info_segment + 0 diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index 9e36d27d88..b95c0b5232 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -25,7 +25,7 @@ pub struct DictManagerExecScope { segment_to_tracker: HashMap, /// The actual trackers of the dictionaries, in the order of allocation. trackers: Vec, - // If set to true, dictionaries will be created on temporary segments and will then be relocated into a single segment by the end of the run + // If set to true, dictionaries will be created on temporary segments which can then be relocated into a single segment by the end of the run // If set to false, each dictionary will use a single real segment use_temporary_segments: bool, } diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index 726b3b7420..98bb0a1547 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -60,7 +60,11 @@ pub struct Cairo1HintProcessor { } impl Cairo1HintProcessor { - pub fn new(hints: &[(usize, Vec)], run_resources: RunResources, segment_arena_validations: bool) -> Self { + pub fn new( + hints: &[(usize, Vec)], + run_resources: RunResources, + segment_arena_validations: bool, + ) -> Self { Self { hints: hints.iter().cloned().collect(), run_resources,