cairo_vm/vm/
vm_core.rs

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