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