Skip to main content

cairo_vm/vm/runners/
cairo_runner.rs

1use crate::vm::trace::trace_entry::TraceEntry;
2
3use std::{
4    any::Any,
5    collections::{BTreeMap, HashMap, HashSet},
6    ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
7};
8
9use crate::{
10    air_private_input::AirPrivateInput,
11    air_public_input::{PublicInput, PublicInputError},
12    math_utils::safe_div_usize,
13    types::{builtin_name::BuiltinName, layout::CairoLayoutParams, layout_name::LayoutName},
14    vm::{
15        runners::builtin_runner::SegmentArenaBuiltinRunner,
16        trace::trace_entry::{relocate_trace_register, RelocatedTraceEntry},
17    },
18    Felt252,
19};
20
21use crate::{
22    hint_processor::hint_processor_definition::{HintProcessor, HintReference},
23    types::{
24        errors::{math_errors::MathError, program_errors::ProgramError},
25        exec_scope::ExecutionScopes,
26        layout::CairoLayout,
27        program::Program,
28        relocatable::{relocate_address, relocate_value, MaybeRelocatable, Relocatable},
29    },
30    utils::is_subsequence,
31    vm::{
32        errors::{
33            cairo_run_errors::CairoRunError,
34            memory_errors::{InsufficientAllocatedCellsError, MemoryError},
35            runner_errors::RunnerError,
36            trace_errors::TraceError,
37            vm_errors::VirtualMachineError,
38            vm_exception::VmException,
39        },
40        security::verify_secure_runner,
41        {
42            runners::builtin_runner::{
43                BitwiseBuiltinRunner, BuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner,
44                OutputBuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner,
45            },
46            vm_core::ExtendedExecutionResourceType,
47            vm_core::VirtualMachine,
48        },
49    },
50};
51use num_integer::div_rem;
52use num_traits::{ToPrimitive, Zero};
53use serde::{Deserialize, Serialize};
54
55use super::{builtin_runner::ModBuiltinRunner, cairo_pie::CairoPieAdditionalData};
56use super::{
57    builtin_runner::{
58        KeccakBuiltinRunner, PoseidonBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD,
59    },
60    cairo_pie::{self, CairoPie, CairoPieMetadata, CairoPieVersion},
61};
62use crate::types::instance_definitions::mod_instance_def::ModInstanceDef;
63use tracing::info;
64
65pub const ORDERED_BUILTIN_LIST: &[BuiltinName] = &[
66    BuiltinName::output,
67    BuiltinName::pedersen,
68    BuiltinName::range_check,
69    BuiltinName::ecdsa,
70    BuiltinName::bitwise,
71    BuiltinName::ec_op,
72    BuiltinName::keccak,
73    BuiltinName::poseidon,
74    BuiltinName::range_check96,
75    BuiltinName::add_mod,
76    BuiltinName::mul_mod,
77];
78
79#[derive(Clone, Debug, Eq, PartialEq)]
80pub enum CairoArg {
81    Single(MaybeRelocatable),
82    Array(Vec<MaybeRelocatable>),
83    Composed(Vec<CairoArg>),
84}
85
86impl From<MaybeRelocatable> for CairoArg {
87    fn from(other: MaybeRelocatable) -> Self {
88        CairoArg::Single(other)
89    }
90}
91
92impl From<Vec<MaybeRelocatable>> for CairoArg {
93    fn from(other: Vec<MaybeRelocatable>) -> Self {
94        CairoArg::Array(other)
95    }
96}
97
98// ================
99//   RunResources
100// ================
101
102/// Maintains the resources of a cairo run. Can be used across multiple runners.
103#[derive(Clone, Default, Debug, PartialEq)]
104pub struct RunResources {
105    n_steps: Option<usize>,
106}
107
108/// This trait is in charge of overseeing the VM's step usage in contexts where a limited amount of steps are available
109/// for a single execution (which may or not involve other executions taking place in the duration of it ).
110/// This is mostly used in the context of starknet, where contracts can call other contracts while sharing the same step limit.
111/// For the general use case, the default implementation can be used, which ignores resource tracking altogether
112/// For an example on how to implement this trait for its intended purpose check out [BuiltinHintProcessor](cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor)
113pub trait ResourceTracker {
114    /// Returns true if there are no more steps left to run
115    fn consumed(&self) -> bool {
116        false
117    }
118    /// Subtracts 1 step from the available steps
119    fn consume_step(&mut self) {}
120    /// Returns the available steps for the run
121    fn get_n_steps(&self) -> Option<usize> {
122        None
123    }
124    /// Returns a reference to the available resources
125    fn run_resources(&self) -> &RunResources {
126        &RunResources { n_steps: None }
127    }
128}
129
130impl RunResources {
131    pub fn new(n_steps: usize) -> Self {
132        Self {
133            n_steps: Some(n_steps),
134        }
135    }
136}
137
138impl ResourceTracker for RunResources {
139    fn consumed(&self) -> bool {
140        if self.n_steps == Some(0) {
141            return true;
142        }
143        false
144    }
145
146    fn consume_step(&mut self) {
147        if let Some(n_steps) = self.n_steps {
148            self.n_steps = Some(n_steps.saturating_sub(1));
149        }
150    }
151
152    fn get_n_steps(&self) -> Option<usize> {
153        self.n_steps
154    }
155
156    fn run_resources(&self) -> &RunResources {
157        self
158    }
159}
160
161pub struct CairoRunner {
162    pub vm: VirtualMachine,
163    pub(crate) program: Program,
164    layout: CairoLayout,
165    final_pc: Option<Relocatable>,
166    pub program_base: Option<Relocatable>,
167    execution_base: Option<Relocatable>,
168    entrypoint: Option<usize>,
169    initial_ap: Option<Relocatable>,
170    initial_fp: Option<Relocatable>,
171    initial_pc: Option<Relocatable>,
172    run_ended: bool,
173    segments_finalized: bool,
174    execution_public_memory: Option<Vec<usize>>,
175    pub(crate) runner_mode: RunnerMode,
176    pub relocated_memory: Vec<Option<Felt252>>,
177    pub exec_scopes: ExecutionScopes,
178    pub relocated_trace: Option<Vec<RelocatedTraceEntry>>,
179}
180
181#[derive(Clone, Debug, PartialEq)]
182pub enum RunnerMode {
183    ExecutionMode,
184    ProofModeCanonical,
185    ProofModeCairo1,
186}
187
188impl CairoRunner {
189    /// The `dynamic_layout_params` argument should only be used with dynamic layout.
190    /// It is ignored otherwise.
191    pub fn new_v2(
192        program: &Program,
193        layout: LayoutName,
194        dynamic_layout_params: Option<CairoLayoutParams>,
195        mode: RunnerMode,
196        trace_enabled: bool,
197        disable_trace_padding: bool,
198    ) -> Result<CairoRunner, RunnerError> {
199        let cairo_layout = match layout {
200            LayoutName::plain => CairoLayout::plain_instance(),
201            LayoutName::small => CairoLayout::small_instance(),
202            LayoutName::dex => CairoLayout::dex_instance(),
203            LayoutName::recursive => CairoLayout::recursive_instance(),
204            LayoutName::starknet => CairoLayout::starknet_instance(),
205            LayoutName::starknet_with_keccak => CairoLayout::starknet_with_keccak_instance(),
206            LayoutName::recursive_large_output => CairoLayout::recursive_large_output_instance(),
207            LayoutName::recursive_with_poseidon => CairoLayout::recursive_with_poseidon(),
208            LayoutName::all_cairo => CairoLayout::all_cairo_instance(),
209            LayoutName::all_cairo_stwo => CairoLayout::all_cairo_stwo_instance(),
210            LayoutName::stwo_no_ecop => CairoLayout::stwo_no_ecop_instance(),
211            LayoutName::all_solidity => CairoLayout::all_solidity_instance(),
212            LayoutName::perpetual => CairoLayout::perpetual_instance(),
213            LayoutName::dex_with_bitwise => CairoLayout::dex_with_bitwise_instance(),
214            LayoutName::dynamic => {
215                let params =
216                    dynamic_layout_params.ok_or(RunnerError::MissingDynamicLayoutParams)?;
217
218                CairoLayout::dynamic_instance(params)?
219            }
220        };
221        Ok(CairoRunner {
222            program: program.clone(),
223            vm: VirtualMachine::new(trace_enabled, disable_trace_padding),
224            layout: cairo_layout,
225            final_pc: None,
226            program_base: None,
227            execution_base: None,
228            entrypoint: program.shared_program_data.main,
229            initial_ap: None,
230            initial_fp: None,
231            initial_pc: None,
232            run_ended: false,
233            segments_finalized: false,
234            runner_mode: mode.clone(),
235            relocated_memory: Vec::new(),
236            exec_scopes: ExecutionScopes::new(),
237            execution_public_memory: if mode != RunnerMode::ExecutionMode {
238                Some(Vec::new())
239            } else {
240                None
241            },
242            relocated_trace: None,
243        })
244    }
245
246    pub fn new(
247        program: &Program,
248        layout: LayoutName,
249        dynamic_layout_params: Option<CairoLayoutParams>,
250        proof_mode: bool,
251        trace_enabled: bool,
252        disable_trace_padding: bool,
253    ) -> Result<CairoRunner, RunnerError> {
254        // `disable_trace_padding` can only be used in `proof_mode`, so we enforce this here to
255        // avoid unintended behavior.
256        if disable_trace_padding && !proof_mode {
257            return Err(RunnerError::DisableTracePaddingWithoutProofMode);
258        }
259        if proof_mode {
260            Self::new_v2(
261                program,
262                layout,
263                dynamic_layout_params,
264                RunnerMode::ProofModeCanonical,
265                trace_enabled,
266                disable_trace_padding,
267            )
268        } else {
269            Self::new_v2(
270                program,
271                layout,
272                dynamic_layout_params,
273                RunnerMode::ExecutionMode,
274                trace_enabled,
275                disable_trace_padding,
276            )
277        }
278    }
279
280    pub fn initialize(&mut self, allow_missing_builtins: bool) -> Result<Relocatable, RunnerError> {
281        info!("Initializing builtins.");
282        self.initialize_builtins(allow_missing_builtins)?;
283        info!("Initializing segments.");
284        self.initialize_segments(None);
285        info!("Initializing main entrypoint.");
286        let end = self.initialize_main_entrypoint()?;
287        info!("Initializing zero segments.");
288        for builtin_runner in self.vm.builtin_runners.iter_mut() {
289            if let BuiltinRunner::Mod(runner) = builtin_runner {
290                runner.initialize_zero_segment(&mut self.vm.segments);
291            }
292        }
293        info!("Initializing VM.");
294        self.initialize_vm()?;
295        Ok(end)
296    }
297
298    /// Creates the builtin runners according to the builtins used by the program and the selected layout
299    /// When running in proof_mode, all builtins in the layout will be created, and only those in the program will be included
300    /// When not running in proof_mode, only program builtins will be created and included
301    /// Unless `allow_missing_builtins` is set to true, an error will be returned if a builtin is included in the program but not on the layout
302    ///
303    /// NOTE: 'included' does not refer to the builtin being included in the builtin runners but rather to the flag `included` in a builtin.
304    pub fn initialize_builtins(&mut self, allow_missing_builtins: bool) -> Result<(), RunnerError> {
305        if !is_subsequence(&self.program.builtins, ORDERED_BUILTIN_LIST) {
306            return Err(RunnerError::DisorderedBuiltins);
307        };
308        let mut program_builtins: HashSet<&BuiltinName> = self.program.builtins.iter().collect();
309
310        if self.layout.builtins.output {
311            let included = program_builtins.remove(&BuiltinName::output);
312            if included || self.is_proof_mode() {
313                self.vm
314                    .builtin_runners
315                    .push(OutputBuiltinRunner::new(included).into());
316            }
317        }
318
319        if let Some(instance_def) = self.layout.builtins.pedersen.as_ref() {
320            let included = program_builtins.remove(&BuiltinName::pedersen);
321            if included || self.is_proof_mode() {
322                self.vm
323                    .builtin_runners
324                    .push(HashBuiltinRunner::new(instance_def.ratio, included).into());
325            }
326        }
327
328        if let Some(instance_def) = self.layout.builtins.range_check.as_ref() {
329            let included = program_builtins.remove(&BuiltinName::range_check);
330            if included || self.is_proof_mode() {
331                self.vm.builtin_runners.push(
332                    RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new_with_low_ratio(
333                        instance_def.ratio,
334                        included,
335                    )
336                    .into(),
337                );
338            }
339        }
340
341        if let Some(instance_def) = self.layout.builtins.ecdsa.as_ref() {
342            let included = program_builtins.remove(&BuiltinName::ecdsa);
343            if included || self.is_proof_mode() {
344                self.vm
345                    .builtin_runners
346                    .push(SignatureBuiltinRunner::new(instance_def.ratio, included).into());
347            }
348        }
349
350        if let Some(instance_def) = self.layout.builtins.bitwise.as_ref() {
351            let included = program_builtins.remove(&BuiltinName::bitwise);
352            if included || self.is_proof_mode() {
353                self.vm
354                    .builtin_runners
355                    .push(BitwiseBuiltinRunner::new(instance_def.ratio, included).into());
356            }
357        }
358
359        if let Some(instance_def) = self.layout.builtins.ec_op.as_ref() {
360            let included = program_builtins.remove(&BuiltinName::ec_op);
361            if included || self.is_proof_mode() {
362                self.vm
363                    .builtin_runners
364                    .push(EcOpBuiltinRunner::new(instance_def.ratio, included).into());
365            }
366        }
367
368        if let Some(instance_def) = self.layout.builtins.keccak.as_ref() {
369            let included = program_builtins.remove(&BuiltinName::keccak);
370            if included || self.is_proof_mode() {
371                self.vm
372                    .builtin_runners
373                    .push(KeccakBuiltinRunner::new(instance_def.ratio, included).into());
374            }
375        }
376
377        if let Some(instance_def) = self.layout.builtins.poseidon.as_ref() {
378            let included = program_builtins.remove(&BuiltinName::poseidon);
379            if included || self.is_proof_mode() {
380                self.vm
381                    .builtin_runners
382                    .push(PoseidonBuiltinRunner::new(instance_def.ratio, included).into());
383            }
384        }
385
386        if let Some(instance_def) = self.layout.builtins.range_check96.as_ref() {
387            let included = program_builtins.remove(&BuiltinName::range_check96);
388            if included || self.is_proof_mode() {
389                self.vm.builtin_runners.push(
390                    RangeCheckBuiltinRunner::<RC_N_PARTS_96>::new_with_low_ratio(
391                        instance_def.ratio,
392                        included,
393                    )
394                    .into(),
395                );
396            }
397        }
398        if let Some(instance_def) = self.layout.builtins.add_mod.as_ref() {
399            let included = program_builtins.remove(&BuiltinName::add_mod);
400            if included || self.is_proof_mode() {
401                self.vm
402                    .builtin_runners
403                    .push(ModBuiltinRunner::new_add_mod(instance_def, included).into());
404            }
405        }
406        if let Some(instance_def) = self.layout.builtins.mul_mod.as_ref() {
407            let included = program_builtins.remove(&BuiltinName::mul_mod);
408            if included || self.is_proof_mode() {
409                self.vm
410                    .builtin_runners
411                    .push(ModBuiltinRunner::new_mul_mod(instance_def, included).into());
412            }
413        }
414        if !program_builtins.is_empty() && !allow_missing_builtins {
415            return Err(RunnerError::NoBuiltinForInstance(Box::new((
416                program_builtins.iter().map(|n| **n).collect(),
417                self.layout.name,
418            ))));
419        }
420
421        Ok(())
422    }
423
424    fn is_proof_mode(&self) -> bool {
425        self.runner_mode == RunnerMode::ProofModeCanonical
426            || self.runner_mode == RunnerMode::ProofModeCairo1
427    }
428
429    // Initialize all program builtins. Values used are the original one from the CairoFunctionRunner
430    // Values extracted from here: https://github.com/starkware-libs/cairo-lang/blob/4fb83010ab77aa7ead0c9df4b0c05e030bc70b87/src/starkware/cairo/common/cairo_function_runner.py#L28
431    pub fn initialize_program_builtins(&mut self) -> Result<(), RunnerError> {
432        fn initialize_builtin(name: BuiltinName, vm: &mut VirtualMachine) {
433            match name {
434                BuiltinName::pedersen => vm
435                    .builtin_runners
436                    .push(HashBuiltinRunner::new(Some(32), true).into()),
437                BuiltinName::range_check => vm.builtin_runners.push(
438                    RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(1), true).into(),
439                ),
440                BuiltinName::output => vm
441                    .builtin_runners
442                    .push(OutputBuiltinRunner::new(true).into()),
443                BuiltinName::ecdsa => vm
444                    .builtin_runners
445                    .push(SignatureBuiltinRunner::new(Some(1), true).into()),
446                BuiltinName::bitwise => vm
447                    .builtin_runners
448                    .push(BitwiseBuiltinRunner::new(Some(1), true).into()),
449                BuiltinName::ec_op => vm
450                    .builtin_runners
451                    .push(EcOpBuiltinRunner::new(Some(1), true).into()),
452                BuiltinName::keccak => vm
453                    .builtin_runners
454                    .push(KeccakBuiltinRunner::new(Some(1), true).into()),
455                BuiltinName::poseidon => vm
456                    .builtin_runners
457                    .push(PoseidonBuiltinRunner::new(Some(1), true).into()),
458                BuiltinName::segment_arena => vm
459                    .builtin_runners
460                    .push(SegmentArenaBuiltinRunner::new(true).into()),
461                BuiltinName::range_check96 => vm
462                    .builtin_runners
463                    .push(RangeCheckBuiltinRunner::<RC_N_PARTS_96>::new(Some(1), true).into()),
464                BuiltinName::add_mod => vm.builtin_runners.push(
465                    ModBuiltinRunner::new_add_mod(&ModInstanceDef::new(Some(1), 1, 96), true)
466                        .into(),
467                ),
468                BuiltinName::mul_mod => vm.builtin_runners.push(
469                    ModBuiltinRunner::new_mul_mod(&ModInstanceDef::new(Some(1), 1, 96), true)
470                        .into(),
471                ),
472            }
473        }
474
475        for builtin_name in &self.program.builtins {
476            initialize_builtin(*builtin_name, &mut self.vm);
477        }
478        Ok(())
479    }
480
481    ///Creates the necessary segments for the program, execution, and each builtin on the MemorySegmentManager and stores the first adress of each of this new segments as each owner's base
482    pub fn initialize_segments(&mut self, program_base: Option<Relocatable>) {
483        self.program_base = match program_base {
484            Some(base) => Some(base),
485            None => Some(self.vm.add_memory_segment()),
486        };
487        self.execution_base = Some(self.vm.add_memory_segment());
488        for builtin_runner in self.vm.builtin_runners.iter_mut() {
489            builtin_runner.initialize_segments(&mut self.vm.segments);
490        }
491    }
492
493    fn initialize_state(
494        &mut self,
495        entrypoint: usize,
496        stack: Vec<MaybeRelocatable>,
497    ) -> Result<(), RunnerError> {
498        let prog_base = self.program_base.ok_or(RunnerError::NoProgBase)?;
499        let exec_base = self.execution_base.ok_or(RunnerError::NoExecBase)?;
500        self.initial_pc = Some((prog_base + entrypoint)?);
501        self.vm
502            .load_data(prog_base, &self.program.shared_program_data.data)
503            .map_err(RunnerError::MemoryInitializationError)?;
504
505        // Mark all addresses from the program segment as accessed
506        for i in 0..self.program.shared_program_data.data.len() {
507            self.vm.segments.memory.mark_as_accessed((prog_base + i)?);
508        }
509        self.vm
510            .segments
511            .load_data(exec_base, &stack)
512            .map_err(RunnerError::MemoryInitializationError)?;
513        Ok(())
514    }
515
516    pub fn initialize_function_entrypoint(
517        &mut self,
518        entrypoint: usize,
519        mut stack: Vec<MaybeRelocatable>,
520        return_fp: MaybeRelocatable,
521    ) -> Result<Relocatable, RunnerError> {
522        let end = self.vm.add_memory_segment();
523        stack.append(&mut vec![
524            return_fp,
525            MaybeRelocatable::RelocatableValue(end),
526        ]);
527        if let Some(base) = &self.execution_base {
528            self.initial_fp = Some(Relocatable {
529                segment_index: base.segment_index,
530                offset: base.offset + stack.len(),
531            });
532            self.initial_ap = self.initial_fp;
533        } else {
534            return Err(RunnerError::NoExecBase);
535        }
536        self.initialize_state(entrypoint, stack)?;
537        self.final_pc = Some(end);
538        Ok(end)
539    }
540
541    ///Initializes state for running a program from the main() entrypoint.
542    ///If self.is_proof_mode() == True, the execution starts from the start label rather then the main() function.
543    ///Returns the value of the program counter after returning from main.
544    fn initialize_main_entrypoint(&mut self) -> Result<Relocatable, RunnerError> {
545        let mut stack = Vec::new();
546        {
547            let builtin_runners = self
548                .vm
549                .builtin_runners
550                .iter()
551                .map(|b| (b.name(), b))
552                .collect::<HashMap<_, _>>();
553            for builtin_name in &self.program.builtins {
554                if let Some(builtin_runner) = builtin_runners.get(builtin_name) {
555                    stack.append(&mut builtin_runner.initial_stack());
556                } else {
557                    stack.push(Felt252::ZERO.into())
558                }
559            }
560        }
561
562        if self.is_proof_mode() {
563            // In canonical proof mode, add the dummy last fp and pc to the public memory, so that the verifier can enforce
564
565            // canonical offset should be 2 for Cairo 0
566            let mut target_offset = 2;
567
568            // Cairo1 is not adding data to check [fp - 2] = fp, and has a different initialization of the stack. This should be updated.
569            // Cairo0 remains canonical
570
571            if matches!(self.runner_mode, RunnerMode::ProofModeCairo1) {
572                target_offset = stack.len() + 2;
573
574                // This values shouldn't be needed with a canonical proof mode
575                let return_fp = self.vm.add_memory_segment();
576                let end = self.vm.add_memory_segment();
577                stack.append(&mut vec![
578                    MaybeRelocatable::RelocatableValue(return_fp),
579                    MaybeRelocatable::RelocatableValue(end),
580                ]);
581
582                self.initialize_state(
583                    self.program
584                        .shared_program_data
585                        .start
586                        .ok_or(RunnerError::NoProgramStart)?,
587                    stack,
588                )?;
589            } else {
590                let mut stack_prefix = vec![
591                    Into::<MaybeRelocatable>::into(
592                        (self.execution_base.ok_or(RunnerError::NoExecBase)? + target_offset)?,
593                    ),
594                    MaybeRelocatable::from(Felt252::zero()),
595                ];
596                stack_prefix.extend(stack.clone());
597
598                self.execution_public_memory = Some(Vec::from_iter(0..stack_prefix.len()));
599
600                self.initialize_state(
601                    self.program
602                        .shared_program_data
603                        .start
604                        .ok_or(RunnerError::NoProgramStart)?,
605                    stack_prefix.clone(),
606                )?;
607            }
608
609            self.initial_fp =
610                Some((self.execution_base.ok_or(RunnerError::NoExecBase)? + target_offset)?);
611
612            self.initial_ap = self.initial_fp;
613            return Ok((self.program_base.ok_or(RunnerError::NoProgBase)?
614                + self
615                    .program
616                    .shared_program_data
617                    .end
618                    .ok_or(RunnerError::NoProgramEnd)?)?);
619        }
620
621        let return_fp = self.vm.add_memory_segment();
622        if let Some(main) = &self.entrypoint {
623            let main_clone = *main;
624            Ok(self.initialize_function_entrypoint(
625                main_clone,
626                stack,
627                MaybeRelocatable::RelocatableValue(return_fp),
628            )?)
629        } else {
630            Err(RunnerError::MissingMain)
631        }
632    }
633
634    pub fn initialize_vm(&mut self) -> Result<(), RunnerError> {
635        self.vm.run_context.pc = *self.initial_pc.as_ref().ok_or(RunnerError::NoPC)?;
636        self.vm.run_context.ap = self.initial_ap.as_ref().ok_or(RunnerError::NoAP)?.offset;
637        self.vm.run_context.fp = self.initial_fp.as_ref().ok_or(RunnerError::NoFP)?.offset;
638        for builtin in self.vm.builtin_runners.iter() {
639            builtin.add_validation_rule(&mut self.vm.segments.memory);
640        }
641
642        self.vm
643            .segments
644            .memory
645            .validate_existing_memory()
646            .map_err(RunnerError::MemoryValidationError)
647    }
648
649    pub fn get_initial_fp(&self) -> Option<Relocatable> {
650        self.initial_fp
651    }
652
653    /// Gets the data used by the HintProcessor to execute each hint
654    pub fn get_hint_data(
655        &self,
656        references: &[HintReference],
657        hint_executor: &mut dyn HintProcessor,
658    ) -> Result<Vec<Box<dyn Any>>, VirtualMachineError> {
659        self.program
660            .shared_program_data
661            .hints_collection
662            .iter_hints()
663            .map(|hint| {
664                hint_executor
665                    .compile_hint(
666                        &hint.code,
667                        &hint.flow_tracking_data.ap_tracking,
668                        &hint.flow_tracking_data.reference_ids,
669                        references,
670                        &hint.accessible_scopes,
671                        self.program.constants.clone(),
672                    )
673                    .map_err(|_| VirtualMachineError::CompileHintFail(hint.code.clone().into()))
674            })
675            .collect()
676    }
677
678    pub fn get_constants(&self) -> &HashMap<String, Felt252> {
679        &self.program.constants
680    }
681
682    pub fn get_program_builtins(&self) -> &Vec<BuiltinName> {
683        &self.program.builtins
684    }
685
686    pub fn run_until_pc(
687        &mut self,
688        address: Relocatable,
689        hint_processor: &mut dyn HintProcessor,
690    ) -> Result<(), VirtualMachineError> {
691        let references = &self.program.shared_program_data.reference_manager;
692        #[cfg(not(feature = "extensive_hints"))]
693        let hint_data = self.get_hint_data(references, hint_processor)?;
694        #[cfg(feature = "extensive_hints")]
695        let mut hint_data = self.get_hint_data(references, hint_processor)?;
696        #[cfg(feature = "extensive_hints")]
697        let mut hint_ranges = self
698            .program
699            .shared_program_data
700            .hints_collection
701            .hints_ranges
702            .clone();
703        #[cfg(feature = "test_utils")]
704        self.vm.execute_before_first_step(&hint_data)?;
705        while self.vm.get_pc() != address && !hint_processor.consumed() {
706            self.vm.step(
707                hint_processor,
708                &mut self.exec_scopes,
709                #[cfg(feature = "extensive_hints")]
710                &mut hint_data,
711                #[cfg(not(feature = "extensive_hints"))]
712                self.program
713                    .shared_program_data
714                    .hints_collection
715                    .get_hint_range_for_pc(self.vm.get_pc().offset)
716                    .and_then(|range| {
717                        range.and_then(|(start, length)| hint_data.get(start..start + length.get()))
718                    })
719                    .unwrap_or(&[]),
720                #[cfg(feature = "extensive_hints")]
721                &mut hint_ranges,
722                #[cfg(feature = "test_utils")]
723                &self.program.constants,
724            )?;
725
726            hint_processor.consume_step();
727        }
728
729        if self.vm.get_pc() != address {
730            return Err(VirtualMachineError::UnfinishedExecution);
731        }
732
733        Ok(())
734    }
735
736    /// Execute an exact number of steps on the program from the actual position.
737    pub fn run_for_steps(
738        &mut self,
739        steps: usize,
740        hint_processor: &mut dyn HintProcessor,
741    ) -> Result<(), VirtualMachineError> {
742        let references = &self.program.shared_program_data.reference_manager;
743        #[cfg(not(feature = "extensive_hints"))]
744        let hint_data = self.get_hint_data(references, hint_processor)?;
745        #[cfg(feature = "extensive_hints")]
746        let mut hint_data = self.get_hint_data(references, hint_processor)?;
747        #[cfg(feature = "extensive_hints")]
748        let mut hint_ranges = self
749            .program
750            .shared_program_data
751            .hints_collection
752            .hints_ranges
753            .clone();
754        #[cfg(not(feature = "extensive_hints"))]
755        let hint_data = &self
756            .program
757            .shared_program_data
758            .hints_collection
759            .get_hint_range_for_pc(self.vm.get_pc().offset)
760            .and_then(|range| {
761                range.and_then(|(start, length)| hint_data.get(start..start + length.get()))
762            })
763            .unwrap_or(&[]);
764
765        for remaining_steps in (1..=steps).rev() {
766            if self.final_pc.as_ref() == Some(&self.vm.get_pc()) {
767                return Err(VirtualMachineError::EndOfProgram(remaining_steps));
768            }
769
770            self.vm.step(
771                hint_processor,
772                &mut self.exec_scopes,
773                #[cfg(feature = "extensive_hints")]
774                &mut hint_data,
775                #[cfg(not(feature = "extensive_hints"))]
776                hint_data,
777                #[cfg(feature = "extensive_hints")]
778                &mut hint_ranges,
779                #[cfg(feature = "test_utils")]
780                &self.program.constants,
781            )?;
782        }
783
784        Ok(())
785    }
786
787    /// Execute steps until a number of steps since the start of the program is reached.
788    pub fn run_until_steps(
789        &mut self,
790        steps: usize,
791        hint_processor: &mut dyn HintProcessor,
792    ) -> Result<(), VirtualMachineError> {
793        self.run_for_steps(steps.saturating_sub(self.vm.current_step), hint_processor)
794    }
795
796    /// Execute steps until the step counter reaches a power of two.
797    pub fn run_until_next_power_of_2(
798        &mut self,
799        hint_processor: &mut dyn HintProcessor,
800    ) -> Result<(), VirtualMachineError> {
801        self.run_until_steps(self.vm.current_step.next_power_of_two(), hint_processor)
802    }
803
804    pub fn get_perm_range_check_limits(&self) -> Option<(isize, isize)> {
805        let runner_usages = self
806            .vm
807            .builtin_runners
808            .iter()
809            .filter_map(|runner| runner.get_range_check_usage(&self.vm.segments.memory))
810            .map(|(rc_min, rc_max)| (rc_min as isize, rc_max as isize));
811        let rc_bounds = self.vm.rc_limits.iter().copied().chain(runner_usages);
812        rc_bounds.reduce(|(min1, max1), (min2, max2)| (min1.min(min2), max1.max(max2)))
813    }
814
815    /// Checks that there are enough trace cells to fill the entire range check
816    /// range.
817    pub fn check_range_check_usage(&self) -> Result<(), VirtualMachineError> {
818        let Some((rc_min, rc_max)) = self.get_perm_range_check_limits() else {
819            return Ok(());
820        };
821
822        let rc_units_used_by_builtins: usize = self
823            .vm
824            .builtin_runners
825            .iter()
826            .map(|runner| runner.get_used_perm_range_check_units(&self.vm))
827            .sum::<Result<usize, MemoryError>>()
828            .map_err(Into::<VirtualMachineError>::into)?;
829
830        let unused_rc_units =
831            (self.layout.rc_units as usize - 3) * self.vm.current_step - rc_units_used_by_builtins;
832        if unused_rc_units < (rc_max - rc_min) as usize {
833            return Err(MemoryError::InsufficientAllocatedCells(
834                InsufficientAllocatedCellsError::RangeCheckUnits(Box::new((
835                    unused_rc_units,
836                    (rc_max - rc_min) as usize,
837                ))),
838            )
839            .into());
840        }
841
842        Ok(())
843    }
844
845    /// Count the number of holes present in the segments.
846    pub fn get_memory_holes(&self) -> Result<usize, MemoryError> {
847        // Grab builtin segment indexes, except for the output builtin
848        let builtin_segment_indexes: HashSet<usize> = self
849            .vm
850            .builtin_runners
851            .iter()
852            .filter(|b| b.name() != BuiltinName::output)
853            .map(|b| b.base())
854            .collect();
855
856        self.vm.segments.get_memory_holes(builtin_segment_indexes)
857    }
858
859    /// Check if there are enough trace cells to fill the entire diluted checks.
860    pub fn check_diluted_check_usage(&self) -> Result<(), VirtualMachineError> {
861        let diluted_pool_instance = match &self.layout.diluted_pool_instance_def {
862            Some(x) => x,
863            None => return Ok(()),
864        };
865
866        let mut used_units_by_builtins = 0;
867        for builtin_runner in &self.vm.builtin_runners {
868            let used_units = builtin_runner.get_used_diluted_check_units(
869                diluted_pool_instance.spacing,
870                diluted_pool_instance.n_bits,
871            );
872
873            let multiplier = builtin_runner.get_allocated_instances(&self.vm)?;
874
875            used_units_by_builtins += used_units * multiplier;
876        }
877
878        let diluted_units = if !diluted_pool_instance.fractional_units_per_step {
879            diluted_pool_instance.units_per_step as usize * self.vm.current_step
880        } else {
881            safe_div_usize(
882                self.vm.current_step,
883                diluted_pool_instance.units_per_step as usize,
884            )?
885        };
886
887        let unused_diluted_units = diluted_units.saturating_sub(used_units_by_builtins);
888
889        let diluted_usage_upper_bound = 1usize << diluted_pool_instance.n_bits;
890        if unused_diluted_units < diluted_usage_upper_bound {
891            return Err(MemoryError::InsufficientAllocatedCells(
892                InsufficientAllocatedCellsError::DilutedCells(Box::new((
893                    unused_diluted_units,
894                    diluted_usage_upper_bound,
895                ))),
896            )
897            .into());
898        }
899
900        Ok(())
901    }
902
903    pub fn end_run(
904        &mut self,
905        disable_trace_padding: bool,
906        disable_finalize_all: bool,
907        hint_processor: &mut dyn HintProcessor,
908        fill_holes: bool,
909    ) -> Result<(), VirtualMachineError> {
910        if self.run_ended {
911            return Err(RunnerError::EndRunCalledTwice.into());
912        }
913
914        info!("Relocating memory.");
915        self.vm.segments.memory.relocate_memory()?;
916        self.vm.end_run(&self.exec_scopes, fill_holes)?;
917
918        if disable_finalize_all {
919            return Ok(());
920        }
921
922        info!("Computing effective sizes of segments.");
923        self.vm.segments.compute_effective_sizes();
924        if self.is_proof_mode() && !disable_trace_padding {
925            info!("in proof mode and enabling trace padding, running until next power of 2.");
926            self.run_until_next_power_of_2(hint_processor)?;
927            loop {
928                match self.check_used_cells() {
929                    Ok(_) => break,
930                    Err(e) => match e {
931                        VirtualMachineError::Memory(MemoryError::InsufficientAllocatedCells(_)) => {
932                        }
933                        e => return Err(e),
934                    },
935                }
936
937                self.run_for_steps(1, hint_processor)?;
938                self.run_until_next_power_of_2(hint_processor)?;
939            }
940        }
941
942        self.run_ended = true;
943        Ok(())
944    }
945
946    ///Relocates the VM's trace, turning relocatable registers to numbered ones
947    pub fn relocate_trace(&mut self, relocation_table: &[usize]) -> Result<(), TraceError> {
948        if self.relocated_trace.is_some() {
949            return Err(TraceError::AlreadyRelocated);
950        }
951
952        let trace = self
953            .vm
954            .trace
955            .as_ref()
956            .ok_or(TraceError::TraceNotEnabled)?
957            .iter();
958        let mut relocated_trace = Vec::<RelocatedTraceEntry>::with_capacity(trace.len());
959        let segment_1_base = relocation_table
960            .get(1)
961            .ok_or(TraceError::NoRelocationFound)?;
962
963        for entry in trace {
964            relocated_trace.push(RelocatedTraceEntry {
965                pc: relocate_trace_register(entry.pc, relocation_table)?,
966                ap: entry.ap + segment_1_base,
967                fp: entry.fp + segment_1_base,
968            })
969        }
970        self.relocated_trace = Some(relocated_trace);
971        Ok(())
972    }
973
974    /// Relocates the VM's memory, turning bidimensional indexes into contiguous numbers, and values
975    /// into Felt252s. Uses the relocation_table to asign each index a number according to the value
976    /// on its segment number.
977    fn relocate_memory(&mut self, relocation_table: &[usize]) -> Result<(), MemoryError> {
978        if !(self.relocated_memory.is_empty()) {
979            return Err(MemoryError::Relocation);
980        }
981        //Relocated addresses start at 1
982        self.relocated_memory.push(None);
983        for (index, segment) in self.vm.segments.memory.data.iter().enumerate() {
984            for (seg_offset, cell) in segment.iter().enumerate() {
985                match cell.get_value() {
986                    Some(cell) => {
987                        let relocated_addr = relocate_address(
988                            Relocatable::from((index as isize, seg_offset)),
989                            relocation_table,
990                        )?;
991                        let value = relocate_value(cell, relocation_table)?;
992                        if self.relocated_memory.len() <= relocated_addr {
993                            self.relocated_memory.resize(relocated_addr + 1, None);
994                        }
995                        self.relocated_memory[relocated_addr] = Some(value);
996                    }
997                    None => self.relocated_memory.push(None),
998                }
999            }
1000        }
1001        Ok(())
1002    }
1003
1004    pub fn relocate(&mut self, relocate_mem: bool, relocate_trace: bool) -> Result<(), TraceError> {
1005        self.vm.segments.compute_effective_sizes();
1006        if !relocate_mem && (self.vm.trace.is_none() || !relocate_trace) {
1007            return Ok(());
1008        }
1009        // relocate_segments can fail if compute_effective_sizes is not called before.
1010        // The expect should be unreachable.
1011        let relocation_table = self
1012            .vm
1013            .segments
1014            .relocate_segments()
1015            .expect("compute_effective_sizes called but relocate_memory still returned error");
1016
1017        if relocate_mem {
1018            if let Err(memory_error) = self.relocate_memory(&relocation_table) {
1019                return Err(TraceError::MemoryError(memory_error));
1020            }
1021        }
1022        if self.vm.trace.is_some() && relocate_trace {
1023            self.relocate_trace(&relocation_table)?;
1024        }
1025        self.vm.relocation_table = Some(relocation_table);
1026        Ok(())
1027    }
1028
1029    /// Returns a tuple of builtin base's segment index and stop_ptr offset
1030    /// Aka the builtin's segment number and its maximum offset
1031    pub fn get_builtin_segments_info(&self) -> Result<Vec<(usize, usize)>, RunnerError> {
1032        let proof_mode = self.is_proof_mode();
1033        let mut builtin_segment_info = Vec::new();
1034
1035        for builtin in &self.vm.builtin_runners {
1036            let (index, stop_ptr) = builtin.get_memory_segment_addresses();
1037
1038            match (proof_mode, stop_ptr) {
1039                // Segment present (same handling in both modes).
1040                (_, Some(sp)) => builtin_segment_info.push((index, sp)),
1041
1042                // If non proof-mode, only builtins in the program are present and they must
1043                // point to a segment (so `stop_ptr` must be set). Throw an error if not.
1044                (false, None) => {
1045                    return Err(RunnerError::NoStopPointer(Box::new(
1046                        builtin.name().to_owned(),
1047                    )));
1048                }
1049
1050                // In proof‐mode there are builtin runners for all builtins in the layout, but only
1051                // the ones that are in the program point to a segment (so `stop_ptr` is set).
1052                // Only collect those and silently ignore the rest.
1053                (true, None) => {}
1054            }
1055        }
1056
1057        Ok(builtin_segment_info)
1058    }
1059
1060    // Returns a map from builtin's name wihout the "_builtin" suffix to its base's segment index and stop_ptr offset
1061    // Aka the builtin's segment number and its maximum offset
1062    pub fn get_builtin_segment_info_for_pie(
1063        &self,
1064    ) -> Result<HashMap<BuiltinName, cairo_pie::SegmentInfo>, RunnerError> {
1065        let mut builtin_segment_info = HashMap::new();
1066
1067        for builtin in &self.vm.builtin_runners {
1068            let (index, stop_ptr) = builtin.get_memory_segment_addresses();
1069
1070            builtin_segment_info.insert(
1071                builtin.name(),
1072                (
1073                    index as isize,
1074                    stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))?,
1075                )
1076                    .into(),
1077            );
1078        }
1079
1080        Ok(builtin_segment_info)
1081    }
1082
1083    pub fn get_execution_resources(&self) -> Result<ExecutionResources, RunnerError> {
1084        let n_steps = self
1085            .vm
1086            .trace
1087            .as_ref()
1088            .map(|x| x.len())
1089            .unwrap_or(self.vm.current_step);
1090        let n_memory_holes = self.get_memory_holes()?;
1091
1092        let mut builtin_instance_counter = BTreeMap::new();
1093        for builtin_runner in &self.vm.builtin_runners {
1094            builtin_instance_counter.insert(
1095                builtin_runner.name(),
1096                builtin_runner.get_used_instances(&self.vm.segments)?,
1097            );
1098        }
1099
1100        Ok(ExecutionResources {
1101            n_steps,
1102            n_memory_holes,
1103            builtin_instance_counter,
1104        })
1105    }
1106
1107    pub fn get_extended_execution_resources(&self) -> &HashMap<ExtendedExecutionResourceType, u32> {
1108        &self.vm.extended_resource_counter
1109    }
1110
1111    // Finalizes the segments.
1112    //     Note:
1113    //     1.  end_run() must precede a call to this method.
1114    //     2.  Call read_return_values() *before* finalize_segments(), otherwise the return values
1115    //         will not be included in the public memory.
1116    pub fn finalize_segments(&mut self) -> Result<(), RunnerError> {
1117        if self.segments_finalized {
1118            return Ok(());
1119        }
1120        if !self.run_ended {
1121            return Err(RunnerError::FinalizeNoEndRun);
1122        }
1123        let size = self.program.shared_program_data.data.len();
1124        let mut public_memory = Vec::with_capacity(size);
1125        for i in 0..size {
1126            public_memory.push((i, 0_usize))
1127        }
1128        self.vm.segments.finalize(
1129            Some(size),
1130            self.program_base
1131                .as_ref()
1132                .ok_or(RunnerError::NoProgBase)?
1133                .segment_index as usize,
1134            Some(&public_memory),
1135        );
1136        let mut public_memory = Vec::with_capacity(size);
1137        let exec_base = self
1138            .execution_base
1139            .as_ref()
1140            .ok_or(RunnerError::NoExecBase)?;
1141        for elem in self
1142            .execution_public_memory
1143            .as_ref()
1144            .ok_or(RunnerError::FinalizeSegmentsNoProofMode)?
1145            .iter()
1146        {
1147            public_memory.push((elem + exec_base.offset, 0))
1148        }
1149        self.vm
1150            .segments
1151            .finalize(None, exec_base.segment_index as usize, Some(&public_memory));
1152        for builtin_runner in self.vm.builtin_runners.iter() {
1153            let (_, size) = builtin_runner
1154                .get_used_cells_and_allocated_size(&self.vm)
1155                .map_err(RunnerError::FinalizeSegements)?;
1156            if let BuiltinRunner::Output(output_builtin) = builtin_runner {
1157                let public_memory = output_builtin.get_public_memory(&self.vm.segments)?;
1158                self.vm
1159                    .segments
1160                    .finalize(Some(size), builtin_runner.base(), Some(&public_memory))
1161            } else {
1162                self.vm
1163                    .segments
1164                    .finalize(Some(size), builtin_runner.base(), None)
1165            }
1166        }
1167        self.vm.segments.finalize_zero_segment();
1168        self.segments_finalized = true;
1169        Ok(())
1170    }
1171
1172    #[allow(clippy::result_large_err)]
1173    /// Runs a cairo program from a give entrypoint, indicated by its pc offset, with the given arguments.
1174    /// If `verify_secure` is set to true, [verify_secure_runner] will be called to run extra verifications.
1175    /// `program_segment_size` is only used by the [verify_secure_runner] function and will be ignored if `verify_secure` is set to false.
1176    pub fn run_from_entrypoint(
1177        &mut self,
1178        entrypoint: usize,
1179        args: &[&CairoArg],
1180        verify_secure: bool,
1181        program_segment_size: Option<usize>,
1182        hint_processor: &mut dyn HintProcessor,
1183    ) -> Result<(), CairoRunError> {
1184        let stack = args
1185            .iter()
1186            .map(|arg| self.vm.segments.gen_cairo_arg(arg))
1187            .collect::<Result<Vec<MaybeRelocatable>, VirtualMachineError>>()?;
1188        let return_fp = MaybeRelocatable::from(0);
1189        let end = self.initialize_function_entrypoint(entrypoint, stack, return_fp)?;
1190
1191        self.initialize_vm()?;
1192
1193        self.run_until_pc(end, hint_processor)
1194            .map_err(|err| VmException::from_vm_error(self, err))?;
1195        self.end_run(true, false, hint_processor, self.is_proof_mode())?;
1196
1197        if verify_secure {
1198            verify_secure_runner(self, false, program_segment_size)?;
1199        }
1200
1201        Ok(())
1202    }
1203
1204    // Returns Ok(()) if there are enough allocated cells for the builtins.
1205    // If not, the number of steps should be increased or a different layout should be used.
1206    pub fn check_used_cells(&self) -> Result<(), VirtualMachineError> {
1207        self.vm
1208            .builtin_runners
1209            .iter()
1210            .map(|builtin_runner| builtin_runner.get_used_cells_and_allocated_size(&self.vm))
1211            .collect::<Result<Vec<(usize, usize)>, MemoryError>>()?;
1212        self.check_range_check_usage()?;
1213        self.check_memory_usage()?;
1214        self.check_diluted_check_usage()?;
1215        Ok(())
1216    }
1217
1218    // Checks that there are enough trace cells to fill the entire memory range.
1219    pub fn check_memory_usage(&self) -> Result<(), VirtualMachineError> {
1220        let instance = &self.layout;
1221
1222        let builtins_memory_units: usize = self
1223            .vm
1224            .builtin_runners
1225            .iter()
1226            .map(|builtin_runner| builtin_runner.get_allocated_memory_units(&self.vm))
1227            .collect::<Result<Vec<usize>, MemoryError>>()?
1228            .iter()
1229            .sum();
1230
1231        let builtins_memory_units = builtins_memory_units as u32;
1232
1233        let vm_current_step_u32 = self.vm.current_step as u32;
1234
1235        // Out of the memory units available per step, a fraction is used for public memory, and
1236        // four are used for the instruction.
1237        let total_memory_units = instance.memory_units_per_step * vm_current_step_u32;
1238        let (public_memory_units, rem) =
1239            div_rem(total_memory_units, instance.public_memory_fraction);
1240        if rem != 0 {
1241            return Err(MathError::SafeDivFailU32(
1242                total_memory_units,
1243                instance.public_memory_fraction,
1244            )
1245            .into());
1246        }
1247
1248        let instruction_memory_units = 4 * vm_current_step_u32;
1249
1250        let unused_memory_units = total_memory_units
1251            - (public_memory_units + instruction_memory_units + builtins_memory_units);
1252        let memory_address_holes = self.get_memory_holes()?;
1253        if unused_memory_units < memory_address_holes as u32 {
1254            Err(MemoryError::InsufficientAllocatedCells(
1255                InsufficientAllocatedCellsError::MemoryAddresses(Box::new((
1256                    unused_memory_units,
1257                    memory_address_holes,
1258                ))),
1259            ))?
1260        }
1261        Ok(())
1262    }
1263
1264    /// Intitializes the runner in order to run cairo 1 contract entrypoints
1265    /// Swaps the program's builtins field with program_builtins
1266    /// Initializes program builtins & segments
1267    pub fn initialize_function_runner_cairo_1(
1268        &mut self,
1269        program_builtins: &[BuiltinName],
1270    ) -> Result<(), RunnerError> {
1271        self.program.builtins = program_builtins.to_vec();
1272        self.initialize_program_builtins()?;
1273        self.initialize_segments(self.program_base);
1274        Ok(())
1275    }
1276
1277    /// Intitializes the runner in order to run cairo 0 contract entrypoints
1278    /// Initializes program builtins & segments
1279    pub fn initialize_function_runner(&mut self) -> Result<(), RunnerError> {
1280        self.initialize_program_builtins()?;
1281        self.initialize_segments(self.program_base);
1282        Ok(())
1283    }
1284
1285    /// Overrides the previous entrypoint with a custom one, or "main" if none
1286    /// is specified.
1287    pub fn set_entrypoint(&mut self, new_entrypoint: Option<&str>) -> Result<(), ProgramError> {
1288        let new_entrypoint = new_entrypoint.unwrap_or("main");
1289        self.entrypoint = Some(
1290            self.program
1291                .shared_program_data
1292                .identifiers
1293                .get(&format!("__main__.{new_entrypoint}"))
1294                .and_then(|x| x.pc)
1295                .ok_or_else(|| ProgramError::EntrypointNotFound(new_entrypoint.to_string()))?,
1296        );
1297
1298        Ok(())
1299    }
1300
1301    pub fn read_return_values(&mut self, allow_missing_builtins: bool) -> Result<(), RunnerError> {
1302        if !self.run_ended {
1303            return Err(RunnerError::ReadReturnValuesNoEndRun);
1304        }
1305        let mut pointer = self.vm.get_ap();
1306        for builtin_name in self.program.builtins.iter().rev() {
1307            if let Some(builtin_runner) = self
1308                .vm
1309                .builtin_runners
1310                .iter_mut()
1311                .find(|b| b.name() == *builtin_name)
1312            {
1313                let new_pointer = builtin_runner.final_stack(&self.vm.segments, pointer)?;
1314                pointer = new_pointer;
1315            } else {
1316                if !allow_missing_builtins {
1317                    return Err(RunnerError::MissingBuiltin(*builtin_name));
1318                }
1319                pointer.offset = pointer.offset.saturating_sub(1);
1320
1321                if !self.vm.get_integer(pointer)?.is_zero() {
1322                    return Err(RunnerError::MissingBuiltinStopPtrNotZero(*builtin_name));
1323                }
1324            }
1325        }
1326        if self.segments_finalized {
1327            return Err(RunnerError::FailedAddingReturnValues);
1328        }
1329        if self.is_proof_mode() {
1330            let exec_base = *self
1331                .execution_base
1332                .as_ref()
1333                .ok_or(RunnerError::NoExecBase)?;
1334            let begin = pointer.offset - exec_base.offset;
1335            let ap = self.vm.get_ap();
1336            let end = ap.offset - exec_base.offset;
1337            self.execution_public_memory
1338                .as_mut()
1339                .ok_or(RunnerError::NoExecPublicMemory)?
1340                .extend(begin..end);
1341        }
1342        Ok(())
1343    }
1344
1345    // Iterates over the program builtins in reverse, calling BuiltinRunner::final_stack on each of them and returns the final pointer
1346    // This method is used by cairo-vm-py to replace starknet functionality
1347    pub fn get_builtins_final_stack(
1348        &mut self,
1349        stack_ptr: Relocatable,
1350    ) -> Result<Relocatable, RunnerError> {
1351        let mut stack_ptr = Relocatable::from(&stack_ptr);
1352        for runner in self
1353            .vm
1354            .builtin_runners
1355            .iter_mut()
1356            .rev()
1357            .filter(|builtin_runner| {
1358                self.program
1359                    .builtins
1360                    .iter()
1361                    .any(|bn| *bn == builtin_runner.name())
1362            })
1363        {
1364            stack_ptr = runner.final_stack(&self.vm.segments, stack_ptr)?
1365        }
1366        Ok(stack_ptr)
1367    }
1368
1369    /// Return CairoRunner.program
1370    pub fn get_program(&self) -> &Program {
1371        &self.program
1372    }
1373
1374    // Constructs and returns a CairoPie representing the current VM run.
1375    pub fn get_cairo_pie(&self) -> Result<CairoPie, RunnerError> {
1376        let program_base = self.program_base.ok_or(RunnerError::NoProgBase)?;
1377        let execution_base = self.execution_base.ok_or(RunnerError::NoExecBase)?;
1378
1379        let builtin_segments = self.get_builtin_segment_info_for_pie()?;
1380        let mut known_segment_indices = HashSet::new();
1381        for info in builtin_segments.values() {
1382            known_segment_indices.insert(info.index);
1383        }
1384        let n_used_builtins = self.program.builtins_len();
1385        let return_fp_addr = (execution_base + n_used_builtins)?;
1386        let return_fp = self.vm.get_relocatable(return_fp_addr)?;
1387        let return_pc = self.vm.get_relocatable((return_fp_addr + 1)?)?;
1388
1389        if let None | Some(false) = return_fp
1390            .segment_index
1391            .to_usize()
1392            .and_then(|u| self.vm.get_segment_size(u))
1393            .map(|u| u.is_zero())
1394        {
1395            // return_fp negative index / no size / size is zero
1396            return Err(RunnerError::UnexpectedRetFpSegmentSize);
1397        }
1398
1399        if let None | Some(false) = return_pc
1400            .segment_index
1401            .to_usize()
1402            .and_then(|u| self.vm.get_segment_size(u))
1403            .map(|u| u.is_zero())
1404        {
1405            // return_pc negative index / no size / size is zero
1406            return Err(RunnerError::UnexpectedRetPcSegmentSize);
1407        }
1408
1409        if program_base.offset != 0 {
1410            return Err(RunnerError::ProgramBaseOffsetNotZero);
1411        }
1412        known_segment_indices.insert(program_base.segment_index);
1413
1414        if execution_base.offset != 0 {
1415            return Err(RunnerError::ExecBaseOffsetNotZero);
1416        }
1417        known_segment_indices.insert(execution_base.segment_index);
1418
1419        if return_fp.offset != 0 {
1420            return Err(RunnerError::RetFpOffsetNotZero);
1421        }
1422        known_segment_indices.insert(return_fp.segment_index);
1423
1424        if return_pc.offset != 0 {
1425            return Err(RunnerError::RetPcOffsetNotZero);
1426        }
1427        known_segment_indices.insert(return_pc.segment_index);
1428
1429        // Put all the remaining segments in extra_segments.
1430        let mut extra_segments = Vec::default();
1431        for index in 0..self.vm.segments.num_segments() {
1432            if !known_segment_indices.contains(&(index as isize)) {
1433                extra_segments.push(
1434                    (
1435                        index as isize,
1436                        self.vm
1437                            .get_segment_size(index)
1438                            .ok_or(MemoryError::MissingSegmentUsedSizes)?,
1439                    )
1440                        .into(),
1441                );
1442            }
1443        }
1444
1445        let execution_size = (self.vm.get_ap() - execution_base)?;
1446        let metadata = CairoPieMetadata {
1447            program: self
1448                .get_program()
1449                .get_stripped_program()
1450                .map_err(|_| RunnerError::StrippedProgramNoMain)?,
1451            program_segment: (program_base.segment_index, self.program.data_len()).into(),
1452            execution_segment: (execution_base.segment_index, execution_size).into(),
1453            ret_fp_segment: (return_fp.segment_index, 0).into(),
1454            ret_pc_segment: (return_pc.segment_index, 0).into(),
1455            builtin_segments: builtin_segments.into_iter().collect(),
1456            extra_segments,
1457        };
1458
1459        Ok(CairoPie {
1460            metadata,
1461            memory: (&self.vm.segments.memory).into(),
1462            execution_resources: self.get_execution_resources()?,
1463            additional_data: CairoPieAdditionalData(
1464                self.vm
1465                    .builtin_runners
1466                    .iter()
1467                    .map(|b| (b.name(), b.get_additional_data()))
1468                    .collect(),
1469            ),
1470            version: CairoPieVersion { cairo_pie: () },
1471        })
1472    }
1473
1474    pub fn get_air_public_input(&'_ self) -> Result<PublicInput<'_>, PublicInputError> {
1475        PublicInput::new(
1476            &self.relocated_memory,
1477            self.layout.name.to_str(),
1478            &self.vm.get_public_memory_addresses()?,
1479            self.get_memory_segment_addresses()?,
1480            self.relocated_trace
1481                .as_ref()
1482                .ok_or(PublicInputError::EmptyTrace)?,
1483            self.get_perm_range_check_limits()
1484                .ok_or(PublicInputError::NoRangeCheckLimits)?,
1485        )
1486    }
1487
1488    pub fn get_air_private_input(&self) -> AirPrivateInput {
1489        let mut private_inputs = HashMap::new();
1490        for builtin in self.vm.builtin_runners.iter() {
1491            private_inputs.insert(builtin.name(), builtin.air_private_input(&self.vm.segments));
1492        }
1493        AirPrivateInput(private_inputs)
1494    }
1495
1496    pub fn get_memory_segment_addresses(
1497        &self,
1498    ) -> Result<HashMap<&'static str, (usize, usize)>, VirtualMachineError> {
1499        let relocation_table = self
1500            .vm
1501            .relocation_table
1502            .as_ref()
1503            .ok_or(MemoryError::UnrelocatedMemory)?;
1504
1505        let relocate = |segment: (usize, usize)| -> Result<(usize, usize), VirtualMachineError> {
1506            let (index, stop_ptr_offset) = segment;
1507            let base = relocation_table
1508                .get(index)
1509                .ok_or(VirtualMachineError::RelocationNotFound(index))?;
1510            Ok((*base, base + stop_ptr_offset))
1511        };
1512
1513        self.vm
1514            .builtin_runners
1515            .iter()
1516            .map(|builtin| -> Result<_, VirtualMachineError> {
1517                let (base, stop_ptr) = builtin.get_memory_segment_addresses();
1518                let stop_ptr = if self.program.builtins.contains(&builtin.name()) {
1519                    stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))?
1520                } else {
1521                    stop_ptr.unwrap_or_default()
1522                };
1523
1524                Ok((builtin.name().to_str(), relocate((base, stop_ptr))?))
1525            })
1526            .collect()
1527    }
1528
1529    /// Returns a reference to the relocatable trace.
1530    pub fn get_relocatable_trace(&self) -> Result<&[TraceEntry], RunnerError> {
1531        self.vm
1532            .trace
1533            .as_deref()
1534            .ok_or(RunnerError::Trace(TraceError::TraceNotEnabled))
1535    }
1536
1537    /// Returns a vector of segments, where each segment is a vector of Option<MaybeRelocatable> values, representing the relocatble memory values.
1538    pub fn get_relocatable_memory(&self) -> Vec<Vec<Option<MaybeRelocatable>>> {
1539        self.vm
1540            .segments
1541            .memory
1542            .data
1543            .iter()
1544            .map(|segment| segment.iter().map(|cell| cell.get_value()).collect())
1545            .collect()
1546    }
1547
1548    /// Returns a map from the builtin segment index into its name.
1549    pub fn get_builtin_segments(&self) -> BTreeMap<usize, BuiltinName> {
1550        self.vm
1551            .builtin_runners
1552            .iter()
1553            .map(|builtin| {
1554                let (index, _) = builtin.get_memory_segment_addresses();
1555                (index, builtin.name())
1556            })
1557            .collect()
1558    }
1559}
1560
1561//* ----------------------
1562//*   ExecutionResources
1563//* ----------------------
1564
1565#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
1566pub struct ExecutionResources {
1567    pub n_steps: usize,
1568    pub n_memory_holes: usize,
1569    #[serde(with = "crate::types::builtin_name::serde_generic_map_impl")]
1570    pub builtin_instance_counter: BTreeMap<BuiltinName, usize>,
1571}
1572
1573/// Returns a copy of the execution resources where all the builtins with a usage counter
1574/// of 0 are omitted.
1575impl ExecutionResources {
1576    pub fn filter_unused_builtins(&self) -> ExecutionResources {
1577        ExecutionResources {
1578            n_steps: self.n_steps,
1579            n_memory_holes: self.n_memory_holes,
1580            builtin_instance_counter: self
1581                .clone()
1582                .builtin_instance_counter
1583                .into_iter()
1584                .filter(|builtin| !builtin.1.is_zero())
1585                .collect(),
1586        }
1587    }
1588}
1589
1590impl Add<&ExecutionResources> for &ExecutionResources {
1591    type Output = ExecutionResources;
1592
1593    fn add(self, rhs: &ExecutionResources) -> ExecutionResources {
1594        let mut new = self.clone();
1595        new.add_assign(rhs);
1596        new
1597    }
1598}
1599
1600impl AddAssign<&ExecutionResources> for ExecutionResources {
1601    fn add_assign(&mut self, rhs: &ExecutionResources) {
1602        self.n_steps += rhs.n_steps;
1603        self.n_memory_holes += rhs.n_memory_holes;
1604        for (k, v) in rhs.builtin_instance_counter.iter() {
1605            // FIXME: remove k's clone, use &'static str
1606            *self.builtin_instance_counter.entry(*k).or_insert(0) += v;
1607        }
1608    }
1609}
1610
1611impl Sub<&ExecutionResources> for &ExecutionResources {
1612    type Output = ExecutionResources;
1613
1614    fn sub(self, rhs: &ExecutionResources) -> ExecutionResources {
1615        let mut new = self.clone();
1616        new.sub_assign(rhs);
1617        new
1618    }
1619}
1620
1621impl SubAssign<&ExecutionResources> for ExecutionResources {
1622    fn sub_assign(&mut self, rhs: &ExecutionResources) {
1623        self.n_steps -= rhs.n_steps;
1624        self.n_memory_holes -= rhs.n_memory_holes;
1625        for (k, v) in rhs.builtin_instance_counter.iter() {
1626            // FIXME: remove k's clone, use &'static str
1627            let entry = self.builtin_instance_counter.entry(*k).or_insert(0);
1628            *entry = (*entry).saturating_sub(*v);
1629        }
1630    }
1631}
1632
1633impl Mul<usize> for &ExecutionResources {
1634    type Output = ExecutionResources;
1635
1636    fn mul(self, rhs: usize) -> ExecutionResources {
1637        let mut new = self.clone();
1638        new.mul_assign(rhs);
1639        new
1640    }
1641}
1642
1643impl MulAssign<usize> for ExecutionResources {
1644    fn mul_assign(&mut self, rhs: usize) {
1645        self.n_steps *= rhs;
1646        self.n_memory_holes *= rhs;
1647        for (_builtin_name, counter) in self.builtin_instance_counter.iter_mut() {
1648            *counter *= rhs;
1649        }
1650    }
1651}
1652
1653#[cfg(test)]
1654mod tests {
1655    use super::*;
1656    use crate::air_private_input::{PrivateInput, PrivateInputSignature, SignatureInput};
1657    use crate::cairo_run::{cairo_run, CairoRunConfig};
1658    use crate::types::instance_definitions::bitwise_instance_def::CELLS_PER_BITWISE;
1659    use crate::types::instance_definitions::keccak_instance_def::CELLS_PER_KECCAK;
1660    use crate::vm::vm_memory::memory::MemoryCell;
1661    use std::collections::{HashMap, HashSet};
1662
1663    use crate::felt_hex;
1664    use crate::{
1665        hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
1666        relocatable,
1667        serde::deserialize_program::{Identifier, ReferenceManager},
1668        utils::test_utils::*,
1669        vm::trace::trace_entry::TraceEntry,
1670    };
1671    use assert_matches::assert_matches;
1672
1673    #[test]
1674    fn check_memory_usage_ok_case() {
1675        let program = program![BuiltinName::range_check, BuiltinName::output];
1676        let mut cairo_runner = cairo_runner!(program);
1677        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
1678
1679        assert_matches!(cairo_runner.check_memory_usage(), Ok(()));
1680    }
1681
1682    #[test]
1683    fn check_memory_usage_err_case() {
1684        let program = program!();
1685
1686        let mut cairo_runner = cairo_runner!(program);
1687        cairo_runner.vm.builtin_runners = vec![{
1688            let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
1689            builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
1690
1691            builtin_runner
1692        }];
1693        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4, 12]);
1694        cairo_runner.vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 1)];
1695        cairo_runner
1696            .vm
1697            .segments
1698            .memory
1699            .mark_as_accessed((0, 0).into());
1700        assert_matches!(
1701            cairo_runner.check_memory_usage(),
1702            Err(VirtualMachineError::Memory(
1703                MemoryError::InsufficientAllocatedCells(_)
1704            ))
1705        );
1706    }
1707
1708    #[test]
1709    fn initialize_builtins_with_disordered_builtins() {
1710        let program = program![BuiltinName::range_check, BuiltinName::output];
1711        let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
1712        assert!(cairo_runner.initialize_builtins(false).is_err());
1713    }
1714
1715    #[test]
1716    fn initialize_builtins_missing_builtins_no_allow_missing() {
1717        let program = program![BuiltinName::output, BuiltinName::ecdsa];
1718        let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
1719        assert_matches!(
1720            cairo_runner.initialize_builtins(false),
1721            Err(RunnerError::NoBuiltinForInstance(_))
1722        )
1723    }
1724
1725    #[test]
1726    fn initialize_builtins_missing_builtins_allow_missing() {
1727        let program = program![BuiltinName::output, BuiltinName::ecdsa];
1728        let mut cairo_runner = cairo_runner!(program);
1729        assert!(cairo_runner.initialize_builtins(true).is_ok())
1730    }
1731
1732    #[test]
1733    fn initialize_segments_with_base() {
1734        let program = program![BuiltinName::output];
1735        let mut cairo_runner = cairo_runner!(program);
1736        let program_base = Some(Relocatable {
1737            segment_index: 5,
1738            offset: 9,
1739        });
1740        add_segments!(&mut cairo_runner.vm, 6);
1741        cairo_runner.initialize_builtins(false).unwrap();
1742        cairo_runner.initialize_segments(program_base);
1743        assert_eq!(
1744            cairo_runner.program_base,
1745            Some(Relocatable {
1746                segment_index: 5,
1747                offset: 9,
1748            })
1749        );
1750        assert_eq!(
1751            cairo_runner.execution_base,
1752            Some(Relocatable {
1753                segment_index: 6,
1754                offset: 0,
1755            })
1756        );
1757        assert_eq!(
1758            cairo_runner.vm.builtin_runners[0].name(),
1759            BuiltinName::output
1760        );
1761        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 7);
1762
1763        assert_eq!(cairo_runner.vm.segments.num_segments(), 8);
1764    }
1765
1766    #[test]
1767    fn initialize_segments_no_base() {
1768        let program = program![BuiltinName::output];
1769        let mut cairo_runner = cairo_runner!(program);
1770        cairo_runner.initialize_builtins(false).unwrap();
1771        cairo_runner.initialize_segments(None);
1772        assert_eq!(
1773            cairo_runner.program_base,
1774            Some(Relocatable {
1775                segment_index: 0,
1776                offset: 0
1777            })
1778        );
1779        assert_eq!(
1780            cairo_runner.execution_base,
1781            Some(Relocatable {
1782                segment_index: 1,
1783                offset: 0
1784            })
1785        );
1786        assert_eq!(
1787            cairo_runner.vm.builtin_runners[0].name(),
1788            BuiltinName::output
1789        );
1790        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
1791
1792        assert_eq!(cairo_runner.vm.segments.num_segments(), 3);
1793    }
1794
1795    #[test]
1796    fn initialize_state_empty_data_and_stack() {
1797        let program = program![BuiltinName::output];
1798        let mut cairo_runner = cairo_runner!(program);
1799        cairo_runner.program_base = Some(relocatable!(1, 0));
1800        cairo_runner.execution_base = Some(relocatable!(2, 0));
1801        let stack = Vec::new();
1802        cairo_runner.initialize_builtins(false).unwrap();
1803        cairo_runner.initialize_state(1, stack).unwrap();
1804        assert_eq!(
1805            cairo_runner.initial_pc,
1806            Some(Relocatable {
1807                segment_index: 1,
1808                offset: 1
1809            })
1810        );
1811    }
1812
1813    #[test]
1814    fn initialize_state_some_data_empty_stack() {
1815        let program = program!(
1816            builtins = vec![BuiltinName::output],
1817            data = vec_data!((4), (6)),
1818        );
1819        let mut cairo_runner = cairo_runner!(program);
1820        for _ in 0..2 {
1821            cairo_runner.vm.segments.add();
1822        }
1823        cairo_runner.program_base = Some(Relocatable {
1824            segment_index: 1,
1825            offset: 0,
1826        });
1827        cairo_runner.execution_base = Some(relocatable!(2, 0));
1828        let stack = Vec::new();
1829        cairo_runner.initialize_state(1, stack).unwrap();
1830        check_memory!(cairo_runner.vm.segments.memory, ((1, 0), 4), ((1, 1), 6));
1831    }
1832
1833    #[test]
1834    fn initialize_state_empty_data_some_stack() {
1835        let program = program![BuiltinName::output];
1836        let mut cairo_runner = cairo_runner!(program);
1837        for _ in 0..3 {
1838            cairo_runner.vm.segments.add();
1839        }
1840        cairo_runner.program_base = Some(relocatable!(1, 0));
1841        cairo_runner.execution_base = Some(relocatable!(2, 0));
1842        let stack = vec![mayberelocatable!(4), mayberelocatable!(6)];
1843        cairo_runner.initialize_state(1, stack).unwrap();
1844        check_memory!(cairo_runner.vm.segments.memory, ((2, 0), 4), ((2, 1), 6));
1845    }
1846
1847    #[test]
1848    fn initialize_state_no_program_base() {
1849        let program = program![BuiltinName::output];
1850        let mut cairo_runner = cairo_runner!(program);
1851        for _ in 0..2 {
1852            cairo_runner.vm.segments.add();
1853        }
1854        cairo_runner.execution_base = Some(Relocatable {
1855            segment_index: 2,
1856            offset: 0,
1857        });
1858        let stack = vec![
1859            MaybeRelocatable::from(Felt252::from(4_i32)),
1860            MaybeRelocatable::from(Felt252::from(6_i32)),
1861        ];
1862        assert!(cairo_runner.initialize_state(1, stack).is_err());
1863    }
1864
1865    #[test]
1866    #[should_panic]
1867    fn initialize_state_no_execution_base() {
1868        let program = program![BuiltinName::output];
1869        let mut cairo_runner = cairo_runner!(program);
1870        for _ in 0..2 {
1871            cairo_runner.vm.segments.add();
1872        }
1873        cairo_runner.program_base = Some(relocatable!(1, 0));
1874        let stack = vec![
1875            MaybeRelocatable::from(Felt252::from(4_i32)),
1876            MaybeRelocatable::from(Felt252::from(6_i32)),
1877        ];
1878        cairo_runner.initialize_state(1, stack).unwrap();
1879    }
1880
1881    #[test]
1882    fn initialize_function_entrypoint_empty_stack() {
1883        let program = program![BuiltinName::output];
1884        let mut cairo_runner = cairo_runner!(program);
1885        for _ in 0..2 {
1886            cairo_runner.vm.segments.add();
1887        }
1888        cairo_runner.program_base = Some(relocatable!(0, 0));
1889        cairo_runner.execution_base = Some(relocatable!(1, 0));
1890        let stack = Vec::new();
1891        let return_fp = MaybeRelocatable::from(Felt252::from(9_i32));
1892        cairo_runner
1893            .initialize_function_entrypoint(0, stack, return_fp)
1894            .unwrap();
1895        assert_eq!(cairo_runner.initial_fp, cairo_runner.initial_ap);
1896        assert_eq!(cairo_runner.initial_fp, Some(relocatable!(1, 2)));
1897        check_memory!(
1898            cairo_runner.vm.segments.memory,
1899            ((1, 0), 9),
1900            ((1, 1), (2, 0))
1901        );
1902    }
1903
1904    #[test]
1905    fn initialize_function_entrypoint_some_stack() {
1906        let program = program![BuiltinName::output];
1907        let mut cairo_runner = cairo_runner!(program);
1908        for _ in 0..2 {
1909            cairo_runner.vm.segments.add();
1910        }
1911        cairo_runner.program_base = Some(relocatable!(0, 0));
1912        cairo_runner.execution_base = Some(relocatable!(1, 0));
1913        let stack = vec![MaybeRelocatable::from(Felt252::from(7_i32))];
1914        let return_fp = MaybeRelocatable::from(Felt252::from(9_i32));
1915        cairo_runner
1916            .initialize_function_entrypoint(1, stack, return_fp)
1917            .unwrap();
1918        assert_eq!(cairo_runner.initial_fp, cairo_runner.initial_ap);
1919        assert_eq!(cairo_runner.initial_fp, Some(relocatable!(1, 3)));
1920        check_memory!(
1921            cairo_runner.vm.segments.memory,
1922            ((1, 0), 7),
1923            ((1, 1), 9),
1924            ((1, 2), (2, 0))
1925        );
1926    }
1927
1928    #[test]
1929    #[should_panic]
1930    fn initialize_function_entrypoint_no_execution_base() {
1931        let program = program![BuiltinName::output];
1932        let mut cairo_runner = cairo_runner!(program);
1933        let stack = vec![MaybeRelocatable::from(Felt252::from(7_i32))];
1934        let return_fp = MaybeRelocatable::from(Felt252::from(9_i32));
1935        cairo_runner
1936            .initialize_function_entrypoint(1, stack, return_fp)
1937            .unwrap();
1938    }
1939
1940    #[test]
1941    #[should_panic]
1942    fn initialize_main_entrypoint_no_main() {
1943        let program = program![BuiltinName::output];
1944        let mut cairo_runner = cairo_runner!(program);
1945        cairo_runner.initialize_main_entrypoint().unwrap();
1946    }
1947
1948    #[test]
1949    fn initialize_main_entrypoint() {
1950        let program = program!(main = Some(1),);
1951        let mut cairo_runner = cairo_runner!(program);
1952        cairo_runner.program_base = Some(relocatable!(0, 0));
1953        cairo_runner.execution_base = Some(relocatable!(0, 0));
1954        let return_pc = cairo_runner.initialize_main_entrypoint().unwrap();
1955        assert_eq!(return_pc, Relocatable::from((1, 0)));
1956    }
1957
1958    #[test]
1959    fn initialize_state_program_segment_accessed_addrs() {
1960        // This test checks that all addresses from the program segment are marked as accessed at VM state initialization.
1961        // The fibonacci program has 24 instructions, so there should be 24 accessed addresses,
1962        // from (0, 0) to (0, 23).
1963        let program = Program::from_bytes(
1964            include_bytes!("../../../../cairo_programs/fibonacci.json"),
1965            Some("main"),
1966        )
1967        .unwrap();
1968
1969        let mut cairo_runner = cairo_runner!(program);
1970
1971        cairo_runner.initialize(false).unwrap();
1972        assert_eq!(
1973            cairo_runner
1974                .vm
1975                .segments
1976                .memory
1977                .get_amount_of_accessed_addresses_for_segment(0),
1978            Some(24)
1979        );
1980    }
1981
1982    #[test]
1983    fn initialize_vm_no_builtins() {
1984        let program = program!(main = Some(1),);
1985        let mut cairo_runner = cairo_runner!(program);
1986        cairo_runner.program_base = Some(relocatable!(0, 0));
1987        cairo_runner.initial_pc = Some(relocatable!(0, 1));
1988        cairo_runner.initial_ap = Some(relocatable!(1, 2));
1989        cairo_runner.initial_fp = Some(relocatable!(1, 2));
1990        cairo_runner.initialize_vm().unwrap();
1991        assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 1));
1992        assert_eq!(cairo_runner.vm.run_context.ap, 2);
1993        assert_eq!(cairo_runner.vm.run_context.fp, 2);
1994    }
1995
1996    #[test]
1997    fn initialize_vm_with_range_check_valid() {
1998        let program = program!(builtins = vec![BuiltinName::range_check], main = Some(1),);
1999        let mut cairo_runner = cairo_runner!(program);
2000        cairo_runner.initial_pc = Some(relocatable!(0, 1));
2001        cairo_runner.initial_ap = Some(relocatable!(1, 2));
2002        cairo_runner.initial_fp = Some(relocatable!(1, 2));
2003        cairo_runner.initialize_builtins(false).unwrap();
2004        cairo_runner.initialize_segments(None);
2005        cairo_runner.vm.segments = segments![((2, 0), 23), ((2, 1), 233)];
2006        assert_eq!(
2007            cairo_runner.vm.builtin_runners[0].name(),
2008            BuiltinName::range_check
2009        );
2010        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2011        cairo_runner.initialize_vm().unwrap();
2012        assert!(cairo_runner
2013            .vm
2014            .segments
2015            .memory
2016            .validated_addresses
2017            .contains(&Relocatable::from((2, 0))));
2018        assert!(cairo_runner
2019            .vm
2020            .segments
2021            .memory
2022            .validated_addresses
2023            .contains(&Relocatable::from((2, 1))));
2024        assert_eq!(cairo_runner.vm.segments.memory.validated_addresses.len(), 2);
2025    }
2026
2027    #[test]
2028    fn initialize_vm_with_range_check_invalid() {
2029        let program = program!(builtins = vec![BuiltinName::range_check], main = Some(1),);
2030        let mut cairo_runner = cairo_runner!(program);
2031        cairo_runner.initial_pc = Some(relocatable!(0, 1));
2032        cairo_runner.initial_ap = Some(relocatable!(1, 2));
2033        cairo_runner.initial_fp = Some(relocatable!(1, 2));
2034        cairo_runner.initialize_builtins(false).unwrap();
2035        cairo_runner.initialize_segments(None);
2036        cairo_runner.vm.segments = segments![((2, 1), 23), ((2, 4), (-1))];
2037
2038        assert_eq!(
2039            cairo_runner.initialize_vm(),
2040            Err(RunnerError::MemoryValidationError(
2041                MemoryError::RangeCheckFoundNonInt(Box::new((2, 0).into()))
2042            ))
2043        );
2044    }
2045
2046    //Integration tests for initialization phase
2047
2048    #[test]
2049    /* Program used:
2050    func myfunc(a: felt) -> (r: felt):
2051        let b = a * 2
2052        return(b)
2053    end
2054
2055    func main():
2056        let a = 1
2057        let b = myfunc(a)
2058        return()
2059    end
2060
2061    main = 3
2062    data = [5207990763031199744, 2, 2345108766317314046, 5189976364521848832, 1, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020476, 2345108766317314046]
2063    */
2064    fn initialization_phase_no_builtins() {
2065        let program = program!(
2066            data = vec_data!(
2067                (5207990763031199744_u64),
2068                (2),
2069                (2345108766317314046_u64),
2070                (5189976364521848832_u64),
2071                (1),
2072                (1226245742482522112_u64),
2073                ((
2074                    "3618502788666131213697322783095070105623107215331596699973092056135872020476",
2075                    10
2076                )),
2077                (2345108766317314046_i64)
2078            ),
2079            main = Some(3),
2080        );
2081        let mut cairo_runner = cairo_runner!(program);
2082        cairo_runner.initialize_segments(None);
2083        cairo_runner.initialize_main_entrypoint().unwrap();
2084        cairo_runner.initialize_vm().unwrap();
2085
2086        assert_eq!(cairo_runner.program_base, Some(relocatable!(0, 0)));
2087        assert_eq!(cairo_runner.execution_base, Some(relocatable!(1, 0)));
2088        assert_eq!(cairo_runner.final_pc, Some(relocatable!(3, 0)));
2089
2090        //RunContext check
2091        //Registers
2092        assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 3));
2093        assert_eq!(cairo_runner.vm.run_context.ap, 2);
2094        assert_eq!(cairo_runner.vm.run_context.fp, 2);
2095        //Memory
2096        check_memory!(
2097            cairo_runner.vm.segments.memory,
2098            ((0, 0), 5207990763031199744_u64),
2099            ((0, 1), 2),
2100            ((0, 2), 2345108766317314046_u64),
2101            ((0, 3), 5189976364521848832_u64),
2102            ((0, 4), 1),
2103            ((0, 5), 1226245742482522112_u64),
2104            (
2105                (0, 6),
2106                (
2107                    "3618502788666131213697322783095070105623107215331596699973092056135872020476",
2108                    10
2109                )
2110            ),
2111            ((0, 7), 2345108766317314046_u64),
2112            ((1, 0), (2, 0)),
2113            ((1, 1), (3, 0))
2114        );
2115    }
2116
2117    #[test]
2118    /*Program used:
2119    %builtins output
2120
2121    from starkware.cairo.common.serialize import serialize_word
2122
2123    func main{output_ptr: felt*}():
2124        let a = 1
2125        serialize_word(a)
2126        return()
2127    end
2128
2129    main = 4
2130    data = [4612671182993129469, 5198983563776393216, 1, 2345108766317314046, 5191102247248822272, 5189976364521848832, 1, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020474, 2345108766317314046]
2131    */
2132    fn initialization_phase_output_builtin() {
2133        let program = program!(
2134            builtins = vec![BuiltinName::output],
2135            data = vec_data!(
2136                (4612671182993129469_u64),
2137                (5198983563776393216_u64),
2138                (1),
2139                (2345108766317314046_u64),
2140                (5191102247248822272_u64),
2141                (5189976364521848832_u64),
2142                (1),
2143                (1226245742482522112_u64),
2144                ((
2145                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2146                    10
2147                )),
2148                (2345108766317314046_u64)
2149            ),
2150            main = Some(4),
2151        );
2152        let mut cairo_runner = cairo_runner!(program);
2153
2154        cairo_runner.initialize_builtins(false).unwrap();
2155        cairo_runner.initialize_segments(None);
2156        cairo_runner.initialize_main_entrypoint().unwrap();
2157        cairo_runner.initialize_vm().unwrap();
2158
2159        assert_eq!(cairo_runner.program_base, Some(relocatable!(0, 0)));
2160        assert_eq!(cairo_runner.execution_base, Some(relocatable!(1, 0)));
2161        assert_eq!(cairo_runner.final_pc, Some(relocatable!(4, 0)));
2162
2163        //RunContext check
2164        //Registers
2165        assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 4));
2166        assert_eq!(cairo_runner.vm.run_context.ap, 3);
2167        assert_eq!(cairo_runner.vm.run_context.fp, 3);
2168        //Memory
2169        check_memory!(
2170            cairo_runner.vm.segments.memory,
2171            ((0, 0), 4612671182993129469_u64),
2172            ((0, 1), 5198983563776393216_u64),
2173            ((0, 2), 1),
2174            ((0, 3), 2345108766317314046_u64),
2175            ((0, 4), 5191102247248822272_u64),
2176            ((0, 5), 5189976364521848832_u64),
2177            ((0, 6), 1),
2178            ((0, 7), 1226245742482522112_u64),
2179            (
2180                (0, 8),
2181                (
2182                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2183                    10
2184                )
2185            ),
2186            ((0, 9), 2345108766317314046_u64),
2187            ((1, 0), (2, 0)),
2188            ((1, 1), (3, 0)),
2189            ((1, 2), (4, 0))
2190        );
2191    }
2192
2193    #[test]
2194    /*Program used:
2195    %builtins range_check
2196
2197    func check_range{range_check_ptr}(num):
2198
2199        # Check that 0 <= num < 2**64.
2200        [range_check_ptr] = num
2201        assert [range_check_ptr + 1] = 2 ** 64 - 1 - num
2202        let range_check_ptr = range_check_ptr + 2
2203        return()
2204    end
2205
2206    func main{range_check_ptr}():
2207        check_range(7)
2208        return()
2209    end
2210
2211    main = 8
2212    data = [4612671182993129469, 5189976364521848832, 18446744073709551615, 5199546496550207487, 4612389712311386111, 5198983563776393216, 2, 2345108766317314046, 5191102247248822272, 5189976364521848832, 7, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020470, 2345108766317314046]
2213    */
2214    fn initialization_phase_range_check_builtin() {
2215        let program = program!(
2216            builtins = vec![BuiltinName::range_check],
2217            data = vec_data!(
2218                (4612671182993129469_u64),
2219                (5189976364521848832_u64),
2220                (18446744073709551615_u128),
2221                (5199546496550207487_u64),
2222                (4612389712311386111_u64),
2223                (5198983563776393216_u64),
2224                (2),
2225                (2345108766317314046_u64),
2226                (5191102247248822272_u64),
2227                (5189976364521848832_u64),
2228                (7),
2229                (1226245742482522112_u64),
2230                ((
2231                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2232                    10
2233                )),
2234                (2345108766317314046_u64)
2235            ),
2236            main = Some(8),
2237        );
2238
2239        let mut cairo_runner = cairo_runner!(program);
2240
2241        cairo_runner.initialize_builtins(false).unwrap();
2242        cairo_runner.initialize_segments(None);
2243        cairo_runner.initialize_main_entrypoint().unwrap();
2244        cairo_runner.initialize_vm().unwrap();
2245
2246        assert_eq!(cairo_runner.program_base, Some(relocatable!(0, 0)));
2247        assert_eq!(cairo_runner.execution_base, Some(relocatable!(1, 0)));
2248        assert_eq!(cairo_runner.final_pc, Some(relocatable!(4, 0)));
2249
2250        //RunContext check
2251        //Registers
2252        assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 8));
2253        assert_eq!(cairo_runner.vm.run_context.ap, 3);
2254        assert_eq!(cairo_runner.vm.run_context.fp, 3);
2255        //Memory
2256        check_memory!(
2257            cairo_runner.vm.segments.memory,
2258            ((0, 0), 4612671182993129469_u64),
2259            ((0, 1), 5189976364521848832_u64),
2260            ((0, 2), 18446744073709551615_u128),
2261            ((0, 3), 5199546496550207487_u64),
2262            ((0, 4), 4612389712311386111_u64),
2263            ((0, 5), 5198983563776393216_u64),
2264            ((0, 6), 2),
2265            ((0, 7), 2345108766317314046_u64),
2266            ((0, 8), 5191102247248822272_u64),
2267            ((0, 9), 5189976364521848832_u64),
2268            ((0, 10), 7),
2269            ((0, 11), 1226245742482522112_u64),
2270            (
2271                (0, 12),
2272                (
2273                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2274                    10
2275                )
2276            ),
2277            ((0, 13), 2345108766317314046_u64),
2278            ((1, 0), (2, 0)),
2279            ((1, 1), (3, 0)),
2280            ((1, 2), (4, 0))
2281        );
2282    }
2283
2284    //Integration tests for initialization + execution phase
2285
2286    #[test]
2287    /*Program used:
2288    func myfunc(a: felt) -> (r: felt):
2289        let b = a * 2
2290        return(b)
2291    end
2292
2293    func main():
2294        let a = 1
2295        let b = myfunc(a)
2296        return()
2297    end
2298
2299    main = 3
2300    data = [5207990763031199744, 2, 2345108766317314046, 5189976364521848832, 1, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020476, 2345108766317314046]
2301    */
2302    fn initialize_and_run_function_call() {
2303        //Initialization Phase
2304        let program = program!(
2305            data = vec_data!(
2306                (5207990763031199744_i64),
2307                (2),
2308                (2345108766317314046_i64),
2309                (5189976364521848832_i64),
2310                (1),
2311                (1226245742482522112_i64),
2312                ((
2313                    "3618502788666131213697322783095070105623107215331596699973092056135872020476",
2314                    10
2315                )),
2316                (2345108766317314046_i64)
2317            ),
2318            main = Some(3),
2319        );
2320        let mut hint_processor = BuiltinHintProcessor::new_empty();
2321        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2322        cairo_runner.initialize_segments(None);
2323        let end = cairo_runner.initialize_main_entrypoint().unwrap();
2324        assert_eq!(end, Relocatable::from((3, 0)));
2325        cairo_runner.initialize_vm().unwrap();
2326        //Execution Phase
2327        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2328        //Check final values against Python VM
2329        //Check final register values
2330        assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((3, 0)));
2331
2332        assert_eq!(cairo_runner.vm.run_context.ap, 6);
2333
2334        assert_eq!(cairo_runner.vm.run_context.fp, 0);
2335
2336        //Check each TraceEntry in trace
2337        let trace = cairo_runner.vm.trace.unwrap();
2338        assert_eq!(trace.len(), 5);
2339        trace_check(
2340            &trace,
2341            &[
2342                ((0, 3).into(), 2, 2),
2343                ((0, 5).into(), 3, 2),
2344                ((0, 0).into(), 5, 5),
2345                ((0, 2).into(), 6, 5),
2346                ((0, 7).into(), 6, 2),
2347            ],
2348        );
2349    }
2350
2351    #[test]
2352    /*Program used:
2353    %builtins range_check
2354
2355    func check_range{range_check_ptr}(num):
2356
2357        # Check that 0 <= num < 2**64.
2358        [range_check_ptr] = num
2359        assert [range_check_ptr + 1] = 2 ** 64 - 1 - num
2360        let range_check_ptr = range_check_ptr + 2
2361        return()
2362    end
2363
2364    func main{range_check_ptr}():
2365        check_range(7)
2366        return()
2367    end
2368
2369    main = 8
2370    data = [4612671182993129469, 5189976364521848832, 18446744073709551615, 5199546496550207487, 4612389712311386111, 5198983563776393216, 2, 2345108766317314046, 5191102247248822272, 5189976364521848832, 7, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020470, 2345108766317314046]
2371    */
2372    fn initialize_and_run_range_check_builtin() {
2373        //Initialization Phase
2374        let program = program!(
2375            builtins = vec![BuiltinName::range_check],
2376            data = vec_data!(
2377                (4612671182993129469_i64),
2378                (5189976364521848832_i64),
2379                (18446744073709551615_i128),
2380                (5199546496550207487_i64),
2381                (4612389712311386111_i64),
2382                (5198983563776393216_i64),
2383                (2),
2384                (2345108766317314046_i64),
2385                (5191102247248822272_i64),
2386                (5189976364521848832_i64),
2387                (7),
2388                (1226245742482522112_i64),
2389                ((
2390                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
2391                    10
2392                )),
2393                (2345108766317314046_i64)
2394            ),
2395            main = Some(8),
2396        );
2397        let mut hint_processor = BuiltinHintProcessor::new_empty();
2398        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2399        cairo_runner.initialize_builtins(false).unwrap();
2400        cairo_runner.initialize_segments(None);
2401        let end = cairo_runner.initialize_main_entrypoint().unwrap();
2402        cairo_runner.initialize_vm().unwrap();
2403        //Execution Phase
2404        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2405        //Check final values against Python VM
2406        //Check final register values
2407        assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((4, 0)));
2408
2409        assert_eq!(cairo_runner.vm.run_context.ap, 10);
2410
2411        assert_eq!(cairo_runner.vm.run_context.fp, 0);
2412
2413        //Check each TraceEntry in trace
2414        let trace = cairo_runner.vm.trace.unwrap();
2415        assert_eq!(trace.len(), 10);
2416        trace_check(
2417            &trace,
2418            &[
2419                ((0, 8).into(), 3, 3),
2420                ((0, 9).into(), 4, 3),
2421                ((0, 11).into(), 5, 3),
2422                ((0, 0).into(), 7, 7),
2423                ((0, 1).into(), 7, 7),
2424                ((0, 3).into(), 8, 7),
2425                ((0, 4).into(), 9, 7),
2426                ((0, 5).into(), 9, 7),
2427                ((0, 7).into(), 10, 7),
2428                ((0, 13).into(), 10, 3),
2429            ],
2430        );
2431        //Check the range_check builtin segment
2432        assert_eq!(
2433            cairo_runner.vm.builtin_runners[0].name(),
2434            BuiltinName::range_check
2435        );
2436        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2437
2438        check_memory!(
2439            cairo_runner.vm.segments.memory,
2440            ((2, 0), 7),
2441            ((2, 1), 18446744073709551608_i128)
2442        );
2443        assert!(cairo_runner
2444            .vm
2445            .segments
2446            .memory
2447            .get(&MaybeRelocatable::from((2, 2)))
2448            .is_none());
2449    }
2450
2451    #[test]
2452    /*Program used:
2453    %builtins output
2454
2455    from starkware.cairo.common.serialize import serialize_word
2456
2457    func main{output_ptr: felt*}():
2458        let a = 1
2459        serialize_word(a)
2460        let b = 17 * a
2461        serialize_word(b)
2462        return()
2463    end
2464
2465    main = 4
2466    data = [
2467    4612671182993129469,
2468    5198983563776393216,
2469    1,
2470    2345108766317314046,
2471    5191102247248822272,
2472    5189976364521848832,
2473    1,
2474    1226245742482522112,
2475    3618502788666131213697322783095070105623107215331596699973092056135872020474,
2476    5189976364521848832,
2477    17,
2478    1226245742482522112,
2479    3618502788666131213697322783095070105623107215331596699973092056135872020470,
2480    2345108766317314046
2481    ]
2482    */
2483    fn initialize_and_run_output_builtin() {
2484        //Initialization Phase
2485        let program = program!(
2486            builtins = vec![BuiltinName::output],
2487            data = vec_data!(
2488                (4612671182993129469_i64),
2489                (5198983563776393216_i64),
2490                (1),
2491                (2345108766317314046_i64),
2492                (5191102247248822272_i64),
2493                (5189976364521848832_i64),
2494                (1),
2495                (1226245742482522112_i64),
2496                ((
2497                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2498                    10
2499                )),
2500                (5189976364521848832_i64),
2501                (17),
2502                (1226245742482522112_i64),
2503                ((
2504                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
2505                    10
2506                )),
2507                (2345108766317314046_i64)
2508            ),
2509            main = Some(4),
2510        );
2511        let mut hint_processor = BuiltinHintProcessor::new_empty();
2512        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2513        cairo_runner.initialize_builtins(false).unwrap();
2514        cairo_runner.initialize_segments(None);
2515        let end = cairo_runner.initialize_main_entrypoint().unwrap();
2516        cairo_runner.initialize_vm().unwrap();
2517        //Execution Phase
2518        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2519        //Check final values against Python VM
2520        //Check final register values
2521        //todo
2522        assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((4, 0)));
2523
2524        assert_eq!(cairo_runner.vm.run_context.ap, 12);
2525
2526        assert_eq!(cairo_runner.vm.run_context.fp, 0);
2527
2528        //Check each TraceEntry in trace
2529        let trace = cairo_runner.vm.trace.unwrap();
2530        assert_eq!(trace.len(), 12);
2531        trace_check(
2532            &trace,
2533            &[
2534                ((0, 4).into(), 3, 3),
2535                ((0, 5).into(), 4, 3),
2536                ((0, 7).into(), 5, 3),
2537                ((0, 0).into(), 7, 7),
2538                ((0, 1).into(), 7, 7),
2539                ((0, 3).into(), 8, 7),
2540                ((0, 9).into(), 8, 3),
2541                ((0, 11).into(), 9, 3),
2542                ((0, 0).into(), 11, 11),
2543                ((0, 1).into(), 11, 11),
2544                ((0, 3).into(), 12, 11),
2545                ((0, 13).into(), 12, 3),
2546            ],
2547        );
2548        //Check that the output to be printed is correct
2549        assert_eq!(
2550            cairo_runner.vm.builtin_runners[0].name(),
2551            BuiltinName::output
2552        );
2553        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2554        check_memory!(cairo_runner.vm.segments.memory, ((2, 0), 1), ((2, 1), 17));
2555        assert!(cairo_runner
2556            .vm
2557            .segments
2558            .memory
2559            .get(&MaybeRelocatable::from((2, 2)))
2560            .is_none());
2561    }
2562
2563    #[test]
2564    /*Program used:
2565    %builtins output range_check
2566
2567    from starkware.cairo.common.serialize import serialize_word
2568
2569    func check_range{range_check_ptr}(num) -> (num : felt):
2570
2571        # Check that 0 <= num < 2**64.
2572        [range_check_ptr] = num
2573        assert [range_check_ptr + 1] = 2 ** 64 - 1 - num
2574        let range_check_ptr = range_check_ptr + 2
2575        return(num)
2576    end
2577
2578    func main{output_ptr: felt*, range_check_ptr: felt}():
2579        let num: felt = check_range(7)
2580        serialize_word(num)
2581        return()
2582    end
2583
2584    main = 13
2585    data = [
2586    4612671182993129469,
2587    5198983563776393216,
2588    1,
2589    2345108766317314046,
2590    4612671182993129469,
2591    5189976364521848832,
2592    18446744073709551615,
2593    5199546496550207487,
2594    4612389712311386111,
2595    5198983563776393216,
2596    2,
2597    5191102247248822272,
2598    2345108766317314046,
2599    5191102247248822272,
2600    5189976364521848832,
2601    7,
2602    1226245742482522112,
2603    3618502788666131213697322783095070105623107215331596699973092056135872020469,
2604    5191102242953854976,
2605    5193354051357474816,
2606    1226245742482522112,
2607    3618502788666131213697322783095070105623107215331596699973092056135872020461,
2608    5193354029882638336,
2609    2345108766317314046]
2610    */
2611    fn initialize_and_run_output_range_check_builtin() {
2612        //Initialization Phase
2613        let program = program!(
2614            builtins = vec![BuiltinName::output, BuiltinName::range_check],
2615            data = vec_data!(
2616                (4612671182993129469_i64),
2617                (5198983563776393216_i64),
2618                (1),
2619                (2345108766317314046_i64),
2620                (4612671182993129469_i64),
2621                (5189976364521848832_i64),
2622                (18446744073709551615_i128),
2623                (5199546496550207487_i64),
2624                (4612389712311386111_i64),
2625                (5198983563776393216_i64),
2626                (2),
2627                (5191102247248822272_i64),
2628                (2345108766317314046_i64),
2629                (5191102247248822272_i64),
2630                (5189976364521848832_i64),
2631                (7),
2632                (1226245742482522112_i64),
2633                ((
2634                    "3618502788666131213697322783095070105623107215331596699973092056135872020469",
2635                    10
2636                )),
2637                (5191102242953854976_i64),
2638                (5193354051357474816_i64),
2639                (1226245742482522112_i64),
2640                ((
2641                    "3618502788666131213697322783095070105623107215331596699973092056135872020461",
2642                    10
2643                )),
2644                (5193354029882638336_i64),
2645                (2345108766317314046_i64)
2646            ),
2647            main = Some(13),
2648        );
2649        let mut hint_processor = BuiltinHintProcessor::new_empty();
2650        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2651        cairo_runner.initialize_builtins(false).unwrap();
2652        cairo_runner.initialize_segments(None);
2653        let end = cairo_runner.initialize_main_entrypoint().unwrap();
2654        cairo_runner.initialize_vm().unwrap();
2655        //Execution Phase
2656        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2657        //Check final values against Python VM
2658        //Check final register values
2659        assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((5, 0)));
2660
2661        assert_eq!(cairo_runner.vm.run_context.ap, 18);
2662
2663        assert_eq!(cairo_runner.vm.run_context.fp, 0);
2664
2665        //Check each TraceEntry in trace
2666        let trace = cairo_runner.vm.trace.unwrap();
2667        assert_eq!(trace.len(), 18);
2668        trace_check(
2669            &trace,
2670            &[
2671                ((0, 13).into(), 4, 4),
2672                ((0, 14).into(), 5, 4),
2673                ((0, 16).into(), 6, 4),
2674                ((0, 4).into(), 8, 8),
2675                ((0, 5).into(), 8, 8),
2676                ((0, 7).into(), 9, 8),
2677                ((0, 8).into(), 10, 8),
2678                ((0, 9).into(), 10, 8),
2679                ((0, 11).into(), 11, 8),
2680                ((0, 12).into(), 12, 8),
2681                ((0, 18).into(), 12, 4),
2682                ((0, 19).into(), 13, 4),
2683                ((0, 20).into(), 14, 4),
2684                ((0, 0).into(), 16, 16),
2685                ((0, 1).into(), 16, 16),
2686                ((0, 3).into(), 17, 16),
2687                ((0, 22).into(), 17, 4),
2688                ((0, 23).into(), 18, 4),
2689            ],
2690        );
2691        //Check the range_check builtin segment
2692        assert_eq!(
2693            cairo_runner.vm.builtin_runners[1].name(),
2694            BuiltinName::range_check
2695        );
2696        assert_eq!(cairo_runner.vm.builtin_runners[1].base(), 3);
2697
2698        check_memory!(
2699            cairo_runner.vm.segments.memory,
2700            ((3, 0), 7),
2701            ((3, 1), 18446744073709551608_i128)
2702        );
2703        assert!(cairo_runner
2704            .vm
2705            .segments
2706            .memory
2707            .get(&MaybeRelocatable::from((2, 2)))
2708            .is_none());
2709
2710        //Check the output segment
2711        assert_eq!(
2712            cairo_runner.vm.builtin_runners[0].name(),
2713            BuiltinName::output
2714        );
2715        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2716
2717        check_memory!(cairo_runner.vm.segments.memory, ((2, 0), 7));
2718        assert!(cairo_runner
2719            .vm
2720            .segments
2721            .memory
2722            .get(&(MaybeRelocatable::from((2, 1))))
2723            .is_none());
2724    }
2725
2726    #[test]
2727    /*Memory from this test is taken from a cairo program execution
2728    Program used:
2729        func main():
2730        let a = 1
2731        [ap + 3] = 5
2732        return()
2733
2734    end
2735    Final Memory:
2736    {RelocatableValue(segment_index=0, offset=0): 4613515612218425347,
2737     RelocatableValue(segment_index=0, offset=1): 5,
2738     RelocatableValue(segment_index=0, offset=2): 2345108766317314046,
2739     RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
2740     RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0),
2741     RelocatableValue(segment_index=1, offset=5): 5}
2742    Relocated Memory:
2743        1     4613515612218425347
2744        2     5
2745        3     2345108766317314046
2746        4     10
2747        5     10
27482749        9     5
2750    */
2751    fn relocate_memory_with_gap() {
2752        let program = program!();
2753        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2754        for _ in 0..4 {
2755            cairo_runner.vm.segments.add();
2756        }
2757        // Memory initialization without macro
2758        cairo_runner
2759            .vm
2760            .segments
2761            .memory
2762            .insert(
2763                Relocatable::from((0, 0)),
2764                &MaybeRelocatable::from(Felt252::from(4613515612218425347_i64)),
2765            )
2766            .unwrap();
2767        cairo_runner
2768            .vm
2769            .segments
2770            .memory
2771            .insert(
2772                Relocatable::from((0, 1)),
2773                &MaybeRelocatable::from(Felt252::from(5)),
2774            )
2775            .unwrap();
2776        cairo_runner
2777            .vm
2778            .segments
2779            .memory
2780            .insert(
2781                Relocatable::from((0, 2)),
2782                &MaybeRelocatable::from(Felt252::from(2345108766317314046_i64)),
2783            )
2784            .unwrap();
2785        cairo_runner
2786            .vm
2787            .segments
2788            .memory
2789            .insert(Relocatable::from((1, 0)), &MaybeRelocatable::from((2, 0)))
2790            .unwrap();
2791        cairo_runner
2792            .vm
2793            .segments
2794            .memory
2795            .insert(Relocatable::from((1, 1)), &MaybeRelocatable::from((3, 0)))
2796            .unwrap();
2797        cairo_runner
2798            .vm
2799            .segments
2800            .memory
2801            .insert(
2802                Relocatable::from((1, 5)),
2803                &MaybeRelocatable::from(Felt252::from(5)),
2804            )
2805            .unwrap();
2806        cairo_runner.vm.segments.compute_effective_sizes();
2807        let rel_table = cairo_runner
2808            .vm
2809            .segments
2810            .relocate_segments()
2811            .expect("Couldn't relocate after compute effective sizes");
2812        assert_eq!(cairo_runner.relocate_memory(&rel_table), Ok(()));
2813        assert_eq!(cairo_runner.relocated_memory[0], None);
2814        assert_eq!(
2815            cairo_runner.relocated_memory[1],
2816            Some(Felt252::from(4613515612218425347_i64))
2817        );
2818        assert_eq!(cairo_runner.relocated_memory[2], Some(Felt252::from(5)));
2819        assert_eq!(
2820            cairo_runner.relocated_memory[3],
2821            Some(Felt252::from(2345108766317314046_i64))
2822        );
2823        assert_eq!(cairo_runner.relocated_memory[4], Some(Felt252::from(10)));
2824        assert_eq!(cairo_runner.relocated_memory[5], Some(Felt252::from(10)));
2825        assert_eq!(cairo_runner.relocated_memory[6], None);
2826        assert_eq!(cairo_runner.relocated_memory[7], None);
2827        assert_eq!(cairo_runner.relocated_memory[8], None);
2828        assert_eq!(cairo_runner.relocated_memory[9], Some(Felt252::from(5)));
2829    }
2830
2831    #[test]
2832    /* Program used:
2833    %builtins output
2834
2835    from starkware.cairo.common.serialize import serialize_word
2836
2837    func main{output_ptr: felt*}():
2838        let a = 1
2839        serialize_word(a)
2840        let b = 17 * a
2841        serialize_word(b)
2842        return()
2843    end
2844    Relocated Memory:
2845        1     4612671182993129469
2846        2     5198983563776393216
2847        3     1
2848        4     2345108766317314046
2849        5     5191102247248822272
2850        6     5189976364521848832
2851        7     1
2852        8     1226245742482522112
2853        9     -7
2854        10    5189976364521848832
2855        11    17
2856        12    1226245742482522112
2857        13    -11
2858        14    2345108766317314046
2859        15    27
2860        16    29
2861        17    29
2862        18    27
2863        19    1
2864        20    18
2865        21    10
2866        22    28
2867        23    17
2868        24    18
2869        25    14
2870        26    29
2871        27    1
2872        28    17
2873     */
2874    fn initialize_run_and_relocate_output_builtin() {
2875        let program = program!(
2876            builtins = vec![BuiltinName::output],
2877            data = vec_data!(
2878                (4612671182993129469_i64),
2879                (5198983563776393216_i64),
2880                (1),
2881                (2345108766317314046_i64),
2882                (5191102247248822272_i64),
2883                (5189976364521848832_i64),
2884                (1),
2885                (1226245742482522112_i64),
2886                ((
2887                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2888                    10
2889                )),
2890                (5189976364521848832_i64),
2891                (17),
2892                (1226245742482522112_i64),
2893                ((
2894                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
2895                    10
2896                )),
2897                (2345108766317314046_i64)
2898            ),
2899            main = Some(4),
2900        );
2901        let mut hint_processor = BuiltinHintProcessor::new_empty();
2902        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2903        cairo_runner.initialize_builtins(false).unwrap();
2904        cairo_runner.initialize_segments(None);
2905        let end = cairo_runner.initialize_main_entrypoint().unwrap();
2906        cairo_runner.initialize_vm().unwrap();
2907        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2908        cairo_runner.vm.segments.compute_effective_sizes();
2909        let rel_table = cairo_runner
2910            .vm
2911            .segments
2912            .relocate_segments()
2913            .expect("Couldn't relocate after compute effective sizes");
2914        assert_eq!(cairo_runner.relocate_memory(&rel_table), Ok(()));
2915        assert_eq!(cairo_runner.relocated_memory[0], None);
2916        assert_eq!(
2917            cairo_runner.relocated_memory[1],
2918            Some(Felt252::from(4612671182993129469_u64))
2919        );
2920        assert_eq!(
2921            cairo_runner.relocated_memory[2],
2922            Some(Felt252::from(5198983563776393216_u64))
2923        );
2924        assert_eq!(cairo_runner.relocated_memory[3], Some(Felt252::ONE));
2925        assert_eq!(
2926            cairo_runner.relocated_memory[4],
2927            Some(Felt252::from(2345108766317314046_u64))
2928        );
2929        assert_eq!(
2930            cairo_runner.relocated_memory[5],
2931            Some(Felt252::from(5191102247248822272_u64))
2932        );
2933        assert_eq!(
2934            cairo_runner.relocated_memory[6],
2935            Some(Felt252::from(5189976364521848832_u64))
2936        );
2937        assert_eq!(cairo_runner.relocated_memory[7], Some(Felt252::ONE));
2938        assert_eq!(
2939            cairo_runner.relocated_memory[8],
2940            Some(Felt252::from(1226245742482522112_u64))
2941        );
2942        assert_eq!(
2943            cairo_runner.relocated_memory[9],
2944            Some(felt_hex!(
2945                "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffa"
2946            ))
2947        );
2948        assert_eq!(
2949            cairo_runner.relocated_memory[10],
2950            Some(Felt252::from(5189976364521848832_u64))
2951        );
2952        assert_eq!(cairo_runner.relocated_memory[11], Some(Felt252::from(17)));
2953        assert_eq!(
2954            cairo_runner.relocated_memory[12],
2955            Some(Felt252::from(1226245742482522112_u64))
2956        );
2957        assert_eq!(
2958            cairo_runner.relocated_memory[13],
2959            Some(felt_hex!(
2960                "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff6"
2961            ))
2962        );
2963        assert_eq!(
2964            cairo_runner.relocated_memory[14],
2965            Some(Felt252::from(2345108766317314046_u64))
2966        );
2967        assert_eq!(
2968            cairo_runner.relocated_memory[15],
2969            Some(Felt252::from(27_u64))
2970        );
2971        assert_eq!(cairo_runner.relocated_memory[16], Some(Felt252::from(29)));
2972        assert_eq!(cairo_runner.relocated_memory[17], Some(Felt252::from(29)));
2973        assert_eq!(cairo_runner.relocated_memory[18], Some(Felt252::from(27)));
2974        assert_eq!(cairo_runner.relocated_memory[19], Some(Felt252::ONE));
2975        assert_eq!(cairo_runner.relocated_memory[20], Some(Felt252::from(18)));
2976        assert_eq!(cairo_runner.relocated_memory[21], Some(Felt252::from(10)));
2977        assert_eq!(cairo_runner.relocated_memory[22], Some(Felt252::from(28)));
2978        assert_eq!(cairo_runner.relocated_memory[23], Some(Felt252::from(17)));
2979        assert_eq!(cairo_runner.relocated_memory[24], Some(Felt252::from(18)));
2980        assert_eq!(cairo_runner.relocated_memory[25], Some(Felt252::from(14)));
2981        assert_eq!(cairo_runner.relocated_memory[26], Some(Felt252::from(29)));
2982        assert_eq!(cairo_runner.relocated_memory[27], Some(Felt252::ONE));
2983        assert_eq!(cairo_runner.relocated_memory[28], Some(Felt252::from(17)));
2984    }
2985
2986    #[test]
2987    /* Program used:
2988    %builtins output
2989
2990    from starkware.cairo.common.serialize import serialize_word
2991
2992    func main{output_ptr: felt*}():
2993        let a = 1
2994        serialize_word(a)
2995        let b = 17 * a
2996        serialize_word(b)
2997        return()
2998    end
2999
3000    Relocated Trace:
3001    [TraceEntry(pc=5, ap=18, fp=18),
3002     TraceEntry(pc=6, ap=19, fp=18),
3003     TraceEntry(pc=8, ap=20, fp=18),
3004     TraceEntry(pc=1, ap=22, fp=22),
3005     TraceEntry(pc=2, ap=22, fp=22),
3006     TraceEntry(pc=4, ap=23, fp=22),
3007     TraceEntry(pc=10, ap=23, fp=18),
3008    */
3009    fn relocate_trace_output_builtin() {
3010        let program = program!(
3011            builtins = vec![BuiltinName::output],
3012            data = vec_data!(
3013                (4612671182993129469_i64),
3014                (5198983563776393216_i64),
3015                (1),
3016                (2345108766317314046_i64),
3017                (5191102247248822272_i64),
3018                (5189976364521848832_i64),
3019                (1),
3020                (1226245742482522112_i64),
3021                ((
3022                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
3023                    10
3024                )),
3025                (5189976364521848832_i64),
3026                (17),
3027                (1226245742482522112_i64),
3028                ((
3029                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3030                    10
3031                )),
3032                (2345108766317314046_i64)
3033            ),
3034            main = Some(4),
3035        );
3036        let mut hint_processor = BuiltinHintProcessor::new_empty();
3037        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3038        cairo_runner.initialize_builtins(false).unwrap();
3039        cairo_runner.initialize_segments(None);
3040        let end = cairo_runner.initialize_main_entrypoint().unwrap();
3041        cairo_runner.initialize_vm().unwrap();
3042        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3043        cairo_runner.vm.segments.compute_effective_sizes();
3044        let rel_table = cairo_runner
3045            .vm
3046            .segments
3047            .relocate_segments()
3048            .expect("Couldn't relocate after compute effective sizes");
3049        cairo_runner.relocate_trace(&rel_table).unwrap();
3050        let relocated_trace = cairo_runner.relocated_trace.unwrap();
3051        assert_eq!(relocated_trace.len(), 12);
3052        assert_eq!(
3053            relocated_trace[0],
3054            RelocatedTraceEntry {
3055                pc: 5,
3056                ap: 18,
3057                fp: 18
3058            }
3059        );
3060        assert_eq!(
3061            relocated_trace[1],
3062            RelocatedTraceEntry {
3063                pc: 6,
3064                ap: 19,
3065                fp: 18
3066            }
3067        );
3068        assert_eq!(
3069            relocated_trace[2],
3070            RelocatedTraceEntry {
3071                pc: 8,
3072                ap: 20,
3073                fp: 18
3074            }
3075        );
3076        assert_eq!(
3077            relocated_trace[3],
3078            RelocatedTraceEntry {
3079                pc: 1,
3080                ap: 22,
3081                fp: 22
3082            }
3083        );
3084        assert_eq!(
3085            relocated_trace[4],
3086            RelocatedTraceEntry {
3087                pc: 2,
3088                ap: 22,
3089                fp: 22
3090            }
3091        );
3092        assert_eq!(
3093            relocated_trace[5],
3094            RelocatedTraceEntry {
3095                pc: 4,
3096                ap: 23,
3097                fp: 22
3098            }
3099        );
3100        assert_eq!(
3101            relocated_trace[6],
3102            RelocatedTraceEntry {
3103                pc: 10,
3104                ap: 23,
3105                fp: 18
3106            }
3107        );
3108        assert_eq!(
3109            relocated_trace[7],
3110            RelocatedTraceEntry {
3111                pc: 12,
3112                ap: 24,
3113                fp: 18
3114            }
3115        );
3116        assert_eq!(
3117            relocated_trace[8],
3118            RelocatedTraceEntry {
3119                pc: 1,
3120                ap: 26,
3121                fp: 26
3122            }
3123        );
3124        assert_eq!(
3125            relocated_trace[9],
3126            RelocatedTraceEntry {
3127                pc: 2,
3128                ap: 26,
3129                fp: 26
3130            }
3131        );
3132        assert_eq!(
3133            relocated_trace[10],
3134            RelocatedTraceEntry {
3135                pc: 4,
3136                ap: 27,
3137                fp: 26
3138            }
3139        );
3140        assert_eq!(
3141            relocated_trace[11],
3142            RelocatedTraceEntry {
3143                pc: 14,
3144                ap: 27,
3145                fp: 18
3146            }
3147        );
3148    }
3149
3150    #[test]
3151    fn write_output_from_preset_memory() {
3152        let program = program![BuiltinName::output];
3153        let mut cairo_runner = cairo_runner!(program);
3154        cairo_runner.initialize_builtins(false).unwrap();
3155        cairo_runner.initialize_segments(None);
3156        assert_eq!(
3157            cairo_runner.vm.builtin_runners[0].name(),
3158            BuiltinName::output
3159        );
3160        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
3161
3162        cairo_runner.vm.segments = segments![((2, 0), 1), ((2, 1), 2)];
3163        cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 0, 2]);
3164
3165        let mut output_buffer = String::new();
3166        cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3167        assert_eq!(&output_buffer, "1\n2\n");
3168    }
3169
3170    #[test]
3171    /*Program used:
3172    %builtins output
3173
3174    from starkware.cairo.common.serialize import serialize_word
3175
3176    func main{output_ptr: felt*}():
3177        let a = 1
3178        serialize_word(a)
3179        return()
3180    end */
3181    fn get_output_from_program() {
3182        //Initialization Phase
3183        let program = program!(
3184            builtins = vec![BuiltinName::output],
3185            data = vec_data!(
3186                (4612671182993129469_i64),
3187                (5198983563776393216_i64),
3188                (1),
3189                (2345108766317314046_i64),
3190                (5191102247248822272_i64),
3191                (5189976364521848832_i64),
3192                (1),
3193                (1226245742482522112_i64),
3194                ((
3195                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
3196                    10
3197                )),
3198                (5189976364521848832_i64),
3199                (17),
3200                (1226245742482522112_i64),
3201                ((
3202                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3203                    10
3204                )),
3205                (2345108766317314046_i64)
3206            ),
3207            main = Some(4),
3208        );
3209        let mut cairo_runner = cairo_runner!(program);
3210        cairo_runner.initialize_builtins(false).unwrap();
3211        cairo_runner.initialize_segments(None);
3212        let end = cairo_runner.initialize_main_entrypoint().unwrap();
3213        cairo_runner.initialize_vm().unwrap();
3214        //Execution Phase
3215        let mut hint_processor = BuiltinHintProcessor::new_empty();
3216        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3217
3218        let mut output_buffer = String::new();
3219        cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3220        assert_eq!(&output_buffer, "1\n17\n");
3221    }
3222
3223    #[test]
3224    /*Program used:
3225    %builtins output
3226
3227    func main{output_ptr: felt*}() {
3228        //Memory Gap + Relocatable value
3229        assert [output_ptr + 1] = cast(output_ptr, felt);
3230        let output_ptr = output_ptr + 2;
3231        return ();
3232    }*/
3233    fn write_output_from_program_gap_relocatable_output() {
3234        //Initialization Phase
3235        let program = program!(
3236            builtins = vec![BuiltinName::output],
3237            data = vec_data!(
3238                (4612671187288162301),
3239                (5198983563776458752),
3240                (2),
3241                (2345108766317314046)
3242            ),
3243            main = Some(0),
3244        );
3245        let mut cairo_runner = cairo_runner!(program);
3246        cairo_runner.initialize_builtins(false).unwrap();
3247        cairo_runner.initialize_segments(None);
3248        let end = cairo_runner.initialize_main_entrypoint().unwrap();
3249        cairo_runner.initialize_vm().unwrap();
3250        //Execution Phase
3251        let mut hint_processor = BuiltinHintProcessor::new_empty();
3252        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3253
3254        let mut output_buffer = String::new();
3255        cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3256        assert_eq!(&output_buffer, "<missing>\n2:0\n");
3257    }
3258
3259    #[test]
3260    fn write_output_from_preset_memory_neg_output() {
3261        let program = program![BuiltinName::output];
3262        let mut cairo_runner = cairo_runner!(program);
3263        cairo_runner.initialize_builtins(false).unwrap();
3264        cairo_runner.initialize_segments(None);
3265        assert_eq!(
3266            cairo_runner.vm.builtin_runners[0].name(),
3267            BuiltinName::output
3268        );
3269        assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
3270        cairo_runner.vm.segments = segments![(
3271            (2, 0),
3272            (
3273                "800000000000011000000000000000000000000000000000000000000000000",
3274                16
3275            )
3276        )];
3277        cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 0, 1]);
3278
3279        let mut output_buffer = String::new();
3280        cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3281        assert_eq!(&output_buffer, "-1\n");
3282    }
3283
3284    /// Test that `get_output()` works when the `output` builtin is not the first one.
3285    #[test]
3286    fn get_output_unordered_builtins() {
3287        //Initialization Phase
3288        let program = program!(
3289            builtins = vec![BuiltinName::output, BuiltinName::bitwise],
3290            data = vec_data!(
3291                (4612671182993129469_i64),
3292                (5198983563776393216_i64),
3293                (1),
3294                (2345108766317314046_i64),
3295                (5191102247248822272_i64),
3296                (5189976364521848832_i64),
3297                (1),
3298                (1226245742482522112_i64),
3299                ((
3300                    "3618502788666131213697322783095070105623107215331596699973092056135872020474",
3301                    10
3302                )),
3303                (5189976364521848832_i64),
3304                (17),
3305                (1226245742482522112_i64),
3306                ((
3307                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3308                    10
3309                )),
3310                (2345108766317314046_i64)
3311            ),
3312            main = Some(4),
3313        );
3314
3315        let mut cairo_runner = cairo_runner!(program);
3316
3317        cairo_runner
3318            .initialize_builtins(false)
3319            .expect("Couldn't initialize builtins.");
3320
3321        // Swap the first and second builtins (first should be `output`).
3322        cairo_runner.vm.builtin_runners.swap(0, 1);
3323        cairo_runner.program.builtins.swap(0, 1);
3324
3325        cairo_runner.initialize_segments(None);
3326
3327        let end = cairo_runner
3328            .initialize_main_entrypoint()
3329            .expect("Couldn't initialize the main entrypoint.");
3330        cairo_runner
3331            .initialize_vm()
3332            .expect("Couldn't initialize the cairo_runner.VM.");
3333
3334        let mut hint_processor = BuiltinHintProcessor::new_empty();
3335        assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3336
3337        let mut output_buffer = String::new();
3338        cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3339        assert_eq!(&output_buffer, "1\n17\n");
3340    }
3341
3342    #[test]
3343    fn insert_all_builtins_in_order() {
3344        let program = program![
3345            BuiltinName::output,
3346            BuiltinName::pedersen,
3347            BuiltinName::range_check,
3348            BuiltinName::bitwise,
3349            BuiltinName::ec_op
3350        ];
3351        let mut cairo_runner = cairo_runner!(program);
3352        cairo_runner.initialize_builtins(false).unwrap();
3353        assert_eq!(
3354            cairo_runner.vm.builtin_runners[0].name(),
3355            BuiltinName::output
3356        );
3357        assert_eq!(
3358            cairo_runner.vm.builtin_runners[1].name(),
3359            BuiltinName::pedersen
3360        );
3361        assert_eq!(
3362            cairo_runner.vm.builtin_runners[2].name(),
3363            BuiltinName::range_check
3364        );
3365        assert_eq!(
3366            cairo_runner.vm.builtin_runners[3].name(),
3367            BuiltinName::bitwise
3368        );
3369        assert_eq!(
3370            cairo_runner.vm.builtin_runners[4].name(),
3371            BuiltinName::ec_op
3372        );
3373    }
3374
3375    #[test]
3376    /*Program used:
3377    %builtins range_check
3378
3379    func check_range{range_check_ptr}(num):
3380        # Check that 0 <= num < 2**64.
3381        [range_check_ptr] = num
3382        assert [range_check_ptr + 1] = 2 ** 64 - 1 - num
3383        let range_check_ptr = range_check_ptr + 2
3384        return()
3385    end
3386
3387    func main{range_check_ptr}():
3388        check_range(7)
3389        return()
3390    end
3391
3392    main = 8
3393    data = [4612671182993129469, 5189976364521848832, 18446744073709551615, 5199546496550207487, 4612389712311386111, 5198983563776393216, 2, 2345108766317314046, 5191102247248822272, 5189976364521848832, 7, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020470, 2345108766317314046]
3394    */
3395    fn run_for_steps() {
3396        let program = program!(
3397            builtins = vec![BuiltinName::range_check],
3398            data = vec_data!(
3399                (4612671182993129469_i64),
3400                (5189976364521848832_i64),
3401                (18446744073709551615_i128),
3402                (5199546496550207487_i64),
3403                (4612389712311386111_i64),
3404                (5198983563776393216_i64),
3405                (2),
3406                (2345108766317314046_i64),
3407                (5191102247248822272_i64),
3408                (5189976364521848832_i64),
3409                (7),
3410                (1226245742482522112_i64),
3411                ((
3412                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3413                    10
3414                )),
3415                (2345108766317314046_i64)
3416            ),
3417            main = Some(8),
3418        );
3419
3420        let mut hint_processor = BuiltinHintProcessor::new_empty();
3421        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3422        cairo_runner.initialize_builtins(false).unwrap();
3423        cairo_runner.initialize_segments(None);
3424
3425        cairo_runner.initialize_main_entrypoint().unwrap();
3426        cairo_runner.initialize_vm().unwrap();
3427
3428        // Full takes 10 steps.
3429        assert_matches!(cairo_runner.run_for_steps(8, &mut hint_processor), Ok(()));
3430        assert_matches!(
3431            cairo_runner.run_for_steps(8, &mut hint_processor),
3432            Err(VirtualMachineError::EndOfProgram(x)) if x == 8 - 2
3433        );
3434    }
3435
3436    #[test]
3437    fn run_empty_all_cairo() {
3438        let program = program!();
3439        let mut cairo_runner = cairo_runner!(&program, LayoutName::all_cairo, false, true);
3440        assert_matches!(
3441            cairo_runner.initialize(false),
3442            Err(RunnerError::MissingMain)
3443        );
3444    }
3445
3446    #[test]
3447    fn run_empty_recursive_with_poseidon() {
3448        let program = program!();
3449        let mut cairo_runner =
3450            cairo_runner!(&program, LayoutName::recursive_with_poseidon, false, true);
3451        assert_matches!(
3452            cairo_runner.initialize(false),
3453            Err(RunnerError::MissingMain)
3454        );
3455    }
3456
3457    #[test]
3458    fn run_empty_all_cairo_stwo() {
3459        let program = program!();
3460        let mut cairo_runner = cairo_runner!(&program, LayoutName::all_cairo_stwo, false, true);
3461        assert_matches!(
3462            cairo_runner.initialize(false),
3463            Err(RunnerError::MissingMain)
3464        );
3465    }
3466
3467    #[test]
3468    /*Program used:
3469    %builtins range_check
3470
3471    func check_range{range_check_ptr}(num):
3472        # Check that 0 <= num < 2**64.
3473        [range_check_ptr] = num
3474        assert [range_check_ptr + 1] = 2 ** 64 - 1 - num
3475        let range_check_ptr = range_check_ptr + 2
3476        return()
3477    end
3478
3479    func main{range_check_ptr}():
3480        check_range(7)
3481        return()
3482    end
3483
3484    main = 8
3485    data = [4612671182993129469, 5189976364521848832, 18446744073709551615, 5199546496550207487, 4612389712311386111, 5198983563776393216, 2, 2345108766317314046, 5191102247248822272, 5189976364521848832, 7, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020470, 2345108766317314046]
3486    */
3487    fn run_until_steps() {
3488        let program = program!(
3489            builtins = vec![BuiltinName::range_check],
3490            data = vec_data!(
3491                (4612671182993129469_i64),
3492                (5189976364521848832_i64),
3493                (18446744073709551615_i128),
3494                (5199546496550207487_i64),
3495                (4612389712311386111_i64),
3496                (5198983563776393216_i64),
3497                (2),
3498                (2345108766317314046_i64),
3499                (5191102247248822272_i64),
3500                (5189976364521848832_i64),
3501                (7),
3502                (1226245742482522112_i64),
3503                ((
3504                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3505                    10
3506                )),
3507                (2345108766317314046_i64)
3508            ),
3509            main = Some(8),
3510        );
3511
3512        let mut hint_processor = BuiltinHintProcessor::new_empty();
3513        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3514        cairo_runner.initialize_builtins(false).unwrap();
3515        cairo_runner.initialize_segments(None);
3516
3517        cairo_runner.initialize_main_entrypoint().unwrap();
3518        cairo_runner.initialize_vm().unwrap();
3519
3520        // Full takes 10 steps.
3521        assert_matches!(cairo_runner.run_until_steps(8, &mut hint_processor), Ok(()));
3522        assert_matches!(
3523            cairo_runner.run_until_steps(10, &mut hint_processor),
3524            Ok(())
3525        );
3526        assert_matches!(
3527            cairo_runner.run_until_steps(11, &mut hint_processor),
3528            Err(VirtualMachineError::EndOfProgram(1))
3529        );
3530    }
3531
3532    #[test]
3533    /*Program used:
3534    %builtins range_check
3535
3536    func check_range{range_check_ptr}(num):
3537        # Check that 0 <= num < 2**64.
3538        [range_check_ptr] = num
3539        assert [range_check_ptr + 1] = 2 ** 64 - 1 - num
3540        let range_check_ptr = range_check_ptr + 2
3541        return()
3542    end
3543
3544    func main{range_check_ptr}():
3545        check_range(7)
3546        return()
3547    end
3548
3549    main = 8
3550    data = [4612671182993129469, 5189976364521848832, 18446744073709551615, 5199546496550207487, 4612389712311386111, 5198983563776393216, 2, 2345108766317314046, 5191102247248822272, 5189976364521848832, 7, 1226245742482522112, 3618502788666131213697322783095070105623107215331596699973092056135872020470, 2345108766317314046]
3551    */
3552    /// Verify that run_until_next_power_2() executes steps until the current
3553    /// step reaches a power of two, or an error occurs.
3554    fn run_until_next_power_of_2() {
3555        let program = program!(
3556            builtins = vec![BuiltinName::range_check],
3557            data = vec_data!(
3558                (4612671182993129469_i64),
3559                (5189976364521848832_i64),
3560                (18446744073709551615_i128),
3561                (5199546496550207487_i64),
3562                (4612389712311386111_i64),
3563                (5198983563776393216_i64),
3564                (2),
3565                (2345108766317314046_i64),
3566                (5191102247248822272_i64),
3567                (5189976364521848832_i64),
3568                (7),
3569                (1226245742482522112_i64),
3570                ((
3571                    "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3572                    10
3573                )),
3574                (2345108766317314046_i64)
3575            ),
3576            main = Some(8),
3577        );
3578
3579        let mut hint_processor = BuiltinHintProcessor::new_empty();
3580        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3581        cairo_runner.initialize_builtins(false).unwrap();
3582        cairo_runner.initialize_segments(None);
3583
3584        cairo_runner.initialize_main_entrypoint().unwrap();
3585        cairo_runner.initialize_vm().unwrap();
3586
3587        // Full takes 10 steps.
3588        assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3589        assert_matches!(
3590            cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3591            Ok(())
3592        );
3593        assert_eq!(cairo_runner.vm.current_step, 1);
3594
3595        assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3596        assert_matches!(
3597            cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3598            Ok(())
3599        );
3600        assert_eq!(cairo_runner.vm.current_step, 2);
3601
3602        assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3603        assert_matches!(
3604            cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3605            Ok(())
3606        );
3607        assert_eq!(cairo_runner.vm.current_step, 4);
3608
3609        assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3610        assert_matches!(
3611            cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3612            Ok(())
3613        );
3614        assert_eq!(cairo_runner.vm.current_step, 8);
3615
3616        assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3617        assert_matches!(
3618            cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3619            Err(VirtualMachineError::EndOfProgram(6))
3620        );
3621        assert_eq!(cairo_runner.vm.current_step, 10);
3622    }
3623
3624    #[test]
3625    fn get_constants() {
3626        let program_constants = HashMap::from([
3627            ("MAX".to_string(), Felt252::from(300)),
3628            ("MIN".to_string(), Felt252::from(20)),
3629        ]);
3630        let program = program!(constants = program_constants.clone(),);
3631        let cairo_runner = cairo_runner!(program);
3632        assert_eq!(cairo_runner.get_constants(), &program_constants);
3633    }
3634
3635    #[test]
3636    fn get_memory_holes_missing_segment_used_sizes() {
3637        let program = program!();
3638
3639        let mut cairo_runner = cairo_runner!(program);
3640        // Add element into memory and mark it as accessed so that get_memory_holes tries to access a segment size
3641        cairo_runner.vm.segments.memory = memory![((0, 0), 9)];
3642        cairo_runner
3643            .vm
3644            .segments
3645            .memory
3646            .mark_as_accessed((0, 0).into());
3647
3648        cairo_runner.vm.builtin_runners = Vec::new();
3649        assert_eq!(
3650            cairo_runner.get_memory_holes(),
3651            Err(MemoryError::MissingSegmentUsedSizes),
3652        );
3653    }
3654
3655    #[test]
3656    fn get_memory_holes_empty() {
3657        let program = program!();
3658
3659        let mut cairo_runner = cairo_runner!(program);
3660
3661        cairo_runner.vm.builtin_runners = Vec::new();
3662        cairo_runner.vm.segments.segment_used_sizes = Some(Vec::new());
3663        assert_eq!(cairo_runner.get_memory_holes(), Ok(0));
3664    }
3665
3666    #[test]
3667    fn get_memory_holes_empty_builtins() {
3668        let program = program!();
3669
3670        let mut cairo_runner = cairo_runner!(program);
3671        cairo_runner.vm.segments.memory = memory![((0, 0), 0), ((0, 2), 0)];
3672        cairo_runner
3673            .vm
3674            .segments
3675            .memory
3676            .mark_as_accessed((0, 0).into());
3677        cairo_runner
3678            .vm
3679            .segments
3680            .memory
3681            .mark_as_accessed((0, 2).into());
3682        cairo_runner.vm.builtin_runners = Vec::new();
3683        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3684        assert_eq!(cairo_runner.get_memory_holes(), Ok(2));
3685    }
3686
3687    #[test]
3688    fn get_memory_holes_empty_accesses() {
3689        let program = program!();
3690
3691        let mut cairo_runner = cairo_runner!(program);
3692
3693        cairo_runner.vm.builtin_runners = vec![{
3694            let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
3695            builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
3696
3697            builtin_runner
3698        }];
3699        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3700        assert_eq!(cairo_runner.get_memory_holes(), Ok(0));
3701    }
3702
3703    #[test]
3704    fn get_memory_holes() {
3705        let program = program!();
3706
3707        let mut cairo_runner = cairo_runner!(program);
3708        cairo_runner.vm.segments.memory = memory![((1, 0), 0), ((1, 2), 2)];
3709        cairo_runner
3710            .vm
3711            .segments
3712            .memory
3713            .mark_as_accessed((1, 0).into());
3714        cairo_runner
3715            .vm
3716            .segments
3717            .memory
3718            .mark_as_accessed((1, 2).into());
3719        cairo_runner.vm.builtin_runners = vec![{
3720            let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
3721            builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
3722
3723            builtin_runner
3724        }];
3725        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4, 4]);
3726        assert_eq!(cairo_runner.get_memory_holes(), Ok(2));
3727    }
3728
3729    /// Test that check_diluted_check_usage() works without a diluted pool
3730    /// instance.
3731    #[test]
3732    fn check_diluted_check_usage_without_pool_instance() {
3733        let program = program!();
3734
3735        let mut cairo_runner = cairo_runner!(program);
3736
3737        cairo_runner.layout.diluted_pool_instance_def = None;
3738        assert_matches!(cairo_runner.check_diluted_check_usage(), Ok(()));
3739    }
3740
3741    /// Test that check_diluted_check_usage() works without builtin runners.
3742    #[test]
3743    fn check_diluted_check_usage_without_builtin_runners() {
3744        let program = program!();
3745
3746        let mut cairo_runner = cairo_runner!(program);
3747
3748        cairo_runner.vm.current_step = 10000;
3749        cairo_runner.vm.builtin_runners = vec![];
3750        assert_matches!(cairo_runner.check_diluted_check_usage(), Ok(()));
3751    }
3752
3753    /// Test that check_diluted_check_usage() fails when there aren't enough
3754    /// allocated units.
3755    #[test]
3756    fn check_diluted_check_usage_insufficient_allocated_cells() {
3757        let program = program!();
3758
3759        let mut cairo_runner = cairo_runner!(program);
3760
3761        cairo_runner.vm.current_step = 100;
3762        cairo_runner.vm.builtin_runners = vec![];
3763        assert_matches!(
3764            cairo_runner.check_diluted_check_usage(),
3765            Err(VirtualMachineError::Memory(
3766                MemoryError::InsufficientAllocatedCells(_)
3767            ))
3768        );
3769    }
3770
3771    /// Test that check_diluted_check_usage() succeeds when all the conditions
3772    /// are met.
3773    #[test]
3774    fn check_diluted_check_usage() {
3775        let program = program!();
3776
3777        let mut cairo_runner = cairo_runner!(program);
3778
3779        cairo_runner.vm.current_step = 8192;
3780        cairo_runner.vm.builtin_runners = vec![BitwiseBuiltinRunner::new(Some(256), true).into()];
3781        assert_matches!(cairo_runner.check_diluted_check_usage(), Ok(()));
3782    }
3783
3784    #[test]
3785    fn end_run_run_already_finished() {
3786        let program = program!();
3787
3788        let mut hint_processor = BuiltinHintProcessor::new_empty();
3789        let mut cairo_runner = cairo_runner!(program);
3790
3791        cairo_runner.run_ended = true;
3792        assert_matches!(
3793            cairo_runner.end_run(true, false, &mut hint_processor, false),
3794            Err(VirtualMachineError::RunnerError(
3795                RunnerError::EndRunCalledTwice
3796            ))
3797        );
3798    }
3799
3800    #[test]
3801    fn end_run() {
3802        let program = program!();
3803
3804        let mut hint_processor = BuiltinHintProcessor::new_empty();
3805        let mut cairo_runner = cairo_runner!(program);
3806
3807        assert_matches!(
3808            cairo_runner.end_run(true, false, &mut hint_processor, false),
3809            Ok(())
3810        );
3811
3812        cairo_runner.run_ended = false;
3813        cairo_runner.relocated_memory.clear();
3814        assert_matches!(
3815            cairo_runner.end_run(true, true, &mut hint_processor, false),
3816            Ok(())
3817        );
3818        assert!(!cairo_runner.run_ended);
3819    }
3820
3821    #[test]
3822    fn end_run_proof_mode_insufficient_allocated_cells() {
3823        let program = Program::from_bytes(
3824            include_bytes!("../../../../cairo_programs/proof_programs/fibonacci.json"),
3825            Some("main"),
3826        )
3827        .unwrap();
3828        let proof_mode = true;
3829        let mut hint_processor = BuiltinHintProcessor::new_empty();
3830        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, proof_mode, true);
3831
3832        let end = cairo_runner.initialize(false).unwrap();
3833        cairo_runner
3834            .run_until_pc(end, &mut hint_processor)
3835            .expect("Call to `CairoRunner::run_until_pc()` failed.");
3836        assert_matches!(
3837            cairo_runner.end_run(false, false, &mut hint_processor, proof_mode),
3838            Ok(())
3839        );
3840    }
3841
3842    #[test]
3843    fn get_builtin_segments_info_empty() {
3844        let program = program!();
3845
3846        let cairo_runner = cairo_runner!(program);
3847
3848        assert_eq!(cairo_runner.get_builtin_segments_info(), Ok(Vec::new()),);
3849    }
3850
3851    #[test]
3852    fn get_builtin_segments_info_base_not_finished() {
3853        let program = program!();
3854
3855        let mut cairo_runner = cairo_runner!(program);
3856
3857        cairo_runner.vm.builtin_runners =
3858            vec![BuiltinRunner::Output(OutputBuiltinRunner::new(true))];
3859        assert_eq!(
3860            cairo_runner.get_builtin_segments_info(),
3861            Err(RunnerError::NoStopPointer(Box::new(BuiltinName::output))),
3862        );
3863    }
3864
3865    #[test]
3866    fn get_builtin_segments_info_non_proof_mode() {
3867        let program_data =
3868            include_bytes!("../../../../cairo_programs/proof_programs/assert_nn.json");
3869        let cairo_run_config = CairoRunConfig {
3870            entrypoint: "main",
3871            trace_enabled: false,
3872            relocate_mem: false,
3873            layout: LayoutName::small,
3874            proof_mode: false,
3875            fill_holes: false,
3876            secure_run: Some(true),
3877            ..Default::default()
3878        };
3879        let mut hint_executor = BuiltinHintProcessor::new_empty();
3880        let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
3881        // Only the range_check builtin is used in this program, and in non-proof mode, it will
3882        // be the first and only builtin segment initialized (and used).
3883        assert_eq!(runner.get_builtin_segments_info(), Ok(vec![(2, 6)]));
3884    }
3885
3886    #[test]
3887    fn get_builtin_segments_info_proof_mode() {
3888        let program_data =
3889            include_bytes!("../../../../cairo_programs/proof_programs/assert_nn.json");
3890        let cairo_run_config = CairoRunConfig {
3891            entrypoint: "main",
3892            trace_enabled: false,
3893            relocate_mem: false,
3894            layout: LayoutName::small,
3895            proof_mode: true,
3896            fill_holes: true,
3897            secure_run: Some(true),
3898            ..Default::default()
3899        };
3900        let mut hint_executor = BuiltinHintProcessor::new_empty();
3901        let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
3902        // Only the range_check builtin is used in this program, and in proof mode, it will
3903        // be the first and only builtin segment used, but initialized after the other builtins
3904        // in the layout.
3905        assert_eq!(runner.get_builtin_segments_info(), Ok(vec![(4, 6)]));
3906    }
3907
3908    #[test]
3909    fn get_execution_resources_trace_not_enabled() {
3910        let program = program!();
3911
3912        let mut cairo_runner = cairo_runner!(program);
3913
3914        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3915        cairo_runner.vm.current_step = 10;
3916        assert_eq!(
3917            cairo_runner.get_execution_resources(),
3918            Ok(ExecutionResources {
3919                n_steps: 10,
3920                n_memory_holes: 0,
3921                builtin_instance_counter: BTreeMap::new(),
3922            }),
3923        );
3924    }
3925
3926    #[test]
3927    fn get_execution_resources_run_program() {
3928        let program_data = include_bytes!("../../../../cairo_programs/fibonacci.json");
3929        let cairo_run_config = CairoRunConfig {
3930            entrypoint: "main",
3931            trace_enabled: true,
3932            relocate_mem: false,
3933            layout: LayoutName::all_cairo,
3934            proof_mode: false,
3935            fill_holes: false,
3936            secure_run: Some(false),
3937            ..Default::default()
3938        };
3939        let mut hint_executor = BuiltinHintProcessor::new_empty();
3940        let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
3941        assert_eq!(runner.get_execution_resources().unwrap().n_steps, 80);
3942    }
3943
3944    #[test]
3945    fn get_execution_resources_run_program_no_trace() {
3946        let program_data = include_bytes!("../../../../cairo_programs/fibonacci.json");
3947        let cairo_run_config = CairoRunConfig {
3948            entrypoint: "main",
3949            trace_enabled: false,
3950            relocate_mem: false,
3951            layout: LayoutName::all_cairo,
3952            proof_mode: false,
3953            fill_holes: false,
3954            secure_run: Some(false),
3955            ..Default::default()
3956        };
3957        let mut hint_executor = BuiltinHintProcessor::new_empty();
3958        let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
3959        assert_eq!(runner.get_execution_resources().unwrap().n_steps, 80);
3960    }
3961
3962    #[test]
3963    fn get_execution_resources_empty_builtins() {
3964        let program = program!();
3965
3966        let mut cairo_runner = cairo_runner!(program);
3967
3968        cairo_runner.vm.current_step = 10;
3969        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3970        assert_eq!(
3971            cairo_runner.get_execution_resources(),
3972            Ok(ExecutionResources {
3973                n_steps: 10,
3974                n_memory_holes: 0,
3975                builtin_instance_counter: BTreeMap::new(),
3976            }),
3977        );
3978    }
3979
3980    #[test]
3981    fn get_execution_resources() {
3982        let program = program!();
3983
3984        let mut cairo_runner = cairo_runner!(program);
3985
3986        cairo_runner.vm.current_step = 10;
3987        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3988        cairo_runner.vm.builtin_runners = vec![{
3989            let mut builtin = OutputBuiltinRunner::new(true);
3990            builtin.initialize_segments(&mut cairo_runner.vm.segments);
3991
3992            BuiltinRunner::Output(builtin)
3993        }];
3994        assert_eq!(
3995            cairo_runner.get_execution_resources(),
3996            Ok(ExecutionResources {
3997                n_steps: 10,
3998                n_memory_holes: 0,
3999                builtin_instance_counter: BTreeMap::from([(BuiltinName::output, 4)]),
4000            }),
4001        );
4002    }
4003
4004    #[test]
4005    fn get_blake_extended_execution_resources() {
4006        let program_data = include_bytes!(
4007            "../../../../cairo_programs/stwo_exclusive_programs/blake2s_opcode_test.json"
4008        );
4009        let cairo_run_config = CairoRunConfig {
4010            entrypoint: "main",
4011            trace_enabled: false,
4012            relocate_mem: false,
4013            layout: LayoutName::all_cairo,
4014            proof_mode: false,
4015            fill_holes: false,
4016            secure_run: Some(false),
4017            ..Default::default()
4018        };
4019        let mut hint_executor = BuiltinHintProcessor::new_empty();
4020        let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
4021        let extended_resource_counter = runner.get_extended_execution_resources();
4022        assert_eq!(
4023            extended_resource_counter[&ExtendedExecutionResourceType::Blake],
4024            1
4025        );
4026        assert_eq!(
4027            extended_resource_counter[&ExtendedExecutionResourceType::BlakeFinalize],
4028            1
4029        );
4030    }
4031
4032    #[test]
4033    fn finalize_segments_run_not_ended() {
4034        let program = program!();
4035        let mut cairo_runner = cairo_runner!(program);
4036        assert_eq!(
4037            cairo_runner.finalize_segments(),
4038            Err(RunnerError::FinalizeNoEndRun)
4039        )
4040    }
4041
4042    #[test]
4043    fn finalize_segments_run_ended_empty_no_prog_base() {
4044        let program = program!();
4045        let mut cairo_runner = cairo_runner!(program);
4046        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4047        cairo_runner.run_ended = true;
4048        assert_eq!(
4049            cairo_runner.finalize_segments(),
4050            Err(RunnerError::NoProgBase)
4051        )
4052    }
4053
4054    #[test]
4055    fn finalize_segments_run_ended_empty_no_exec_base() {
4056        let program = program!();
4057        let mut cairo_runner = cairo_runner!(program);
4058        cairo_runner.runner_mode = RunnerMode::ProofModeCanonical;
4059        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4060        cairo_runner.run_ended = true;
4061        assert_eq!(
4062            cairo_runner.finalize_segments(),
4063            Err(RunnerError::NoExecBase)
4064        )
4065    }
4066
4067    #[test]
4068    fn finalize_segments_run_ended_empty_noproof_mode() {
4069        let program = program!();
4070        let mut cairo_runner = cairo_runner!(program);
4071        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4072        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4073        cairo_runner.run_ended = true;
4074        assert_eq!(
4075            cairo_runner.finalize_segments(),
4076            Err(RunnerError::FinalizeSegmentsNoProofMode)
4077        )
4078    }
4079
4080    #[test]
4081    fn finalize_segments_run_ended_emptyproof_mode() {
4082        let program = program!();
4083        let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4084        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4085        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4086        cairo_runner.run_ended = true;
4087        assert_eq!(cairo_runner.finalize_segments(), Ok(()));
4088        assert!(cairo_runner.segments_finalized);
4089        assert!(cairo_runner.execution_public_memory.unwrap().is_empty())
4090    }
4091
4092    #[test]
4093    fn finalize_segments_run_ended_not_emptyproof_mode_empty_execution_public_memory() {
4094        let mut program = program!();
4095        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4096            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4097        //Program data len = 8
4098        let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4099        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4100        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4101        cairo_runner.run_ended = true;
4102        assert_eq!(cairo_runner.finalize_segments(), Ok(()));
4103        assert!(cairo_runner.segments_finalized);
4104        //Check values written by first call to segments.finalize()
4105        assert_eq!(
4106            cairo_runner.vm.segments.segment_sizes.get(&0),
4107            Some(&8_usize)
4108        );
4109        assert_eq!(
4110            cairo_runner.vm.segments.public_memory_offsets.get(&0),
4111            Some(&vec![
4112                (0_usize, 0_usize),
4113                (1_usize, 0_usize),
4114                (2_usize, 0_usize),
4115                (3_usize, 0_usize),
4116                (4_usize, 0_usize),
4117                (5_usize, 0_usize),
4118                (6_usize, 0_usize),
4119                (7_usize, 0_usize)
4120            ])
4121        );
4122        //Check values written by second call to segments.finalize()
4123        assert_eq!(cairo_runner.vm.segments.segment_sizes.get(&1), None);
4124        assert_eq!(
4125            cairo_runner.vm.segments.public_memory_offsets.get(&1),
4126            Some(&vec![])
4127        );
4128    }
4129
4130    #[test]
4131    fn finalize_segments_run_ended_not_emptyproof_mode_with_execution_public_memory() {
4132        let mut program = program!();
4133        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4134            vec_data![(1), (2), (3), (4)];
4135        //Program data len = 4
4136        let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4137        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4138        cairo_runner.execution_base = Some(Relocatable::from((1, 1)));
4139        cairo_runner.execution_public_memory = Some(vec![1_usize, 3_usize, 5_usize, 4_usize]);
4140        cairo_runner.run_ended = true;
4141        assert_eq!(cairo_runner.finalize_segments(), Ok(()));
4142        assert!(cairo_runner.segments_finalized);
4143        //Check values written by first call to segments.finalize()
4144        assert_eq!(
4145            cairo_runner.vm.segments.segment_sizes.get(&0),
4146            Some(&4_usize)
4147        );
4148        assert_eq!(
4149            cairo_runner.vm.segments.public_memory_offsets.get(&0),
4150            Some(&vec![
4151                (0_usize, 0_usize),
4152                (1_usize, 0_usize),
4153                (2_usize, 0_usize),
4154                (3_usize, 0_usize)
4155            ])
4156        );
4157        //Check values written by second call to segments.finalize()
4158        assert_eq!(cairo_runner.vm.segments.segment_sizes.get(&1), None);
4159        assert_eq!(
4160            cairo_runner.vm.segments.public_memory_offsets.get(&1),
4161            Some(&vec![
4162                (2_usize, 0_usize),
4163                (4_usize, 0_usize),
4164                (6_usize, 0_usize),
4165                (5_usize, 0_usize)
4166            ])
4167        );
4168    }
4169
4170    /// Test that get_perm_range_check_limits() works correctly when there are
4171    /// no builtins.
4172    #[test]
4173    fn get_perm_range_check_limits_no_builtins() {
4174        let program = program!();
4175        let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::default());
4176
4177        let mut cairo_runner = cairo_runner!(program);
4178
4179        cairo_runner.vm.segments.memory.data = vec![
4180            vec![
4181                MemoryCell::new(Felt252::from(0x8000_8023_8012u64).into()),
4182                MemoryCell::new(Felt252::from(0xBFFF_8000_0620u64).into()),
4183                MemoryCell::new(Felt252::from(0x8FFF_8000_0750u64).into()),
4184            ],
4185            vec![MemoryCell::new((0isize, 0usize).into()); 128 * 1024],
4186        ];
4187
4188        cairo_runner.run_for_steps(1, &mut hint_processor).unwrap();
4189
4190        assert_matches!(
4191            cairo_runner.get_perm_range_check_limits(),
4192            Some((32768, 32803))
4193        );
4194    }
4195
4196    /// Test that get_perm_range_check_limits() works correctly when there are
4197    /// builtins.
4198    #[test]
4199    fn get_perm_range_check_limits() {
4200        let program = program!();
4201
4202        let mut cairo_runner = cairo_runner!(program);
4203
4204        cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4205            0x80FF_8000_0530u64
4206        ))]];
4207        cairo_runner.vm.builtin_runners =
4208            vec![RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(12), true).into()];
4209
4210        assert_matches!(cairo_runner.get_perm_range_check_limits(), Some((0, 33023)));
4211    }
4212
4213    /// Test that check_range_check_usage() returns successfully when trace is
4214    /// not enabled.
4215    #[test]
4216    fn check_range_check_usage_perm_range_limits_none() {
4217        let program = program!();
4218
4219        let mut cairo_runner = cairo_runner!(program);
4220        cairo_runner.vm.trace = Some(vec![]);
4221
4222        assert_matches!(cairo_runner.check_range_check_usage(), Ok(()));
4223    }
4224
4225    /// Test that check_range_check_usage() returns successfully when all the
4226    /// conditions are met.
4227    #[test]
4228    fn check_range_check_usage_without_builtins() {
4229        let program = program!();
4230
4231        let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
4232        cairo_runner.vm.builtin_runners = vec![];
4233        cairo_runner.vm.current_step = 10000;
4234        cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4235            0x80FF_8000_0530u64
4236        ))]];
4237        cairo_runner.vm.trace = Some(vec![TraceEntry {
4238            pc: (0, 0).into(),
4239            ap: 0,
4240            fp: 0,
4241        }]);
4242
4243        assert_matches!(cairo_runner.check_range_check_usage(), Ok(()));
4244    }
4245
4246    /// Test that check_range_check_usage() returns an error if there are
4247    /// insufficient allocated cells.
4248    #[test]
4249    fn check_range_check_usage_insufficient_allocated_cells() {
4250        let program = program!();
4251
4252        let mut cairo_runner = cairo_runner!(program);
4253        cairo_runner.vm.builtin_runners =
4254            vec![RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true).into()];
4255        cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4256            0x80FF_8000_0530u64
4257        ))]];
4258        cairo_runner.vm.trace = Some(vec![TraceEntry {
4259            pc: (0, 0).into(),
4260            ap: 0,
4261            fp: 0,
4262        }]);
4263        cairo_runner.vm.segments.compute_effective_sizes();
4264
4265        assert_matches!(
4266            cairo_runner.check_range_check_usage(),
4267            Err(VirtualMachineError::Memory(
4268                MemoryError::InsufficientAllocatedCells(_)
4269            ))
4270        );
4271    }
4272
4273    #[test]
4274    fn get_initial_fp_is_none_without_initialization() {
4275        let program = program!();
4276
4277        let runner = cairo_runner!(program);
4278
4279        assert_eq!(None, runner.get_initial_fp());
4280    }
4281
4282    #[test]
4283    fn get_initial_fp_can_be_obtained() {
4284        let program = program![BuiltinName::output];
4285        let mut cairo_runner = cairo_runner!(program);
4286        for _ in 0..2 {
4287            cairo_runner.vm.segments.add();
4288        }
4289        cairo_runner.program_base = Some(relocatable!(0, 0));
4290        cairo_runner.execution_base = Some(relocatable!(1, 0));
4291        let return_fp = Felt252::from(9_i32).into();
4292        cairo_runner
4293            .initialize_function_entrypoint(0, vec![], return_fp)
4294            .unwrap();
4295        assert_eq!(Some(relocatable!(1, 2)), cairo_runner.get_initial_fp());
4296    }
4297
4298    #[test]
4299    fn check_used_cells_valid_case() {
4300        let program = program![BuiltinName::range_check, BuiltinName::output];
4301        let mut cairo_runner = cairo_runner!(program);
4302        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
4303        cairo_runner.vm.trace = Some(vec![]);
4304        cairo_runner.layout.diluted_pool_instance_def = None;
4305
4306        assert_matches!(cairo_runner.check_used_cells(), Ok(()));
4307    }
4308
4309    #[test]
4310    fn check_used_cells_get_used_cells_and_allocated_size_error() {
4311        let program = program!();
4312
4313        let mut cairo_runner = cairo_runner!(program);
4314        cairo_runner.vm.builtin_runners =
4315            vec![RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true).into()];
4316        cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4317            0x80FF_8000_0530u64
4318        ))]];
4319        cairo_runner.vm.trace = Some(vec![TraceEntry {
4320            pc: (0, 0).into(),
4321            ap: 0,
4322            fp: 0,
4323        }]);
4324        cairo_runner.vm.segments.compute_effective_sizes();
4325        assert_matches!(
4326            cairo_runner.check_used_cells(),
4327            Err(VirtualMachineError::Memory(
4328                MemoryError::InsufficientAllocatedCells(_)
4329            ))
4330        );
4331    }
4332
4333    #[test]
4334    fn check_used_cells_check_memory_usage_error() {
4335        let program = program!();
4336
4337        let mut cairo_runner = cairo_runner!(program);
4338        cairo_runner
4339            .vm
4340            .segments
4341            .memory
4342            .mark_as_accessed((1, 0).into());
4343        cairo_runner
4344            .vm
4345            .segments
4346            .memory
4347            .mark_as_accessed((1, 3).into());
4348        cairo_runner.vm.builtin_runners = vec![{
4349            let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
4350            builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
4351
4352            builtin_runner
4353        }];
4354        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4, 12]);
4355        cairo_runner.vm.trace = Some(vec![]);
4356
4357        assert_matches!(
4358            cairo_runner.check_used_cells(),
4359            Err(VirtualMachineError::Memory(
4360                MemoryError::InsufficientAllocatedCells(_)
4361            ))
4362        );
4363    }
4364
4365    #[test]
4366    fn check_used_cells_check_diluted_check_usage_error() {
4367        let program = program![BuiltinName::range_check, BuiltinName::output];
4368        let mut cairo_runner = cairo_runner!(program);
4369        cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
4370        cairo_runner.vm.trace = Some(vec![]);
4371
4372        assert_matches!(
4373            cairo_runner.check_used_cells(),
4374            Err(VirtualMachineError::Memory(
4375                MemoryError::InsufficientAllocatedCells(_)
4376            ))
4377        );
4378    }
4379
4380    #[test]
4381    fn initialize_all_program_builtins() {
4382        let mut program = program!();
4383
4384        // we manually add the builtins and check that they exist later
4385        program.builtins = vec![
4386            BuiltinName::pedersen,
4387            BuiltinName::range_check,
4388            BuiltinName::output,
4389            BuiltinName::ecdsa,
4390            BuiltinName::bitwise,
4391            BuiltinName::ec_op,
4392            BuiltinName::keccak,
4393            BuiltinName::poseidon,
4394        ];
4395
4396        let mut cairo_runner = cairo_runner!(program);
4397
4398        cairo_runner
4399            .initialize_program_builtins()
4400            .expect("Builtin initialization failed.");
4401
4402        let given_output = cairo_runner.vm.get_builtin_runners();
4403
4404        assert_eq!(given_output[0].name(), BuiltinName::pedersen);
4405        assert_eq!(given_output[1].name(), BuiltinName::range_check);
4406        assert_eq!(given_output[2].name(), BuiltinName::output);
4407        assert_eq!(given_output[3].name(), BuiltinName::ecdsa);
4408        assert_eq!(given_output[4].name(), BuiltinName::bitwise);
4409        assert_eq!(given_output[5].name(), BuiltinName::ec_op);
4410        assert_eq!(given_output[6].name(), BuiltinName::keccak);
4411        assert_eq!(given_output[7].name(), BuiltinName::poseidon);
4412    }
4413
4414    #[test]
4415    fn initialize_function_runner_without_builtins() {
4416        let program = program!();
4417
4418        let mut cairo_runner = cairo_runner!(program);
4419
4420        cairo_runner
4421            .initialize_function_runner()
4422            .expect("initialize_function_runner failed.");
4423
4424        assert_eq!(
4425            cairo_runner.program_base,
4426            Some(Relocatable {
4427                segment_index: 0,
4428                offset: 0,
4429            })
4430        );
4431        assert_eq!(
4432            cairo_runner.execution_base,
4433            Some(Relocatable {
4434                segment_index: 1,
4435                offset: 0,
4436            })
4437        );
4438        assert_eq!(cairo_runner.vm.segments.num_segments(), 2);
4439    }
4440
4441    #[test]
4442    fn initialize_function_runner_with_segment_arena_builtin() {
4443        let program = program!();
4444
4445        let mut cairo_runner = cairo_runner!(program);
4446
4447        cairo_runner
4448            .initialize_function_runner_cairo_1(&[BuiltinName::segment_arena])
4449            .expect("initialize_function_runner failed.");
4450
4451        let builtin_runners = cairo_runner.vm.get_builtin_runners();
4452
4453        assert_eq!(builtin_runners[0].name(), BuiltinName::segment_arena);
4454
4455        assert_eq!(
4456            cairo_runner.program_base,
4457            Some(Relocatable {
4458                segment_index: 0,
4459                offset: 0,
4460            })
4461        );
4462        assert_eq!(
4463            cairo_runner.execution_base,
4464            Some(Relocatable {
4465                segment_index: 1,
4466                offset: 0,
4467            })
4468        );
4469        // segment arena builtin adds 2 segments
4470        assert_eq!(cairo_runner.vm.segments.num_segments(), 4);
4471    }
4472
4473    #[test]
4474    fn initialize_segments_incorrect_layout_plain_one_builtin() {
4475        let program = program![BuiltinName::output];
4476        let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
4477        assert_eq!(
4478            cairo_runner.initialize_builtins(false),
4479            Err(RunnerError::NoBuiltinForInstance(Box::new((
4480                HashSet::from([BuiltinName::output]),
4481                LayoutName::plain
4482            ))))
4483        );
4484    }
4485
4486    #[test]
4487    fn initialize_segments_incorrect_layout_plain_two_builtins() {
4488        let program = program![BuiltinName::output, BuiltinName::pedersen];
4489        let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
4490        assert_eq!(
4491            cairo_runner.initialize_builtins(false),
4492            Err(RunnerError::NoBuiltinForInstance(Box::new((
4493                HashSet::from([BuiltinName::output, BuiltinName::pedersen]),
4494                LayoutName::plain
4495            ))))
4496        );
4497    }
4498
4499    #[test]
4500    fn initialize_segments_incorrect_layout_small_two_builtins() {
4501        let program = program![BuiltinName::output, BuiltinName::bitwise];
4502        let mut cairo_runner = cairo_runner!(program, LayoutName::small);
4503        assert_eq!(
4504            cairo_runner.initialize_builtins(false),
4505            Err(RunnerError::NoBuiltinForInstance(Box::new((
4506                HashSet::from([BuiltinName::bitwise]),
4507                LayoutName::small,
4508            ))))
4509        );
4510    }
4511    #[test]
4512    fn initialize_main_entrypoint_proof_mode_empty_program() {
4513        let program = program!(start = Some(0), end = Some(0), main = Some(8),);
4514        let mut runner = cairo_runner!(program);
4515        runner.runner_mode = RunnerMode::ProofModeCanonical;
4516        runner.initialize_segments(None);
4517        assert_eq!(runner.execution_base, Some(Relocatable::from((1, 0))));
4518        assert_eq!(runner.program_base, Some(Relocatable::from((0, 0))));
4519        assert_eq!(
4520            runner.initialize_main_entrypoint(),
4521            Ok(Relocatable::from((0, 0)))
4522        );
4523        assert_eq!(runner.initial_ap, Some(Relocatable::from((1, 2))));
4524        assert_eq!(runner.initial_fp, runner.initial_ap);
4525        assert_eq!(runner.execution_public_memory, Some(vec![0, 1]));
4526    }
4527
4528    #[test]
4529    fn initialize_main_entrypoint_proof_mode_empty_program_two_builtins() {
4530        let program = program!(
4531            start = Some(0),
4532            end = Some(0),
4533            main = Some(8),
4534            builtins = vec![BuiltinName::output, BuiltinName::ec_op],
4535        );
4536        let mut runner = cairo_runner!(program);
4537        runner.runner_mode = RunnerMode::ProofModeCanonical;
4538        runner.initialize_builtins(false).unwrap();
4539        runner.initialize_segments(None);
4540        assert_eq!(runner.execution_base, Some(Relocatable::from((1, 0))));
4541        assert_eq!(runner.program_base, Some(Relocatable::from((0, 0))));
4542        assert_eq!(
4543            runner.initialize_main_entrypoint(),
4544            Ok(Relocatable::from((0, 0)))
4545        );
4546        assert_eq!(runner.initial_ap, Some(Relocatable::from((1, 2))));
4547        assert_eq!(runner.initial_fp, runner.initial_ap);
4548        assert_eq!(runner.execution_public_memory, Some(vec![0, 1, 2, 3]));
4549    }
4550
4551    #[test]
4552    fn can_get_the_runner_program_builtins() {
4553        let program = program!(
4554            start = Some(0),
4555            end = Some(0),
4556            main = Some(8),
4557            builtins = vec![BuiltinName::output, BuiltinName::ec_op],
4558        );
4559        let runner = cairo_runner!(program);
4560
4561        assert_eq!(&program.builtins, runner.get_program_builtins());
4562    }
4563
4564    #[test]
4565    fn set_entrypoint_main_default() {
4566        let program = program!(
4567            identifiers = [(
4568                "__main__.main",
4569                Identifier {
4570                    pc: Some(0),
4571                    type_: None,
4572                    value: None,
4573                    full_name: None,
4574                    members: None,
4575                    cairo_type: None,
4576                    size: None,
4577                    destination: None,
4578                },
4579            )]
4580            .into_iter()
4581            .map(|(k, v)| (k.to_string(), v))
4582            .collect(),
4583        );
4584        let mut cairo_runner = cairo_runner!(program);
4585
4586        cairo_runner
4587            .set_entrypoint(None)
4588            .expect("Call to `set_entrypoint()` failed.");
4589        assert_eq!(cairo_runner.entrypoint, Some(0));
4590    }
4591
4592    #[test]
4593    fn set_entrypoint_main() {
4594        let program = program!(
4595            identifiers = [
4596                (
4597                    "__main__.main",
4598                    Identifier {
4599                        pc: Some(0),
4600                        type_: None,
4601                        value: None,
4602                        full_name: None,
4603                        members: None,
4604                        cairo_type: None,
4605                        size: None,
4606                        destination: None,
4607                    },
4608                ),
4609                (
4610                    "__main__.alternate_main",
4611                    Identifier {
4612                        pc: Some(1),
4613                        type_: None,
4614                        value: None,
4615                        full_name: None,
4616                        members: None,
4617                        cairo_type: None,
4618                        size: None,
4619                        destination: None,
4620                    },
4621                ),
4622            ]
4623            .into_iter()
4624            .map(|(k, v)| (k.to_string(), v))
4625            .collect(),
4626        );
4627        let mut cairo_runner = cairo_runner!(program);
4628
4629        cairo_runner
4630            .set_entrypoint(Some("alternate_main"))
4631            .expect("Call to `set_entrypoint()` failed.");
4632        assert_eq!(cairo_runner.entrypoint, Some(1));
4633    }
4634
4635    /// Test that set_entrypoint() fails when the entrypoint doesn't exist.
4636    #[test]
4637    fn set_entrypoint_main_non_existent() {
4638        let program = program!(
4639            identifiers = [(
4640                "__main__.main",
4641                Identifier {
4642                    pc: Some(0),
4643                    type_: None,
4644                    value: None,
4645                    full_name: None,
4646                    members: None,
4647                    cairo_type: None,
4648                    size: None,
4649                    destination: None,
4650                },
4651            )]
4652            .into_iter()
4653            .map(|(k, v)| (k.to_string(), v))
4654            .collect(),
4655        );
4656        let mut cairo_runner = cairo_runner!(program);
4657
4658        cairo_runner
4659            .set_entrypoint(Some("nonexistent_main"))
4660            .expect_err("Call to `set_entrypoint()` succeeded (should've failed).");
4661        assert_eq!(cairo_runner.entrypoint, None);
4662    }
4663
4664    #[test]
4665    fn read_return_values_test() {
4666        let mut program = program!();
4667        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4668            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4669        //Program data len = 8
4670        let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4671        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4672        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4673        cairo_runner.run_ended = true;
4674        cairo_runner.segments_finalized = false;
4675        //Check values written by first call to segments.finalize()
4676
4677        assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4678        assert_eq!(
4679            cairo_runner
4680                .execution_public_memory
4681                .expect("missing execution public memory"),
4682            Vec::<usize>::new()
4683        );
4684    }
4685
4686    #[test]
4687    fn read_return_values_test_with_run_not_ended() {
4688        let mut program = program!();
4689        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4690            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4691        //Program data len = 8
4692        let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4693        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4694        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4695        cairo_runner.run_ended = false;
4696        assert_eq!(
4697            cairo_runner.read_return_values(false),
4698            Err(RunnerError::ReadReturnValuesNoEndRun)
4699        );
4700    }
4701
4702    #[test]
4703    fn read_return_values_test_with_segments_finalized() {
4704        let mut program = program!();
4705        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4706            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4707        //Program data len = 8
4708        let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4709        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4710        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4711        cairo_runner.run_ended = true;
4712        cairo_runner.segments_finalized = true;
4713        assert_eq!(
4714            cairo_runner.read_return_values(false),
4715            Err(RunnerError::FailedAddingReturnValues)
4716        );
4717    }
4718
4719    #[test]
4720    fn read_return_values_updates_builtin_stop_ptr_one_builtin_empty() {
4721        let mut program = program![BuiltinName::output];
4722        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4723            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4724        //Program data len = 8
4725        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true);
4726        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4727        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4728        cairo_runner.run_ended = true;
4729        cairo_runner.segments_finalized = false;
4730        let output_builtin = OutputBuiltinRunner::new(true);
4731        cairo_runner.vm.builtin_runners.push(output_builtin.into());
4732        cairo_runner.vm.segments.memory.data = vec![
4733            vec![],
4734            vec![MemoryCell::new(MaybeRelocatable::from((0, 0)))],
4735            vec![],
4736        ];
4737        cairo_runner.vm.set_ap(1);
4738        cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 1, 0]);
4739        //Check values written by first call to segments.finalize()
4740        assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4741        let output_builtin = match &cairo_runner.vm.builtin_runners[0] {
4742            BuiltinRunner::Output(runner) => runner,
4743            _ => unreachable!(),
4744        };
4745        assert_eq!(output_builtin.stop_ptr, Some(0))
4746    }
4747
4748    #[test]
4749    fn read_return_values_updates_builtin_stop_ptr_one_builtin_one_element() {
4750        let mut program = program![BuiltinName::output];
4751        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4752            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4753        //Program data len = 8
4754        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true);
4755        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4756        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4757        cairo_runner.run_ended = true;
4758        cairo_runner.segments_finalized = false;
4759        let output_builtin = OutputBuiltinRunner::new(true);
4760        cairo_runner.vm.builtin_runners.push(output_builtin.into());
4761        cairo_runner.vm.segments.memory.data = vec![
4762            vec![MemoryCell::new(MaybeRelocatable::from((0, 0)))],
4763            vec![MemoryCell::new(MaybeRelocatable::from((0, 1)))],
4764            vec![],
4765        ];
4766        cairo_runner.vm.set_ap(1);
4767        cairo_runner.vm.segments.segment_used_sizes = Some(vec![1, 1, 0]);
4768        //Check values written by first call to segments.finalize()
4769        assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4770        let output_builtin = match &cairo_runner.vm.builtin_runners[0] {
4771            BuiltinRunner::Output(runner) => runner,
4772            _ => unreachable!(),
4773        };
4774        assert_eq!(output_builtin.stop_ptr, Some(1))
4775    }
4776
4777    #[test]
4778    fn read_return_values_updates_builtin_stop_ptr_two_builtins() {
4779        let mut program = program![BuiltinName::output, BuiltinName::bitwise];
4780        Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4781            vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4782        //Program data len = 8
4783        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true);
4784        cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4785        cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4786        cairo_runner.run_ended = true;
4787        cairo_runner.segments_finalized = false;
4788        let output_builtin = OutputBuiltinRunner::new(true);
4789        let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true);
4790        cairo_runner.vm.builtin_runners.push(output_builtin.into());
4791        cairo_runner.vm.builtin_runners.push(bitwise_builtin.into());
4792        cairo_runner.initialize_segments(None);
4793        cairo_runner.vm.segments.memory.data = vec![
4794            vec![MemoryCell::new(MaybeRelocatable::from((0, 0)))],
4795            vec![
4796                MemoryCell::new(MaybeRelocatable::from((2, 0))),
4797                MemoryCell::new(MaybeRelocatable::from((3, 5))),
4798            ],
4799            vec![],
4800        ];
4801        cairo_runner.vm.set_ap(2);
4802        // We use 5 as bitwise builtin's segment size as a bitwise instance is 5 cells
4803        cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 2, 0, 5]);
4804        //Check values written by first call to segments.finalize()
4805        assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4806        let output_builtin = match &cairo_runner.vm.builtin_runners[0] {
4807            BuiltinRunner::Output(runner) => runner,
4808            _ => unreachable!(),
4809        };
4810        assert_eq!(output_builtin.stop_ptr, Some(0));
4811        assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4812        let bitwise_builtin = match &cairo_runner.vm.builtin_runners[1] {
4813            BuiltinRunner::Bitwise(runner) => runner,
4814            _ => unreachable!(),
4815        };
4816        assert_eq!(bitwise_builtin.stop_ptr, Some(5));
4817    }
4818
4819    #[test]
4820    fn run_from_entrypoint_custom_program_test() {
4821        let program = Program::from_bytes(
4822            include_bytes!("../../../../cairo_programs/example_program.json"),
4823            None,
4824        )
4825        .unwrap();
4826        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
4827        let mut hint_processor = BuiltinHintProcessor::new_empty();
4828
4829        //this entrypoint tells which function to run in the cairo program
4830        let main_entrypoint = program
4831            .shared_program_data
4832            .identifiers
4833            .get("__main__.main")
4834            .unwrap()
4835            .pc
4836            .unwrap();
4837
4838        cairo_runner.initialize_builtins(false).unwrap();
4839        cairo_runner.initialize_segments(None);
4840        assert_matches!(
4841            cairo_runner.run_from_entrypoint(
4842                main_entrypoint,
4843                &[
4844                    &mayberelocatable!(2).into(),
4845                    &MaybeRelocatable::from((2, 0)).into()
4846                ], //range_check_ptr
4847                true,
4848                None,
4849                &mut hint_processor,
4850            ),
4851            Ok(())
4852        );
4853
4854        let mut new_cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
4855        let mut hint_processor = BuiltinHintProcessor::new_empty();
4856
4857        new_cairo_runner.initialize_builtins(false).unwrap();
4858        new_cairo_runner.initialize_segments(None);
4859
4860        let fib_entrypoint = program
4861            .shared_program_data
4862            .identifiers
4863            .get("__main__.evaluate_fib")
4864            .unwrap()
4865            .pc
4866            .unwrap();
4867
4868        assert_matches!(
4869            new_cairo_runner.run_from_entrypoint(
4870                fib_entrypoint,
4871                &[
4872                    &mayberelocatable!(2).into(),
4873                    &MaybeRelocatable::from((2, 0)).into()
4874                ],
4875                true,
4876                None,
4877                &mut hint_processor,
4878            ),
4879            Ok(())
4880        );
4881    }
4882
4883    #[test]
4884    fn run_from_entrypoint_bitwise_test_check_memory_holes() {
4885        let program = Program::from_bytes(
4886            include_bytes!("../../../../cairo_programs/bitwise_builtin_test.json"),
4887            None,
4888        )
4889        .unwrap();
4890        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
4891        let mut hint_processor = BuiltinHintProcessor::new_empty();
4892
4893        //this entrypoint tells which function to run in the cairo program
4894        let main_entrypoint = program
4895            .shared_program_data
4896            .identifiers
4897            .get("__main__.main")
4898            .unwrap()
4899            .pc
4900            .unwrap();
4901
4902        cairo_runner.initialize_function_runner().unwrap();
4903
4904        assert!(cairo_runner
4905            .run_from_entrypoint(
4906                main_entrypoint,
4907                &[
4908                    &MaybeRelocatable::from((2, 0)).into() //bitwise_ptr
4909                ],
4910                true,
4911                None,
4912                &mut hint_processor,
4913            )
4914            .is_ok());
4915
4916        // Check that memory_holes == 0
4917        assert!(cairo_runner.get_memory_holes().unwrap().is_zero());
4918    }
4919
4920    #[test]
4921    fn cairo_arg_from_single() {
4922        let expected = CairoArg::Single(MaybeRelocatable::from((0, 0)));
4923        let value = MaybeRelocatable::from((0, 0));
4924        assert_eq!(expected, value.into())
4925    }
4926
4927    #[test]
4928    fn cairo_arg_from_array() {
4929        let expected = CairoArg::Array(vec![MaybeRelocatable::from((0, 0))]);
4930        let value = vec![MaybeRelocatable::from((0, 0))];
4931        assert_eq!(expected, value.into())
4932    }
4933
4934    fn setup_execution_resources() -> (ExecutionResources, ExecutionResources) {
4935        let mut builtin_instance_counter: BTreeMap<BuiltinName, usize> = BTreeMap::new();
4936        builtin_instance_counter.insert(BuiltinName::output, 8);
4937
4938        let execution_resources_1 = ExecutionResources {
4939            n_steps: 100,
4940            n_memory_holes: 5,
4941            builtin_instance_counter: builtin_instance_counter.clone(),
4942        };
4943
4944        //Test that the combined Execution Resources only contains the shared builtins
4945        builtin_instance_counter.insert(BuiltinName::range_check, 8);
4946
4947        let execution_resources_2 = ExecutionResources {
4948            n_steps: 100,
4949            n_memory_holes: 5,
4950            builtin_instance_counter,
4951        };
4952
4953        (execution_resources_1, execution_resources_2)
4954    }
4955
4956    #[test]
4957    fn execution_resources_add() {
4958        let (execution_resources_1, execution_resources_2) = setup_execution_resources();
4959        let combined_resources = &execution_resources_1 + &execution_resources_2;
4960
4961        assert_eq!(combined_resources.n_steps, 200);
4962        assert_eq!(combined_resources.n_memory_holes, 10);
4963        assert_eq!(
4964            combined_resources
4965                .builtin_instance_counter
4966                .get(&BuiltinName::output)
4967                .unwrap(),
4968            &16
4969        );
4970        assert!(combined_resources
4971            .builtin_instance_counter
4972            .contains_key(&BuiltinName::range_check));
4973    }
4974
4975    #[test]
4976    fn execution_resources_sub() {
4977        let (execution_resources_1, execution_resources_2) = setup_execution_resources();
4978
4979        let combined_resources = &execution_resources_1 - &execution_resources_2;
4980
4981        assert_eq!(combined_resources.n_steps, 0);
4982        assert_eq!(combined_resources.n_memory_holes, 0);
4983        assert_eq!(
4984            combined_resources
4985                .builtin_instance_counter
4986                .get(&BuiltinName::output)
4987                .unwrap(),
4988            &0
4989        );
4990        assert!(combined_resources
4991            .builtin_instance_counter
4992            .contains_key(&BuiltinName::range_check));
4993    }
4994
4995    #[test]
4996    fn run_from_entrypoint_substitute_error_message_test() {
4997        let program = Program::from_bytes(
4998            include_bytes!("../../../../cairo_programs/bad_programs/error_msg_function.json"),
4999            None,
5000        )
5001        .unwrap();
5002        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
5003        let mut hint_processor = BuiltinHintProcessor::new_empty();
5004
5005        //this entrypoint tells which function to run in the cairo program
5006        let main_entrypoint = program
5007            .shared_program_data
5008            .identifiers
5009            .get("__main__.main")
5010            .unwrap()
5011            .pc
5012            .unwrap();
5013
5014        cairo_runner.initialize_builtins(false).unwrap();
5015        cairo_runner.initialize_segments(None);
5016
5017        let result =
5018            cairo_runner.run_from_entrypoint(main_entrypoint, &[], true, None, &mut hint_processor);
5019        match result {
5020            Err(CairoRunError::VmException(exception)) => {
5021                assert_eq!(
5022                    exception.error_attr_value,
5023                    Some(String::from("Error message: Test error\n"))
5024                )
5025            }
5026            Err(_) => panic!("Wrong error returned, expected VmException"),
5027            Ok(_) => panic!("Expected run to fail"),
5028        }
5029    }
5030
5031    #[test]
5032    fn get_builtins_final_stack_range_check_builtin() {
5033        let program = Program::from_bytes(
5034            include_bytes!("../../../../cairo_programs/assert_le_felt_hint.json"),
5035            Some("main"),
5036        )
5037        .unwrap();
5038        let mut runner = cairo_runner!(program);
5039        let end = runner.initialize(false).unwrap();
5040        runner
5041            .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5042            .unwrap();
5043        runner.vm.segments.compute_effective_sizes();
5044        let initial_pointer = runner.vm.get_ap();
5045        let expected_pointer = (runner.vm.get_ap() - 1).unwrap();
5046        assert_eq!(
5047            runner.get_builtins_final_stack(initial_pointer),
5048            Ok(expected_pointer)
5049        );
5050    }
5051
5052    #[test]
5053    fn get_builtins_final_stack_4_builtins() {
5054        let program = Program::from_bytes(
5055            include_bytes!("../../../../cairo_programs/integration.json"),
5056            Some("main"),
5057        )
5058        .unwrap();
5059        let mut runner = cairo_runner!(program);
5060        let end = runner.initialize(false).unwrap();
5061        runner
5062            .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5063            .unwrap();
5064        runner.vm.segments.compute_effective_sizes();
5065        let initial_pointer = runner.vm.get_ap();
5066        let expected_pointer = (runner.vm.get_ap() - 4).unwrap();
5067        assert_eq!(
5068            runner.get_builtins_final_stack(initial_pointer),
5069            Ok(expected_pointer)
5070        );
5071    }
5072
5073    #[test]
5074    fn get_builtins_final_stack_no_builtins() {
5075        let program = Program::from_bytes(
5076            include_bytes!("../../../../cairo_programs/fibonacci.json"),
5077            Some("main"),
5078        )
5079        .unwrap();
5080        let mut runner = cairo_runner!(program);
5081        let end = runner.initialize(false).unwrap();
5082        runner
5083            .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5084            .unwrap();
5085        runner.vm.segments.compute_effective_sizes();
5086        let initial_pointer = runner.vm.get_ap();
5087        let expected_pointer = runner.vm.get_ap();
5088        assert_eq!(
5089            runner.get_builtins_final_stack(initial_pointer),
5090            Ok(expected_pointer)
5091        );
5092    }
5093
5094    #[test]
5095    fn filter_unused_builtins_test() {
5096        let program = Program::from_bytes(
5097            include_bytes!("../../../../cairo_programs/integration.json"),
5098            Some("main"),
5099        )
5100        .unwrap();
5101        let mut runner = cairo_runner!(program);
5102        let end = runner.initialize(false).unwrap();
5103        runner
5104            .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5105            .unwrap();
5106        runner.vm.segments.compute_effective_sizes();
5107        let mut exec = runner.get_execution_resources().unwrap();
5108        exec.builtin_instance_counter.insert(BuiltinName::keccak, 0);
5109        assert_eq!(exec.builtin_instance_counter.len(), 5);
5110        let rsc = exec.filter_unused_builtins();
5111        assert_eq!(rsc.builtin_instance_counter.len(), 4);
5112    }
5113
5114    #[test]
5115    fn execution_resources_mul() {
5116        let execution_resources_1 = ExecutionResources {
5117            n_steps: 800,
5118            n_memory_holes: 0,
5119            builtin_instance_counter: BTreeMap::from([
5120                (BuiltinName::pedersen, 7),
5121                (BuiltinName::range_check, 16),
5122            ]),
5123        };
5124
5125        assert_eq!(
5126            &execution_resources_1 * 2,
5127            ExecutionResources {
5128                n_steps: 1600,
5129                n_memory_holes: 0,
5130                builtin_instance_counter: BTreeMap::from([
5131                    (BuiltinName::pedersen, 14),
5132                    (BuiltinName::range_check, 32)
5133                ])
5134            }
5135        );
5136
5137        let execution_resources_2 = ExecutionResources {
5138            n_steps: 545,
5139            n_memory_holes: 0,
5140            builtin_instance_counter: BTreeMap::from([(BuiltinName::range_check, 17)]),
5141        };
5142
5143        assert_eq!(
5144            &execution_resources_2 * 8,
5145            ExecutionResources {
5146                n_steps: 4360,
5147                n_memory_holes: 0,
5148                builtin_instance_counter: BTreeMap::from([(BuiltinName::range_check, 136)])
5149            }
5150        );
5151
5152        let execution_resources_3 = ExecutionResources {
5153            n_steps: 42,
5154            n_memory_holes: 0,
5155            builtin_instance_counter: BTreeMap::new(),
5156        };
5157
5158        assert_eq!(
5159            &execution_resources_3 * 18,
5160            ExecutionResources {
5161                n_steps: 756,
5162                n_memory_holes: 0,
5163                builtin_instance_counter: BTreeMap::new()
5164            }
5165        );
5166    }
5167
5168    #[test]
5169    fn test_get_program() {
5170        let program = program!(
5171            builtins = vec![BuiltinName::output],
5172            data = vec_data!((4), (6)),
5173        );
5174        let runner = cairo_runner!(program);
5175
5176        assert_eq!(runner.get_program().data_len(), 2)
5177    }
5178
5179    #[test]
5180    fn test_run_resources_none() {
5181        let program = Program::from_bytes(
5182            include_bytes!("../../../../cairo_programs/fibonacci.json"),
5183            Some("main"),
5184        )
5185        .unwrap();
5186        let mut runner = cairo_runner!(program);
5187        let end = runner.initialize(false).unwrap();
5188
5189        // program takes 80 steps
5190        assert_matches!(
5191            runner.run_until_pc(end, &mut BuiltinHintProcessor::new_empty(),),
5192            Ok(())
5193        )
5194    }
5195
5196    #[test]
5197    fn test_run_resources_ok() {
5198        let program = Program::from_bytes(
5199            include_bytes!("../../../../cairo_programs/fibonacci.json"),
5200            Some("main"),
5201        )
5202        .unwrap();
5203        let mut runner = cairo_runner!(program);
5204        let end = runner.initialize(false).unwrap();
5205        let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(81));
5206        // program takes 81 steps
5207        assert_matches!(runner.run_until_pc(end, &mut hint_processor), Ok(()));
5208
5209        assert_eq!(hint_processor.run_resources().get_n_steps(), Some(1));
5210    }
5211
5212    #[test]
5213    fn test_run_resources_ok_2() {
5214        let program = Program::from_bytes(
5215            include_bytes!("../../../../cairo_programs/fibonacci.json"),
5216            Some("main"),
5217        )
5218        .unwrap();
5219        let mut runner = cairo_runner!(program);
5220        let end = runner.initialize(false).unwrap();
5221        let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(80));
5222        // program takes 80 steps
5223        assert_matches!(runner.run_until_pc(end, &mut hint_processor), Ok(()));
5224
5225        assert_eq!(hint_processor.run_resources(), &RunResources::new(0));
5226    }
5227
5228    #[test]
5229    fn test_run_resources_error() {
5230        let program = Program::from_bytes(
5231            include_bytes!("../../../../cairo_programs/fibonacci.json"),
5232            Some("main"),
5233        )
5234        .unwrap();
5235        let mut runner = cairo_runner!(program);
5236        let end = runner.initialize(false).unwrap();
5237        let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(9));
5238        // program takes 9 steps
5239        assert_matches!(
5240            runner.run_until_pc(end, &mut hint_processor,),
5241            Err(VirtualMachineError::UnfinishedExecution)
5242        );
5243        assert_eq!(hint_processor.run_resources(), &RunResources::new(0));
5244    }
5245
5246    #[test]
5247    fn get_cairo_pie_no_program_base() {
5248        let runner = cairo_runner!(Default::default());
5249        assert_eq!(runner.get_cairo_pie(), Err(RunnerError::NoProgBase))
5250    }
5251
5252    #[test]
5253    fn get_cairo_pie_no_execution_base() {
5254        let mut runner = cairo_runner!(Default::default());
5255        runner.program_base = Some(Relocatable::from((0, 0)));
5256        assert_eq!(runner.get_cairo_pie(), Err(RunnerError::NoExecBase))
5257    }
5258
5259    #[test]
5260    fn get_cairo_pie_no_segment_sizes() {
5261        let mut runner = cairo_runner!(Default::default());
5262        runner.program_base = Some(Relocatable::from((0, 0)));
5263        runner.execution_base = Some(Relocatable::from((1, 0)));
5264        runner.vm.add_memory_segment();
5265        runner.vm.add_memory_segment();
5266        // return_fp
5267        runner
5268            .vm
5269            .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5270            .unwrap();
5271        // return_pc
5272        runner
5273            .vm
5274            .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5275            .unwrap();
5276        assert_eq!(
5277            runner.get_cairo_pie(),
5278            Err(RunnerError::UnexpectedRetFpSegmentSize)
5279        );
5280    }
5281
5282    #[test]
5283    fn get_cairo_pie_ret_pc_segment_size_not_zero() {
5284        let mut runner = cairo_runner!(Default::default());
5285        runner.program_base = Some(Relocatable::from((0, 0)));
5286        runner.execution_base = Some(Relocatable::from((1, 0)));
5287        runner.vm.add_memory_segment();
5288        runner.vm.add_memory_segment();
5289        // return_fp
5290        runner
5291            .vm
5292            .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5293            .unwrap();
5294        // return_pc
5295        runner
5296            .vm
5297            .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5298            .unwrap();
5299        // segment sizes
5300        runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 1)]);
5301        assert_eq!(
5302            runner.get_cairo_pie(),
5303            Err(RunnerError::UnexpectedRetPcSegmentSize)
5304        );
5305    }
5306
5307    #[test]
5308    fn get_cairo_pie_program_base_offset_not_zero() {
5309        let mut runner = cairo_runner!(Default::default());
5310        runner.program_base = Some(Relocatable::from((0, 1)));
5311        runner.execution_base = Some(Relocatable::from((1, 0)));
5312        runner.vm.add_memory_segment();
5313        runner.vm.add_memory_segment();
5314        // return_fp
5315        runner
5316            .vm
5317            .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5318            .unwrap();
5319        // return_pc
5320        runner
5321            .vm
5322            .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5323            .unwrap();
5324        // segment sizes
5325        runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5326        assert_eq!(
5327            runner.get_cairo_pie(),
5328            Err(RunnerError::ProgramBaseOffsetNotZero)
5329        );
5330    }
5331
5332    #[test]
5333    fn get_cairo_pie_execution_base_offset_not_zero() {
5334        let mut runner = cairo_runner!(Default::default());
5335        runner.program_base = Some(Relocatable::from((0, 0)));
5336        runner.execution_base = Some(Relocatable::from((1, 1)));
5337        runner.vm.add_memory_segment();
5338        runner.vm.add_memory_segment();
5339        // return_fp
5340        runner
5341            .vm
5342            .insert_value::<Relocatable>((1, 1).into(), (2, 0).into())
5343            .unwrap();
5344        // return_pc
5345        runner
5346            .vm
5347            .insert_value::<Relocatable>((1, 2).into(), (3, 0).into())
5348            .unwrap();
5349        // segment sizes
5350        runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5351        assert_eq!(
5352            runner.get_cairo_pie(),
5353            Err(RunnerError::ExecBaseOffsetNotZero)
5354        );
5355    }
5356
5357    #[test]
5358    fn get_cairo_pie_ret_fp_offset_not_zero() {
5359        let mut runner = cairo_runner!(Default::default());
5360        runner.program_base = Some(Relocatable::from((0, 0)));
5361        runner.execution_base = Some(Relocatable::from((1, 0)));
5362        runner.vm.add_memory_segment();
5363        runner.vm.add_memory_segment();
5364        // return_fp
5365        runner
5366            .vm
5367            .insert_value::<Relocatable>((1, 0).into(), (2, 1).into())
5368            .unwrap();
5369        // return_pc
5370        runner
5371            .vm
5372            .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5373            .unwrap();
5374        // segment sizes
5375        runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5376        assert_eq!(runner.get_cairo_pie(), Err(RunnerError::RetFpOffsetNotZero));
5377    }
5378
5379    #[test]
5380    fn get_cairo_pie_ret_pc_offset_not_zero() {
5381        let mut runner = cairo_runner!(Default::default());
5382        runner.program_base = Some(Relocatable::from((0, 0)));
5383        runner.execution_base = Some(Relocatable::from((1, 0)));
5384        runner.vm.add_memory_segment();
5385        runner.vm.add_memory_segment();
5386        // return_fp
5387        runner
5388            .vm
5389            .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5390            .unwrap();
5391        // return_pc
5392        runner
5393            .vm
5394            .insert_value::<Relocatable>((1, 1).into(), (3, 1).into())
5395            .unwrap();
5396        // segment sizes
5397        runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5398        assert_eq!(runner.get_cairo_pie(), Err(RunnerError::RetPcOffsetNotZero));
5399    }
5400
5401    #[test]
5402    fn get_cairo_pie_ok() {
5403        let mut runner = cairo_runner!(Default::default());
5404        runner.program_base = Some(Relocatable::from((0, 0)));
5405        runner.execution_base = Some(Relocatable::from((1, 0)));
5406        runner.vm.add_memory_segment();
5407        runner.vm.add_memory_segment();
5408        // return_fp
5409        runner
5410            .vm
5411            .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5412            .unwrap();
5413        // return_pc
5414        runner
5415            .vm
5416            .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5417            .unwrap();
5418        // segment sizes
5419        runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5420    }
5421
5422    #[test]
5423    fn get_air_private_input() {
5424        let program_content =
5425            include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json");
5426        let runner = crate::cairo_run::cairo_run(
5427            program_content,
5428            &CairoRunConfig {
5429                proof_mode: true,
5430                fill_holes: true,
5431                layout: LayoutName::all_cairo,
5432                ..Default::default()
5433            },
5434            &mut BuiltinHintProcessor::new_empty(),
5435        )
5436        .unwrap();
5437        let air_private_input = runner.get_air_private_input();
5438        assert!(air_private_input.0[&BuiltinName::pedersen].is_empty());
5439        assert!(air_private_input.0[&BuiltinName::range_check].is_empty());
5440        assert!(air_private_input.0[&BuiltinName::bitwise].is_empty());
5441        assert!(air_private_input.0[&BuiltinName::ec_op].is_empty());
5442        assert!(air_private_input.0[&BuiltinName::keccak].is_empty());
5443        assert!(air_private_input.0[&BuiltinName::poseidon].is_empty());
5444        assert_eq!(
5445            air_private_input.0[&BuiltinName::ecdsa],
5446            vec![PrivateInput::Signature(PrivateInputSignature {
5447                index: 0,
5448                pubkey: felt_hex!(
5449                    "0x3d60886c2353d93ec2862e91e23036cd9999a534481166e5a616a983070434d"
5450                ),
5451                msg: felt_hex!("0xa9e"),
5452                signature_input: SignatureInput {
5453                    r: felt_hex!(
5454                        "0x6d2e2e00dfceffd6a375db04764da249a5a1534c7584738dfe01cb3944a33ee"
5455                    ),
5456                    w: felt_hex!(
5457                        "0x396362a34ff391372fca63f691e27753ce8f0c2271a614cbd240e1dc1596b28"
5458                    )
5459                }
5460            })]
5461        );
5462    }
5463
5464    #[test]
5465    fn test_disable_trace_padding_without_proof_mode() {
5466        let program = program!();
5467        // Attempt to create a runner in non-proof mode with trace padding disabled.
5468        let result = CairoRunner::new(&program, LayoutName::plain, None, false, true, true);
5469        match result {
5470            Err(RunnerError::DisableTracePaddingWithoutProofMode) => { /* test passed */ }
5471            _ => panic!("Expected DisableTracePaddingWithoutProofMode error"),
5472        }
5473    }
5474
5475    #[test]
5476    fn test_get_relocatable_trace() {
5477        let program_content =
5478            include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json");
5479        let runner = crate::cairo_run::cairo_run(
5480            program_content,
5481            &CairoRunConfig {
5482                trace_enabled: true,
5483                layout: LayoutName::all_cairo,
5484                ..Default::default()
5485            },
5486            &mut BuiltinHintProcessor::new_empty(),
5487        )
5488        .unwrap();
5489        let relocatable_trace = runner.get_relocatable_trace().unwrap();
5490        let expected_trace = vec![
5491            TraceEntry {
5492                pc: (0, 15).into(),
5493                ap: 3,
5494                fp: 3,
5495            },
5496            TraceEntry {
5497                pc: (0, 16).into(),
5498                ap: 4,
5499                fp: 3,
5500            },
5501            TraceEntry {
5502                pc: (0, 18).into(),
5503                ap: 5,
5504                fp: 3,
5505            },
5506            TraceEntry {
5507                pc: (0, 20).into(),
5508                ap: 6,
5509                fp: 3,
5510            },
5511            TraceEntry {
5512                pc: (0, 22).into(),
5513                ap: 7,
5514                fp: 3,
5515            },
5516            TraceEntry {
5517                pc: (0, 24).into(),
5518                ap: 8,
5519                fp: 3,
5520            },
5521            TraceEntry {
5522                pc: (0, 10).into(),
5523                ap: 10,
5524                fp: 10,
5525            },
5526            TraceEntry {
5527                pc: (0, 11).into(),
5528                ap: 10,
5529                fp: 10,
5530            },
5531            TraceEntry {
5532                pc: (0, 12).into(),
5533                ap: 10,
5534                fp: 10,
5535            },
5536            TraceEntry {
5537                pc: (0, 14).into(),
5538                ap: 11,
5539                fp: 10,
5540            },
5541            TraceEntry {
5542                pc: (0, 26).into(),
5543                ap: 11,
5544                fp: 3,
5545            },
5546        ];
5547        assert_eq!(relocatable_trace, expected_trace);
5548    }
5549
5550    #[test]
5551    fn test_get_relocatable_memory() {
5552        let program_content =
5553            include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json");
5554        let runner = crate::cairo_run::cairo_run(
5555            program_content,
5556            &CairoRunConfig {
5557                layout: LayoutName::all_cairo,
5558                ..Default::default()
5559            },
5560            &mut BuiltinHintProcessor::new_empty(),
5561        )
5562        .unwrap();
5563        let relocatable_memory = runner.get_relocatable_memory();
5564
5565        let expected_in_memory_0_3 = MaybeRelocatable::Int(13.into());
5566        let expected_in_memory_1_0 = MaybeRelocatable::RelocatableValue(Relocatable {
5567            segment_index: 2,
5568            offset: 0,
5569        });
5570
5571        assert_eq!(relocatable_memory[0][3], Some(expected_in_memory_0_3));
5572        assert_eq!(relocatable_memory[1][0], Some(expected_in_memory_1_0));
5573    }
5574
5575    #[test]
5576    fn test_get_builtin_segments() {
5577        let program_content =
5578            include_bytes!("../../../../cairo_programs/proof_programs/bitwise_builtin_test.json");
5579        let runner = crate::cairo_run::cairo_run(
5580            program_content,
5581            &CairoRunConfig {
5582                layout: LayoutName::all_cairo,
5583                ..Default::default()
5584            },
5585            &mut BuiltinHintProcessor::new_empty(),
5586        )
5587        .unwrap();
5588        let builtin_segments = runner.get_builtin_segments();
5589
5590        assert_eq!(builtin_segments[&2], BuiltinName::bitwise);
5591    }
5592
5593    #[test]
5594    fn end_run_fill_builtins() {
5595        let program = Program::from_bytes(
5596            include_bytes!("../../../../cairo_programs/proof_programs/keccak_uint256.json"),
5597            Some("main"),
5598        )
5599        .unwrap();
5600
5601        let mut hint_processor = BuiltinHintProcessor::new_empty();
5602        let proof_mode = true;
5603        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, proof_mode, true);
5604
5605        let end = cairo_runner.initialize(false).unwrap();
5606        cairo_runner
5607            .run_until_pc(end, &mut hint_processor)
5608            .expect("Call to `CairoRunner::run_until_pc()` failed.");
5609
5610        // Before end run
5611        assert!(cairo_runner.vm.segments.memory.data[6].len() as u32 % CELLS_PER_BITWISE != 0);
5612        assert!(cairo_runner.vm.segments.memory.data[8].len() as u32 % CELLS_PER_KECCAK != 0);
5613
5614        assert_matches!(
5615            cairo_runner.end_run(false, false, &mut hint_processor, proof_mode),
5616            Ok(())
5617        );
5618
5619        // After end run
5620        assert!(cairo_runner.vm.segments.memory.data[6].len() as u32 % CELLS_PER_BITWISE == 0);
5621        assert!(cairo_runner.vm.segments.memory.data[8].len() as u32 % CELLS_PER_KECCAK == 0);
5622        assert!(cairo_runner.vm.segments.memory.data[6].last().is_some());
5623        assert!(cairo_runner.vm.segments.memory.data[8].last().is_some());
5624
5625        let builtin_segments = cairo_runner.get_builtin_segments();
5626        assert!(builtin_segments.get(&6) == Some(&BuiltinName::bitwise));
5627        assert!(builtin_segments.get(&8) == Some(&BuiltinName::keccak));
5628    }
5629
5630    #[test]
5631    fn end_run_fill_middle_holes() {
5632        let program = Program::from_bytes(
5633            include_bytes!("../../../../cairo_programs/proof_programs/poseidon_builtin_hole.json"),
5634            Some("main"),
5635        )
5636        .unwrap();
5637
5638        let mut hint_processor = BuiltinHintProcessor::new_empty();
5639        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true, true);
5640
5641        let end = cairo_runner.initialize(false).unwrap();
5642        cairo_runner
5643            .run_until_pc(end, &mut hint_processor)
5644            .expect("Call to `CairoRunner::run_until_pc()` failed.");
5645
5646        // Before end run
5647        // In 'poseidon_builtin_hole.cairo' we are not accessing result.s1, so there is a hole in that builtin segment.
5648        assert!(cairo_runner.vm.segments.memory.data[9][4].is_none());
5649        assert_matches!(
5650            cairo_runner.end_run(false, false, &mut hint_processor, true),
5651            Ok(())
5652        );
5653
5654        // After end run
5655        assert!(!cairo_runner.vm.segments.memory.data[9][4].is_none());
5656
5657        let builtin_segments = cairo_runner.get_builtin_segments();
5658        assert!(builtin_segments.get(&9) == Some(&BuiltinName::poseidon));
5659    }
5660
5661    #[test]
5662    #[cfg(feature = "test_utils")]
5663    fn test_simulated_builtins() {
5664        let program_bytes = include_bytes!("../../../../cairo_programs/simulated_builtins.json");
5665        let program =
5666            Program::from_bytes(program_bytes, Some("main")).expect("failed to read program");
5667
5668        let program: &Program = &program;
5669        let mut cairo_runner =
5670            CairoRunner::new(program, LayoutName::plain, None, false, false, false)
5671                .expect("failed to create runner");
5672
5673        // We allow missing builtins, as we will simulate them later.
5674        let end = cairo_runner
5675            .initialize(true)
5676            .expect("failed to initialize builtins");
5677
5678        // Initialize the ec_op simulated builtin runner.
5679        let mut builtin_runner = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(None, true));
5680        builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
5681        cairo_runner
5682            .vm
5683            .simulated_builtin_runners
5684            .push(builtin_runner);
5685
5686        let hint_processor: &mut dyn HintProcessor = &mut BuiltinHintProcessor::new_empty();
5687        cairo_runner
5688            .run_until_pc(end, hint_processor)
5689            .expect("failed to run program");
5690    }
5691}