1use crate::{
2 air_private_input::AirPrivateInput,
3 air_public_input::{PublicInput, PublicInputError},
4 math_utils::safe_div_usize,
5 stdlib::{
6 any::Any,
7 collections::{BTreeMap, HashMap, HashSet},
8 ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
9 prelude::*,
10 },
11 types::{builtin_name::BuiltinName, layout::CairoLayoutParams, layout_name::LayoutName},
12 vm::{
13 runners::builtin_runner::SegmentArenaBuiltinRunner,
14 trace::trace_entry::{relocate_trace_register, RelocatedTraceEntry, TraceEntry},
15 },
16 Felt252,
17};
18
19use crate::{
20 hint_processor::hint_processor_definition::{HintProcessor, HintReference},
21 types::{
22 errors::{math_errors::MathError, program_errors::ProgramError},
23 exec_scope::ExecutionScopes,
24 layout::CairoLayout,
25 program::Program,
26 relocatable::{relocate_address, relocate_value, MaybeRelocatable, Relocatable},
27 },
28 utils::is_subsequence,
29 vm::{
30 errors::{
31 cairo_run_errors::CairoRunError,
32 memory_errors::{InsufficientAllocatedCellsError, MemoryError},
33 runner_errors::RunnerError,
34 trace_errors::TraceError,
35 vm_errors::VirtualMachineError,
36 vm_exception::VmException,
37 },
38 security::verify_secure_runner,
39 {
40 runners::builtin_runner::{
41 BitwiseBuiltinRunner, BuiltinRunner, EcOpBuiltinRunner, HashBuiltinRunner,
42 OutputBuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner,
43 },
44 vm_core::VirtualMachine,
45 },
46 },
47};
48use num_integer::div_rem;
49use num_traits::{ToPrimitive, Zero};
50use serde::{Deserialize, Serialize};
51
52use super::{builtin_runner::ModBuiltinRunner, cairo_pie::CairoPieAdditionalData};
53use super::{
54 builtin_runner::{
55 KeccakBuiltinRunner, PoseidonBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD,
56 },
57 cairo_pie::{self, CairoPie, CairoPieMetadata, CairoPieVersion},
58};
59use crate::types::instance_definitions::mod_instance_def::ModInstanceDef;
60
61#[derive(Clone, Debug, Eq, PartialEq)]
62pub enum CairoArg {
63 Single(MaybeRelocatable),
64 Array(Vec<MaybeRelocatable>),
65 Composed(Vec<CairoArg>),
66}
67
68impl From<MaybeRelocatable> for CairoArg {
69 fn from(other: MaybeRelocatable) -> Self {
70 CairoArg::Single(other)
71 }
72}
73
74impl From<Vec<MaybeRelocatable>> for CairoArg {
75 fn from(other: Vec<MaybeRelocatable>) -> Self {
76 CairoArg::Array(other)
77 }
78}
79
80#[derive(Clone, Default, Debug, PartialEq)]
86pub struct RunResources {
87 n_steps: Option<usize>,
88}
89
90pub trait ResourceTracker {
96 fn consumed(&self) -> bool {
98 false
99 }
100 fn consume_step(&mut self) {}
102 fn get_n_steps(&self) -> Option<usize> {
104 None
105 }
106 fn run_resources(&self) -> &RunResources {
108 &RunResources { n_steps: None }
109 }
110}
111
112impl RunResources {
113 pub fn new(n_steps: usize) -> Self {
114 Self {
115 n_steps: Some(n_steps),
116 }
117 }
118}
119
120impl ResourceTracker for RunResources {
121 fn consumed(&self) -> bool {
122 if self.n_steps == Some(0) {
123 return true;
124 }
125 false
126 }
127
128 fn consume_step(&mut self) {
129 if let Some(n_steps) = self.n_steps {
130 self.n_steps = Some(n_steps.saturating_sub(1));
131 }
132 }
133
134 fn get_n_steps(&self) -> Option<usize> {
135 self.n_steps
136 }
137
138 fn run_resources(&self) -> &RunResources {
139 self
140 }
141}
142
143pub struct CairoRunner {
144 pub vm: VirtualMachine,
145 pub(crate) program: Program,
146 layout: CairoLayout,
147 final_pc: Option<Relocatable>,
148 pub program_base: Option<Relocatable>,
149 execution_base: Option<Relocatable>,
150 entrypoint: Option<usize>,
151 initial_ap: Option<Relocatable>,
152 initial_fp: Option<Relocatable>,
153 initial_pc: Option<Relocatable>,
154 run_ended: bool,
155 segments_finalized: bool,
156 execution_public_memory: Option<Vec<usize>>,
157 pub(crate) runner_mode: RunnerMode,
158 pub relocated_memory: Vec<Option<Felt252>>,
159 pub exec_scopes: ExecutionScopes,
160 pub relocated_trace: Option<Vec<RelocatedTraceEntry>>,
161}
162
163#[derive(Clone, Debug, PartialEq)]
164pub enum RunnerMode {
165 ExecutionMode,
166 ProofModeCanonical,
167 ProofModeCairo1,
168}
169
170impl CairoRunner {
171 pub fn new_v2(
174 program: &Program,
175 layout: LayoutName,
176 dynamic_layout_params: Option<CairoLayoutParams>,
177 mode: RunnerMode,
178 trace_enabled: bool,
179 disable_trace_padding: bool,
180 ) -> Result<CairoRunner, RunnerError> {
181 let cairo_layout = match layout {
182 LayoutName::plain => CairoLayout::plain_instance(),
183 LayoutName::small => CairoLayout::small_instance(),
184 LayoutName::dex => CairoLayout::dex_instance(),
185 LayoutName::recursive => CairoLayout::recursive_instance(),
186 LayoutName::starknet => CairoLayout::starknet_instance(),
187 LayoutName::starknet_with_keccak => CairoLayout::starknet_with_keccak_instance(),
188 LayoutName::recursive_large_output => CairoLayout::recursive_large_output_instance(),
189 LayoutName::recursive_with_poseidon => CairoLayout::recursive_with_poseidon(),
190 LayoutName::all_cairo => CairoLayout::all_cairo_instance(),
191 LayoutName::all_cairo_stwo => CairoLayout::all_cairo_stwo_instance(),
192 LayoutName::all_solidity => CairoLayout::all_solidity_instance(),
193 LayoutName::dynamic => {
194 let params =
195 dynamic_layout_params.ok_or(RunnerError::MissingDynamicLayoutParams)?;
196
197 CairoLayout::dynamic_instance(params)
198 }
199 };
200 Ok(CairoRunner {
201 program: program.clone(),
202 vm: VirtualMachine::new(trace_enabled, disable_trace_padding),
203 layout: cairo_layout,
204 final_pc: None,
205 program_base: None,
206 execution_base: None,
207 entrypoint: program.shared_program_data.main,
208 initial_ap: None,
209 initial_fp: None,
210 initial_pc: None,
211 run_ended: false,
212 segments_finalized: false,
213 runner_mode: mode.clone(),
214 relocated_memory: Vec::new(),
215 exec_scopes: ExecutionScopes::new(),
216 execution_public_memory: if mode != RunnerMode::ExecutionMode {
217 Some(Vec::new())
218 } else {
219 None
220 },
221 relocated_trace: None,
222 })
223 }
224
225 pub fn new(
226 program: &Program,
227 layout: LayoutName,
228 dynamic_layout_params: Option<CairoLayoutParams>,
229 proof_mode: bool,
230 trace_enabled: bool,
231 disable_trace_padding: bool,
232 ) -> Result<CairoRunner, RunnerError> {
233 if disable_trace_padding && !proof_mode {
236 return Err(RunnerError::DisableTracePaddingWithoutProofMode);
237 }
238 if proof_mode {
239 Self::new_v2(
240 program,
241 layout,
242 dynamic_layout_params,
243 RunnerMode::ProofModeCanonical,
244 trace_enabled,
245 disable_trace_padding,
246 )
247 } else {
248 Self::new_v2(
249 program,
250 layout,
251 dynamic_layout_params,
252 RunnerMode::ExecutionMode,
253 trace_enabled,
254 disable_trace_padding,
255 )
256 }
257 }
258
259 pub fn initialize(&mut self, allow_missing_builtins: bool) -> Result<Relocatable, RunnerError> {
260 self.initialize_builtins(allow_missing_builtins)?;
261 self.initialize_segments(None);
262 let end = self.initialize_main_entrypoint()?;
263 for builtin_runner in self.vm.builtin_runners.iter_mut() {
264 if let BuiltinRunner::Mod(runner) = builtin_runner {
265 runner.initialize_zero_segment(&mut self.vm.segments);
266 }
267 }
268 self.initialize_vm()?;
269 Ok(end)
270 }
271
272 pub fn initialize_builtins(&mut self, allow_missing_builtins: bool) -> Result<(), RunnerError> {
279 let builtin_ordered_list = vec![
280 BuiltinName::output,
281 BuiltinName::pedersen,
282 BuiltinName::range_check,
283 BuiltinName::ecdsa,
284 BuiltinName::bitwise,
285 BuiltinName::ec_op,
286 BuiltinName::keccak,
287 BuiltinName::poseidon,
288 BuiltinName::range_check96,
289 BuiltinName::add_mod,
290 BuiltinName::mul_mod,
291 ];
292 if !is_subsequence(&self.program.builtins, &builtin_ordered_list) {
293 return Err(RunnerError::DisorderedBuiltins);
294 };
295 let mut program_builtins: HashSet<&BuiltinName> = self.program.builtins.iter().collect();
296
297 if self.layout.builtins.output {
298 let included = program_builtins.remove(&BuiltinName::output);
299 if included || self.is_proof_mode() {
300 self.vm
301 .builtin_runners
302 .push(OutputBuiltinRunner::new(included).into());
303 }
304 }
305
306 if let Some(instance_def) = self.layout.builtins.pedersen.as_ref() {
307 let included = program_builtins.remove(&BuiltinName::pedersen);
308 if included || self.is_proof_mode() {
309 self.vm
310 .builtin_runners
311 .push(HashBuiltinRunner::new(instance_def.ratio, included).into());
312 }
313 }
314
315 if let Some(instance_def) = self.layout.builtins.range_check.as_ref() {
316 let included = program_builtins.remove(&BuiltinName::range_check);
317 if included || self.is_proof_mode() {
318 self.vm.builtin_runners.push(
319 RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new_with_low_ratio(
320 instance_def.ratio,
321 included,
322 )
323 .into(),
324 );
325 }
326 }
327
328 if let Some(instance_def) = self.layout.builtins.ecdsa.as_ref() {
329 let included = program_builtins.remove(&BuiltinName::ecdsa);
330 if included || self.is_proof_mode() {
331 self.vm
332 .builtin_runners
333 .push(SignatureBuiltinRunner::new(instance_def.ratio, included).into());
334 }
335 }
336
337 if let Some(instance_def) = self.layout.builtins.bitwise.as_ref() {
338 let included = program_builtins.remove(&BuiltinName::bitwise);
339 if included || self.is_proof_mode() {
340 self.vm
341 .builtin_runners
342 .push(BitwiseBuiltinRunner::new(instance_def.ratio, included).into());
343 }
344 }
345
346 if let Some(instance_def) = self.layout.builtins.ec_op.as_ref() {
347 let included = program_builtins.remove(&BuiltinName::ec_op);
348 if included || self.is_proof_mode() {
349 self.vm
350 .builtin_runners
351 .push(EcOpBuiltinRunner::new(instance_def.ratio, included).into());
352 }
353 }
354
355 if let Some(instance_def) = self.layout.builtins.keccak.as_ref() {
356 let included = program_builtins.remove(&BuiltinName::keccak);
357 if included || self.is_proof_mode() {
358 self.vm
359 .builtin_runners
360 .push(KeccakBuiltinRunner::new(instance_def.ratio, included).into());
361 }
362 }
363
364 if let Some(instance_def) = self.layout.builtins.poseidon.as_ref() {
365 let included = program_builtins.remove(&BuiltinName::poseidon);
366 if included || self.is_proof_mode() {
367 self.vm
368 .builtin_runners
369 .push(PoseidonBuiltinRunner::new(instance_def.ratio, included).into());
370 }
371 }
372
373 if let Some(instance_def) = self.layout.builtins.range_check96.as_ref() {
374 let included = program_builtins.remove(&BuiltinName::range_check96);
375 if included || self.is_proof_mode() {
376 self.vm.builtin_runners.push(
377 RangeCheckBuiltinRunner::<RC_N_PARTS_96>::new_with_low_ratio(
378 instance_def.ratio,
379 included,
380 )
381 .into(),
382 );
383 }
384 }
385 if let Some(instance_def) = self.layout.builtins.add_mod.as_ref() {
386 let included = program_builtins.remove(&BuiltinName::add_mod);
387 if included || self.is_proof_mode() {
388 self.vm
389 .builtin_runners
390 .push(ModBuiltinRunner::new_add_mod(instance_def, included).into());
391 }
392 }
393 if let Some(instance_def) = self.layout.builtins.mul_mod.as_ref() {
394 let included = program_builtins.remove(&BuiltinName::mul_mod);
395 if included || self.is_proof_mode() {
396 self.vm
397 .builtin_runners
398 .push(ModBuiltinRunner::new_mul_mod(instance_def, included).into());
399 }
400 }
401 if !program_builtins.is_empty() && !allow_missing_builtins {
402 return Err(RunnerError::NoBuiltinForInstance(Box::new((
403 program_builtins.iter().map(|n| **n).collect(),
404 self.layout.name,
405 ))));
406 }
407
408 Ok(())
409 }
410
411 fn is_proof_mode(&self) -> bool {
412 self.runner_mode == RunnerMode::ProofModeCanonical
413 || self.runner_mode == RunnerMode::ProofModeCairo1
414 }
415
416 pub fn initialize_program_builtins(&mut self) -> Result<(), RunnerError> {
419 fn initialize_builtin(name: BuiltinName, vm: &mut VirtualMachine) {
420 match name {
421 BuiltinName::pedersen => vm
422 .builtin_runners
423 .push(HashBuiltinRunner::new(Some(32), true).into()),
424 BuiltinName::range_check => vm.builtin_runners.push(
425 RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(1), true).into(),
426 ),
427 BuiltinName::output => vm
428 .builtin_runners
429 .push(OutputBuiltinRunner::new(true).into()),
430 BuiltinName::ecdsa => vm
431 .builtin_runners
432 .push(SignatureBuiltinRunner::new(Some(1), true).into()),
433 BuiltinName::bitwise => vm
434 .builtin_runners
435 .push(BitwiseBuiltinRunner::new(Some(1), true).into()),
436 BuiltinName::ec_op => vm
437 .builtin_runners
438 .push(EcOpBuiltinRunner::new(Some(1), true).into()),
439 BuiltinName::keccak => vm
440 .builtin_runners
441 .push(KeccakBuiltinRunner::new(Some(1), true).into()),
442 BuiltinName::poseidon => vm
443 .builtin_runners
444 .push(PoseidonBuiltinRunner::new(Some(1), true).into()),
445 BuiltinName::segment_arena => vm
446 .builtin_runners
447 .push(SegmentArenaBuiltinRunner::new(true).into()),
448 BuiltinName::range_check96 => vm
449 .builtin_runners
450 .push(RangeCheckBuiltinRunner::<RC_N_PARTS_96>::new(Some(1), true).into()),
451 BuiltinName::add_mod => vm.builtin_runners.push(
452 ModBuiltinRunner::new_add_mod(&ModInstanceDef::new(Some(1), 1, 96), true)
453 .into(),
454 ),
455 BuiltinName::mul_mod => vm.builtin_runners.push(
456 ModBuiltinRunner::new_mul_mod(&ModInstanceDef::new(Some(1), 1, 96), true)
457 .into(),
458 ),
459 }
460 }
461
462 for builtin_name in &self.program.builtins {
463 initialize_builtin(*builtin_name, &mut self.vm);
464 }
465 Ok(())
466 }
467
468 pub fn initialize_segments(&mut self, program_base: Option<Relocatable>) {
470 self.program_base = match program_base {
471 Some(base) => Some(base),
472 None => Some(self.vm.add_memory_segment()),
473 };
474 self.execution_base = Some(self.vm.add_memory_segment());
475 for builtin_runner in self.vm.builtin_runners.iter_mut() {
476 builtin_runner.initialize_segments(&mut self.vm.segments);
477 }
478 }
479
480 fn initialize_state(
481 &mut self,
482 entrypoint: usize,
483 stack: Vec<MaybeRelocatable>,
484 ) -> Result<(), RunnerError> {
485 let prog_base = self.program_base.ok_or(RunnerError::NoProgBase)?;
486 let exec_base = self.execution_base.ok_or(RunnerError::NoExecBase)?;
487 self.initial_pc = Some((prog_base + entrypoint)?);
488 self.vm
489 .load_data(prog_base, &self.program.shared_program_data.data)
490 .map_err(RunnerError::MemoryInitializationError)?;
491
492 for i in 0..self.program.shared_program_data.data.len() {
494 self.vm.segments.memory.mark_as_accessed((prog_base + i)?);
495 }
496 self.vm
497 .segments
498 .load_data(exec_base, &stack)
499 .map_err(RunnerError::MemoryInitializationError)?;
500 Ok(())
501 }
502
503 pub fn initialize_function_entrypoint(
504 &mut self,
505 entrypoint: usize,
506 mut stack: Vec<MaybeRelocatable>,
507 return_fp: MaybeRelocatable,
508 ) -> Result<Relocatable, RunnerError> {
509 let end = self.vm.add_memory_segment();
510 stack.append(&mut vec![
511 return_fp,
512 MaybeRelocatable::RelocatableValue(end),
513 ]);
514 if let Some(base) = &self.execution_base {
515 self.initial_fp = Some(Relocatable {
516 segment_index: base.segment_index,
517 offset: base.offset + stack.len(),
518 });
519 self.initial_ap = self.initial_fp;
520 } else {
521 return Err(RunnerError::NoExecBase);
522 }
523 self.initialize_state(entrypoint, stack)?;
524 self.final_pc = Some(end);
525 Ok(end)
526 }
527
528 fn initialize_main_entrypoint(&mut self) -> Result<Relocatable, RunnerError> {
532 let mut stack = Vec::new();
533 {
534 let builtin_runners = self
535 .vm
536 .builtin_runners
537 .iter()
538 .map(|b| (b.name(), b))
539 .collect::<HashMap<_, _>>();
540 for builtin_name in &self.program.builtins {
541 if let Some(builtin_runner) = builtin_runners.get(builtin_name) {
542 stack.append(&mut builtin_runner.initial_stack());
543 } else {
544 stack.push(Felt252::ZERO.into())
545 }
546 }
547 }
548
549 if self.is_proof_mode() {
550 let mut target_offset = 2;
554
555 if matches!(self.runner_mode, RunnerMode::ProofModeCairo1) {
559 target_offset = stack.len() + 2;
560
561 let return_fp = self.vm.add_memory_segment();
563 let end = self.vm.add_memory_segment();
564 stack.append(&mut vec![
565 MaybeRelocatable::RelocatableValue(return_fp),
566 MaybeRelocatable::RelocatableValue(end),
567 ]);
568
569 self.initialize_state(
570 self.program
571 .shared_program_data
572 .start
573 .ok_or(RunnerError::NoProgramStart)?,
574 stack,
575 )?;
576 } else {
577 let mut stack_prefix = vec![
578 Into::<MaybeRelocatable>::into(
579 (self.execution_base.ok_or(RunnerError::NoExecBase)? + target_offset)?,
580 ),
581 MaybeRelocatable::from(Felt252::zero()),
582 ];
583 stack_prefix.extend(stack.clone());
584
585 self.execution_public_memory = Some(Vec::from_iter(0..stack_prefix.len()));
586
587 self.initialize_state(
588 self.program
589 .shared_program_data
590 .start
591 .ok_or(RunnerError::NoProgramStart)?,
592 stack_prefix.clone(),
593 )?;
594 }
595
596 self.initial_fp =
597 Some((self.execution_base.ok_or(RunnerError::NoExecBase)? + target_offset)?);
598
599 self.initial_ap = self.initial_fp;
600 return Ok((self.program_base.ok_or(RunnerError::NoProgBase)?
601 + self
602 .program
603 .shared_program_data
604 .end
605 .ok_or(RunnerError::NoProgramEnd)?)?);
606 }
607
608 let return_fp = self.vm.add_memory_segment();
609 if let Some(main) = &self.entrypoint {
610 let main_clone = *main;
611 Ok(self.initialize_function_entrypoint(
612 main_clone,
613 stack,
614 MaybeRelocatable::RelocatableValue(return_fp),
615 )?)
616 } else {
617 Err(RunnerError::MissingMain)
618 }
619 }
620
621 pub fn initialize_vm(&mut self) -> Result<(), RunnerError> {
622 self.vm.run_context.pc = *self.initial_pc.as_ref().ok_or(RunnerError::NoPC)?;
623 self.vm.run_context.ap = self.initial_ap.as_ref().ok_or(RunnerError::NoAP)?.offset;
624 self.vm.run_context.fp = self.initial_fp.as_ref().ok_or(RunnerError::NoFP)?.offset;
625 for builtin in self.vm.builtin_runners.iter() {
626 builtin.add_validation_rule(&mut self.vm.segments.memory);
627 }
628
629 self.vm
630 .segments
631 .memory
632 .validate_existing_memory()
633 .map_err(RunnerError::MemoryValidationError)
634 }
635
636 pub fn get_initial_fp(&self) -> Option<Relocatable> {
637 self.initial_fp
638 }
639
640 pub fn get_hint_data(
642 &self,
643 references: &[HintReference],
644 hint_executor: &mut dyn HintProcessor,
645 ) -> Result<Vec<Box<dyn Any>>, VirtualMachineError> {
646 self.program
647 .shared_program_data
648 .hints_collection
649 .iter_hints()
650 .map(|hint| {
651 hint_executor
652 .compile_hint(
653 &hint.code,
654 &hint.flow_tracking_data.ap_tracking,
655 &hint.flow_tracking_data.reference_ids,
656 references,
657 )
658 .map_err(|_| VirtualMachineError::CompileHintFail(hint.code.clone().into()))
659 })
660 .collect()
661 }
662
663 pub fn get_constants(&self) -> &HashMap<String, Felt252> {
664 &self.program.constants
665 }
666
667 pub fn get_program_builtins(&self) -> &Vec<BuiltinName> {
668 &self.program.builtins
669 }
670
671 pub fn run_until_pc(
672 &mut self,
673 address: Relocatable,
674 hint_processor: &mut dyn HintProcessor,
675 ) -> Result<(), VirtualMachineError> {
676 let references = &self.program.shared_program_data.reference_manager;
677 #[cfg(not(feature = "extensive_hints"))]
678 let hint_data = self.get_hint_data(references, hint_processor)?;
679 #[cfg(feature = "extensive_hints")]
680 let mut hint_data = self.get_hint_data(references, hint_processor)?;
681 #[cfg(feature = "extensive_hints")]
682 let mut hint_ranges = self
683 .program
684 .shared_program_data
685 .hints_collection
686 .hints_ranges
687 .clone();
688 #[cfg(feature = "test_utils")]
689 self.vm.execute_before_first_step(&hint_data)?;
690 while self.vm.get_pc() != address && !hint_processor.consumed() {
691 self.vm.step(
692 hint_processor,
693 &mut self.exec_scopes,
694 #[cfg(feature = "extensive_hints")]
695 &mut hint_data,
696 #[cfg(not(feature = "extensive_hints"))]
697 self.program
698 .shared_program_data
699 .hints_collection
700 .get_hint_range_for_pc(self.vm.get_pc().offset)
701 .and_then(|range| {
702 range.and_then(|(start, length)| hint_data.get(start..start + length.get()))
703 })
704 .unwrap_or(&[]),
705 #[cfg(feature = "extensive_hints")]
706 &mut hint_ranges,
707 &self.program.constants,
708 )?;
709
710 hint_processor.consume_step();
711 }
712
713 if self.vm.get_pc() != address {
714 return Err(VirtualMachineError::UnfinishedExecution);
715 }
716
717 Ok(())
718 }
719
720 pub fn run_for_steps(
722 &mut self,
723 steps: usize,
724 hint_processor: &mut dyn HintProcessor,
725 ) -> Result<(), VirtualMachineError> {
726 let references = &self.program.shared_program_data.reference_manager;
727 #[cfg(not(feature = "extensive_hints"))]
728 let hint_data = self.get_hint_data(references, hint_processor)?;
729 #[cfg(feature = "extensive_hints")]
730 let mut hint_data = self.get_hint_data(references, hint_processor)?;
731 #[cfg(feature = "extensive_hints")]
732 let mut hint_ranges = self
733 .program
734 .shared_program_data
735 .hints_collection
736 .hints_ranges
737 .clone();
738 #[cfg(not(feature = "extensive_hints"))]
739 let hint_data = &self
740 .program
741 .shared_program_data
742 .hints_collection
743 .get_hint_range_for_pc(self.vm.get_pc().offset)
744 .and_then(|range| {
745 range.and_then(|(start, length)| hint_data.get(start..start + length.get()))
746 })
747 .unwrap_or(&[]);
748
749 for remaining_steps in (1..=steps).rev() {
750 if self.final_pc.as_ref() == Some(&self.vm.get_pc()) {
751 return Err(VirtualMachineError::EndOfProgram(remaining_steps));
752 }
753
754 self.vm.step(
755 hint_processor,
756 &mut self.exec_scopes,
757 #[cfg(feature = "extensive_hints")]
758 &mut hint_data,
759 #[cfg(not(feature = "extensive_hints"))]
760 hint_data,
761 #[cfg(feature = "extensive_hints")]
762 &mut hint_ranges,
763 &self.program.constants,
764 )?;
765 }
766
767 Ok(())
768 }
769
770 pub fn run_until_steps(
772 &mut self,
773 steps: usize,
774 hint_processor: &mut dyn HintProcessor,
775 ) -> Result<(), VirtualMachineError> {
776 self.run_for_steps(steps.saturating_sub(self.vm.current_step), hint_processor)
777 }
778
779 pub fn run_until_next_power_of_2(
781 &mut self,
782 hint_processor: &mut dyn HintProcessor,
783 ) -> Result<(), VirtualMachineError> {
784 self.run_until_steps(self.vm.current_step.next_power_of_two(), hint_processor)
785 }
786
787 pub fn get_perm_range_check_limits(&self) -> Option<(isize, isize)> {
788 let runner_usages = self
789 .vm
790 .builtin_runners
791 .iter()
792 .filter_map(|runner| runner.get_range_check_usage(&self.vm.segments.memory))
793 .map(|(rc_min, rc_max)| (rc_min as isize, rc_max as isize));
794 let rc_bounds = self.vm.rc_limits.iter().copied().chain(runner_usages);
795 rc_bounds.reduce(|(min1, max1), (min2, max2)| (min1.min(min2), max1.max(max2)))
796 }
797
798 pub fn check_range_check_usage(&self) -> Result<(), VirtualMachineError> {
801 let Some((rc_min, rc_max)) = self.get_perm_range_check_limits() else {
802 return Ok(());
803 };
804
805 let rc_units_used_by_builtins: usize = self
806 .vm
807 .builtin_runners
808 .iter()
809 .map(|runner| runner.get_used_perm_range_check_units(&self.vm))
810 .sum::<Result<usize, MemoryError>>()
811 .map_err(Into::<VirtualMachineError>::into)?;
812
813 let unused_rc_units =
814 (self.layout.rc_units as usize - 3) * self.vm.current_step - rc_units_used_by_builtins;
815 if unused_rc_units < (rc_max - rc_min) as usize {
816 return Err(MemoryError::InsufficientAllocatedCells(
817 InsufficientAllocatedCellsError::RangeCheckUnits(Box::new((
818 unused_rc_units,
819 (rc_max - rc_min) as usize,
820 ))),
821 )
822 .into());
823 }
824
825 Ok(())
826 }
827
828 pub fn get_memory_holes(&self) -> Result<usize, MemoryError> {
830 let builtin_segment_indexes: HashSet<usize> = self
832 .vm
833 .builtin_runners
834 .iter()
835 .filter(|b| b.name() != BuiltinName::output)
836 .map(|b| b.base())
837 .collect();
838
839 self.vm.segments.get_memory_holes(builtin_segment_indexes)
840 }
841
842 pub fn check_diluted_check_usage(&self) -> Result<(), VirtualMachineError> {
844 let diluted_pool_instance = match &self.layout.diluted_pool_instance_def {
845 Some(x) => x,
846 None => return Ok(()),
847 };
848
849 let mut used_units_by_builtins = 0;
850 for builtin_runner in &self.vm.builtin_runners {
851 let used_units = builtin_runner.get_used_diluted_check_units(
852 diluted_pool_instance.spacing,
853 diluted_pool_instance.n_bits,
854 );
855
856 let multiplier = builtin_runner.get_allocated_instances(&self.vm)?;
857
858 used_units_by_builtins += used_units * multiplier;
859 }
860
861 let diluted_units = if !diluted_pool_instance.fractional_units_per_step {
862 diluted_pool_instance.units_per_step as usize * self.vm.current_step
863 } else {
864 safe_div_usize(
865 self.vm.current_step,
866 diluted_pool_instance.units_per_step as usize,
867 )?
868 };
869
870 let unused_diluted_units = diluted_units.saturating_sub(used_units_by_builtins);
871
872 let diluted_usage_upper_bound = 1usize << diluted_pool_instance.n_bits;
873 if unused_diluted_units < diluted_usage_upper_bound {
874 return Err(MemoryError::InsufficientAllocatedCells(
875 InsufficientAllocatedCellsError::DilutedCells(Box::new((
876 unused_diluted_units,
877 diluted_usage_upper_bound,
878 ))),
879 )
880 .into());
881 }
882
883 Ok(())
884 }
885
886 pub fn end_run(
887 &mut self,
888 disable_trace_padding: bool,
889 disable_finalize_all: bool,
890 hint_processor: &mut dyn HintProcessor,
891 ) -> Result<(), VirtualMachineError> {
892 if self.run_ended {
893 return Err(RunnerError::EndRunCalledTwice.into());
894 }
895
896 self.vm.segments.memory.relocate_memory()?;
897 self.vm.end_run(&self.exec_scopes)?;
898
899 if disable_finalize_all {
900 return Ok(());
901 }
902
903 self.vm.segments.compute_effective_sizes();
904 if self.is_proof_mode() && !disable_trace_padding {
905 self.run_until_next_power_of_2(hint_processor)?;
906 loop {
907 match self.check_used_cells() {
908 Ok(_) => break,
909 Err(e) => match e {
910 VirtualMachineError::Memory(MemoryError::InsufficientAllocatedCells(_)) => {
911 }
912 e => return Err(e),
913 },
914 }
915
916 self.run_for_steps(1, hint_processor)?;
917 self.run_until_next_power_of_2(hint_processor)?;
918 }
919 }
920
921 self.run_ended = true;
922 Ok(())
923 }
924
925 pub fn relocate_trace(&mut self, relocation_table: &[usize]) -> Result<(), TraceError> {
927 if self.relocated_trace.is_some() {
928 return Err(TraceError::AlreadyRelocated);
929 }
930
931 let trace = self
932 .vm
933 .trace
934 .as_ref()
935 .ok_or(TraceError::TraceNotEnabled)?
936 .iter();
937 let mut relocated_trace = Vec::<RelocatedTraceEntry>::with_capacity(trace.len());
938 let segment_1_base = relocation_table
939 .get(1)
940 .ok_or(TraceError::NoRelocationFound)?;
941
942 for entry in trace {
943 relocated_trace.push(RelocatedTraceEntry {
944 pc: relocate_trace_register(entry.pc, relocation_table)?,
945 ap: entry.ap + segment_1_base,
946 fp: entry.fp + segment_1_base,
947 })
948 }
949 self.relocated_trace = Some(relocated_trace);
950 Ok(())
951 }
952
953 fn relocate_memory(&mut self, relocation_table: &[usize]) -> Result<(), MemoryError> {
957 if !(self.relocated_memory.is_empty()) {
958 return Err(MemoryError::Relocation);
959 }
960 self.relocated_memory.push(None);
962 for (index, segment) in self.vm.segments.memory.data.iter().enumerate() {
963 for (seg_offset, cell) in segment.iter().enumerate() {
964 match cell.get_value() {
965 Some(cell) => {
966 let relocated_addr = relocate_address(
967 Relocatable::from((index as isize, seg_offset)),
968 relocation_table,
969 )?;
970 let value = relocate_value(cell, relocation_table)?;
971 if self.relocated_memory.len() <= relocated_addr {
972 self.relocated_memory.resize(relocated_addr + 1, None);
973 }
974 self.relocated_memory[relocated_addr] = Some(value);
975 }
976 None => self.relocated_memory.push(None),
977 }
978 }
979 }
980 Ok(())
981 }
982
983 pub fn relocate(&mut self, relocate_mem: bool) -> Result<(), TraceError> {
984 self.vm.segments.compute_effective_sizes();
985 if !relocate_mem && self.vm.trace.is_none() {
986 return Ok(());
987 }
988 let relocation_table = self
991 .vm
992 .segments
993 .relocate_segments()
994 .expect("compute_effective_sizes called but relocate_memory still returned error");
995
996 if relocate_mem {
997 if let Err(memory_error) = self.relocate_memory(&relocation_table) {
998 return Err(TraceError::MemoryError(memory_error));
999 }
1000 }
1001 if self.vm.trace.is_some() {
1002 self.relocate_trace(&relocation_table)?;
1003 }
1004 self.vm.relocation_table = Some(relocation_table);
1005 Ok(())
1006 }
1007
1008 pub fn get_builtin_segments_info(&self) -> Result<Vec<(usize, usize)>, RunnerError> {
1011 let mut builtin_segment_info = Vec::new();
1012
1013 for builtin in &self.vm.builtin_runners {
1014 let (index, stop_ptr) = builtin.get_memory_segment_addresses();
1015
1016 builtin_segment_info.push((
1017 index,
1018 stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))?,
1019 ));
1020 }
1021
1022 Ok(builtin_segment_info)
1023 }
1024
1025 pub fn get_builtin_segment_info_for_pie(
1028 &self,
1029 ) -> Result<HashMap<BuiltinName, cairo_pie::SegmentInfo>, RunnerError> {
1030 let mut builtin_segment_info = HashMap::new();
1031
1032 for builtin in &self.vm.builtin_runners {
1033 let (index, stop_ptr) = builtin.get_memory_segment_addresses();
1034
1035 builtin_segment_info.insert(
1036 builtin.name(),
1037 (
1038 index as isize,
1039 stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))?,
1040 )
1041 .into(),
1042 );
1043 }
1044
1045 Ok(builtin_segment_info)
1046 }
1047
1048 pub fn get_execution_resources(&self) -> Result<ExecutionResources, RunnerError> {
1049 let n_steps = self
1050 .vm
1051 .trace
1052 .as_ref()
1053 .map(|x| x.len())
1054 .unwrap_or(self.vm.current_step);
1055 let n_memory_holes = self.get_memory_holes()?;
1056
1057 let mut builtin_instance_counter = HashMap::new();
1058 for builtin_runner in &self.vm.builtin_runners {
1059 builtin_instance_counter.insert(
1060 builtin_runner.name(),
1061 builtin_runner.get_used_instances(&self.vm.segments)?,
1062 );
1063 }
1064
1065 Ok(ExecutionResources {
1066 n_steps,
1067 n_memory_holes,
1068 builtin_instance_counter,
1069 })
1070 }
1071
1072 pub fn finalize_segments(&mut self) -> Result<(), RunnerError> {
1078 if self.segments_finalized {
1079 return Ok(());
1080 }
1081 if !self.run_ended {
1082 return Err(RunnerError::FinalizeNoEndRun);
1083 }
1084 let size = self.program.shared_program_data.data.len();
1085 let mut public_memory = Vec::with_capacity(size);
1086 for i in 0..size {
1087 public_memory.push((i, 0_usize))
1088 }
1089 self.vm.segments.finalize(
1090 Some(size),
1091 self.program_base
1092 .as_ref()
1093 .ok_or(RunnerError::NoProgBase)?
1094 .segment_index as usize,
1095 Some(&public_memory),
1096 );
1097 let mut public_memory = Vec::with_capacity(size);
1098 let exec_base = self
1099 .execution_base
1100 .as_ref()
1101 .ok_or(RunnerError::NoExecBase)?;
1102 for elem in self
1103 .execution_public_memory
1104 .as_ref()
1105 .ok_or(RunnerError::FinalizeSegmentsNoProofMode)?
1106 .iter()
1107 {
1108 public_memory.push((elem + exec_base.offset, 0))
1109 }
1110 self.vm
1111 .segments
1112 .finalize(None, exec_base.segment_index as usize, Some(&public_memory));
1113 for builtin_runner in self.vm.builtin_runners.iter() {
1114 let (_, size) = builtin_runner
1115 .get_used_cells_and_allocated_size(&self.vm)
1116 .map_err(RunnerError::FinalizeSegements)?;
1117 if let BuiltinRunner::Output(output_builtin) = builtin_runner {
1118 let public_memory = output_builtin.get_public_memory(&self.vm.segments)?;
1119 self.vm
1120 .segments
1121 .finalize(Some(size), builtin_runner.base(), Some(&public_memory))
1122 } else {
1123 self.vm
1124 .segments
1125 .finalize(Some(size), builtin_runner.base(), None)
1126 }
1127 }
1128 self.vm.segments.finalize_zero_segment();
1129 self.segments_finalized = true;
1130 Ok(())
1131 }
1132
1133 #[allow(clippy::result_large_err)]
1134 pub fn run_from_entrypoint(
1138 &mut self,
1139 entrypoint: usize,
1140 args: &[&CairoArg],
1141 verify_secure: bool,
1142 program_segment_size: Option<usize>,
1143 hint_processor: &mut dyn HintProcessor,
1144 ) -> Result<(), CairoRunError> {
1145 let stack = args
1146 .iter()
1147 .map(|arg| self.vm.segments.gen_cairo_arg(arg))
1148 .collect::<Result<Vec<MaybeRelocatable>, VirtualMachineError>>()?;
1149 let return_fp = MaybeRelocatable::from(0);
1150 let end = self.initialize_function_entrypoint(entrypoint, stack, return_fp)?;
1151
1152 self.initialize_vm()?;
1153
1154 self.run_until_pc(end, hint_processor)
1155 .map_err(|err| VmException::from_vm_error(self, err))?;
1156 self.end_run(true, false, hint_processor)?;
1157
1158 if verify_secure {
1159 verify_secure_runner(self, false, program_segment_size)?;
1160 }
1161
1162 Ok(())
1163 }
1164
1165 pub fn check_used_cells(&self) -> Result<(), VirtualMachineError> {
1168 self.vm
1169 .builtin_runners
1170 .iter()
1171 .map(|builtin_runner| builtin_runner.get_used_cells_and_allocated_size(&self.vm))
1172 .collect::<Result<Vec<(usize, usize)>, MemoryError>>()?;
1173 self.check_range_check_usage()?;
1174 self.check_memory_usage()?;
1175 self.check_diluted_check_usage()?;
1176 Ok(())
1177 }
1178
1179 pub fn check_memory_usage(&self) -> Result<(), VirtualMachineError> {
1181 let instance = &self.layout;
1182
1183 let builtins_memory_units: usize = self
1184 .vm
1185 .builtin_runners
1186 .iter()
1187 .map(|builtin_runner| builtin_runner.get_allocated_memory_units(&self.vm))
1188 .collect::<Result<Vec<usize>, MemoryError>>()?
1189 .iter()
1190 .sum();
1191
1192 let builtins_memory_units = builtins_memory_units as u32;
1193
1194 let vm_current_step_u32 = self.vm.current_step as u32;
1195
1196 let total_memory_units = instance.memory_units_per_step * vm_current_step_u32;
1199 let (public_memory_units, rem) =
1200 div_rem(total_memory_units, instance.public_memory_fraction);
1201 if rem != 0 {
1202 return Err(MathError::SafeDivFailU32(
1203 total_memory_units,
1204 instance.public_memory_fraction,
1205 )
1206 .into());
1207 }
1208
1209 let instruction_memory_units = 4 * vm_current_step_u32;
1210
1211 let unused_memory_units = total_memory_units
1212 - (public_memory_units + instruction_memory_units + builtins_memory_units);
1213 let memory_address_holes = self.get_memory_holes()?;
1214 if unused_memory_units < memory_address_holes as u32 {
1215 Err(MemoryError::InsufficientAllocatedCells(
1216 InsufficientAllocatedCellsError::MemoryAddresses(Box::new((
1217 unused_memory_units,
1218 memory_address_holes,
1219 ))),
1220 ))?
1221 }
1222 Ok(())
1223 }
1224
1225 pub fn initialize_function_runner_cairo_1(
1229 &mut self,
1230 program_builtins: &[BuiltinName],
1231 ) -> Result<(), RunnerError> {
1232 self.program.builtins = program_builtins.to_vec();
1233 self.initialize_program_builtins()?;
1234 self.initialize_segments(self.program_base);
1235 Ok(())
1236 }
1237
1238 pub fn initialize_function_runner(&mut self) -> Result<(), RunnerError> {
1241 self.initialize_program_builtins()?;
1242 self.initialize_segments(self.program_base);
1243 Ok(())
1244 }
1245
1246 pub fn set_entrypoint(&mut self, new_entrypoint: Option<&str>) -> Result<(), ProgramError> {
1249 let new_entrypoint = new_entrypoint.unwrap_or("main");
1250 self.entrypoint = Some(
1251 self.program
1252 .shared_program_data
1253 .identifiers
1254 .get(&format!("__main__.{new_entrypoint}"))
1255 .and_then(|x| x.pc)
1256 .ok_or_else(|| ProgramError::EntrypointNotFound(new_entrypoint.to_string()))?,
1257 );
1258
1259 Ok(())
1260 }
1261
1262 pub fn read_return_values(&mut self, allow_missing_builtins: bool) -> Result<(), RunnerError> {
1263 if !self.run_ended {
1264 return Err(RunnerError::ReadReturnValuesNoEndRun);
1265 }
1266 let mut pointer = self.vm.get_ap();
1267 for builtin_name in self.program.builtins.iter().rev() {
1268 if let Some(builtin_runner) = self
1269 .vm
1270 .builtin_runners
1271 .iter_mut()
1272 .find(|b| b.name() == *builtin_name)
1273 {
1274 let new_pointer = builtin_runner.final_stack(&self.vm.segments, pointer)?;
1275 pointer = new_pointer;
1276 } else {
1277 if !allow_missing_builtins {
1278 return Err(RunnerError::MissingBuiltin(*builtin_name));
1279 }
1280 pointer.offset = pointer.offset.saturating_sub(1);
1281
1282 if !self.vm.get_integer(pointer)?.is_zero() {
1283 return Err(RunnerError::MissingBuiltinStopPtrNotZero(*builtin_name));
1284 }
1285 }
1286 }
1287 if self.segments_finalized {
1288 return Err(RunnerError::FailedAddingReturnValues);
1289 }
1290 if self.is_proof_mode() {
1291 let exec_base = *self
1292 .execution_base
1293 .as_ref()
1294 .ok_or(RunnerError::NoExecBase)?;
1295 let begin = pointer.offset - exec_base.offset;
1296 let ap = self.vm.get_ap();
1297 let end = ap.offset - exec_base.offset;
1298 self.execution_public_memory
1299 .as_mut()
1300 .ok_or(RunnerError::NoExecPublicMemory)?
1301 .extend(begin..end);
1302 }
1303 Ok(())
1304 }
1305
1306 pub fn get_builtins_final_stack(
1309 &mut self,
1310 stack_ptr: Relocatable,
1311 ) -> Result<Relocatable, RunnerError> {
1312 let mut stack_ptr = Relocatable::from(&stack_ptr);
1313 for runner in self
1314 .vm
1315 .builtin_runners
1316 .iter_mut()
1317 .rev()
1318 .filter(|builtin_runner| {
1319 self.program
1320 .builtins
1321 .iter()
1322 .any(|bn| *bn == builtin_runner.name())
1323 })
1324 {
1325 stack_ptr = runner.final_stack(&self.vm.segments, stack_ptr)?
1326 }
1327 Ok(stack_ptr)
1328 }
1329
1330 pub fn get_program(&self) -> &Program {
1332 &self.program
1333 }
1334
1335 pub fn get_cairo_pie(&self) -> Result<CairoPie, RunnerError> {
1337 let program_base = self.program_base.ok_or(RunnerError::NoProgBase)?;
1338 let execution_base = self.execution_base.ok_or(RunnerError::NoExecBase)?;
1339
1340 let builtin_segments = self.get_builtin_segment_info_for_pie()?;
1341 let mut known_segment_indices = HashSet::new();
1342 for info in builtin_segments.values() {
1343 known_segment_indices.insert(info.index);
1344 }
1345 let n_used_builtins = self.program.builtins_len();
1346 let return_fp_addr = (execution_base + n_used_builtins)?;
1347 let return_fp = self.vm.get_relocatable(return_fp_addr)?;
1348 let return_pc = self.vm.get_relocatable((return_fp_addr + 1)?)?;
1349
1350 if let None | Some(false) = return_fp
1351 .segment_index
1352 .to_usize()
1353 .and_then(|u| self.vm.get_segment_size(u))
1354 .map(|u| u.is_zero())
1355 {
1356 return Err(RunnerError::UnexpectedRetFpSegmentSize);
1358 }
1359
1360 if let None | Some(false) = return_pc
1361 .segment_index
1362 .to_usize()
1363 .and_then(|u| self.vm.get_segment_size(u))
1364 .map(|u| u.is_zero())
1365 {
1366 return Err(RunnerError::UnexpectedRetPcSegmentSize);
1368 }
1369
1370 if program_base.offset != 0 {
1371 return Err(RunnerError::ProgramBaseOffsetNotZero);
1372 }
1373 known_segment_indices.insert(program_base.segment_index);
1374
1375 if execution_base.offset != 0 {
1376 return Err(RunnerError::ExecBaseOffsetNotZero);
1377 }
1378 known_segment_indices.insert(execution_base.segment_index);
1379
1380 if return_fp.offset != 0 {
1381 return Err(RunnerError::RetFpOffsetNotZero);
1382 }
1383 known_segment_indices.insert(return_fp.segment_index);
1384
1385 if return_pc.offset != 0 {
1386 return Err(RunnerError::RetPcOffsetNotZero);
1387 }
1388 known_segment_indices.insert(return_pc.segment_index);
1389
1390 let mut extra_segments = Vec::default();
1392 for index in 0..self.vm.segments.num_segments() {
1393 if !known_segment_indices.contains(&(index as isize)) {
1394 extra_segments.push(
1395 (
1396 index as isize,
1397 self.vm
1398 .get_segment_size(index)
1399 .ok_or(MemoryError::MissingSegmentUsedSizes)?,
1400 )
1401 .into(),
1402 );
1403 }
1404 }
1405
1406 let execution_size = (self.vm.get_ap() - execution_base)?;
1407 let metadata = CairoPieMetadata {
1408 program: self
1409 .get_program()
1410 .get_stripped_program()
1411 .map_err(|_| RunnerError::StrippedProgramNoMain)?,
1412 program_segment: (program_base.segment_index, self.program.data_len()).into(),
1413 execution_segment: (execution_base.segment_index, execution_size).into(),
1414 ret_fp_segment: (return_fp.segment_index, 0).into(),
1415 ret_pc_segment: (return_pc.segment_index, 0).into(),
1416 builtin_segments,
1417 extra_segments,
1418 };
1419
1420 Ok(CairoPie {
1421 metadata,
1422 memory: (&self.vm.segments.memory).into(),
1423 execution_resources: self.get_execution_resources()?,
1424 additional_data: CairoPieAdditionalData(
1425 self.vm
1426 .builtin_runners
1427 .iter()
1428 .map(|b| (b.name(), b.get_additional_data()))
1429 .collect(),
1430 ),
1431 version: CairoPieVersion { cairo_pie: () },
1432 })
1433 }
1434
1435 pub fn get_air_public_input(&self) -> Result<PublicInput, PublicInputError> {
1436 PublicInput::new(
1437 &self.relocated_memory,
1438 self.layout.name.to_str(),
1439 &self.vm.get_public_memory_addresses()?,
1440 self.get_memory_segment_addresses()?,
1441 self.relocated_trace
1442 .as_ref()
1443 .ok_or(PublicInputError::EmptyTrace)?,
1444 self.get_perm_range_check_limits()
1445 .ok_or(PublicInputError::NoRangeCheckLimits)?,
1446 )
1447 }
1448
1449 pub fn get_air_private_input(&self) -> AirPrivateInput {
1450 let mut private_inputs = HashMap::new();
1451 for builtin in self.vm.builtin_runners.iter() {
1452 private_inputs.insert(builtin.name(), builtin.air_private_input(&self.vm.segments));
1453 }
1454 AirPrivateInput(private_inputs)
1455 }
1456
1457 pub fn get_memory_segment_addresses(
1458 &self,
1459 ) -> Result<HashMap<&'static str, (usize, usize)>, VirtualMachineError> {
1460 let relocation_table = self
1461 .vm
1462 .relocation_table
1463 .as_ref()
1464 .ok_or(MemoryError::UnrelocatedMemory)?;
1465
1466 let relocate = |segment: (usize, usize)| -> Result<(usize, usize), VirtualMachineError> {
1467 let (index, stop_ptr_offset) = segment;
1468 let base = relocation_table
1469 .get(index)
1470 .ok_or(VirtualMachineError::RelocationNotFound(index))?;
1471 Ok((*base, base + stop_ptr_offset))
1472 };
1473
1474 self.vm
1475 .builtin_runners
1476 .iter()
1477 .map(|builtin| -> Result<_, VirtualMachineError> {
1478 let (base, stop_ptr) = builtin.get_memory_segment_addresses();
1479 let stop_ptr = if self.program.builtins.contains(&builtin.name()) {
1480 stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))?
1481 } else {
1482 stop_ptr.unwrap_or_default()
1483 };
1484
1485 Ok((builtin.name().to_str(), relocate((base, stop_ptr))?))
1486 })
1487 .collect()
1488 }
1489
1490 pub fn get_prover_input_info(&self) -> Result<ProverInputInfo, RunnerError> {
1493 let relocatable_trace = self
1494 .vm
1495 .trace
1496 .as_ref()
1497 .ok_or(RunnerError::Trace(TraceError::TraceNotEnabled))?
1498 .clone();
1499
1500 let relocatable_memory = self
1501 .vm
1502 .segments
1503 .memory
1504 .data
1505 .iter()
1506 .map(|segment| segment.iter().map(|cell| cell.get_value()).collect())
1507 .collect();
1508
1509 let public_memory_offsets = self
1510 .vm
1511 .segments
1512 .public_memory_offsets
1513 .iter()
1514 .map(|(segment, offset_page)| {
1515 let offsets: Vec<usize> = offset_page.iter().map(|(offset, _)| *offset).collect();
1516 (*segment, offsets)
1517 })
1518 .collect();
1519
1520 let builtins_segments: BTreeMap<usize, BuiltinName> = self
1521 .vm
1522 .builtin_runners
1523 .iter()
1524 .filter(|builtin| {
1525 !matches!(
1527 builtin,
1528 BuiltinRunner::SegmentArena(_) | BuiltinRunner::Output(_)
1529 )
1530 })
1531 .map(|builtin| {
1532 let (index, _) = builtin.get_memory_segment_addresses();
1533 (index, builtin.name())
1534 })
1535 .collect();
1536
1537 Ok(ProverInputInfo {
1538 relocatable_trace,
1539 relocatable_memory,
1540 public_memory_offsets,
1541 builtins_segments,
1542 })
1543 }
1544}
1545
1546#[derive(Deserialize, Serialize)]
1552pub struct ProverInputInfo {
1553 pub relocatable_trace: Vec<TraceEntry>,
1555 pub relocatable_memory: Vec<Vec<Option<MaybeRelocatable>>>,
1557 pub public_memory_offsets: BTreeMap<usize, Vec<usize>>,
1559 pub builtins_segments: BTreeMap<usize, BuiltinName>,
1561}
1562
1563#[derive(Clone, Debug, Eq, PartialEq)]
1564pub struct SegmentInfo {
1565 pub index: isize,
1566 pub size: usize,
1567}
1568
1569#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
1574pub struct ExecutionResources {
1575 pub n_steps: usize,
1576 pub n_memory_holes: usize,
1577 #[serde(with = "crate::types::builtin_name::serde_generic_map_impl")]
1578 pub builtin_instance_counter: HashMap<BuiltinName, usize>,
1579}
1580
1581impl ExecutionResources {
1584 pub fn filter_unused_builtins(&self) -> ExecutionResources {
1585 ExecutionResources {
1586 n_steps: self.n_steps,
1587 n_memory_holes: self.n_memory_holes,
1588 builtin_instance_counter: self
1589 .clone()
1590 .builtin_instance_counter
1591 .into_iter()
1592 .filter(|builtin| !builtin.1.is_zero())
1593 .collect(),
1594 }
1595 }
1596}
1597
1598impl Add<&ExecutionResources> for &ExecutionResources {
1599 type Output = ExecutionResources;
1600
1601 fn add(self, rhs: &ExecutionResources) -> ExecutionResources {
1602 let mut new = self.clone();
1603 new.add_assign(rhs);
1604 new
1605 }
1606}
1607
1608impl AddAssign<&ExecutionResources> for ExecutionResources {
1609 fn add_assign(&mut self, rhs: &ExecutionResources) {
1610 self.n_steps += rhs.n_steps;
1611 self.n_memory_holes += rhs.n_memory_holes;
1612 for (k, v) in rhs.builtin_instance_counter.iter() {
1613 *self.builtin_instance_counter.entry(*k).or_insert(0) += v;
1615 }
1616 }
1617}
1618
1619impl Sub<&ExecutionResources> for &ExecutionResources {
1620 type Output = ExecutionResources;
1621
1622 fn sub(self, rhs: &ExecutionResources) -> ExecutionResources {
1623 let mut new = self.clone();
1624 new.sub_assign(rhs);
1625 new
1626 }
1627}
1628
1629impl SubAssign<&ExecutionResources> for ExecutionResources {
1630 fn sub_assign(&mut self, rhs: &ExecutionResources) {
1631 self.n_steps -= rhs.n_steps;
1632 self.n_memory_holes -= rhs.n_memory_holes;
1633 for (k, v) in rhs.builtin_instance_counter.iter() {
1634 let entry = self.builtin_instance_counter.entry(*k).or_insert(0);
1636 *entry = (*entry).saturating_sub(*v);
1637 }
1638 }
1639}
1640
1641impl Mul<usize> for &ExecutionResources {
1642 type Output = ExecutionResources;
1643
1644 fn mul(self, rhs: usize) -> ExecutionResources {
1645 let mut new = self.clone();
1646 new.mul_assign(rhs);
1647 new
1648 }
1649}
1650
1651impl MulAssign<usize> for ExecutionResources {
1652 fn mul_assign(&mut self, rhs: usize) {
1653 self.n_steps *= rhs;
1654 self.n_memory_holes *= rhs;
1655 for (_builtin_name, counter) in self.builtin_instance_counter.iter_mut() {
1656 *counter *= rhs;
1657 }
1658 }
1659}
1660
1661#[cfg(test)]
1662mod tests {
1663 use super::*;
1664 use crate::air_private_input::{PrivateInput, PrivateInputSignature, SignatureInput};
1665 use crate::cairo_run::{cairo_run, CairoRunConfig};
1666 use crate::stdlib::collections::{HashMap, HashSet};
1667 use crate::vm::vm_memory::memory::MemoryCell;
1668
1669 use crate::felt_hex;
1670 use crate::{
1671 hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
1672 relocatable,
1673 serde::deserialize_program::{Identifier, ReferenceManager},
1674 utils::test_utils::*,
1675 vm::trace::trace_entry::TraceEntry,
1676 };
1677 use assert_matches::assert_matches;
1678
1679 #[cfg(target_arch = "wasm32")]
1680 use wasm_bindgen_test::*;
1681
1682 #[test]
1683 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1684 fn check_memory_usage_ok_case() {
1685 let program = program![BuiltinName::range_check, BuiltinName::output];
1686 let mut cairo_runner = cairo_runner!(program);
1687 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
1688
1689 assert_matches!(cairo_runner.check_memory_usage(), Ok(()));
1690 }
1691
1692 #[test]
1693 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1694 fn check_memory_usage_err_case() {
1695 let program = program!();
1696
1697 let mut cairo_runner = cairo_runner!(program);
1698 cairo_runner.vm.builtin_runners = vec![{
1699 let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
1700 builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
1701
1702 builtin_runner
1703 }];
1704 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4, 12]);
1705 cairo_runner.vm.segments.memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 1)];
1706 cairo_runner
1707 .vm
1708 .segments
1709 .memory
1710 .mark_as_accessed((0, 0).into());
1711 assert_matches!(
1712 cairo_runner.check_memory_usage(),
1713 Err(VirtualMachineError::Memory(
1714 MemoryError::InsufficientAllocatedCells(_)
1715 ))
1716 );
1717 }
1718
1719 #[test]
1720 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1721 fn initialize_builtins_with_disordered_builtins() {
1722 let program = program![BuiltinName::range_check, BuiltinName::output];
1723 let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
1724 assert!(cairo_runner.initialize_builtins(false).is_err());
1725 }
1726
1727 #[test]
1728 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1729 fn initialize_builtins_missing_builtins_no_allow_missing() {
1730 let program = program![BuiltinName::output, BuiltinName::ecdsa];
1731 let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
1732 assert_matches!(
1733 cairo_runner.initialize_builtins(false),
1734 Err(RunnerError::NoBuiltinForInstance(_))
1735 )
1736 }
1737
1738 #[test]
1739 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1740 fn initialize_builtins_missing_builtins_allow_missing() {
1741 let program = program![BuiltinName::output, BuiltinName::ecdsa];
1742 let mut cairo_runner = cairo_runner!(program);
1743 assert!(cairo_runner.initialize_builtins(true).is_ok())
1744 }
1745
1746 #[test]
1747 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1748 fn initialize_segments_with_base() {
1749 let program = program![BuiltinName::output];
1750 let mut cairo_runner = cairo_runner!(program);
1751 let program_base = Some(Relocatable {
1752 segment_index: 5,
1753 offset: 9,
1754 });
1755 add_segments!(&mut cairo_runner.vm, 6);
1756 cairo_runner.initialize_builtins(false).unwrap();
1757 cairo_runner.initialize_segments(program_base);
1758 assert_eq!(
1759 cairo_runner.program_base,
1760 Some(Relocatable {
1761 segment_index: 5,
1762 offset: 9,
1763 })
1764 );
1765 assert_eq!(
1766 cairo_runner.execution_base,
1767 Some(Relocatable {
1768 segment_index: 6,
1769 offset: 0,
1770 })
1771 );
1772 assert_eq!(
1773 cairo_runner.vm.builtin_runners[0].name(),
1774 BuiltinName::output
1775 );
1776 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 7);
1777
1778 assert_eq!(cairo_runner.vm.segments.num_segments(), 8);
1779 }
1780
1781 #[test]
1782 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1783 fn initialize_segments_no_base() {
1784 let program = program![BuiltinName::output];
1785 let mut cairo_runner = cairo_runner!(program);
1786 cairo_runner.initialize_builtins(false).unwrap();
1787 cairo_runner.initialize_segments(None);
1788 assert_eq!(
1789 cairo_runner.program_base,
1790 Some(Relocatable {
1791 segment_index: 0,
1792 offset: 0
1793 })
1794 );
1795 assert_eq!(
1796 cairo_runner.execution_base,
1797 Some(Relocatable {
1798 segment_index: 1,
1799 offset: 0
1800 })
1801 );
1802 assert_eq!(
1803 cairo_runner.vm.builtin_runners[0].name(),
1804 BuiltinName::output
1805 );
1806 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
1807
1808 assert_eq!(cairo_runner.vm.segments.num_segments(), 3);
1809 }
1810
1811 #[test]
1812 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1813 fn initialize_state_empty_data_and_stack() {
1814 let program = program![BuiltinName::output];
1815 let mut cairo_runner = cairo_runner!(program);
1816 cairo_runner.program_base = Some(relocatable!(1, 0));
1817 cairo_runner.execution_base = Some(relocatable!(2, 0));
1818 let stack = Vec::new();
1819 cairo_runner.initialize_builtins(false).unwrap();
1820 cairo_runner.initialize_state(1, stack).unwrap();
1821 assert_eq!(
1822 cairo_runner.initial_pc,
1823 Some(Relocatable {
1824 segment_index: 1,
1825 offset: 1
1826 })
1827 );
1828 }
1829
1830 #[test]
1831 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1832 fn initialize_state_some_data_empty_stack() {
1833 let program = program!(
1834 builtins = vec![BuiltinName::output],
1835 data = vec_data!((4), (6)),
1836 );
1837 let mut cairo_runner = cairo_runner!(program);
1838 for _ in 0..2 {
1839 cairo_runner.vm.segments.add();
1840 }
1841 cairo_runner.program_base = Some(Relocatable {
1842 segment_index: 1,
1843 offset: 0,
1844 });
1845 cairo_runner.execution_base = Some(relocatable!(2, 0));
1846 let stack = Vec::new();
1847 cairo_runner.initialize_state(1, stack).unwrap();
1848 check_memory!(cairo_runner.vm.segments.memory, ((1, 0), 4), ((1, 1), 6));
1849 }
1850
1851 #[test]
1852 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1853 fn initialize_state_empty_data_some_stack() {
1854 let program = program![BuiltinName::output];
1855 let mut cairo_runner = cairo_runner!(program);
1856 for _ in 0..3 {
1857 cairo_runner.vm.segments.add();
1858 }
1859 cairo_runner.program_base = Some(relocatable!(1, 0));
1860 cairo_runner.execution_base = Some(relocatable!(2, 0));
1861 let stack = vec![mayberelocatable!(4), mayberelocatable!(6)];
1862 cairo_runner.initialize_state(1, stack).unwrap();
1863 check_memory!(cairo_runner.vm.segments.memory, ((2, 0), 4), ((2, 1), 6));
1864 }
1865
1866 #[test]
1867 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1868 fn initialize_state_no_program_base() {
1869 let program = program![BuiltinName::output];
1870 let mut cairo_runner = cairo_runner!(program);
1871 for _ in 0..2 {
1872 cairo_runner.vm.segments.add();
1873 }
1874 cairo_runner.execution_base = Some(Relocatable {
1875 segment_index: 2,
1876 offset: 0,
1877 });
1878 let stack = vec![
1879 MaybeRelocatable::from(Felt252::from(4_i32)),
1880 MaybeRelocatable::from(Felt252::from(6_i32)),
1881 ];
1882 assert!(cairo_runner.initialize_state(1, stack).is_err());
1883 }
1884
1885 #[test]
1886 #[should_panic]
1887 fn initialize_state_no_execution_base() {
1888 let program = program![BuiltinName::output];
1889 let mut cairo_runner = cairo_runner!(program);
1890 for _ in 0..2 {
1891 cairo_runner.vm.segments.add();
1892 }
1893 cairo_runner.program_base = Some(relocatable!(1, 0));
1894 let stack = vec![
1895 MaybeRelocatable::from(Felt252::from(4_i32)),
1896 MaybeRelocatable::from(Felt252::from(6_i32)),
1897 ];
1898 cairo_runner.initialize_state(1, stack).unwrap();
1899 }
1900
1901 #[test]
1902 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1903 fn initialize_function_entrypoint_empty_stack() {
1904 let program = program![BuiltinName::output];
1905 let mut cairo_runner = cairo_runner!(program);
1906 for _ in 0..2 {
1907 cairo_runner.vm.segments.add();
1908 }
1909 cairo_runner.program_base = Some(relocatable!(0, 0));
1910 cairo_runner.execution_base = Some(relocatable!(1, 0));
1911 let stack = Vec::new();
1912 let return_fp = MaybeRelocatable::from(Felt252::from(9_i32));
1913 cairo_runner
1914 .initialize_function_entrypoint(0, stack, return_fp)
1915 .unwrap();
1916 assert_eq!(cairo_runner.initial_fp, cairo_runner.initial_ap);
1917 assert_eq!(cairo_runner.initial_fp, Some(relocatable!(1, 2)));
1918 check_memory!(
1919 cairo_runner.vm.segments.memory,
1920 ((1, 0), 9),
1921 ((1, 1), (2, 0))
1922 );
1923 }
1924
1925 #[test]
1926 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1927 fn initialize_function_entrypoint_some_stack() {
1928 let program = program![BuiltinName::output];
1929 let mut cairo_runner = cairo_runner!(program);
1930 for _ in 0..2 {
1931 cairo_runner.vm.segments.add();
1932 }
1933 cairo_runner.program_base = Some(relocatable!(0, 0));
1934 cairo_runner.execution_base = Some(relocatable!(1, 0));
1935 let stack = vec![MaybeRelocatable::from(Felt252::from(7_i32))];
1936 let return_fp = MaybeRelocatable::from(Felt252::from(9_i32));
1937 cairo_runner
1938 .initialize_function_entrypoint(1, stack, return_fp)
1939 .unwrap();
1940 assert_eq!(cairo_runner.initial_fp, cairo_runner.initial_ap);
1941 assert_eq!(cairo_runner.initial_fp, Some(relocatable!(1, 3)));
1942 check_memory!(
1943 cairo_runner.vm.segments.memory,
1944 ((1, 0), 7),
1945 ((1, 1), 9),
1946 ((1, 2), (2, 0))
1947 );
1948 }
1949
1950 #[test]
1951 #[should_panic]
1952 fn initialize_function_entrypoint_no_execution_base() {
1953 let program = program![BuiltinName::output];
1954 let mut cairo_runner = cairo_runner!(program);
1955 let stack = vec![MaybeRelocatable::from(Felt252::from(7_i32))];
1956 let return_fp = MaybeRelocatable::from(Felt252::from(9_i32));
1957 cairo_runner
1958 .initialize_function_entrypoint(1, stack, return_fp)
1959 .unwrap();
1960 }
1961
1962 #[test]
1963 #[should_panic]
1964 fn initialize_main_entrypoint_no_main() {
1965 let program = program![BuiltinName::output];
1966 let mut cairo_runner = cairo_runner!(program);
1967 cairo_runner.initialize_main_entrypoint().unwrap();
1968 }
1969
1970 #[test]
1971 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1972 fn initialize_main_entrypoint() {
1973 let program = program!(main = Some(1),);
1974 let mut cairo_runner = cairo_runner!(program);
1975 cairo_runner.program_base = Some(relocatable!(0, 0));
1976 cairo_runner.execution_base = Some(relocatable!(0, 0));
1977 let return_pc = cairo_runner.initialize_main_entrypoint().unwrap();
1978 assert_eq!(return_pc, Relocatable::from((1, 0)));
1979 }
1980
1981 #[test]
1982 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1983 fn initialize_state_program_segment_accessed_addrs() {
1984 let program = Program::from_bytes(
1988 include_bytes!("../../../../cairo_programs/fibonacci.json"),
1989 Some("main"),
1990 )
1991 .unwrap();
1992
1993 let mut cairo_runner = cairo_runner!(program);
1994
1995 cairo_runner.initialize(false).unwrap();
1996 assert_eq!(
1997 cairo_runner
1998 .vm
1999 .segments
2000 .memory
2001 .get_amount_of_accessed_addresses_for_segment(0),
2002 Some(24)
2003 );
2004 }
2005
2006 #[test]
2007 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2008 fn initialize_vm_no_builtins() {
2009 let program = program!(main = Some(1),);
2010 let mut cairo_runner = cairo_runner!(program);
2011 cairo_runner.program_base = Some(relocatable!(0, 0));
2012 cairo_runner.initial_pc = Some(relocatable!(0, 1));
2013 cairo_runner.initial_ap = Some(relocatable!(1, 2));
2014 cairo_runner.initial_fp = Some(relocatable!(1, 2));
2015 cairo_runner.initialize_vm().unwrap();
2016 assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 1));
2017 assert_eq!(cairo_runner.vm.run_context.ap, 2);
2018 assert_eq!(cairo_runner.vm.run_context.fp, 2);
2019 }
2020
2021 #[test]
2022 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2023 fn initialize_vm_with_range_check_valid() {
2024 let program = program!(builtins = vec![BuiltinName::range_check], main = Some(1),);
2025 let mut cairo_runner = cairo_runner!(program);
2026 cairo_runner.initial_pc = Some(relocatable!(0, 1));
2027 cairo_runner.initial_ap = Some(relocatable!(1, 2));
2028 cairo_runner.initial_fp = Some(relocatable!(1, 2));
2029 cairo_runner.initialize_builtins(false).unwrap();
2030 cairo_runner.initialize_segments(None);
2031 cairo_runner.vm.segments = segments![((2, 0), 23), ((2, 1), 233)];
2032 assert_eq!(
2033 cairo_runner.vm.builtin_runners[0].name(),
2034 BuiltinName::range_check
2035 );
2036 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2037 cairo_runner.initialize_vm().unwrap();
2038 assert!(cairo_runner
2039 .vm
2040 .segments
2041 .memory
2042 .validated_addresses
2043 .contains(&Relocatable::from((2, 0))));
2044 assert!(cairo_runner
2045 .vm
2046 .segments
2047 .memory
2048 .validated_addresses
2049 .contains(&Relocatable::from((2, 1))));
2050 assert_eq!(cairo_runner.vm.segments.memory.validated_addresses.len(), 2);
2051 }
2052
2053 #[test]
2054 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2055 fn initialize_vm_with_range_check_invalid() {
2056 let program = program!(builtins = vec![BuiltinName::range_check], main = Some(1),);
2057 let mut cairo_runner = cairo_runner!(program);
2058 cairo_runner.initial_pc = Some(relocatable!(0, 1));
2059 cairo_runner.initial_ap = Some(relocatable!(1, 2));
2060 cairo_runner.initial_fp = Some(relocatable!(1, 2));
2061 cairo_runner.initialize_builtins(false).unwrap();
2062 cairo_runner.initialize_segments(None);
2063 cairo_runner.vm.segments = segments![((2, 1), 23), ((2, 4), (-1))];
2064
2065 assert_eq!(
2066 cairo_runner.initialize_vm(),
2067 Err(RunnerError::MemoryValidationError(
2068 MemoryError::RangeCheckFoundNonInt(Box::new((2, 0).into()))
2069 ))
2070 );
2071 }
2072
2073 #[test]
2076 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2077 fn initialization_phase_no_builtins() {
2093 let program = program!(
2094 data = vec_data!(
2095 (5207990763031199744_u64),
2096 (2),
2097 (2345108766317314046_u64),
2098 (5189976364521848832_u64),
2099 (1),
2100 (1226245742482522112_u64),
2101 ((
2102 "3618502788666131213697322783095070105623107215331596699973092056135872020476",
2103 10
2104 )),
2105 (2345108766317314046_i64)
2106 ),
2107 main = Some(3),
2108 );
2109 let mut cairo_runner = cairo_runner!(program);
2110 cairo_runner.initialize_segments(None);
2111 cairo_runner.initialize_main_entrypoint().unwrap();
2112 cairo_runner.initialize_vm().unwrap();
2113
2114 assert_eq!(cairo_runner.program_base, Some(relocatable!(0, 0)));
2115 assert_eq!(cairo_runner.execution_base, Some(relocatable!(1, 0)));
2116 assert_eq!(cairo_runner.final_pc, Some(relocatable!(3, 0)));
2117
2118 assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 3));
2121 assert_eq!(cairo_runner.vm.run_context.ap, 2);
2122 assert_eq!(cairo_runner.vm.run_context.fp, 2);
2123 check_memory!(
2125 cairo_runner.vm.segments.memory,
2126 ((0, 0), 5207990763031199744_u64),
2127 ((0, 1), 2),
2128 ((0, 2), 2345108766317314046_u64),
2129 ((0, 3), 5189976364521848832_u64),
2130 ((0, 4), 1),
2131 ((0, 5), 1226245742482522112_u64),
2132 (
2133 (0, 6),
2134 (
2135 "3618502788666131213697322783095070105623107215331596699973092056135872020476",
2136 10
2137 )
2138 ),
2139 ((0, 7), 2345108766317314046_u64),
2140 ((1, 0), (2, 0)),
2141 ((1, 1), (3, 0))
2142 );
2143 }
2144
2145 #[test]
2146 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2147 fn initialization_phase_output_builtin() {
2162 let program = program!(
2163 builtins = vec![BuiltinName::output],
2164 data = vec_data!(
2165 (4612671182993129469_u64),
2166 (5198983563776393216_u64),
2167 (1),
2168 (2345108766317314046_u64),
2169 (5191102247248822272_u64),
2170 (5189976364521848832_u64),
2171 (1),
2172 (1226245742482522112_u64),
2173 ((
2174 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2175 10
2176 )),
2177 (2345108766317314046_u64)
2178 ),
2179 main = Some(4),
2180 );
2181 let mut cairo_runner = cairo_runner!(program);
2182
2183 cairo_runner.initialize_builtins(false).unwrap();
2184 cairo_runner.initialize_segments(None);
2185 cairo_runner.initialize_main_entrypoint().unwrap();
2186 cairo_runner.initialize_vm().unwrap();
2187
2188 assert_eq!(cairo_runner.program_base, Some(relocatable!(0, 0)));
2189 assert_eq!(cairo_runner.execution_base, Some(relocatable!(1, 0)));
2190 assert_eq!(cairo_runner.final_pc, Some(relocatable!(4, 0)));
2191
2192 assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 4));
2195 assert_eq!(cairo_runner.vm.run_context.ap, 3);
2196 assert_eq!(cairo_runner.vm.run_context.fp, 3);
2197 check_memory!(
2199 cairo_runner.vm.segments.memory,
2200 ((0, 0), 4612671182993129469_u64),
2201 ((0, 1), 5198983563776393216_u64),
2202 ((0, 2), 1),
2203 ((0, 3), 2345108766317314046_u64),
2204 ((0, 4), 5191102247248822272_u64),
2205 ((0, 5), 5189976364521848832_u64),
2206 ((0, 6), 1),
2207 ((0, 7), 1226245742482522112_u64),
2208 (
2209 (0, 8),
2210 (
2211 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2212 10
2213 )
2214 ),
2215 ((0, 9), 2345108766317314046_u64),
2216 ((1, 0), (2, 0)),
2217 ((1, 1), (3, 0)),
2218 ((1, 2), (4, 0))
2219 );
2220 }
2221
2222 #[test]
2223 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2224 fn initialization_phase_range_check_builtin() {
2245 let program = program!(
2246 builtins = vec![BuiltinName::range_check],
2247 data = vec_data!(
2248 (4612671182993129469_u64),
2249 (5189976364521848832_u64),
2250 (18446744073709551615_u128),
2251 (5199546496550207487_u64),
2252 (4612389712311386111_u64),
2253 (5198983563776393216_u64),
2254 (2),
2255 (2345108766317314046_u64),
2256 (5191102247248822272_u64),
2257 (5189976364521848832_u64),
2258 (7),
2259 (1226245742482522112_u64),
2260 ((
2261 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2262 10
2263 )),
2264 (2345108766317314046_u64)
2265 ),
2266 main = Some(8),
2267 );
2268
2269 let mut cairo_runner = cairo_runner!(program);
2270
2271 cairo_runner.initialize_builtins(false).unwrap();
2272 cairo_runner.initialize_segments(None);
2273 cairo_runner.initialize_main_entrypoint().unwrap();
2274 cairo_runner.initialize_vm().unwrap();
2275
2276 assert_eq!(cairo_runner.program_base, Some(relocatable!(0, 0)));
2277 assert_eq!(cairo_runner.execution_base, Some(relocatable!(1, 0)));
2278 assert_eq!(cairo_runner.final_pc, Some(relocatable!(4, 0)));
2279
2280 assert_eq!(cairo_runner.vm.run_context.pc, relocatable!(0, 8));
2283 assert_eq!(cairo_runner.vm.run_context.ap, 3);
2284 assert_eq!(cairo_runner.vm.run_context.fp, 3);
2285 check_memory!(
2287 cairo_runner.vm.segments.memory,
2288 ((0, 0), 4612671182993129469_u64),
2289 ((0, 1), 5189976364521848832_u64),
2290 ((0, 2), 18446744073709551615_u128),
2291 ((0, 3), 5199546496550207487_u64),
2292 ((0, 4), 4612389712311386111_u64),
2293 ((0, 5), 5198983563776393216_u64),
2294 ((0, 6), 2),
2295 ((0, 7), 2345108766317314046_u64),
2296 ((0, 8), 5191102247248822272_u64),
2297 ((0, 9), 5189976364521848832_u64),
2298 ((0, 10), 7),
2299 ((0, 11), 1226245742482522112_u64),
2300 (
2301 (0, 12),
2302 (
2303 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2304 10
2305 )
2306 ),
2307 ((0, 13), 2345108766317314046_u64),
2308 ((1, 0), (2, 0)),
2309 ((1, 1), (3, 0)),
2310 ((1, 2), (4, 0))
2311 );
2312 }
2313
2314 #[test]
2317 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2318 fn initialize_and_run_function_call() {
2334 let program = program!(
2336 data = vec_data!(
2337 (5207990763031199744_i64),
2338 (2),
2339 (2345108766317314046_i64),
2340 (5189976364521848832_i64),
2341 (1),
2342 (1226245742482522112_i64),
2343 ((
2344 "3618502788666131213697322783095070105623107215331596699973092056135872020476",
2345 10
2346 )),
2347 (2345108766317314046_i64)
2348 ),
2349 main = Some(3),
2350 );
2351 let mut hint_processor = BuiltinHintProcessor::new_empty();
2352 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2353 cairo_runner.initialize_segments(None);
2354 let end = cairo_runner.initialize_main_entrypoint().unwrap();
2355 assert_eq!(end, Relocatable::from((3, 0)));
2356 cairo_runner.initialize_vm().unwrap();
2357 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2359 assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((3, 0)));
2362
2363 assert_eq!(cairo_runner.vm.run_context.ap, 6);
2364
2365 assert_eq!(cairo_runner.vm.run_context.fp, 0);
2366
2367 let trace = cairo_runner.vm.trace.unwrap();
2369 assert_eq!(trace.len(), 5);
2370 trace_check(
2371 &trace,
2372 &[
2373 ((0, 3).into(), 2, 2),
2374 ((0, 5).into(), 3, 2),
2375 ((0, 0).into(), 5, 5),
2376 ((0, 2).into(), 6, 5),
2377 ((0, 7).into(), 6, 2),
2378 ],
2379 );
2380 }
2381
2382 #[test]
2383 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2384 fn initialize_and_run_range_check_builtin() {
2405 let program = program!(
2407 builtins = vec![BuiltinName::range_check],
2408 data = vec_data!(
2409 (4612671182993129469_i64),
2410 (5189976364521848832_i64),
2411 (18446744073709551615_i128),
2412 (5199546496550207487_i64),
2413 (4612389712311386111_i64),
2414 (5198983563776393216_i64),
2415 (2),
2416 (2345108766317314046_i64),
2417 (5191102247248822272_i64),
2418 (5189976364521848832_i64),
2419 (7),
2420 (1226245742482522112_i64),
2421 ((
2422 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
2423 10
2424 )),
2425 (2345108766317314046_i64)
2426 ),
2427 main = Some(8),
2428 );
2429 let mut hint_processor = BuiltinHintProcessor::new_empty();
2430 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2431 cairo_runner.initialize_builtins(false).unwrap();
2432 cairo_runner.initialize_segments(None);
2433 let end = cairo_runner.initialize_main_entrypoint().unwrap();
2434 cairo_runner.initialize_vm().unwrap();
2435 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2437 assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((4, 0)));
2440
2441 assert_eq!(cairo_runner.vm.run_context.ap, 10);
2442
2443 assert_eq!(cairo_runner.vm.run_context.fp, 0);
2444
2445 let trace = cairo_runner.vm.trace.unwrap();
2447 assert_eq!(trace.len(), 10);
2448 trace_check(
2449 &trace,
2450 &[
2451 ((0, 8).into(), 3, 3),
2452 ((0, 9).into(), 4, 3),
2453 ((0, 11).into(), 5, 3),
2454 ((0, 0).into(), 7, 7),
2455 ((0, 1).into(), 7, 7),
2456 ((0, 3).into(), 8, 7),
2457 ((0, 4).into(), 9, 7),
2458 ((0, 5).into(), 9, 7),
2459 ((0, 7).into(), 10, 7),
2460 ((0, 13).into(), 10, 3),
2461 ],
2462 );
2463 assert_eq!(
2465 cairo_runner.vm.builtin_runners[0].name(),
2466 BuiltinName::range_check
2467 );
2468 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2469
2470 check_memory!(
2471 cairo_runner.vm.segments.memory,
2472 ((2, 0), 7),
2473 ((2, 1), 18446744073709551608_i128)
2474 );
2475 assert!(cairo_runner
2476 .vm
2477 .segments
2478 .memory
2479 .get(&MaybeRelocatable::from((2, 2)))
2480 .is_none());
2481 }
2482
2483 #[test]
2484 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2485 fn initialize_and_run_output_builtin() {
2517 let program = program!(
2519 builtins = vec![BuiltinName::output],
2520 data = vec_data!(
2521 (4612671182993129469_i64),
2522 (5198983563776393216_i64),
2523 (1),
2524 (2345108766317314046_i64),
2525 (5191102247248822272_i64),
2526 (5189976364521848832_i64),
2527 (1),
2528 (1226245742482522112_i64),
2529 ((
2530 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2531 10
2532 )),
2533 (5189976364521848832_i64),
2534 (17),
2535 (1226245742482522112_i64),
2536 ((
2537 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
2538 10
2539 )),
2540 (2345108766317314046_i64)
2541 ),
2542 main = Some(4),
2543 );
2544 let mut hint_processor = BuiltinHintProcessor::new_empty();
2545 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2546 cairo_runner.initialize_builtins(false).unwrap();
2547 cairo_runner.initialize_segments(None);
2548 let end = cairo_runner.initialize_main_entrypoint().unwrap();
2549 cairo_runner.initialize_vm().unwrap();
2550 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2552 assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((4, 0)));
2556
2557 assert_eq!(cairo_runner.vm.run_context.ap, 12);
2558
2559 assert_eq!(cairo_runner.vm.run_context.fp, 0);
2560
2561 let trace = cairo_runner.vm.trace.unwrap();
2563 assert_eq!(trace.len(), 12);
2564 trace_check(
2565 &trace,
2566 &[
2567 ((0, 4).into(), 3, 3),
2568 ((0, 5).into(), 4, 3),
2569 ((0, 7).into(), 5, 3),
2570 ((0, 0).into(), 7, 7),
2571 ((0, 1).into(), 7, 7),
2572 ((0, 3).into(), 8, 7),
2573 ((0, 9).into(), 8, 3),
2574 ((0, 11).into(), 9, 3),
2575 ((0, 0).into(), 11, 11),
2576 ((0, 1).into(), 11, 11),
2577 ((0, 3).into(), 12, 11),
2578 ((0, 13).into(), 12, 3),
2579 ],
2580 );
2581 assert_eq!(
2583 cairo_runner.vm.builtin_runners[0].name(),
2584 BuiltinName::output
2585 );
2586 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2587 check_memory!(cairo_runner.vm.segments.memory, ((2, 0), 1), ((2, 1), 17));
2588 assert!(cairo_runner
2589 .vm
2590 .segments
2591 .memory
2592 .get(&MaybeRelocatable::from((2, 2)))
2593 .is_none());
2594 }
2595
2596 #[test]
2597 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2598 fn initialize_and_run_output_range_check_builtin() {
2646 let program = program!(
2648 builtins = vec![BuiltinName::output, BuiltinName::range_check],
2649 data = vec_data!(
2650 (4612671182993129469_i64),
2651 (5198983563776393216_i64),
2652 (1),
2653 (2345108766317314046_i64),
2654 (4612671182993129469_i64),
2655 (5189976364521848832_i64),
2656 (18446744073709551615_i128),
2657 (5199546496550207487_i64),
2658 (4612389712311386111_i64),
2659 (5198983563776393216_i64),
2660 (2),
2661 (5191102247248822272_i64),
2662 (2345108766317314046_i64),
2663 (5191102247248822272_i64),
2664 (5189976364521848832_i64),
2665 (7),
2666 (1226245742482522112_i64),
2667 ((
2668 "3618502788666131213697322783095070105623107215331596699973092056135872020469",
2669 10
2670 )),
2671 (5191102242953854976_i64),
2672 (5193354051357474816_i64),
2673 (1226245742482522112_i64),
2674 ((
2675 "3618502788666131213697322783095070105623107215331596699973092056135872020461",
2676 10
2677 )),
2678 (5193354029882638336_i64),
2679 (2345108766317314046_i64)
2680 ),
2681 main = Some(13),
2682 );
2683 let mut hint_processor = BuiltinHintProcessor::new_empty();
2684 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2685 cairo_runner.initialize_builtins(false).unwrap();
2686 cairo_runner.initialize_segments(None);
2687 let end = cairo_runner.initialize_main_entrypoint().unwrap();
2688 cairo_runner.initialize_vm().unwrap();
2689 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2691 assert_eq!(cairo_runner.vm.run_context.pc, Relocatable::from((5, 0)));
2694
2695 assert_eq!(cairo_runner.vm.run_context.ap, 18);
2696
2697 assert_eq!(cairo_runner.vm.run_context.fp, 0);
2698
2699 let trace = cairo_runner.vm.trace.unwrap();
2701 assert_eq!(trace.len(), 18);
2702 trace_check(
2703 &trace,
2704 &[
2705 ((0, 13).into(), 4, 4),
2706 ((0, 14).into(), 5, 4),
2707 ((0, 16).into(), 6, 4),
2708 ((0, 4).into(), 8, 8),
2709 ((0, 5).into(), 8, 8),
2710 ((0, 7).into(), 9, 8),
2711 ((0, 8).into(), 10, 8),
2712 ((0, 9).into(), 10, 8),
2713 ((0, 11).into(), 11, 8),
2714 ((0, 12).into(), 12, 8),
2715 ((0, 18).into(), 12, 4),
2716 ((0, 19).into(), 13, 4),
2717 ((0, 20).into(), 14, 4),
2718 ((0, 0).into(), 16, 16),
2719 ((0, 1).into(), 16, 16),
2720 ((0, 3).into(), 17, 16),
2721 ((0, 22).into(), 17, 4),
2722 ((0, 23).into(), 18, 4),
2723 ],
2724 );
2725 assert_eq!(
2727 cairo_runner.vm.builtin_runners[1].name(),
2728 BuiltinName::range_check
2729 );
2730 assert_eq!(cairo_runner.vm.builtin_runners[1].base(), 3);
2731
2732 check_memory!(
2733 cairo_runner.vm.segments.memory,
2734 ((3, 0), 7),
2735 ((3, 1), 18446744073709551608_i128)
2736 );
2737 assert!(cairo_runner
2738 .vm
2739 .segments
2740 .memory
2741 .get(&MaybeRelocatable::from((2, 2)))
2742 .is_none());
2743
2744 assert_eq!(
2746 cairo_runner.vm.builtin_runners[0].name(),
2747 BuiltinName::output
2748 );
2749 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
2750
2751 check_memory!(cairo_runner.vm.segments.memory, ((2, 0), 7));
2752 assert!(cairo_runner
2753 .vm
2754 .segments
2755 .memory
2756 .get(&(MaybeRelocatable::from((2, 1))))
2757 .is_none());
2758 }
2759
2760 #[test]
2761 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2762 fn relocate_memory_with_gap() {
2787 let program = program!();
2788 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2789 for _ in 0..4 {
2790 cairo_runner.vm.segments.add();
2791 }
2792 cairo_runner
2794 .vm
2795 .segments
2796 .memory
2797 .insert(
2798 Relocatable::from((0, 0)),
2799 &MaybeRelocatable::from(Felt252::from(4613515612218425347_i64)),
2800 )
2801 .unwrap();
2802 cairo_runner
2803 .vm
2804 .segments
2805 .memory
2806 .insert(
2807 Relocatable::from((0, 1)),
2808 &MaybeRelocatable::from(Felt252::from(5)),
2809 )
2810 .unwrap();
2811 cairo_runner
2812 .vm
2813 .segments
2814 .memory
2815 .insert(
2816 Relocatable::from((0, 2)),
2817 &MaybeRelocatable::from(Felt252::from(2345108766317314046_i64)),
2818 )
2819 .unwrap();
2820 cairo_runner
2821 .vm
2822 .segments
2823 .memory
2824 .insert(Relocatable::from((1, 0)), &MaybeRelocatable::from((2, 0)))
2825 .unwrap();
2826 cairo_runner
2827 .vm
2828 .segments
2829 .memory
2830 .insert(Relocatable::from((1, 1)), &MaybeRelocatable::from((3, 0)))
2831 .unwrap();
2832 cairo_runner
2833 .vm
2834 .segments
2835 .memory
2836 .insert(
2837 Relocatable::from((1, 5)),
2838 &MaybeRelocatable::from(Felt252::from(5)),
2839 )
2840 .unwrap();
2841 cairo_runner.vm.segments.compute_effective_sizes();
2842 let rel_table = cairo_runner
2843 .vm
2844 .segments
2845 .relocate_segments()
2846 .expect("Couldn't relocate after compute effective sizes");
2847 assert_eq!(cairo_runner.relocate_memory(&rel_table), Ok(()));
2848 assert_eq!(cairo_runner.relocated_memory[0], None);
2849 assert_eq!(
2850 cairo_runner.relocated_memory[1],
2851 Some(Felt252::from(4613515612218425347_i64))
2852 );
2853 assert_eq!(cairo_runner.relocated_memory[2], Some(Felt252::from(5)));
2854 assert_eq!(
2855 cairo_runner.relocated_memory[3],
2856 Some(Felt252::from(2345108766317314046_i64))
2857 );
2858 assert_eq!(cairo_runner.relocated_memory[4], Some(Felt252::from(10)));
2859 assert_eq!(cairo_runner.relocated_memory[5], Some(Felt252::from(10)));
2860 assert_eq!(cairo_runner.relocated_memory[6], None);
2861 assert_eq!(cairo_runner.relocated_memory[7], None);
2862 assert_eq!(cairo_runner.relocated_memory[8], None);
2863 assert_eq!(cairo_runner.relocated_memory[9], Some(Felt252::from(5)));
2864 }
2865
2866 #[test]
2867 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
2868 fn initialize_run_and_relocate_output_builtin() {
2911 let program = program!(
2912 builtins = vec![BuiltinName::output],
2913 data = vec_data!(
2914 (4612671182993129469_i64),
2915 (5198983563776393216_i64),
2916 (1),
2917 (2345108766317314046_i64),
2918 (5191102247248822272_i64),
2919 (5189976364521848832_i64),
2920 (1),
2921 (1226245742482522112_i64),
2922 ((
2923 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
2924 10
2925 )),
2926 (5189976364521848832_i64),
2927 (17),
2928 (1226245742482522112_i64),
2929 ((
2930 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
2931 10
2932 )),
2933 (2345108766317314046_i64)
2934 ),
2935 main = Some(4),
2936 );
2937 let mut hint_processor = BuiltinHintProcessor::new_empty();
2938 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
2939 cairo_runner.initialize_builtins(false).unwrap();
2940 cairo_runner.initialize_segments(None);
2941 let end = cairo_runner.initialize_main_entrypoint().unwrap();
2942 cairo_runner.initialize_vm().unwrap();
2943 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
2944 cairo_runner.vm.segments.compute_effective_sizes();
2945 let rel_table = cairo_runner
2946 .vm
2947 .segments
2948 .relocate_segments()
2949 .expect("Couldn't relocate after compute effective sizes");
2950 assert_eq!(cairo_runner.relocate_memory(&rel_table), Ok(()));
2951 assert_eq!(cairo_runner.relocated_memory[0], None);
2952 assert_eq!(
2953 cairo_runner.relocated_memory[1],
2954 Some(Felt252::from(4612671182993129469_u64))
2955 );
2956 assert_eq!(
2957 cairo_runner.relocated_memory[2],
2958 Some(Felt252::from(5198983563776393216_u64))
2959 );
2960 assert_eq!(cairo_runner.relocated_memory[3], Some(Felt252::ONE));
2961 assert_eq!(
2962 cairo_runner.relocated_memory[4],
2963 Some(Felt252::from(2345108766317314046_u64))
2964 );
2965 assert_eq!(
2966 cairo_runner.relocated_memory[5],
2967 Some(Felt252::from(5191102247248822272_u64))
2968 );
2969 assert_eq!(
2970 cairo_runner.relocated_memory[6],
2971 Some(Felt252::from(5189976364521848832_u64))
2972 );
2973 assert_eq!(cairo_runner.relocated_memory[7], Some(Felt252::ONE));
2974 assert_eq!(
2975 cairo_runner.relocated_memory[8],
2976 Some(Felt252::from(1226245742482522112_u64))
2977 );
2978 assert_eq!(
2979 cairo_runner.relocated_memory[9],
2980 Some(felt_hex!(
2981 "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffa"
2982 ))
2983 );
2984 assert_eq!(
2985 cairo_runner.relocated_memory[10],
2986 Some(Felt252::from(5189976364521848832_u64))
2987 );
2988 assert_eq!(cairo_runner.relocated_memory[11], Some(Felt252::from(17)));
2989 assert_eq!(
2990 cairo_runner.relocated_memory[12],
2991 Some(Felt252::from(1226245742482522112_u64))
2992 );
2993 assert_eq!(
2994 cairo_runner.relocated_memory[13],
2995 Some(felt_hex!(
2996 "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff6"
2997 ))
2998 );
2999 assert_eq!(
3000 cairo_runner.relocated_memory[14],
3001 Some(Felt252::from(2345108766317314046_u64))
3002 );
3003 assert_eq!(
3004 cairo_runner.relocated_memory[15],
3005 Some(Felt252::from(27_u64))
3006 );
3007 assert_eq!(cairo_runner.relocated_memory[16], Some(Felt252::from(29)));
3008 assert_eq!(cairo_runner.relocated_memory[17], Some(Felt252::from(29)));
3009 assert_eq!(cairo_runner.relocated_memory[18], Some(Felt252::from(27)));
3010 assert_eq!(cairo_runner.relocated_memory[19], Some(Felt252::ONE));
3011 assert_eq!(cairo_runner.relocated_memory[20], Some(Felt252::from(18)));
3012 assert_eq!(cairo_runner.relocated_memory[21], Some(Felt252::from(10)));
3013 assert_eq!(cairo_runner.relocated_memory[22], Some(Felt252::from(28)));
3014 assert_eq!(cairo_runner.relocated_memory[23], Some(Felt252::from(17)));
3015 assert_eq!(cairo_runner.relocated_memory[24], Some(Felt252::from(18)));
3016 assert_eq!(cairo_runner.relocated_memory[25], Some(Felt252::from(14)));
3017 assert_eq!(cairo_runner.relocated_memory[26], Some(Felt252::from(29)));
3018 assert_eq!(cairo_runner.relocated_memory[27], Some(Felt252::ONE));
3019 assert_eq!(cairo_runner.relocated_memory[28], Some(Felt252::from(17)));
3020 }
3021
3022 #[test]
3023 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3024 fn relocate_trace_output_builtin() {
3047 let program = program!(
3048 builtins = vec![BuiltinName::output],
3049 data = vec_data!(
3050 (4612671182993129469_i64),
3051 (5198983563776393216_i64),
3052 (1),
3053 (2345108766317314046_i64),
3054 (5191102247248822272_i64),
3055 (5189976364521848832_i64),
3056 (1),
3057 (1226245742482522112_i64),
3058 ((
3059 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
3060 10
3061 )),
3062 (5189976364521848832_i64),
3063 (17),
3064 (1226245742482522112_i64),
3065 ((
3066 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3067 10
3068 )),
3069 (2345108766317314046_i64)
3070 ),
3071 main = Some(4),
3072 );
3073 let mut hint_processor = BuiltinHintProcessor::new_empty();
3074 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3075 cairo_runner.initialize_builtins(false).unwrap();
3076 cairo_runner.initialize_segments(None);
3077 let end = cairo_runner.initialize_main_entrypoint().unwrap();
3078 cairo_runner.initialize_vm().unwrap();
3079 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3080 cairo_runner.vm.segments.compute_effective_sizes();
3081 let rel_table = cairo_runner
3082 .vm
3083 .segments
3084 .relocate_segments()
3085 .expect("Couldn't relocate after compute effective sizes");
3086 cairo_runner.relocate_trace(&rel_table).unwrap();
3087 let relocated_trace = cairo_runner.relocated_trace.unwrap();
3088 assert_eq!(relocated_trace.len(), 12);
3089 assert_eq!(
3090 relocated_trace[0],
3091 RelocatedTraceEntry {
3092 pc: 5,
3093 ap: 18,
3094 fp: 18
3095 }
3096 );
3097 assert_eq!(
3098 relocated_trace[1],
3099 RelocatedTraceEntry {
3100 pc: 6,
3101 ap: 19,
3102 fp: 18
3103 }
3104 );
3105 assert_eq!(
3106 relocated_trace[2],
3107 RelocatedTraceEntry {
3108 pc: 8,
3109 ap: 20,
3110 fp: 18
3111 }
3112 );
3113 assert_eq!(
3114 relocated_trace[3],
3115 RelocatedTraceEntry {
3116 pc: 1,
3117 ap: 22,
3118 fp: 22
3119 }
3120 );
3121 assert_eq!(
3122 relocated_trace[4],
3123 RelocatedTraceEntry {
3124 pc: 2,
3125 ap: 22,
3126 fp: 22
3127 }
3128 );
3129 assert_eq!(
3130 relocated_trace[5],
3131 RelocatedTraceEntry {
3132 pc: 4,
3133 ap: 23,
3134 fp: 22
3135 }
3136 );
3137 assert_eq!(
3138 relocated_trace[6],
3139 RelocatedTraceEntry {
3140 pc: 10,
3141 ap: 23,
3142 fp: 18
3143 }
3144 );
3145 assert_eq!(
3146 relocated_trace[7],
3147 RelocatedTraceEntry {
3148 pc: 12,
3149 ap: 24,
3150 fp: 18
3151 }
3152 );
3153 assert_eq!(
3154 relocated_trace[8],
3155 RelocatedTraceEntry {
3156 pc: 1,
3157 ap: 26,
3158 fp: 26
3159 }
3160 );
3161 assert_eq!(
3162 relocated_trace[9],
3163 RelocatedTraceEntry {
3164 pc: 2,
3165 ap: 26,
3166 fp: 26
3167 }
3168 );
3169 assert_eq!(
3170 relocated_trace[10],
3171 RelocatedTraceEntry {
3172 pc: 4,
3173 ap: 27,
3174 fp: 26
3175 }
3176 );
3177 assert_eq!(
3178 relocated_trace[11],
3179 RelocatedTraceEntry {
3180 pc: 14,
3181 ap: 27,
3182 fp: 18
3183 }
3184 );
3185 }
3186
3187 #[test]
3188 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3189 fn write_output_from_preset_memory() {
3190 let program = program![BuiltinName::output];
3191 let mut cairo_runner = cairo_runner!(program);
3192 cairo_runner.initialize_builtins(false).unwrap();
3193 cairo_runner.initialize_segments(None);
3194 assert_eq!(
3195 cairo_runner.vm.builtin_runners[0].name(),
3196 BuiltinName::output
3197 );
3198 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
3199
3200 cairo_runner.vm.segments = segments![((2, 0), 1), ((2, 1), 2)];
3201 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 0, 2]);
3202
3203 let mut output_buffer = String::new();
3204 cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3205 assert_eq!(&output_buffer, "1\n2\n");
3206 }
3207
3208 #[test]
3209 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3210 fn get_output_from_program() {
3221 let program = program!(
3223 builtins = vec![BuiltinName::output],
3224 data = vec_data!(
3225 (4612671182993129469_i64),
3226 (5198983563776393216_i64),
3227 (1),
3228 (2345108766317314046_i64),
3229 (5191102247248822272_i64),
3230 (5189976364521848832_i64),
3231 (1),
3232 (1226245742482522112_i64),
3233 ((
3234 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
3235 10
3236 )),
3237 (5189976364521848832_i64),
3238 (17),
3239 (1226245742482522112_i64),
3240 ((
3241 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3242 10
3243 )),
3244 (2345108766317314046_i64)
3245 ),
3246 main = Some(4),
3247 );
3248 let mut cairo_runner = cairo_runner!(program);
3249 cairo_runner.initialize_builtins(false).unwrap();
3250 cairo_runner.initialize_segments(None);
3251 let end = cairo_runner.initialize_main_entrypoint().unwrap();
3252 cairo_runner.initialize_vm().unwrap();
3253 let mut hint_processor = BuiltinHintProcessor::new_empty();
3255 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3256
3257 let mut output_buffer = String::new();
3258 cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3259 assert_eq!(&output_buffer, "1\n17\n");
3260 }
3261
3262 #[test]
3263 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3264 fn write_output_from_program_gap_relocatable_output() {
3274 let program = program!(
3276 builtins = vec![BuiltinName::output],
3277 data = vec_data!(
3278 (4612671187288162301),
3279 (5198983563776458752),
3280 (2),
3281 (2345108766317314046)
3282 ),
3283 main = Some(0),
3284 );
3285 let mut cairo_runner = cairo_runner!(program);
3286 cairo_runner.initialize_builtins(false).unwrap();
3287 cairo_runner.initialize_segments(None);
3288 let end = cairo_runner.initialize_main_entrypoint().unwrap();
3289 cairo_runner.initialize_vm().unwrap();
3290 let mut hint_processor = BuiltinHintProcessor::new_empty();
3292 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3293
3294 let mut output_buffer = String::new();
3295 cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3296 assert_eq!(&output_buffer, "<missing>\n2:0\n");
3297 }
3298
3299 #[test]
3300 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3301 fn write_output_from_preset_memory_neg_output() {
3302 let program = program![BuiltinName::output];
3303 let mut cairo_runner = cairo_runner!(program);
3304 cairo_runner.initialize_builtins(false).unwrap();
3305 cairo_runner.initialize_segments(None);
3306 assert_eq!(
3307 cairo_runner.vm.builtin_runners[0].name(),
3308 BuiltinName::output
3309 );
3310 assert_eq!(cairo_runner.vm.builtin_runners[0].base(), 2);
3311 cairo_runner.vm.segments = segments![(
3312 (2, 0),
3313 (
3314 "800000000000011000000000000000000000000000000000000000000000000",
3315 16
3316 )
3317 )];
3318 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 0, 1]);
3319
3320 let mut output_buffer = String::new();
3321 cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3322 assert_eq!(&output_buffer, "-1\n");
3323 }
3324
3325 #[test]
3327 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3328 fn get_output_unordered_builtins() {
3329 let program = program!(
3331 builtins = vec![BuiltinName::output, BuiltinName::bitwise],
3332 data = vec_data!(
3333 (4612671182993129469_i64),
3334 (5198983563776393216_i64),
3335 (1),
3336 (2345108766317314046_i64),
3337 (5191102247248822272_i64),
3338 (5189976364521848832_i64),
3339 (1),
3340 (1226245742482522112_i64),
3341 ((
3342 "3618502788666131213697322783095070105623107215331596699973092056135872020474",
3343 10
3344 )),
3345 (5189976364521848832_i64),
3346 (17),
3347 (1226245742482522112_i64),
3348 ((
3349 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3350 10
3351 )),
3352 (2345108766317314046_i64)
3353 ),
3354 main = Some(4),
3355 );
3356
3357 let mut cairo_runner = cairo_runner!(program);
3358
3359 cairo_runner
3360 .initialize_builtins(false)
3361 .expect("Couldn't initialize builtins.");
3362
3363 cairo_runner.vm.builtin_runners.swap(0, 1);
3365 cairo_runner.program.builtins.swap(0, 1);
3366
3367 cairo_runner.initialize_segments(None);
3368
3369 let end = cairo_runner
3370 .initialize_main_entrypoint()
3371 .expect("Couldn't initialize the main entrypoint.");
3372 cairo_runner
3373 .initialize_vm()
3374 .expect("Couldn't initialize the cairo_runner.VM.");
3375
3376 let mut hint_processor = BuiltinHintProcessor::new_empty();
3377 assert_matches!(cairo_runner.run_until_pc(end, &mut hint_processor), Ok(()));
3378
3379 let mut output_buffer = String::new();
3380 cairo_runner.vm.write_output(&mut output_buffer).unwrap();
3381 assert_eq!(&output_buffer, "1\n17\n");
3382 }
3383
3384 #[test]
3385 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3386 fn insert_all_builtins_in_order() {
3387 let program = program![
3388 BuiltinName::output,
3389 BuiltinName::pedersen,
3390 BuiltinName::range_check,
3391 BuiltinName::bitwise,
3392 BuiltinName::ec_op
3393 ];
3394 let mut cairo_runner = cairo_runner!(program);
3395 cairo_runner.initialize_builtins(false).unwrap();
3396 assert_eq!(
3397 cairo_runner.vm.builtin_runners[0].name(),
3398 BuiltinName::output
3399 );
3400 assert_eq!(
3401 cairo_runner.vm.builtin_runners[1].name(),
3402 BuiltinName::pedersen
3403 );
3404 assert_eq!(
3405 cairo_runner.vm.builtin_runners[2].name(),
3406 BuiltinName::range_check
3407 );
3408 assert_eq!(
3409 cairo_runner.vm.builtin_runners[3].name(),
3410 BuiltinName::bitwise
3411 );
3412 assert_eq!(
3413 cairo_runner.vm.builtin_runners[4].name(),
3414 BuiltinName::ec_op
3415 );
3416 }
3417
3418 #[test]
3419 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3420 fn run_for_steps() {
3440 let program = program!(
3441 builtins = vec![BuiltinName::range_check],
3442 data = vec_data!(
3443 (4612671182993129469_i64),
3444 (5189976364521848832_i64),
3445 (18446744073709551615_i128),
3446 (5199546496550207487_i64),
3447 (4612389712311386111_i64),
3448 (5198983563776393216_i64),
3449 (2),
3450 (2345108766317314046_i64),
3451 (5191102247248822272_i64),
3452 (5189976364521848832_i64),
3453 (7),
3454 (1226245742482522112_i64),
3455 ((
3456 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3457 10
3458 )),
3459 (2345108766317314046_i64)
3460 ),
3461 main = Some(8),
3462 );
3463
3464 let mut hint_processor = BuiltinHintProcessor::new_empty();
3465 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3466 cairo_runner.initialize_builtins(false).unwrap();
3467 cairo_runner.initialize_segments(None);
3468
3469 cairo_runner.initialize_main_entrypoint().unwrap();
3470 cairo_runner.initialize_vm().unwrap();
3471
3472 assert_matches!(cairo_runner.run_for_steps(8, &mut hint_processor), Ok(()));
3474 assert_matches!(
3475 cairo_runner.run_for_steps(8, &mut hint_processor),
3476 Err(VirtualMachineError::EndOfProgram(x)) if x == 8 - 2
3477 );
3478 }
3479
3480 #[test]
3481 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3482 fn run_empty_all_cairo() {
3483 let program = program!();
3484 let mut cairo_runner = cairo_runner!(&program, LayoutName::all_cairo, false, true);
3485 assert_matches!(
3486 cairo_runner.initialize(false),
3487 Err(RunnerError::MissingMain)
3488 );
3489 }
3490
3491 #[test]
3492 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3493 fn run_empty_recursive_with_poseidon() {
3494 let program = program!();
3495 let mut cairo_runner =
3496 cairo_runner!(&program, LayoutName::recursive_with_poseidon, false, true);
3497 assert_matches!(
3498 cairo_runner.initialize(false),
3499 Err(RunnerError::MissingMain)
3500 );
3501 }
3502
3503 #[test]
3504 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3505 fn run_empty_all_cairo_stwo() {
3506 let program = program!();
3507 let mut cairo_runner = cairo_runner!(&program, LayoutName::all_cairo_stwo, false, true);
3508 assert_matches!(
3509 cairo_runner.initialize(false),
3510 Err(RunnerError::MissingMain)
3511 );
3512 }
3513
3514 #[test]
3515 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3516 fn run_until_steps() {
3536 let program = program!(
3537 builtins = vec![BuiltinName::range_check],
3538 data = vec_data!(
3539 (4612671182993129469_i64),
3540 (5189976364521848832_i64),
3541 (18446744073709551615_i128),
3542 (5199546496550207487_i64),
3543 (4612389712311386111_i64),
3544 (5198983563776393216_i64),
3545 (2),
3546 (2345108766317314046_i64),
3547 (5191102247248822272_i64),
3548 (5189976364521848832_i64),
3549 (7),
3550 (1226245742482522112_i64),
3551 ((
3552 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3553 10
3554 )),
3555 (2345108766317314046_i64)
3556 ),
3557 main = Some(8),
3558 );
3559
3560 let mut hint_processor = BuiltinHintProcessor::new_empty();
3561 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3562 cairo_runner.initialize_builtins(false).unwrap();
3563 cairo_runner.initialize_segments(None);
3564
3565 cairo_runner.initialize_main_entrypoint().unwrap();
3566 cairo_runner.initialize_vm().unwrap();
3567
3568 assert_matches!(cairo_runner.run_until_steps(8, &mut hint_processor), Ok(()));
3570 assert_matches!(
3571 cairo_runner.run_until_steps(10, &mut hint_processor),
3572 Ok(())
3573 );
3574 assert_matches!(
3575 cairo_runner.run_until_steps(11, &mut hint_processor),
3576 Err(VirtualMachineError::EndOfProgram(1))
3577 );
3578 }
3579
3580 #[test]
3581 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3582 fn run_until_next_power_of_2() {
3604 let program = program!(
3605 builtins = vec![BuiltinName::range_check],
3606 data = vec_data!(
3607 (4612671182993129469_i64),
3608 (5189976364521848832_i64),
3609 (18446744073709551615_i128),
3610 (5199546496550207487_i64),
3611 (4612389712311386111_i64),
3612 (5198983563776393216_i64),
3613 (2),
3614 (2345108766317314046_i64),
3615 (5191102247248822272_i64),
3616 (5189976364521848832_i64),
3617 (7),
3618 (1226245742482522112_i64),
3619 ((
3620 "3618502788666131213697322783095070105623107215331596699973092056135872020470",
3621 10
3622 )),
3623 (2345108766317314046_i64)
3624 ),
3625 main = Some(8),
3626 );
3627
3628 let mut hint_processor = BuiltinHintProcessor::new_empty();
3629 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
3630 cairo_runner.initialize_builtins(false).unwrap();
3631 cairo_runner.initialize_segments(None);
3632
3633 cairo_runner.initialize_main_entrypoint().unwrap();
3634 cairo_runner.initialize_vm().unwrap();
3635
3636 assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3638 assert_matches!(
3639 cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3640 Ok(())
3641 );
3642 assert_eq!(cairo_runner.vm.current_step, 1);
3643
3644 assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3645 assert_matches!(
3646 cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3647 Ok(())
3648 );
3649 assert_eq!(cairo_runner.vm.current_step, 2);
3650
3651 assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3652 assert_matches!(
3653 cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3654 Ok(())
3655 );
3656 assert_eq!(cairo_runner.vm.current_step, 4);
3657
3658 assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3659 assert_matches!(
3660 cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3661 Ok(())
3662 );
3663 assert_eq!(cairo_runner.vm.current_step, 8);
3664
3665 assert_matches!(cairo_runner.run_for_steps(1, &mut hint_processor), Ok(()));
3666 assert_matches!(
3667 cairo_runner.run_until_next_power_of_2(&mut hint_processor),
3668 Err(VirtualMachineError::EndOfProgram(6))
3669 );
3670 assert_eq!(cairo_runner.vm.current_step, 10);
3671 }
3672
3673 #[test]
3674 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3675 fn get_constants() {
3676 let program_constants = HashMap::from([
3677 ("MAX".to_string(), Felt252::from(300)),
3678 ("MIN".to_string(), Felt252::from(20)),
3679 ]);
3680 let program = program!(constants = program_constants.clone(),);
3681 let cairo_runner = cairo_runner!(program);
3682 assert_eq!(cairo_runner.get_constants(), &program_constants);
3683 }
3684
3685 #[test]
3686 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3687 fn get_memory_holes_missing_segment_used_sizes() {
3688 let program = program!();
3689
3690 let mut cairo_runner = cairo_runner!(program);
3691 cairo_runner.vm.segments.memory = memory![((0, 0), 9)];
3693 cairo_runner
3694 .vm
3695 .segments
3696 .memory
3697 .mark_as_accessed((0, 0).into());
3698
3699 cairo_runner.vm.builtin_runners = Vec::new();
3700 assert_eq!(
3701 cairo_runner.get_memory_holes(),
3702 Err(MemoryError::MissingSegmentUsedSizes),
3703 );
3704 }
3705
3706 #[test]
3707 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3708 fn get_memory_holes_empty() {
3709 let program = program!();
3710
3711 let mut cairo_runner = cairo_runner!(program);
3712
3713 cairo_runner.vm.builtin_runners = Vec::new();
3714 cairo_runner.vm.segments.segment_used_sizes = Some(Vec::new());
3715 assert_eq!(cairo_runner.get_memory_holes(), Ok(0));
3716 }
3717
3718 #[test]
3719 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3720 fn get_memory_holes_empty_builtins() {
3721 let program = program!();
3722
3723 let mut cairo_runner = cairo_runner!(program);
3724 cairo_runner.vm.segments.memory = memory![((0, 0), 0), ((0, 2), 0)];
3725 cairo_runner
3726 .vm
3727 .segments
3728 .memory
3729 .mark_as_accessed((0, 0).into());
3730 cairo_runner
3731 .vm
3732 .segments
3733 .memory
3734 .mark_as_accessed((0, 2).into());
3735 cairo_runner.vm.builtin_runners = Vec::new();
3736 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3737 assert_eq!(cairo_runner.get_memory_holes(), Ok(2));
3738 }
3739
3740 #[test]
3741 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3742 fn get_memory_holes_empty_accesses() {
3743 let program = program!();
3744
3745 let mut cairo_runner = cairo_runner!(program);
3746
3747 cairo_runner.vm.builtin_runners = vec![{
3748 let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
3749 builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
3750
3751 builtin_runner
3752 }];
3753 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3754 assert_eq!(cairo_runner.get_memory_holes(), Ok(0));
3755 }
3756
3757 #[test]
3758 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3759 fn get_memory_holes() {
3760 let program = program!();
3761
3762 let mut cairo_runner = cairo_runner!(program);
3763 cairo_runner.vm.segments.memory = memory![((1, 0), 0), ((1, 2), 2)];
3764 cairo_runner
3765 .vm
3766 .segments
3767 .memory
3768 .mark_as_accessed((1, 0).into());
3769 cairo_runner
3770 .vm
3771 .segments
3772 .memory
3773 .mark_as_accessed((1, 2).into());
3774 cairo_runner.vm.builtin_runners = vec![{
3775 let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
3776 builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
3777
3778 builtin_runner
3779 }];
3780 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4, 4]);
3781 assert_eq!(cairo_runner.get_memory_holes(), Ok(2));
3782 }
3783
3784 #[test]
3787 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3788 fn check_diluted_check_usage_without_pool_instance() {
3789 let program = program!();
3790
3791 let mut cairo_runner = cairo_runner!(program);
3792
3793 cairo_runner.layout.diluted_pool_instance_def = None;
3794 assert_matches!(cairo_runner.check_diluted_check_usage(), Ok(()));
3795 }
3796
3797 #[test]
3799 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3800 fn check_diluted_check_usage_without_builtin_runners() {
3801 let program = program!();
3802
3803 let mut cairo_runner = cairo_runner!(program);
3804
3805 cairo_runner.vm.current_step = 10000;
3806 cairo_runner.vm.builtin_runners = vec![];
3807 assert_matches!(cairo_runner.check_diluted_check_usage(), Ok(()));
3808 }
3809
3810 #[test]
3813 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3814 fn check_diluted_check_usage_insufficient_allocated_cells() {
3815 let program = program!();
3816
3817 let mut cairo_runner = cairo_runner!(program);
3818
3819 cairo_runner.vm.current_step = 100;
3820 cairo_runner.vm.builtin_runners = vec![];
3821 assert_matches!(
3822 cairo_runner.check_diluted_check_usage(),
3823 Err(VirtualMachineError::Memory(
3824 MemoryError::InsufficientAllocatedCells(_)
3825 ))
3826 );
3827 }
3828
3829 #[test]
3832 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3833 fn check_diluted_check_usage() {
3834 let program = program!();
3835
3836 let mut cairo_runner = cairo_runner!(program);
3837
3838 cairo_runner.vm.current_step = 8192;
3839 cairo_runner.vm.builtin_runners = vec![BitwiseBuiltinRunner::new(Some(256), true).into()];
3840 assert_matches!(cairo_runner.check_diluted_check_usage(), Ok(()));
3841 }
3842
3843 #[test]
3844 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3845 fn end_run_run_already_finished() {
3846 let program = program!();
3847
3848 let mut hint_processor = BuiltinHintProcessor::new_empty();
3849 let mut cairo_runner = cairo_runner!(program);
3850
3851 cairo_runner.run_ended = true;
3852 assert_matches!(
3853 cairo_runner.end_run(true, false, &mut hint_processor),
3854 Err(VirtualMachineError::RunnerError(
3855 RunnerError::EndRunCalledTwice
3856 ))
3857 );
3858 }
3859
3860 #[test]
3861 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3862 fn end_run() {
3863 let program = program!();
3864
3865 let mut hint_processor = BuiltinHintProcessor::new_empty();
3866 let mut cairo_runner = cairo_runner!(program);
3867
3868 assert_matches!(
3869 cairo_runner.end_run(true, false, &mut hint_processor),
3870 Ok(())
3871 );
3872
3873 cairo_runner.run_ended = false;
3874 cairo_runner.relocated_memory.clear();
3875 assert_matches!(
3876 cairo_runner.end_run(true, true, &mut hint_processor),
3877 Ok(())
3878 );
3879 assert!(!cairo_runner.run_ended);
3880 }
3881
3882 #[test]
3883 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3884 fn end_run_proof_mode_insufficient_allocated_cells() {
3885 let program = Program::from_bytes(
3886 include_bytes!("../../../../cairo_programs/proof_programs/fibonacci.json"),
3887 Some("main"),
3888 )
3889 .unwrap();
3890
3891 let mut hint_processor = BuiltinHintProcessor::new_empty();
3892 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true, true);
3893
3894 let end = cairo_runner.initialize(false).unwrap();
3895 cairo_runner
3896 .run_until_pc(end, &mut hint_processor)
3897 .expect("Call to `CairoRunner::run_until_pc()` failed.");
3898 assert_matches!(
3899 cairo_runner.end_run(false, false, &mut hint_processor),
3900 Ok(())
3901 );
3902 }
3903
3904 #[test]
3905 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3906 fn get_builtin_segments_info_empty() {
3907 let program = program!();
3908
3909 let cairo_runner = cairo_runner!(program);
3910
3911 assert_eq!(cairo_runner.get_builtin_segments_info(), Ok(Vec::new()),);
3912 }
3913
3914 #[test]
3915 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3916 fn get_builtin_segments_info_base_not_finished() {
3917 let program = program!();
3918
3919 let mut cairo_runner = cairo_runner!(program);
3920
3921 cairo_runner.vm.builtin_runners =
3922 vec![BuiltinRunner::Output(OutputBuiltinRunner::new(true))];
3923 assert_eq!(
3924 cairo_runner.get_builtin_segments_info(),
3925 Err(RunnerError::NoStopPointer(Box::new(BuiltinName::output))),
3926 );
3927 }
3928
3929 #[test]
3930 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3931 fn get_execution_resources_trace_not_enabled() {
3932 let program = program!();
3933
3934 let mut cairo_runner = cairo_runner!(program);
3935
3936 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3937 cairo_runner.vm.current_step = 10;
3938 assert_eq!(
3939 cairo_runner.get_execution_resources(),
3940 Ok(ExecutionResources {
3941 n_steps: 10,
3942 n_memory_holes: 0,
3943 builtin_instance_counter: HashMap::new(),
3944 }),
3945 );
3946 }
3947
3948 #[test]
3949 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3950 fn get_execution_resources_run_program() {
3951 let program_data = include_bytes!("../../../../cairo_programs/fibonacci.json");
3952 let cairo_run_config = CairoRunConfig {
3953 entrypoint: "main",
3954 trace_enabled: true,
3955 relocate_mem: false,
3956 layout: LayoutName::all_cairo,
3957 proof_mode: false,
3958 secure_run: Some(false),
3959 ..Default::default()
3960 };
3961 let mut hint_executor = BuiltinHintProcessor::new_empty();
3962 let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
3963 assert_eq!(runner.get_execution_resources().unwrap().n_steps, 80);
3964 }
3965
3966 #[test]
3967 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3968 fn get_execution_resources_run_program_no_trace() {
3969 let program_data = include_bytes!("../../../../cairo_programs/fibonacci.json");
3970 let cairo_run_config = CairoRunConfig {
3971 entrypoint: "main",
3972 trace_enabled: false,
3973 relocate_mem: false,
3974 layout: LayoutName::all_cairo,
3975 proof_mode: false,
3976 secure_run: Some(false),
3977 ..Default::default()
3978 };
3979 let mut hint_executor = BuiltinHintProcessor::new_empty();
3980 let runner = cairo_run(program_data, &cairo_run_config, &mut hint_executor).unwrap();
3981 assert_eq!(runner.get_execution_resources().unwrap().n_steps, 80);
3982 }
3983
3984 #[test]
3985 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
3986 fn get_execution_resources_empty_builtins() {
3987 let program = program!();
3988
3989 let mut cairo_runner = cairo_runner!(program);
3990
3991 cairo_runner.vm.current_step = 10;
3992 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
3993 assert_eq!(
3994 cairo_runner.get_execution_resources(),
3995 Ok(ExecutionResources {
3996 n_steps: 10,
3997 n_memory_holes: 0,
3998 builtin_instance_counter: HashMap::new(),
3999 }),
4000 );
4001 }
4002
4003 #[test]
4004 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4005 fn get_execution_resources() {
4006 let program = program!();
4007
4008 let mut cairo_runner = cairo_runner!(program);
4009
4010 cairo_runner.vm.current_step = 10;
4011 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
4012 cairo_runner.vm.builtin_runners = vec![{
4013 let mut builtin = OutputBuiltinRunner::new(true);
4014 builtin.initialize_segments(&mut cairo_runner.vm.segments);
4015
4016 BuiltinRunner::Output(builtin)
4017 }];
4018 assert_eq!(
4019 cairo_runner.get_execution_resources(),
4020 Ok(ExecutionResources {
4021 n_steps: 10,
4022 n_memory_holes: 0,
4023 builtin_instance_counter: HashMap::from([(BuiltinName::output, 4)]),
4024 }),
4025 );
4026 }
4027
4028 #[test]
4029 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4030 fn finalize_segments_run_not_ended() {
4031 let program = program!();
4032 let mut cairo_runner = cairo_runner!(program);
4033 assert_eq!(
4034 cairo_runner.finalize_segments(),
4035 Err(RunnerError::FinalizeNoEndRun)
4036 )
4037 }
4038
4039 #[test]
4040 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4041 fn finalize_segments_run_ended_empty_no_prog_base() {
4042 let program = program!();
4043 let mut cairo_runner = cairo_runner!(program);
4044 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4045 cairo_runner.run_ended = true;
4046 assert_eq!(
4047 cairo_runner.finalize_segments(),
4048 Err(RunnerError::NoProgBase)
4049 )
4050 }
4051
4052 #[test]
4053 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4054 fn finalize_segments_run_ended_empty_no_exec_base() {
4055 let program = program!();
4056 let mut cairo_runner = cairo_runner!(program);
4057 cairo_runner.runner_mode = RunnerMode::ProofModeCanonical;
4058 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4059 cairo_runner.run_ended = true;
4060 assert_eq!(
4061 cairo_runner.finalize_segments(),
4062 Err(RunnerError::NoExecBase)
4063 )
4064 }
4065
4066 #[test]
4067 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4068 fn finalize_segments_run_ended_empty_noproof_mode() {
4069 let program = program!();
4070 let mut cairo_runner = cairo_runner!(program);
4071 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4072 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4073 cairo_runner.run_ended = true;
4074 assert_eq!(
4075 cairo_runner.finalize_segments(),
4076 Err(RunnerError::FinalizeSegmentsNoProofMode)
4077 )
4078 }
4079
4080 #[test]
4081 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4082 fn finalize_segments_run_ended_emptyproof_mode() {
4083 let program = program!();
4084 let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4085 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4086 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4087 cairo_runner.run_ended = true;
4088 assert_eq!(cairo_runner.finalize_segments(), Ok(()));
4089 assert!(cairo_runner.segments_finalized);
4090 assert!(cairo_runner.execution_public_memory.unwrap().is_empty())
4091 }
4092
4093 #[test]
4094 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4095 fn finalize_segments_run_ended_not_emptyproof_mode_empty_execution_public_memory() {
4096 let mut program = program!();
4097 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4098 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4099 let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4101 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4102 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4103 cairo_runner.run_ended = true;
4104 assert_eq!(cairo_runner.finalize_segments(), Ok(()));
4105 assert!(cairo_runner.segments_finalized);
4106 assert_eq!(
4108 cairo_runner.vm.segments.segment_sizes.get(&0),
4109 Some(&8_usize)
4110 );
4111 assert_eq!(
4112 cairo_runner.vm.segments.public_memory_offsets.get(&0),
4113 Some(&vec![
4114 (0_usize, 0_usize),
4115 (1_usize, 0_usize),
4116 (2_usize, 0_usize),
4117 (3_usize, 0_usize),
4118 (4_usize, 0_usize),
4119 (5_usize, 0_usize),
4120 (6_usize, 0_usize),
4121 (7_usize, 0_usize)
4122 ])
4123 );
4124 assert_eq!(cairo_runner.vm.segments.segment_sizes.get(&1), None);
4126 assert_eq!(
4127 cairo_runner.vm.segments.public_memory_offsets.get(&1),
4128 Some(&vec![])
4129 );
4130 }
4131
4132 #[test]
4133 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4134 fn finalize_segments_run_ended_not_emptyproof_mode_with_execution_public_memory() {
4135 let mut program = program!();
4136 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4137 vec_data![(1), (2), (3), (4)];
4138 let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4140 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4141 cairo_runner.execution_base = Some(Relocatable::from((1, 1)));
4142 cairo_runner.execution_public_memory = Some(vec![1_usize, 3_usize, 5_usize, 4_usize]);
4143 cairo_runner.run_ended = true;
4144 assert_eq!(cairo_runner.finalize_segments(), Ok(()));
4145 assert!(cairo_runner.segments_finalized);
4146 assert_eq!(
4148 cairo_runner.vm.segments.segment_sizes.get(&0),
4149 Some(&4_usize)
4150 );
4151 assert_eq!(
4152 cairo_runner.vm.segments.public_memory_offsets.get(&0),
4153 Some(&vec![
4154 (0_usize, 0_usize),
4155 (1_usize, 0_usize),
4156 (2_usize, 0_usize),
4157 (3_usize, 0_usize)
4158 ])
4159 );
4160 assert_eq!(cairo_runner.vm.segments.segment_sizes.get(&1), None);
4162 assert_eq!(
4163 cairo_runner.vm.segments.public_memory_offsets.get(&1),
4164 Some(&vec![
4165 (2_usize, 0_usize),
4166 (4_usize, 0_usize),
4167 (6_usize, 0_usize),
4168 (5_usize, 0_usize)
4169 ])
4170 );
4171 }
4172
4173 #[test]
4176 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4177 fn get_perm_range_check_limits_no_builtins() {
4178 let program = program!();
4179 let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::default());
4180
4181 let mut cairo_runner = cairo_runner!(program);
4182
4183 cairo_runner.vm.segments.memory.data = vec![
4184 vec![
4185 MemoryCell::new(Felt252::from(0x8000_8023_8012u64).into()),
4186 MemoryCell::new(Felt252::from(0xBFFF_8000_0620u64).into()),
4187 MemoryCell::new(Felt252::from(0x8FFF_8000_0750u64).into()),
4188 ],
4189 vec![MemoryCell::new((0isize, 0usize).into()); 128 * 1024],
4190 ];
4191
4192 cairo_runner.run_for_steps(1, &mut hint_processor).unwrap();
4193
4194 assert_matches!(
4195 cairo_runner.get_perm_range_check_limits(),
4196 Some((32768, 32803))
4197 );
4198 }
4199
4200 #[test]
4203 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4204 fn get_perm_range_check_limits() {
4205 let program = program!();
4206
4207 let mut cairo_runner = cairo_runner!(program);
4208
4209 cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4210 0x80FF_8000_0530u64
4211 ))]];
4212 cairo_runner.vm.builtin_runners =
4213 vec![RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(12), true).into()];
4214
4215 assert_matches!(cairo_runner.get_perm_range_check_limits(), Some((0, 33023)));
4216 }
4217
4218 #[test]
4221 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4222 fn check_range_check_usage_perm_range_limits_none() {
4223 let program = program!();
4224
4225 let mut cairo_runner = cairo_runner!(program);
4226 cairo_runner.vm.trace = Some(vec![]);
4227
4228 assert_matches!(cairo_runner.check_range_check_usage(), Ok(()));
4229 }
4230
4231 #[test]
4234 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4235 fn check_range_check_usage_without_builtins() {
4236 let program = program!();
4237
4238 let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
4239 cairo_runner.vm.builtin_runners = vec![];
4240 cairo_runner.vm.current_step = 10000;
4241 cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4242 0x80FF_8000_0530u64
4243 ))]];
4244 cairo_runner.vm.trace = Some(vec![TraceEntry {
4245 pc: (0, 0).into(),
4246 ap: 0,
4247 fp: 0,
4248 }]);
4249
4250 assert_matches!(cairo_runner.check_range_check_usage(), Ok(()));
4251 }
4252
4253 #[test]
4256 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4257 fn check_range_check_usage_insufficient_allocated_cells() {
4258 let program = program!();
4259
4260 let mut cairo_runner = cairo_runner!(program);
4261 cairo_runner.vm.builtin_runners =
4262 vec![RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true).into()];
4263 cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4264 0x80FF_8000_0530u64
4265 ))]];
4266 cairo_runner.vm.trace = Some(vec![TraceEntry {
4267 pc: (0, 0).into(),
4268 ap: 0,
4269 fp: 0,
4270 }]);
4271 cairo_runner.vm.segments.compute_effective_sizes();
4272
4273 assert_matches!(
4274 cairo_runner.check_range_check_usage(),
4275 Err(VirtualMachineError::Memory(
4276 MemoryError::InsufficientAllocatedCells(_)
4277 ))
4278 );
4279 }
4280
4281 #[test]
4282 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4283 fn get_initial_fp_is_none_without_initialization() {
4284 let program = program!();
4285
4286 let runner = cairo_runner!(program);
4287
4288 assert_eq!(None, runner.get_initial_fp());
4289 }
4290
4291 #[test]
4292 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4293 fn get_initial_fp_can_be_obtained() {
4294 let program = program![BuiltinName::output];
4295 let mut cairo_runner = cairo_runner!(program);
4296 for _ in 0..2 {
4297 cairo_runner.vm.segments.add();
4298 }
4299 cairo_runner.program_base = Some(relocatable!(0, 0));
4300 cairo_runner.execution_base = Some(relocatable!(1, 0));
4301 let return_fp = Felt252::from(9_i32).into();
4302 cairo_runner
4303 .initialize_function_entrypoint(0, vec![], return_fp)
4304 .unwrap();
4305 assert_eq!(Some(relocatable!(1, 2)), cairo_runner.get_initial_fp());
4306 }
4307
4308 #[test]
4309 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4310 fn check_used_cells_valid_case() {
4311 let program = program![BuiltinName::range_check, BuiltinName::output];
4312 let mut cairo_runner = cairo_runner!(program);
4313 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
4314 cairo_runner.vm.trace = Some(vec![]);
4315 cairo_runner.layout.diluted_pool_instance_def = None;
4316
4317 assert_matches!(cairo_runner.check_used_cells(), Ok(()));
4318 }
4319
4320 #[test]
4321 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4322 fn check_used_cells_get_used_cells_and_allocated_size_error() {
4323 let program = program!();
4324
4325 let mut cairo_runner = cairo_runner!(program);
4326 cairo_runner.vm.builtin_runners =
4327 vec![RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true).into()];
4328 cairo_runner.vm.segments.memory.data = vec![vec![MemoryCell::new(mayberelocatable!(
4329 0x80FF_8000_0530u64
4330 ))]];
4331 cairo_runner.vm.trace = Some(vec![TraceEntry {
4332 pc: (0, 0).into(),
4333 ap: 0,
4334 fp: 0,
4335 }]);
4336 cairo_runner.vm.segments.compute_effective_sizes();
4337 assert_matches!(
4338 cairo_runner.check_used_cells(),
4339 Err(VirtualMachineError::Memory(
4340 MemoryError::InsufficientAllocatedCells(_)
4341 ))
4342 );
4343 }
4344
4345 #[test]
4346 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4347 fn check_used_cells_check_memory_usage_error() {
4348 let program = program!();
4349
4350 let mut cairo_runner = cairo_runner!(program);
4351 cairo_runner
4352 .vm
4353 .segments
4354 .memory
4355 .mark_as_accessed((1, 0).into());
4356 cairo_runner
4357 .vm
4358 .segments
4359 .memory
4360 .mark_as_accessed((1, 3).into());
4361 cairo_runner.vm.builtin_runners = vec![{
4362 let mut builtin_runner: BuiltinRunner = OutputBuiltinRunner::new(true).into();
4363 builtin_runner.initialize_segments(&mut cairo_runner.vm.segments);
4364
4365 builtin_runner
4366 }];
4367 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4, 12]);
4368 cairo_runner.vm.trace = Some(vec![]);
4369
4370 assert_matches!(
4371 cairo_runner.check_used_cells(),
4372 Err(VirtualMachineError::Memory(
4373 MemoryError::InsufficientAllocatedCells(_)
4374 ))
4375 );
4376 }
4377
4378 #[test]
4379 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4380 fn check_used_cells_check_diluted_check_usage_error() {
4381 let program = program![BuiltinName::range_check, BuiltinName::output];
4382 let mut cairo_runner = cairo_runner!(program);
4383 cairo_runner.vm.segments.segment_used_sizes = Some(vec![4]);
4384 cairo_runner.vm.trace = Some(vec![]);
4385
4386 assert_matches!(
4387 cairo_runner.check_used_cells(),
4388 Err(VirtualMachineError::Memory(
4389 MemoryError::InsufficientAllocatedCells(_)
4390 ))
4391 );
4392 }
4393
4394 #[test]
4395 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4396 fn initialize_all_program_builtins() {
4397 let mut program = program!();
4398
4399 program.builtins = vec![
4401 BuiltinName::pedersen,
4402 BuiltinName::range_check,
4403 BuiltinName::output,
4404 BuiltinName::ecdsa,
4405 BuiltinName::bitwise,
4406 BuiltinName::ec_op,
4407 BuiltinName::keccak,
4408 BuiltinName::poseidon,
4409 ];
4410
4411 let mut cairo_runner = cairo_runner!(program);
4412
4413 cairo_runner
4414 .initialize_program_builtins()
4415 .expect("Builtin initialization failed.");
4416
4417 let given_output = cairo_runner.vm.get_builtin_runners();
4418
4419 assert_eq!(given_output[0].name(), BuiltinName::pedersen);
4420 assert_eq!(given_output[1].name(), BuiltinName::range_check);
4421 assert_eq!(given_output[2].name(), BuiltinName::output);
4422 assert_eq!(given_output[3].name(), BuiltinName::ecdsa);
4423 assert_eq!(given_output[4].name(), BuiltinName::bitwise);
4424 assert_eq!(given_output[5].name(), BuiltinName::ec_op);
4425 assert_eq!(given_output[6].name(), BuiltinName::keccak);
4426 assert_eq!(given_output[7].name(), BuiltinName::poseidon);
4427 }
4428
4429 #[test]
4430 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4431 fn initialize_function_runner_without_builtins() {
4432 let program = program!();
4433
4434 let mut cairo_runner = cairo_runner!(program);
4435
4436 cairo_runner
4437 .initialize_function_runner()
4438 .expect("initialize_function_runner failed.");
4439
4440 assert_eq!(
4441 cairo_runner.program_base,
4442 Some(Relocatable {
4443 segment_index: 0,
4444 offset: 0,
4445 })
4446 );
4447 assert_eq!(
4448 cairo_runner.execution_base,
4449 Some(Relocatable {
4450 segment_index: 1,
4451 offset: 0,
4452 })
4453 );
4454 assert_eq!(cairo_runner.vm.segments.num_segments(), 2);
4455 }
4456
4457 #[test]
4458 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4459 fn initialize_function_runner_with_segment_arena_builtin() {
4460 let program = program!();
4461
4462 let mut cairo_runner = cairo_runner!(program);
4463
4464 cairo_runner
4465 .initialize_function_runner_cairo_1(&[BuiltinName::segment_arena])
4466 .expect("initialize_function_runner failed.");
4467
4468 let builtin_runners = cairo_runner.vm.get_builtin_runners();
4469
4470 assert_eq!(builtin_runners[0].name(), BuiltinName::segment_arena);
4471
4472 assert_eq!(
4473 cairo_runner.program_base,
4474 Some(Relocatable {
4475 segment_index: 0,
4476 offset: 0,
4477 })
4478 );
4479 assert_eq!(
4480 cairo_runner.execution_base,
4481 Some(Relocatable {
4482 segment_index: 1,
4483 offset: 0,
4484 })
4485 );
4486 assert_eq!(cairo_runner.vm.segments.num_segments(), 4);
4488 }
4489
4490 #[test]
4491 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4492 fn initialize_segments_incorrect_layout_plain_one_builtin() {
4493 let program = program![BuiltinName::output];
4494 let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
4495 assert_eq!(
4496 cairo_runner.initialize_builtins(false),
4497 Err(RunnerError::NoBuiltinForInstance(Box::new((
4498 HashSet::from([BuiltinName::output]),
4499 LayoutName::plain
4500 ))))
4501 );
4502 }
4503
4504 #[test]
4505 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4506 fn initialize_segments_incorrect_layout_plain_two_builtins() {
4507 let program = program![BuiltinName::output, BuiltinName::pedersen];
4508 let mut cairo_runner = cairo_runner!(program, LayoutName::plain);
4509 assert_eq!(
4510 cairo_runner.initialize_builtins(false),
4511 Err(RunnerError::NoBuiltinForInstance(Box::new((
4512 HashSet::from([BuiltinName::output, BuiltinName::pedersen]),
4513 LayoutName::plain
4514 ))))
4515 );
4516 }
4517
4518 #[test]
4519 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4520 fn initialize_segments_incorrect_layout_small_two_builtins() {
4521 let program = program![BuiltinName::output, BuiltinName::bitwise];
4522 let mut cairo_runner = cairo_runner!(program, LayoutName::small);
4523 assert_eq!(
4524 cairo_runner.initialize_builtins(false),
4525 Err(RunnerError::NoBuiltinForInstance(Box::new((
4526 HashSet::from([BuiltinName::bitwise]),
4527 LayoutName::small,
4528 ))))
4529 );
4530 }
4531 #[test]
4532 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4533 fn initialize_main_entrypoint_proof_mode_empty_program() {
4534 let program = program!(start = Some(0), end = Some(0), main = Some(8),);
4535 let mut runner = cairo_runner!(program);
4536 runner.runner_mode = RunnerMode::ProofModeCanonical;
4537 runner.initialize_segments(None);
4538 assert_eq!(runner.execution_base, Some(Relocatable::from((1, 0))));
4539 assert_eq!(runner.program_base, Some(Relocatable::from((0, 0))));
4540 assert_eq!(
4541 runner.initialize_main_entrypoint(),
4542 Ok(Relocatable::from((0, 0)))
4543 );
4544 assert_eq!(runner.initial_ap, Some(Relocatable::from((1, 2))));
4545 assert_eq!(runner.initial_fp, runner.initial_ap);
4546 assert_eq!(runner.execution_public_memory, Some(vec![0, 1]));
4547 }
4548
4549 #[test]
4550 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4551 fn initialize_main_entrypoint_proof_mode_empty_program_two_builtins() {
4552 let program = program!(
4553 start = Some(0),
4554 end = Some(0),
4555 main = Some(8),
4556 builtins = vec![BuiltinName::output, BuiltinName::ec_op],
4557 );
4558 let mut runner = cairo_runner!(program);
4559 runner.runner_mode = RunnerMode::ProofModeCanonical;
4560 runner.initialize_builtins(false).unwrap();
4561 runner.initialize_segments(None);
4562 assert_eq!(runner.execution_base, Some(Relocatable::from((1, 0))));
4563 assert_eq!(runner.program_base, Some(Relocatable::from((0, 0))));
4564 assert_eq!(
4565 runner.initialize_main_entrypoint(),
4566 Ok(Relocatable::from((0, 0)))
4567 );
4568 assert_eq!(runner.initial_ap, Some(Relocatable::from((1, 2))));
4569 assert_eq!(runner.initial_fp, runner.initial_ap);
4570 assert_eq!(runner.execution_public_memory, Some(vec![0, 1, 2, 3]));
4571 }
4572
4573 #[test]
4574 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4575 fn can_get_the_runner_program_builtins() {
4576 let program = program!(
4577 start = Some(0),
4578 end = Some(0),
4579 main = Some(8),
4580 builtins = vec![BuiltinName::output, BuiltinName::ec_op],
4581 );
4582 let runner = cairo_runner!(program);
4583
4584 assert_eq!(&program.builtins, runner.get_program_builtins());
4585 }
4586
4587 #[test]
4588 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4589 fn set_entrypoint_main_default() {
4590 let program = program!(
4591 identifiers = [(
4592 "__main__.main",
4593 Identifier {
4594 pc: Some(0),
4595 type_: None,
4596 value: None,
4597 full_name: None,
4598 members: None,
4599 cairo_type: None,
4600 size: None,
4601 destination: None,
4602 },
4603 )]
4604 .into_iter()
4605 .map(|(k, v)| (k.to_string(), v))
4606 .collect(),
4607 );
4608 let mut cairo_runner = cairo_runner!(program);
4609
4610 cairo_runner
4611 .set_entrypoint(None)
4612 .expect("Call to `set_entrypoint()` failed.");
4613 assert_eq!(cairo_runner.entrypoint, Some(0));
4614 }
4615
4616 #[test]
4617 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4618 fn set_entrypoint_main() {
4619 let program = program!(
4620 identifiers = [
4621 (
4622 "__main__.main",
4623 Identifier {
4624 pc: Some(0),
4625 type_: None,
4626 value: None,
4627 full_name: None,
4628 members: None,
4629 cairo_type: None,
4630 size: None,
4631 destination: None,
4632 },
4633 ),
4634 (
4635 "__main__.alternate_main",
4636 Identifier {
4637 pc: Some(1),
4638 type_: None,
4639 value: None,
4640 full_name: None,
4641 members: None,
4642 cairo_type: None,
4643 size: None,
4644 destination: None,
4645 },
4646 ),
4647 ]
4648 .into_iter()
4649 .map(|(k, v)| (k.to_string(), v))
4650 .collect(),
4651 );
4652 let mut cairo_runner = cairo_runner!(program);
4653
4654 cairo_runner
4655 .set_entrypoint(Some("alternate_main"))
4656 .expect("Call to `set_entrypoint()` failed.");
4657 assert_eq!(cairo_runner.entrypoint, Some(1));
4658 }
4659
4660 #[test]
4662 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4663 fn set_entrypoint_main_non_existent() {
4664 let program = program!(
4665 identifiers = [(
4666 "__main__.main",
4667 Identifier {
4668 pc: Some(0),
4669 type_: None,
4670 value: None,
4671 full_name: None,
4672 members: None,
4673 cairo_type: None,
4674 size: None,
4675 destination: None,
4676 },
4677 )]
4678 .into_iter()
4679 .map(|(k, v)| (k.to_string(), v))
4680 .collect(),
4681 );
4682 let mut cairo_runner = cairo_runner!(program);
4683
4684 cairo_runner
4685 .set_entrypoint(Some("nonexistent_main"))
4686 .expect_err("Call to `set_entrypoint()` succeeded (should've failed).");
4687 assert_eq!(cairo_runner.entrypoint, None);
4688 }
4689
4690 #[test]
4691 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4692 fn read_return_values_test() {
4693 let mut program = program!();
4694 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4695 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4696 let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4698 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4699 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4700 cairo_runner.run_ended = true;
4701 cairo_runner.segments_finalized = false;
4702 assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4705 assert_eq!(
4706 cairo_runner
4707 .execution_public_memory
4708 .expect("missing execution public memory"),
4709 Vec::<usize>::new()
4710 );
4711 }
4712
4713 #[test]
4714 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4715 fn read_return_values_test_with_run_not_ended() {
4716 let mut program = program!();
4717 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4718 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4719 let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4721 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4722 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4723 cairo_runner.run_ended = false;
4724 assert_eq!(
4725 cairo_runner.read_return_values(false),
4726 Err(RunnerError::ReadReturnValuesNoEndRun)
4727 );
4728 }
4729
4730 #[test]
4731 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4732 fn read_return_values_test_with_segments_finalized() {
4733 let mut program = program!();
4734 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4735 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4736 let mut cairo_runner = cairo_runner!(program, LayoutName::plain, true);
4738 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4739 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4740 cairo_runner.run_ended = true;
4741 cairo_runner.segments_finalized = true;
4742 assert_eq!(
4743 cairo_runner.read_return_values(false),
4744 Err(RunnerError::FailedAddingReturnValues)
4745 );
4746 }
4747
4748 #[test]
4749 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4750 fn read_return_values_updates_builtin_stop_ptr_one_builtin_empty() {
4751 let mut program = program![BuiltinName::output];
4752 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4753 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4754 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true);
4756 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4757 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4758 cairo_runner.run_ended = true;
4759 cairo_runner.segments_finalized = false;
4760 let output_builtin = OutputBuiltinRunner::new(true);
4761 cairo_runner.vm.builtin_runners.push(output_builtin.into());
4762 cairo_runner.vm.segments.memory.data = vec![
4763 vec![],
4764 vec![MemoryCell::new(MaybeRelocatable::from((0, 0)))],
4765 vec![],
4766 ];
4767 cairo_runner.vm.set_ap(1);
4768 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 1, 0]);
4769 assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4771 let output_builtin = match &cairo_runner.vm.builtin_runners[0] {
4772 BuiltinRunner::Output(runner) => runner,
4773 _ => unreachable!(),
4774 };
4775 assert_eq!(output_builtin.stop_ptr, Some(0))
4776 }
4777
4778 #[test]
4779 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4780 fn read_return_values_updates_builtin_stop_ptr_one_builtin_one_element() {
4781 let mut program = program![BuiltinName::output];
4782 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4783 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4784 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true);
4786 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4787 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4788 cairo_runner.run_ended = true;
4789 cairo_runner.segments_finalized = false;
4790 let output_builtin = OutputBuiltinRunner::new(true);
4791 cairo_runner.vm.builtin_runners.push(output_builtin.into());
4792 cairo_runner.vm.segments.memory.data = vec![
4793 vec![MemoryCell::new(MaybeRelocatable::from((0, 0)))],
4794 vec![MemoryCell::new(MaybeRelocatable::from((0, 1)))],
4795 vec![],
4796 ];
4797 cairo_runner.vm.set_ap(1);
4798 cairo_runner.vm.segments.segment_used_sizes = Some(vec![1, 1, 0]);
4799 assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4801 let output_builtin = match &cairo_runner.vm.builtin_runners[0] {
4802 BuiltinRunner::Output(runner) => runner,
4803 _ => unreachable!(),
4804 };
4805 assert_eq!(output_builtin.stop_ptr, Some(1))
4806 }
4807
4808 #[test]
4809 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4810 fn read_return_values_updates_builtin_stop_ptr_two_builtins() {
4811 let mut program = program![BuiltinName::output, BuiltinName::bitwise];
4812 Arc::get_mut(&mut program.shared_program_data).unwrap().data =
4813 vec_data![(1), (2), (3), (4), (5), (6), (7), (8)];
4814 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, true);
4816 cairo_runner.program_base = Some(Relocatable::from((0, 0)));
4817 cairo_runner.execution_base = Some(Relocatable::from((1, 0)));
4818 cairo_runner.run_ended = true;
4819 cairo_runner.segments_finalized = false;
4820 let output_builtin = OutputBuiltinRunner::new(true);
4821 let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true);
4822 cairo_runner.vm.builtin_runners.push(output_builtin.into());
4823 cairo_runner.vm.builtin_runners.push(bitwise_builtin.into());
4824 cairo_runner.initialize_segments(None);
4825 cairo_runner.vm.segments.memory.data = vec![
4826 vec![MemoryCell::new(MaybeRelocatable::from((0, 0)))],
4827 vec![
4828 MemoryCell::new(MaybeRelocatable::from((2, 0))),
4829 MemoryCell::new(MaybeRelocatable::from((3, 5))),
4830 ],
4831 vec![],
4832 ];
4833 cairo_runner.vm.set_ap(2);
4834 cairo_runner.vm.segments.segment_used_sizes = Some(vec![0, 2, 0, 5]);
4836 assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4838 let output_builtin = match &cairo_runner.vm.builtin_runners[0] {
4839 BuiltinRunner::Output(runner) => runner,
4840 _ => unreachable!(),
4841 };
4842 assert_eq!(output_builtin.stop_ptr, Some(0));
4843 assert_eq!(cairo_runner.read_return_values(false), Ok(()));
4844 let bitwise_builtin = match &cairo_runner.vm.builtin_runners[1] {
4845 BuiltinRunner::Bitwise(runner) => runner,
4846 _ => unreachable!(),
4847 };
4848 assert_eq!(bitwise_builtin.stop_ptr, Some(5));
4849 }
4850
4851 #[test]
4852 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4853 fn run_from_entrypoint_custom_program_test() {
4854 let program = Program::from_bytes(
4855 include_bytes!("../../../../cairo_programs/example_program.json"),
4856 None,
4857 )
4858 .unwrap();
4859 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
4860 let mut hint_processor = BuiltinHintProcessor::new_empty();
4861
4862 let main_entrypoint = program
4864 .shared_program_data
4865 .identifiers
4866 .get("__main__.main")
4867 .unwrap()
4868 .pc
4869 .unwrap();
4870
4871 cairo_runner.initialize_builtins(false).unwrap();
4872 cairo_runner.initialize_segments(None);
4873 assert_matches!(
4874 cairo_runner.run_from_entrypoint(
4875 main_entrypoint,
4876 &[
4877 &mayberelocatable!(2).into(),
4878 &MaybeRelocatable::from((2, 0)).into()
4879 ], true,
4881 None,
4882 &mut hint_processor,
4883 ),
4884 Ok(())
4885 );
4886
4887 let mut new_cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
4888 let mut hint_processor = BuiltinHintProcessor::new_empty();
4889
4890 new_cairo_runner.initialize_builtins(false).unwrap();
4891 new_cairo_runner.initialize_segments(None);
4892
4893 let fib_entrypoint = program
4894 .shared_program_data
4895 .identifiers
4896 .get("__main__.evaluate_fib")
4897 .unwrap()
4898 .pc
4899 .unwrap();
4900
4901 assert_matches!(
4902 new_cairo_runner.run_from_entrypoint(
4903 fib_entrypoint,
4904 &[
4905 &mayberelocatable!(2).into(),
4906 &MaybeRelocatable::from((2, 0)).into()
4907 ],
4908 true,
4909 None,
4910 &mut hint_processor,
4911 ),
4912 Ok(())
4913 );
4914 }
4915
4916 #[test]
4917 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4918 fn run_from_entrypoint_bitwise_test_check_memory_holes() {
4919 let program = Program::from_bytes(
4920 include_bytes!("../../../../cairo_programs/bitwise_builtin_test.json"),
4921 None,
4922 )
4923 .unwrap();
4924 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
4925 let mut hint_processor = BuiltinHintProcessor::new_empty();
4926
4927 let main_entrypoint = program
4929 .shared_program_data
4930 .identifiers
4931 .get("__main__.main")
4932 .unwrap()
4933 .pc
4934 .unwrap();
4935
4936 cairo_runner.initialize_function_runner().unwrap();
4937
4938 assert!(cairo_runner
4939 .run_from_entrypoint(
4940 main_entrypoint,
4941 &[
4942 &MaybeRelocatable::from((2, 0)).into() ],
4944 true,
4945 None,
4946 &mut hint_processor,
4947 )
4948 .is_ok());
4949
4950 assert!(cairo_runner.get_memory_holes().unwrap().is_zero());
4952 }
4953
4954 #[test]
4955 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4956 fn cairo_arg_from_single() {
4957 let expected = CairoArg::Single(MaybeRelocatable::from((0, 0)));
4958 let value = MaybeRelocatable::from((0, 0));
4959 assert_eq!(expected, value.into())
4960 }
4961
4962 #[test]
4963 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4964 fn cairo_arg_from_array() {
4965 let expected = CairoArg::Array(vec![MaybeRelocatable::from((0, 0))]);
4966 let value = vec![MaybeRelocatable::from((0, 0))];
4967 assert_eq!(expected, value.into())
4968 }
4969
4970 fn setup_execution_resources() -> (ExecutionResources, ExecutionResources) {
4971 let mut builtin_instance_counter: HashMap<BuiltinName, usize> = HashMap::new();
4972 builtin_instance_counter.insert(BuiltinName::output, 8);
4973
4974 let execution_resources_1 = ExecutionResources {
4975 n_steps: 100,
4976 n_memory_holes: 5,
4977 builtin_instance_counter: builtin_instance_counter.clone(),
4978 };
4979
4980 builtin_instance_counter.insert(BuiltinName::range_check, 8);
4982
4983 let execution_resources_2 = ExecutionResources {
4984 n_steps: 100,
4985 n_memory_holes: 5,
4986 builtin_instance_counter,
4987 };
4988
4989 (execution_resources_1, execution_resources_2)
4990 }
4991
4992 #[test]
4993 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4994 fn execution_resources_add() {
4995 let (execution_resources_1, execution_resources_2) = setup_execution_resources();
4996 let combined_resources = &execution_resources_1 + &execution_resources_2;
4997
4998 assert_eq!(combined_resources.n_steps, 200);
4999 assert_eq!(combined_resources.n_memory_holes, 10);
5000 assert_eq!(
5001 combined_resources
5002 .builtin_instance_counter
5003 .get(&BuiltinName::output)
5004 .unwrap(),
5005 &16
5006 );
5007 assert!(combined_resources
5008 .builtin_instance_counter
5009 .contains_key(&BuiltinName::range_check));
5010 }
5011
5012 #[test]
5013 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5014 fn execution_resources_sub() {
5015 let (execution_resources_1, execution_resources_2) = setup_execution_resources();
5016
5017 let combined_resources = &execution_resources_1 - &execution_resources_2;
5018
5019 assert_eq!(combined_resources.n_steps, 0);
5020 assert_eq!(combined_resources.n_memory_holes, 0);
5021 assert_eq!(
5022 combined_resources
5023 .builtin_instance_counter
5024 .get(&BuiltinName::output)
5025 .unwrap(),
5026 &0
5027 );
5028 assert!(combined_resources
5029 .builtin_instance_counter
5030 .contains_key(&BuiltinName::range_check));
5031 }
5032
5033 #[test]
5034 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5035 fn run_from_entrypoint_substitute_error_message_test() {
5036 let program = Program::from_bytes(
5037 include_bytes!("../../../../cairo_programs/bad_programs/error_msg_function.json"),
5038 None,
5039 )
5040 .unwrap();
5041 let mut cairo_runner = cairo_runner!(program, LayoutName::all_cairo, false, true);
5042 let mut hint_processor = BuiltinHintProcessor::new_empty();
5043
5044 let main_entrypoint = program
5046 .shared_program_data
5047 .identifiers
5048 .get("__main__.main")
5049 .unwrap()
5050 .pc
5051 .unwrap();
5052
5053 cairo_runner.initialize_builtins(false).unwrap();
5054 cairo_runner.initialize_segments(None);
5055
5056 let result =
5057 cairo_runner.run_from_entrypoint(main_entrypoint, &[], true, None, &mut hint_processor);
5058 match result {
5059 Err(CairoRunError::VmException(exception)) => {
5060 assert_eq!(
5061 exception.error_attr_value,
5062 Some(String::from("Error message: Test error\n"))
5063 )
5064 }
5065 Err(_) => panic!("Wrong error returned, expected VmException"),
5066 Ok(_) => panic!("Expected run to fail"),
5067 }
5068 }
5069
5070 #[test]
5071 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5072 fn get_builtins_final_stack_range_check_builtin() {
5073 let program = Program::from_bytes(
5074 include_bytes!("../../../../cairo_programs/assert_le_felt_hint.json"),
5075 Some("main"),
5076 )
5077 .unwrap();
5078 let mut runner = cairo_runner!(program);
5079 let end = runner.initialize(false).unwrap();
5080 runner
5081 .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5082 .unwrap();
5083 runner.vm.segments.compute_effective_sizes();
5084 let initial_pointer = runner.vm.get_ap();
5085 let expected_pointer = (runner.vm.get_ap() - 1).unwrap();
5086 assert_eq!(
5087 runner.get_builtins_final_stack(initial_pointer),
5088 Ok(expected_pointer)
5089 );
5090 }
5091
5092 #[test]
5093 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5094 fn get_builtins_final_stack_4_builtins() {
5095 let program = Program::from_bytes(
5096 include_bytes!("../../../../cairo_programs/integration.json"),
5097 Some("main"),
5098 )
5099 .unwrap();
5100 let mut runner = cairo_runner!(program);
5101 let end = runner.initialize(false).unwrap();
5102 runner
5103 .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5104 .unwrap();
5105 runner.vm.segments.compute_effective_sizes();
5106 let initial_pointer = runner.vm.get_ap();
5107 let expected_pointer = (runner.vm.get_ap() - 4).unwrap();
5108 assert_eq!(
5109 runner.get_builtins_final_stack(initial_pointer),
5110 Ok(expected_pointer)
5111 );
5112 }
5113
5114 #[test]
5115 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5116 fn get_builtins_final_stack_no_builtins() {
5117 let program = Program::from_bytes(
5118 include_bytes!("../../../../cairo_programs/fibonacci.json"),
5119 Some("main"),
5120 )
5121 .unwrap();
5122 let mut runner = cairo_runner!(program);
5123 let end = runner.initialize(false).unwrap();
5124 runner
5125 .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5126 .unwrap();
5127 runner.vm.segments.compute_effective_sizes();
5128 let initial_pointer = runner.vm.get_ap();
5129 let expected_pointer = runner.vm.get_ap();
5130 assert_eq!(
5131 runner.get_builtins_final_stack(initial_pointer),
5132 Ok(expected_pointer)
5133 );
5134 }
5135
5136 #[test]
5137 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5138 fn filter_unused_builtins_test() {
5139 let program = Program::from_bytes(
5140 include_bytes!("../../../../cairo_programs/integration.json"),
5141 Some("main"),
5142 )
5143 .unwrap();
5144 let mut runner = cairo_runner!(program);
5145 let end = runner.initialize(false).unwrap();
5146 runner
5147 .run_until_pc(end, &mut BuiltinHintProcessor::new_empty())
5148 .unwrap();
5149 runner.vm.segments.compute_effective_sizes();
5150 let mut exec = runner.get_execution_resources().unwrap();
5151 exec.builtin_instance_counter.insert(BuiltinName::keccak, 0);
5152 assert_eq!(exec.builtin_instance_counter.len(), 5);
5153 let rsc = exec.filter_unused_builtins();
5154 assert_eq!(rsc.builtin_instance_counter.len(), 4);
5155 }
5156
5157 #[test]
5158 fn execution_resources_mul() {
5159 let execution_resources_1 = ExecutionResources {
5160 n_steps: 800,
5161 n_memory_holes: 0,
5162 builtin_instance_counter: HashMap::from([
5163 (BuiltinName::pedersen, 7),
5164 (BuiltinName::range_check, 16),
5165 ]),
5166 };
5167
5168 assert_eq!(
5169 &execution_resources_1 * 2,
5170 ExecutionResources {
5171 n_steps: 1600,
5172 n_memory_holes: 0,
5173 builtin_instance_counter: HashMap::from([
5174 (BuiltinName::pedersen, 14),
5175 (BuiltinName::range_check, 32)
5176 ])
5177 }
5178 );
5179
5180 let execution_resources_2 = ExecutionResources {
5181 n_steps: 545,
5182 n_memory_holes: 0,
5183 builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 17)]),
5184 };
5185
5186 assert_eq!(
5187 &execution_resources_2 * 8,
5188 ExecutionResources {
5189 n_steps: 4360,
5190 n_memory_holes: 0,
5191 builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 136)])
5192 }
5193 );
5194
5195 let execution_resources_3 = ExecutionResources {
5196 n_steps: 42,
5197 n_memory_holes: 0,
5198 builtin_instance_counter: HashMap::new(),
5199 };
5200
5201 assert_eq!(
5202 &execution_resources_3 * 18,
5203 ExecutionResources {
5204 n_steps: 756,
5205 n_memory_holes: 0,
5206 builtin_instance_counter: HashMap::new()
5207 }
5208 );
5209 }
5210
5211 #[test]
5212 fn test_get_program() {
5213 let program = program!(
5214 builtins = vec![BuiltinName::output],
5215 data = vec_data!((4), (6)),
5216 );
5217 let runner = cairo_runner!(program);
5218
5219 assert_eq!(runner.get_program().data_len(), 2)
5220 }
5221
5222 #[test]
5223 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5224 fn test_run_resources_none() {
5225 let program = Program::from_bytes(
5226 include_bytes!("../../../../cairo_programs/fibonacci.json"),
5227 Some("main"),
5228 )
5229 .unwrap();
5230 let mut runner = cairo_runner!(program);
5231 let end = runner.initialize(false).unwrap();
5232
5233 assert_matches!(
5235 runner.run_until_pc(end, &mut BuiltinHintProcessor::new_empty(),),
5236 Ok(())
5237 )
5238 }
5239
5240 #[test]
5241 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5242 fn test_run_resources_ok() {
5243 let program = Program::from_bytes(
5244 include_bytes!("../../../../cairo_programs/fibonacci.json"),
5245 Some("main"),
5246 )
5247 .unwrap();
5248 let mut runner = cairo_runner!(program);
5249 let end = runner.initialize(false).unwrap();
5250 let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(81));
5251 assert_matches!(runner.run_until_pc(end, &mut hint_processor), Ok(()));
5253
5254 assert_eq!(hint_processor.run_resources().get_n_steps(), Some(1));
5255 }
5256
5257 #[test]
5258 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5259 fn test_run_resources_ok_2() {
5260 let program = Program::from_bytes(
5261 include_bytes!("../../../../cairo_programs/fibonacci.json"),
5262 Some("main"),
5263 )
5264 .unwrap();
5265 let mut runner = cairo_runner!(program);
5266 let end = runner.initialize(false).unwrap();
5267 let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(80));
5268 assert_matches!(runner.run_until_pc(end, &mut hint_processor), Ok(()));
5270
5271 assert_eq!(hint_processor.run_resources(), &RunResources::new(0));
5272 }
5273
5274 #[test]
5275 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
5276 fn test_run_resources_error() {
5277 let program = Program::from_bytes(
5278 include_bytes!("../../../../cairo_programs/fibonacci.json"),
5279 Some("main"),
5280 )
5281 .unwrap();
5282 let mut runner = cairo_runner!(program);
5283 let end = runner.initialize(false).unwrap();
5284 let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(9));
5285 assert_matches!(
5287 runner.run_until_pc(end, &mut hint_processor,),
5288 Err(VirtualMachineError::UnfinishedExecution)
5289 );
5290 assert_eq!(hint_processor.run_resources(), &RunResources::new(0));
5291 }
5292
5293 #[test]
5294 fn get_cairo_pie_no_program_base() {
5295 let runner = cairo_runner!(Default::default());
5296 assert_eq!(runner.get_cairo_pie(), Err(RunnerError::NoProgBase))
5297 }
5298
5299 #[test]
5300 fn get_cairo_pie_no_execution_base() {
5301 let mut runner = cairo_runner!(Default::default());
5302 runner.program_base = Some(Relocatable::from((0, 0)));
5303 assert_eq!(runner.get_cairo_pie(), Err(RunnerError::NoExecBase))
5304 }
5305
5306 #[test]
5307 fn get_cairo_pie_no_segment_sizes() {
5308 let mut runner = cairo_runner!(Default::default());
5309 runner.program_base = Some(Relocatable::from((0, 0)));
5310 runner.execution_base = Some(Relocatable::from((1, 0)));
5311 runner.vm.add_memory_segment();
5312 runner.vm.add_memory_segment();
5313 runner
5315 .vm
5316 .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5317 .unwrap();
5318 runner
5320 .vm
5321 .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5322 .unwrap();
5323 assert_eq!(
5324 runner.get_cairo_pie(),
5325 Err(RunnerError::UnexpectedRetFpSegmentSize)
5326 );
5327 }
5328
5329 #[test]
5330 fn get_cairo_pie_ret_pc_segment_size_not_zero() {
5331 let mut runner = cairo_runner!(Default::default());
5332 runner.program_base = Some(Relocatable::from((0, 0)));
5333 runner.execution_base = Some(Relocatable::from((1, 0)));
5334 runner.vm.add_memory_segment();
5335 runner.vm.add_memory_segment();
5336 runner
5338 .vm
5339 .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5340 .unwrap();
5341 runner
5343 .vm
5344 .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5345 .unwrap();
5346 runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 1)]);
5348 assert_eq!(
5349 runner.get_cairo_pie(),
5350 Err(RunnerError::UnexpectedRetPcSegmentSize)
5351 );
5352 }
5353
5354 #[test]
5355 fn get_cairo_pie_program_base_offset_not_zero() {
5356 let mut runner = cairo_runner!(Default::default());
5357 runner.program_base = Some(Relocatable::from((0, 1)));
5358 runner.execution_base = Some(Relocatable::from((1, 0)));
5359 runner.vm.add_memory_segment();
5360 runner.vm.add_memory_segment();
5361 runner
5363 .vm
5364 .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5365 .unwrap();
5366 runner
5368 .vm
5369 .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5370 .unwrap();
5371 runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5373 assert_eq!(
5374 runner.get_cairo_pie(),
5375 Err(RunnerError::ProgramBaseOffsetNotZero)
5376 );
5377 }
5378
5379 #[test]
5380 fn get_cairo_pie_execution_base_offset_not_zero() {
5381 let mut runner = cairo_runner!(Default::default());
5382 runner.program_base = Some(Relocatable::from((0, 0)));
5383 runner.execution_base = Some(Relocatable::from((1, 1)));
5384 runner.vm.add_memory_segment();
5385 runner.vm.add_memory_segment();
5386 runner
5388 .vm
5389 .insert_value::<Relocatable>((1, 1).into(), (2, 0).into())
5390 .unwrap();
5391 runner
5393 .vm
5394 .insert_value::<Relocatable>((1, 2).into(), (3, 0).into())
5395 .unwrap();
5396 runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5398 assert_eq!(
5399 runner.get_cairo_pie(),
5400 Err(RunnerError::ExecBaseOffsetNotZero)
5401 );
5402 }
5403
5404 #[test]
5405 fn get_cairo_pie_ret_fp_offset_not_zero() {
5406 let mut runner = cairo_runner!(Default::default());
5407 runner.program_base = Some(Relocatable::from((0, 0)));
5408 runner.execution_base = Some(Relocatable::from((1, 0)));
5409 runner.vm.add_memory_segment();
5410 runner.vm.add_memory_segment();
5411 runner
5413 .vm
5414 .insert_value::<Relocatable>((1, 0).into(), (2, 1).into())
5415 .unwrap();
5416 runner
5418 .vm
5419 .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5420 .unwrap();
5421 runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5423 assert_eq!(runner.get_cairo_pie(), Err(RunnerError::RetFpOffsetNotZero));
5424 }
5425
5426 #[test]
5427 fn get_cairo_pie_ret_pc_offset_not_zero() {
5428 let mut runner = cairo_runner!(Default::default());
5429 runner.program_base = Some(Relocatable::from((0, 0)));
5430 runner.execution_base = Some(Relocatable::from((1, 0)));
5431 runner.vm.add_memory_segment();
5432 runner.vm.add_memory_segment();
5433 runner
5435 .vm
5436 .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5437 .unwrap();
5438 runner
5440 .vm
5441 .insert_value::<Relocatable>((1, 1).into(), (3, 1).into())
5442 .unwrap();
5443 runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5445 assert_eq!(runner.get_cairo_pie(), Err(RunnerError::RetPcOffsetNotZero));
5446 }
5447
5448 #[test]
5449 fn get_cairo_pie_ok() {
5450 let mut runner = cairo_runner!(Default::default());
5451 runner.program_base = Some(Relocatable::from((0, 0)));
5452 runner.execution_base = Some(Relocatable::from((1, 0)));
5453 runner.vm.add_memory_segment();
5454 runner.vm.add_memory_segment();
5455 runner
5457 .vm
5458 .insert_value::<Relocatable>((1, 0).into(), (2, 0).into())
5459 .unwrap();
5460 runner
5462 .vm
5463 .insert_value::<Relocatable>((1, 1).into(), (3, 0).into())
5464 .unwrap();
5465 runner.vm.segments.segment_sizes = HashMap::from([(0, 0), (1, 2), (2, 0), (3, 0)]);
5467 }
5468
5469 #[test]
5470 fn get_air_private_input() {
5471 let program_content =
5472 include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json");
5473 let runner = crate::cairo_run::cairo_run(
5474 program_content,
5475 &CairoRunConfig {
5476 proof_mode: true,
5477 layout: LayoutName::all_cairo,
5478 ..Default::default()
5479 },
5480 &mut BuiltinHintProcessor::new_empty(),
5481 )
5482 .unwrap();
5483 let air_private_input = runner.get_air_private_input();
5484 assert!(air_private_input.0[&BuiltinName::pedersen].is_empty());
5485 assert!(air_private_input.0[&BuiltinName::range_check].is_empty());
5486 assert!(air_private_input.0[&BuiltinName::bitwise].is_empty());
5487 assert!(air_private_input.0[&BuiltinName::ec_op].is_empty());
5488 assert!(air_private_input.0[&BuiltinName::keccak].is_empty());
5489 assert!(air_private_input.0[&BuiltinName::poseidon].is_empty());
5490 assert_eq!(
5491 air_private_input.0[&BuiltinName::ecdsa],
5492 vec![PrivateInput::Signature(PrivateInputSignature {
5493 index: 0,
5494 pubkey: felt_hex!(
5495 "0x3d60886c2353d93ec2862e91e23036cd9999a534481166e5a616a983070434d"
5496 ),
5497 msg: felt_hex!("0xa9e"),
5498 signature_input: SignatureInput {
5499 r: felt_hex!(
5500 "0x6d2e2e00dfceffd6a375db04764da249a5a1534c7584738dfe01cb3944a33ee"
5501 ),
5502 w: felt_hex!(
5503 "0x396362a34ff391372fca63f691e27753ce8f0c2271a614cbd240e1dc1596b28"
5504 )
5505 }
5506 })]
5507 );
5508 }
5509
5510 #[test]
5511 fn test_disable_trace_padding_without_proof_mode() {
5512 let program = program!();
5513 let result = CairoRunner::new(&program, LayoutName::plain, None, false, true, true);
5515 match result {
5516 Err(RunnerError::DisableTracePaddingWithoutProofMode) => { }
5517 _ => panic!("Expected DisableTracePaddingWithoutProofMode error"),
5518 }
5519 }
5520
5521 #[test]
5522 fn get_prover_input_info() {
5523 let program_content =
5524 include_bytes!("../../../../cairo_programs/proof_programs/common_signature.json");
5525 let runner = crate::cairo_run::cairo_run(
5526 program_content,
5527 &CairoRunConfig {
5528 trace_enabled: true,
5529 layout: LayoutName::all_cairo,
5530 ..Default::default()
5531 },
5532 &mut BuiltinHintProcessor::new_empty(),
5533 )
5534 .unwrap();
5535 let prover_info = runner.get_prover_input_info().unwrap();
5536 let expected_trace = vec![
5537 TraceEntry {
5538 pc: (0, 15).into(),
5539 ap: 3,
5540 fp: 3,
5541 },
5542 TraceEntry {
5543 pc: (0, 16).into(),
5544 ap: 4,
5545 fp: 3,
5546 },
5547 TraceEntry {
5548 pc: (0, 18).into(),
5549 ap: 5,
5550 fp: 3,
5551 },
5552 TraceEntry {
5553 pc: (0, 20).into(),
5554 ap: 6,
5555 fp: 3,
5556 },
5557 TraceEntry {
5558 pc: (0, 22).into(),
5559 ap: 7,
5560 fp: 3,
5561 },
5562 TraceEntry {
5563 pc: (0, 24).into(),
5564 ap: 8,
5565 fp: 3,
5566 },
5567 TraceEntry {
5568 pc: (0, 10).into(),
5569 ap: 10,
5570 fp: 10,
5571 },
5572 TraceEntry {
5573 pc: (0, 11).into(),
5574 ap: 10,
5575 fp: 10,
5576 },
5577 TraceEntry {
5578 pc: (0, 12).into(),
5579 ap: 10,
5580 fp: 10,
5581 },
5582 TraceEntry {
5583 pc: (0, 14).into(),
5584 ap: 11,
5585 fp: 10,
5586 },
5587 TraceEntry {
5588 pc: (0, 26).into(),
5589 ap: 11,
5590 fp: 3,
5591 },
5592 ];
5593 let expected_in_memory_0_3 = MaybeRelocatable::Int(13.into());
5594 let expected_in_memory_1_0 = MaybeRelocatable::RelocatableValue(Relocatable {
5595 segment_index: 2,
5596 offset: 0,
5597 });
5598 assert_eq!(prover_info.relocatable_trace, expected_trace);
5599 assert_eq!(
5600 prover_info.relocatable_memory[0][3],
5601 Some(expected_in_memory_0_3)
5602 );
5603 assert_eq!(
5604 prover_info.relocatable_memory[1][0],
5605 Some(expected_in_memory_1_0)
5606 );
5607 assert!(prover_info.public_memory_offsets.is_empty());
5608 assert_eq!(
5609 prover_info.builtins_segments,
5610 BTreeMap::from([(2, BuiltinName::ecdsa)])
5611 );
5612 }
5613
5614 #[test]
5615 fn test_output_not_builtin_segment() {
5616 let program_content =
5617 include_bytes!("../../../../cairo_programs/proof_programs/split_felt.json");
5618 let runner = crate::cairo_run::cairo_run(
5619 program_content,
5620 &CairoRunConfig {
5621 trace_enabled: true,
5622 layout: LayoutName::all_cairo,
5623 ..Default::default()
5624 },
5625 &mut BuiltinHintProcessor::new_empty(),
5626 )
5627 .unwrap();
5628 let prover_info = runner.get_prover_input_info().unwrap();
5629
5630 assert!(!prover_info
5631 .builtins_segments
5632 .values()
5633 .any(|v| *v == BuiltinName::output));
5634 }
5635}