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