From 5a8aff31e5e748bbba0ff51955f51914eba974e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 13 Mar 2025 14:15:55 -0300 Subject: [PATCH 01/38] Add cairo-lang executable --- Cargo.toml | 1 + vm/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7744e5788d..ac2bf8a748 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,6 +72,7 @@ cairo-lang-sierra-to-casm = { version = "2.10.0-rc.0", default-features = false cairo-lang-sierra = { version = "2.10.0-rc.0", default-features = false } cairo-lang-runner = { version = "2.10.0-rc.0", default-features = false } cairo-lang-utils = { version = "=2.10.0-rc.0", default-features = false } +cairo-lang-executable = { version = "=2.10.0-rc.0", default-features = false } # TODO: check these dependencies for wasm compatibility ark-ff = { version = "0.4.2", default-features = false } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index be960a993c..b86def8b98 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -61,6 +61,7 @@ anyhow = { workspace = true } thiserror = { workspace = true } starknet-types-core = { version = "0.1.2", default-features = false, features = ["serde", "curve", "num-traits", "hash"] } rust_decimal = { version = "1.35.0", default-features = false } +cairo-lang-executable = { workspace = true } # only for std num-prime = { version = "0.4.3", features = ["big-int"], optional = true } From 3ef313d7b533f29e968bd2cbfb5380256f084e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 15:39:54 -0300 Subject: [PATCH 02/38] Add CairoRunner2 definition --- vm/src/vm/runners/cairo_runner_2.rs | 54 +++++++++++++++++++++++++++++ vm/src/vm/runners/mod.rs | 1 + 2 files changed, 55 insertions(+) create mode 100644 vm/src/vm/runners/cairo_runner_2.rs diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs new file mode 100644 index 0000000000..6d146d56e6 --- /dev/null +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -0,0 +1,54 @@ +use std::collections::HashMap; + +use cairo_lang_executable::executable::{EntryPointKind, Executable}; + +use crate::{ + hint_processor::hint_processor_definition::HintReference, + serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, + types::layout::CairoLayout, + vm::errors::vm_errors::VirtualMachineError, + Felt252, +}; + +#[allow(dead_code)] +pub struct CairoRunner2 { + executable: Executable, + entrypoint: EntryPointKind, + layout: CairoLayout, + trace_enabled: bool, + constants: HashMap, + error_message_attributes: Vec, + instruction_locations: Option>, + identifiers: HashMap, + reference_manager: Vec, +} + +impl CairoRunner2 { + pub fn new( + executable: Executable, + entrypoint: EntryPointKind, + layout: CairoLayout, + trace_enabled: bool, + constants: HashMap, + error_message_attributes: Vec, + instruction_locations: Option>, + identifiers: HashMap, + reference_manager: Vec, + ) -> Self { + Self { + executable, + entrypoint, + layout, + trace_enabled, + constants, + error_message_attributes, + instruction_locations, + identifiers, + reference_manager, + } + } + + pub fn run(&mut self) -> Result<(), VirtualMachineError> { + Ok(()) + } +} diff --git a/vm/src/vm/runners/mod.rs b/vm/src/vm/runners/mod.rs index ed5ecaa7dc..30b6dae47d 100644 --- a/vm/src/vm/runners/mod.rs +++ b/vm/src/vm/runners/mod.rs @@ -1,3 +1,4 @@ pub mod builtin_runner; pub mod cairo_pie; pub mod cairo_runner; +pub mod cairo_runner_2; From 0e827c0155172f3133c586087d4357f0a47bd40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 15:51:30 -0300 Subject: [PATCH 03/38] Add new_executable/empty.cairo --- cairo_programs/new_executable/empty.cairo | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 cairo_programs/new_executable/empty.cairo diff --git a/cairo_programs/new_executable/empty.cairo b/cairo_programs/new_executable/empty.cairo new file mode 100644 index 0000000000..a53ef42c03 --- /dev/null +++ b/cairo_programs/new_executable/empty.cairo @@ -0,0 +1,2 @@ +#[executable] +fn main() {} From 0c89a13132ad7e62b9a445819f36b3562818d555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 16:16:08 -0300 Subject: [PATCH 04/38] Add basic test --- vm/Cargo.toml | 1 + vm/src/vm/runners/cairo_runner_2.rs | 34 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index b86def8b98..526cf8af95 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -86,6 +86,7 @@ clap = { version = "4.3.10", features = ["derive"], optional = true} assert_matches = "1.5.0" rstest = { version = "0.17.0", default-features = false } num-prime = { version = "0.4.3", features = ["big-int"] } +cairo-lang-compiler.workspace = true [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.50" diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 6d146d56e6..64b1509f3d 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -52,3 +52,37 @@ impl CairoRunner2 { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use cairo_lang_compiler::diagnostics::DiagnosticsReporter; + use cairo_lang_executable::{compile::compile_executable, executable::Executable}; + use std::path::Path; + + #[test] + fn execute_program() { + let program_path = Path::new("../cairo_programs/new_executable/empty.cairo"); + + let reporter = DiagnosticsReporter::stderr(); + let executable = Executable::new( + compile_executable(program_path, None, reporter).expect("failed to compile program"), + ); + + let layout = CairoLayout::all_cairo_instance(); + + let mut runner = CairoRunner2::new( + executable, + EntryPointKind::Standalone, + layout, + false, + HashMap::default(), + Vec::default(), + None, + HashMap::default(), + Vec::default(), + ); + + runner.run().expect("failed to run program"); + } +} From 0b173f90546b0bc8cde4eec8064878eafa9f38c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 16:53:25 -0300 Subject: [PATCH 05/38] Rename to entrypoint_kind --- vm/src/vm/runners/cairo_runner_2.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 64b1509f3d..b65bd1cb54 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -13,7 +13,7 @@ use crate::{ #[allow(dead_code)] pub struct CairoRunner2 { executable: Executable, - entrypoint: EntryPointKind, + entrypoint_kind: EntryPointKind, layout: CairoLayout, trace_enabled: bool, constants: HashMap, @@ -26,7 +26,7 @@ pub struct CairoRunner2 { impl CairoRunner2 { pub fn new( executable: Executable, - entrypoint: EntryPointKind, + entrypoint_kind: EntryPointKind, layout: CairoLayout, trace_enabled: bool, constants: HashMap, @@ -37,7 +37,7 @@ impl CairoRunner2 { ) -> Self { Self { executable, - entrypoint, + entrypoint_kind, layout, trace_enabled, constants, From bb100efd145e2cb4655ba3215e19200f5adafea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 16:59:45 -0300 Subject: [PATCH 06/38] Add VM to CairoRunner --- vm/src/vm/runners/cairo_runner_2.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index b65bd1cb54..b3eafc48bb 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -6,13 +6,17 @@ use crate::{ hint_processor::hint_processor_definition::HintReference, serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, types::layout::CairoLayout, - vm::errors::vm_errors::VirtualMachineError, + vm::{ + errors::vm_errors::VirtualMachineError, + vm_core::{VirtualMachine, VirtualMachineBuilder}, + }, Felt252, }; #[allow(dead_code)] pub struct CairoRunner2 { executable: Executable, + virtual_machine: VirtualMachine, entrypoint_kind: EntryPointKind, layout: CairoLayout, trace_enabled: bool, @@ -35,8 +39,11 @@ impl CairoRunner2 { identifiers: HashMap, reference_manager: Vec, ) -> Self { + let virtual_machine = VirtualMachineBuilder::default().build(); + Self { executable, + virtual_machine, entrypoint_kind, layout, trace_enabled, From 8ee22adbba25ab1c3433736411add8205fdffa76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 17:25:11 -0300 Subject: [PATCH 07/38] Implement builtin initialization --- vm/src/vm/runners/cairo_runner_2.rs | 184 ++++++++++++++++++++++++++-- 1 file changed, 175 insertions(+), 9 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index b3eafc48bb..9a177f0cce 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -1,13 +1,19 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; -use cairo_lang_executable::executable::{EntryPointKind, Executable}; +use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; use crate::{ hint_processor::hint_processor_definition::HintReference, serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, - types::layout::CairoLayout, + types::{builtin_name::BuiltinName, layout::CairoLayout}, + utils::is_subsequence, vm::{ - errors::vm_errors::VirtualMachineError, + errors::{runner_errors::RunnerError, vm_errors::VirtualMachineError}, + runners::builtin_runner::{ + BitwiseBuiltinRunner, BuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner, + KeccakBuiltinRunner, ModBuiltinRunner, OutputBuiltinRunner, PoseidonBuiltinRunner, + RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD, + }, vm_core::{VirtualMachine, VirtualMachineBuilder}, }, Felt252, @@ -38,10 +44,28 @@ impl CairoRunner2 { instruction_locations: Option>, identifiers: HashMap, reference_manager: Vec, - ) -> Self { - let virtual_machine = VirtualMachineBuilder::default().build(); + ) -> Result { + let entrypoint = executable + .entrypoints + .iter() + .find(|entrypoint| { + // TODO: Use `Eq` once implemented on `EntryPointKind`. + std::mem::discriminant(&entrypoint.kind) == std::mem::discriminant(&entrypoint_kind) + }) + .expect("executable had no entrypoint of required kind"); - Self { + let builtins = get_entrypoint_builtins(entrypoint); + + check_builtin_order(&builtins)?; + + let builtins_set: HashSet = builtins.clone().into_iter().collect(); + let builtin_runners = initialize_builtin_runners(&layout, builtins_set, true, true)?; + + let virtual_machine = VirtualMachineBuilder::default() + .builtin_runners(builtin_runners) + .build(); + + Ok(Self { executable, virtual_machine, entrypoint_kind, @@ -52,7 +76,7 @@ impl CairoRunner2 { instruction_locations, identifiers, reference_manager, - } + }) } pub fn run(&mut self) -> Result<(), VirtualMachineError> { @@ -60,6 +84,147 @@ impl CairoRunner2 { } } +// TODO: Remove this once cyclic dependency is fixed. +// It should not be necessary, but cargo treats executable BuiltinName as a separate type +// which is why I had to create this adapter function. +pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec { + let mut builtins = Vec::with_capacity(entrypoint.builtins.len()); + + for builtin in &entrypoint.builtins { + let adapted_builtin = BuiltinName::from_str(builtin.to_str()) + .expect("should never fail under the same implementation"); + builtins.push(adapted_builtin); + } + + builtins +} + +pub fn check_builtin_order(builtins: &[BuiltinName]) -> Result<(), RunnerError> { + let ordered_builtins = vec![ + BuiltinName::output, + BuiltinName::pedersen, + BuiltinName::range_check, + BuiltinName::ecdsa, + BuiltinName::bitwise, + BuiltinName::ec_op, + BuiltinName::keccak, + BuiltinName::poseidon, + BuiltinName::range_check96, + BuiltinName::add_mod, + BuiltinName::mul_mod, + ]; + if !is_subsequence(builtins, &ordered_builtins) { + return Err(RunnerError::DisorderedBuiltins); + }; + + Ok(()) +} + +pub fn initialize_builtin_runners( + layout: &CairoLayout, + mut builtins: HashSet, + allow_missing_builtins: bool, + create_all_builtins: bool, +) -> Result, RunnerError> { + let mut builtin_runners = Vec::new(); + + if layout.builtins.output { + let included = builtins.remove(&BuiltinName::output); + if included || create_all_builtins { + builtin_runners.push(OutputBuiltinRunner::new(included).into()); + } + } + + if let Some(instance_def) = layout.builtins.pedersen.as_ref() { + let included = builtins.remove(&BuiltinName::pedersen); + if included || create_all_builtins { + builtin_runners.push(HashBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.range_check.as_ref() { + let included = builtins.remove(&BuiltinName::range_check); + if included || create_all_builtins { + builtin_runners.push( + RangeCheckBuiltinRunner::::new_with_low_ratio( + instance_def.ratio, + included, + ) + .into(), + ); + } + } + + if let Some(instance_def) = layout.builtins.ecdsa.as_ref() { + let included = builtins.remove(&BuiltinName::ecdsa); + if included || create_all_builtins { + builtin_runners.push(SignatureBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.bitwise.as_ref() { + let included = builtins.remove(&BuiltinName::bitwise); + if included || create_all_builtins { + builtin_runners.push(BitwiseBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.ec_op.as_ref() { + let included = builtins.remove(&BuiltinName::ec_op); + if included || create_all_builtins { + builtin_runners.push(EcOpBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.keccak.as_ref() { + let included = builtins.remove(&BuiltinName::keccak); + if included || create_all_builtins { + builtin_runners.push(KeccakBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.poseidon.as_ref() { + let included = builtins.remove(&BuiltinName::poseidon); + if included || create_all_builtins { + builtin_runners.push(PoseidonBuiltinRunner::new(instance_def.ratio, included).into()); + } + } + + if let Some(instance_def) = layout.builtins.range_check96.as_ref() { + let included = builtins.remove(&BuiltinName::range_check96); + if included || create_all_builtins { + builtin_runners.push( + RangeCheckBuiltinRunner::::new_with_low_ratio( + instance_def.ratio, + included, + ) + .into(), + ); + } + } + if let Some(instance_def) = layout.builtins.add_mod.as_ref() { + let included = builtins.remove(&BuiltinName::add_mod); + if included || create_all_builtins { + builtin_runners.push(ModBuiltinRunner::new_add_mod(instance_def, included).into()); + } + } + if let Some(instance_def) = layout.builtins.mul_mod.as_ref() { + let included = builtins.remove(&BuiltinName::mul_mod); + if included || create_all_builtins { + builtin_runners.push(ModBuiltinRunner::new_mul_mod(instance_def, included).into()); + } + } + + if !builtins.is_empty() && !allow_missing_builtins { + return Err(RunnerError::NoBuiltinForInstance(Box::new(( + builtins, + layout.name, + )))); + } + + Ok(builtin_runners) +} + #[cfg(test)] mod tests { use super::*; @@ -88,7 +253,8 @@ mod tests { None, HashMap::default(), Vec::default(), - ); + ) + .expect("failed to create runner"); runner.run().expect("failed to run program"); } From 40deae7af32a12ad7a1c4d25edb8ec8c4a8481ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 17:36:42 -0300 Subject: [PATCH 08/38] Implement segment initialization --- vm/src/vm/runners/cairo_runner_2.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 9a177f0cce..68d7875917 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -5,7 +5,7 @@ use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEn use crate::{ hint_processor::hint_processor_definition::HintReference, serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, - types::{builtin_name::BuiltinName, layout::CairoLayout}, + types::{builtin_name::BuiltinName, layout::CairoLayout, relocatable::Relocatable}, utils::is_subsequence, vm::{ errors::{runner_errors::RunnerError, vm_errors::VirtualMachineError}, @@ -15,14 +15,19 @@ use crate::{ RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD, }, vm_core::{VirtualMachine, VirtualMachineBuilder}, + vm_memory::memory_segments::MemorySegmentManager, }, Felt252, }; #[allow(dead_code)] pub struct CairoRunner2 { - executable: Executable, virtual_machine: VirtualMachine, + program_base: Relocatable, + execution_base: Relocatable, + + // Configuration + executable: Executable, entrypoint_kind: EntryPointKind, layout: CairoLayout, trace_enabled: bool, @@ -59,15 +64,26 @@ impl CairoRunner2 { check_builtin_order(&builtins)?; let builtins_set: HashSet = builtins.clone().into_iter().collect(); - let builtin_runners = initialize_builtin_runners(&layout, builtins_set, true, true)?; + let mut builtin_runners = initialize_builtin_runners(&layout, builtins_set, true, true)?; + + let mut memory_segment_manager = MemorySegmentManager::new(); + let program_base = memory_segment_manager.add(); + let execution_base = memory_segment_manager.add(); + + for builtin_runner in &mut builtin_runners { + builtin_runner.initialize_segments(&mut memory_segment_manager); + } let virtual_machine = VirtualMachineBuilder::default() .builtin_runners(builtin_runners) + .segments(memory_segment_manager) .build(); Ok(Self { executable, virtual_machine, + program_base, + execution_base, entrypoint_kind, layout, trace_enabled, From 2ac305288e4fedd16ec6a37722b0ce138f1dfbab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 17:44:47 -0300 Subject: [PATCH 09/38] Implement builtin zero segment initialization --- vm/src/vm/runners/cairo_runner_2.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 68d7875917..8ebb83aeb8 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -74,6 +74,12 @@ impl CairoRunner2 { builtin_runner.initialize_segments(&mut memory_segment_manager); } + for builtin_runner in &mut builtin_runners { + if let BuiltinRunner::Mod(runner) = builtin_runner { + runner.initialize_zero_segment(&mut memory_segment_manager); + } + } + let virtual_machine = VirtualMachineBuilder::default() .builtin_runners(builtin_runners) .segments(memory_segment_manager) From 1e582754b7939928891714e6c9362412ce0acb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 17:54:46 -0300 Subject: [PATCH 10/38] Implement vm initialization --- vm/src/vm/runners/cairo_runner_2.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 8ebb83aeb8..091229605b 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -8,6 +8,7 @@ use crate::{ types::{builtin_name::BuiltinName, layout::CairoLayout, relocatable::Relocatable}, utils::is_subsequence, vm::{ + context::run_context::RunContext, errors::{runner_errors::RunnerError, vm_errors::VirtualMachineError}, runners::builtin_runner::{ BitwiseBuiltinRunner, BuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner, @@ -80,9 +81,26 @@ impl CairoRunner2 { } } + // TODO: implement main entrypoint initialization + let pc = (|| todo!())(); + let ap = (|| todo!())(); + let fp = (|| todo!())(); + + let run_context = RunContext::new(pc, ap, fp); + + for builtin_runner in &mut builtin_runners { + builtin_runner.add_validation_rule(&mut memory_segment_manager.memory) + } + + memory_segment_manager + .memory + .validate_existing_memory() + .map_err(RunnerError::MemoryValidationError)?; + let virtual_machine = VirtualMachineBuilder::default() .builtin_runners(builtin_runners) .segments(memory_segment_manager) + .run_context(run_context) .build(); Ok(Self { From 68435b2539f6fd00de1fe6433256461f7651fc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 18:22:48 -0300 Subject: [PATCH 11/38] Move vm creation to before entrypoint initalization --- vm/src/vm/runners/cairo_runner_2.rs | 20 +++++++++++--------- vm/src/vm/vm_core.rs | 5 +++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 091229605b..7b66b0feb8 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -81,6 +81,11 @@ impl CairoRunner2 { } } + let mut virtual_machine = VirtualMachineBuilder::default() + .builtin_runners(builtin_runners) + .segments(memory_segment_manager) + .build(); + // TODO: implement main entrypoint initialization let pc = (|| todo!())(); let ap = (|| todo!())(); @@ -88,21 +93,18 @@ impl CairoRunner2 { let run_context = RunContext::new(pc, ap, fp); - for builtin_runner in &mut builtin_runners { - builtin_runner.add_validation_rule(&mut memory_segment_manager.memory) + for builtin_runner in &mut virtual_machine.builtin_runners { + builtin_runner.add_validation_rule(&mut virtual_machine.segments.memory) } - memory_segment_manager + virtual_machine.set_run_context(run_context); + + virtual_machine + .segments .memory .validate_existing_memory() .map_err(RunnerError::MemoryValidationError)?; - let virtual_machine = VirtualMachineBuilder::default() - .builtin_runners(builtin_runners) - .segments(memory_segment_manager) - .run_context(run_context) - .build(); - Ok(Self { executable, virtual_machine, diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index 1c0a59682e..0f32bbb589 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -1067,6 +1067,11 @@ impl VirtualMachine { self.run_context.set_pc(pc) } + #[doc(hidden)] + pub fn set_run_context(&mut self, run_context: RunContext) { + self.run_context = run_context; + } + pub fn get_segment_used_size(&self, index: usize) -> Option { self.segments.get_segment_used_size(index) } From f54443c6e925ba3b27eaac540b129378a096fdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 18:44:39 -0300 Subject: [PATCH 12/38] Implement entrypoint initalization --- vm/src/vm/runners/cairo_runner_2.rs | 60 +++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 7b66b0feb8..02e464e0a5 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -5,7 +5,11 @@ use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEn use crate::{ hint_processor::hint_processor_definition::HintReference, serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, - types::{builtin_name::BuiltinName, layout::CairoLayout, relocatable::Relocatable}, + types::{ + builtin_name::BuiltinName, + layout::CairoLayout, + relocatable::{MaybeRelocatable, Relocatable}, + }, utils::is_subsequence, vm::{ context::run_context::RunContext, @@ -86,19 +90,59 @@ impl CairoRunner2 { .segments(memory_segment_manager) .build(); - // TODO: implement main entrypoint initialization - let pc = (|| todo!())(); - let ap = (|| todo!())(); - let fp = (|| todo!())(); + let builtin_runner_map: HashMap = virtual_machine + .builtin_runners + .iter() + .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) + .collect(); + let mut stack = Vec::new(); + for builtin in builtins { + if let Some(builtin_runner) = builtin_runner_map.get(&builtin) { + stack.append(&mut builtin_runner.initial_stack()); + } else { + stack.push(Felt252::ZERO.into()) + } + } + + let return_fp = virtual_machine.add_memory_segment(); + let return_pc = virtual_machine.add_memory_segment(); + stack.push(MaybeRelocatable::RelocatableValue(return_fp)); + stack.push(MaybeRelocatable::RelocatableValue(return_pc)); + + let initial_pc = (program_base + entrypoint.offset)?; + let initial_fp = (execution_base + stack.len())?; + let initial_ap = initial_fp; + + let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); + virtual_machine.set_run_context(run_context); + + let bytecode = executable + .program + .bytecode + .iter() + .map(Felt252::from) + .map(MaybeRelocatable::from) + .collect::>(); + + virtual_machine + .load_data(program_base, &bytecode) + .map_err(RunnerError::MemoryInitializationError)?; + + for i in 0..bytecode.len() { + virtual_machine + .segments + .memory + .mark_as_accessed((program_base + i)?); + } - let run_context = RunContext::new(pc, ap, fp); + virtual_machine + .load_data(execution_base, &stack) + .map_err(RunnerError::MemoryInitializationError)?; for builtin_runner in &mut virtual_machine.builtin_runners { builtin_runner.add_validation_rule(&mut virtual_machine.segments.memory) } - virtual_machine.set_run_context(run_context); - virtual_machine .segments .memory From 3d32addf280221068366a376b35d732d9691e0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 18 Mar 2025 18:50:26 -0300 Subject: [PATCH 13/38] Save final_pc in structure --- vm/src/vm/runners/cairo_runner_2.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 02e464e0a5..c87093678a 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -30,6 +30,7 @@ pub struct CairoRunner2 { virtual_machine: VirtualMachine, program_base: Relocatable, execution_base: Relocatable, + final_pc: Relocatable, // Configuration executable: Executable, @@ -149,11 +150,17 @@ impl CairoRunner2 { .validate_existing_memory() .map_err(RunnerError::MemoryValidationError)?; + let final_pc = match entrypoint_kind { + EntryPointKind::Bootloader => return_pc, + EntryPointKind::Standalone => (initial_pc + 4)?, + }; + Ok(Self { executable, virtual_machine, program_base, execution_base, + final_pc, entrypoint_kind, layout, trace_enabled, From 6be8f62aa17a9bb21f67d77ad6a777dafcfc65db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 10:27:24 -0300 Subject: [PATCH 14/38] Reorder code --- vm/src/vm/runners/cairo_runner_2.rs | 128 +++++++++++++++------------- 1 file changed, 69 insertions(+), 59 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index c87093678a..5a956d3df6 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -27,7 +27,7 @@ use crate::{ #[allow(dead_code)] pub struct CairoRunner2 { - virtual_machine: VirtualMachine, + vm: VirtualMachine, program_base: Relocatable, execution_base: Relocatable, final_pc: Relocatable, @@ -56,66 +56,37 @@ impl CairoRunner2 { identifiers: HashMap, reference_manager: Vec, ) -> Result { - let entrypoint = executable - .entrypoints - .iter() - .find(|entrypoint| { - // TODO: Use `Eq` once implemented on `EntryPointKind`. - std::mem::discriminant(&entrypoint.kind) == std::mem::discriminant(&entrypoint_kind) - }) - .expect("executable had no entrypoint of required kind"); + let entrypoint = find_entrypoint_of_kind(&executable.entrypoints, entrypoint_kind.clone()); let builtins = get_entrypoint_builtins(entrypoint); check_builtin_order(&builtins)?; + let mut builtin_runners = initialize_builtin_runners(&layout, &builtins, true, true)?; - let builtins_set: HashSet = builtins.clone().into_iter().collect(); - let mut builtin_runners = initialize_builtin_runners(&layout, builtins_set, true, true)?; - - let mut memory_segment_manager = MemorySegmentManager::new(); - let program_base = memory_segment_manager.add(); - let execution_base = memory_segment_manager.add(); + let mut segments = MemorySegmentManager::new(); + let program_base = segments.add(); + let execution_base = segments.add(); - for builtin_runner in &mut builtin_runners { - builtin_runner.initialize_segments(&mut memory_segment_manager); - } + initialize_builtin_runner_segments(&mut builtin_runners, &mut segments); - for builtin_runner in &mut builtin_runners { - if let BuiltinRunner::Mod(runner) = builtin_runner { - runner.initialize_zero_segment(&mut memory_segment_manager); - } - } - - let mut virtual_machine = VirtualMachineBuilder::default() + let mut vm = VirtualMachineBuilder::default() .builtin_runners(builtin_runners) - .segments(memory_segment_manager) + .segments(segments) .build(); - let builtin_runner_map: HashMap = virtual_machine - .builtin_runners - .iter() - .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) - .collect(); let mut stack = Vec::new(); - for builtin in builtins { - if let Some(builtin_runner) = builtin_runner_map.get(&builtin) { - stack.append(&mut builtin_runner.initial_stack()); - } else { - stack.push(Felt252::ZERO.into()) - } - } + extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); - let return_fp = virtual_machine.add_memory_segment(); - let return_pc = virtual_machine.add_memory_segment(); + let return_fp = vm.add_memory_segment(); + let return_pc = vm.add_memory_segment(); stack.push(MaybeRelocatable::RelocatableValue(return_fp)); stack.push(MaybeRelocatable::RelocatableValue(return_pc)); let initial_pc = (program_base + entrypoint.offset)?; let initial_fp = (execution_base + stack.len())?; let initial_ap = initial_fp; - let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); - virtual_machine.set_run_context(run_context); + vm.set_run_context(run_context); let bytecode = executable .program @@ -124,28 +95,19 @@ impl CairoRunner2 { .map(Felt252::from) .map(MaybeRelocatable::from) .collect::>(); - - virtual_machine - .load_data(program_base, &bytecode) + vm.load_data(program_base, &bytecode) .map_err(RunnerError::MemoryInitializationError)?; - for i in 0..bytecode.len() { - virtual_machine - .segments - .memory - .mark_as_accessed((program_base + i)?); + vm.segments.memory.mark_as_accessed((program_base + i)?); } - virtual_machine - .load_data(execution_base, &stack) + vm.load_data(execution_base, &stack) .map_err(RunnerError::MemoryInitializationError)?; - for builtin_runner in &mut virtual_machine.builtin_runners { - builtin_runner.add_validation_rule(&mut virtual_machine.segments.memory) + for builtin_runner in &mut vm.builtin_runners { + builtin_runner.add_validation_rule(&mut vm.segments.memory) } - - virtual_machine - .segments + vm.segments .memory .validate_existing_memory() .map_err(RunnerError::MemoryValidationError)?; @@ -157,7 +119,7 @@ impl CairoRunner2 { Ok(Self { executable, - virtual_machine, + vm, program_base, execution_base, final_pc, @@ -177,6 +139,52 @@ impl CairoRunner2 { } } +fn find_entrypoint_of_kind( + entrypoints: &[ExecutableEntryPoint], + entrypoint_kind: EntryPointKind, +) -> &ExecutableEntryPoint { + entrypoints + .iter() + .find(|entrypoint| { + // TODO: Use `Eq` once implemented on `EntryPointKind`. + std::mem::discriminant(&entrypoint.kind) == std::mem::discriminant(&entrypoint_kind) + }) + .expect("executable had no entrypoint of required kind") +} + +fn extend_stack_with_builtins( + stack: &mut Vec, + builtins: &[BuiltinName], + runners: &[BuiltinRunner], +) { + let runner_map: HashMap = runners + .iter() + .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) + .collect(); + for builtin in builtins { + if let Some(builtin_runner) = runner_map.get(&builtin) { + stack.append(&mut builtin_runner.initial_stack()); + } else { + stack.push(Felt252::ZERO.into()) + } + } +} + +fn initialize_builtin_runner_segments( + builtin_runners: &mut [BuiltinRunner], + segments: &mut MemorySegmentManager, +) { + for builtin_runner in builtin_runners.iter_mut() { + builtin_runner.initialize_segments(segments); + } + + for builtin_runner in builtin_runners.iter_mut() { + if let BuiltinRunner::Mod(mod_builtin_runner) = builtin_runner { + mod_builtin_runner.initialize_zero_segment(segments); + } + } +} + // TODO: Remove this once cyclic dependency is fixed. // It should not be necessary, but cargo treats executable BuiltinName as a separate type // which is why I had to create this adapter function. @@ -215,12 +223,14 @@ pub fn check_builtin_order(builtins: &[BuiltinName]) -> Result<(), RunnerError> pub fn initialize_builtin_runners( layout: &CairoLayout, - mut builtins: HashSet, + builtins: &[BuiltinName], allow_missing_builtins: bool, create_all_builtins: bool, ) -> Result, RunnerError> { let mut builtin_runners = Vec::new(); + let mut builtins: HashSet = builtins.into_iter().map(ToOwned::to_owned).collect(); + if layout.builtins.output { let included = builtins.remove(&BuiltinName::output); if included || create_all_builtins { From 883085a0d9ea92fb41815cb0fb4a131b88092f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 10:35:46 -0300 Subject: [PATCH 15/38] Add hint processor to run function --- vm/src/vm/runners/cairo_runner_2.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 5a956d3df6..6ad4a9e108 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet}; use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; use crate::{ - hint_processor::hint_processor_definition::HintReference, + hint_processor::hint_processor_definition::{HintProcessor, HintReference}, serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, types::{ builtin_name::BuiltinName, @@ -134,7 +134,10 @@ impl CairoRunner2 { }) } - pub fn run(&mut self) -> Result<(), VirtualMachineError> { + pub fn run( + &mut self, + _hint_processor: &mut dyn HintProcessor, + ) -> Result<(), VirtualMachineError> { Ok(()) } } @@ -330,6 +333,8 @@ pub fn initialize_builtin_runners( #[cfg(test)] mod tests { + use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; + use super::*; use cairo_lang_compiler::diagnostics::DiagnosticsReporter; use cairo_lang_executable::{compile::compile_executable, executable::Executable}; @@ -359,6 +364,9 @@ mod tests { ) .expect("failed to create runner"); - runner.run().expect("failed to run program"); + let mut hint_processor = BuiltinHintProcessor::new_empty(); + runner + .run(&mut hint_processor) + .expect("failed to run program"); } } From 7e7c6be86ffcaf9e0f4f2e35f290e0dcb51e8856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 10:54:28 -0300 Subject: [PATCH 16/38] Generate HintsCollection --- vm/src/vm/runners/cairo_runner_2.rs | 42 +++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 6ad4a9e108..27fdf4ce3e 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -1,13 +1,17 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; +use cairo_lang_casm::hints::Hint; use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; use crate::{ hint_processor::hint_processor_definition::{HintProcessor, HintReference}, - serde::deserialize_program::{Attribute, Identifier, InstructionLocation}, + serde::deserialize_program::{ + ApTracking, Attribute, FlowTrackingData, HintParams, Identifier, InstructionLocation, + }, types::{ builtin_name::BuiltinName, layout::CairoLayout, + program::HintsCollection, relocatable::{MaybeRelocatable, Relocatable}, }, utils::is_subsequence, @@ -42,6 +46,9 @@ pub struct CairoRunner2 { instruction_locations: Option>, identifiers: HashMap, reference_manager: Vec, + + // Preprocessed Data + hint_collection: HintsCollection, } impl CairoRunner2 { @@ -117,6 +124,8 @@ impl CairoRunner2 { EntryPointKind::Standalone => (initial_pc + 4)?, }; + let hint_collection = build_hint_collection(&executable.program.hints, bytecode.len()); + Ok(Self { executable, vm, @@ -131,6 +140,7 @@ impl CairoRunner2 { instruction_locations, identifiers, reference_manager, + hint_collection, }) } @@ -203,6 +213,34 @@ pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec)], + program_length: usize, +) -> HintsCollection { + let mut hint_map: BTreeMap> = BTreeMap::new(); + + for (offset, offset_hints) in hints { + hint_map.insert( + *offset, + offset_hints + .iter() + .map(|hint| HintParams { + code: hint.representing_string(), + accessible_scopes: vec![], + flow_tracking_data: FlowTrackingData { + ap_tracking: ApTracking::new(), + reference_ids: HashMap::new(), + }, + }) + .collect(), + ); + } + + HintsCollection::new(&hint_map, program_length).expect("failed to build hint collection") +} + pub fn check_builtin_order(builtins: &[BuiltinName]) -> Result<(), RunnerError> { let ordered_builtins = vec![ BuiltinName::output, From 0779205ae1ab1a1df1b4fc83cc6e7d5c886d1354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 10:55:27 -0300 Subject: [PATCH 17/38] Use stdlib intead of std --- vm/src/vm/runners/cairo_runner_2.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 27fdf4ce3e..9d980fc9b0 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -1,5 +1,3 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; - use cairo_lang_casm::hints::Hint; use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; @@ -8,6 +6,7 @@ use crate::{ serde::deserialize_program::{ ApTracking, Attribute, FlowTrackingData, HintParams, Identifier, InstructionLocation, }, + stdlib::collections::{BTreeMap, HashMap, HashSet}, types::{ builtin_name::BuiltinName, layout::CairoLayout, From 8ce65ab21ab543b0e48d2458b74dfd17fab1ebc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 10:59:20 -0300 Subject: [PATCH 18/38] Improve comment --- vm/src/vm/runners/cairo_runner_2.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 9d980fc9b0..d3f2ca0589 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -197,9 +197,9 @@ fn initialize_builtin_runner_segments( } } -// TODO: Remove this once cyclic dependency is fixed. -// It should not be necessary, but cargo treats executable BuiltinName as a separate type -// which is why I had to create this adapter function. +/// TODO: Remove this once cyclic dependency is fixed. +/// It should not be necessary, but cargo treats executable BuiltinName as a separate type +/// which is why I had to create this adapter function. pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec { let mut builtins = Vec::with_capacity(entrypoint.builtins.len()); From 3278f2fd738a03c330f327b42cee3e5149575b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 11:03:08 -0300 Subject: [PATCH 19/38] Reorder functions --- vm/src/vm/runners/cairo_runner_2.rs | 152 ++++++++++++++-------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index d3f2ca0589..610056c860 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -164,82 +164,6 @@ fn find_entrypoint_of_kind( .expect("executable had no entrypoint of required kind") } -fn extend_stack_with_builtins( - stack: &mut Vec, - builtins: &[BuiltinName], - runners: &[BuiltinRunner], -) { - let runner_map: HashMap = runners - .iter() - .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) - .collect(); - for builtin in builtins { - if let Some(builtin_runner) = runner_map.get(&builtin) { - stack.append(&mut builtin_runner.initial_stack()); - } else { - stack.push(Felt252::ZERO.into()) - } - } -} - -fn initialize_builtin_runner_segments( - builtin_runners: &mut [BuiltinRunner], - segments: &mut MemorySegmentManager, -) { - for builtin_runner in builtin_runners.iter_mut() { - builtin_runner.initialize_segments(segments); - } - - for builtin_runner in builtin_runners.iter_mut() { - if let BuiltinRunner::Mod(mod_builtin_runner) = builtin_runner { - mod_builtin_runner.initialize_zero_segment(segments); - } - } -} - -/// TODO: Remove this once cyclic dependency is fixed. -/// It should not be necessary, but cargo treats executable BuiltinName as a separate type -/// which is why I had to create this adapter function. -pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec { - let mut builtins = Vec::with_capacity(entrypoint.builtins.len()); - - for builtin in &entrypoint.builtins { - let adapted_builtin = BuiltinName::from_str(builtin.to_str()) - .expect("should never fail under the same implementation"); - builtins.push(adapted_builtin); - } - - builtins -} - -/// TODO: Determine if we receive the hint collection or build it ourselves -/// This function was adapted from cairo-lang-runner -pub fn build_hint_collection( - hints: &[(usize, Vec)], - program_length: usize, -) -> HintsCollection { - let mut hint_map: BTreeMap> = BTreeMap::new(); - - for (offset, offset_hints) in hints { - hint_map.insert( - *offset, - offset_hints - .iter() - .map(|hint| HintParams { - code: hint.representing_string(), - accessible_scopes: vec![], - flow_tracking_data: FlowTrackingData { - ap_tracking: ApTracking::new(), - reference_ids: HashMap::new(), - }, - }) - .collect(), - ); - } - - HintsCollection::new(&hint_map, program_length).expect("failed to build hint collection") -} - pub fn check_builtin_order(builtins: &[BuiltinName]) -> Result<(), RunnerError> { let ordered_builtins = vec![ BuiltinName::output, @@ -368,6 +292,82 @@ pub fn initialize_builtin_runners( Ok(builtin_runners) } +fn initialize_builtin_runner_segments( + builtin_runners: &mut [BuiltinRunner], + segments: &mut MemorySegmentManager, +) { + for builtin_runner in builtin_runners.iter_mut() { + builtin_runner.initialize_segments(segments); + } + + for builtin_runner in builtin_runners.iter_mut() { + if let BuiltinRunner::Mod(mod_builtin_runner) = builtin_runner { + mod_builtin_runner.initialize_zero_segment(segments); + } + } +} + +fn extend_stack_with_builtins( + stack: &mut Vec, + builtins: &[BuiltinName], + runners: &[BuiltinRunner], +) { + let runner_map: HashMap = runners + .iter() + .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) + .collect(); + for builtin in builtins { + if let Some(builtin_runner) = runner_map.get(&builtin) { + stack.append(&mut builtin_runner.initial_stack()); + } else { + stack.push(Felt252::ZERO.into()) + } + } +} + +/// TODO: Remove this once cyclic dependency is fixed. +/// It should not be necessary, but cargo treats executable BuiltinName as a separate type +/// which is why I had to create this adapter function. +pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec { + let mut builtins = Vec::with_capacity(entrypoint.builtins.len()); + + for builtin in &entrypoint.builtins { + let adapted_builtin = BuiltinName::from_str(builtin.to_str()) + .expect("should never fail under the same implementation"); + builtins.push(adapted_builtin); + } + + builtins +} + +/// TODO: Determine if we receive the hint collection or build it ourselves +/// This function was adapted from cairo-lang-runner +pub fn build_hint_collection( + hints: &[(usize, Vec)], + program_length: usize, +) -> HintsCollection { + let mut hint_map: BTreeMap> = BTreeMap::new(); + + for (offset, offset_hints) in hints { + hint_map.insert( + *offset, + offset_hints + .iter() + .map(|hint| HintParams { + code: hint.representing_string(), + accessible_scopes: vec![], + flow_tracking_data: FlowTrackingData { + ap_tracking: ApTracking::new(), + reference_ids: HashMap::new(), + }, + }) + .collect(), + ); + } + + HintsCollection::new(&hint_map, program_length).expect("failed to build hint collection") +} + #[cfg(test)] mod tests { use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; From 9a561489eccf82dcb14a9ff68bdb47ae0b323791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 11:12:13 -0300 Subject: [PATCH 20/38] Build hint data --- vm/src/vm/runners/cairo_runner_2.rs | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 610056c860..f049bb5a41 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -1,3 +1,5 @@ +use core::any::Any; + use cairo_lang_casm::hints::Hint; use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; @@ -145,8 +147,17 @@ impl CairoRunner2 { pub fn run( &mut self, - _hint_processor: &mut dyn HintProcessor, + hint_processor: &mut dyn HintProcessor, ) -> Result<(), VirtualMachineError> { + #[allow(unused_mut)] + let mut hint_data = get_hint_data( + &self.hint_collection, + &self.reference_manager, + hint_processor, + )?; + + let _ = hint_data; + Ok(()) } } @@ -325,6 +336,26 @@ fn extend_stack_with_builtins( } } +fn get_hint_data( + collection: &HintsCollection, + references: &[HintReference], + processor: &dyn HintProcessor, +) -> Result>, VirtualMachineError> { + collection + .iter_hints() + .map(|hint| { + processor + .compile_hint( + &hint.code, + &hint.flow_tracking_data.ap_tracking, + &hint.flow_tracking_data.reference_ids, + references, + ) + .map_err(|_| VirtualMachineError::CompileHintFail(hint.code.clone().into())) + }) + .collect() +} + /// TODO: Remove this once cyclic dependency is fixed. /// It should not be necessary, but cargo treats executable BuiltinName as a separate type /// which is why I had to create this adapter function. From e789c5339ab4cac5b2eaa3e7909dfe3b435af095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 11:28:18 -0300 Subject: [PATCH 21/38] Implement run --- vm/src/vm/runners/cairo_runner_2.rs | 36 +++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index f049bb5a41..d67adeb5fe 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -11,6 +11,7 @@ use crate::{ stdlib::collections::{BTreeMap, HashMap, HashSet}, types::{ builtin_name::BuiltinName, + exec_scope::ExecutionScopes, layout::CairoLayout, program::HintsCollection, relocatable::{MaybeRelocatable, Relocatable}, @@ -36,6 +37,7 @@ pub struct CairoRunner2 { program_base: Relocatable, execution_base: Relocatable, final_pc: Relocatable, + execution_scopes: ExecutionScopes, // Configuration executable: Executable, @@ -133,6 +135,7 @@ impl CairoRunner2 { program_base, execution_base, final_pc, + execution_scopes: ExecutionScopes::new(), entrypoint_kind, layout, trace_enabled, @@ -149,14 +152,43 @@ impl CairoRunner2 { &mut self, hint_processor: &mut dyn HintProcessor, ) -> Result<(), VirtualMachineError> { - #[allow(unused_mut)] + #[cfg_attr(not(feature = "extensive_hints"), allow(unused_mut))] let mut hint_data = get_hint_data( &self.hint_collection, &self.reference_manager, hint_processor, )?; - let _ = hint_data; + #[cfg(feature = "extensive_hints")] + let mut hint_ranges = self.hint_collection.hints_ranges.clone(); + + while self.vm.get_pc() != self.final_pc && !hint_processor.consumed() { + #[cfg(feature = "extensive_hints")] + let hint_data = &mut hint_data; + #[cfg(not(feature = "extensive_hints"))] + let hint_data = self + .hint_collection + .get_hint_range_for_pc(self.vm.get_pc().offset) + .and_then(|range| { + range.and_then(|(start, length)| hint_data.get(start..start + length.get())) + }) + .unwrap_or(&[]); + + self.vm.step( + hint_processor, + &mut self.execution_scopes, + hint_data, + #[cfg(feature = "extensive_hints")] + &mut hint_ranges, + &self.constants, + )?; + + hint_processor.consume_step(); + } + + if self.vm.get_pc() != self.final_pc { + return Err(VirtualMachineError::UnfinishedExecution); + } Ok(()) } From eddeadad0107e570da97be8908ce04512ffacc25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 14:38:20 -0300 Subject: [PATCH 22/38] Remove test --- vm/src/vm/runners/cairo_runner_2.rs | 40 ----------------------------- 1 file changed, 40 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index d67adeb5fe..e43106aa60 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -430,43 +430,3 @@ pub fn build_hint_collection( HintsCollection::new(&hint_map, program_length).expect("failed to build hint collection") } - -#[cfg(test)] -mod tests { - use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; - - use super::*; - use cairo_lang_compiler::diagnostics::DiagnosticsReporter; - use cairo_lang_executable::{compile::compile_executable, executable::Executable}; - use std::path::Path; - - #[test] - fn execute_program() { - let program_path = Path::new("../cairo_programs/new_executable/empty.cairo"); - - let reporter = DiagnosticsReporter::stderr(); - let executable = Executable::new( - compile_executable(program_path, None, reporter).expect("failed to compile program"), - ); - - let layout = CairoLayout::all_cairo_instance(); - - let mut runner = CairoRunner2::new( - executable, - EntryPointKind::Standalone, - layout, - false, - HashMap::default(), - Vec::default(), - None, - HashMap::default(), - Vec::default(), - ) - .expect("failed to create runner"); - - let mut hint_processor = BuiltinHintProcessor::new_empty(); - runner - .run(&mut hint_processor) - .expect("failed to run program"); - } -} From 75511cb2b1776cd8b70f9682cbcda7fba321b079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 14:39:29 -0300 Subject: [PATCH 23/38] Fix deps --- vm/Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 526cf8af95..da58aff97a 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -22,7 +22,6 @@ std = [ ] cairo-1-hints = [ "dep:cairo-lang-starknet", - "dep:cairo-lang-casm", "dep:cairo-lang-starknet-classes", "dep:ark-ff", "dep:ark-std", @@ -61,7 +60,10 @@ anyhow = { workspace = true } thiserror = { workspace = true } starknet-types-core = { version = "0.1.2", default-features = false, features = ["serde", "curve", "num-traits", "hash"] } rust_decimal = { version = "1.35.0", default-features = false } + +# cairo-lang dependencies cairo-lang-executable = { workspace = true } +cairo-lang-casm = { workspace = true } # only for std num-prime = { version = "0.4.3", features = ["big-int"], optional = true } @@ -70,7 +72,6 @@ bitvec = { workspace = true } # Dependencies for cairo-1-hints feature cairo-lang-starknet = { workspace = true, optional = true } cairo-lang-starknet-classes = { workspace = true, optional = true } -cairo-lang-casm = { workspace = true, optional = true } # TODO: check these dependencies for wasm compatibility ark-ff = { workspace = true, optional = true } From cc11553eacd04ee090253ad1da38ab77568524e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 14:39:42 -0300 Subject: [PATCH 24/38] Update lock --- Cargo.lock | 333 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 322 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f1cca0486..3044fb402a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.11" @@ -227,8 +238,8 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "zstd", - "zstd-safe", + "zstd 0.13.3", + "zstd-safe 7.2.3", ] [[package]] @@ -318,6 +329,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -445,6 +462,26 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "cairo-lang-casm" version = "2.10.0-rc.0" @@ -533,6 +570,31 @@ dependencies = [ "good_lp", ] +[[package]] +name = "cairo-lang-executable" +version = "2.10.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e1372cbef644001d7a73364581b9b1348add79aba5ec9f9e7a9ce0fe0980c4" +dependencies = [ + "anyhow", + "cairo-lang-casm", + "cairo-lang-compiler", + "cairo-lang-defs", + "cairo-lang-filesystem", + "cairo-lang-lowering", + "cairo-lang-plugins", + "cairo-lang-runnable-utils", + "cairo-lang-semantic", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-syntax", + "cairo-lang-utils", + "cairo-vm 1.0.2", + "indoc", + "itertools 0.12.1", + "serde", +] + [[package]] name = "cairo-lang-filesystem" version = "2.10.0-rc.0" @@ -663,6 +725,24 @@ dependencies = [ "toml", ] +[[package]] +name = "cairo-lang-runnable-utils" +version = "2.10.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951b72522c8a76e177119699bdcd3c4288bdc0bc784ac22dd7c0f80b2a7444d0" +dependencies = [ + "cairo-lang-casm", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", + "cairo-lang-sierra-to-casm", + "cairo-lang-sierra-type-size", + "cairo-lang-utils", + "cairo-vm 1.0.2", + "itertools 0.12.1", + "thiserror 1.0.69", +] + [[package]] name = "cairo-lang-semantic" version = "2.10.0-rc.0" @@ -912,6 +992,37 @@ dependencies = [ "serde", ] +[[package]] +name = "cairo-vm" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fa8b4b56ee66cebcade4d85128e55b2bfdf046502187aeaa8c2768a427684dc" +dependencies = [ + "anyhow", + "bincode", + "bitvec", + "generic-array", + "hashbrown 0.14.5", + "hex", + "keccak", + "lazy_static", + "nom", + "num-bigint", + "num-integer", + "num-prime", + "num-traits", + "rand", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "sha3", + "starknet-crypto 0.6.2", + "starknet-types-core", + "thiserror-no-std", + "zip", +] + [[package]] name = "cairo-vm" version = "2.0.1" @@ -924,6 +1035,8 @@ dependencies = [ "bincode", "bitvec", "cairo-lang-casm", + "cairo-lang-compiler", + "cairo-lang-executable", "cairo-lang-starknet", "cairo-lang-starknet-classes", "clap", @@ -950,7 +1063,7 @@ dependencies = [ "serde_json", "sha2", "sha3", - "starknet-crypto", + "starknet-crypto 0.7.4", "starknet-types-core", "thiserror 2.0.12", "wasm-bindgen-test", @@ -963,7 +1076,7 @@ version = "2.0.1" dependencies = [ "assert_matches", "bincode", - "cairo-vm", + "cairo-vm 2.0.1", "cairo-vm-tracer", "clap", "mimalloc", @@ -977,7 +1090,7 @@ name = "cairo-vm-tracer" version = "2.0.1" dependencies = [ "axum", - "cairo-vm", + "cairo-vm 2.0.1", "include_dir", "mime_guess", "num-bigint", @@ -1006,7 +1119,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-starknet-classes", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 2.0.1", "clap", "itertools 0.11.0", "mimalloc", @@ -1067,6 +1180,16 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.31" @@ -1159,6 +1282,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.6.0" @@ -1274,6 +1403,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1677,7 +1815,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" name = "hint_accountant" version = "2.0.1" dependencies = [ - "cairo-vm", + "cairo-vm 2.0.1", "serde", "serde_json", ] @@ -1758,7 +1896,7 @@ dependencies = [ name = "hyper_threading" version = "2.0.1" dependencies = [ - "cairo-vm", + "cairo-vm 2.0.1", "rayon", "tracing", ] @@ -1855,6 +1993,15 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "iri-string" version = "0.7.7" @@ -2217,6 +2364,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -2340,6 +2493,17 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -2352,6 +2516,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2464,6 +2640,12 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2924,6 +3106,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -3024,6 +3217,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "starknet-crypto" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2c30c01e8eb0fc913c4ee3cf676389fffc1d1182bfe5bb9670e4e72e968064" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-crypto-codegen", + "starknet-curve 0.4.2", + "starknet-ff", + "zeroize", +] + [[package]] name = "starknet-crypto" version = "0.7.4" @@ -3038,11 +3251,31 @@ dependencies = [ "num-traits", "rfc6979", "sha2", - "starknet-curve", + "starknet-curve 0.5.1", "starknet-types-core", "zeroize", ] +[[package]] +name = "starknet-crypto-codegen" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" +dependencies = [ + "starknet-curve 0.4.2", + "starknet-ff", + "syn 2.0.98", +] + +[[package]] +name = "starknet-curve" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c383518bb312751e4be80f53e8644034aa99a0afb29d7ac41b89a997db875b" +dependencies = [ + "starknet-ff", +] + [[package]] name = "starknet-curve" version = "0.5.1" @@ -3052,6 +3285,18 @@ dependencies = [ "starknet-types-core", ] +[[package]] +name = "starknet-ff" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abf1b44ec5b18d87c1ae5f54590ca9d0699ef4dd5b2ffa66fc97f24613ec585" +dependencies = [ + "ark-ff", + "crypto-bigint", + "getrandom 0.2.15", + "hex", +] + [[package]] name = "starknet-types-core" version = "0.1.7" @@ -3191,6 +3436,26 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "thiserror-impl-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "thiserror-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" +dependencies = [ + "thiserror-impl-no-std", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -3201,6 +3466,25 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -3640,7 +3924,7 @@ dependencies = [ name = "wasm-demo" version = "2.0.1" dependencies = [ - "cairo-vm", + "cairo-vm 2.0.1", "console_error_panic_hook", "serde_json", "wasm-bindgen", @@ -3865,10 +4149,27 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ + "aes", "byteorder", + "bzip2", + "constant_time_eq", "crc32fast", "crossbeam-utils", "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", ] [[package]] @@ -3877,7 +4178,17 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ - "zstd-safe", + "zstd-safe 7.2.3", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] From dc46708b27b1fe1cbd2dd2eb70b3c1c0037553df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 14:49:40 -0300 Subject: [PATCH 25/38] Fix clippy --- vm/src/vm/runners/cairo_runner_2.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index e43106aa60..09ef784e5a 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -55,6 +55,7 @@ pub struct CairoRunner2 { } impl CairoRunner2 { + #[allow(clippy::too_many_arguments)] pub fn new( executable: Executable, entrypoint_kind: EntryPointKind, @@ -236,7 +237,7 @@ pub fn initialize_builtin_runners( ) -> Result, RunnerError> { let mut builtin_runners = Vec::new(); - let mut builtins: HashSet = builtins.into_iter().map(ToOwned::to_owned).collect(); + let mut builtins: HashSet = builtins.iter().map(ToOwned::to_owned).collect(); if layout.builtins.output { let included = builtins.remove(&BuiltinName::output); @@ -360,7 +361,7 @@ fn extend_stack_with_builtins( .map(|builtin_runner| (builtin_runner.name(), builtin_runner)) .collect(); for builtin in builtins { - if let Some(builtin_runner) = runner_map.get(&builtin) { + if let Some(builtin_runner) = runner_map.get(builtin) { stack.append(&mut builtin_runner.initial_stack()); } else { stack.push(Felt252::ZERO.into()) From 702480359caf46bd70d84f2b18e34e7addcd76a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 15:06:36 -0300 Subject: [PATCH 26/38] Import Vec --- vm/src/vm/runners/cairo_runner_2.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 09ef784e5a..f2972f0c47 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -8,7 +8,10 @@ use crate::{ serde::deserialize_program::{ ApTracking, Attribute, FlowTrackingData, HintParams, Identifier, InstructionLocation, }, - stdlib::collections::{BTreeMap, HashMap, HashSet}, + stdlib::{ + collections::{BTreeMap, HashMap, HashSet}, + prelude::Vec, + }, types::{ builtin_name::BuiltinName, exec_scope::ExecutionScopes, From dadbdd2f1a2efec3b1a04eba0437d07453934054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Wed, 19 Mar 2025 18:49:27 -0300 Subject: [PATCH 27/38] Fix standalone --- vm/src/vm/runners/cairo_runner_2.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index f2972f0c47..e872538b16 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -89,15 +89,18 @@ impl CairoRunner2 { .build(); let mut stack = Vec::new(); + + let initial_fp_offset: usize = 2; + stack.push(MaybeRelocatable::RelocatableValue( + (execution_base + initial_fp_offset)?, + )); + stack.push(MaybeRelocatable::Int(Felt252::ZERO)); + extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); - let return_fp = vm.add_memory_segment(); - let return_pc = vm.add_memory_segment(); - stack.push(MaybeRelocatable::RelocatableValue(return_fp)); - stack.push(MaybeRelocatable::RelocatableValue(return_pc)); let initial_pc = (program_base + entrypoint.offset)?; - let initial_fp = (execution_base + stack.len())?; + let initial_fp = (execution_base + initial_fp_offset)?; let initial_ap = initial_fp; let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); vm.set_run_context(run_context); @@ -127,7 +130,7 @@ impl CairoRunner2 { .map_err(RunnerError::MemoryValidationError)?; let final_pc = match entrypoint_kind { - EntryPointKind::Bootloader => return_pc, + EntryPointKind::Bootloader => unimplemented!(), EntryPointKind::Standalone => (initial_pc + 4)?, }; @@ -420,8 +423,8 @@ pub fn build_hint_collection( *offset, offset_hints .iter() - .map(|hint| HintParams { - code: hint.representing_string(), + .map(|_| HintParams { + code: format!("{offset}"), accessible_scopes: vec![], flow_tracking_data: FlowTrackingData { ap_tracking: ApTracking::new(), From 4f8c7eb7fea6f7f2514fe7a042d182826464ab2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 12:23:22 -0300 Subject: [PATCH 28/38] Fix bootloader --- vm/src/vm/runners/cairo_runner_2.rs | 61 ++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index e872538b16..182edd6faa 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -90,17 +90,55 @@ impl CairoRunner2 { let mut stack = Vec::new(); - let initial_fp_offset: usize = 2; - stack.push(MaybeRelocatable::RelocatableValue( - (execution_base + initial_fp_offset)?, - )); - stack.push(MaybeRelocatable::Int(Felt252::ZERO)); - - extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); + let initial_pc = (program_base + entrypoint.offset)?; + let (initial_fp, final_pc) = match entrypoint_kind { + EntryPointKind::Bootloader => { + // On bootloader, we execute until control flow is returned. + // The stack is arranged as if we are at the start of a function call. + // Input arguments are set as input arguments to the the function. + // + // --- ARGUMENTS --- RETURN FP RETURN PC + // ┌────┬────┬────┬────┬───────────┬───────────┬ ─ ─ ─ ─ ┐ + // │ │ │ │ │ │ │ START FP + // └────┴────┴────┴────┴───────────┴───────────┴ ─ ─ ─ ─ ┘ + // Note: The size of the cells is not relevant + + extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); + + let return_fp = vm.add_memory_segment(); + let return_pc = vm.add_memory_segment(); + stack.push(MaybeRelocatable::RelocatableValue(return_fp)); + stack.push(MaybeRelocatable::RelocatableValue(return_pc)); + + let initial_fp = (execution_base + stack.len())?; + + (initial_fp, return_pc) + } + EntryPointKind::Standalone => { + // On standalone, we execute until a fixed address. + // Input arguments are set as local variables to the current frame. + // + // ZERO ------ ARGUMENTS ------ + // ┌──────┬──────────┬────┬────┬────┐ + // │ │ START FP │ │ │ │ + // └──────┴──────────┴────┴────┴────┘ + // Note: The size of the cells is not relevant + // + // The zero element is necessary because the compiler asumes that `fp` + // is not pointing to the start of a segment - it fails otherwise. + + let stack_prefix = &[MaybeRelocatable::Int(Felt252::ZERO)]; + stack.extend_from_slice(stack_prefix); + extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); + + let final_pc = (initial_pc + 4)?; + let initial_fp = (execution_base + stack_prefix.len())?; + + (initial_fp, final_pc) + } + }; - let initial_pc = (program_base + entrypoint.offset)?; - let initial_fp = (execution_base + initial_fp_offset)?; let initial_ap = initial_fp; let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); vm.set_run_context(run_context); @@ -129,11 +167,6 @@ impl CairoRunner2 { .validate_existing_memory() .map_err(RunnerError::MemoryValidationError)?; - let final_pc = match entrypoint_kind { - EntryPointKind::Bootloader => unimplemented!(), - EntryPointKind::Standalone => (initial_pc + 4)?, - }; - let hint_collection = build_hint_collection(&executable.program.hints, bytecode.len()); Ok(Self { From c9428b5093047ade434d38988a14354ccd40c1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 12:37:22 -0300 Subject: [PATCH 29/38] Add cairo-runner-2 feature --- vm/Cargo.toml | 9 +++++++-- vm/src/vm/runners/cairo_runner_2.rs | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index da58aff97a..cc2bc5998f 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -22,6 +22,7 @@ std = [ ] cairo-1-hints = [ "dep:cairo-lang-starknet", + "dep:cairo-lang-casm", "dep:cairo-lang-starknet-classes", "dep:ark-ff", "dep:ark-std", @@ -30,6 +31,10 @@ tracer = [] mod_builtin = [] cairo-0-secp-hints = [] cairo-0-data-availability-hints = [] +cairo-runner-2 = [ + "dep:cairo-lang-casm", + "dep:cairo-lang-executable", +] # Note that these features are not retro-compatible with the cairo Python VM. test_utils = ["std", "dep:arbitrary", "starknet-types-core/arbitrary", "starknet-types-core/std"] # This feature will reference every test-oriented feature @@ -62,8 +67,8 @@ starknet-types-core = { version = "0.1.2", default-features = false, features = rust_decimal = { version = "1.35.0", default-features = false } # cairo-lang dependencies -cairo-lang-executable = { workspace = true } -cairo-lang-casm = { workspace = true } +cairo-lang-executable = { workspace = true, optional = true } +cairo-lang-casm = { workspace = true, optional = true } # only for std num-prime = { version = "0.4.3", features = ["big-int"], optional = true } diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 182edd6faa..7f9b01595b 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "cairo-runner-2")] + use core::any::Any; use cairo_lang_casm::hints::Hint; From 3c9024a52e9e32190d7fc2c1115506d95ee5d5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 12:40:31 -0300 Subject: [PATCH 30/38] Remove unused dep --- vm/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index cc2bc5998f..1fed7c98b7 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -92,7 +92,6 @@ clap = { version = "4.3.10", features = ["derive"], optional = true} assert_matches = "1.5.0" rstest = { version = "0.17.0", default-features = false } num-prime = { version = "0.4.3", features = ["big-int"] } -cairo-lang-compiler.workspace = true [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.50" From d3f07fcb9009caaf86d1dbbc24fefa65fd4c67a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 12:44:21 -0300 Subject: [PATCH 31/38] Import prelude --- vm/src/vm/runners/cairo_runner_2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 7f9b01595b..c3c4052137 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -12,7 +12,7 @@ use crate::{ }, stdlib::{ collections::{BTreeMap, HashMap, HashSet}, - prelude::Vec, + prelude::*, }, types::{ builtin_name::BuiltinName, From 14b5a90a5d88aaa9cf538c76d2855bc579e89a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 12:49:11 -0300 Subject: [PATCH 32/38] Update lock --- Cargo.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 3044fb402a..7406fd65e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1035,7 +1035,6 @@ dependencies = [ "bincode", "bitvec", "cairo-lang-casm", - "cairo-lang-compiler", "cairo-lang-executable", "cairo-lang-starknet", "cairo-lang-starknet-classes", From 36f513e33f8b01450ce24370278ad24e83627e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 12:56:42 -0300 Subject: [PATCH 33/38] Import mem from stdlib --- vm/src/vm/runners/cairo_runner_2.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index c3c4052137..2b8b22b9b1 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -12,6 +12,7 @@ use crate::{ }, stdlib::{ collections::{BTreeMap, HashMap, HashSet}, + mem, prelude::*, }, types::{ @@ -244,7 +245,7 @@ fn find_entrypoint_of_kind( .iter() .find(|entrypoint| { // TODO: Use `Eq` once implemented on `EntryPointKind`. - std::mem::discriminant(&entrypoint.kind) == std::mem::discriminant(&entrypoint_kind) + mem::discriminant(&entrypoint.kind) == mem::discriminant(&entrypoint_kind) }) .expect("executable had no entrypoint of required kind") } From 23f54c5d57def51f5c8ba331caf5bc58fc9b5e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 13:05:44 -0300 Subject: [PATCH 34/38] Improve diagram --- vm/src/vm/runners/cairo_runner_2.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 2b8b22b9b1..b9d70be31d 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -101,11 +101,14 @@ impl CairoRunner2 { // The stack is arranged as if we are at the start of a function call. // Input arguments are set as input arguments to the the function. // - // --- ARGUMENTS --- RETURN FP RETURN PC - // ┌────┬────┬────┬────┬───────────┬───────────┬ ─ ─ ─ ─ ┐ - // │ │ │ │ │ │ │ START FP - // └────┴────┴────┴────┴───────────┴───────────┴ ─ ─ ─ ─ ┘ + // <-------- ARGUMENTS ---- + // ┌────┬────┬────┬────┬────────┬────────┬ ─ ─ ─ ─ ┐ + // ... │ │ │ │ │ RET FP │ RET PC │ + // └────┴────┴────┴────┴────────┴────────┴ ─ ─ ─ ─ ┘ + // INIT FP // Note: The size of the cells is not relevant + // + // The initial fp variable points to the cell after the return pc. extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); @@ -122,12 +125,15 @@ impl CairoRunner2 { // On standalone, we execute until a fixed address. // Input arguments are set as local variables to the current frame. // - // ZERO ------ ARGUMENTS ------ - // ┌──────┬──────────┬────┬────┬────┐ - // │ │ START FP │ │ │ │ - // └──────┴──────────┴────┴────┴────┘ + // -------------- ARGUMENTS ------------------> + // ┌──────┬─────────┬────┬────┬────┬────┬────┬────┐ + // │ ZERO │ │ │ │ │ │ │ │ ... + // └──────┴─────────┴────┴────┴────┴────┴────┴────┘ + // INIT FP // Note: The size of the cells is not relevant // + // The initial fp variable points to the cell after the zero element. + // // The zero element is necessary because the compiler asumes that `fp` // is not pointing to the start of a segment - it fails otherwise. From 571275a0af48f8323128284fac5002d5bd770dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 16:41:42 -0300 Subject: [PATCH 35/38] Receive hint map directly --- vm/src/vm/runners/cairo_runner_2.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index b9d70be31d..2c5bffd7aa 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -2,14 +2,11 @@ use core::any::Any; -use cairo_lang_casm::hints::Hint; use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; use crate::{ hint_processor::hint_processor_definition::{HintProcessor, HintReference}, - serde::deserialize_program::{ - ApTracking, Attribute, FlowTrackingData, HintParams, Identifier, InstructionLocation, - }, + serde::deserialize_program::{Attribute, HintParams, Identifier, InstructionLocation}, stdlib::{ collections::{BTreeMap, HashMap, HashSet}, mem, @@ -72,6 +69,7 @@ impl CairoRunner2 { instruction_locations: Option>, identifiers: HashMap, reference_manager: Vec, + hints: BTreeMap>, ) -> Result { let entrypoint = find_entrypoint_of_kind(&executable.entrypoints, entrypoint_kind.clone()); @@ -176,7 +174,8 @@ impl CairoRunner2 { .validate_existing_memory() .map_err(RunnerError::MemoryValidationError)?; - let hint_collection = build_hint_collection(&executable.program.hints, bytecode.len()); + let hint_collection = + HintsCollection::new(&hints, bytecode.len()).expect("failed to build hint collection"); Ok(Self { executable, From eb27800be3219b993d0296672487d62ebefbeaa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Thu, 20 Mar 2025 18:53:59 -0300 Subject: [PATCH 36/38] Remove unuused code --- vm/src/vm/runners/cairo_runner_2.rs | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index 2c5bffd7aa..f31b36c3e3 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -450,31 +450,3 @@ pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec)], - program_length: usize, -) -> HintsCollection { - let mut hint_map: BTreeMap> = BTreeMap::new(); - - for (offset, offset_hints) in hints { - hint_map.insert( - *offset, - offset_hints - .iter() - .map(|_| HintParams { - code: format!("{offset}"), - accessible_scopes: vec![], - flow_tracking_data: FlowTrackingData { - ap_tracking: ApTracking::new(), - reference_ids: HashMap::new(), - }, - }) - .collect(), - ); - } - - HintsCollection::new(&hint_map, program_length).expect("failed to build hint collection") -} From f97267f9fb23e745f231fdfe5e12e8e187a01fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Fri, 21 Mar 2025 11:13:02 -0300 Subject: [PATCH 37/38] Refactor cairo runner 2 code --- vm/src/vm/runners/cairo_runner_2.rs | 102 ++++++++++++++++++---------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index f31b36c3e3..d7aaddaad9 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -28,8 +28,8 @@ use crate::{ KeccakBuiltinRunner, ModBuiltinRunner, OutputBuiltinRunner, PoseidonBuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD, }, - vm_core::{VirtualMachine, VirtualMachineBuilder}, - vm_memory::memory_segments::MemorySegmentManager, + vm_core::VirtualMachine, + vm_memory::{memory::Memory, memory_segments::MemorySegmentManager}, }, Felt252, }; @@ -71,23 +71,40 @@ impl CairoRunner2 { reference_manager: Vec, hints: BTreeMap>, ) -> Result { + // ============= + // PREPROCESSING + // ============= + let entrypoint = find_entrypoint_of_kind(&executable.entrypoints, entrypoint_kind.clone()); + let bytecode = executable + .program + .bytecode + .iter() + .map(Felt252::from) + .map(MaybeRelocatable::from) + .collect::>(); + + let hint_collection = + HintsCollection::new(&hints, bytecode.len()).expect("failed to build hint collection"); + let builtins = get_entrypoint_builtins(entrypoint); + // ============== + // INITIALIZATION + // ============== + + let mut vm = VirtualMachine::new(trace_enabled, false); + check_builtin_order(&builtins)?; - let mut builtin_runners = initialize_builtin_runners(&layout, &builtins, true, true)?; + vm.builtin_runners = initialize_builtin_runners(&layout, &builtins, true, true)?; - let mut segments = MemorySegmentManager::new(); - let program_base = segments.add(); - let execution_base = segments.add(); + let program_base = vm.add_memory_segment(); + let execution_base = vm.add_memory_segment(); - initialize_builtin_runner_segments(&mut builtin_runners, &mut segments); + initialize_builtin_runner_segments(&mut vm.builtin_runners, &mut vm.segments); - let mut vm = VirtualMachineBuilder::default() - .builtin_runners(builtin_runners) - .segments(segments) - .build(); + load_program(&mut vm, program_base, &bytecode)?; let mut stack = Vec::new(); @@ -150,32 +167,9 @@ impl CairoRunner2 { let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); vm.set_run_context(run_context); - let bytecode = executable - .program - .bytecode - .iter() - .map(Felt252::from) - .map(MaybeRelocatable::from) - .collect::>(); - vm.load_data(program_base, &bytecode) - .map_err(RunnerError::MemoryInitializationError)?; - for i in 0..bytecode.len() { - vm.segments.memory.mark_as_accessed((program_base + i)?); - } - - vm.load_data(execution_base, &stack) - .map_err(RunnerError::MemoryInitializationError)?; - - for builtin_runner in &mut vm.builtin_runners { - builtin_runner.add_validation_rule(&mut vm.segments.memory) - } - vm.segments - .memory - .validate_existing_memory() - .map_err(RunnerError::MemoryValidationError)?; + load_stack(&mut vm, execution_base, stack)?; - let hint_collection = - HintsCollection::new(&hints, bytecode.len()).expect("failed to build hint collection"); + add_builtin_validation_rules(&mut vm.segments.memory, &mut vm.builtin_runners)?; Ok(Self { executable, @@ -416,6 +410,42 @@ fn extend_stack_with_builtins( } } +fn load_program( + vm: &mut VirtualMachine, + program_base: Relocatable, + bytecode: &Vec, +) -> Result<(), RunnerError> { + vm.load_data(program_base, bytecode) + .map_err(RunnerError::MemoryInitializationError)?; + for i in 0..bytecode.len() { + vm.segments.memory.mark_as_accessed((program_base + i)?); + } + Ok(()) +} + +fn load_stack( + vm: &mut VirtualMachine, + execution_base: Relocatable, + stack: Vec, +) -> Result<(), RunnerError> { + vm.load_data(execution_base, &stack) + .map_err(RunnerError::MemoryInitializationError)?; + Ok(()) +} + +fn add_builtin_validation_rules( + memory: &mut Memory, + runners: &mut [BuiltinRunner], +) -> Result<(), RunnerError> { + for runner in runners { + runner.add_validation_rule(memory) + } + memory + .validate_existing_memory() + .map_err(RunnerError::MemoryValidationError)?; + Ok(()) +} + fn get_hint_data( collection: &HintsCollection, references: &[HintReference], From 6727a1058eeeb6094cb7cdbf768984d5151162f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 25 Mar 2025 18:40:28 -0300 Subject: [PATCH 38/38] Create Program2 type --- vm/src/vm/runners/cairo_runner_2.rs | 176 ++++++++++++---------------- 1 file changed, 77 insertions(+), 99 deletions(-) diff --git a/vm/src/vm/runners/cairo_runner_2.rs b/vm/src/vm/runners/cairo_runner_2.rs index d7aaddaad9..4978c56fc6 100644 --- a/vm/src/vm/runners/cairo_runner_2.rs +++ b/vm/src/vm/runners/cairo_runner_2.rs @@ -2,18 +2,16 @@ use core::any::Any; -use cairo_lang_executable::executable::{EntryPointKind, Executable, ExecutableEntryPoint}; - use crate::{ hint_processor::hint_processor_definition::{HintProcessor, HintReference}, - serde::deserialize_program::{Attribute, HintParams, Identifier, InstructionLocation}, + serde::deserialize_program::HintParams, stdlib::{ collections::{BTreeMap, HashMap, HashSet}, - mem, prelude::*, }, types::{ builtin_name::BuiltinName, + errors::program_errors::ProgramError, exec_scope::ExecutionScopes, layout::CairoLayout, program::HintsCollection, @@ -34,6 +32,52 @@ use crate::{ Felt252, }; +/// This type is originally defined in `cairo-lang-executable`. +/// We redefine it here to avoid a cyclic dependencies. +#[derive(Debug)] +pub struct ExecutableEntryPoint { + pub builtins: Vec, + pub offset: usize, + pub kind: EntryPointKind, +} + +/// This type is originally defined in `cairo-lang-executable`. +/// We redefine it here to avoid a cyclic dependencies. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EntryPointKind { + Bootloader, + Standalone, +} + +pub struct Program2 { + pub bytecode: Vec, + pub hints_collection: HintsCollection, + pub entrypoint: ExecutableEntryPoint, + + pub reference_manager: Vec, + pub constants: HashMap, +} + +impl Program2 { + pub fn new( + bytecode: Vec, + hints: BTreeMap>, + entrypoint: ExecutableEntryPoint, + reference_manager: Vec, + constants: HashMap, + ) -> Result { + let hints_collection = HintsCollection::new(&hints, bytecode.len())?; + + Ok(Self { + bytecode, + hints_collection, + entrypoint, + reference_manager, + constants, + }) + } +} + #[allow(dead_code)] pub struct CairoRunner2 { vm: VirtualMachine, @@ -43,74 +87,35 @@ pub struct CairoRunner2 { execution_scopes: ExecutionScopes, // Configuration - executable: Executable, - entrypoint_kind: EntryPointKind, + program: Program2, layout: CairoLayout, - trace_enabled: bool, - constants: HashMap, - error_message_attributes: Vec, - instruction_locations: Option>, - identifiers: HashMap, - reference_manager: Vec, - - // Preprocessed Data - hint_collection: HintsCollection, } impl CairoRunner2 { #[allow(clippy::too_many_arguments)] pub fn new( - executable: Executable, - entrypoint_kind: EntryPointKind, + program: Program2, layout: CairoLayout, trace_enabled: bool, - constants: HashMap, - error_message_attributes: Vec, - instruction_locations: Option>, - identifiers: HashMap, - reference_manager: Vec, - hints: BTreeMap>, ) -> Result { - // ============= - // PREPROCESSING - // ============= - - let entrypoint = find_entrypoint_of_kind(&executable.entrypoints, entrypoint_kind.clone()); - - let bytecode = executable - .program - .bytecode - .iter() - .map(Felt252::from) - .map(MaybeRelocatable::from) - .collect::>(); - - let hint_collection = - HintsCollection::new(&hints, bytecode.len()).expect("failed to build hint collection"); - - let builtins = get_entrypoint_builtins(entrypoint); - - // ============== - // INITIALIZATION - // ============== - let mut vm = VirtualMachine::new(trace_enabled, false); - check_builtin_order(&builtins)?; - vm.builtin_runners = initialize_builtin_runners(&layout, &builtins, true, true)?; + check_builtin_order(&(&program.entrypoint).builtins)?; + vm.builtin_runners = + initialize_builtin_runners(&layout, &program.entrypoint.builtins, true, true)?; let program_base = vm.add_memory_segment(); let execution_base = vm.add_memory_segment(); initialize_builtin_runner_segments(&mut vm.builtin_runners, &mut vm.segments); - load_program(&mut vm, program_base, &bytecode)?; + load_program(&mut vm, program_base, &program.bytecode)?; let mut stack = Vec::new(); - let initial_pc = (program_base + entrypoint.offset)?; + let initial_pc = (program_base + program.entrypoint.offset)?; - let (initial_fp, final_pc) = match entrypoint_kind { + let (initial_fp, final_pc) = match program.entrypoint.kind { EntryPointKind::Bootloader => { // On bootloader, we execute until control flow is returned. // The stack is arranged as if we are at the start of a function call. @@ -125,7 +130,11 @@ impl CairoRunner2 { // // The initial fp variable points to the cell after the return pc. - extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); + extend_stack_with_builtins( + &mut stack, + &program.entrypoint.builtins, + &vm.builtin_runners, + ); let return_fp = vm.add_memory_segment(); let return_pc = vm.add_memory_segment(); @@ -154,7 +163,11 @@ impl CairoRunner2 { let stack_prefix = &[MaybeRelocatable::Int(Felt252::ZERO)]; stack.extend_from_slice(stack_prefix); - extend_stack_with_builtins(&mut stack, &builtins, &vm.builtin_runners); + extend_stack_with_builtins( + &mut stack, + &program.entrypoint.builtins, + &vm.builtin_runners, + ); let final_pc = (initial_pc + 4)?; let initial_fp = (execution_base + stack_prefix.len())?; @@ -167,26 +180,18 @@ impl CairoRunner2 { let run_context = RunContext::new(initial_pc, initial_ap.offset, initial_fp.offset); vm.set_run_context(run_context); - load_stack(&mut vm, execution_base, stack)?; + load_stack(&mut vm, execution_base, &stack)?; add_builtin_validation_rules(&mut vm.segments.memory, &mut vm.builtin_runners)?; Ok(Self { - executable, vm, program_base, execution_base, final_pc, execution_scopes: ExecutionScopes::new(), - entrypoint_kind, + program, layout, - trace_enabled, - constants, - error_message_attributes, - instruction_locations, - identifiers, - reference_manager, - hint_collection, }) } @@ -196,20 +201,21 @@ impl CairoRunner2 { ) -> Result<(), VirtualMachineError> { #[cfg_attr(not(feature = "extensive_hints"), allow(unused_mut))] let mut hint_data = get_hint_data( - &self.hint_collection, - &self.reference_manager, + &self.program.hints_collection, + &self.program.reference_manager, hint_processor, )?; #[cfg(feature = "extensive_hints")] - let mut hint_ranges = self.hint_collection.hints_ranges.clone(); + let mut hint_ranges = self.program.hints_collection.hints_ranges.clone(); while self.vm.get_pc() != self.final_pc && !hint_processor.consumed() { #[cfg(feature = "extensive_hints")] let hint_data = &mut hint_data; #[cfg(not(feature = "extensive_hints"))] let hint_data = self - .hint_collection + .program + .hints_collection .get_hint_range_for_pc(self.vm.get_pc().offset) .and_then(|range| { range.and_then(|(start, length)| hint_data.get(start..start + length.get())) @@ -222,7 +228,7 @@ impl CairoRunner2 { hint_data, #[cfg(feature = "extensive_hints")] &mut hint_ranges, - &self.constants, + &self.program.constants, )?; hint_processor.consume_step(); @@ -236,19 +242,6 @@ impl CairoRunner2 { } } -fn find_entrypoint_of_kind( - entrypoints: &[ExecutableEntryPoint], - entrypoint_kind: EntryPointKind, -) -> &ExecutableEntryPoint { - entrypoints - .iter() - .find(|entrypoint| { - // TODO: Use `Eq` once implemented on `EntryPointKind`. - mem::discriminant(&entrypoint.kind) == mem::discriminant(&entrypoint_kind) - }) - .expect("executable had no entrypoint of required kind") -} - pub fn check_builtin_order(builtins: &[BuiltinName]) -> Result<(), RunnerError> { let ordered_builtins = vec![ BuiltinName::output, @@ -413,7 +406,7 @@ fn extend_stack_with_builtins( fn load_program( vm: &mut VirtualMachine, program_base: Relocatable, - bytecode: &Vec, + bytecode: &[MaybeRelocatable], ) -> Result<(), RunnerError> { vm.load_data(program_base, bytecode) .map_err(RunnerError::MemoryInitializationError)?; @@ -426,9 +419,9 @@ fn load_program( fn load_stack( vm: &mut VirtualMachine, execution_base: Relocatable, - stack: Vec, + stack: &[MaybeRelocatable], ) -> Result<(), RunnerError> { - vm.load_data(execution_base, &stack) + vm.load_data(execution_base, stack) .map_err(RunnerError::MemoryInitializationError)?; Ok(()) } @@ -465,18 +458,3 @@ fn get_hint_data( }) .collect() } - -/// TODO: Remove this once cyclic dependency is fixed. -/// It should not be necessary, but cargo treats executable BuiltinName as a separate type -/// which is why I had to create this adapter function. -pub fn get_entrypoint_builtins(entrypoint: &ExecutableEntryPoint) -> Vec { - let mut builtins = Vec::with_capacity(entrypoint.builtins.len()); - - for builtin in &entrypoint.builtins { - let adapted_builtin = BuiltinName::from_str(builtin.to_str()) - .expect("should never fail under the same implementation"); - builtins.push(adapted_builtin); - } - - builtins -}