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