cairo_vm/vm/runners/
cairo_runner.rs

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