cairo_vm/vm/
vm_core.rs

1use crate::math_utils::signed_felt;
2use crate::stdlib::{any::Any, borrow::Cow, collections::HashMap, prelude::*};
3use crate::types::builtin_name::BuiltinName;
4#[cfg(feature = "extensive_hints")]
5use crate::types::program::HintRange;
6use crate::vm::vm_memory::memory::MemoryCell;
7use crate::{
8    hint_processor::{
9        builtin_hint_processor::blake2s_hash::blake2s_compress,
10        hint_processor_definition::HintProcessor,
11    },
12    typed_operations::{typed_add, typed_div, typed_mul, typed_sub},
13    types::{
14        errors::math_errors::MathError,
15        exec_scope::ExecutionScopes,
16        instruction::{
17            is_call_instruction, ApUpdate, FpUpdate, Instruction, Opcode, OpcodeExtension,
18            PcUpdate, Res,
19        },
20        relocatable::{MaybeRelocatable, Relocatable},
21    },
22    vm::{
23        context::run_context::RunContext,
24        decoding::decoder::decode_instruction,
25        errors::{
26            exec_scope_errors::ExecScopeError, memory_errors::MemoryError,
27            vm_errors::VirtualMachineError,
28        },
29        runners::builtin_runner::{
30            BuiltinRunner, OutputBuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner,
31        },
32        trace::trace_entry::TraceEntry,
33        vm_memory::memory_segments::MemorySegmentManager,
34    },
35};
36
37use crate::Felt252;
38use core::cmp::Ordering;
39#[cfg(feature = "extensive_hints")]
40use core::num::NonZeroUsize;
41use num_traits::{ToPrimitive, Zero};
42
43use super::errors::runner_errors::RunnerError;
44use super::runners::builtin_runner::{ModBuiltinRunner, RC_N_PARTS_STANDARD};
45use super::runners::cairo_pie::CairoPie;
46
47const MAX_TRACEBACK_ENTRIES: u32 = 20;
48
49#[derive(PartialEq, Eq, Debug)]
50pub struct Operands {
51    dst: MaybeRelocatable,
52    res: Option<MaybeRelocatable>,
53    op0: MaybeRelocatable,
54    op1: MaybeRelocatable,
55}
56
57#[derive(PartialEq, Eq, Debug)]
58pub struct OperandsAddresses {
59    dst_addr: Relocatable,
60    op0_addr: Relocatable,
61    op1_addr: Relocatable,
62}
63
64#[derive(Default, Debug, Clone, Copy)]
65pub struct DeducedOperands(u8);
66
67impl DeducedOperands {
68    fn set_dst(&mut self, value: bool) {
69        self.0 |= value as u8;
70    }
71    fn set_op0(&mut self, value: bool) {
72        self.0 |= (value as u8) << 1;
73    }
74    fn set_op1(&mut self, value: bool) {
75        self.0 |= (value as u8) << 2;
76    }
77
78    fn was_dest_deducted(&self) -> bool {
79        self.0 & 1 != 0
80    }
81    fn was_op0_deducted(&self) -> bool {
82        self.0 & (1 << 1) != 0
83    }
84    fn was_op1_deducted(&self) -> bool {
85        self.0 & (1 << 2) != 0
86    }
87}
88
89pub struct VirtualMachine {
90    pub(crate) run_context: RunContext,
91    pub builtin_runners: Vec<BuiltinRunner>,
92    /// A simulated builtin is being verified in the executed Cairo
93    /// code (so proving them only involves proving cairo steps), rather
94    /// than being outputted as their own segment and proven later using
95    /// dedicated AIRs.
96    ///
97    /// These builtins won't be included in the layout, hence the builtin
98    /// segment pointer won't be passed as argument to the program. The program
99    /// needs a mechanism for obtaining the segment pointer. See example
100    /// implementation of this mechanism in `simulated_builtins.cairo`, or
101    /// cairo-lang's `simple_bootloader.cairo`.
102    pub simulated_builtin_runners: Vec<BuiltinRunner>,
103    pub segments: MemorySegmentManager,
104    pub(crate) trace: Option<Vec<TraceEntry>>,
105    pub(crate) current_step: usize,
106    pub(crate) rc_limits: Option<(isize, isize)>,
107    skip_instruction_execution: bool,
108    run_finished: bool,
109    // This flag is a parallel to the one in `struct CairoRunConfig`.
110    pub(crate) disable_trace_padding: bool,
111    instruction_cache: Vec<Option<Instruction>>,
112    #[cfg(feature = "test_utils")]
113    pub(crate) hooks: crate::vm::hooks::Hooks,
114    pub(crate) relocation_table: Option<Vec<usize>>,
115}
116
117impl VirtualMachine {
118    pub fn new(trace_enabled: bool, disable_trace_padding: bool) -> VirtualMachine {
119        let run_context = RunContext {
120            pc: Relocatable::from((0, 0)),
121            ap: 0,
122            fp: 0,
123        };
124
125        let trace = if trace_enabled {
126            Some(Vec::<TraceEntry>::new())
127        } else {
128            None
129        };
130
131        VirtualMachine {
132            run_context,
133            builtin_runners: Vec::new(),
134            simulated_builtin_runners: Vec::new(),
135            trace,
136            current_step: 0,
137            skip_instruction_execution: false,
138            segments: MemorySegmentManager::new(),
139            rc_limits: None,
140            run_finished: false,
141            disable_trace_padding,
142            instruction_cache: Vec::new(),
143            #[cfg(feature = "test_utils")]
144            hooks: Default::default(),
145            relocation_table: None,
146        }
147    }
148
149    pub fn compute_segments_effective_sizes(&mut self) {
150        self.segments.compute_effective_sizes();
151    }
152
153    fn update_fp(
154        &mut self,
155        instruction: &Instruction,
156        operands: &Operands,
157    ) -> Result<(), VirtualMachineError> {
158        let new_fp_offset: usize = match instruction.fp_update {
159            FpUpdate::APPlus2 => self.run_context.ap + 2,
160            FpUpdate::Dst => match operands.dst {
161                MaybeRelocatable::RelocatableValue(ref rel) => rel.offset,
162                MaybeRelocatable::Int(ref num) => num
163                    .to_usize()
164                    .ok_or_else(|| MathError::Felt252ToUsizeConversion(Box::new(*num)))?,
165            },
166            FpUpdate::Regular => return Ok(()),
167        };
168        self.run_context.fp = new_fp_offset;
169        Ok(())
170    }
171
172    fn update_ap(
173        &mut self,
174        instruction: &Instruction,
175        operands: &Operands,
176    ) -> Result<(), VirtualMachineError> {
177        let new_apset: usize = match instruction.ap_update {
178            ApUpdate::Add => match &operands.res {
179                Some(res) => (self.run_context.get_ap() + res)?.offset,
180                None => return Err(VirtualMachineError::UnconstrainedResAdd),
181            },
182            ApUpdate::Add1 => self.run_context.ap + 1,
183            ApUpdate::Add2 => self.run_context.ap + 2,
184            ApUpdate::Regular => return Ok(()),
185        };
186        self.run_context.ap = new_apset;
187        Ok(())
188    }
189
190    fn update_pc(
191        &mut self,
192        instruction: &Instruction,
193        operands: &Operands,
194    ) -> Result<(), VirtualMachineError> {
195        let new_pc: Relocatable = match instruction.pc_update {
196            PcUpdate::Regular => (self.run_context.pc + instruction.size())?,
197            PcUpdate::Jump => match operands.res.as_ref().and_then(|x| x.get_relocatable()) {
198                Some(ref res) => *res,
199                None => return Err(VirtualMachineError::UnconstrainedResJump),
200            },
201            PcUpdate::JumpRel => match &operands.res {
202                Some(res) => match res {
203                    MaybeRelocatable::Int(num_res) => (self.run_context.pc + num_res)?,
204                    _ => return Err(VirtualMachineError::JumpRelNotInt),
205                },
206                None => return Err(VirtualMachineError::UnconstrainedResJumpRel),
207            },
208            PcUpdate::Jnz => match VirtualMachine::is_zero(&operands.dst) {
209                true => (self.run_context.pc + instruction.size())?,
210                false => (self.run_context.pc + &operands.op1)?,
211            },
212        };
213        self.run_context.pc = new_pc;
214        Ok(())
215    }
216
217    fn update_registers(
218        &mut self,
219        instruction: &Instruction,
220        operands: Operands,
221    ) -> Result<(), VirtualMachineError> {
222        self.update_fp(instruction, &operands)?;
223        self.update_ap(instruction, &operands)?;
224        self.update_pc(instruction, &operands)?;
225        Ok(())
226    }
227
228    /// Returns true if the value is zero
229    /// Used for JNZ instructions
230    fn is_zero(addr: &MaybeRelocatable) -> bool {
231        match addr {
232            MaybeRelocatable::Int(num) => num.is_zero(),
233            _ => false,
234        }
235    }
236
237    ///Returns a tuple (deduced_op0, deduced_res).
238    ///Deduces the value of op0 if possible (based on dst and op1). Otherwise, returns None.
239    ///If res was already deduced, returns its deduced value as well.
240    fn deduce_op0(
241        &self,
242        instruction: &Instruction,
243        dst: Option<&MaybeRelocatable>,
244        op1: Option<&MaybeRelocatable>,
245    ) -> Result<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError> {
246        match instruction.opcode {
247            Opcode::Call => Ok((
248                Some(MaybeRelocatable::from(
249                    (self.run_context.pc + instruction.size())?,
250                )),
251                None,
252            )),
253            Opcode::AssertEq => match (&instruction.res, dst, op1) {
254                (Res::Add, Some(dst_addr), Some(op1_addr)) => Ok((
255                    Some(typed_sub(dst_addr, op1_addr, instruction.opcode_extension)?),
256                    dst.cloned(),
257                )),
258                (
259                    Res::Mul,
260                    Some(MaybeRelocatable::Int(num_dst)),
261                    Some(MaybeRelocatable::Int(num_op1)),
262                ) if !num_op1.is_zero() => {
263                    let num_op0 = typed_div(num_dst, num_op1, instruction.opcode_extension)?;
264                    Ok((Some(MaybeRelocatable::Int(num_op0)), dst.cloned()))
265                }
266                _ => Ok((None, None)),
267            },
268            _ => Ok((None, None)),
269        }
270    }
271
272    /// Returns a tuple (deduced_op1, deduced_res).
273    ///Deduces the value of op1 if possible (based on dst and op0). Otherwise, returns None.
274    ///If res was already deduced, returns its deduced value as well.
275    fn deduce_op1(
276        &self,
277        instruction: &Instruction,
278        dst: Option<&MaybeRelocatable>,
279        op0: Option<MaybeRelocatable>,
280    ) -> Result<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError> {
281        if let Opcode::AssertEq = instruction.opcode {
282            match instruction.res {
283                Res::Op1 => return Ok((dst.cloned(), dst.cloned())),
284                Res::Add => {
285                    return Ok((
286                        dst.zip(op0).and_then(|(dst, op0)| {
287                            typed_sub(dst, &op0, instruction.opcode_extension).ok()
288                        }),
289                        dst.cloned(),
290                    ))
291                }
292                Res::Mul => match (dst, op0) {
293                    (
294                        Some(MaybeRelocatable::Int(num_dst)),
295                        Some(MaybeRelocatable::Int(num_op0)),
296                    ) if !num_op0.is_zero() => {
297                        let num_op1 = typed_div(num_dst, &num_op0, instruction.opcode_extension)?;
298                        return Ok((Some(MaybeRelocatable::Int(num_op1)), dst.cloned()));
299                    }
300                    _ => (),
301                },
302                _ => (),
303            };
304        };
305        Ok((None, None))
306    }
307
308    fn deduce_memory_cell(
309        &self,
310        address: Relocatable,
311    ) -> Result<Option<MaybeRelocatable>, VirtualMachineError> {
312        let memory = &self.segments.memory;
313
314        for runner in self
315            .builtin_runners
316            .iter()
317            .chain(self.simulated_builtin_runners.iter())
318        {
319            if runner.base() as isize == address.segment_index {
320                return runner
321                    .deduce_memory_cell(address, memory)
322                    .map_err(VirtualMachineError::RunnerError);
323            }
324        }
325        Ok(None)
326    }
327
328    ///Computes the value of res if possible
329    fn compute_res(
330        &self,
331        instruction: &Instruction,
332        op0: &MaybeRelocatable,
333        op1: &MaybeRelocatable,
334    ) -> Result<Option<MaybeRelocatable>, VirtualMachineError> {
335        match instruction.res {
336            Res::Op1 => Ok(Some(op1.clone())),
337            Res::Add => Ok(Some(typed_add(op0, op1, instruction.opcode_extension)?)),
338            Res::Mul => Ok(Some(typed_mul(op0, op1, instruction.opcode_extension)?)),
339            Res::Unconstrained => Ok(None),
340        }
341    }
342
343    fn deduce_dst(
344        &self,
345        instruction: &Instruction,
346        res: &Option<MaybeRelocatable>,
347    ) -> Result<MaybeRelocatable, VirtualMachineError> {
348        let dst = match (instruction.opcode, res) {
349            (Opcode::AssertEq, Some(res)) => res.clone(),
350            (Opcode::Call, _) => MaybeRelocatable::from(self.run_context.get_fp()),
351            _ => return Err(VirtualMachineError::NoDst),
352        };
353        Ok(dst)
354    }
355
356    fn opcode_assertions(
357        &self,
358        instruction: &Instruction,
359        operands: &Operands,
360    ) -> Result<(), VirtualMachineError> {
361        match instruction.opcode {
362            Opcode::AssertEq => match &operands.res {
363                None => Err(VirtualMachineError::UnconstrainedResAssertEq),
364                Some(res) if res != &operands.dst => Err(VirtualMachineError::DiffAssertValues(
365                    Box::new((operands.dst.clone(), res.clone())),
366                )),
367                _ => Ok(()),
368            },
369            Opcode::Call => {
370                let return_pc = MaybeRelocatable::from((self.run_context.pc + instruction.size())?);
371                if operands.op0 != return_pc {
372                    return Err(VirtualMachineError::CantWriteReturnPc(Box::new((
373                        operands.op0.clone(),
374                        return_pc,
375                    ))));
376                };
377
378                if MaybeRelocatable::from(self.run_context.get_fp()) != operands.dst {
379                    return Err(VirtualMachineError::CantWriteReturnFp(Box::new((
380                        operands.dst.clone(),
381                        MaybeRelocatable::from(self.run_context.get_fp()),
382                    ))));
383                };
384                Ok(())
385            }
386            _ => Ok(()),
387        }
388    }
389
390    fn insert_deduced_operands(
391        &mut self,
392        deduced_operands: DeducedOperands,
393        operands: &Operands,
394        operands_addresses: &OperandsAddresses,
395    ) -> Result<(), VirtualMachineError> {
396        if deduced_operands.was_op0_deducted() {
397            self.segments
398                .memory
399                .insert(operands_addresses.op0_addr, &operands.op0)
400                .map_err(VirtualMachineError::Memory)?;
401        }
402        if deduced_operands.was_op1_deducted() {
403            self.segments
404                .memory
405                .insert(operands_addresses.op1_addr, &operands.op1)
406                .map_err(VirtualMachineError::Memory)?;
407        }
408        if deduced_operands.was_dest_deducted() {
409            self.segments
410                .memory
411                .insert(operands_addresses.dst_addr, &operands.dst)
412                .map_err(VirtualMachineError::Memory)?;
413        }
414
415        Ok(())
416    }
417
418    fn run_instruction(&mut self, instruction: &Instruction) -> Result<(), VirtualMachineError> {
419        let (operands, operands_addresses, deduced_operands) =
420            self.compute_operands(instruction)?;
421        self.insert_deduced_operands(deduced_operands, &operands, &operands_addresses)?;
422        self.opcode_assertions(instruction, &operands)?;
423
424        if let Some(ref mut trace) = &mut self.trace {
425            trace.push(TraceEntry {
426                pc: self.run_context.pc,
427                ap: self.run_context.ap,
428                fp: self.run_context.fp,
429            });
430        }
431
432        // Update range check limits
433        const OFFSET_BITS: u32 = 16;
434        let (off0, off1, off2) = (
435            instruction.off0 + (1_isize << (OFFSET_BITS - 1)),
436            instruction.off1 + (1_isize << (OFFSET_BITS - 1)),
437            instruction.off2 + (1_isize << (OFFSET_BITS - 1)),
438        );
439        let (min, max) = self.rc_limits.unwrap_or((off0, off0));
440        self.rc_limits = Some((
441            min.min(off0).min(off1).min(off2),
442            max.max(off0).max(off1).max(off2),
443        ));
444
445        self.segments
446            .memory
447            .mark_as_accessed(operands_addresses.dst_addr);
448        self.segments
449            .memory
450            .mark_as_accessed(operands_addresses.op0_addr);
451        self.segments
452            .memory
453            .mark_as_accessed(operands_addresses.op1_addr);
454        self.segments.memory.mark_as_accessed(self.run_context.pc);
455
456        if instruction.opcode_extension == OpcodeExtension::Blake
457            || instruction.opcode_extension == OpcodeExtension::BlakeFinalize
458        {
459            self.handle_blake2s_instruction(
460                &operands_addresses,
461                instruction.opcode_extension == OpcodeExtension::BlakeFinalize,
462            )?;
463        }
464
465        self.update_registers(instruction, operands)?;
466        self.current_step += 1;
467
468        Ok(())
469    }
470
471    /// Executes a Blake2s or Blake2sLastBlock instruction.
472    /// Expects operands to be RelocatableValue and to point to segments of memory.
473    /// op0 is expected to point to a sequence of 8 u32 values (state).
474    /// op1 is expected to point to a sequence of 16 u32 values (message).
475    /// dst is expected hold the u32 value of the counter (t).
476    /// [ap] is expected to point to a sequence of 8 cells each being either unitialised or
477    /// containing the Blake2s compression output at that index.
478    /// Deviation from the aforementioned expectations will result in an error.
479    /// The instruction will update the memory segment pointed by [ap] with the new state.
480    /// Note: the byte counter should count the number of message bytes processed so far including
481    /// the current portion of the message (i.e. it starts at 64, not 0).
482    fn handle_blake2s_instruction(
483        &mut self,
484        operands_addresses: &OperandsAddresses,
485        is_last_block: bool,
486    ) -> Result<(), VirtualMachineError> {
487        let counter = self.segments.memory.get_u32(operands_addresses.dst_addr)?;
488
489        let state: [u32; 8] = (self.get_u32_range(
490            self.segments
491                .memory
492                .get_relocatable(operands_addresses.op0_addr)?,
493            8,
494        )?)
495        .try_into()
496        .map_err(|_| VirtualMachineError::Blake2sInvalidOperand(0, 8))?;
497
498        let message: [u32; 16] = (self.get_u32_range(
499            self.segments
500                .memory
501                .get_relocatable(operands_addresses.op1_addr)?,
502            16,
503        )?)
504        .try_into()
505        .map_err(|_| VirtualMachineError::Blake2sInvalidOperand(1, 16))?;
506
507        let f0 = if is_last_block { 0xffffffff } else { 0 };
508
509        let ap = self.run_context.get_ap();
510        let output_address = self.segments.memory.get_relocatable(ap)?;
511
512        let new_state = blake2s_compress(&state, &message, counter, 0, f0, 0);
513
514        for (i, &val) in new_state.iter().enumerate() {
515            self.segments.memory.insert_as_accessed(
516                (output_address + i)?,
517                MaybeRelocatable::Int(Felt252::from(val)),
518            )?;
519        }
520
521        Ok(())
522    }
523
524    fn decode_current_instruction(&self) -> Result<Instruction, VirtualMachineError> {
525        let instruction = self
526            .segments
527            .memory
528            .get_integer(self.run_context.pc)?
529            .to_u128()
530            .ok_or(VirtualMachineError::InvalidInstructionEncoding)?;
531        decode_instruction(instruction)
532    }
533
534    #[cfg(not(feature = "extensive_hints"))]
535    pub fn step_hint(
536        &mut self,
537        hint_processor: &mut dyn HintProcessor,
538        exec_scopes: &mut ExecutionScopes,
539        hint_datas: &[Box<dyn Any>],
540    ) -> Result<(), VirtualMachineError> {
541        for (hint_index, hint_data) in hint_datas.iter().enumerate() {
542            hint_processor
543                .execute_hint(self, exec_scopes, hint_data)
544                .map_err(|err| VirtualMachineError::Hint(Box::new((hint_index, err))))?
545        }
546        Ok(())
547    }
548
549    #[cfg(feature = "extensive_hints")]
550    pub fn step_hint(
551        &mut self,
552        hint_processor: &mut dyn HintProcessor,
553        exec_scopes: &mut ExecutionScopes,
554        hint_datas: &mut Vec<Box<dyn Any>>,
555        hint_ranges: &mut HashMap<Relocatable, HintRange>,
556    ) -> Result<(), VirtualMachineError> {
557        // Check if there is a hint range for the current pc
558        if let Some((s, l)) = hint_ranges.get(&self.run_context.pc) {
559            // Re-binding to avoid mutability problems
560            let s = *s;
561            // Execute each hint for the given range
562            for idx in s..(s + l.get()) {
563                let hint_extension = hint_processor
564                    .execute_hint_extensive(
565                        self,
566                        exec_scopes,
567                        hint_datas.get(idx).ok_or(VirtualMachineError::Unexpected)?,
568                    )
569                    .map_err(|err| VirtualMachineError::Hint(Box::new((idx - s, err))))?;
570                // Update the hint_ranges & hint_datas with the hints added by the executed hint
571                for (hint_pc, hints) in hint_extension {
572                    if let Ok(len) = NonZeroUsize::try_from(hints.len()) {
573                        hint_ranges.insert(hint_pc, (hint_datas.len(), len));
574                        hint_datas.extend(hints);
575                    }
576                }
577            }
578        }
579        Ok(())
580    }
581
582    pub fn step_instruction(&mut self) -> Result<(), VirtualMachineError> {
583        if self.run_context.pc.segment_index == 0 {
584            // Run instructions from program segment, using instruction cache
585            let pc = self.run_context.pc.offset;
586
587            if self.segments.memory.data[0].len() <= pc {
588                return Err(MemoryError::UnknownMemoryCell(Box::new((0, pc).into())))?;
589            }
590
591            let mut inst_cache = core::mem::take(&mut self.instruction_cache);
592            inst_cache.resize((pc + 1).max(inst_cache.len()), None);
593
594            let instruction = inst_cache.get_mut(pc).unwrap();
595            if instruction.is_none() {
596                *instruction = Some(self.decode_current_instruction()?);
597            }
598            let instruction = instruction.as_ref().unwrap();
599
600            if !self.skip_instruction_execution {
601                self.run_instruction(instruction)?;
602            } else {
603                self.run_context.pc += instruction.size();
604                self.skip_instruction_execution = false;
605            }
606            self.instruction_cache = inst_cache;
607        } else {
608            // Run instructions from programs loaded in other segments, without instruction cache
609            let instruction = self.decode_current_instruction()?;
610
611            if !self.skip_instruction_execution {
612                self.run_instruction(&instruction)?;
613            } else {
614                self.run_context.pc += instruction.size();
615                self.skip_instruction_execution = false;
616            }
617        }
618        Ok(())
619    }
620
621    pub fn step(
622        &mut self,
623        hint_processor: &mut dyn HintProcessor,
624        exec_scopes: &mut ExecutionScopes,
625        #[cfg(feature = "extensive_hints")] hint_datas: &mut Vec<Box<dyn Any>>,
626        #[cfg(not(feature = "extensive_hints"))] hint_datas: &[Box<dyn Any>],
627        #[cfg(feature = "extensive_hints")] hint_ranges: &mut HashMap<Relocatable, HintRange>,
628        #[cfg(feature = "test_utils")] constants: &HashMap<String, Felt252>,
629    ) -> Result<(), VirtualMachineError> {
630        self.step_hint(
631            hint_processor,
632            exec_scopes,
633            hint_datas,
634            #[cfg(feature = "extensive_hints")]
635            hint_ranges,
636        )?;
637
638        #[cfg(feature = "test_utils")]
639        self.execute_pre_step_instruction(hint_processor, exec_scopes, hint_datas, constants)?;
640        self.step_instruction()?;
641        #[cfg(feature = "test_utils")]
642        self.execute_post_step_instruction(hint_processor, exec_scopes, hint_datas, constants)?;
643
644        Ok(())
645    }
646
647    fn compute_op0_deductions(
648        &self,
649        op0_addr: Relocatable,
650        res: &mut Option<MaybeRelocatable>,
651        instruction: &Instruction,
652        dst_op: &Option<MaybeRelocatable>,
653        op1_op: &Option<MaybeRelocatable>,
654    ) -> Result<MaybeRelocatable, VirtualMachineError> {
655        let op0_op = match self.deduce_memory_cell(op0_addr)? {
656            None => {
657                let op0;
658                (op0, *res) = self.deduce_op0(instruction, dst_op.as_ref(), op1_op.as_ref())?;
659                op0
660            }
661            deduced_memory_cell => deduced_memory_cell,
662        };
663        let op0 = op0_op.ok_or_else(|| {
664            VirtualMachineError::FailedToComputeOperands(Box::new(("op0".to_string(), op0_addr)))
665        })?;
666        Ok(op0)
667    }
668
669    fn compute_op1_deductions(
670        &self,
671        op1_addr: Relocatable,
672        res: &mut Option<MaybeRelocatable>,
673        instruction: &Instruction,
674        dst_op: &Option<MaybeRelocatable>,
675        op0: &MaybeRelocatable,
676    ) -> Result<MaybeRelocatable, VirtualMachineError> {
677        let op1_op = match self.deduce_memory_cell(op1_addr)? {
678            None => {
679                let (op1, deduced_res) =
680                    self.deduce_op1(instruction, dst_op.as_ref(), Some(op0.clone()))?;
681                if res.is_none() {
682                    *res = deduced_res
683                }
684                op1
685            }
686            deduced_memory_cell => deduced_memory_cell,
687        };
688        let op1 = op1_op.ok_or_else(|| {
689            VirtualMachineError::FailedToComputeOperands(Box::new(("op1".to_string(), op1_addr)))
690        })?;
691        Ok(op1)
692    }
693
694    /// Compute operands and result, trying to deduce them if normal memory access returns a None
695    /// value.
696    pub fn compute_operands(
697        &self,
698        instruction: &Instruction,
699    ) -> Result<(Operands, OperandsAddresses, DeducedOperands), VirtualMachineError> {
700        //Get operands from memory
701        let dst_addr = self.run_context.compute_dst_addr(instruction)?;
702        let dst_op = self.segments.memory.get(&dst_addr).map(Cow::into_owned);
703
704        let op0_addr = self.run_context.compute_op0_addr(instruction)?;
705        let op0_op = self.segments.memory.get(&op0_addr).map(Cow::into_owned);
706
707        let op1_addr = self
708            .run_context
709            .compute_op1_addr(instruction, op0_op.as_ref())?;
710        let op1_op = self.segments.memory.get(&op1_addr).map(Cow::into_owned);
711
712        let mut res: Option<MaybeRelocatable> = None;
713
714        let mut deduced_operands = DeducedOperands::default();
715
716        //Deduce op0 if it wasnt previously computed
717        let op0 = match op0_op {
718            Some(op0) => op0,
719            None => {
720                deduced_operands.set_op0(true);
721                self.compute_op0_deductions(op0_addr, &mut res, instruction, &dst_op, &op1_op)?
722            }
723        };
724
725        //Deduce op1 if it wasnt previously computed
726        let op1 = match op1_op {
727            Some(op1) => op1,
728            None => {
729                deduced_operands.set_op1(true);
730                self.compute_op1_deductions(op1_addr, &mut res, instruction, &dst_op, &op0)?
731            }
732        };
733
734        //Compute res if it wasnt previously deduced
735        if res.is_none() {
736            res = self.compute_res(instruction, &op0, &op1)?;
737        }
738
739        //Deduce dst if it wasnt previously computed
740        let dst = match dst_op {
741            Some(dst) => dst,
742            None => {
743                deduced_operands.set_dst(true);
744                self.deduce_dst(instruction, &res)?
745            }
746        };
747        let accessed_addresses = OperandsAddresses {
748            dst_addr,
749            op0_addr,
750            op1_addr,
751        };
752        Ok((
753            Operands { dst, op0, op1, res },
754            accessed_addresses,
755            deduced_operands,
756        ))
757    }
758
759    /// Updates the memory with missing built-in deductions and verifies the existing ones.
760    pub fn complete_builtin_auto_deductions(&mut self) -> Result<(), VirtualMachineError> {
761        for builtin in self.builtin_runners.iter() {
762            let builtin_index: usize = builtin.base();
763
764            // Output and SegmentArena do not need to be auto-deduced in the memory.
765            if matches!(
766                builtin,
767                BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_)
768            ) {
769                continue;
770            }
771
772            // Extend the segment size to a multiple of the number of cells per instance.
773            let current_builtin_segment = &mut self.segments.memory.data[builtin_index];
774            let len = current_builtin_segment.len();
775            let cells_per_instance = builtin.cells_per_instance() as usize;
776            current_builtin_segment.resize(
777                len.div_ceil(cells_per_instance) * cells_per_instance,
778                MemoryCell::NONE,
779            );
780
781            let mut missing_values: Vec<(usize, MemoryCell)> = vec![];
782
783            for (offset, cell) in self.segments.memory.data[builtin_index].iter().enumerate() {
784                if let Some(deduced_memory_cell) = builtin
785                    .deduce_memory_cell(
786                        Relocatable::from((builtin_index as isize, offset)),
787                        &self.segments.memory,
788                    )
789                    .map_err(VirtualMachineError::RunnerError)?
790                {
791                    match cell.get_value() {
792                        Some(memory_value) => {
793                            // Checks that the value in the memory is correct.
794                            if memory_value != deduced_memory_cell {
795                                return Err(VirtualMachineError::InconsistentAutoDeduction(
796                                    Box::new((
797                                        builtin.name(),
798                                        deduced_memory_cell,
799                                        Some(memory_value),
800                                    )),
801                                ));
802                            }
803                        }
804                        None => {
805                            // Collect value to be stored in memory.
806                            missing_values.push((offset, MemoryCell::new(deduced_memory_cell)));
807                        }
808                    }
809                }
810            }
811
812            for (offset, value) in missing_values {
813                self.segments.memory.data[builtin_index][offset] = value;
814            }
815        }
816        Ok(())
817    }
818
819    ///Makes sure that all assigned memory cells are consistent with their auto deduction rules.
820    pub fn verify_auto_deductions(&self) -> Result<(), VirtualMachineError> {
821        for builtin in self.builtin_runners.iter() {
822            let index: usize = builtin.base();
823            for (offset, value) in self.segments.memory.data[index].iter().enumerate() {
824                if let Some(deduced_memory_cell) = builtin
825                    .deduce_memory_cell(
826                        Relocatable::from((index as isize, offset)),
827                        &self.segments.memory,
828                    )
829                    .map_err(VirtualMachineError::RunnerError)?
830                {
831                    let value = value.get_value();
832                    if Some(&deduced_memory_cell) != value.as_ref() && value.is_some() {
833                        return Err(VirtualMachineError::InconsistentAutoDeduction(Box::new((
834                            builtin.name(),
835                            deduced_memory_cell,
836                            value,
837                        ))));
838                    }
839                }
840            }
841        }
842        Ok(())
843    }
844
845    //Makes sure that the value at the given address is consistent with the auto deduction rules.
846    pub fn verify_auto_deductions_for_addr(
847        &self,
848        addr: Relocatable,
849        builtin: &BuiltinRunner,
850    ) -> Result<(), VirtualMachineError> {
851        let value = match builtin.deduce_memory_cell(addr, &self.segments.memory)? {
852            Some(value) => value,
853            None => return Ok(()),
854        };
855        let current_value = match self.segments.memory.get(&addr) {
856            Some(value) => value.into_owned(),
857            None => return Ok(()),
858        };
859        if value != current_value {
860            return Err(VirtualMachineError::InconsistentAutoDeduction(Box::new((
861                builtin.name(),
862                value,
863                Some(current_value),
864            ))));
865        }
866        Ok(())
867    }
868
869    pub fn end_run(
870        &mut self,
871        exec_scopes: &ExecutionScopes,
872        fill_holes: bool,
873    ) -> Result<(), VirtualMachineError> {
874        if fill_holes {
875            self.complete_builtin_auto_deductions()?;
876        } else {
877            self.verify_auto_deductions()?;
878        }
879        self.run_finished = true;
880        match exec_scopes.data.len() {
881            1 => Ok(()),
882            _ => Err(ExecScopeError::NoScopeError.into()),
883        }
884    }
885
886    pub fn mark_address_range_as_accessed(
887        &mut self,
888        base: Relocatable,
889        len: usize,
890    ) -> Result<(), VirtualMachineError> {
891        if !self.run_finished {
892            return Err(VirtualMachineError::RunNotFinished);
893        }
894        for i in 0..len {
895            self.segments.memory.mark_as_accessed((base + i)?);
896        }
897        Ok(())
898    }
899
900    /// Returns the values (fp, pc) corresponding to each call instruction in the traceback.
901    /// Returns the most recent call last.
902    pub fn get_traceback_entries(&self) -> Vec<(Relocatable, Relocatable)> {
903        let mut entries = Vec::<(Relocatable, Relocatable)>::new();
904        let mut fp = Relocatable::from((1, self.run_context.fp));
905        // Fetch the fp and pc traceback entries
906        for _ in 0..MAX_TRACEBACK_ENTRIES {
907            // Get return pc
908            let ret_pc = match (fp - 1)
909                .ok()
910                .map(|r| self.segments.memory.get_relocatable(r))
911            {
912                Some(Ok(opt_pc)) => opt_pc,
913                _ => break,
914            };
915            // Get fp traceback
916            match (fp - 2)
917                .ok()
918                .map(|r| self.segments.memory.get_relocatable(r))
919            {
920                Some(Ok(opt_fp)) if opt_fp != fp => fp = opt_fp,
921                _ => break,
922            }
923            // Try to check if the call instruction is (instruction0, instruction1) or just
924            // instruction1 (with no immediate).
925            let call_pc = match (ret_pc - 1)
926                .ok()
927                .map(|r| self.segments.memory.get_integer(r))
928            {
929                Some(Ok(instruction1)) => {
930                    match is_call_instruction(&instruction1) {
931                        true => (ret_pc - 1).unwrap(), // This unwrap wont fail as it is checked before
932                        false => {
933                            match (ret_pc - 2)
934                                .ok()
935                                .map(|r| self.segments.memory.get_integer(r))
936                            {
937                                Some(Ok(instruction0)) => {
938                                    match is_call_instruction(&instruction0) {
939                                        true => (ret_pc - 2).unwrap(), // This unwrap wont fail as it is checked before
940                                        false => break,
941                                    }
942                                }
943                                _ => break,
944                            }
945                        }
946                    }
947                }
948                _ => break,
949            };
950            // Append traceback entries
951            entries.push((fp, call_pc))
952        }
953        entries.reverse();
954        entries
955    }
956
957    ///Adds a new segment and to the memory and returns its starting location as a Relocatable value.
958    pub fn add_memory_segment(&mut self) -> Relocatable {
959        self.segments.add()
960    }
961
962    pub fn get_ap(&self) -> Relocatable {
963        self.run_context.get_ap()
964    }
965
966    pub fn get_fp(&self) -> Relocatable {
967        self.run_context.get_fp()
968    }
969
970    pub fn get_pc(&self) -> Relocatable {
971        self.run_context.get_pc()
972    }
973
974    pub fn get_current_step(&self) -> usize {
975        self.current_step
976    }
977
978    ///Gets the integer value corresponding to the Relocatable address
979    pub fn get_integer(&'_ self, key: Relocatable) -> Result<Cow<'_, Felt252>, MemoryError> {
980        self.segments.memory.get_integer(key)
981    }
982
983    ///Gets the relocatable value corresponding to the Relocatable address
984    pub fn get_relocatable(&self, key: Relocatable) -> Result<Relocatable, MemoryError> {
985        self.segments.memory.get_relocatable(key)
986    }
987
988    ///Gets a MaybeRelocatable value from memory indicated by a generic address
989    pub fn get_maybe<'a, 'b: 'a, K: 'a>(&'b self, key: &'a K) -> Option<MaybeRelocatable>
990    where
991        Relocatable: TryFrom<&'a K>,
992    {
993        self.segments.memory.get(key).map(|x| x.into_owned())
994    }
995
996    /// Returns a reference to the vector with all builtins present in the virtual machine
997    pub fn get_builtin_runners(&self) -> &Vec<BuiltinRunner> {
998        &self.builtin_runners
999    }
1000
1001    /// Returns a mutable reference to the vector with all builtins present in the virtual machine
1002    pub fn get_builtin_runners_as_mut(&mut self) -> &mut Vec<BuiltinRunner> {
1003        &mut self.builtin_runners
1004    }
1005
1006    /// Returns a mutable iterator over all builtin runners used. That is, both builtin_runners and
1007    /// simulated_builtin_runners.
1008    pub fn get_all_builtin_runners_as_mut_iter(
1009        &mut self,
1010    ) -> impl Iterator<Item = &mut BuiltinRunner> {
1011        self.builtin_runners
1012            .iter_mut()
1013            .chain(self.simulated_builtin_runners.iter_mut())
1014    }
1015
1016    ///Inserts a value into a memory address given by a Relocatable value
1017    pub fn insert_value<T: Into<MaybeRelocatable>>(
1018        &mut self,
1019        key: Relocatable,
1020        val: T,
1021    ) -> Result<(), MemoryError> {
1022        self.segments.memory.insert_value(key, val)
1023    }
1024
1025    /// Removes (unsets) a value from a memory cell that was not accessed by the VM.
1026    ///
1027    /// This function can be used to implement lazy opening of merkelized contracts. The full
1028    /// program is initially loaded into memory via a hint. After execution, any entry points to
1029    /// contract segments that were not accessed are replaced with an invalid opcode.
1030    ///
1031    /// [Use case](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/core/os/contract_class/compiled_class.cairo#L244-L253)
1032    pub fn delete_unaccessed(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
1033        self.segments.memory.delete_unaccessed(addr)
1034    }
1035
1036    ///Writes data into the memory from address ptr and returns the first address after the data.
1037    pub fn load_data(
1038        &mut self,
1039        ptr: Relocatable,
1040        data: &[MaybeRelocatable],
1041    ) -> Result<Relocatable, MemoryError> {
1042        if ptr.segment_index == 0 {
1043            self.instruction_cache.resize(data.len(), None);
1044        }
1045        self.segments.load_data(ptr, data)
1046    }
1047
1048    /// Writes args into the memory from address ptr and returns the first address after the data.
1049    pub fn write_arg(
1050        &mut self,
1051        ptr: Relocatable,
1052        arg: &dyn Any,
1053    ) -> Result<MaybeRelocatable, MemoryError> {
1054        self.segments.write_arg(ptr, arg)
1055    }
1056
1057    pub fn memcmp(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> (Ordering, usize) {
1058        self.segments.memory.memcmp(lhs, rhs, len)
1059    }
1060
1061    pub fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
1062        self.segments.memory.mem_eq(lhs, rhs, len)
1063    }
1064
1065    pub fn is_accessed(&self, addr: &Relocatable) -> Result<bool, MemoryError> {
1066        self.segments.is_accessed(addr)
1067    }
1068
1069    ///Gets `n_ret` return values from memory
1070    pub fn get_return_values(&self, n_ret: usize) -> Result<Vec<MaybeRelocatable>, MemoryError> {
1071        let addr = (self.run_context.get_ap() - n_ret)
1072            .map_err(|_| MemoryError::FailedToGetReturnValues(Box::new((n_ret, self.get_ap()))))?;
1073        self.segments.memory.get_continuous_range(addr, n_ret)
1074    }
1075
1076    ///Gets n elements from memory starting from addr (n being size)
1077    pub fn get_range(
1078        &'_ self,
1079        addr: Relocatable,
1080        size: usize,
1081    ) -> Vec<Option<Cow<'_, MaybeRelocatable>>> {
1082        self.segments.memory.get_range(addr, size)
1083    }
1084
1085    ///Gets n elements from memory starting from addr (n being size)
1086    pub fn get_continuous_range(
1087        &self,
1088        addr: Relocatable,
1089        size: usize,
1090    ) -> Result<Vec<MaybeRelocatable>, MemoryError> {
1091        self.segments.memory.get_continuous_range(addr, size)
1092    }
1093
1094    ///Gets n integer values from memory starting from addr (n being size),
1095    pub fn get_integer_range(
1096        &'_ self,
1097        addr: Relocatable,
1098        size: usize,
1099    ) -> Result<Vec<Cow<'_, Felt252>>, MemoryError> {
1100        self.segments.memory.get_integer_range(addr, size)
1101    }
1102
1103    /// Gets n u32 values from memory starting from addr (n being size).
1104    /// Returns an error if any of the values inside the range is missing (memory gap) or is not a u32.
1105    pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result<Vec<u32>, MemoryError> {
1106        self.segments.memory.get_u32_range(addr, size)
1107    }
1108
1109    pub fn get_range_check_builtin(
1110        &self,
1111    ) -> Result<&RangeCheckBuiltinRunner<RC_N_PARTS_STANDARD>, VirtualMachineError> {
1112        for builtin in &self.builtin_runners {
1113            if let BuiltinRunner::RangeCheck(range_check_builtin) = builtin {
1114                return Ok(range_check_builtin);
1115            };
1116        }
1117        Err(VirtualMachineError::NoRangeCheckBuiltin)
1118    }
1119
1120    pub fn get_signature_builtin(
1121        &mut self,
1122    ) -> Result<&mut SignatureBuiltinRunner, VirtualMachineError> {
1123        for builtin in self.get_all_builtin_runners_as_mut_iter() {
1124            if let BuiltinRunner::Signature(signature_builtin) = builtin {
1125                return Ok(signature_builtin);
1126            };
1127        }
1128
1129        Err(VirtualMachineError::NoSignatureBuiltin)
1130    }
1131
1132    pub fn get_output_builtin_mut(
1133        &mut self,
1134    ) -> Result<&mut OutputBuiltinRunner, VirtualMachineError> {
1135        for builtin in self.get_builtin_runners_as_mut() {
1136            if let BuiltinRunner::Output(output_builtin) = builtin {
1137                return Ok(output_builtin);
1138            };
1139        }
1140
1141        Err(VirtualMachineError::NoOutputBuiltin)
1142    }
1143
1144    #[cfg(feature = "tracer")]
1145    pub fn relocate_segments(&self) -> Result<Vec<usize>, MemoryError> {
1146        self.segments.relocate_segments()
1147    }
1148
1149    #[doc(hidden)]
1150    pub fn skip_next_instruction_execution(&mut self) {
1151        self.skip_instruction_execution = true;
1152    }
1153
1154    #[doc(hidden)]
1155    pub fn set_ap(&mut self, ap: usize) {
1156        self.run_context.set_ap(ap)
1157    }
1158
1159    #[doc(hidden)]
1160    pub fn set_fp(&mut self, fp: usize) {
1161        self.run_context.set_fp(fp)
1162    }
1163
1164    #[doc(hidden)]
1165    pub fn set_pc(&mut self, pc: Relocatable) {
1166        self.run_context.set_pc(pc)
1167    }
1168
1169    pub fn get_segment_used_size(&self, index: usize) -> Option<usize> {
1170        self.segments.get_segment_used_size(index)
1171    }
1172
1173    pub fn get_segment_size(&self, index: usize) -> Option<usize> {
1174        self.segments.get_segment_size(index)
1175    }
1176
1177    pub fn add_temporary_segment(&mut self) -> Relocatable {
1178        self.segments.add_temporary_segment()
1179    }
1180
1181    /// Add a new relocation rule.
1182    ///
1183    /// When using feature "extensive_hints" the destination is allowed to be an Integer (via
1184    /// MaybeRelocatable). Relocating memory to anything other than a `Relocatable` is generally
1185    /// not useful, but it does make the implementation consistent with the pythonic version.
1186    ///
1187    /// Will return an error if any of the following conditions are not met:
1188    ///   - Source address's segment must be negative (temporary).
1189    ///   - Source address's offset must be zero.
1190    ///   - There shouldn't already be relocation at the source segment.
1191    pub fn add_relocation_rule(
1192        &mut self,
1193        src_ptr: Relocatable,
1194        #[cfg(not(feature = "extensive_hints"))] dst_ptr: Relocatable,
1195        #[cfg(feature = "extensive_hints")] dst_ptr: MaybeRelocatable,
1196    ) -> Result<(), MemoryError> {
1197        self.segments.memory.add_relocation_rule(src_ptr, dst_ptr)
1198    }
1199
1200    pub fn gen_arg(&mut self, arg: &dyn Any) -> Result<MaybeRelocatable, MemoryError> {
1201        self.segments.gen_arg(arg)
1202    }
1203
1204    /// Write the values hosted in the output builtin's segment.
1205    /// Does nothing if the output builtin is not present in the program.
1206    pub fn write_output(
1207        &mut self,
1208        writer: &mut impl core::fmt::Write,
1209    ) -> Result<(), VirtualMachineError> {
1210        let builtin = match self
1211            .builtin_runners
1212            .iter()
1213            .find(|b| b.name() == BuiltinName::output)
1214        {
1215            Some(x) => x,
1216            _ => return Ok(()),
1217        };
1218
1219        let segment_used_sizes = self.segments.compute_effective_sizes();
1220        let segment_index = builtin.base();
1221        for i in 0..segment_used_sizes[segment_index] {
1222            let formatted_value = match self
1223                .segments
1224                .memory
1225                .get(&Relocatable::from((segment_index as isize, i)))
1226            {
1227                Some(val) => match val.as_ref() {
1228                    MaybeRelocatable::Int(num) => format!("{}", signed_felt(*num)),
1229                    MaybeRelocatable::RelocatableValue(rel) => format!("{}", rel),
1230                },
1231                _ => "<missing>".to_string(),
1232            };
1233            writeln!(writer, "{formatted_value}")
1234                .map_err(|_| VirtualMachineError::FailedToWriteOutput)?;
1235        }
1236
1237        Ok(())
1238    }
1239
1240    /// Returns a list of addresses of memory cells that constitute the public memory.
1241    pub fn get_public_memory_addresses(&self) -> Result<Vec<(usize, usize)>, VirtualMachineError> {
1242        if let Some(relocation_table) = &self.relocation_table {
1243            self.segments
1244                .get_public_memory_addresses(relocation_table)
1245                .map_err(VirtualMachineError::Memory)
1246        } else {
1247            Err(MemoryError::UnrelocatedMemory.into())
1248        }
1249    }
1250
1251    #[doc(hidden)]
1252    pub fn builtins_final_stack_from_stack_pointer_dict(
1253        &mut self,
1254        builtin_name_to_stack_pointer: &HashMap<BuiltinName, Relocatable>,
1255        skip_output: bool,
1256    ) -> Result<(), RunnerError> {
1257        for builtin in self.builtin_runners.iter_mut() {
1258            if matches!(builtin, BuiltinRunner::Output(_)) && skip_output {
1259                continue;
1260            }
1261            builtin.final_stack(
1262                &self.segments,
1263                builtin_name_to_stack_pointer
1264                    .get(&builtin.name())
1265                    .cloned()
1266                    .unwrap_or_default(),
1267            )?;
1268        }
1269        Ok(())
1270    }
1271
1272    #[doc(hidden)]
1273    pub fn set_output_stop_ptr_offset(&mut self, offset: usize) {
1274        if let Some(BuiltinRunner::Output(builtin)) = self.builtin_runners.first_mut() {
1275            builtin.set_stop_ptr_offset(offset);
1276            if let Some(segment_used_sizes) = &mut self.segments.segment_used_sizes {
1277                segment_used_sizes[builtin.base()] = offset;
1278            }
1279        }
1280    }
1281
1282    /// Fetches add_mod & mul_mod builtins according to the optional arguments and executes `fill_memory`
1283    /// Returns an error if either of this optional parameters is true but the corresponding builtin is not present
1284    /// Verifies that both builtin's (if present) batch sizes match the batch_size arg if set
1285    // This method is needed as running `fill_memory` direclty from outside the vm struct would require cloning the builtin runners to avoid double borrowing
1286    pub fn mod_builtin_fill_memory(
1287        &mut self,
1288        add_mod_ptr_n: Option<(Relocatable, usize)>,
1289        mul_mod_ptr_n: Option<(Relocatable, usize)>,
1290        batch_size: Option<usize>,
1291    ) -> Result<(), VirtualMachineError> {
1292        let fetch_builtin_params = |mod_params: Option<(Relocatable, usize)>,
1293                                    mod_name: BuiltinName|
1294         -> Result<
1295            Option<(Relocatable, &ModBuiltinRunner, usize)>,
1296            VirtualMachineError,
1297        > {
1298            if let Some((ptr, n)) = mod_params {
1299                let mod_builtin = self
1300                    .builtin_runners
1301                    .iter()
1302                    .find_map(|b| match b {
1303                        BuiltinRunner::Mod(b) if b.name() == mod_name => Some(b),
1304                        _ => None,
1305                    })
1306                    .ok_or_else(|| VirtualMachineError::NoModBuiltin(mod_name))?;
1307                if let Some(batch_size) = batch_size {
1308                    if mod_builtin.batch_size() != batch_size {
1309                        return Err(VirtualMachineError::ModBuiltinBatchSize(Box::new((
1310                            mod_builtin.name(),
1311                            batch_size,
1312                        ))));
1313                    }
1314                }
1315                Ok(Some((ptr, mod_builtin, n)))
1316            } else {
1317                Ok(None)
1318            }
1319        };
1320
1321        ModBuiltinRunner::fill_memory(
1322            &mut self.segments.memory,
1323            fetch_builtin_params(add_mod_ptr_n, BuiltinName::add_mod)?,
1324            fetch_builtin_params(mul_mod_ptr_n, BuiltinName::mul_mod)?,
1325        )
1326        .map_err(VirtualMachineError::RunnerError)
1327    }
1328
1329    pub(crate) fn finalize_segments_by_cairo_pie(&mut self, pie: &CairoPie) {
1330        let mut segment_infos = vec![
1331            &pie.metadata.program_segment,
1332            &pie.metadata.execution_segment,
1333            &pie.metadata.ret_fp_segment,
1334            &pie.metadata.ret_pc_segment,
1335        ];
1336        segment_infos.extend(pie.metadata.builtin_segments.values());
1337        segment_infos.extend(pie.metadata.extra_segments.iter());
1338        for info in segment_infos {
1339            self.segments
1340                .finalize(Some(info.size), info.index as usize, None)
1341        }
1342    }
1343}
1344
1345pub struct VirtualMachineBuilder {
1346    pub(crate) run_context: RunContext,
1347    pub(crate) builtin_runners: Vec<BuiltinRunner>,
1348    pub(crate) segments: MemorySegmentManager,
1349    pub(crate) trace: Option<Vec<TraceEntry>>,
1350    pub(crate) current_step: usize,
1351    skip_instruction_execution: bool,
1352    run_finished: bool,
1353    #[cfg(feature = "test_utils")]
1354    pub(crate) hooks: crate::vm::hooks::Hooks,
1355}
1356
1357impl Default for VirtualMachineBuilder {
1358    fn default() -> Self {
1359        let run_context = RunContext {
1360            pc: Relocatable::from((0, 0)),
1361            ap: 0,
1362            fp: 0,
1363        };
1364
1365        VirtualMachineBuilder {
1366            run_context,
1367            builtin_runners: Vec::new(),
1368            trace: None,
1369            current_step: 0,
1370            skip_instruction_execution: false,
1371            segments: MemorySegmentManager::new(),
1372            run_finished: false,
1373            #[cfg(feature = "test_utils")]
1374            hooks: Default::default(),
1375        }
1376    }
1377}
1378
1379impl VirtualMachineBuilder {
1380    pub fn run_context(mut self, run_context: RunContext) -> VirtualMachineBuilder {
1381        self.run_context = run_context;
1382        self
1383    }
1384
1385    pub fn builtin_runners(mut self, builtin_runners: Vec<BuiltinRunner>) -> VirtualMachineBuilder {
1386        self.builtin_runners = builtin_runners;
1387        self
1388    }
1389
1390    pub fn segments(mut self, segments: MemorySegmentManager) -> VirtualMachineBuilder {
1391        self.segments = segments;
1392        self
1393    }
1394
1395    pub fn trace(mut self, trace: Option<Vec<TraceEntry>>) -> VirtualMachineBuilder {
1396        self.trace = trace;
1397        self
1398    }
1399
1400    pub fn current_step(mut self, current_step: usize) -> VirtualMachineBuilder {
1401        self.current_step = current_step;
1402        self
1403    }
1404
1405    pub fn skip_instruction_execution(
1406        mut self,
1407        skip_instruction_execution: bool,
1408    ) -> VirtualMachineBuilder {
1409        self.skip_instruction_execution = skip_instruction_execution;
1410        self
1411    }
1412
1413    pub fn run_finished(mut self, run_finished: bool) -> VirtualMachineBuilder {
1414        self.run_finished = run_finished;
1415        self
1416    }
1417
1418    #[cfg(feature = "test_utils")]
1419    pub fn hooks(mut self, hooks: crate::vm::hooks::Hooks) -> VirtualMachineBuilder {
1420        self.hooks = hooks;
1421        self
1422    }
1423
1424    pub fn build(self) -> VirtualMachine {
1425        VirtualMachine {
1426            run_context: self.run_context,
1427            builtin_runners: self.builtin_runners,
1428            simulated_builtin_runners: Vec::new(),
1429            trace: self.trace,
1430            current_step: self.current_step,
1431            skip_instruction_execution: self.skip_instruction_execution,
1432            segments: self.segments,
1433            rc_limits: None,
1434            run_finished: self.run_finished,
1435            instruction_cache: Vec::new(),
1436            #[cfg(feature = "test_utils")]
1437            hooks: self.hooks,
1438            relocation_table: None,
1439            disable_trace_padding: false,
1440        }
1441    }
1442}
1443
1444#[cfg(test)]
1445mod tests {
1446    use super::*;
1447    use crate::felt_hex;
1448    use crate::math_utils::{qm31_coordinates_to_packed_reduced, STWO_PRIME};
1449    use crate::stdlib::collections::HashMap;
1450    use crate::types::instruction::OpcodeExtension;
1451    use crate::types::layout_name::LayoutName;
1452    use crate::types::program::Program;
1453    use crate::{
1454        any_box,
1455        hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{
1456            BuiltinHintProcessor, HintProcessorData,
1457        },
1458        relocatable,
1459        types::{
1460            instruction::{Op1Addr, Register},
1461            relocatable::Relocatable,
1462        },
1463        utils::test_utils::*,
1464        vm::{
1465            errors::memory_errors::MemoryError,
1466            runners::builtin_runner::{BitwiseBuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner},
1467        },
1468    };
1469    use assert_matches::assert_matches;
1470
1471    #[cfg(target_arch = "wasm32")]
1472    use wasm_bindgen_test::*;
1473
1474    #[test]
1475    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1476    fn update_fp_ap_plus2() {
1477        let instruction = Instruction {
1478            off0: 1,
1479            off1: 2,
1480            off2: 3,
1481            dst_register: Register::FP,
1482            op0_register: Register::AP,
1483            op1_addr: Op1Addr::AP,
1484            res: Res::Add,
1485            pc_update: PcUpdate::Regular,
1486            ap_update: ApUpdate::Regular,
1487            fp_update: FpUpdate::APPlus2,
1488            opcode: Opcode::NOp,
1489            opcode_extension: OpcodeExtension::Stone,
1490        };
1491
1492        let operands = Operands {
1493            dst: MaybeRelocatable::Int(Felt252::from(11)),
1494            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1495            op0: MaybeRelocatable::Int(Felt252::from(9)),
1496            op1: MaybeRelocatable::Int(Felt252::from(10)),
1497        };
1498
1499        let mut vm = vm!();
1500        run_context!(vm, 4, 5, 6);
1501        assert_matches!(
1502            vm.update_fp(&instruction, &operands),
1503            Ok::<(), VirtualMachineError>(())
1504        );
1505        assert_eq!(vm.run_context.fp, 7)
1506    }
1507
1508    #[test]
1509    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1510    fn update_fp_dst() {
1511        let instruction = Instruction {
1512            off0: 1,
1513            off1: 2,
1514            off2: 3,
1515            dst_register: Register::FP,
1516            op0_register: Register::AP,
1517            op1_addr: Op1Addr::AP,
1518            res: Res::Add,
1519            pc_update: PcUpdate::Regular,
1520            ap_update: ApUpdate::Regular,
1521            fp_update: FpUpdate::Dst,
1522            opcode: Opcode::NOp,
1523            opcode_extension: OpcodeExtension::Stone,
1524        };
1525
1526        let operands = Operands {
1527            dst: mayberelocatable!(1, 6),
1528            res: Some(mayberelocatable!(8)),
1529            op0: mayberelocatable!(9),
1530            op1: mayberelocatable!(10),
1531        };
1532
1533        let mut vm = vm!();
1534
1535        assert_matches!(
1536            vm.update_fp(&instruction, &operands),
1537            Ok::<(), VirtualMachineError>(())
1538        );
1539        assert_eq!(vm.run_context.fp, 6)
1540    }
1541
1542    #[test]
1543    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1544    fn update_fp_regular() {
1545        let instruction = Instruction {
1546            off0: 1,
1547            off1: 2,
1548            off2: 3,
1549            dst_register: Register::FP,
1550            op0_register: Register::AP,
1551            op1_addr: Op1Addr::AP,
1552            res: Res::Add,
1553            pc_update: PcUpdate::Regular,
1554            ap_update: ApUpdate::Regular,
1555            fp_update: FpUpdate::Regular,
1556            opcode: Opcode::NOp,
1557            opcode_extension: OpcodeExtension::Stone,
1558        };
1559
1560        let operands = Operands {
1561            dst: MaybeRelocatable::Int(Felt252::from(11_u64)),
1562            res: Some(MaybeRelocatable::Int(Felt252::from(8_u64))),
1563            op0: MaybeRelocatable::Int(Felt252::from(9_u64)),
1564            op1: MaybeRelocatable::Int(Felt252::from(10_u64)),
1565        };
1566
1567        let mut vm = vm!();
1568
1569        assert_matches!(
1570            vm.update_fp(&instruction, &operands),
1571            Ok::<(), VirtualMachineError>(())
1572        );
1573        assert_eq!(vm.run_context.fp, 0)
1574    }
1575
1576    #[test]
1577    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1578    fn update_fp_dst_num() {
1579        let instruction = Instruction {
1580            off0: 1,
1581            off1: 2,
1582            off2: 3,
1583            dst_register: Register::FP,
1584            op0_register: Register::AP,
1585            op1_addr: Op1Addr::AP,
1586            res: Res::Add,
1587            pc_update: PcUpdate::Regular,
1588            ap_update: ApUpdate::Regular,
1589            fp_update: FpUpdate::Dst,
1590            opcode: Opcode::NOp,
1591            opcode_extension: OpcodeExtension::Stone,
1592        };
1593
1594        let operands = Operands {
1595            dst: MaybeRelocatable::Int(Felt252::from(11)),
1596            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1597            op0: MaybeRelocatable::Int(Felt252::from(9)),
1598            op1: MaybeRelocatable::Int(Felt252::from(10)),
1599        };
1600
1601        let mut vm = vm!();
1602        run_context!(vm, 4, 5, 6);
1603
1604        assert_matches!(
1605            vm.update_fp(&instruction, &operands),
1606            Ok::<(), VirtualMachineError>(())
1607        );
1608        assert_eq!(vm.run_context.fp, 11)
1609    }
1610
1611    #[test]
1612    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1613    fn update_ap_add_with_res() {
1614        let instruction = Instruction {
1615            off0: 1,
1616            off1: 2,
1617            off2: 3,
1618            dst_register: Register::FP,
1619            op0_register: Register::AP,
1620            op1_addr: Op1Addr::AP,
1621            res: Res::Add,
1622            pc_update: PcUpdate::Regular,
1623            ap_update: ApUpdate::Add,
1624            fp_update: FpUpdate::Regular,
1625            opcode: Opcode::NOp,
1626            opcode_extension: OpcodeExtension::Stone,
1627        };
1628
1629        let operands = Operands {
1630            dst: MaybeRelocatable::Int(Felt252::from(11)),
1631            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1632            op0: MaybeRelocatable::Int(Felt252::from(9)),
1633            op1: MaybeRelocatable::Int(Felt252::from(10)),
1634        };
1635
1636        let mut vm = VirtualMachine::new(false, false);
1637        vm.run_context.pc = Relocatable::from((0, 4));
1638        vm.run_context.ap = 5;
1639        vm.run_context.fp = 6;
1640
1641        assert_matches!(
1642            vm.update_ap(&instruction, &operands),
1643            Ok::<(), VirtualMachineError>(())
1644        );
1645        assert_eq!(vm.run_context.ap, 13);
1646    }
1647
1648    #[test]
1649    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1650    fn update_ap_add_without_res() {
1651        let instruction = Instruction {
1652            off0: 1,
1653            off1: 2,
1654            off2: 3,
1655            dst_register: Register::FP,
1656            op0_register: Register::AP,
1657            op1_addr: Op1Addr::AP,
1658            res: Res::Add,
1659            pc_update: PcUpdate::Regular,
1660            ap_update: ApUpdate::Add,
1661            fp_update: FpUpdate::Regular,
1662            opcode: Opcode::NOp,
1663            opcode_extension: OpcodeExtension::Stone,
1664        };
1665
1666        let operands = Operands {
1667            dst: MaybeRelocatable::Int(Felt252::from(11)),
1668            res: None,
1669            op0: MaybeRelocatable::Int(Felt252::from(9)),
1670            op1: MaybeRelocatable::Int(Felt252::from(10)),
1671        };
1672
1673        let mut vm = vm!();
1674        vm.run_context.pc = Relocatable::from((0, 4));
1675        vm.run_context.ap = 5;
1676        vm.run_context.fp = 6;
1677
1678        assert_matches!(
1679            vm.update_ap(&instruction, &operands),
1680            Err(VirtualMachineError::UnconstrainedResAdd)
1681        );
1682    }
1683
1684    #[test]
1685    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1686    fn update_ap_add1() {
1687        let instruction = Instruction {
1688            off0: 1,
1689            off1: 2,
1690            off2: 3,
1691            dst_register: Register::FP,
1692            op0_register: Register::AP,
1693            op1_addr: Op1Addr::AP,
1694            res: Res::Add,
1695            pc_update: PcUpdate::Regular,
1696            ap_update: ApUpdate::Add1,
1697            fp_update: FpUpdate::Regular,
1698            opcode: Opcode::NOp,
1699            opcode_extension: OpcodeExtension::Stone,
1700        };
1701
1702        let operands = Operands {
1703            dst: MaybeRelocatable::Int(Felt252::from(11)),
1704            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1705            op0: MaybeRelocatable::Int(Felt252::from(9)),
1706            op1: MaybeRelocatable::Int(Felt252::from(10)),
1707        };
1708
1709        let mut vm = vm!();
1710        vm.run_context.pc = Relocatable::from((0, 4));
1711        vm.run_context.ap = 5;
1712        vm.run_context.fp = 6;
1713
1714        assert_matches!(
1715            vm.update_ap(&instruction, &operands),
1716            Ok::<(), VirtualMachineError>(())
1717        );
1718        assert_eq!(vm.run_context.ap, 6);
1719    }
1720
1721    #[test]
1722    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1723    fn update_ap_add2() {
1724        let instruction = Instruction {
1725            off0: 1,
1726            off1: 2,
1727            off2: 3,
1728            dst_register: Register::FP,
1729            op0_register: Register::AP,
1730            op1_addr: Op1Addr::AP,
1731            res: Res::Add,
1732            pc_update: PcUpdate::Regular,
1733            ap_update: ApUpdate::Add2,
1734            fp_update: FpUpdate::Regular,
1735            opcode: Opcode::NOp,
1736            opcode_extension: OpcodeExtension::Stone,
1737        };
1738
1739        let operands = Operands {
1740            dst: MaybeRelocatable::Int(Felt252::from(11_u64)),
1741            res: Some(MaybeRelocatable::Int(Felt252::from(8_u64))),
1742            op0: MaybeRelocatable::Int(Felt252::from(9_u64)),
1743            op1: MaybeRelocatable::Int(Felt252::from(10_u64)),
1744        };
1745
1746        let mut vm = vm!();
1747        vm.run_context.pc = Relocatable::from((0, 4));
1748        vm.run_context.ap = 5;
1749        vm.run_context.fp = 6;
1750
1751        assert_matches!(
1752            vm.update_ap(&instruction, &operands),
1753            Ok::<(), VirtualMachineError>(())
1754        );
1755        assert_eq!(vm.run_context.ap, 7);
1756    }
1757
1758    #[test]
1759    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1760    fn update_ap_regular() {
1761        let instruction = Instruction {
1762            off0: 1,
1763            off1: 2,
1764            off2: 3,
1765            dst_register: Register::FP,
1766            op0_register: Register::AP,
1767            op1_addr: Op1Addr::AP,
1768            res: Res::Add,
1769            pc_update: PcUpdate::Regular,
1770            ap_update: ApUpdate::Regular,
1771            fp_update: FpUpdate::Regular,
1772            opcode: Opcode::NOp,
1773            opcode_extension: OpcodeExtension::Stone,
1774        };
1775
1776        let operands = Operands {
1777            dst: MaybeRelocatable::Int(Felt252::from(11)),
1778            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1779            op0: MaybeRelocatable::Int(Felt252::from(9)),
1780            op1: MaybeRelocatable::Int(Felt252::from(10)),
1781        };
1782
1783        let mut vm = vm!();
1784        vm.run_context.pc = Relocatable::from((0, 4));
1785        vm.run_context.ap = 5;
1786        vm.run_context.fp = 6;
1787
1788        assert_matches!(
1789            vm.update_ap(&instruction, &operands),
1790            Ok::<(), VirtualMachineError>(())
1791        );
1792        assert_eq!(vm.run_context.ap, 5);
1793    }
1794
1795    #[test]
1796    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1797    fn update_pc_regular_instruction_no_imm() {
1798        let instruction = Instruction {
1799            off0: 1,
1800            off1: 2,
1801            off2: 3,
1802            dst_register: Register::FP,
1803            op0_register: Register::AP,
1804            op1_addr: Op1Addr::AP,
1805            res: Res::Add,
1806            pc_update: PcUpdate::Regular,
1807            ap_update: ApUpdate::Regular,
1808            fp_update: FpUpdate::Regular,
1809            opcode: Opcode::NOp,
1810            opcode_extension: OpcodeExtension::Stone,
1811        };
1812
1813        let operands = Operands {
1814            dst: MaybeRelocatable::Int(Felt252::from(11)),
1815            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1816            op0: MaybeRelocatable::Int(Felt252::from(9)),
1817            op1: MaybeRelocatable::Int(Felt252::from(10)),
1818        };
1819
1820        let mut vm = vm!();
1821
1822        assert_matches!(
1823            vm.update_pc(&instruction, &operands),
1824            Ok::<(), VirtualMachineError>(())
1825        );
1826        assert_eq!(vm.run_context.pc, Relocatable::from((0, 1)));
1827    }
1828
1829    #[test]
1830    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1831    fn update_pc_regular_instruction_has_imm() {
1832        let instruction = Instruction {
1833            off0: 1,
1834            off1: 2,
1835            off2: 3,
1836            dst_register: Register::FP,
1837            op0_register: Register::AP,
1838            op1_addr: Op1Addr::Imm,
1839            res: Res::Add,
1840            pc_update: PcUpdate::Regular,
1841            ap_update: ApUpdate::Regular,
1842            fp_update: FpUpdate::Regular,
1843            opcode: Opcode::NOp,
1844            opcode_extension: OpcodeExtension::Stone,
1845        };
1846
1847        let operands = Operands {
1848            dst: MaybeRelocatable::Int(Felt252::from(11)),
1849            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1850            op0: MaybeRelocatable::Int(Felt252::from(9)),
1851            op1: MaybeRelocatable::Int(Felt252::from(10)),
1852        };
1853
1854        let mut vm = vm!();
1855
1856        assert_matches!(
1857            vm.update_pc(&instruction, &operands),
1858            Ok::<(), VirtualMachineError>(())
1859        );
1860        assert_eq!(vm.run_context.pc, Relocatable::from((0, 2)));
1861    }
1862
1863    #[test]
1864    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1865    fn update_pc_jump_with_res() {
1866        let instruction = Instruction {
1867            off0: 1,
1868            off1: 2,
1869            off2: 3,
1870            dst_register: Register::FP,
1871            op0_register: Register::AP,
1872            op1_addr: Op1Addr::AP,
1873            res: Res::Add,
1874            pc_update: PcUpdate::Jump,
1875            ap_update: ApUpdate::Regular,
1876            fp_update: FpUpdate::Regular,
1877            opcode: Opcode::NOp,
1878            opcode_extension: OpcodeExtension::Stone,
1879        };
1880
1881        let operands = Operands {
1882            dst: mayberelocatable!(1, 11),
1883            res: Some(mayberelocatable!(0, 8)),
1884            op0: MaybeRelocatable::Int(Felt252::from(9)),
1885            op1: MaybeRelocatable::Int(Felt252::from(10)),
1886        };
1887
1888        let mut vm = vm!();
1889
1890        assert_matches!(
1891            vm.update_pc(&instruction, &operands),
1892            Ok::<(), VirtualMachineError>(())
1893        );
1894        assert_eq!(vm.run_context.pc, Relocatable::from((0, 8)));
1895    }
1896
1897    #[test]
1898    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1899    fn update_pc_jump_without_res() {
1900        let instruction = Instruction {
1901            off0: 1,
1902            off1: 2,
1903            off2: 3,
1904            dst_register: Register::FP,
1905            op0_register: Register::AP,
1906            op1_addr: Op1Addr::AP,
1907            res: Res::Add,
1908            pc_update: PcUpdate::Jump,
1909            ap_update: ApUpdate::Regular,
1910            fp_update: FpUpdate::Regular,
1911            opcode: Opcode::NOp,
1912            opcode_extension: OpcodeExtension::Stone,
1913        };
1914
1915        let operands = Operands {
1916            dst: MaybeRelocatable::Int(Felt252::from(11)),
1917            res: None,
1918            op0: MaybeRelocatable::Int(Felt252::from(9)),
1919            op1: MaybeRelocatable::Int(Felt252::from(10)),
1920        };
1921
1922        let mut vm = vm!();
1923        vm.run_context.pc = Relocatable::from((0, 4));
1924        vm.run_context.ap = 5;
1925        vm.run_context.fp = 6;
1926
1927        assert_matches!(
1928            vm.update_pc(&instruction, &operands),
1929            Err(VirtualMachineError::UnconstrainedResJump)
1930        );
1931    }
1932
1933    #[test]
1934    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1935    fn update_pc_jump_rel_with_int_res() {
1936        let instruction = Instruction {
1937            off0: 1,
1938            off1: 2,
1939            off2: 3,
1940            dst_register: Register::FP,
1941            op0_register: Register::AP,
1942            op1_addr: Op1Addr::AP,
1943            res: Res::Add,
1944            pc_update: PcUpdate::JumpRel,
1945            ap_update: ApUpdate::Regular,
1946            fp_update: FpUpdate::Regular,
1947            opcode: Opcode::NOp,
1948            opcode_extension: OpcodeExtension::Stone,
1949        };
1950
1951        let operands = Operands {
1952            dst: MaybeRelocatable::Int(Felt252::from(11)),
1953            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
1954            op0: MaybeRelocatable::Int(Felt252::from(9)),
1955            op1: MaybeRelocatable::Int(Felt252::from(10)),
1956        };
1957
1958        let mut vm = vm!();
1959        run_context!(vm, 1, 1, 1);
1960
1961        assert_matches!(
1962            vm.update_pc(&instruction, &operands),
1963            Ok::<(), VirtualMachineError>(())
1964        );
1965        assert_eq!(vm.run_context.pc, Relocatable::from((0, 9)));
1966    }
1967
1968    #[test]
1969    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1970    fn update_pc_jump_rel_without_res() {
1971        let instruction = Instruction {
1972            off0: 1,
1973            off1: 2,
1974            off2: 3,
1975            dst_register: Register::FP,
1976            op0_register: Register::AP,
1977            op1_addr: Op1Addr::AP,
1978            res: Res::Add,
1979            pc_update: PcUpdate::JumpRel,
1980            ap_update: ApUpdate::Regular,
1981            fp_update: FpUpdate::Regular,
1982            opcode: Opcode::NOp,
1983            opcode_extension: OpcodeExtension::Stone,
1984        };
1985
1986        let operands = Operands {
1987            dst: MaybeRelocatable::Int(Felt252::from(11)),
1988            res: None,
1989            op0: MaybeRelocatable::Int(Felt252::from(9)),
1990            op1: MaybeRelocatable::Int(Felt252::from(10)),
1991        };
1992
1993        let mut vm = vm!();
1994
1995        assert_matches!(
1996            vm.update_pc(&instruction, &operands),
1997            Err(VirtualMachineError::UnconstrainedResJumpRel)
1998        );
1999    }
2000
2001    #[test]
2002    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2003    fn update_pc_jump_rel_with_non_int_res() {
2004        let instruction = Instruction {
2005            off0: 1,
2006            off1: 2,
2007            off2: 3,
2008            dst_register: Register::FP,
2009            op0_register: Register::AP,
2010            op1_addr: Op1Addr::AP,
2011            res: Res::Add,
2012            pc_update: PcUpdate::JumpRel,
2013            ap_update: ApUpdate::Regular,
2014            fp_update: FpUpdate::Regular,
2015            opcode: Opcode::NOp,
2016            opcode_extension: OpcodeExtension::Stone,
2017        };
2018
2019        let operands = Operands {
2020            dst: MaybeRelocatable::Int(Felt252::from(11)),
2021            res: Some(MaybeRelocatable::from((1, 4))),
2022            op0: MaybeRelocatable::Int(Felt252::from(9)),
2023            op1: MaybeRelocatable::Int(Felt252::from(10)),
2024        };
2025
2026        let mut vm = vm!();
2027        assert_matches!(
2028            vm.update_pc(&instruction, &operands),
2029            Err::<(), VirtualMachineError>(VirtualMachineError::JumpRelNotInt)
2030        );
2031    }
2032
2033    #[test]
2034    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2035    fn update_pc_jnz_dst_is_zero() {
2036        let instruction = Instruction {
2037            off0: 1,
2038            off1: 2,
2039            off2: 3,
2040            dst_register: Register::FP,
2041            op0_register: Register::AP,
2042            op1_addr: Op1Addr::AP,
2043            res: Res::Add,
2044            pc_update: PcUpdate::Jnz,
2045            ap_update: ApUpdate::Regular,
2046            fp_update: FpUpdate::Regular,
2047            opcode: Opcode::NOp,
2048            opcode_extension: OpcodeExtension::Stone,
2049        };
2050
2051        let operands = Operands {
2052            dst: MaybeRelocatable::Int(Felt252::from(0)),
2053            res: Some(MaybeRelocatable::Int(Felt252::from(0))),
2054            op0: MaybeRelocatable::Int(Felt252::from(9)),
2055            op1: MaybeRelocatable::Int(Felt252::from(10)),
2056        };
2057
2058        let mut vm = vm!();
2059
2060        assert_matches!(
2061            vm.update_pc(&instruction, &operands),
2062            Ok::<(), VirtualMachineError>(())
2063        );
2064        assert_eq!(vm.run_context.pc, Relocatable::from((0, 1)));
2065    }
2066
2067    #[test]
2068    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2069    fn update_pc_jnz_dst_is_not_zero() {
2070        let instruction = Instruction {
2071            off0: 1,
2072            off1: 2,
2073            off2: 3,
2074            dst_register: Register::FP,
2075            op0_register: Register::AP,
2076            op1_addr: Op1Addr::AP,
2077            res: Res::Add,
2078            pc_update: PcUpdate::Jnz,
2079            ap_update: ApUpdate::Regular,
2080            fp_update: FpUpdate::Regular,
2081            opcode: Opcode::NOp,
2082            opcode_extension: OpcodeExtension::Stone,
2083        };
2084
2085        let operands = Operands {
2086            dst: MaybeRelocatable::Int(Felt252::from(11)),
2087            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
2088            op0: MaybeRelocatable::Int(Felt252::from(9)),
2089            op1: MaybeRelocatable::Int(Felt252::from(10)),
2090        };
2091
2092        let mut vm = vm!();
2093
2094        assert_matches!(
2095            vm.update_pc(&instruction, &operands),
2096            Ok::<(), VirtualMachineError>(())
2097        );
2098        assert_eq!(vm.run_context.pc, Relocatable::from((0, 10)));
2099    }
2100
2101    #[test]
2102    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2103    fn update_registers_all_regular() {
2104        let instruction = Instruction {
2105            off0: 1,
2106            off1: 2,
2107            off2: 3,
2108            dst_register: Register::FP,
2109            op0_register: Register::AP,
2110            op1_addr: Op1Addr::AP,
2111            res: Res::Add,
2112            pc_update: PcUpdate::Regular,
2113            ap_update: ApUpdate::Regular,
2114            fp_update: FpUpdate::Regular,
2115            opcode: Opcode::NOp,
2116            opcode_extension: OpcodeExtension::Stone,
2117        };
2118
2119        let operands = Operands {
2120            dst: MaybeRelocatable::Int(Felt252::from(11)),
2121            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
2122            op0: MaybeRelocatable::Int(Felt252::from(9)),
2123            op1: MaybeRelocatable::Int(Felt252::from(10)),
2124        };
2125
2126        let mut vm = vm!();
2127        vm.run_context.pc = Relocatable::from((0, 4));
2128        vm.run_context.ap = 5;
2129        vm.run_context.fp = 6;
2130
2131        assert_matches!(
2132            vm.update_registers(&instruction, operands),
2133            Ok::<(), VirtualMachineError>(())
2134        );
2135        assert_eq!(vm.run_context.pc, Relocatable::from((0, 5)));
2136        assert_eq!(vm.run_context.ap, 5);
2137        assert_eq!(vm.run_context.fp, 6);
2138    }
2139
2140    #[test]
2141    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2142    fn update_registers_mixed_types() {
2143        let instruction = Instruction {
2144            off0: 1,
2145            off1: 2,
2146            off2: 3,
2147            dst_register: Register::FP,
2148            op0_register: Register::AP,
2149            op1_addr: Op1Addr::AP,
2150            res: Res::Add,
2151            pc_update: PcUpdate::JumpRel,
2152            ap_update: ApUpdate::Add2,
2153            fp_update: FpUpdate::Dst,
2154            opcode: Opcode::NOp,
2155            opcode_extension: OpcodeExtension::Stone,
2156        };
2157
2158        let operands = Operands {
2159            dst: MaybeRelocatable::from((1, 11)),
2160            res: Some(MaybeRelocatable::Int(Felt252::from(8))),
2161            op0: MaybeRelocatable::Int(Felt252::from(9)),
2162            op1: MaybeRelocatable::Int(Felt252::from(10)),
2163        };
2164
2165        let mut vm = vm!();
2166        run_context!(vm, 4, 5, 6);
2167
2168        assert_matches!(
2169            vm.update_registers(&instruction, operands),
2170            Ok::<(), VirtualMachineError>(())
2171        );
2172        assert_eq!(vm.run_context.pc, Relocatable::from((0, 12)));
2173        assert_eq!(vm.run_context.ap, 7);
2174        assert_eq!(vm.run_context.fp, 11);
2175    }
2176
2177    #[test]
2178    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2179    fn is_zero_int_value() {
2180        let value = MaybeRelocatable::Int(Felt252::from(1));
2181        assert!(!VirtualMachine::is_zero(&value));
2182    }
2183
2184    #[test]
2185    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2186    fn is_zero_relocatable_value() {
2187        let value = MaybeRelocatable::from((1, 2));
2188        assert!(!VirtualMachine::is_zero(&value));
2189    }
2190
2191    #[test]
2192    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2193    fn deduce_op0_opcode_call() {
2194        let instruction = Instruction {
2195            off0: 1,
2196            off1: 2,
2197            off2: 3,
2198            dst_register: Register::FP,
2199            op0_register: Register::AP,
2200            op1_addr: Op1Addr::AP,
2201            res: Res::Add,
2202            pc_update: PcUpdate::Jump,
2203            ap_update: ApUpdate::Regular,
2204            fp_update: FpUpdate::Regular,
2205            opcode: Opcode::Call,
2206            opcode_extension: OpcodeExtension::Stone,
2207        };
2208
2209        let vm = vm!();
2210
2211        assert_matches!(
2212            vm.deduce_op0(&instruction, None, None),
2213            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2214                Some(x),
2215                None
2216            )) if x == MaybeRelocatable::from((0, 1))
2217        );
2218    }
2219
2220    #[test]
2221    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2222    fn deduce_op0_opcode_assert_eq_res_add_with_optionals() {
2223        let instruction = Instruction {
2224            off0: 1,
2225            off1: 2,
2226            off2: 3,
2227            dst_register: Register::FP,
2228            op0_register: Register::AP,
2229            op1_addr: Op1Addr::AP,
2230            res: Res::Add,
2231            pc_update: PcUpdate::Jump,
2232            ap_update: ApUpdate::Regular,
2233            fp_update: FpUpdate::Regular,
2234            opcode: Opcode::AssertEq,
2235            opcode_extension: OpcodeExtension::Stone,
2236        };
2237
2238        let vm = vm!();
2239
2240        let dst = MaybeRelocatable::Int(Felt252::from(3));
2241        let op1 = MaybeRelocatable::Int(Felt252::from(2));
2242
2243        assert_matches!(
2244            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2245            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2246                x,
2247                y
2248            )) if x == Some(MaybeRelocatable::Int(Felt252::from(1))) &&
2249                    y == Some(MaybeRelocatable::Int(Felt252::from(3)))
2250        );
2251    }
2252
2253    #[test]
2254    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2255    fn deduce_op0_opcode_assert_eq_res_add_without_optionals() {
2256        let instruction = Instruction {
2257            off0: 1,
2258            off1: 2,
2259            off2: 3,
2260            dst_register: Register::FP,
2261            op0_register: Register::AP,
2262            op1_addr: Op1Addr::AP,
2263            res: Res::Add,
2264            pc_update: PcUpdate::Jump,
2265            ap_update: ApUpdate::Regular,
2266            fp_update: FpUpdate::Regular,
2267            opcode: Opcode::AssertEq,
2268            opcode_extension: OpcodeExtension::Stone,
2269        };
2270
2271        let vm = vm!();
2272
2273        assert_matches!(
2274            vm.deduce_op0(&instruction, None, None),
2275            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2276                None, None
2277            ))
2278        );
2279    }
2280
2281    #[test]
2282    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2283    fn deduce_op0_opcode_assert_eq_res_mul_non_zero_op1() {
2284        let instruction = Instruction {
2285            off0: 1,
2286            off1: 2,
2287            off2: 3,
2288            dst_register: Register::FP,
2289            op0_register: Register::AP,
2290            op1_addr: Op1Addr::AP,
2291            res: Res::Mul,
2292            pc_update: PcUpdate::Jump,
2293            ap_update: ApUpdate::Regular,
2294            fp_update: FpUpdate::Regular,
2295            opcode: Opcode::AssertEq,
2296            opcode_extension: OpcodeExtension::Stone,
2297        };
2298
2299        let vm = vm!();
2300
2301        let dst = MaybeRelocatable::Int(Felt252::from(4));
2302        let op1 = MaybeRelocatable::Int(Felt252::from(2));
2303
2304        assert_matches!(
2305            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2306            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2307                Some(x),
2308                Some(y)
2309            )) if x == MaybeRelocatable::Int(Felt252::from(2)) &&
2310                    y == MaybeRelocatable::Int(Felt252::from(4))
2311        );
2312    }
2313
2314    #[test]
2315    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2316    fn deduce_op0_opcode_assert_eq_res_mul_zero_op1() {
2317        let instruction = Instruction {
2318            off0: 1,
2319            off1: 2,
2320            off2: 3,
2321            dst_register: Register::FP,
2322            op0_register: Register::AP,
2323            op1_addr: Op1Addr::AP,
2324            res: Res::Mul,
2325            pc_update: PcUpdate::Jump,
2326            ap_update: ApUpdate::Regular,
2327            fp_update: FpUpdate::Regular,
2328            opcode: Opcode::AssertEq,
2329            opcode_extension: OpcodeExtension::Stone,
2330        };
2331
2332        let vm = vm!();
2333
2334        let dst = MaybeRelocatable::Int(Felt252::from(4));
2335        let op1 = MaybeRelocatable::Int(Felt252::from(0));
2336        assert_matches!(
2337            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2338            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2339                None, None
2340            ))
2341        );
2342    }
2343
2344    #[test]
2345    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2346    fn deduce_op0_opcode_assert_eq_res_op1() {
2347        let instruction = Instruction {
2348            off0: 1,
2349            off1: 2,
2350            off2: 3,
2351            dst_register: Register::FP,
2352            op0_register: Register::AP,
2353            op1_addr: Op1Addr::AP,
2354            res: Res::Op1,
2355            pc_update: PcUpdate::Jump,
2356            ap_update: ApUpdate::Regular,
2357            fp_update: FpUpdate::Regular,
2358            opcode: Opcode::AssertEq,
2359            opcode_extension: OpcodeExtension::Stone,
2360        };
2361
2362        let vm = vm!();
2363
2364        let dst = MaybeRelocatable::Int(Felt252::from(4));
2365        let op1 = MaybeRelocatable::Int(Felt252::from(0));
2366        assert_matches!(
2367            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2368            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2369                None, None
2370            ))
2371        );
2372    }
2373
2374    #[test]
2375    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2376    fn deduce_op0_opcode_ret() {
2377        let instruction = Instruction {
2378            off0: 1,
2379            off1: 2,
2380            off2: 3,
2381            dst_register: Register::FP,
2382            op0_register: Register::AP,
2383            op1_addr: Op1Addr::AP,
2384            res: Res::Mul,
2385            pc_update: PcUpdate::Jump,
2386            ap_update: ApUpdate::Regular,
2387            fp_update: FpUpdate::Regular,
2388            opcode: Opcode::Ret,
2389            opcode_extension: OpcodeExtension::Stone,
2390        };
2391
2392        let vm = vm!();
2393
2394        let dst = MaybeRelocatable::Int(Felt252::from(4));
2395        let op1 = MaybeRelocatable::Int(Felt252::from(0));
2396
2397        assert_matches!(
2398            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2399            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2400                None, None
2401            ))
2402        );
2403    }
2404
2405    #[test]
2406    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2407    fn deduce_op0_qm31_add_int_operands() {
2408        let instruction = Instruction {
2409            off0: 1,
2410            off1: 2,
2411            off2: 3,
2412            dst_register: Register::FP,
2413            op0_register: Register::AP,
2414            op1_addr: Op1Addr::AP,
2415            res: Res::Add,
2416            pc_update: PcUpdate::Regular,
2417            ap_update: ApUpdate::Regular,
2418            fp_update: FpUpdate::Regular,
2419            opcode: Opcode::AssertEq,
2420            opcode_extension: OpcodeExtension::QM31Operation,
2421        };
2422
2423        let vm = vm!();
2424
2425        let op1_coordinates = [STWO_PRIME - 10, 5, STWO_PRIME - 5, 1];
2426        let dst_coordinates = [STWO_PRIME - 4, 2, 12, 3];
2427        let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2428        let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2429        let op1 = MaybeRelocatable::Int(op1_packed);
2430        let dst = MaybeRelocatable::Int(dst_packed);
2431        assert_matches!(
2432            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2433            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2434                x,
2435                y
2436            )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([6, STWO_PRIME-3, 17, 2]))) &&
2437                    y == Some(MaybeRelocatable::Int(dst_packed))
2438        );
2439    }
2440
2441    #[test]
2442    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2443    fn deduce_op0_qm31_mul_int_operands() {
2444        let instruction = Instruction {
2445            off0: 1,
2446            off1: 2,
2447            off2: 3,
2448            dst_register: Register::FP,
2449            op0_register: Register::AP,
2450            op1_addr: Op1Addr::AP,
2451            res: Res::Mul,
2452            pc_update: PcUpdate::Regular,
2453            ap_update: ApUpdate::Regular,
2454            fp_update: FpUpdate::Regular,
2455            opcode: Opcode::AssertEq,
2456            opcode_extension: OpcodeExtension::QM31Operation,
2457        };
2458
2459        let vm = vm!();
2460
2461        let op1_coordinates = [0, 0, 1, 0];
2462        let dst_coordinates = [0, 0, 0, 1];
2463        let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2464        let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2465        let op1 = MaybeRelocatable::Int(op1_packed);
2466        let dst = MaybeRelocatable::Int(dst_packed);
2467        assert_matches!(
2468            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2469            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2470                x,
2471                y
2472            )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([0, 1, 0, 0]))) &&
2473                    y == Some(MaybeRelocatable::Int(dst_packed))
2474        );
2475    }
2476
2477    #[test]
2478    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2479    fn deduce_op0_blake_finalize_add_int_operands() {
2480        let instruction = Instruction {
2481            off0: 1,
2482            off1: 2,
2483            off2: 3,
2484            dst_register: Register::FP,
2485            op0_register: Register::AP,
2486            op1_addr: Op1Addr::AP,
2487            res: Res::Add,
2488            pc_update: PcUpdate::Regular,
2489            ap_update: ApUpdate::Regular,
2490            fp_update: FpUpdate::Regular,
2491            opcode: Opcode::AssertEq,
2492            opcode_extension: OpcodeExtension::BlakeFinalize,
2493        };
2494
2495        let vm = vm!();
2496
2497        let op1 = MaybeRelocatable::Int(Felt252::from(5));
2498        let dst = MaybeRelocatable::Int(Felt252::from(15));
2499        assert_matches!(
2500            vm.deduce_op0(&instruction, Some(&dst), Some(&op1)),
2501            Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_sub"
2502        );
2503    }
2504
2505    #[test]
2506    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2507    fn deduce_op1_opcode_call() {
2508        let instruction = Instruction {
2509            off0: 1,
2510            off1: 2,
2511            off2: 3,
2512            dst_register: Register::FP,
2513            op0_register: Register::AP,
2514            op1_addr: Op1Addr::AP,
2515            res: Res::Add,
2516            pc_update: PcUpdate::Jump,
2517            ap_update: ApUpdate::Regular,
2518            fp_update: FpUpdate::Regular,
2519            opcode: Opcode::Call,
2520            opcode_extension: OpcodeExtension::Stone,
2521        };
2522
2523        let vm = vm!();
2524
2525        assert_matches!(
2526            vm.deduce_op1(&instruction, None, None),
2527            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2528                None, None
2529            ))
2530        );
2531    }
2532
2533    #[test]
2534    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2535    fn deduce_op1_opcode_assert_eq_res_add_with_optionals() {
2536        let instruction = Instruction {
2537            off0: 1,
2538            off1: 2,
2539            off2: 3,
2540            dst_register: Register::FP,
2541            op0_register: Register::AP,
2542            op1_addr: Op1Addr::AP,
2543            res: Res::Add,
2544            pc_update: PcUpdate::Jump,
2545            ap_update: ApUpdate::Regular,
2546            fp_update: FpUpdate::Regular,
2547            opcode: Opcode::AssertEq,
2548            opcode_extension: OpcodeExtension::Stone,
2549        };
2550
2551        let vm = vm!();
2552
2553        let dst = MaybeRelocatable::Int(Felt252::from(3));
2554        let op0 = MaybeRelocatable::Int(Felt252::from(2));
2555        assert_matches!(
2556            vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2557            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2558                x,
2559                y
2560            )) if x == Some(MaybeRelocatable::Int(Felt252::from(1))) &&
2561                    y == Some(MaybeRelocatable::Int(Felt252::from(3)))
2562        );
2563    }
2564
2565    #[test]
2566    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2567    fn deduce_op1_opcode_assert_eq_res_add_without_optionals() {
2568        let instruction = Instruction {
2569            off0: 1,
2570            off1: 2,
2571            off2: 3,
2572            dst_register: Register::FP,
2573            op0_register: Register::AP,
2574            op1_addr: Op1Addr::AP,
2575            res: Res::Add,
2576            pc_update: PcUpdate::Jump,
2577            ap_update: ApUpdate::Regular,
2578            fp_update: FpUpdate::Regular,
2579            opcode: Opcode::AssertEq,
2580            opcode_extension: OpcodeExtension::Stone,
2581        };
2582
2583        let vm = vm!();
2584        assert_matches!(
2585            vm.deduce_op1(&instruction, None, None),
2586            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2587                None, None
2588            ))
2589        );
2590    }
2591
2592    #[test]
2593    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2594    fn deduce_op1_opcode_assert_eq_res_mul_non_zero_op0() {
2595        let instruction = Instruction {
2596            off0: 1,
2597            off1: 2,
2598            off2: 3,
2599            dst_register: Register::FP,
2600            op0_register: Register::AP,
2601            op1_addr: Op1Addr::AP,
2602            res: Res::Mul,
2603            pc_update: PcUpdate::Jump,
2604            ap_update: ApUpdate::Regular,
2605            fp_update: FpUpdate::Regular,
2606            opcode: Opcode::AssertEq,
2607            opcode_extension: OpcodeExtension::Stone,
2608        };
2609
2610        let vm = vm!();
2611
2612        let dst = MaybeRelocatable::Int(Felt252::from(4));
2613        let op0 = MaybeRelocatable::Int(Felt252::from(2));
2614        assert_matches!(
2615            vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2616            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2617                x,
2618                y
2619            )) if x == Some(MaybeRelocatable::Int(Felt252::from(2))) &&
2620                    y == Some(MaybeRelocatable::Int(Felt252::from(4)))
2621        );
2622    }
2623
2624    #[test]
2625    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2626    fn deduce_op1_opcode_assert_eq_res_mul_zero_op0() {
2627        let instruction = Instruction {
2628            off0: 1,
2629            off1: 2,
2630            off2: 3,
2631            dst_register: Register::FP,
2632            op0_register: Register::AP,
2633            op1_addr: Op1Addr::AP,
2634            res: Res::Mul,
2635            pc_update: PcUpdate::Jump,
2636            ap_update: ApUpdate::Regular,
2637            fp_update: FpUpdate::Regular,
2638            opcode: Opcode::AssertEq,
2639            opcode_extension: OpcodeExtension::Stone,
2640        };
2641
2642        let vm = vm!();
2643
2644        let dst = MaybeRelocatable::Int(Felt252::from(4));
2645        let op0 = MaybeRelocatable::Int(Felt252::from(0));
2646        assert_matches!(
2647            vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2648            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2649                None, None
2650            ))
2651        );
2652    }
2653
2654    #[test]
2655    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2656    fn deduce_op1_opcode_assert_eq_res_op1_without_dst() {
2657        let instruction = Instruction {
2658            off0: 1,
2659            off1: 2,
2660            off2: 3,
2661            dst_register: Register::FP,
2662            op0_register: Register::AP,
2663            op1_addr: Op1Addr::AP,
2664            res: Res::Op1,
2665            pc_update: PcUpdate::Jump,
2666            ap_update: ApUpdate::Regular,
2667            fp_update: FpUpdate::Regular,
2668            opcode: Opcode::AssertEq,
2669            opcode_extension: OpcodeExtension::Stone,
2670        };
2671
2672        let vm = vm!();
2673
2674        let op0 = MaybeRelocatable::Int(Felt252::from(0));
2675        assert_matches!(
2676            vm.deduce_op1(&instruction, None, Some(op0)),
2677            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2678                None, None
2679            ))
2680        );
2681    }
2682
2683    #[test]
2684    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2685    fn deduce_op1_opcode_assert_eq_res_op1_with_dst() {
2686        let instruction = Instruction {
2687            off0: 1,
2688            off1: 2,
2689            off2: 3,
2690            dst_register: Register::FP,
2691            op0_register: Register::AP,
2692            op1_addr: Op1Addr::AP,
2693            res: Res::Op1,
2694            pc_update: PcUpdate::Jump,
2695            ap_update: ApUpdate::Regular,
2696            fp_update: FpUpdate::Regular,
2697            opcode: Opcode::AssertEq,
2698            opcode_extension: OpcodeExtension::Stone,
2699        };
2700
2701        let vm = vm!();
2702
2703        let dst = MaybeRelocatable::Int(Felt252::from(7));
2704        assert_matches!(
2705            vm.deduce_op1(&instruction, Some(&dst), None),
2706            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2707                x,
2708                y
2709            )) if x == Some(MaybeRelocatable::Int(Felt252::from(7))) &&
2710                    y == Some(MaybeRelocatable::Int(Felt252::from(7)))
2711        );
2712    }
2713
2714    #[test]
2715    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2716    fn deduce_op1_qm31_add_int_operands() {
2717        let instruction = Instruction {
2718            off0: 1,
2719            off1: 2,
2720            off2: 3,
2721            dst_register: Register::FP,
2722            op0_register: Register::AP,
2723            op1_addr: Op1Addr::AP,
2724            res: Res::Add,
2725            pc_update: PcUpdate::Regular,
2726            ap_update: ApUpdate::Regular,
2727            fp_update: FpUpdate::Regular,
2728            opcode: Opcode::AssertEq,
2729            opcode_extension: OpcodeExtension::QM31Operation,
2730        };
2731
2732        let vm = vm!();
2733
2734        let op0_coordinates = [4, STWO_PRIME - 13, 3, 7];
2735        let dst_coordinates = [8, 7, 6, 5];
2736        let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2737        let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2738        let op0 = MaybeRelocatable::Int(op0_packed);
2739        let dst = MaybeRelocatable::Int(dst_packed);
2740        assert_matches!(
2741            vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2742            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2743                x,
2744                y
2745            )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([4, 20, 3, STWO_PRIME - 2]))) &&
2746                    y == Some(MaybeRelocatable::Int(dst_packed))
2747        );
2748    }
2749
2750    #[test]
2751    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2752    fn deduce_op1_qm31_mul_int_operands() {
2753        let instruction = Instruction {
2754            off0: 1,
2755            off1: 2,
2756            off2: 3,
2757            dst_register: Register::FP,
2758            op0_register: Register::AP,
2759            op1_addr: Op1Addr::AP,
2760            res: Res::Mul,
2761            pc_update: PcUpdate::Regular,
2762            ap_update: ApUpdate::Regular,
2763            fp_update: FpUpdate::Regular,
2764            opcode: Opcode::AssertEq,
2765            opcode_extension: OpcodeExtension::QM31Operation,
2766        };
2767
2768        let vm = vm!();
2769
2770        let op0_coordinates = [0, 1, 0, 0];
2771        let dst_coordinates = [STWO_PRIME - 1, 0, 0, 0];
2772        let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2773        let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates);
2774        let op0 = MaybeRelocatable::Int(op0_packed);
2775        let dst = MaybeRelocatable::Int(dst_packed);
2776        assert_matches!(
2777            vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2778            Ok::<(Option<MaybeRelocatable>, Option<MaybeRelocatable>), VirtualMachineError>((
2779                x,
2780                y
2781            )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([0, 1, 0, 0]))) &&
2782                    y == Some(MaybeRelocatable::Int(dst_packed))
2783        );
2784    }
2785
2786    #[test]
2787    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2788    fn deduce_op1_blake_mul_int_operands() {
2789        let instruction = Instruction {
2790            off0: 1,
2791            off1: 2,
2792            off2: 3,
2793            dst_register: Register::FP,
2794            op0_register: Register::AP,
2795            op1_addr: Op1Addr::AP,
2796            res: Res::Mul,
2797            pc_update: PcUpdate::Regular,
2798            ap_update: ApUpdate::Regular,
2799            fp_update: FpUpdate::Regular,
2800            opcode: Opcode::AssertEq,
2801            opcode_extension: OpcodeExtension::Blake,
2802        };
2803
2804        let vm = vm!();
2805
2806        let op0 = MaybeRelocatable::Int(Felt252::from(4));
2807        let dst = MaybeRelocatable::Int(Felt252::from(16));
2808        assert_matches!(
2809            vm.deduce_op1(&instruction, Some(&dst), Some(op0)),
2810            Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_div"
2811        );
2812    }
2813
2814    #[test]
2815    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2816    fn compute_res_op1() {
2817        let instruction = Instruction {
2818            off0: 1,
2819            off1: 2,
2820            off2: 3,
2821            dst_register: Register::FP,
2822            op0_register: Register::AP,
2823            op1_addr: Op1Addr::AP,
2824            res: Res::Op1,
2825            pc_update: PcUpdate::Jump,
2826            ap_update: ApUpdate::Regular,
2827            fp_update: FpUpdate::Regular,
2828            opcode: Opcode::AssertEq,
2829            opcode_extension: OpcodeExtension::Stone,
2830        };
2831
2832        let vm = vm!();
2833
2834        let op1 = MaybeRelocatable::Int(Felt252::from(7));
2835        let op0 = MaybeRelocatable::Int(Felt252::from(9));
2836        assert_matches!(
2837            vm.compute_res(&instruction, &op0, &op1),
2838            Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2839                x
2840            ))) if x == Felt252::from(7)
2841        );
2842    }
2843
2844    #[test]
2845    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2846    fn compute_res_add() {
2847        let instruction = Instruction {
2848            off0: 1,
2849            off1: 2,
2850            off2: 3,
2851            dst_register: Register::FP,
2852            op0_register: Register::AP,
2853            op1_addr: Op1Addr::AP,
2854            res: Res::Add,
2855            pc_update: PcUpdate::Jump,
2856            ap_update: ApUpdate::Regular,
2857            fp_update: FpUpdate::Regular,
2858            opcode: Opcode::AssertEq,
2859            opcode_extension: OpcodeExtension::Stone,
2860        };
2861
2862        let vm = vm!();
2863
2864        let op1 = MaybeRelocatable::Int(Felt252::from(7));
2865        let op0 = MaybeRelocatable::Int(Felt252::from(9));
2866        assert_matches!(
2867            vm.compute_res(&instruction, &op0, &op1),
2868            Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2869                x
2870            ))) if x == Felt252::from(16)
2871        );
2872    }
2873
2874    #[test]
2875    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2876    fn compute_res_mul_int_operands() {
2877        let instruction = Instruction {
2878            off0: 1,
2879            off1: 2,
2880            off2: 3,
2881            dst_register: Register::FP,
2882            op0_register: Register::AP,
2883            op1_addr: Op1Addr::AP,
2884            res: Res::Mul,
2885            pc_update: PcUpdate::Jump,
2886            ap_update: ApUpdate::Regular,
2887            fp_update: FpUpdate::Regular,
2888            opcode: Opcode::AssertEq,
2889            opcode_extension: OpcodeExtension::Stone,
2890        };
2891
2892        let vm = vm!();
2893
2894        let op1 = MaybeRelocatable::Int(Felt252::from(7));
2895        let op0 = MaybeRelocatable::Int(Felt252::from(9));
2896        assert_matches!(
2897            vm.compute_res(&instruction, &op0, &op1),
2898            Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2899                x
2900            ))) if x == Felt252::from(63)
2901        );
2902    }
2903
2904    #[test]
2905    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2906    fn compute_res_mul_relocatable_values() {
2907        let instruction = Instruction {
2908            off0: 1,
2909            off1: 2,
2910            off2: 3,
2911            dst_register: Register::FP,
2912            op0_register: Register::AP,
2913            op1_addr: Op1Addr::AP,
2914            res: Res::Mul,
2915            pc_update: PcUpdate::Jump,
2916            ap_update: ApUpdate::Regular,
2917            fp_update: FpUpdate::Regular,
2918            opcode: Opcode::AssertEq,
2919            opcode_extension: OpcodeExtension::Stone,
2920        };
2921
2922        let vm = vm!();
2923
2924        let op1 = MaybeRelocatable::from((2, 3));
2925        let op0 = MaybeRelocatable::from((2, 6));
2926        assert_matches!(
2927            vm.compute_res(&instruction, &op0, &op1),
2928            Err(VirtualMachineError::ComputeResRelocatableMul(bx)) if *bx == (op0, op1)
2929        );
2930    }
2931
2932    #[test]
2933    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2934    fn compute_res_qm31_add_relocatable_values() {
2935        let instruction = Instruction {
2936            off0: 1,
2937            off1: 2,
2938            off2: 3,
2939            dst_register: Register::FP,
2940            op0_register: Register::AP,
2941            op1_addr: Op1Addr::AP,
2942            res: Res::Add,
2943            pc_update: PcUpdate::Regular,
2944            ap_update: ApUpdate::Regular,
2945            fp_update: FpUpdate::Regular,
2946            opcode: Opcode::AssertEq,
2947            opcode_extension: OpcodeExtension::QM31Operation,
2948        };
2949
2950        let vm = vm!();
2951
2952        let op1 = MaybeRelocatable::from((2, 3));
2953        let op0 = MaybeRelocatable::from(7);
2954        assert_matches!(
2955            vm.compute_res(&instruction, &op0, &op1),
2956            Err(VirtualMachineError::Math(MathError::RelocatableQM31Add(bx))) if *bx == (op0, op1)
2957        );
2958    }
2959
2960    #[test]
2961    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2962    fn compute_res_qm31_add_int_operands() {
2963        let instruction = Instruction {
2964            off0: 1,
2965            off1: 2,
2966            off2: 3,
2967            dst_register: Register::FP,
2968            op0_register: Register::AP,
2969            op1_addr: Op1Addr::AP,
2970            res: Res::Add,
2971            pc_update: PcUpdate::Regular,
2972            ap_update: ApUpdate::Regular,
2973            fp_update: FpUpdate::Regular,
2974            opcode: Opcode::AssertEq,
2975            opcode_extension: OpcodeExtension::QM31Operation,
2976        };
2977
2978        let vm = vm!();
2979
2980        let op1_coordinates = [1, 2, 3, 4];
2981        let op0_coordinates = [10, 11, STWO_PRIME - 1, 13];
2982        let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
2983        let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
2984        let op1 = MaybeRelocatable::Int(op1_packed);
2985        let op0 = MaybeRelocatable::Int(op0_packed);
2986        assert_matches!(
2987            vm.compute_res(&instruction, &op0, &op1),
2988            Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
2989                x
2990            ))) if x == qm31_coordinates_to_packed_reduced([11, 13, 2, 17])
2991        );
2992    }
2993
2994    #[test]
2995    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2996    fn compute_res_qm31_mul_int_operands() {
2997        let instruction = Instruction {
2998            off0: 1,
2999            off1: 2,
3000            off2: 3,
3001            dst_register: Register::FP,
3002            op0_register: Register::AP,
3003            op1_addr: Op1Addr::AP,
3004            res: Res::Mul,
3005            pc_update: PcUpdate::Regular,
3006            ap_update: ApUpdate::Regular,
3007            fp_update: FpUpdate::Regular,
3008            opcode: Opcode::AssertEq,
3009            opcode_extension: OpcodeExtension::QM31Operation,
3010        };
3011
3012        let vm = vm!();
3013
3014        let op1_coordinates = [0, 0, 1, 0];
3015        let op0_coordinates = [0, 0, 1, 0];
3016        let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates);
3017        let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates);
3018        let op1 = MaybeRelocatable::Int(op1_packed);
3019        let op0 = MaybeRelocatable::Int(op0_packed);
3020        assert_matches!(
3021            vm.compute_res(&instruction, &op0, &op1),
3022            Ok::<Option<MaybeRelocatable>, VirtualMachineError>(Some(MaybeRelocatable::Int(
3023                x
3024            ))) if x == qm31_coordinates_to_packed_reduced([2, 1, 0, 0])
3025        );
3026    }
3027
3028    #[test]
3029    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3030    fn compute_res_blake_mul_int_operands() {
3031        let instruction = Instruction {
3032            off0: 1,
3033            off1: 2,
3034            off2: 3,
3035            dst_register: Register::FP,
3036            op0_register: Register::AP,
3037            op1_addr: Op1Addr::AP,
3038            res: Res::Mul,
3039            pc_update: PcUpdate::Regular,
3040            ap_update: ApUpdate::Regular,
3041            fp_update: FpUpdate::Regular,
3042            opcode: Opcode::AssertEq,
3043            opcode_extension: OpcodeExtension::Blake,
3044        };
3045
3046        let vm = vm!();
3047
3048        let op1 = MaybeRelocatable::Int(Felt252::from(11));
3049        let op0 = MaybeRelocatable::Int(Felt252::from(12));
3050        assert_matches!(
3051            vm.compute_res(&instruction, &op0, &op1),
3052            Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension(ref message)) if message.as_ref() == "typed_mul"
3053        );
3054    }
3055
3056    #[test]
3057    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3058    fn compute_res_unconstrained() {
3059        let instruction = Instruction {
3060            off0: 1,
3061            off1: 2,
3062            off2: 3,
3063            dst_register: Register::FP,
3064            op0_register: Register::AP,
3065            op1_addr: Op1Addr::AP,
3066            res: Res::Unconstrained,
3067            pc_update: PcUpdate::Jump,
3068            ap_update: ApUpdate::Regular,
3069            fp_update: FpUpdate::Regular,
3070            opcode: Opcode::AssertEq,
3071            opcode_extension: OpcodeExtension::Stone,
3072        };
3073
3074        let vm = vm!();
3075
3076        let op1 = MaybeRelocatable::Int(Felt252::from(7));
3077        let op0 = MaybeRelocatable::Int(Felt252::from(9));
3078        assert_matches!(
3079            vm.compute_res(&instruction, &op0, &op1),
3080            Ok::<Option<MaybeRelocatable>, VirtualMachineError>(None)
3081        );
3082    }
3083
3084    #[test]
3085    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3086    fn deduce_dst_opcode_assert_eq_with_res() {
3087        let instruction = Instruction {
3088            off0: 1,
3089            off1: 2,
3090            off2: 3,
3091            dst_register: Register::FP,
3092            op0_register: Register::AP,
3093            op1_addr: Op1Addr::AP,
3094            res: Res::Unconstrained,
3095            pc_update: PcUpdate::Jump,
3096            ap_update: ApUpdate::Regular,
3097            fp_update: FpUpdate::Regular,
3098            opcode: Opcode::AssertEq,
3099            opcode_extension: OpcodeExtension::Stone,
3100        };
3101
3102        let vm = vm!();
3103
3104        let res = MaybeRelocatable::Int(Felt252::from(7));
3105        assert_eq!(
3106            MaybeRelocatable::Int(Felt252::from(7)),
3107            vm.deduce_dst(&instruction, &Some(res)).unwrap()
3108        );
3109    }
3110
3111    #[test]
3112    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3113    fn deduce_dst_opcode_assert_eq_without_res() {
3114        let instruction = Instruction {
3115            off0: 1,
3116            off1: 2,
3117            off2: 3,
3118            dst_register: Register::FP,
3119            op0_register: Register::AP,
3120            op1_addr: Op1Addr::AP,
3121            res: Res::Unconstrained,
3122            pc_update: PcUpdate::Jump,
3123            ap_update: ApUpdate::Regular,
3124            fp_update: FpUpdate::Regular,
3125            opcode: Opcode::AssertEq,
3126            opcode_extension: OpcodeExtension::Stone,
3127        };
3128
3129        let vm = vm!();
3130
3131        assert!(vm.deduce_dst(&instruction, &None).is_err());
3132    }
3133
3134    #[test]
3135    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3136    fn deduce_dst_opcode_call() {
3137        let instruction = Instruction {
3138            off0: 1,
3139            off1: 2,
3140            off2: 3,
3141            dst_register: Register::FP,
3142            op0_register: Register::AP,
3143            op1_addr: Op1Addr::AP,
3144            res: Res::Unconstrained,
3145            pc_update: PcUpdate::Jump,
3146            ap_update: ApUpdate::Regular,
3147            fp_update: FpUpdate::Regular,
3148            opcode: Opcode::Call,
3149            opcode_extension: OpcodeExtension::Stone,
3150        };
3151
3152        let vm = vm!();
3153
3154        assert_eq!(
3155            MaybeRelocatable::from((1, 0)),
3156            vm.deduce_dst(&instruction, &None).unwrap()
3157        );
3158    }
3159
3160    #[test]
3161    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3162    fn deduce_dst_opcode_ret() {
3163        let instruction = Instruction {
3164            off0: 1,
3165            off1: 2,
3166            off2: 3,
3167            dst_register: Register::FP,
3168            op0_register: Register::AP,
3169            op1_addr: Op1Addr::AP,
3170            res: Res::Unconstrained,
3171            pc_update: PcUpdate::Jump,
3172            ap_update: ApUpdate::Regular,
3173            fp_update: FpUpdate::Regular,
3174            opcode: Opcode::Ret,
3175            opcode_extension: OpcodeExtension::Stone,
3176        };
3177
3178        let vm = vm!();
3179
3180        assert!(vm.deduce_dst(&instruction, &None).is_err());
3181    }
3182
3183    #[test]
3184    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3185    fn compute_operands_add_ap() {
3186        let inst = Instruction {
3187            off0: 0,
3188            off1: 1,
3189            off2: 2,
3190            dst_register: Register::AP,
3191            op0_register: Register::AP,
3192            op1_addr: Op1Addr::AP,
3193            res: Res::Add,
3194            pc_update: PcUpdate::Regular,
3195            ap_update: ApUpdate::Regular,
3196            fp_update: FpUpdate::Regular,
3197            opcode: Opcode::NOp,
3198            opcode_extension: OpcodeExtension::Stone,
3199        };
3200
3201        let mut vm = vm!();
3202        for _ in 0..2 {
3203            vm.segments.add();
3204        }
3205
3206        vm.segments.memory.data.push(Vec::new());
3207        let dst_addr = Relocatable::from((1, 0));
3208        let dst_addr_value = MaybeRelocatable::Int(Felt252::from(5));
3209        let op0_addr = Relocatable::from((1, 1));
3210        let op0_addr_value = MaybeRelocatable::Int(Felt252::from(2));
3211        let op1_addr = Relocatable::from((1, 2));
3212        let op1_addr_value = MaybeRelocatable::Int(Felt252::from(3));
3213        vm.segments
3214            .memory
3215            .insert(dst_addr, &dst_addr_value)
3216            .unwrap();
3217        vm.segments
3218            .memory
3219            .insert(op0_addr, &op0_addr_value)
3220            .unwrap();
3221        vm.segments
3222            .memory
3223            .insert(op1_addr, &op1_addr_value)
3224            .unwrap();
3225
3226        let expected_operands = Operands {
3227            dst: dst_addr_value.clone(),
3228            res: Some(dst_addr_value.clone()),
3229            op0: op0_addr_value.clone(),
3230            op1: op1_addr_value.clone(),
3231        };
3232
3233        let expected_addresses = OperandsAddresses {
3234            dst_addr,
3235            op0_addr,
3236            op1_addr,
3237        };
3238
3239        let (operands, addresses, _) = vm.compute_operands(&inst).unwrap();
3240        assert!(operands == expected_operands);
3241        assert!(addresses == expected_addresses);
3242    }
3243
3244    #[test]
3245    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3246    fn compute_operands_mul_fp() {
3247        let inst = Instruction {
3248            off0: 0,
3249            off1: 1,
3250            off2: 2,
3251            dst_register: Register::FP,
3252            op0_register: Register::FP,
3253            op1_addr: Op1Addr::FP,
3254            res: Res::Mul,
3255            pc_update: PcUpdate::Regular,
3256            ap_update: ApUpdate::Regular,
3257            fp_update: FpUpdate::Regular,
3258            opcode: Opcode::NOp,
3259            opcode_extension: OpcodeExtension::Stone,
3260        };
3261        let mut vm = vm!();
3262        //Create program and execution segments
3263        for _ in 0..2 {
3264            vm.segments.add();
3265        }
3266        vm.segments.memory.data.push(Vec::new());
3267        let dst_addr = relocatable!(1, 0);
3268        let dst_addr_value = mayberelocatable!(6);
3269        let op0_addr = relocatable!(1, 1);
3270        let op0_addr_value = mayberelocatable!(2);
3271        let op1_addr = relocatable!(1, 2);
3272        let op1_addr_value = mayberelocatable!(3);
3273        vm.segments
3274            .memory
3275            .insert(dst_addr, &dst_addr_value)
3276            .unwrap();
3277        vm.segments
3278            .memory
3279            .insert(op0_addr, &op0_addr_value)
3280            .unwrap();
3281        vm.segments
3282            .memory
3283            .insert(op1_addr, &op1_addr_value)
3284            .unwrap();
3285
3286        let expected_operands = Operands {
3287            dst: dst_addr_value.clone(),
3288            res: Some(dst_addr_value.clone()),
3289            op0: op0_addr_value.clone(),
3290            op1: op1_addr_value.clone(),
3291        };
3292
3293        let expected_addresses = OperandsAddresses {
3294            dst_addr,
3295            op0_addr,
3296            op1_addr,
3297        };
3298
3299        let (operands, addresses, _) = vm.compute_operands(&inst).unwrap();
3300        assert!(operands == expected_operands);
3301        assert!(addresses == expected_addresses);
3302    }
3303
3304    #[test]
3305    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3306    fn compute_jnz() {
3307        let instruction = Instruction {
3308            off0: 1,
3309            off1: 1,
3310            off2: 1,
3311            dst_register: Register::AP,
3312            op0_register: Register::AP,
3313            op1_addr: Op1Addr::Imm,
3314            res: Res::Unconstrained,
3315            pc_update: PcUpdate::Jnz,
3316            ap_update: ApUpdate::Regular,
3317            fp_update: FpUpdate::Regular,
3318            opcode: Opcode::NOp,
3319            opcode_extension: OpcodeExtension::Stone,
3320        };
3321
3322        let mut vm = vm!();
3323        vm.segments = segments![
3324            ((0, 0), 0x206800180018001_i64),
3325            ((1, 1), 0x4),
3326            ((0, 1), 0x4)
3327        ];
3328
3329        let expected_operands = Operands {
3330            dst: mayberelocatable!(4),
3331            res: None,
3332            op0: mayberelocatable!(4),
3333            op1: mayberelocatable!(4),
3334        };
3335
3336        let expected_addresses = OperandsAddresses {
3337            dst_addr: relocatable!(1, 1),
3338            op0_addr: relocatable!(1, 1),
3339            op1_addr: relocatable!(0, 1),
3340        };
3341
3342        let (operands, addresses, _) = vm.compute_operands(&instruction).unwrap();
3343        assert!(operands == expected_operands);
3344        assert!(addresses == expected_addresses);
3345        let mut hint_processor = BuiltinHintProcessor::new_empty();
3346        assert_matches!(
3347            vm.step(
3348                &mut hint_processor,
3349                exec_scopes_ref!(),
3350                &mut Vec::new(),
3351                #[cfg(feature = "extensive_hints")]
3352                &mut HashMap::new(),
3353                #[cfg(feature = "test_utils")]
3354                &HashMap::new(),
3355            ),
3356            Ok(())
3357        );
3358        assert_eq!(vm.run_context.pc, relocatable!(0, 4));
3359    }
3360
3361    #[test]
3362    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3363    fn compute_operands_deduce_dst_none() {
3364        let instruction = Instruction {
3365            off0: 2,
3366            off1: 0,
3367            off2: 0,
3368            dst_register: Register::FP,
3369            op0_register: Register::AP,
3370            op1_addr: Op1Addr::AP,
3371            res: Res::Unconstrained,
3372            pc_update: PcUpdate::Regular,
3373            ap_update: ApUpdate::Regular,
3374            fp_update: FpUpdate::Regular,
3375            opcode: Opcode::NOp,
3376            opcode_extension: OpcodeExtension::Stone,
3377        };
3378
3379        let mut vm = vm!();
3380
3381        vm.segments = segments!(((1, 0), 145944781867024385_i64));
3382
3383        let error = vm.compute_operands(&instruction).unwrap_err();
3384        assert_matches!(error, VirtualMachineError::NoDst);
3385    }
3386
3387    #[test]
3388    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3389    fn opcode_assertions_res_unconstrained() {
3390        let instruction = Instruction {
3391            off0: 1,
3392            off1: 2,
3393            off2: 3,
3394            dst_register: Register::FP,
3395            op0_register: Register::AP,
3396            op1_addr: Op1Addr::AP,
3397            res: Res::Add,
3398            pc_update: PcUpdate::Regular,
3399            ap_update: ApUpdate::Regular,
3400            fp_update: FpUpdate::APPlus2,
3401            opcode: Opcode::AssertEq,
3402            opcode_extension: OpcodeExtension::Stone,
3403        };
3404
3405        let operands = Operands {
3406            dst: MaybeRelocatable::Int(Felt252::from(8)),
3407            res: None,
3408            op0: MaybeRelocatable::Int(Felt252::from(9)),
3409            op1: MaybeRelocatable::Int(Felt252::from(10)),
3410        };
3411
3412        let vm = vm!();
3413
3414        let error = vm.opcode_assertions(&instruction, &operands);
3415        assert_matches!(error, Err(VirtualMachineError::UnconstrainedResAssertEq));
3416    }
3417
3418    #[test]
3419    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3420    fn opcode_assertions_instruction_failed() {
3421        let instruction = Instruction {
3422            off0: 1,
3423            off1: 2,
3424            off2: 3,
3425            dst_register: Register::FP,
3426            op0_register: Register::AP,
3427            op1_addr: Op1Addr::AP,
3428            res: Res::Add,
3429            pc_update: PcUpdate::Regular,
3430            ap_update: ApUpdate::Regular,
3431            fp_update: FpUpdate::APPlus2,
3432            opcode: Opcode::AssertEq,
3433            opcode_extension: OpcodeExtension::Stone,
3434        };
3435
3436        let operands = Operands {
3437            dst: MaybeRelocatable::Int(Felt252::from(9_i32)),
3438            res: Some(MaybeRelocatable::Int(Felt252::from(8_i32))),
3439            op0: MaybeRelocatable::Int(Felt252::from(9_i32)),
3440            op1: MaybeRelocatable::Int(Felt252::from(10_i32)),
3441        };
3442
3443        let vm = vm!();
3444
3445        assert_matches!(
3446            vm.opcode_assertions(&instruction, &operands),
3447            Err(VirtualMachineError::DiffAssertValues(bx))
3448            if *bx == (MaybeRelocatable::Int(Felt252::from(9_i32)),
3449                 MaybeRelocatable::Int(Felt252::from(8_i32)))
3450        );
3451    }
3452
3453    #[test]
3454    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3455    fn opcode_assertions_instruction_failed_relocatables() {
3456        let instruction = Instruction {
3457            off0: 1,
3458            off1: 2,
3459            off2: 3,
3460            dst_register: Register::FP,
3461            op0_register: Register::AP,
3462            op1_addr: Op1Addr::AP,
3463            res: Res::Add,
3464            pc_update: PcUpdate::Regular,
3465            ap_update: ApUpdate::Regular,
3466            fp_update: FpUpdate::APPlus2,
3467            opcode: Opcode::AssertEq,
3468            opcode_extension: OpcodeExtension::Stone,
3469        };
3470
3471        let operands = Operands {
3472            dst: MaybeRelocatable::from((1, 1)),
3473            res: Some(MaybeRelocatable::from((1, 2))),
3474            op0: MaybeRelocatable::Int(Felt252::from(9_i32)),
3475            op1: MaybeRelocatable::Int(Felt252::from(10_i32)),
3476        };
3477
3478        let vm = vm!();
3479
3480        assert_matches!(
3481            vm.opcode_assertions(&instruction, &operands),
3482            Err(VirtualMachineError::DiffAssertValues(bx)) if *bx == (MaybeRelocatable::from((1, 1)), MaybeRelocatable::from((1, 2)))
3483        );
3484    }
3485
3486    #[test]
3487    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3488    fn opcode_assertions_inconsistent_op0() {
3489        let instruction = Instruction {
3490            off0: 1,
3491            off1: 2,
3492            off2: 3,
3493            dst_register: Register::FP,
3494            op0_register: Register::AP,
3495            op1_addr: Op1Addr::AP,
3496            res: Res::Add,
3497            pc_update: PcUpdate::Regular,
3498            ap_update: ApUpdate::Regular,
3499            fp_update: FpUpdate::APPlus2,
3500            opcode: Opcode::Call,
3501            opcode_extension: OpcodeExtension::Stone,
3502        };
3503
3504        let operands = Operands {
3505            dst: mayberelocatable!(0, 8),
3506            res: Some(mayberelocatable!(8)),
3507            op0: mayberelocatable!(9),
3508            op1: mayberelocatable!(10),
3509        };
3510
3511        let mut vm = vm!();
3512        vm.run_context.pc = relocatable!(0, 4);
3513
3514        assert_matches!(
3515            vm.opcode_assertions(&instruction, &operands),
3516            Err(VirtualMachineError::CantWriteReturnPc(bx)) if *bx == (mayberelocatable!(9), mayberelocatable!(0, 5))
3517        );
3518    }
3519
3520    #[test]
3521    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3522    fn opcode_assertions_inconsistent_dst() {
3523        let instruction = Instruction {
3524            off0: 1,
3525            off1: 2,
3526            off2: 3,
3527            dst_register: Register::FP,
3528            op0_register: Register::AP,
3529            op1_addr: Op1Addr::AP,
3530            res: Res::Add,
3531            pc_update: PcUpdate::Regular,
3532            ap_update: ApUpdate::Regular,
3533            fp_update: FpUpdate::APPlus2,
3534            opcode: Opcode::Call,
3535            opcode_extension: OpcodeExtension::Stone,
3536        };
3537
3538        let operands = Operands {
3539            dst: mayberelocatable!(8),
3540            res: Some(mayberelocatable!(8)),
3541            op0: mayberelocatable!(0, 1),
3542            op1: mayberelocatable!(10),
3543        };
3544        let mut vm = vm!();
3545        vm.run_context.fp = 6;
3546
3547        assert_matches!(
3548            vm.opcode_assertions(&instruction, &operands),
3549            Err(VirtualMachineError::CantWriteReturnFp(bx)) if *bx == (mayberelocatable!(8), mayberelocatable!(1, 6))
3550        );
3551    }
3552
3553    #[test]
3554    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3555    /// Test for a simple program execution
3556    /// Used program code:
3557    /// func main():
3558    ///     let a = 1
3559    ///     let b = 2
3560    ///     let c = a + b
3561    ///     return()
3562    /// end
3563    /// Memory taken from original vm
3564    /// {RelocatableValue(segment_index=0, offset=0): 2345108766317314046,
3565    ///  RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
3566    ///  RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
3567    /// Current register values:
3568    /// AP 1:2
3569    /// FP 1:2
3570    /// PC 0:0
3571    fn test_step_for_preset_memory() {
3572        let mut vm = vm!(true);
3573
3574        let mut hint_processor = BuiltinHintProcessor::new_empty();
3575
3576        run_context!(vm, 0, 2, 2);
3577
3578        vm.segments = segments![
3579            ((0, 0), 2345108766317314046_u64),
3580            ((1, 0), (2, 0)),
3581            ((1, 1), (3, 0))
3582        ];
3583
3584        assert_matches!(
3585            vm.step(
3586                &mut hint_processor,
3587                exec_scopes_ref!(),
3588                &mut Vec::new(),
3589                #[cfg(feature = "extensive_hints")]
3590                &mut HashMap::new(),
3591                #[cfg(feature = "test_utils")]
3592                &HashMap::new(),
3593            ),
3594            Ok(())
3595        );
3596        let trace = vm.trace.unwrap();
3597        trace_check(&trace, &[((0, 0).into(), 2, 2)]);
3598
3599        assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
3600        assert_eq!(vm.run_context.ap, 2);
3601        assert_eq!(vm.run_context.fp, 0);
3602
3603        //Check that the following addresses have been accessed:
3604        // Addresses have been copied from python execution:
3605        let mem = vm.segments.memory.data;
3606        assert!(mem[1][0].is_accessed());
3607        assert!(mem[1][1].is_accessed());
3608    }
3609
3610    #[test]
3611    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3612    /*
3613    Test for a simple program execution
3614    Used program code:
3615        func myfunc(a: felt) -> (r: felt):
3616            let b = a * 2
3617            return(b)
3618        end
3619        func main():
3620            let a = 1
3621            let b = myfunc(a)
3622            return()
3623        end
3624    Memory taken from original vm:
3625    {RelocatableValue(segment_index=0, offset=0): 5207990763031199744,
3626    RelocatableValue(segment_index=0, offset=1): 2,
3627    RelocatableValue(segment_index=0, offset=2): 2345108766317314046,
3628    RelocatableValue(segment_index=0, offset=3): 5189976364521848832,
3629    RelocatableValue(segment_index=0, offset=4): 1,
3630    RelocatableValue(segment_index=0, offset=5): 1226245742482522112,
3631    RelocatableValue(segment_index=0, offset=6): 3618502788666131213697322783095070105623107215331596699973092056135872020476,
3632    RelocatableValue(segment_index=0, offset=7): 2345108766317314046,
3633    RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
3634    RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
3635    Current register values:
3636    AP 1:2
3637    FP 1:2
3638    PC 0:3
3639    Final Pc (not executed): 3:0
3640    This program consists of 5 steps
3641    */
3642    fn test_step_for_preset_memory_function_call() {
3643        let mut vm = vm!(true);
3644
3645        run_context!(vm, 3, 2, 2);
3646
3647        //Insert values into memory
3648        vm.segments.memory =
3649            memory![
3650            ((0, 0), 5207990763031199744_i64),
3651            ((0, 1), 2),
3652            ((0, 2), 2345108766317314046_i64),
3653            ((0, 3), 5189976364521848832_i64),
3654            ((0, 4), 1),
3655            ((0, 5), 1226245742482522112_i64),
3656            (
3657                (0, 6),
3658                ("3618502788666131213697322783095070105623107215331596699973092056135872020476",10)
3659            ),
3660            ((0, 7), 2345108766317314046_i64),
3661            ((1, 0), (2, 0)),
3662            ((1, 1), (3, 0))
3663        ];
3664
3665        let final_pc = Relocatable::from((3, 0));
3666        let mut hint_processor = BuiltinHintProcessor::new_empty();
3667        //Run steps
3668        while vm.run_context.pc != final_pc {
3669            assert_matches!(
3670                vm.step(
3671                    &mut hint_processor,
3672                    exec_scopes_ref!(),
3673                    &mut Vec::new(),
3674                    #[cfg(feature = "extensive_hints")]
3675                    &mut HashMap::new(),
3676                    #[cfg(feature = "test_utils")]
3677                    &HashMap::new()
3678                ),
3679                Ok(())
3680            );
3681        }
3682
3683        //Check final register values
3684        assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
3685
3686        assert_eq!(vm.run_context.ap, 6);
3687
3688        assert_eq!(vm.run_context.fp, 0);
3689        //Check each TraceEntry in trace
3690        let trace = vm.trace.unwrap();
3691        assert_eq!(trace.len(), 5);
3692        trace_check(
3693            &trace,
3694            &[
3695                ((0, 3).into(), 2, 2),
3696                ((0, 5).into(), 3, 2),
3697                ((0, 0).into(), 5, 5),
3698                ((0, 2).into(), 6, 5),
3699                ((0, 7).into(), 6, 2),
3700            ],
3701        );
3702        //Check that the following addresses have been accessed:
3703        // Addresses have been copied from python execution + addresses of accessed code:
3704        let mem = &vm.segments.memory.data;
3705        assert!(mem[0][0].is_accessed());
3706        assert!(mem[0][1].is_accessed());
3707        assert!(mem[0][2].is_accessed());
3708        assert!(mem[0][3].is_accessed());
3709        assert!(mem[0][4].is_accessed());
3710        assert!(mem[0][5].is_accessed());
3711        assert!(mem[0][6].is_accessed());
3712        assert!(mem[0][7].is_accessed());
3713        assert!(mem[1][0].is_accessed());
3714        assert!(mem[1][1].is_accessed());
3715        assert!(mem[1][2].is_accessed());
3716        assert!(mem[1][3].is_accessed());
3717        assert!(mem[1][4].is_accessed());
3718        assert!(mem[1][5].is_accessed());
3719        assert_eq!(
3720            vm.segments
3721                .memory
3722                .get_amount_of_accessed_addresses_for_segment(0),
3723            Some(8)
3724        );
3725        assert_eq!(
3726            vm.segments
3727                .memory
3728                .get_amount_of_accessed_addresses_for_segment(1),
3729            Some(6)
3730        );
3731    }
3732
3733    #[test]
3734    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3735    /// Test the following program:
3736    /// ...
3737    /// [ap] = 4
3738    /// ap += 1
3739    /// [ap] = 5; ap++
3740    /// [ap] = [ap - 1] * [ap - 2]
3741    /// ...
3742    /// Original vm memory:
3743    /// RelocatableValue(segment_index=0, offset=0): '0x400680017fff8000',
3744    /// RelocatableValue(segment_index=0, offset=1): '0x4',
3745    /// RelocatableValue(segment_index=0, offset=2): '0x40780017fff7fff',
3746    /// RelocatableValue(segment_index=0, offset=3): '0x1',
3747    /// RelocatableValue(segment_index=0, offset=4): '0x480680017fff8000',
3748    /// RelocatableValue(segment_index=0, offset=5): '0x5',
3749    /// RelocatableValue(segment_index=0, offset=6): '0x40507ffe7fff8000',
3750    /// RelocatableValue(segment_index=0, offset=7): '0x208b7fff7fff7ffe',
3751    /// RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
3752    /// RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0),
3753    /// RelocatableValue(segment_index=1, offset=2): '0x4',
3754    /// RelocatableValue(segment_index=1, offset=3): '0x5',
3755    /// RelocatableValue(segment_index=1, offset=4): '0x14'
3756    fn multiplication_and_different_ap_increase() {
3757        let mut vm = vm!();
3758        vm.segments = segments![
3759            ((0, 0), 0x400680017fff8000_i64),
3760            ((0, 1), 0x4),
3761            ((0, 2), 0x40780017fff7fff_i64),
3762            ((0, 3), 0x1),
3763            ((0, 4), 0x480680017fff8000_i64),
3764            ((0, 5), 0x5),
3765            ((0, 6), 0x40507ffe7fff8000_i64),
3766            ((0, 7), 0x208b7fff7fff7ffe_i64),
3767            ((1, 0), (2, 0)),
3768            ((1, 1), (3, 0)),
3769            ((1, 2), 0x4),
3770            ((1, 3), 0x5),
3771            ((1, 4), 0x14)
3772        ];
3773
3774        run_context!(vm, 0, 2, 2);
3775
3776        assert_eq!(vm.run_context.pc, Relocatable::from((0, 0)));
3777        assert_eq!(vm.run_context.ap, 2);
3778        let mut hint_processor = BuiltinHintProcessor::new_empty();
3779        assert_matches!(
3780            vm.step(
3781                &mut hint_processor,
3782                exec_scopes_ref!(),
3783                &mut Vec::new(),
3784                #[cfg(feature = "extensive_hints")]
3785                &mut HashMap::new(),
3786                #[cfg(feature = "test_utils")]
3787                &HashMap::new()
3788            ),
3789            Ok(())
3790        );
3791        assert_eq!(vm.run_context.pc, Relocatable::from((0, 2)));
3792        assert_eq!(vm.run_context.ap, 2);
3793
3794        assert_eq!(
3795            vm.segments
3796                .memory
3797                .get(&vm.run_context.get_ap())
3798                .unwrap()
3799                .as_ref(),
3800            &MaybeRelocatable::Int(Felt252::from(0x4)),
3801        );
3802        let mut hint_processor = BuiltinHintProcessor::new_empty();
3803        assert_matches!(
3804            vm.step(
3805                &mut hint_processor,
3806                exec_scopes_ref!(),
3807                &mut Vec::new(),
3808                #[cfg(feature = "extensive_hints")]
3809                &mut HashMap::new(),
3810                #[cfg(feature = "test_utils")]
3811                &HashMap::new()
3812            ),
3813            Ok(())
3814        );
3815        assert_eq!(vm.run_context.pc, Relocatable::from((0, 4)));
3816        assert_eq!(vm.run_context.ap, 3);
3817
3818        assert_eq!(
3819            vm.segments
3820                .memory
3821                .get(&vm.run_context.get_ap())
3822                .unwrap()
3823                .as_ref(),
3824            &MaybeRelocatable::Int(Felt252::from(0x5))
3825        );
3826
3827        let mut hint_processor = BuiltinHintProcessor::new_empty();
3828        assert_matches!(
3829            vm.step(
3830                &mut hint_processor,
3831                exec_scopes_ref!(),
3832                &mut Vec::new(),
3833                #[cfg(feature = "extensive_hints")]
3834                &mut HashMap::new(),
3835                #[cfg(feature = "test_utils")]
3836                &HashMap::new()
3837            ),
3838            Ok(())
3839        );
3840        assert_eq!(vm.run_context.pc, Relocatable::from((0, 6)));
3841        assert_eq!(vm.run_context.ap, 4);
3842
3843        assert_eq!(
3844            vm.segments
3845                .memory
3846                .get(&vm.run_context.get_ap())
3847                .unwrap()
3848                .as_ref(),
3849            &MaybeRelocatable::Int(Felt252::from(0x14)),
3850        );
3851    }
3852
3853    #[test]
3854    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3855    fn deduce_memory_cell_no_pedersen_builtin() {
3856        let vm = vm!();
3857        assert_matches!(vm.deduce_memory_cell(Relocatable::from((0, 0))), Ok(None));
3858    }
3859
3860    #[test]
3861    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3862    fn deduce_memory_cell_pedersen_builtin_valid() {
3863        let mut vm = vm!();
3864        let builtin = HashBuiltinRunner::new(Some(8), true);
3865        vm.builtin_runners.push(builtin.into());
3866        vm.segments = segments![((0, 3), 32), ((0, 4), 72), ((0, 5), 0)];
3867        assert_matches!(
3868            vm.deduce_memory_cell(Relocatable::from((0, 5))),
3869            Ok(i) if i == Some(MaybeRelocatable::from(crate::felt_hex!(
3870                "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3871            )))
3872        );
3873    }
3874
3875    #[test]
3876    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3877    /* Program used:
3878    %builtins output pedersen
3879    from starkware.cairo.common.cairo_builtins import HashBuiltin
3880    from starkware.cairo.common.hash import hash2
3881    from starkware.cairo.common.serialize import serialize_word
3882
3883    func foo(hash_ptr : HashBuiltin*) -> (
3884        hash_ptr : HashBuiltin*, z
3885    ):
3886        # Use a with-statement, since 'hash_ptr' is not an
3887        # implicit argument.
3888        with hash_ptr:
3889            let (z) = hash2(32, 72)
3890        end
3891        return (hash_ptr=hash_ptr, z=z)
3892    end
3893
3894    func main{output_ptr: felt*, pedersen_ptr: HashBuiltin*}():
3895        let (pedersen_ptr, a) = foo(pedersen_ptr)
3896        serialize_word(a)
3897        return()
3898    end
3899     */
3900    fn compute_operands_pedersen() {
3901        let instruction = Instruction {
3902            off0: 0,
3903            off1: -5,
3904            off2: 2,
3905            dst_register: Register::AP,
3906            op0_register: Register::FP,
3907            op1_addr: Op1Addr::Op0,
3908            res: Res::Op1,
3909            pc_update: PcUpdate::Regular,
3910            ap_update: ApUpdate::Add1,
3911            fp_update: FpUpdate::Regular,
3912            opcode: Opcode::AssertEq,
3913            opcode_extension: OpcodeExtension::Stone,
3914        };
3915        let mut builtin = HashBuiltinRunner::new(Some(8), true);
3916        builtin.base = 3;
3917        let mut vm = vm!();
3918        vm.builtin_runners.push(builtin.into());
3919        run_context!(vm, 0, 13, 12);
3920
3921        //Insert values into memory (excluding those from the program segment (instructions))
3922        vm.segments = segments![
3923            ((3, 0), 32),
3924            ((3, 1), 72),
3925            ((1, 0), (2, 0)),
3926            ((1, 1), (3, 0)),
3927            ((1, 2), (4, 0)),
3928            ((1, 3), (5, 0)),
3929            ((1, 4), (3, 0)),
3930            ((1, 5), (1, 4)),
3931            ((1, 6), (0, 21)),
3932            ((1, 7), (3, 0)),
3933            ((1, 8), 32),
3934            ((1, 9), 72),
3935            ((1, 10), (1, 7)),
3936            ((1, 11), (0, 17)),
3937            ((1, 12), (3, 3))
3938        ];
3939
3940        let expected_operands = Operands {
3941            dst: MaybeRelocatable::from(crate::felt_hex!(
3942                "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3943            )),
3944            res: Some(MaybeRelocatable::from(crate::felt_hex!(
3945                "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3946            ))),
3947            op0: MaybeRelocatable::from((3, 0)),
3948            op1: MaybeRelocatable::from(crate::felt_hex!(
3949                "0x73b3ec210cccbb970f80c6826fb1c40ae9f487617696234ff147451405c339f"
3950            )),
3951        };
3952        let expected_operands_mem_addresses = OperandsAddresses {
3953            dst_addr: Relocatable::from((1, 13)),
3954            op0_addr: Relocatable::from((1, 7)),
3955            op1_addr: Relocatable::from((3, 2)),
3956        };
3957        let (operands, operands_mem_address, _) = vm.compute_operands(&instruction).unwrap();
3958        assert_eq!(operands, expected_operands);
3959        assert_eq!(operands_mem_address, expected_operands_mem_addresses);
3960    }
3961
3962    #[test]
3963    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3964    fn deduce_memory_cell_bitwise_builtin_valid_and() {
3965        let mut vm = vm!();
3966        let builtin = BitwiseBuiltinRunner::new(Some(256), true);
3967        vm.builtin_runners.push(builtin.into());
3968        vm.segments = segments![((0, 5), 10), ((0, 6), 12), ((0, 7), 0)];
3969        assert_matches!(
3970            vm.deduce_memory_cell(Relocatable::from((0, 7))),
3971            Ok(i) if i == Some(MaybeRelocatable::from(Felt252::from(8_i32)))
3972        );
3973    }
3974
3975    #[test]
3976    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3977    /* Program used:
3978    %builtins bitwise
3979    from starkware.cairo.common.bitwise import bitwise_and
3980    from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
3981
3982
3983    func main{bitwise_ptr: BitwiseBuiltin*}():
3984        let (result) = bitwise_and(12, 10)  # Binary (1100, 1010).
3985        assert result = 8  # Binary 1000.
3986        return()
3987    end
3988    */
3989    fn compute_operands_bitwise() {
3990        let instruction = Instruction {
3991            off0: 0,
3992            off1: -5,
3993            off2: 2,
3994            dst_register: Register::AP,
3995            op0_register: Register::FP,
3996            op1_addr: Op1Addr::Op0,
3997            res: Res::Op1,
3998            pc_update: PcUpdate::Regular,
3999            ap_update: ApUpdate::Add1,
4000            fp_update: FpUpdate::Regular,
4001            opcode: Opcode::AssertEq,
4002            opcode_extension: OpcodeExtension::Stone,
4003        };
4004
4005        let mut builtin = BitwiseBuiltinRunner::new(Some(256), true);
4006        builtin.base = 2;
4007        let mut vm = vm!();
4008
4009        vm.builtin_runners.push(builtin.into());
4010        run_context!(vm, 0, 9, 8);
4011
4012        //Insert values into memory (excluding those from the program segment (instructions))
4013        vm.segments = segments![
4014            ((2, 0), 12),
4015            ((2, 1), 10),
4016            ((1, 0), (2, 0)),
4017            ((1, 1), (3, 0)),
4018            ((1, 2), (4, 0)),
4019            ((1, 3), (2, 0)),
4020            ((1, 4), 12),
4021            ((1, 5), 10),
4022            ((1, 6), (1, 3)),
4023            ((1, 7), (0, 13))
4024        ];
4025
4026        let expected_operands = Operands {
4027            dst: MaybeRelocatable::from(Felt252::from(8_i32)),
4028            res: Some(MaybeRelocatable::from(Felt252::from(8_i32))),
4029            op0: MaybeRelocatable::from((2, 0)),
4030            op1: MaybeRelocatable::from(Felt252::from(8_i32)),
4031        };
4032        let expected_operands_mem_addresses = OperandsAddresses {
4033            dst_addr: Relocatable::from((1, 9)),
4034            op0_addr: Relocatable::from((1, 3)),
4035            op1_addr: Relocatable::from((2, 2)),
4036        };
4037        let (operands, operands_mem_address, _) = vm.compute_operands(&instruction).unwrap();
4038        assert_eq!(operands, expected_operands);
4039        assert_eq!(operands_mem_address, expected_operands_mem_addresses);
4040    }
4041
4042    #[test]
4043    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4044    fn deduce_memory_cell_ec_op_builtin_valid() {
4045        let mut vm = vm!();
4046        let builtin = EcOpBuiltinRunner::new(Some(256), true);
4047        vm.builtin_runners.push(builtin.into());
4048
4049        vm.segments = segments![
4050            (
4051                (0, 0),
4052                (
4053                    "0x68caa9509b7c2e90b4d92661cbf7c465471c1e8598c5f989691eef6653e0f38",
4054                    16
4055                )
4056            ),
4057            (
4058                (0, 1),
4059                (
4060                    "0x79a8673f498531002fc549e06ff2010ffc0c191cceb7da5532acb95cdcb591",
4061                    16
4062                )
4063            ),
4064            (
4065                (0, 2),
4066                (
4067                    "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
4068                    16
4069                )
4070            ),
4071            (
4072                (0, 3),
4073                (
4074                    "0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f",
4075                    16
4076                )
4077            ),
4078            ((0, 4), 34),
4079            (
4080                (0, 5),
4081                (
4082                    "0x6245403e2fafe5df3b79ea28d050d477771bc560fc59e915b302cc9b70a92f5",
4083                    16
4084                )
4085            )
4086        ];
4087
4088        assert_matches!(
4089            vm.deduce_memory_cell(Relocatable::from((0, 6))),
4090            Ok(i) if i == Some(MaybeRelocatable::from(felt_hex!(
4091                "0x7f49de2c3a7d1671437406869edb1805ba43e1c0173b35f8c2e8fcc13c3fa6d"
4092            )))
4093        );
4094    }
4095
4096    #[test]
4097    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4098    /* Data taken from this program execution:
4099       %builtins output ec_op
4100       from starkware.cairo.common.cairo_builtins import EcOpBuiltin
4101       from starkware.cairo.common.serialize import serialize_word
4102       from starkware.cairo.common.ec_point import EcPoint
4103       from starkware.cairo.common.ec import ec_op
4104
4105       func main{output_ptr: felt*, ec_op_ptr: EcOpBuiltin*}():
4106           let x: EcPoint = EcPoint(2089986280348253421170679821480865132823066470938446095505822317253594081284, 1713931329540660377023406109199410414810705867260802078187082345529207694986)
4107
4108           let y: EcPoint = EcPoint(874739451078007766457464989774322083649278607533249481151382481072868806602,152666792071518830868575557812948353041420400780739481342941381225525861407)
4109           let z: EcPoint = ec_op(x,34, y)
4110           serialize_word(z.x)
4111           return()
4112           end
4113    */
4114    fn verify_auto_deductions_for_ec_op_builtin_valid() {
4115        let mut builtin = EcOpBuiltinRunner::new(Some(256), true);
4116        builtin.base = 3;
4117        let mut vm = vm!();
4118        vm.builtin_runners.push(builtin.into());
4119        vm.segments = segments![
4120            (
4121                (3, 0),
4122                (
4123                    "2962412995502985605007699495352191122971573493113767820301112397466445942584",
4124                    10
4125                )
4126            ),
4127            (
4128                (3, 1),
4129                (
4130                    "214950771763870898744428659242275426967582168179217139798831865603966154129",
4131                    10
4132                )
4133            ),
4134            (
4135                (3, 2),
4136                (
4137                    "874739451078007766457464989774322083649278607533249481151382481072868806602",
4138                    10
4139                )
4140            ),
4141            (
4142                (3, 3),
4143                (
4144                    "152666792071518830868575557812948353041420400780739481342941381225525861407",
4145                    10
4146                )
4147            ),
4148            ((3, 4), 34),
4149            (
4150                (3, 5),
4151                (
4152                    "2778063437308421278851140253538604815869848682781135193774472480292420096757",
4153                    10
4154                )
4155            )
4156        ];
4157        assert_matches!(vm.verify_auto_deductions(), Ok(()));
4158    }
4159
4160    #[test]
4161    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4162    fn verify_auto_deductions_for_ec_op_builtin_valid_points_invalid_result() {
4163        let mut builtin = EcOpBuiltinRunner::new(Some(256), true);
4164        builtin.base = 3;
4165        let mut vm = vm!();
4166        vm.builtin_runners.push(builtin.into());
4167        vm.segments = segments![
4168            (
4169                (3, 0),
4170                (
4171                    "2962412995502985605007699495352191122971573493113767820301112397466445942584",
4172                    10
4173                )
4174            ),
4175            (
4176                (3, 1),
4177                (
4178                    "214950771763870898744428659242275426967582168179217139798831865603966154129",
4179                    10
4180                )
4181            ),
4182            (
4183                (3, 2),
4184                (
4185                    "2089986280348253421170679821480865132823066470938446095505822317253594081284",
4186                    10
4187                )
4188            ),
4189            (
4190                (3, 3),
4191                (
4192                    "1713931329540660377023406109199410414810705867260802078187082345529207694986",
4193                    10
4194                )
4195            ),
4196            ((3, 4), 34),
4197            (
4198                (3, 5),
4199                (
4200                    "2778063437308421278851140253538604815869848682781135193774472480292420096757",
4201                    10
4202                )
4203            )
4204        ];
4205        let error = vm.verify_auto_deductions();
4206        assert_matches!(
4207            error,
4208            Err(VirtualMachineError::InconsistentAutoDeduction(bx))
4209            if *bx == (BuiltinName::ec_op,
4210                    MaybeRelocatable::Int(crate::felt_str!(
4211                        "2739017437753868763038285897969098325279422804143820990343394856167768859289"
4212                    )),
4213                    Some(MaybeRelocatable::Int(crate::felt_str!(
4214                        "2778063437308421278851140253538604815869848682781135193774472480292420096757"
4215                    ))))
4216        );
4217    }
4218
4219    #[test]
4220    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4221    /* Program used:
4222    %builtins bitwise
4223    from starkware.cairo.common.bitwise import bitwise_and
4224    from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
4225
4226
4227    func main{bitwise_ptr: BitwiseBuiltin*}():
4228        let (result) = bitwise_and(12, 10)  # Binary (1100, 1010).
4229        assert result = 8  # Binary 1000.
4230        return()
4231    end
4232    */
4233    fn verify_auto_deductions_bitwise() {
4234        let mut builtin = BitwiseBuiltinRunner::new(Some(256), true);
4235        builtin.base = 2;
4236        let mut vm = vm!();
4237        vm.builtin_runners.push(builtin.into());
4238        vm.segments = segments![((2, 0), 12), ((2, 1), 10)];
4239        assert_matches!(vm.verify_auto_deductions(), Ok(()));
4240    }
4241
4242    #[test]
4243    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4244    /* Program used:
4245    %builtins bitwise
4246    from starkware.cairo.common.bitwise import bitwise_and
4247    from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
4248
4249
4250    func main{bitwise_ptr: BitwiseBuiltin*}():
4251        let (result) = bitwise_and(12, 10)  # Binary (1100, 1010).
4252        assert result = 8  # Binary 1000.
4253        return()
4254    end
4255    */
4256    fn verify_auto_deductions_for_addr_bitwise() {
4257        let mut builtin = BitwiseBuiltinRunner::new(Some(256), true);
4258        builtin.base = 2;
4259        let builtin: BuiltinRunner = builtin.into();
4260        let mut vm = vm!();
4261        vm.segments = segments![((2, 0), 12), ((2, 1), 10)];
4262        assert_matches!(
4263            vm.verify_auto_deductions_for_addr(relocatable!(2, 0), &builtin),
4264            Ok(())
4265        );
4266        assert_matches!(
4267            vm.verify_auto_deductions_for_addr(relocatable!(2, 1), &builtin),
4268            Ok(())
4269        );
4270    }
4271
4272    #[test]
4273    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4274    /* Program used:
4275    %builtins output pedersen
4276    from starkware.cairo.common.cairo_builtins import HashBuiltin
4277    from starkware.cairo.common.hash import hash2
4278    from starkware.cairo.common.serialize import serialize_word
4279
4280    func foo(hash_ptr : HashBuiltin*) -> (
4281        hash_ptr : HashBuiltin*, z
4282    ):
4283        # Use a with-statement, since 'hash_ptr' is not an
4284        # implicit argument.
4285        with hash_ptr:
4286            let (z) = hash2(32, 72)
4287        end
4288        return (hash_ptr=hash_ptr, z=z)
4289    end
4290
4291    func main{output_ptr: felt*, pedersen_ptr: HashBuiltin*}():
4292        let (pedersen_ptr, a) = foo(pedersen_ptr)
4293        serialize_word(a)
4294        return()
4295    end
4296     */
4297    fn verify_auto_deductions_pedersen() {
4298        let mut builtin = HashBuiltinRunner::new(Some(8), true);
4299        builtin.base = 3;
4300        let mut vm = vm!();
4301        vm.builtin_runners.push(builtin.into());
4302        vm.segments = segments![((3, 0), 32), ((3, 1), 72)];
4303        assert_matches!(vm.verify_auto_deductions(), Ok(()));
4304    }
4305
4306    #[test]
4307    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4308    fn can_get_return_values() {
4309        let mut vm = vm!();
4310        vm.set_ap(4);
4311        vm.segments = segments![((1, 0), 1), ((1, 1), 2), ((1, 2), 3), ((1, 3), 4)];
4312        let expected = vec![
4313            MaybeRelocatable::Int(Felt252::from(1_i32)),
4314            MaybeRelocatable::Int(Felt252::from(2_i32)),
4315            MaybeRelocatable::Int(Felt252::from(3_i32)),
4316            MaybeRelocatable::Int(Felt252::from(4_i32)),
4317        ];
4318        assert_eq!(vm.get_return_values(4).unwrap(), expected);
4319    }
4320
4321    #[test]
4322    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4323    fn get_return_values_fails_when_ap_is_0() {
4324        let mut vm = vm!();
4325        vm.segments = segments![((1, 0), 1), ((1, 1), 2), ((1, 2), 3), ((1, 3), 4)];
4326        assert_matches!(vm.get_return_values(3),
4327            Err(MemoryError::FailedToGetReturnValues(bx))
4328            if *bx == (3, Relocatable::from((1,0))));
4329    }
4330
4331    /*
4332    Program used for this test:
4333    from starkware.cairo.common.alloc import alloc
4334    func main{}():
4335        let vec: felt* = alloc()
4336        assert vec[0] = 1
4337        return()
4338    end
4339    Memory: {RelocatableValue(segment_index=0, offset=0): 290341444919459839,
4340        RelocatableValue(segment_index=0, offset=1): 1,
4341        RelocatableValue(segment_index=0, offset=2): 2345108766317314046,
4342        RelocatableValue(segment_index=0, offset=3): 1226245742482522112,
4343        RelocatableValue(segment_index=0, offset=4): 3618502788666131213697322783095070105623107215331596699973092056135872020478,
4344        RelocatableValue(segment_index=0, offset=5): 5189976364521848832,
4345        RelocatableValue(segment_index=0, offset=6): 1,
4346        RelocatableValue(segment_index=0, offset=7): 4611826758063128575,
4347        RelocatableValue(segment_index=0, offset=8): 2345108766317314046,
4348        RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
4349        RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
4350     */
4351
4352    #[test]
4353    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4354    fn test_step_for_preset_memory_with_alloc_hint() {
4355        let mut vm = vm!(true);
4356        let hint_data = vec![any_box!(HintProcessorData::new_default(
4357            "memory[ap] = segments.add()".to_string(),
4358            HashMap::new(),
4359        ))];
4360
4361        //Initialzie registers
4362        run_context!(vm, 3, 2, 2);
4363
4364        //Create program and execution segments
4365        for _ in 0..2 {
4366            vm.segments.add();
4367        }
4368        //Initialize memory
4369
4370        let mut hint_processor = BuiltinHintProcessor::new_empty();
4371
4372        vm.segments = segments![
4373            ((0, 0), 290341444919459839_i64),
4374            ((0, 1), 1),
4375            ((0, 2), 2345108766317314046_i64),
4376            ((0, 3), 1226245742482522112_i64),
4377            (
4378                (0, 4),
4379                (
4380                    "3618502788666131213697322783095070105623107215331596699973092056135872020478",
4381                    10
4382                )
4383            ),
4384            ((0, 5), 5189976364521848832_i64),
4385            ((0, 6), 1),
4386            ((0, 7), 4611826758063128575_i64),
4387            ((0, 8), 2345108766317314046_i64),
4388            ((1, 0), (2, 0)),
4389            ((1, 1), (3, 0))
4390        ];
4391
4392        #[cfg(feature = "extensive_hints")]
4393        let mut hint_data = hint_data;
4394
4395        //Run Steps
4396        for _ in 0..6 {
4397            #[cfg(not(feature = "extensive_hints"))]
4398            let mut hint_data = if vm.run_context.pc == (0, 0).into() {
4399                &hint_data[0..]
4400            } else {
4401                &hint_data[0..0]
4402            };
4403            assert_matches!(
4404                vm.step(
4405                    &mut hint_processor,
4406                    exec_scopes_ref!(),
4407                    &mut hint_data,
4408                    #[cfg(feature = "extensive_hints")]
4409                    &mut HashMap::from([(
4410                        Relocatable::from((0, 0)),
4411                        (0_usize, NonZeroUsize::new(1).unwrap())
4412                    )]),
4413                    #[cfg(feature = "test_utils")]
4414                    &HashMap::new(),
4415                ),
4416                Ok(())
4417            );
4418        }
4419        //Compare trace
4420        let trace = vm.trace.unwrap();
4421        trace_check(
4422            &trace,
4423            &[
4424                ((0, 3).into(), 2, 2),
4425                ((0, 0).into(), 4, 4),
4426                ((0, 2).into(), 5, 4),
4427                ((0, 5).into(), 5, 2),
4428                ((0, 7).into(), 6, 2),
4429                ((0, 8).into(), 6, 2),
4430            ],
4431        );
4432
4433        //Compare final register values
4434        assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
4435        assert_eq!(vm.run_context.ap, 6);
4436        assert_eq!(vm.run_context.fp, 0);
4437
4438        //Check that the array created through alloc contains the element we inserted
4439        //As there are no builtins present, the next segment crated will have the index 2
4440        check_memory!(vm.segments.memory, ((2, 0), 1));
4441    }
4442
4443    #[test]
4444    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4445    fn test_get_builtin_runners() {
4446        let mut vm = vm!();
4447        let hash_builtin = HashBuiltinRunner::new(Some(8), true);
4448        let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true);
4449        vm.builtin_runners.push(hash_builtin.into());
4450        vm.builtin_runners.push(bitwise_builtin.into());
4451
4452        let builtins = vm.get_builtin_runners();
4453
4454        assert_eq!(builtins[0].name(), BuiltinName::pedersen);
4455        assert_eq!(builtins[1].name(), BuiltinName::bitwise);
4456    }
4457
4458    #[test]
4459    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4460    fn test_get_output_builtin_mut() {
4461        let mut vm = vm!();
4462
4463        assert_matches!(
4464            vm.get_output_builtin_mut(),
4465            Err(VirtualMachineError::NoOutputBuiltin)
4466        );
4467
4468        let output_builtin = OutputBuiltinRunner::new(true);
4469        vm.builtin_runners.push(output_builtin.clone().into());
4470
4471        let vm_output_builtin = vm
4472            .get_output_builtin_mut()
4473            .expect("Output builtin should be returned");
4474
4475        assert_eq!(vm_output_builtin.base(), output_builtin.base());
4476        assert_eq!(vm_output_builtin.pages, output_builtin.pages);
4477        assert_eq!(vm_output_builtin.attributes, output_builtin.attributes);
4478        assert_eq!(vm_output_builtin.stop_ptr, output_builtin.stop_ptr);
4479        assert_eq!(vm_output_builtin.included, output_builtin.included);
4480    }
4481
4482    #[test]
4483    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4484    fn get_range_for_continuous_memory() {
4485        let mut vm = vm!();
4486        vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
4487
4488        let value1 = MaybeRelocatable::from(Felt252::from(2_i32));
4489        let value2 = MaybeRelocatable::from(Felt252::from(3_i32));
4490        let value3 = MaybeRelocatable::from(Felt252::from(4_i32));
4491
4492        let expected_vec = vec![
4493            Some(Cow::Borrowed(&value1)),
4494            Some(Cow::Borrowed(&value2)),
4495            Some(Cow::Borrowed(&value3)),
4496        ];
4497        assert_eq!(vm.get_range(Relocatable::from((1, 0)), 3), expected_vec);
4498    }
4499
4500    #[test]
4501    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4502    fn get_range_for_non_continuous_memory() {
4503        let mut vm = vm!();
4504        vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
4505
4506        let value1 = MaybeRelocatable::from(Felt252::from(2_i32));
4507        let value2 = MaybeRelocatable::from(Felt252::from(3_i32));
4508        let value3 = MaybeRelocatable::from(Felt252::from(4_i32));
4509
4510        let expected_vec = vec![
4511            Some(Cow::Borrowed(&value1)),
4512            Some(Cow::Borrowed(&value2)),
4513            None,
4514            Some(Cow::Borrowed(&value3)),
4515        ];
4516        assert_eq!(vm.get_range(Relocatable::from((1, 0)), 4), expected_vec);
4517    }
4518
4519    #[test]
4520    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4521    fn get_continuous_range_for_continuous_memory() {
4522        let mut vm = vm!();
4523        vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
4524
4525        let value1 = MaybeRelocatable::from(Felt252::from(2_i32));
4526        let value2 = MaybeRelocatable::from(Felt252::from(3_i32));
4527        let value3 = MaybeRelocatable::from(Felt252::from(4_i32));
4528
4529        let expected_vec = vec![value1, value2, value3];
4530        assert_eq!(
4531            vm.get_continuous_range(Relocatable::from((1, 0)), 3),
4532            Ok(expected_vec)
4533        );
4534    }
4535
4536    #[test]
4537    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4538    fn get_continuous_range_for_non_continuous_memory() {
4539        let mut vm = vm!();
4540        vm.segments = segments![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
4541
4542        assert_eq!(
4543            vm.get_continuous_range(Relocatable::from((1, 0)), 3),
4544            Err(MemoryError::GetRangeMemoryGap(Box::new(((1, 0).into(), 3))))
4545        );
4546    }
4547
4548    #[test]
4549    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4550    fn get_segment_used_size_after_computing_used() {
4551        let mut vm = vm!();
4552        vm.segments = segments![
4553            ((0, 2), 1),
4554            ((0, 5), 1),
4555            ((0, 7), 1),
4556            ((1, 1), 1),
4557            ((2, 2), 1),
4558            ((2, 4), 1),
4559            ((2, 7), 1)
4560        ];
4561        vm.segments.compute_effective_sizes();
4562        assert_eq!(Some(8), vm.get_segment_used_size(2));
4563    }
4564
4565    #[test]
4566    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4567    fn get_segment_size_before_computing_used() {
4568        let vm = vm!();
4569        assert_eq!(None, vm.get_segment_size(2));
4570    }
4571
4572    #[test]
4573    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4574    fn get_segment_size_before_computing_used_set_size() {
4575        let mut vm = vm!();
4576        vm.segments.segment_sizes.insert(2, 2);
4577        assert_eq!(Some(2), vm.get_segment_size(2));
4578    }
4579
4580    #[test]
4581    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4582    fn get_segment_size_after_computing_used() {
4583        let mut vm = vm!();
4584        vm.segments = segments![
4585            ((0, 2), 1),
4586            ((0, 5), 1),
4587            ((0, 7), 1),
4588            ((1, 1), 1),
4589            ((2, 2), 1),
4590            ((2, 4), 1),
4591            ((2, 7), 1)
4592        ];
4593        vm.segments.compute_effective_sizes();
4594        assert_eq!(Some(8), vm.get_segment_size(2));
4595    }
4596
4597    #[test]
4598    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4599    fn get_segment_used_size_before_computing_used() {
4600        let vm = vm!();
4601        assert_eq!(None, vm.get_segment_used_size(2));
4602    }
4603
4604    #[test]
4605    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4606    fn get_and_set_pc() {
4607        let mut vm = vm!();
4608        vm.set_pc(Relocatable {
4609            segment_index: 3,
4610            offset: 4,
4611        });
4612        assert_eq!(
4613            vm.get_pc(),
4614            Relocatable {
4615                segment_index: 3,
4616                offset: 4
4617            }
4618        )
4619    }
4620
4621    #[test]
4622    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4623    fn get_and_set_fp() {
4624        let mut vm = vm!();
4625        vm.set_fp(3);
4626        assert_eq!(
4627            vm.get_fp(),
4628            Relocatable {
4629                segment_index: 1,
4630                offset: 3
4631            }
4632        )
4633    }
4634
4635    #[test]
4636    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4637    fn get_maybe_key_not_in_memory() {
4638        let vm = vm!();
4639        assert_eq!(
4640            vm.get_maybe(&Relocatable {
4641                segment_index: 5,
4642                offset: 2
4643            }),
4644            None
4645        );
4646    }
4647
4648    #[test]
4649    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4650    fn get_maybe_error() {
4651        let vm = vm!();
4652        assert_eq!(
4653            vm.get_maybe(&MaybeRelocatable::Int(Felt252::from(0_i32))),
4654            None,
4655        );
4656    }
4657
4658    #[test]
4659    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4660    fn end_run_error() {
4661        let mut vm = vm!();
4662        let scopes = exec_scopes_ref!();
4663        scopes.enter_scope(HashMap::new());
4664
4665        assert_matches!(
4666            vm.end_run(scopes, false),
4667            Err(VirtualMachineError::MainScopeError(
4668                ExecScopeError::NoScopeError
4669            ))
4670        );
4671    }
4672
4673    #[test]
4674    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4675    fn add_temporary_segments() {
4676        let mut vm = vm!();
4677        let mut _base = vm.add_temporary_segment();
4678        assert_eq!(
4679            _base,
4680            Relocatable {
4681                segment_index: -1,
4682                offset: 0
4683            }
4684        );
4685        let mut _base = vm.add_temporary_segment();
4686        assert_eq!(
4687            _base,
4688            Relocatable {
4689                segment_index: -2,
4690                offset: 0
4691            }
4692        );
4693    }
4694
4695    #[test]
4696    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4697    fn decode_current_instruction_invalid_encoding() {
4698        let mut vm = vm!();
4699        vm.segments = segments![((0, 0), ("112233445566778899112233445566778899", 16))];
4700        assert_matches!(
4701            vm.decode_current_instruction(),
4702            Err(VirtualMachineError::InvalidInstructionEncoding)
4703        );
4704    }
4705
4706    #[test]
4707    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4708    fn add_relocation_rule_test() {
4709        let mut vm = vm!();
4710
4711        assert_eq!(
4712            vm.add_relocation_rule((-1, 0).into(), (1, 2).into()),
4713            Ok(()),
4714        );
4715        assert_eq!(
4716            vm.add_relocation_rule((-2, 0).into(), (-1, 1).into()),
4717            Ok(()),
4718        );
4719        assert_eq!(
4720            vm.add_relocation_rule((5, 0).into(), (0, 0).into()),
4721            Err(MemoryError::AddressNotInTemporarySegment(5)),
4722        );
4723        assert_eq!(
4724            vm.add_relocation_rule((-3, 6).into(), (0, 0).into()),
4725            Err(MemoryError::NonZeroOffset(6)),
4726        );
4727        assert_eq!(
4728            vm.add_relocation_rule((-1, 0).into(), (0, 0).into()),
4729            Err(MemoryError::DuplicatedRelocation(-1)),
4730        );
4731    }
4732
4733    #[test]
4734    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4735    fn gen_arg_relocatable() {
4736        let mut vm = vm!();
4737
4738        assert_matches!(
4739            vm.gen_arg(&mayberelocatable!(0, 0)),
4740            Ok(x) if x == mayberelocatable!(0, 0)
4741        );
4742    }
4743
4744    /// Test that the call to .gen_arg() with a bigint and no prime number just
4745    /// passes the value through.
4746    #[test]
4747    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4748    fn gen_arg_bigint() {
4749        let mut vm = vm!();
4750
4751        assert_matches!(
4752            vm.gen_arg(&mayberelocatable!(1234)),
4753            Ok(x) if x == mayberelocatable!(1234)
4754        );
4755    }
4756
4757    /// Test that the call to .gen_arg() with a bigint and a prime number passes
4758    /// the value through after applying the modulo.
4759    #[test]
4760    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4761    fn gen_arg_bigint_prime() {
4762        let mut vm = vm!();
4763        let prime = felt_hex!(crate::utils::PRIME_STR);
4764        let prime_maybe = MaybeRelocatable::from(prime);
4765
4766        assert_matches!(vm.gen_arg(&prime_maybe), Ok(x) if x == mayberelocatable!(0));
4767    }
4768
4769    /// Test that the call to .gen_arg() with a Vec<MaybeRelocatable> writes its
4770    /// contents into a new segment and returns a pointer to it.
4771    #[test]
4772    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4773    fn gen_arg_vec() {
4774        let mut vm = vm!();
4775
4776        assert_matches!(
4777            vm.gen_arg(&vec![
4778                mayberelocatable!(0),
4779                mayberelocatable!(1),
4780                mayberelocatable!(2),
4781                mayberelocatable!(3),
4782                mayberelocatable!(0, 0),
4783                mayberelocatable!(0, 1),
4784                mayberelocatable!(0, 2),
4785                mayberelocatable!(0, 3),
4786            ]),
4787            Ok(x) if x == mayberelocatable!(0, 0)
4788        );
4789    }
4790
4791    /// Test that compute_effective_sizes() works as intended.
4792    #[test]
4793    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4794    fn compute_effective_sizes() {
4795        let mut vm = vm!();
4796
4797        let segment = vm.segments.add();
4798        vm.load_data(
4799            segment,
4800            &[
4801                mayberelocatable!(1),
4802                mayberelocatable!(2),
4803                mayberelocatable!(3),
4804                mayberelocatable!(4),
4805            ],
4806        )
4807        .expect("Could not load data into memory.");
4808
4809        assert_eq!(vm.segments.compute_effective_sizes(), &vec![4]);
4810    }
4811
4812    /// Test that compute_segment_effective_sizes() works as intended.
4813    #[test]
4814    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4815    fn compute_segment_effective_sizes() {
4816        let mut vm = vm!();
4817
4818        let segment = vm.segments.add();
4819        vm.load_data(
4820            segment,
4821            &[
4822                mayberelocatable!(1),
4823                mayberelocatable!(2),
4824                mayberelocatable!(3),
4825                mayberelocatable!(4),
4826            ],
4827        )
4828        .expect("Could not load data into memory.");
4829
4830        assert_eq!(vm.segments.compute_effective_sizes(), &vec![4]);
4831    }
4832
4833    #[test]
4834    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4835    fn test_delete_unaccessed() {
4836        let mut vm = vm!();
4837
4838        let segment0 = vm.segments.add();
4839        let segment1 = vm.segments.add();
4840        let segment2 = vm.segments.add();
4841        let segment3 = vm.segments.add();
4842        let tmp_segment = vm.add_temporary_segment();
4843        assert_eq!(segment0.segment_index, 0);
4844        assert_eq!(segment1.segment_index, 1);
4845        assert_eq!(segment2.segment_index, 2);
4846        assert_eq!(segment3.segment_index, 3);
4847        assert_eq!(tmp_segment.segment_index, -1);
4848        vm.segments.memory = memory![
4849            ((0, 1), 1),
4850            ((1, 0), 3),
4851            ((1, 1), 4),
4852            ((2, 0), 7),
4853            ((3, 0), 7),
4854            ((-1, 0), 5),
4855            ((-1, 1), 5),
4856            ((-1, 2), 5)
4857        ];
4858        vm.run_finished = true;
4859
4860        vm.mark_address_range_as_accessed((2, 0).into(), 1).unwrap();
4861
4862        let cell0 = Relocatable::from((0, 0));
4863        let cell1 = Relocatable::from((1, 1));
4864        let cell2 = Relocatable::from((2, 0));
4865        let cell3 = Relocatable::from((3, 7));
4866        let cell7 = Relocatable::from((7, 17));
4867        let cell_tmp = Relocatable::from((-1, 1));
4868        vm.delete_unaccessed(cell0).unwrap();
4869        vm.delete_unaccessed(cell1).unwrap();
4870        vm.delete_unaccessed(cell_tmp).unwrap();
4871
4872        // Check that the cells were set to NONE.
4873        assert!(vm
4874            .segments
4875            .memory
4876            .get_cell_for_testing(cell0)
4877            .unwrap()
4878            .is_none());
4879        assert!(vm
4880            .segments
4881            .memory
4882            .get_cell_for_testing(cell1)
4883            .unwrap()
4884            .is_none());
4885        assert!(vm
4886            .segments
4887            .memory
4888            .get_cell_for_testing(cell_tmp)
4889            .unwrap()
4890            .is_none());
4891        // Segment 3 cell was out of offset range, so it should not be modified or allocated.
4892        assert!(vm.segments.memory.get_cell_for_testing(cell3).is_none());
4893        // Segment 2 cell was accessed, so attempting to unset the memory should result in error.
4894        assert_matches!(
4895            vm.delete_unaccessed(cell2).unwrap_err(),
4896            MemoryError::UnsetAccessedCell(relocatable) if relocatable == cell2
4897        );
4898        // Segment 3 is unallocated, so attempting to unset the memory should result in error.
4899        assert_matches!(
4900            vm.delete_unaccessed(cell3).unwrap_err(),
4901            MemoryError::UnsetUnallocatedCell(relocatable) if relocatable == cell3
4902        );
4903        // Segment 7 was not allocated, so attempting to unset the memory should result in error.
4904        assert_matches!(
4905            vm.delete_unaccessed(cell7).unwrap_err(),
4906            MemoryError::UnallocatedSegment(boxed)
4907            if *boxed == (cell7.segment_index.try_into().unwrap(), vm.segments.memory.data.len())
4908        );
4909    }
4910
4911    #[test]
4912    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4913    fn mark_as_accessed() {
4914        let mut vm = vm!();
4915        vm.run_finished = true;
4916        vm.segments.memory = memory![
4917            ((0, 0), 0),
4918            ((0, 1), 0),
4919            ((0, 2), 1),
4920            ((0, 10), 10),
4921            ((1, 1), 1),
4922            ((1, 2), 0),
4923            ((2, 0), 0),
4924            ((-1, 0), 0),
4925            ((-1, 1), 0)
4926        ];
4927        vm.mark_address_range_as_accessed((0, 0).into(), 3).unwrap();
4928        vm.mark_address_range_as_accessed((0, 10).into(), 2)
4929            .unwrap();
4930        vm.mark_address_range_as_accessed((1, 1).into(), 1).unwrap();
4931        vm.mark_address_range_as_accessed((-1, 0).into(), 1)
4932            .unwrap();
4933        //Check that the following addresses have been accessed:
4934        // Addresses have been copied from python execution:
4935        let mem = &vm.segments.memory.data;
4936        assert!(mem[0][0].is_accessed());
4937        assert!(mem[0][1].is_accessed());
4938        assert!(mem[0][2].is_accessed());
4939        assert!(mem[0][10].is_accessed());
4940        assert!(mem[1][1].is_accessed());
4941        assert_eq!(
4942            vm.segments
4943                .memory
4944                .get_amount_of_accessed_addresses_for_segment(0),
4945            Some(4)
4946        );
4947        assert_eq!(
4948            vm.segments
4949                .memory
4950                .get_amount_of_accessed_addresses_for_segment(1),
4951            Some(1)
4952        );
4953        assert!(vm.is_accessed(&Relocatable::from((0, 0))).unwrap());
4954        assert!(vm.is_accessed(&Relocatable::from((0, 2))).unwrap());
4955        assert!(vm.is_accessed(&Relocatable::from((0, 10))).unwrap());
4956        assert!(vm.is_accessed(&Relocatable::from((1, 1))).unwrap());
4957        assert!(!vm.is_accessed(&Relocatable::from((1, 2))).unwrap());
4958        assert!(!vm.is_accessed(&Relocatable::from((2, 0))).unwrap());
4959        assert!(vm.is_accessed(&Relocatable::from((-1, 0))).unwrap());
4960        assert!(!vm.is_accessed(&Relocatable::from((-1, 1))).unwrap());
4961    }
4962
4963    #[test]
4964    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4965    fn mark_as_accessed_run_not_finished() {
4966        let mut vm = vm!();
4967        assert_matches!(
4968            vm.mark_address_range_as_accessed((0, 0).into(), 3),
4969            Err(VirtualMachineError::RunNotFinished)
4970        );
4971    }
4972
4973    #[test]
4974    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4975    fn mark_as_accessed_missing_accessed_addresses() {
4976        let mut vm = vm!();
4977        assert_matches!(
4978            vm.mark_address_range_as_accessed((0, 0).into(), 3),
4979            Err(VirtualMachineError::RunNotFinished)
4980        );
4981    }
4982
4983    #[test]
4984    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4985    fn get_u32_range_ok() {
4986        let mut vm = vm!();
4987        vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)];
4988        let expected_vector = vec![1, 4294967295];
4989        assert_eq!(vm.get_u32_range((0, 1).into(), 2), Ok(expected_vector));
4990    }
4991
4992    #[test]
4993    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4994    fn get_u32_range_relocatable() {
4995        let mut vm = vm!();
4996        vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)];
4997        assert_matches!(vm.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into());
4998    }
4999
5000    #[test]
5001    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5002    fn get_u32_range_over_32_bits() {
5003        let mut vm = vm!();
5004        vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)];
5005        assert_matches!(vm.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64));
5006    }
5007
5008    #[test]
5009    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5010    fn get_u32_range_memory_gap() {
5011        let mut vm = vm!();
5012        vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)];
5013        assert_matches!(vm.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into());
5014    }
5015
5016    #[test]
5017    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5018    fn handle_blake2s_instruction_state_too_short() {
5019        let mut vm = vm!();
5020        vm.segments.memory = memory![
5021            ((0, 0), 0),
5022            ((0, 1), 0),
5023            ((0, 2), 0),
5024            ((0, 3), 0),
5025            ((0, 4), 0),
5026            ((0, 5), 0),
5027            ((0, 6), 0),
5028            ((2, 0), (0, 0))
5029        ];
5030        let operands_addresses = OperandsAddresses {
5031            dst_addr: (0, 0).into(),
5032            op0_addr: (2, 0).into(),
5033            op1_addr: (2, 0).into(),
5034        };
5035        vm.run_context = RunContext {
5036            pc: (0, 0).into(),
5037            ap: 0,
5038            fp: 0,
5039        };
5040
5041        assert_matches!(
5042            vm.handle_blake2s_instruction(&operands_addresses, false),
5043            Err(VirtualMachineError::Memory(MemoryError::UnknownMemoryCell(bx))) if *bx == (0, 7).into()
5044        );
5045    }
5046
5047    #[test]
5048    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5049    fn handle_blake2s_instruction_message_too_short() {
5050        let mut vm = vm!();
5051        vm.segments.memory = memory![
5052            ((0, 0), 0),
5053            ((0, 1), 0),
5054            ((0, 2), 0),
5055            ((0, 3), 0),
5056            ((0, 4), 0),
5057            ((0, 5), 0),
5058            ((0, 6), 0),
5059            ((0, 7), 0),
5060            ((2, 0), (0, 0))
5061        ];
5062        let operands_addresses = OperandsAddresses {
5063            dst_addr: (0, 0).into(),
5064            op0_addr: (2, 0).into(),
5065            op1_addr: (2, 0).into(),
5066        };
5067        vm.run_context = RunContext {
5068            pc: (0, 0).into(),
5069            ap: 0,
5070            fp: 0,
5071        };
5072
5073        assert_matches!(
5074            vm.handle_blake2s_instruction(&operands_addresses, false),
5075            Err(VirtualMachineError::Memory(MemoryError::UnknownMemoryCell(bx))) if *bx == (0, 8).into()
5076        );
5077    }
5078
5079    #[test]
5080    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5081    fn handle_blake2s_instruction_ap_points_to_inconsistent_memory() {
5082        let mut vm = vm!();
5083        vm.segments.memory = memory![
5084            ((0, 0), 0),
5085            ((0, 1), 0),
5086            ((0, 2), 0),
5087            ((0, 3), 0),
5088            ((0, 4), 0),
5089            ((0, 5), 0),
5090            ((0, 6), 0),
5091            ((0, 7), 0),
5092            ((0, 8), 0),
5093            ((0, 9), 0),
5094            ((0, 10), 0),
5095            ((0, 11), 0),
5096            ((0, 12), 0),
5097            ((0, 13), 0),
5098            ((0, 14), 0),
5099            ((0, 15), 0),
5100            ((1, 0), (0, 0))
5101        ];
5102        let operands_addresses = OperandsAddresses {
5103            dst_addr: (0, 0).into(),
5104            op0_addr: (1, 0).into(),
5105            op1_addr: (1, 0).into(),
5106        };
5107        vm.run_context = RunContext {
5108            pc: (0, 0).into(),
5109            ap: 0,
5110            fp: 0,
5111        };
5112
5113        assert_matches!(
5114            vm.handle_blake2s_instruction(&operands_addresses, false),
5115            Err(VirtualMachineError::Memory(MemoryError::InconsistentMemory(bx))) if *bx == ((0, 0).into(),0.into(),1848029226.into())
5116        );
5117    }
5118
5119    #[test]
5120    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5121    fn handle_blake2s_instruction_ok() {
5122        let mut vm = vm!();
5123        vm.segments.memory = memory![
5124            // State
5125            ((0, 0), 0x6B08E647),
5126            ((0, 1), 0xBB67AE85),
5127            ((0, 2), 0x3C6EF372),
5128            ((0, 3), 0xA54FF53A),
5129            ((0, 4), 0x510E527F),
5130            ((0, 5), 0x9B05688C),
5131            ((0, 6), 0x1F83D9AB),
5132            ((0, 7), 0x5BE0CD19),
5133            // Message
5134            ((0, 8), 930933030),
5135            ((0, 9), 1766240503),
5136            ((0, 10), 3660871006),
5137            ((0, 11), 388409270),
5138            ((0, 12), 1948594622),
5139            ((0, 13), 3119396969),
5140            ((0, 14), 3924579183),
5141            ((0, 15), 2089920034),
5142            ((0, 16), 3857888532),
5143            ((0, 17), 929304360),
5144            ((0, 18), 1810891574),
5145            ((0, 19), 860971754),
5146            ((0, 20), 1822893775),
5147            ((0, 21), 2008495810),
5148            ((0, 22), 2958962335),
5149            ((0, 23), 2340515744),
5150            // Counter
5151            ((0, 24), 64),
5152            // AP
5153            ((1, 0), (0, 25)),
5154            ((2, 0), (0, 0)),
5155            ((2, 1), (0, 8))
5156        ];
5157        let operands_addresses = OperandsAddresses {
5158            dst_addr: (0, 24).into(),
5159            op0_addr: (2, 0).into(),
5160            op1_addr: (2, 1).into(),
5161        };
5162        vm.run_context = RunContext {
5163            pc: (0, 0).into(),
5164            ap: 0,
5165            fp: 0,
5166        };
5167        assert_matches!(
5168            vm.handle_blake2s_instruction(&operands_addresses, false),
5169            Ok(())
5170        );
5171
5172        let state: [u32; 8] = vm
5173            .get_u32_range((0, 0).into(), 8)
5174            .unwrap()
5175            .try_into()
5176            .unwrap();
5177        let message: [u32; 16] = vm
5178            .get_u32_range((0, 8).into(), 16)
5179            .unwrap()
5180            .try_into()
5181            .unwrap();
5182        let counter = vm.segments.memory.get_u32((0, 24).into()).unwrap();
5183
5184        let expected_new_state: [u32; 8] = blake2s_compress(&state, &message, counter, 0, 0, 0)
5185            .try_into()
5186            .unwrap();
5187
5188        let new_state: [u32; 8] = vm
5189            .get_u32_range((0, 25).into(), 8)
5190            .unwrap()
5191            .try_into()
5192            .unwrap();
5193        assert_eq!(new_state, expected_new_state);
5194    }
5195
5196    #[test]
5197    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5198    fn handle_blake2s_last_block_instruction_ok() {
5199        let mut vm = vm!();
5200        vm.segments.memory = memory![
5201            // State
5202            ((0, 0), 0x6B08E647),
5203            ((0, 1), 0xBB67AE85),
5204            ((0, 2), 0x3C6EF372),
5205            ((0, 3), 0xA54FF53A),
5206            ((0, 4), 0x510E527F),
5207            ((0, 5), 0x9B05688C),
5208            ((0, 6), 0x1F83D9AB),
5209            ((0, 7), 0x5BE0CD19),
5210            // Message
5211            ((0, 8), 930933030),
5212            ((0, 9), 1766240503),
5213            ((0, 10), 3660871006),
5214            ((0, 11), 388409270),
5215            ((0, 12), 1948594622),
5216            ((0, 13), 3119396969),
5217            ((0, 14), 3924579183),
5218            ((0, 15), 2089920034),
5219            ((0, 16), 3857888532),
5220            ((0, 17), 929304360),
5221            ((0, 18), 1810891574),
5222            ((0, 19), 860971754),
5223            ((0, 20), 1822893775),
5224            ((0, 21), 2008495810),
5225            ((0, 22), 2958962335),
5226            ((0, 23), 2340515744),
5227            // Counter
5228            ((0, 24), 64),
5229            // AP
5230            ((1, 0), (0, 25)),
5231            ((2, 0), (0, 0)),
5232            ((2, 1), (0, 8))
5233        ];
5234        let operands_addresses = OperandsAddresses {
5235            dst_addr: (0, 24).into(),
5236            op0_addr: (2, 0).into(),
5237            op1_addr: (2, 1).into(),
5238        };
5239        vm.run_context = RunContext {
5240            pc: (0, 0).into(),
5241            ap: 0,
5242            fp: 0,
5243        };
5244        assert_matches!(
5245            vm.handle_blake2s_instruction(&operands_addresses, true),
5246            Ok(())
5247        );
5248
5249        let state: [u32; 8] = vm
5250            .get_u32_range((0, 0).into(), 8)
5251            .unwrap()
5252            .try_into()
5253            .unwrap();
5254        let message: [u32; 16] = vm
5255            .get_u32_range((0, 8).into(), 16)
5256            .unwrap()
5257            .try_into()
5258            .unwrap();
5259        let counter = vm.segments.memory.get_u32((0, 24).into()).unwrap();
5260
5261        let expected_new_state: [u32; 8] =
5262            blake2s_compress(&state, &message, counter, 0, 0xffffffff, 0)
5263                .try_into()
5264                .unwrap();
5265
5266        let new_state: [u32; 8] = vm
5267            .get_u32_range((0, 25).into(), 8)
5268            .unwrap()
5269            .try_into()
5270            .unwrap();
5271        assert_eq!(new_state, expected_new_state);
5272    }
5273
5274    #[test]
5275    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5276    fn get_traceback_entries_bad_usort() {
5277        let program = Program::from_bytes(
5278            include_bytes!("../../../cairo_programs/bad_programs/bad_usort.json"),
5279            Some("main"),
5280        )
5281        .unwrap();
5282
5283        let mut hint_processor = BuiltinHintProcessor::new_empty();
5284        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false);
5285
5286        let end = cairo_runner.initialize(false).unwrap();
5287        assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_err());
5288        let expected_traceback = vec![
5289            (Relocatable::from((1, 3)), Relocatable::from((0, 97))),
5290            (Relocatable::from((1, 14)), Relocatable::from((0, 30))),
5291            (Relocatable::from((1, 26)), Relocatable::from((0, 60))),
5292        ];
5293        assert_eq!(cairo_runner.vm.get_traceback_entries(), expected_traceback);
5294    }
5295
5296    #[test]
5297    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5298    fn get_traceback_entries_bad_dict_update() {
5299        let program = Program::from_bytes(
5300            include_bytes!("../../../cairo_programs/bad_programs/bad_dict_update.json"),
5301            Some("main"),
5302        )
5303        .unwrap();
5304
5305        let mut hint_processor = BuiltinHintProcessor::new_empty();
5306        let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false);
5307
5308        let end = cairo_runner.initialize(false).unwrap();
5309        assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_err());
5310        let expected_traceback = vec![(Relocatable::from((1, 2)), Relocatable::from((0, 34)))];
5311        assert_eq!(cairo_runner.vm.get_traceback_entries(), expected_traceback);
5312    }
5313
5314    #[test]
5315    fn builder_test() {
5316        let virtual_machine_builder: VirtualMachineBuilder = VirtualMachineBuilder::default()
5317            .run_finished(true)
5318            .current_step(12)
5319            .builtin_runners(vec![BuiltinRunner::from(HashBuiltinRunner::new(
5320                Some(12),
5321                true,
5322            ))])
5323            .run_context(RunContext {
5324                pc: Relocatable::from((0, 0)),
5325                ap: 18,
5326                fp: 0,
5327            })
5328            .segments({
5329                let mut segments = MemorySegmentManager::new();
5330                segments.segment_used_sizes = Some(vec![1]);
5331                segments
5332            })
5333            .skip_instruction_execution(true)
5334            .trace(Some(vec![TraceEntry {
5335                pc: (0, 1).into(),
5336                ap: 1,
5337                fp: 1,
5338            }]));
5339
5340        #[cfg(feature = "test_utils")]
5341        fn before_first_step_hook(
5342            _vm: &mut VirtualMachine,
5343            _hint_data: &[Box<dyn Any>],
5344        ) -> Result<(), VirtualMachineError> {
5345            Err(VirtualMachineError::Unexpected)
5346        }
5347        #[cfg(feature = "test_utils")]
5348        let virtual_machine_builder = virtual_machine_builder.hooks(crate::vm::hooks::Hooks::new(
5349            Some(std::sync::Arc::new(before_first_step_hook)),
5350            None,
5351            None,
5352        ));
5353
5354        #[allow(unused_mut)]
5355        let mut virtual_machine_from_builder = virtual_machine_builder.build();
5356
5357        assert!(virtual_machine_from_builder.run_finished);
5358        assert_eq!(virtual_machine_from_builder.get_current_step(), 12);
5359        assert_eq!(
5360            virtual_machine_from_builder
5361                .builtin_runners
5362                .first()
5363                .unwrap()
5364                .name(),
5365            BuiltinName::pedersen
5366        );
5367        assert_eq!(virtual_machine_from_builder.run_context.ap, 18,);
5368        assert_eq!(
5369            virtual_machine_from_builder.segments.segment_used_sizes,
5370            Some(vec![1])
5371        );
5372        assert!(virtual_machine_from_builder.skip_instruction_execution,);
5373        assert_eq!(
5374            virtual_machine_from_builder.trace,
5375            Some(vec![TraceEntry {
5376                pc: (0, 1).into(),
5377                ap: 1,
5378                fp: 1,
5379            }])
5380        );
5381        #[cfg(feature = "test_utils")]
5382        {
5383            let program = crate::types::program::Program::from_bytes(
5384                include_bytes!("../../../cairo_programs/sqrt.json"),
5385                Some("main"),
5386            )
5387            .expect("Call to `Program::from_file()` failed.");
5388            let mut hint_processor = BuiltinHintProcessor::new_empty();
5389            let mut cairo_runner = cairo_runner!(program);
5390            cairo_runner.vm = virtual_machine_from_builder;
5391            let end = cairo_runner.initialize(false).unwrap();
5392
5393            assert!(cairo_runner.run_until_pc(end, &mut hint_processor).is_err());
5394        }
5395    }
5396
5397    #[test]
5398    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5399    /// Test for a simple program execution
5400    /// Used program code:
5401    /// func main():
5402    ///     let a = 1
5403    ///     let b = 2
5404    ///     let c = a + b
5405    ///     return()
5406    /// end
5407    /// Memory taken from original vm
5408    /// {RelocatableValue(segment_index=0, offset=0): 2345108766317314046,
5409    ///  RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
5410    ///  RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
5411    /// Current register values:
5412    /// AP 1:2
5413    /// FP 1:2
5414    /// PC 0:0
5415    fn test_step_for_preset_memory_program_loaded_into_user_segment() {
5416        let mut vm = vm!(true);
5417
5418        let mut hint_processor = BuiltinHintProcessor::new_empty();
5419
5420        run_context!(vm, 0, 2, 2);
5421
5422        vm.segments = segments![
5423            ((2, 0), 2345108766317314046_u64), // Load program into new segment
5424            ((1, 0), (2, 0)),
5425            ((1, 1), (3, 0))
5426        ];
5427        // set starting pc on new segemt to run loaded program
5428        vm.run_context.pc.segment_index = 2;
5429
5430        assert_matches!(
5431            vm.step(
5432                &mut hint_processor,
5433                exec_scopes_ref!(),
5434                &mut Vec::new(),
5435                #[cfg(feature = "extensive_hints")]
5436                &mut HashMap::new(),
5437                #[cfg(feature = "test_utils")]
5438                &HashMap::new()
5439            ),
5440            Ok(())
5441        );
5442        let trace = vm.trace.unwrap();
5443        trace_check(&trace, &[((2, 0).into(), 2, 2)]);
5444
5445        assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
5446        assert_eq!(vm.run_context.ap, 2);
5447        assert_eq!(vm.run_context.fp, 0);
5448
5449        //Check that the following addresses have been accessed:
5450        // Addresses have been copied from python execution:
5451        let mem = vm.segments.memory.data;
5452        assert!(mem[1][0].is_accessed());
5453        assert!(mem[1][1].is_accessed());
5454    }
5455
5456    #[test]
5457    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5458    /*
5459    Test for a simple program execution
5460    Used program code:
5461        func myfunc(a: felt) -> (r: felt):
5462            let b = a * 2
5463            return(b)
5464        end
5465        func main():
5466            let a = 1
5467            let b = myfunc(a)
5468            return()
5469        end
5470    Memory taken from original vm:
5471    {RelocatableValue(segment_index=0, offset=0): 5207990763031199744,
5472    RelocatableValue(segment_index=0, offset=1): 2,
5473    RelocatableValue(segment_index=0, offset=2): 2345108766317314046,
5474    RelocatableValue(segment_index=0, offset=3): 5189976364521848832,
5475    RelocatableValue(segment_index=0, offset=4): 1,
5476    RelocatableValue(segment_index=0, offset=5): 1226245742482522112,
5477    RelocatableValue(segment_index=0, offset=6): 3618502788666131213697322783095070105623107215331596699973092056135872020476,
5478    RelocatableValue(segment_index=0, offset=7): 2345108766317314046,
5479    RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
5480    RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
5481    Current register values:
5482    AP 1:2
5483    FP 1:2
5484    PC 0:3
5485    Final Pc (not executed): 3:0
5486    This program consists of 5 steps
5487    */
5488    fn test_step_for_preset_memory_function_call_program_loaded_into_user_segment() {
5489        let mut vm = vm!(true);
5490
5491        run_context!(vm, 3, 2, 2);
5492        // set starting pc on new segemt to run loaded program
5493        vm.run_context.pc.segment_index = 4;
5494
5495        //Insert values into memory
5496        vm.segments.memory =
5497            memory![
5498            // Load program into new segment
5499            ((4, 0), 5207990763031199744_i64),
5500            ((4, 1), 2),
5501            ((4, 2), 2345108766317314046_i64),
5502            ((4, 3), 5189976364521848832_i64),
5503            ((4, 4), 1),
5504            ((4, 5), 1226245742482522112_i64),
5505            (
5506                (4, 6),
5507                ("3618502788666131213697322783095070105623107215331596699973092056135872020476",10)
5508            ),
5509            ((4, 7), 2345108766317314046_i64),
5510            ((1, 0), (2, 0)),
5511            ((1, 1), (3, 0))
5512        ];
5513
5514        let final_pc = Relocatable::from((3, 0));
5515        let mut hint_processor = BuiltinHintProcessor::new_empty();
5516        //Run steps
5517        while vm.run_context.pc != final_pc {
5518            assert_matches!(
5519                vm.step(
5520                    &mut hint_processor,
5521                    exec_scopes_ref!(),
5522                    &mut Vec::new(),
5523                    #[cfg(feature = "extensive_hints")]
5524                    &mut HashMap::new(),
5525                    #[cfg(feature = "test_utils")]
5526                    &HashMap::new()
5527                ),
5528                Ok(())
5529            );
5530        }
5531
5532        //Check final register values
5533        assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
5534
5535        assert_eq!(vm.run_context.ap, 6);
5536
5537        assert_eq!(vm.run_context.fp, 0);
5538        //Check each TraceEntry in trace
5539        let trace = vm.trace.unwrap();
5540        assert_eq!(trace.len(), 5);
5541        trace_check(
5542            &trace,
5543            &[
5544                ((4, 3).into(), 2, 2),
5545                ((4, 5).into(), 3, 2),
5546                ((4, 0).into(), 5, 5),
5547                ((4, 2).into(), 6, 5),
5548                ((4, 7).into(), 6, 2),
5549            ],
5550        );
5551        //Check that the following addresses have been accessed:
5552        // Addresses have been copied from python execution + addresses of accessed code:
5553        let mem = &vm.segments.memory.data;
5554        assert!(mem[4][0].is_accessed());
5555        assert!(mem[4][1].is_accessed());
5556        assert!(mem[4][2].is_accessed());
5557        assert!(mem[4][3].is_accessed());
5558        assert!(mem[4][4].is_accessed());
5559        assert!(mem[4][5].is_accessed());
5560        assert!(mem[4][6].is_accessed());
5561        assert!(mem[4][7].is_accessed());
5562        assert!(mem[1][0].is_accessed());
5563        assert!(mem[1][1].is_accessed());
5564        assert!(mem[1][2].is_accessed());
5565        assert!(mem[1][3].is_accessed());
5566        assert!(mem[1][4].is_accessed());
5567        assert!(mem[1][5].is_accessed());
5568        assert_eq!(
5569            vm.segments
5570                .memory
5571                .get_amount_of_accessed_addresses_for_segment(4),
5572            Some(8)
5573        );
5574        assert_eq!(
5575            vm.segments
5576                .memory
5577                .get_amount_of_accessed_addresses_for_segment(1),
5578            Some(6)
5579        );
5580    }
5581}