diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b295716b4..be40ac5ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ * feat: Implement `CairoPie::read_zip_file`[#1729](https://github.com/lambdaclass/cairo-vm/pull/1729) +* feat: Implement running from `CairoPie`[#1720](https://github.com/lambdaclass/cairo-vm/pull/1720) + * Add function `cairo_run_pie` + * Add `CairoPie` methods `run_validity_checks` & `check_pie_compatibility` + * Add `Program` method `from_stripped_program` + * feat: Implement `extend_additional_data` for `BuiltinRunner`[#1726](https://github.com/lambdaclass/cairo-vm/pull/1726) * BREAKING: Set dynamic params as null by default on air public input [#1716](https://github.com/lambdaclass/cairo-vm/pull/1716) diff --git a/fuzzer/Cargo.lock b/fuzzer/Cargo.lock index b48dfec845..33f13e1caf 100644 --- a/fuzzer/Cargo.lock +++ b/fuzzer/Cargo.lock @@ -342,7 +342,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -521,9 +521,9 @@ dependencies = [ [[package]] name = "lambdaworks-crypto" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d4c222d5b2fdc0faf702d3ab361d14589b097f40eac9dc550e27083483edc65" +checksum = "458fee521f12d0aa97a2e06eaf134398a5d2ae7b2074af77eb402b0d93138c47" dependencies = [ "lambdaworks-math", "serde", @@ -533,9 +533,9 @@ dependencies = [ [[package]] name = "lambdaworks-math" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee7dcab3968c71896b8ee4dc829147acc918cffe897af6265b1894527fe3add" +checksum = "6c74ce6f0d9cb672330b6ca59e85a6c3607a3329e0372ab0d3fe38c2d38e50f9" dependencies = [ "serde", "serde_json", @@ -699,9 +699,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -784,9 +784,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -853,9 +853,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -944,22 +944,22 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -1045,7 +1045,7 @@ checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ "starknet-curve", "starknet-ff", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -1071,15 +1071,13 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.0.9" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d53160556d1f23425100f42b3230df747ea05763efee685a2cd939dfb640701" +checksum = "b537ba94c95a6c320065653f2a784a395750650c86ef14779be91a233380e9b3" dependencies = [ "arbitrary", - "bitvec", "lambdaworks-crypto", "lambdaworks-math", - "lazy_static", "num-bigint", "num-integer", "num-traits", @@ -1105,9 +1103,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -1216,7 +1214,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", "wasm-bindgen-shared", ] @@ -1238,7 +1236,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1332,7 +1330,7 @@ checksum = "86cd5ca076997b97ef09d3ad65efe811fa68c9e874cb636ccb211223a813b0c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] @@ -1352,7 +1350,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.60", ] [[package]] diff --git a/vm/src/cairo_run.rs b/vm/src/cairo_run.rs index 633b339e7d..4a245dc1b1 100644 --- a/vm/src/cairo_run.rs +++ b/vm/src/cairo_run.rs @@ -1,10 +1,11 @@ use crate::{ hint_processor::hint_processor_definition::HintProcessor, - types::layout_name::LayoutName, - types::program::Program, + types::{builtin_name::BuiltinName, layout_name::LayoutName, program::Program}, vm::{ - errors::{cairo_run_errors::CairoRunError, vm_exception::VmException}, - runners::cairo_runner::CairoRunner, + errors::{ + cairo_run_errors::CairoRunError, runner_errors::RunnerError, vm_exception::VmException, + }, + runners::{cairo_pie::CairoPie, cairo_runner::CairoRunner}, security::verify_secure_runner, vm_core::VirtualMachine, }, @@ -105,6 +106,76 @@ pub fn cairo_run( cairo_run_program(&program, cairo_run_config, hint_executor) } +/// Runs a Cairo PIE generated by a previous cairo execution +/// To generate a cairo pie use the runner's method `get_cairo_pie` +/// Note: Cairo PIEs cannot be ran in proof_mode +/// WARNING: As the RunResources are part of the HintProcessor trait, the caller should make sure that +/// the number of steps in the `RunResources` matches that of the `ExecutionResources` in the `CairoPie`. +/// An error will be returned if this doesn't hold. +pub fn cairo_run_pie( + pie: &CairoPie, + cairo_run_config: &CairoRunConfig, + hint_processor: &mut dyn HintProcessor, +) -> Result<(CairoRunner, VirtualMachine), CairoRunError> { + if cairo_run_config.proof_mode { + return Err(RunnerError::CairoPieProofMode.into()); + } + if !hint_processor + .get_n_steps() + .is_some_and(|steps| steps == pie.execution_resources.n_steps) + { + return Err(RunnerError::PieNStepsVsRunResourcesNStepsMismatch.into()); + } + pie.run_validity_checks()?; + let secure_run = cairo_run_config.secure_run.unwrap_or(true); + + let allow_missing_builtins = cairo_run_config.allow_missing_builtins.unwrap_or_default(); + + let program = Program::from_stripped_program(&pie.metadata.program); + let mut cairo_runner = CairoRunner::new(&program, cairo_run_config.layout, false)?; + + let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled); + let end = cairo_runner.initialize(&mut vm, allow_missing_builtins)?; + vm.finalize_segments_by_cairo_pie(pie); + // Load builtin additional data + for (name, data) in pie.additional_data.0.iter() { + // Data is not trusted in secure_run, therefore we skip extending the hash builtin's data + if matches!(name, BuiltinName::pedersen) && secure_run { + continue; + } + if let Some(builtin) = vm.builtin_runners.iter_mut().find(|b| b.name() == *name) { + builtin.extend_additional_data(data)?; + } + } + // Load previous execution memory + let n_extra_segments = pie.metadata.extra_segments.len(); + vm.segments.load_pie_memory(&pie.memory, n_extra_segments)?; + + cairo_runner + .run_until_pc(end, &mut vm, hint_processor) + .map_err(|err| VmException::from_vm_error(&cairo_runner, &vm, err))?; + + cairo_runner.end_run( + cairo_run_config.disable_trace_padding, + false, + &mut vm, + hint_processor, + )?; + + vm.verify_auto_deductions()?; + cairo_runner.read_return_values(&mut vm, allow_missing_builtins)?; + + if secure_run { + verify_secure_runner(&cairo_runner, true, None, &mut vm)?; + // Check that the Cairo PIE produced by this run is compatible with the Cairo PIE received + cairo_runner + .get_cairo_pie(&vm)? + .check_pie_compatibility(pie)?; + } + cairo_runner.relocate(&mut vm, cairo_run_config.relocate_mem)?; + + Ok((cairo_runner, vm)) +} #[cfg(feature = "arbitrary")] pub fn cairo_run_fuzzed_program( @@ -207,6 +278,7 @@ pub fn write_encoded_memory( mod tests { use super::*; use crate::stdlib::prelude::*; + use crate::vm::runners::cairo_runner::RunResources; use crate::Felt252; use crate::{ hint_processor::{ @@ -217,6 +289,7 @@ mod tests { }; use bincode::enc::write::SliceWriter; + use rstest::rstest; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -377,4 +450,58 @@ mod tests { assert!(cairo_runner.relocate(&mut vm, false).is_ok()); assert!(cairo_runner.relocated_trace.is_none()); } + + #[rstest] + #[case(include_bytes!("../../cairo_programs/fibonacci.json"))] + #[case(include_bytes!("../../cairo_programs/integration.json"))] + #[case(include_bytes!("../../cairo_programs/common_signature.json"))] + #[case(include_bytes!("../../cairo_programs/relocate_segments.json"))] + #[case(include_bytes!("../../cairo_programs/ec_op.json"))] + #[case(include_bytes!("../../cairo_programs/bitwise_output.json"))] + fn get_and_run_cairo_pie(#[case] program_content: &[u8]) { + let cairo_run_config = CairoRunConfig { + layout: LayoutName::starknet_with_keccak, + ..Default::default() + }; + // First run program to get Cairo PIE + let cairo_pie = { + let (runner, vm) = cairo_run( + program_content, + &cairo_run_config, + &mut BuiltinHintProcessor::new_empty(), + ) + .unwrap(); + runner.get_cairo_pie(&vm).unwrap() + }; + let mut hint_processor = BuiltinHintProcessor::new( + Default::default(), + RunResources::new(cairo_pie.execution_resources.n_steps), + ); + // Default config runs with secure_run, which checks that the Cairo PIE produced by this run is compatible with the one received + assert!(cairo_run_pie(&cairo_pie, &cairo_run_config, &mut hint_processor).is_ok()); + } + + #[test] + fn cairo_run_pie_n_steps_not_set() { + // First run program to get Cairo PIE + let cairo_pie = { + let (runner, vm) = cairo_run( + include_bytes!("../../cairo_programs/fibonacci.json"), + &CairoRunConfig::default(), + &mut BuiltinHintProcessor::new_empty(), + ) + .unwrap(); + runner.get_cairo_pie(&vm).unwrap() + }; + // Run Cairo PIE + let res = cairo_run_pie( + &cairo_pie, + &CairoRunConfig::default(), + &mut BuiltinHintProcessor::new_empty(), + ); + assert!(res.is_err_and(|err| matches!( + err, + CairoRunError::Runner(RunnerError::PieNStepsVsRunResourcesNStepsMismatch) + ))); + } } diff --git a/vm/src/tests/cairo_pie_test.rs b/vm/src/tests/cairo_pie_test.rs index 487cbb8341..6b5b6f8e70 100644 --- a/vm/src/tests/cairo_pie_test.rs +++ b/vm/src/tests/cairo_pie_test.rs @@ -274,3 +274,23 @@ fn serialize_cairo_pie() { .unwrap(), ); } + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn run_pie_validity_checks_integration() { + // Run the program + let program_content = include_bytes!("../../../cairo_programs/integration.json"); + let mut hint_processor = BuiltinHintProcessor::new_empty(); + let (runner, vm) = cairo_run( + program_content, + &CairoRunConfig { + layout: LayoutName::all_cairo, + ..Default::default() + }, + &mut hint_processor, + ) + .expect("cairo_run failure"); + // Obtain the pie + let cairo_pie = runner.get_cairo_pie(&vm).expect("Failed to get pie"); + assert!(cairo_pie.run_validity_checks().is_ok()) +} diff --git a/vm/src/types/program.rs b/vm/src/types/program.rs index 956847cd5c..34e332afe9 100644 --- a/vm/src/types/program.rs +++ b/vm/src/types/program.rs @@ -386,6 +386,18 @@ impl Program { }) } + pub fn from_stripped_program(stripped: &StrippedProgram) -> Program { + Program { + shared_program_data: Arc::new(SharedProgramData { + data: stripped.data.clone(), + main: Some(stripped.main), + ..Default::default() + }), + constants: Default::default(), + builtins: stripped.builtins.clone(), + } + } + pub fn serialize(&self) -> Result, ProgramError> { let program_serializer: ProgramSerializer = ProgramSerializer::from(self); let bytes: Vec = serde_json::to_vec(&program_serializer)?; diff --git a/vm/src/vm/errors/cairo_pie_errors.rs b/vm/src/vm/errors/cairo_pie_errors.rs new file mode 100644 index 0000000000..899600d48a --- /dev/null +++ b/vm/src/vm/errors/cairo_pie_errors.rs @@ -0,0 +1,41 @@ +use thiserror_no_std::Error; + +use crate::types::builtin_name::BuiltinName; + +#[derive(Eq, Hash, PartialEq, Debug, Error)] +pub enum CairoPieValidationError { + #[error("Invalid main() address.")] + InvalidMainAddress, + #[error("Program length does not match the program segment size.")] + ProgramLenVsSegmentSizeMismatch, + #[error("Builtin list mismatch in builtin_segments.")] + BuiltinListVsSegmentsMismatch, + #[error("Invalid segment size for ret_fp. Must be 0.")] + InvalidRetFpSegmentSize, + #[error("Invalid segment size for ret_pc. Must be 0.")] + InvalidRetPcSegmentSize, + #[error("Invalid segment index for program_segment.")] + InvalidProgramSegmentIndex, + #[error("Invalid segment index for execution_segment.")] + InvalidExecutionSegmentIndex, + #[error("Invalid segment index for {0}.")] + InvalidBuiltinSegmentIndex(BuiltinName), + #[error("Invalid segment index for ret_fp_segment.")] + InvalidRetFpSegmentIndex, + #[error("Invalid segment index for ret_pc_segment.")] + InvalidRetPcSegmentIndex, + #[error("Invalid segment indices for extra_segments.")] + InvalidExtraSegmentIndex, + #[error("Invalid address")] + InvalidAddress, + #[error("Cairo PIE diff: metadata mismatch")] + DiffMetadata, + #[error("Cairo PIE diff: memory mismatch")] + DiffMemory, + #[error("Cairo PIE diff: execution_resources mismatch")] + DiffExecutionResources, + #[error("Cairo PIE diff: additional_data mismatch")] + DiffAdditionalData, + #[error("Cairo PIE diff: additional_data[{0}] mismatch")] + DiffAdditionalDataForBuiltin(BuiltinName), +} diff --git a/vm/src/vm/errors/cairo_run_errors.rs b/vm/src/vm/errors/cairo_run_errors.rs index 24a8a3552b..7766d472cc 100644 --- a/vm/src/vm/errors/cairo_run_errors.rs +++ b/vm/src/vm/errors/cairo_run_errors.rs @@ -1,5 +1,6 @@ use thiserror_no_std::Error; +use super::cairo_pie_errors::CairoPieValidationError; use super::memory_errors::MemoryError; use super::vm_exception::VmException; use crate::types::errors::program_errors::ProgramError; @@ -21,4 +22,6 @@ pub enum CairoRunError { MemoryError(#[from] MemoryError), #[error(transparent)] VmException(#[from] VmException), + #[error("Cairo Pie validation failed: {0}")] + CairoPieValidation(#[from] CairoPieValidationError), } diff --git a/vm/src/vm/errors/mod.rs b/vm/src/vm/errors/mod.rs index 552f9217d5..eee7ded0e2 100644 --- a/vm/src/vm/errors/mod.rs +++ b/vm/src/vm/errors/mod.rs @@ -1,3 +1,4 @@ +pub mod cairo_pie_errors; pub mod cairo_run_errors; pub mod exec_scope_errors; pub mod hint_errors; diff --git a/vm/src/vm/errors/runner_errors.rs b/vm/src/vm/errors/runner_errors.rs index 91392f4f06..561f89997e 100644 --- a/vm/src/vm/errors/runner_errors.rs +++ b/vm/src/vm/errors/runner_errors.rs @@ -126,6 +126,10 @@ pub enum RunnerError { MissingBuiltin(BuiltinName), #[error("The stop pointer of the missing builtin {0} must be 0")] MissingBuiltinStopPtrNotZero(BuiltinName), + #[error("The number of steps in the Cairo PIE's execution resources does not match the number of steps in the RunResources")] + PieNStepsVsRunResourcesNStepsMismatch, + #[error("A Cairo PIE can not be ran in proof_mode")] + CairoPieProofMode, #[error("{0}: Invalid additional data")] InvalidAdditionalData(BuiltinName), } diff --git a/vm/src/vm/runners/cairo_pie.rs b/vm/src/vm/runners/cairo_pie.rs index 78e6ce9313..856e2b759e 100644 --- a/vm/src/vm/runners/cairo_pie.rs +++ b/vm/src/vm/runners/cairo_pie.rs @@ -1,11 +1,13 @@ use super::cairo_runner::ExecutionResources; use crate::stdlib::prelude::{String, Vec}; use crate::types::builtin_name::BuiltinName; +use crate::vm::errors::cairo_pie_errors::CairoPieValidationError; use crate::{ stdlib::{collections::HashMap, prelude::*}, types::relocatable::{MaybeRelocatable, Relocatable}, Felt252, }; +use num_traits::{One, Zero}; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use { @@ -113,7 +115,138 @@ pub struct CairoPieVersion { pub cairo_pie: (), } +impl CairoPieMetadata { + pub(crate) fn run_validity_checks(&self) -> Result<(), CairoPieValidationError> { + if self.program.main > self.program.data.len() { + return Err(CairoPieValidationError::InvalidMainAddress); + } + if self.program.data.len() != self.program_segment.size { + return Err(CairoPieValidationError::ProgramLenVsSegmentSizeMismatch); + } + if self.builtin_segments.len() != self.program.builtins.len() + || !self + .program + .builtins + .iter() + .all(|b| self.builtin_segments.contains_key(b)) + { + return Err(CairoPieValidationError::BuiltinListVsSegmentsMismatch); + } + if !self.ret_fp_segment.size.is_zero() { + return Err(CairoPieValidationError::InvalidRetFpSegmentSize); + } + if !self.ret_pc_segment.size.is_zero() { + return Err(CairoPieValidationError::InvalidRetPcSegmentSize); + } + self.validate_segment_order() + } + + fn validate_segment_order(&self) -> Result<(), CairoPieValidationError> { + if !self.program_segment.index.is_zero() { + return Err(CairoPieValidationError::InvalidProgramSegmentIndex); + } + if !self.execution_segment.index.is_one() { + return Err(CairoPieValidationError::InvalidExecutionSegmentIndex); + } + for (i, builtin_name) in self.program.builtins.iter().enumerate() { + // We can safely index as run_validity_checks already ensures that the keys match + if self.builtin_segments[builtin_name].index != 2 + i as isize { + return Err(CairoPieValidationError::InvalidBuiltinSegmentIndex( + *builtin_name, + )); + } + } + let n_builtins = self.program.builtins.len() as isize; + if self.ret_fp_segment.index != n_builtins + 2 { + return Err(CairoPieValidationError::InvalidRetFpSegmentIndex); + } + if self.ret_pc_segment.index != n_builtins + 3 { + return Err(CairoPieValidationError::InvalidRetPcSegmentIndex); + } + for (i, segment) in self.extra_segments.iter().enumerate() { + if segment.index != 4 + n_builtins + i as isize { + return Err(CairoPieValidationError::InvalidExtraSegmentIndex); + } + } + Ok(()) + } +} + impl CairoPie { + /// Check that self is a valid Cairo PIE + pub fn run_validity_checks(&self) -> Result<(), CairoPieValidationError> { + self.metadata.run_validity_checks()?; + self.run_memory_validity_checks()?; + if self.execution_resources.builtin_instance_counter.len() + != self.metadata.program.builtins.len() + || !self.metadata.program.builtins.iter().all(|b| { + self.execution_resources + .builtin_instance_counter + .contains_key(b) + }) + { + return Err(CairoPieValidationError::BuiltinListVsSegmentsMismatch); + } + Ok(()) + } + + fn run_memory_validity_checks(&self) -> Result<(), CairoPieValidationError> { + let mut segment_sizes = vec![ + &self.metadata.program_segment, + &self.metadata.execution_segment, + &self.metadata.ret_fp_segment, + &self.metadata.ret_pc_segment, + ]; + segment_sizes.extend(self.metadata.builtin_segments.values()); + segment_sizes.extend(self.metadata.extra_segments.iter()); + let segment_sizes: HashMap = + HashMap::from_iter(segment_sizes.iter().map(|si| (si.index, si.size))); + + let validate_addr = |addr: Relocatable| -> Result<(), CairoPieValidationError> { + if !segment_sizes + .get(&addr.segment_index) + .is_some_and(|size| addr.offset <= *size) + { + return Err(CairoPieValidationError::InvalidAddress); + } + Ok(()) + }; + + for ((si, so), value) in self.memory.0.iter() { + validate_addr((*si as isize, *so).into())?; + if let MaybeRelocatable::RelocatableValue(val) = value { + validate_addr(*val)?; + } + } + Ok(()) + } + + /// Checks that the pie received is identical to self, skipping the fields execution_resources.n_steps, and additional_data[pedersen] + /// Stricter runs check more Pedersen addresses leading to different address lists + pub fn check_pie_compatibility(&self, pie: &CairoPie) -> Result<(), CairoPieValidationError> { + if self.metadata != pie.metadata { + return Err(CairoPieValidationError::DiffMetadata); + } + if self.memory != pie.memory { + return Err(CairoPieValidationError::DiffMemory); + } + if self.execution_resources.n_steps != pie.execution_resources.n_steps + || self.execution_resources.builtin_instance_counter + != pie.execution_resources.builtin_instance_counter + { + return Err(CairoPieValidationError::DiffExecutionResources); + } + if self.additional_data.0.len() != pie.additional_data.0.len() { + return Err(CairoPieValidationError::DiffAdditionalData); + } + for (name, data) in self.additional_data.0.iter() { + if !pie.additional_data.0.get(name).is_some_and(|d| d == data) { + return Err(CairoPieValidationError::DiffAdditionalDataForBuiltin(*name)); + } + } + Ok(()) + } + #[cfg(feature = "std")] pub fn write_zip_file(&self, file_path: &Path) -> Result<(), std::io::Error> { let file = File::create(file_path)?; diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index f8ba07e29c..4fcf978b6a 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -36,6 +36,7 @@ use num_traits::{ToPrimitive, Zero}; use super::errors::runner_errors::RunnerError; use super::runners::builtin_runner::{ModBuiltinRunner, RC_N_PARTS_STANDARD}; +use super::runners::cairo_pie::CairoPie; const MAX_TRACEBACK_ENTRIES: u32 = 20; @@ -1139,6 +1140,21 @@ impl VirtualMachine { ) .map_err(VirtualMachineError::RunnerError) } + + pub(crate) fn finalize_segments_by_cairo_pie(&mut self, pie: &CairoPie) { + let mut segment_infos = vec![ + &pie.metadata.program_segment, + &pie.metadata.execution_segment, + &pie.metadata.ret_fp_segment, + &pie.metadata.ret_pc_segment, + ]; + segment_infos.extend(pie.metadata.builtin_segments.values()); + segment_infos.extend(pie.metadata.extra_segments.iter()); + for info in segment_infos { + self.segments + .finalize(Some(info.size), info.index as usize, None) + } + } } pub struct VirtualMachineBuilder { diff --git a/vm/src/vm/vm_memory/memory_segments.rs b/vm/src/vm/vm_memory/memory_segments.rs index f9886da1a5..a665508483 100644 --- a/vm/src/vm/vm_memory/memory_segments.rs +++ b/vm/src/vm/vm_memory/memory_segments.rs @@ -1,6 +1,7 @@ use core::cmp::max; use core::fmt; +use crate::vm::runners::cairo_pie::CairoPieMemory; use crate::Felt252; use num_traits::Zero; @@ -308,6 +309,22 @@ impl MemorySegmentManager { self.zero_segment_size = 0; } } + + pub(crate) fn load_pie_memory( + &mut self, + pie_memory: &CairoPieMemory, + n_extra_segments: usize, + ) -> Result<(), MemoryError> { + // Create extra segments + for _ in 0..n_extra_segments { + self.add(); + } + // Load previous execution memory + for ((si, so), val) in pie_memory.0.iter() { + self.memory.insert((*si as isize, *so).into(), val)?; + } + Ok(()) + } } impl Default for MemorySegmentManager {