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