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