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