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