From 0945d6dda67d66434825bc5c948a3c38bfbf3c0e Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Wed, 3 Jan 2024 04:33:40 -0700 Subject: [PATCH] Execute task hint #5: call task (#22) Implements the `call_task` execute task hint --------- Co-authored-by: Olivier Desenfans --- .../bootloader/execute_task_hints.rs | 246 +++++++++++- .../bootloader/load_cairo_pie.rs | 380 ++++++++++++++++++ .../builtin_hint_processor/bootloader/mod.rs | 1 + .../bootloader/types.rs | 5 +- .../builtin_hint_processor/bootloader/vars.rs | 3 + .../builtin_hint_processor_definition.rs | 7 +- vm/src/vm/runners/builtin_runner/output.rs | 2 +- vm/src/vm/runners/cairo_pie.rs | 4 +- 8 files changed, 636 insertions(+), 12 deletions(-) create mode 100644 vm/src/hint_processor/builtin_hint_processor/bootloader/load_cairo_pie.rs diff --git a/vm/src/hint_processor/builtin_hint_processor/bootloader/execute_task_hints.rs b/vm/src/hint_processor/builtin_hint_processor/bootloader/execute_task_hints.rs index e415c1a695..d36cdcd9f6 100644 --- a/vm/src/hint_processor/builtin_hint_processor/bootloader/execute_task_hints.rs +++ b/vm/src/hint_processor/builtin_hint_processor/bootloader/execute_task_hints.rs @@ -6,9 +6,11 @@ use starknet_crypto::FieldElement; use crate::Felt252; +use crate::any_box; use crate::hint_processor::builtin_hint_processor::bootloader::fact_topologies::{ get_program_task_fact_topology, FactTopology, }; +use crate::hint_processor::builtin_hint_processor::bootloader::load_cairo_pie::load_cairo_pie; use crate::hint_processor::builtin_hint_processor::bootloader::program_hash::compute_program_hash_chain; use crate::hint_processor::builtin_hint_processor::bootloader::program_loader::ProgramLoader; use crate::hint_processor::builtin_hint_processor::bootloader::types::{BootloaderVersion, Task}; @@ -53,6 +55,11 @@ pub fn allocate_program_data_segment( Ok(()) } +fn field_element_to_felt(field_element: FieldElement) -> Felt252 { + let bytes = field_element.to_bytes_be(); + Felt252::from_bytes_be(&bytes) +} + /// Implements /// /// from starkware.cairo.bootloaders.simple_bootloader.utils import load_program @@ -93,11 +100,6 @@ pub fn load_program_hint( Ok(()) } -fn field_element_to_felt(field_element: FieldElement) -> Felt252 { - let bytes = field_element.to_bytes_be(); - Felt252::from_bytes_be(&bytes) -} - /// Implements /// from starkware.cairo.bootloaders.simple_bootloader.utils import get_task_fact_topology /// @@ -338,13 +340,166 @@ pub fn write_return_builtins_hint( Ok(()) } +/* +Implements hint: +%{ + "from starkware.cairo.bootloaders.simple_bootloader.objects import ( + CairoPieTask, + RunProgramTask, + Task, + ) + from starkware.cairo.bootloaders.simple_bootloader.utils import ( + load_cairo_pie, + prepare_output_runner, + ) + + assert isinstance(task, Task) + n_builtins = len(task.get_program().builtins) + new_task_locals = {} + if isinstance(task, RunProgramTask): + new_task_locals['program_input'] = task.program_input + new_task_locals['WITH_BOOTLOADER'] = True + + vm_load_program(task.program, program_address) + elif isinstance(task, CairoPieTask): + ret_pc = ids.ret_pc_label.instruction_offset_ - ids.call_task.instruction_offset_ + pc + load_cairo_pie( + task=task.cairo_pie, memory=memory, segments=segments, + program_address=program_address, execution_segment_address= ap - n_builtins, + builtin_runners=builtin_runners, ret_fp=fp, ret_pc=ret_pc) + else: + raise NotImplementedError(f'Unexpected task type: {type(task).__name__}.') + + output_runner_data = prepare_output_runner( + task=task, + output_builtin=output_builtin, + output_ptr=ids.pre_execution_builtin_ptrs.output) + vm_enter_scope(new_task_locals)" +%} +*/ +pub fn call_task( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + // assert isinstance(task, Task) + let task: Task = exec_scopes.get(vars::TASK)?; + + // n_builtins = len(task.get_program().builtins) + let num_builtins = get_program_from_task(&task)?.builtins.len(); + + let mut new_task_locals = HashMap::new(); + + // TODO: remove clone here when RunProgramTask has proper variant data (not String) + match &task { + // if isinstance(task, RunProgramTask): + Task::Program(_program) => { + let program_input = HashMap::>::new(); + // new_task_locals['program_input'] = task.program_input + new_task_locals.insert("program_input".to_string(), any_box![program_input]); + // new_task_locals['WITH_BOOTLOADER'] = True + new_task_locals.insert("WITH_BOOTLOADER".to_string(), any_box![true]); + + // TODO: the content of this function is mostly useless for the Rust VM. + // check with SW if there is nothing of interest here. + // vm_load_program(task.program, program_address) + } + // elif isinstance(task, CairoPieTask): + Task::Pie(cairo_pie) => { + let program_address: Relocatable = exec_scopes.get("program_address")?; + + // ret_pc = ids.ret_pc_label.instruction_offset_ - ids.call_task.instruction_offset_ + pc + // load_cairo_pie( + // task=task.cairo_pie, memory=memory, segments=segments, + // program_address=program_address, execution_segment_address= ap - n_builtins, + // builtin_runners=builtin_runners, ret_fp=fp, ret_pc=ret_pc) + load_cairo_pie( + cairo_pie, + vm, + program_address, + (vm.get_ap() - num_builtins)?, + vm.get_fp(), + vm.get_pc(), + ) + .map_err(Into::::into)?; + } + } + + // output_runner_data = prepare_output_runner( + // task=task, + // output_builtin=output_builtin, + // output_ptr=ids.pre_execution_builtin_ptrs.output) + let pre_execution_builtin_ptrs_addr = + get_relocatable_from_var_name(vars::PRE_EXECUTION_BUILTIN_PTRS, vm, ids_data, ap_tracking)?; + let output = vm + .get_integer(pre_execution_builtin_ptrs_addr)? + .into_owned(); + let output_ptr = output + .to_usize() + .ok_or(MathError::Felt252ToUsizeConversion(Box::new(output)))?; + let output_runner_data = + util::prepare_output_runner(&task, vm.get_output_builtin()?, output_ptr)?; + + exec_scopes.insert_box(vars::OUTPUT_RUNNER_DATA, any_box!(output_runner_data)); + + exec_scopes.enter_scope(new_task_locals); + + Ok(()) +} + +mod util { + use crate::vm::runners::{ + builtin_runner::OutputBuiltinRunner, + cairo_pie::{BuiltinAdditionalData, OutputBuiltinAdditionalData}, + }; + + // TODO: clean up / organize + use super::*; + + /// Prepares the output builtin if the type of task is Task, so that pages of the inner program + /// will be recorded separately. + /// If the type of task is CairoPie, nothing should be done, as the program does not contain + /// hints that may affect the output builtin. + /// The return value of this function should be later passed to get_task_fact_topology(). + pub(crate) fn prepare_output_runner( + task: &Task, + output_builtin: &mut OutputBuiltinRunner, + output_ptr: usize, + ) -> Result, HintError> { + return match task { + Task::Program(_) => { + let output_state = match output_builtin.get_additional_data() { + BuiltinAdditionalData::Output(output_state) => Ok(output_state), + _ => Err(HintError::CustomHint( + "output_builtin's additional data is not type Output" + .to_string() + .into_boxed_str(), + )), + }?; + output_builtin.base = output_ptr; + Ok(Some(output_state)) + } + Task::Pie(_) => Ok(None), + }; + } +} + #[cfg(test)] mod tests { + use std::path::Path; + + use assert_matches::assert_matches; use rstest::{fixture, rstest}; use crate::Felt252; + use crate::any_box; + use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; + use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData; + use crate::hint_processor::builtin_hint_processor::hint_code; use crate::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name; + use crate::hint_processor::hint_processor_definition::HintProcessorLogic; use crate::types::relocatable::Relocatable; use crate::utils::test_utils::*; use crate::vm::runners::builtin_runner::{BuiltinRunner, OutputBuiltinRunner}; @@ -399,6 +554,13 @@ mod tests { .expect("Loading example program failed unexpectedly") } + #[fixture] + fn fibonacci_pie() -> CairoPie { + let pie_file = + Path::new("../cairo_programs/manually_compiled/fibonacci_cairo_pie/fibonacci_pie.zip"); + CairoPie::from_file(pie_file).expect("Failed to load the program PIE") + } + #[fixture] fn field_arithmetic_program() -> Program { let program_content = @@ -447,6 +609,80 @@ mod tests { ); } + #[rstest] + fn test_call_task(fibonacci: Program) { + let mut vm = vm!(); + + // Allocate space for pre-execution (8 felts), which mimics the `BuiltinData` struct in the + // Bootloader's Cairo code. Our code only uses the first felt (`output` field in the struct) + vm.segments = segments![((1, 0), 0)]; + vm.run_context.fp = 8; + add_segments!(vm, 1); + + let ids_data = non_continuous_ids_data![(vars::PRE_EXECUTION_BUILTIN_PTRS, -8)]; + + let mut exec_scopes = ExecutionScopes::new(); + + let mut output_builtin = OutputBuiltinRunner::new(true); + output_builtin.initialize_segments(&mut vm.segments); + vm.builtin_runners + .push(BuiltinRunner::Output(output_builtin)); + + let task = Task::Program(fibonacci); + exec_scopes.insert_box(vars::TASK, Box::new(task)); + + assert_matches!( + run_hint!( + vm, + ids_data.clone(), + hint_code::EXECUTE_TASK_CALL_TASK, + &mut exec_scopes + ), + Ok(()) + ); + } + + #[rstest] + fn test_call_cairo_pie_task(fibonacci_pie: CairoPie) { + let mut vm = vm!(); + + // We set the program header pointer at (1, 0) and make it point to the start of segment #2. + // Allocate space for pre-execution (8 values), which follows the `BuiltinData` struct in + // the Bootloader Cairo code. Our code only uses the first felt (`output` field in the + // struct). Finally, we put the mocked output of `select_input_builtins` in the next + // memory address and increase the AP register accordingly. + vm.segments = segments![((1, 0), (2, 0)), ((1, 1), 42), ((1, 9), (4, 0))]; + vm.run_context.ap = 10; + vm.run_context.fp = 9; + add_segments!(vm, 3); + + let program_header_ptr = Relocatable::from((2, 0)); + let ids_data = non_continuous_ids_data![ + ("program_header", -9), + (vars::PRE_EXECUTION_BUILTIN_PTRS, -8), + ]; + let ap_tracking = ApTracking::new(); + + let mut exec_scopes = ExecutionScopes::new(); + + let mut output_builtin = OutputBuiltinRunner::new(true); + output_builtin.initialize_segments(&mut vm.segments); + vm.builtin_runners + .push(BuiltinRunner::Output(output_builtin)); + + let task = Task::Pie(fibonacci_pie); + exec_scopes.insert_value(vars::TASK, task); + exec_scopes.insert_value(vars::PROGRAM_DATA_BASE, program_header_ptr.clone()); + + // Load the program in memory + load_program_hint(&mut vm, &mut exec_scopes, &ids_data, &ap_tracking) + .expect("Failed to load Cairo PIE task in the VM memory"); + + // Execute it + call_task(&mut vm, &mut exec_scopes, &ids_data, &ap_tracking) + .expect("Hint failed unexpectedly"); + } + #[rstest] fn test_append_fact_topologies(fibonacci: Program) { let task = Task::Program(fibonacci.clone()); diff --git a/vm/src/hint_processor/builtin_hint_processor/bootloader/load_cairo_pie.rs b/vm/src/hint_processor/builtin_hint_processor/bootloader/load_cairo_pie.rs new file mode 100644 index 0000000000..6cc0d063b8 --- /dev/null +++ b/vm/src/hint_processor/builtin_hint_processor/bootloader/load_cairo_pie.rs @@ -0,0 +1,380 @@ +use crate::types::relocatable::{MaybeRelocatable, Relocatable}; +use crate::vm::errors::hint_errors::HintError; +use crate::vm::errors::memory_errors::MemoryError; +use crate::vm::runners::builtin_runner::SignatureBuiltinRunner; +use crate::vm::runners::cairo_pie::{BuiltinAdditionalData, CairoPie, CairoPieMemory}; +use crate::vm::vm_core::VirtualMachine; +use crate::Felt252; +use std::collections::HashMap; +use thiserror_no_std::Error; + +#[derive(Error, Debug)] +pub enum RelocationTableError { + #[error(transparent)] + Memory(#[from] MemoryError), + + #[error("Expected relocatable to point to the start of a segment: {0}")] + ExpectedSegmentBase(Relocatable), + + #[error("Segment index already present in the relocation table: {0}")] + SegmentAlreadyMapped(isize), +} + +#[derive(Error, Debug)] +pub enum SignatureRelocationError { + #[error(transparent)] + Memory(#[from] MemoryError), + + #[error("The PIE requires ECDSA but the VM is not configured to use it")] + EcdsaBuiltinNotFound, + + #[error("The data of the Cairo PIE ECDSA builtin does not match the expected type")] + UnexpectedBuiltinDataType, + + #[error("Relocated signature data ({0} not on signature builtin segment {1}")] + RelocatedDataNotOnBuiltinSegment(Relocatable, isize), +} + +#[derive(Error, Debug)] +pub enum MemoryRelocationError { + #[error(transparent)] + Memory(#[from] MemoryError), +} + +#[derive(Error, Debug)] +pub enum CairoPieLoaderError { + #[error("Error while building relocation table: {0}")] + RelocationTable(#[from] RelocationTableError), + + #[error("Error while relocating signature builtin data: {0}")] + SignatureRelocation(#[from] SignatureRelocationError), + + #[error("Error while relocating Cairo PIE memory: {0}")] + MemoryRelocationError(#[from] MemoryRelocationError), +} + +impl Into for CairoPieLoaderError { + fn into(self) -> HintError { + HintError::CustomHint(self.to_string().into_boxed_str()) + } +} + +/// Keeps track of relocations for different segments. +/// +/// Each entry in `relocations` maps a segment index from the PIE to +/// a pointer in the VM memory. +pub struct RelocationTable { + relocations: HashMap, +} + +impl RelocationTable { + pub fn new() -> Self { + Self { + relocations: Default::default(), + } + } + + /// Inserts an entry in the relocations map. + /// + /// * `segment_index`: Index of the Cairo PIE segment. + /// * `relocation`: Destination in the VM memory. + /// + /// Returns `SegmentAlreadyMapped` if a relocation entry already exists for + /// `segment_index`. + pub fn insert( + &mut self, + segment_index: isize, + relocation: Relocatable, + ) -> Result<(), RelocationTableError> { + if self.relocations.contains_key(&segment_index) { + return Err(RelocationTableError::SegmentAlreadyMapped(segment_index)); + } + self.relocations.insert(segment_index, relocation); + + Ok(()) + } + + /// Relocates a pointer. + /// + /// Considering a relocatable (i, o), if a relocation table entry i -> (i*, o*) exists, + /// returns (i*, o + o*). + /// Returns `MemoryError::Relocation` if there is no matching relocation. + pub fn relocate_address(&self, address: Relocatable) -> Result { + let new_base = self + .relocations + .get(&address.segment_index) + .ok_or(MemoryError::Relocation)?; + + Ok(new_base + address.offset) + } + + /// Relocates any value. + /// + /// Returns the value directly if it is an integer, otherwise returns the relocated address + /// using `relocate_address`. + pub fn relocate_value(&self, value: MaybeRelocatable) -> Result { + match value { + MaybeRelocatable::Int(_) => Ok(value), + MaybeRelocatable::RelocatableValue(address) => { + let relocated_addr = self.relocate_address(address); + relocated_addr.map(MaybeRelocatable::RelocatableValue) + } + } + } +} + +/// Returns the segment index for the given value. +/// Verifies that value is a RelocatableValue with offset 0. +pub fn extract_segment(maybe_relocatable: MaybeRelocatable) -> Result { + match maybe_relocatable { + MaybeRelocatable::RelocatableValue(address) => { + if address.offset != 0 { + return Err(RelocationTableError::ExpectedSegmentBase(address)); + } + + Ok(address.segment_index) + } + MaybeRelocatable::Int(_) => Err(RelocationTableError::Memory( + MemoryError::AddressNotRelocatable, + )), + } +} + +/// Builds a hashmap of address -> value from the `CairoPieMemory` vector. +/// +/// Makes it more convenient to access values in the Cairo PIE memory. +fn build_cairo_pie_memory_map(memory: &CairoPieMemory) -> HashMap { + let mut memory_map: HashMap = HashMap::new(); + + for ((segment_index, offset), value) in memory.0.iter() { + let address = Relocatable::from((*segment_index as isize, *offset)); + memory_map.insert(address, value); + } + + memory_map +} + +/// Builds a relocation table for the specified Cairo PIE. +pub fn build_cairo_pie_relocation_table( + cairo_pie: &CairoPie, + vm: &mut VirtualMachine, + program_address: Relocatable, + execution_segment_address: Relocatable, + ret_fp: Relocatable, + ret_pc: Relocatable, +) -> Result { + let mut relocation_table = RelocationTable::new(); + + relocation_table.insert(cairo_pie.metadata.program_segment.index, program_address)?; + relocation_table.insert( + cairo_pie.metadata.execution_segment.index, + execution_segment_address, + )?; + relocation_table.insert(cairo_pie.metadata.ret_fp_segment.index, ret_fp)?; + relocation_table.insert(cairo_pie.metadata.ret_pc_segment.index, ret_pc)?; + + let origin_execution_segment = Relocatable { + segment_index: cairo_pie.metadata.execution_segment.index, + offset: 0, + }; + + // Create a hashmap of the program memory for easier searching. + // If this turns out to be too expensive, consider building it directly + // when building the CairoPie object. + let memory_map = build_cairo_pie_memory_map(&cairo_pie.memory); + + // Set initial stack relocations. + for (idx, _builtin_name) in cairo_pie.metadata.program.builtins.iter().enumerate() { + let memory_address = &origin_execution_segment + idx; + let segment_index = extract_segment(memory_map[&memory_address].clone())?; + let relocation = vm.get_relocatable(&execution_segment_address + idx)?; + relocation_table.insert(segment_index, relocation)?; + } + + for segment_info in cairo_pie.metadata.extra_segments.iter() { + relocation_table.insert(segment_info.index, vm.add_memory_segment())?; + } + + Ok(relocation_table) +} + +fn extend_additional_data( + builtin: &mut SignatureBuiltinRunner, + data: &HashMap, + relocation_table: &RelocationTable, +) -> Result<(), SignatureRelocationError> { + for (addr, signature) in data { + let relocated_addr = relocation_table.relocate_address(*addr)?; + let builtin_segment_base = builtin.base() as isize; + if relocated_addr.segment_index != builtin_segment_base { + return Err(SignatureRelocationError::RelocatedDataNotOnBuiltinSegment( + relocated_addr, + builtin_segment_base, + )); + } + builtin.add_signature(*addr, signature)?; + } + + Ok(()) +} + +/// Relocate builtin additional data. +/// This should occur before the memory relocation, since the signature builtin assumes that a +/// signature is added before the corresponding public key and message are both written to memory. +fn relocate_builtin_additional_data( + cairo_pie: &CairoPie, + vm: &mut VirtualMachine, + relocation_table: &RelocationTable, +) -> Result<(), SignatureRelocationError> { + let ecdsa_additional_data = match cairo_pie.additional_data.get("ecdsa_builtin") { + Some(additional_data) => match additional_data { + BuiltinAdditionalData::Signature(data) => data, + _ => return Err(SignatureRelocationError::UnexpectedBuiltinDataType), + }, + None => return Ok(()), + }; + + let ecdsa_builtin = vm + .get_signature_builtin() + .map_err(|_| SignatureRelocationError::EcdsaBuiltinNotFound)?; + + extend_additional_data(ecdsa_builtin, ecdsa_additional_data, relocation_table)?; + + Ok(()) +} + +/// Relocates the memory of the PIE. +/// +/// * `cairo_pie`: Cairo PIE. +/// * `vm`: Virtual machine. +/// * `relocation_table`: Relocation rules. +fn relocate_cairo_pie_memory( + cairo_pie: &CairoPie, + vm: &mut VirtualMachine, + relocation_table: &RelocationTable, +) -> Result<(), MemoryRelocationError> { + // Relocate memory segment + for ((segment_index, offset), value) in &cairo_pie.memory.0 { + let address = Relocatable::from((*segment_index as isize, *offset)); + let relocated_address = relocation_table.relocate_address(address)?; + let relocated_value = relocation_table.relocate_value(value.clone())?; + + vm.segments + .memory + .insert(relocated_address, relocated_value)?; + } + + Ok(()) +} + +/// Load memory entries of the inner program. +/// +/// Relocates (copies) the memory of the PIE to segments allocated for the current task. +/// This replaces executing hints in a non-trusted program. +pub(crate) fn load_cairo_pie( + cairo_pie: &CairoPie, + vm: &mut VirtualMachine, + program_address: Relocatable, + execution_segment_address: Relocatable, + ret_fp: Relocatable, + ret_pc: Relocatable, +) -> Result<(), CairoPieLoaderError> { + let relocation_table = build_cairo_pie_relocation_table( + &cairo_pie, + vm, + program_address, + execution_segment_address, + ret_fp, + ret_pc, + )?; + + relocate_builtin_additional_data(&cairo_pie, vm, &relocation_table)?; + relocate_cairo_pie_memory(&cairo_pie, vm, &relocation_table)?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + + #[test] + fn test_relocate_value() { + let relocation_table = RelocationTable::new(); + + let value = MaybeRelocatable::Int(Felt252::from(64)); + assert_eq!(relocation_table.relocate_value(value.clone()), Ok(value)); + } + + #[test] + fn test_relocate_address() { + let mut relocation_table = RelocationTable::new(); + let relocation = Relocatable::from((2, 5)); + relocation_table.insert(1, relocation.clone()).unwrap(); + + let address = Relocatable::from((1, 27)); + let expected_address = Relocatable::from((2, 32)); + assert_eq!( + relocation_table.relocate_address(address), + Ok(expected_address) + ); + + let value = MaybeRelocatable::RelocatableValue(address); + let expected_value = MaybeRelocatable::RelocatableValue(expected_address); + assert_eq!(relocation_table.relocate_value(value), Ok(expected_value)); + } + + #[test] + fn test_relocate_address_no_matching_relocation() { + let relocation_table = RelocationTable::new(); + + let value = MaybeRelocatable::RelocatableValue(Relocatable::from((1, 0))); + assert_eq!( + relocation_table.relocate_value(value.clone()), + Err(MemoryError::Relocation) + ); + } + + #[test] + fn test_relocation_table_write_twice() { + let segment_index = 1; + let relocation = Relocatable::from((2, 0)); + + let mut relocation_table = RelocationTable::new(); + relocation_table.insert(segment_index, relocation).unwrap(); + + let new_relocation = Relocatable::from((3, 0)); + + let result = relocation_table.insert(segment_index, new_relocation); + assert_matches!( + result, + Err(RelocationTableError::SegmentAlreadyMapped(idx)) if idx == segment_index + ); + } + + #[test] + fn test_extract_segment_base() { + let address = Relocatable::from((1, 0)); + let result = extract_segment(MaybeRelocatable::RelocatableValue(address)).unwrap(); + assert_eq!(result, address.segment_index); + } + + #[test] + fn test_extract_segment_base_not_a_base() { + let address = Relocatable::from((1, 5)); + let result = extract_segment(MaybeRelocatable::RelocatableValue(address)); + assert_matches!(result, Err(RelocationTableError::ExpectedSegmentBase(relocatable)) if relocatable == address); + } + + #[test] + fn test_extract_segment_base_not_an_address() { + let result = extract_segment(MaybeRelocatable::Int(Felt252::from(1))); + assert_matches!( + result, + Err(RelocationTableError::Memory( + MemoryError::AddressNotRelocatable + )) + ); + } +} diff --git a/vm/src/hint_processor/builtin_hint_processor/bootloader/mod.rs b/vm/src/hint_processor/builtin_hint_processor/bootloader/mod.rs index 7a3b62caa2..aedfca2518 100644 --- a/vm/src/hint_processor/builtin_hint_processor/bootloader/mod.rs +++ b/vm/src/hint_processor/builtin_hint_processor/bootloader/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod bootloader_hints; pub(crate) mod execute_task_hints; mod fact_topologies; pub(crate) mod inner_select_builtins; +mod load_cairo_pie; mod program_hash; mod program_loader; pub(crate) mod select_builtins; diff --git a/vm/src/hint_processor/builtin_hint_processor/bootloader/types.rs b/vm/src/hint_processor/builtin_hint_processor/bootloader/types.rs index a2d2250db1..0fa626b536 100644 --- a/vm/src/hint_processor/builtin_hint_processor/bootloader/types.rs +++ b/vm/src/hint_processor/builtin_hint_processor/bootloader/types.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use crate::serde::deserialize_program::deserialize_and_parse_program; use crate::types::errors::program_errors::ProgramError; + use crate::types::program::Program; use crate::vm::runners::cairo_pie::{CairoPie, StrippedProgram}; @@ -81,14 +82,14 @@ impl TaskSpec { } } -#[derive(Deserialize, Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct SimpleBootloaderInput { pub fact_topologies_path: Option, pub single_page: bool, pub tasks: Vec, } -#[derive(Deserialize, Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct BootloaderInput { pub simple_bootloader_input: SimpleBootloaderInput, pub bootloader_config: BootloaderConfig, diff --git a/vm/src/hint_processor/builtin_hint_processor/bootloader/vars.rs b/vm/src/hint_processor/builtin_hint_processor/bootloader/vars.rs index 4541768736..c34e8fb143 100644 --- a/vm/src/hint_processor/builtin_hint_processor/bootloader/vars.rs +++ b/vm/src/hint_processor/builtin_hint_processor/bootloader/vars.rs @@ -39,3 +39,6 @@ pub(crate) const N_BUILTINS: &str = "n_builtins"; /// Number of selected builtins for the current program. pub(crate) const N_SELECTED_BUILTINS: &str = "n_selected_builtins"; + +/// "pre_execution_builtin_ptrs" +pub(crate) const PRE_EXECUTION_BUILTIN_PTRS: &str = "pre_execution_builtin_ptrs"; diff --git a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index abe8ed059b..85a1bbff8d 100644 --- a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -29,8 +29,8 @@ use super::{ }; use crate::hint_processor::builtin_hint_processor::bootloader::bootloader_hints::compute_and_configure_fact_topologies; use crate::hint_processor::builtin_hint_processor::bootloader::execute_task_hints::{ - allocate_program_data_segment, append_fact_topologies, load_program_hint, validate_hash, - write_return_builtins_hint, + allocate_program_data_segment, append_fact_topologies, call_task, load_program_hint, + validate_hash, write_return_builtins_hint, }; use crate::hint_processor::builtin_hint_processor::bootloader::inner_select_builtins::select_builtin; use crate::hint_processor::builtin_hint_processor::bootloader::select_builtins::select_builtins_enter_scope; @@ -909,6 +909,9 @@ impl HintProcessorLogic for BuiltinHintProcessor { hint_code::EXECUTE_TASK_ASSERT_PROGRAM_ADDRESS => { assert_program_address(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } + hint_code::EXECUTE_TASK_CALL_TASK => { + call_task(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) + } hint_code::EXECUTE_TASK_WRITE_RETURN_BUILTINS => write_return_builtins_hint( vm, exec_scopes, diff --git a/vm/src/vm/runners/builtin_runner/output.rs b/vm/src/vm/runners/builtin_runner/output.rs index d7272447a4..19aaf36e85 100644 --- a/vm/src/vm/runners/builtin_runner/output.rs +++ b/vm/src/vm/runners/builtin_runner/output.rs @@ -13,7 +13,7 @@ use super::OUTPUT_BUILTIN_NAME; #[derive(Debug, Clone)] pub struct OutputBuiltinRunner { - base: usize, + pub(crate) base: usize, pub(crate) pages: Pages, pub(crate) attributes: Attributes, pub(crate) stop_ptr: Option, diff --git a/vm/src/vm/runners/cairo_pie.rs b/vm/src/vm/runners/cairo_pie.rs index 4f5b0ee5b2..385cbefb48 100644 --- a/vm/src/vm/runners/cairo_pie.rs +++ b/vm/src/vm/runners/cairo_pie.rs @@ -642,14 +642,14 @@ mod test { assert_eq!(cairo_pie.memory.len(), 88); // Check a few values assert_eq!( - cairo_pie.memory[0], + cairo_pie.memory.0[0], ( (0usize, 0usize), MaybeRelocatable::Int(Felt252::from(290341444919459839u64)) ) ); assert_eq!( - cairo_pie.memory[cairo_pie.memory.len() - 1], + cairo_pie.memory.0[cairo_pie.memory.len() - 1], ( (1usize, 60usize), MaybeRelocatable::RelocatableValue(Relocatable::from((2, 2)))