cairo_vm/vm/runners/
cairo_runner.rs

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