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