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