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