cairo_vm/vm/runners/
cairo_runner.rs

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