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