cairo_vm/vm/runners/
cairo_runner.rs

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