cairo_vm/vm/runners/
cairo_runner.rs

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