1use crate::stdlib::{borrow::Cow, collections::HashMap, fmt, prelude::*};
2
3use crate::types::errors::math_errors::MathError;
4use crate::vm::runners::cairo_pie::CairoPieMemory;
5use crate::Felt252;
6use crate::{
7 types::relocatable::{MaybeRelocatable, Relocatable},
8 utils::from_relocatable_to_indexes,
9 vm::errors::memory_errors::MemoryError,
10};
11use bitvec::prelude as bv;
12use core::cmp::Ordering;
13use num_traits::ToPrimitive;
14
15pub struct ValidationRule(
16 #[allow(clippy::type_complexity)]
17 pub Box<dyn Fn(&Memory, Relocatable) -> Result<Vec<Relocatable>, MemoryError>>,
18);
19
20#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Debug)]
41#[repr(align(32))]
42pub(crate) struct MemoryCell([u64; 4]);
43
44impl MemoryCell {
45 pub const NONE_MASK: u64 = 1 << 63;
46 pub const ACCESS_MASK: u64 = 1 << 62;
47 pub const RELOCATABLE_MASK: u64 = 1 << 61;
48 pub const NONE: Self = Self([Self::NONE_MASK, 0, 0, 0]);
49
50 pub fn new(value: MaybeRelocatable) -> Self {
51 value.into()
52 }
53
54 pub fn is_none(&self) -> bool {
55 self.0[0] & Self::NONE_MASK == Self::NONE_MASK
56 }
57
58 pub fn is_some(&self) -> bool {
59 !self.is_none()
60 }
61
62 pub fn mark_accessed(&mut self) {
63 self.0[0] |= Self::ACCESS_MASK;
64 }
65
66 pub fn is_accessed(&self) -> bool {
67 self.0[0] & Self::ACCESS_MASK == Self::ACCESS_MASK
68 }
69
70 pub fn get_value(&self) -> Option<MaybeRelocatable> {
71 self.is_some().then(|| (*self).into())
72 }
73}
74
75impl From<MaybeRelocatable> for MemoryCell {
76 fn from(value: MaybeRelocatable) -> Self {
77 match value {
78 MaybeRelocatable::Int(x) => Self(x.to_raw()),
79 MaybeRelocatable::RelocatableValue(x) => Self([
80 Self::RELOCATABLE_MASK,
81 0,
82 usize::from_ne_bytes(x.segment_index.to_ne_bytes()) as u64,
84 x.offset as u64,
85 ]),
86 }
87 }
88}
89
90impl From<MemoryCell> for MaybeRelocatable {
91 fn from(cell: MemoryCell) -> Self {
92 debug_assert!(cell.is_some());
93 let flags = cell.0[0];
94 match flags & MemoryCell::RELOCATABLE_MASK {
95 MemoryCell::RELOCATABLE_MASK => Self::from((
96 isize::from_ne_bytes((cell.0[2] as usize).to_ne_bytes()),
98 cell.0[3] as usize,
99 )),
100 _ => {
101 let mut value = cell.0;
102 value[0] &= 0x0fffffffffffffff;
104 Self::Int(Felt252::from_raw(value))
105 }
106 }
107 }
108}
109
110pub struct AddressSet(Vec<bv::BitVec>);
111
112impl AddressSet {
113 pub(crate) fn new() -> Self {
114 Self(Vec::new())
115 }
116
117 pub(crate) fn contains(&self, addr: &Relocatable) -> bool {
118 let segment = addr.segment_index;
119 if segment.is_negative() {
120 return false;
121 }
122
123 self.0
124 .get(segment as usize)
125 .and_then(|segment| segment.get(addr.offset))
126 .map(|bit| *bit)
127 .unwrap_or(false)
128 }
129
130 pub(crate) fn extend(&mut self, addresses: &[Relocatable]) {
131 for addr in addresses {
132 let segment = addr.segment_index;
133 if segment.is_negative() {
134 continue;
135 }
136 let segment = segment as usize;
137 if segment >= self.0.len() {
138 self.0.resize(segment + 1, bv::BitVec::new());
139 }
140
141 let offset = addr.offset;
142 if offset >= self.0[segment].len() {
143 self.0[segment].resize(offset + 1, false);
144 }
145 self.0[segment].replace(offset, true);
146 }
147 }
148}
149
150#[cfg(test)]
151impl AddressSet {
152 pub(crate) fn len(&self) -> usize {
153 self.0
154 .iter()
155 .map(|segment| segment.iter().map(|bit| *bit as usize).sum::<usize>())
156 .sum()
157 }
158}
159
160pub struct Memory {
161 pub(crate) data: Vec<Vec<MemoryCell>>,
162 pub(crate) temp_data: Vec<Vec<MemoryCell>>,
168 #[cfg(not(feature = "extensive_hints"))]
171 pub(crate) relocation_rules: HashMap<usize, Relocatable>,
172 #[cfg(feature = "extensive_hints")]
173 pub(crate) relocation_rules: HashMap<usize, MaybeRelocatable>,
174 pub validated_addresses: AddressSet,
175 validation_rules: Vec<Option<ValidationRule>>,
176}
177
178impl Memory {
179 pub fn new() -> Memory {
180 Memory {
181 data: Vec::new(),
182 temp_data: Vec::new(),
183 relocation_rules: HashMap::new(),
184 validated_addresses: AddressSet::new(),
185 validation_rules: Vec::with_capacity(7),
186 }
187 }
188
189 fn get_segment(&mut self, key: Relocatable) -> Result<&mut Vec<MemoryCell>, MemoryError> {
190 let (value_index, _) = from_relocatable_to_indexes(key);
191 let data = if key.segment_index.is_negative() {
192 &mut self.temp_data
193 } else {
194 &mut self.data
195 };
196 let data_len = data.len();
197 data.get_mut(value_index)
198 .ok_or_else(|| MemoryError::UnallocatedSegment(Box::new((value_index, data_len))))
199 }
200
201 pub fn insert<V>(&mut self, key: Relocatable, val: V) -> Result<(), MemoryError>
206 where
207 MaybeRelocatable: From<V>,
208 {
209 let val = MaybeRelocatable::from(val);
210 let segment = self.get_segment(key)?;
211 let (_, value_offset) = from_relocatable_to_indexes(key);
212
213 let (len, capacity) = (segment.len(), segment.capacity());
216 if len <= value_offset {
217 let new_len = value_offset
218 .checked_add(1)
219 .ok_or(MemoryError::VecCapacityExceeded)?;
220 segment
221 .try_reserve(new_len.saturating_sub(capacity))
222 .map_err(|_| MemoryError::VecCapacityExceeded)?;
223 segment.resize(new_len, MemoryCell::NONE);
224 }
225 match segment[value_offset].get_value() {
228 None => segment[value_offset] = MemoryCell::new(val),
229 Some(current_cell) => {
230 if current_cell != val {
231 return Err(MemoryError::InconsistentMemory(Box::new((
233 key,
234 current_cell,
235 val,
236 ))));
237 }
238 }
239 };
240 self.validate_memory_cell(key)
241 }
242
243 pub(crate) fn delete_unaccessed(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
244 let (_, offset) = from_relocatable_to_indexes(addr);
245 let segment = self.get_segment(addr)?;
246
247 if offset >= segment.len() {
249 return Err(MemoryError::UnsetUnallocatedCell(addr));
250 }
251
252 if segment[offset].is_accessed() {
254 return Err(MemoryError::UnsetAccessedCell(addr));
255 }
256
257 segment[offset] = MemoryCell::NONE;
259 Ok(())
260 }
261
262 pub(crate) fn get<'a, 'b: 'a, K: 'a>(&'b self, key: &'a K) -> Option<Cow<'b, MaybeRelocatable>>
264 where
265 Relocatable: TryFrom<&'a K>,
266 {
267 let relocatable: Relocatable = key.try_into().ok()?;
268
269 let data = if relocatable.segment_index.is_negative() {
270 &self.temp_data
271 } else {
272 &self.data
273 };
274 let (i, j) = from_relocatable_to_indexes(relocatable);
275 let value = data.get(i)?.get(j)?.get_value()?;
276 Some(Cow::Owned(self.relocate_value(&value).ok()?.into_owned()))
277 }
278
279 #[cfg(not(feature = "extensive_hints"))]
281 fn relocate_address(
282 addr: Relocatable,
283 relocation_rules: &HashMap<usize, Relocatable>,
284 ) -> Result<MaybeRelocatable, MemoryError> {
285 if addr.segment_index < 0 {
286 if let Some(x) = relocation_rules.get(&(-(addr.segment_index + 1) as usize)) {
289 return Ok((*x + addr.offset)?.into());
290 }
291 }
292 Ok(addr.into())
293 }
294
295 #[cfg(feature = "extensive_hints")]
296 fn relocate_address(
297 addr: Relocatable,
298 relocation_rules: &HashMap<usize, MaybeRelocatable>,
299 ) -> Result<MaybeRelocatable, MemoryError> {
300 if addr.segment_index < 0 {
301 if let Some(x) = relocation_rules.get(&(-(addr.segment_index + 1) as usize)) {
304 return Ok(match x {
305 MaybeRelocatable::RelocatableValue(r) => (*r + addr.offset)?.into(),
306 MaybeRelocatable::Int(i) => i.into(),
307 });
308 }
309 }
310 Ok(addr.into())
311 }
312
313 #[cfg(not(feature = "extensive_hints"))]
314 fn flatten_relocation_rules(&mut self) -> Result<(), MemoryError> {
315 let keys: Vec<usize> = self.relocation_rules.keys().copied().collect();
316 let max_hops = self.relocation_rules.len().saturating_add(1);
317 for key in keys {
318 let mut dst = *self
319 .relocation_rules
320 .get(&key)
321 .expect("key taken from keys vec must exist");
322
323 let mut hops = 0;
324 while dst.segment_index < 0 {
325 let next_key = (-(dst.segment_index + 1)) as usize;
326 let next = *self
327 .relocation_rules
328 .get(&next_key)
329 .ok_or(MemoryError::UnmappedTemporarySegment(dst.segment_index))?;
330 dst = (next + dst.offset).map_err(MemoryError::Math)?;
331 hops += 1;
332 if hops > max_hops {
333 return Err(MemoryError::Relocation); }
335 }
336 self.relocation_rules.insert(key, dst);
337 }
338 Ok(())
339 }
340
341 #[cfg(feature = "extensive_hints")]
342 fn flatten_relocation_rules(&mut self) -> Result<(), MemoryError> {
343 let keys: Vec<usize> = self.relocation_rules.keys().copied().collect();
344 let max_hops = self.relocation_rules.len().saturating_add(1);
345 for key in keys {
346 let mut dst = self
347 .relocation_rules
348 .get(&key)
349 .expect("key taken from keys vec must exist")
350 .clone();
351
352 let mut hops = 0;
353 loop {
354 match dst {
355 MaybeRelocatable::RelocatableValue(relocatable)
356 if relocatable.segment_index < 0 =>
357 {
358 let next_key = (-(relocatable.segment_index + 1)) as usize;
359 let next = self
360 .relocation_rules
361 .get(&next_key)
362 .ok_or(MemoryError::UnmappedTemporarySegment(
363 relocatable.segment_index,
364 ))?
365 .clone();
366
367 match next {
368 MaybeRelocatable::RelocatableValue(next_relocatable) => {
369 dst = MaybeRelocatable::RelocatableValue(
370 (next_relocatable + relocatable.offset)
371 .map_err(MemoryError::Math)?,
372 );
373 }
374 MaybeRelocatable::Int(i) => {
375 if relocatable.offset != 0 {
376 return Err(MemoryError::NonZeroOffset(relocatable.offset));
377 }
378 dst = MaybeRelocatable::Int(i);
379 }
380 }
381 }
382 _ => break,
383 }
384 hops += 1;
385 if hops > max_hops {
386 return Err(MemoryError::Relocation);
387 }
388 }
389 self.relocation_rules.insert(key, dst);
390 }
391 Ok(())
392 }
393
394 pub fn relocate_memory(&mut self) -> Result<(), MemoryError> {
396 if self.relocation_rules.is_empty() || self.temp_data.is_empty() {
397 return Ok(());
398 }
399
400 self.flatten_relocation_rules()?;
402
403 for segment in self.data.iter_mut().chain(self.temp_data.iter_mut()) {
405 for cell in segment.iter_mut() {
406 let value = cell.get_value();
407 match value {
408 Some(MaybeRelocatable::RelocatableValue(addr)) if addr.segment_index < 0 => {
409 let mut new_cell = MemoryCell::new(Memory::relocate_address(
410 addr,
411 &self.relocation_rules,
412 )?);
413 if cell.is_accessed() {
414 new_cell.mark_accessed();
415 }
416 *cell = new_cell;
417 }
418 _ => {}
419 }
420 }
421 }
422 for index in (0..self.temp_data.len()).rev() {
424 if let Some(base_addr) = self.relocation_rules.get(&index) {
425 let data_segment = self.temp_data.remove(index);
426
427 #[cfg(feature = "extensive_hints")]
428 let base_addr = match base_addr {
429 MaybeRelocatable::RelocatableValue(addr) => addr,
430 MaybeRelocatable::Int(_) => {
431 continue;
432 }
433 };
434
435 let mut addr = *base_addr;
437 if let Some(s) = self.data.get_mut(addr.segment_index as usize) {
438 s.reserve_exact(data_segment.len())
439 }
440 for cell in data_segment {
441 if let Some(v) = cell.get_value() {
442 self.insert(addr, v)?;
444 if cell.is_accessed() {
446 self.mark_as_accessed(addr)
447 }
448 }
449 addr = (addr + 1)?;
450 }
451 }
452 }
453 self.relocation_rules.clear();
454 Ok(())
455 }
456
457 #[cfg(not(feature = "extensive_hints"))]
468 pub(crate) fn add_relocation_rule(
469 &mut self,
470 src_ptr: Relocatable,
471 dst_ptr: Relocatable,
472 ) -> Result<(), MemoryError> {
473 if src_ptr.segment_index >= 0 {
474 return Err(MemoryError::AddressNotInTemporarySegment(
475 src_ptr.segment_index,
476 ));
477 }
478 if src_ptr.offset != 0 {
479 return Err(MemoryError::NonZeroOffset(src_ptr.offset));
480 }
481
482 let segment_index = -(src_ptr.segment_index + 1) as usize;
485 if self.relocation_rules.contains_key(&segment_index) {
486 return Err(MemoryError::DuplicatedRelocation(src_ptr.segment_index));
487 }
488
489 self.relocation_rules.insert(segment_index, dst_ptr);
490 Ok(())
491 }
492 #[cfg(feature = "extensive_hints")]
493 pub(crate) fn add_relocation_rule(
494 &mut self,
495 src_ptr: Relocatable,
496 dst: MaybeRelocatable,
497 ) -> Result<(), MemoryError> {
498 if src_ptr.segment_index >= 0 {
499 return Err(MemoryError::AddressNotInTemporarySegment(
500 src_ptr.segment_index,
501 ));
502 }
503 if src_ptr.offset != 0 {
504 return Err(MemoryError::NonZeroOffset(src_ptr.offset));
505 }
506
507 let segment_index = -(src_ptr.segment_index + 1) as usize;
510 if self.relocation_rules.contains_key(&segment_index) {
511 return Err(MemoryError::DuplicatedRelocation(src_ptr.segment_index));
512 }
513
514 self.relocation_rules.insert(segment_index, dst);
515 Ok(())
516 }
517
518 pub fn get_integer(&'_ self, key: Relocatable) -> Result<Cow<'_, Felt252>, MemoryError> {
521 match self
522 .get(&key)
523 .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
524 {
525 Cow::Borrowed(MaybeRelocatable::Int(int)) => Ok(Cow::Borrowed(int)),
526 Cow::Owned(MaybeRelocatable::Int(int)) => Ok(Cow::Owned(int)),
527 _ => Err(MemoryError::ExpectedInteger(Box::new(key))),
528 }
529 }
530
531 pub fn get_u32(&self, key: Relocatable) -> Result<u32, MemoryError> {
534 let felt = self.get_integer(key)?.into_owned();
535 felt.to_u32()
536 .ok_or_else(|| MemoryError::Math(MathError::Felt252ToU32Conversion(Box::new(felt))))
537 }
538
539 pub fn get_usize(&self, key: Relocatable) -> Result<usize, MemoryError> {
542 let felt = self.get_integer(key)?.into_owned();
543 felt.to_usize()
544 .ok_or_else(|| MemoryError::Math(MathError::Felt252ToUsizeConversion(Box::new(felt))))
545 }
546
547 pub fn get_relocatable(&self, key: Relocatable) -> Result<Relocatable, MemoryError> {
550 match self
551 .get(&key)
552 .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
553 {
554 Cow::Borrowed(MaybeRelocatable::RelocatableValue(rel)) => Ok(*rel),
555 Cow::Owned(MaybeRelocatable::RelocatableValue(rel)) => Ok(rel),
556 _ => Err(MemoryError::ExpectedRelocatable(Box::new(key))),
557 }
558 }
559
560 pub fn get_maybe_relocatable(&self, key: Relocatable) -> Result<MaybeRelocatable, MemoryError> {
563 match self
564 .get(&key)
565 .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
566 {
567 Cow::Borrowed(maybe_rel) => Ok(maybe_rel.clone()),
569 Cow::Owned(maybe_rel) => Ok(maybe_rel),
570 }
571 }
572
573 pub fn insert_value<T: Into<MaybeRelocatable>>(
576 &mut self,
577 key: Relocatable,
578 val: T,
579 ) -> Result<(), MemoryError> {
580 self.insert(key, &val.into())
581 }
582
583 pub fn add_validation_rule(&mut self, segment_index: usize, rule: ValidationRule) {
584 if segment_index >= self.validation_rules.len() {
585 self.validation_rules
587 .resize_with(segment_index + 1, || None);
588 }
589 self.validation_rules.insert(segment_index, Some(rule));
590 }
591
592 fn validate_memory_cell(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
593 if let Some(Some(rule)) = addr
594 .segment_index
595 .to_usize()
596 .and_then(|x| self.validation_rules.get(x))
597 {
598 if !self.validated_addresses.contains(&addr) {
599 self.validated_addresses
600 .extend(rule.0(self, addr)?.as_slice());
601 }
602 }
603 Ok(())
604 }
605
606 pub fn validate_existing_memory(&mut self) -> Result<(), MemoryError> {
608 for (index, rule) in self.validation_rules.iter().enumerate() {
609 if index >= self.data.len() {
610 continue;
611 }
612 let Some(rule) = rule else {
613 continue;
614 };
615 for offset in 0..self.data[index].len() {
616 let addr = Relocatable::from((index as isize, offset));
617 if !self.validated_addresses.contains(&addr) {
618 self.validated_addresses
619 .extend(rule.0(self, addr)?.as_slice());
620 }
621 }
622 }
623 Ok(())
624 }
625
626 pub(crate) fn memcmp(
636 &self,
637 lhs: Relocatable,
638 rhs: Relocatable,
639 len: usize,
640 ) -> (Ordering, usize) {
641 let get_segment = |idx: isize| {
642 if idx.is_negative() {
643 self.temp_data.get(-(idx + 1) as usize)
644 } else {
645 self.data.get(idx as usize)
646 }
647 };
648 match (
649 get_segment(lhs.segment_index),
650 get_segment(rhs.segment_index),
651 ) {
652 (None, None) => {
653 return (Ordering::Equal, 0);
654 }
655 (Some(_), None) => {
656 return (Ordering::Greater, 0);
657 }
658 (None, Some(_)) => {
659 return (Ordering::Less, 0);
660 }
661 (Some(lhs_segment), Some(rhs_segment)) => {
662 let (lhs_start, rhs_start) = (lhs.offset, rhs.offset);
663 for i in 0..len {
664 let (lhs, rhs) = (
665 lhs_segment.get(lhs_start + i),
666 rhs_segment.get(rhs_start + i),
667 );
668 let ord = lhs.cmp(&rhs);
669 if ord == Ordering::Equal {
670 continue;
671 }
672 return (ord, i);
673 }
674 }
675 };
676 (Ordering::Equal, len)
677 }
678
679 pub(crate) fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
688 if lhs == rhs {
689 return true;
690 }
691 let get_segment = |idx: isize| {
692 if idx.is_negative() {
693 self.temp_data.get(-(idx + 1) as usize)
694 } else {
695 self.data.get(idx as usize)
696 }
697 };
698 match (
699 get_segment(lhs.segment_index).and_then(|s| s.get(lhs.offset..)),
700 get_segment(rhs.segment_index).and_then(|s| s.get(rhs.offset..)),
701 ) {
702 (Some(lhs), Some(rhs)) => {
703 let (lhs_len, rhs_len) = (lhs.len().min(len), rhs.len().min(len));
704 if lhs_len != rhs_len {
705 return false;
706 }
707 lhs[..lhs_len] == rhs[..rhs_len]
708 }
709 (None, None) => true,
710 _ => false,
711 }
712 }
713
714 pub fn get_range(
717 &'_ self,
718 addr: Relocatable,
719 size: usize,
720 ) -> Vec<Option<Cow<'_, MaybeRelocatable>>> {
721 let mut values = Vec::new();
722
723 for i in 0..size {
724 values.push((addr + i).ok().and_then(|x| self.get(&x)));
725 }
726
727 values
728 }
729
730 pub fn get_continuous_range(
733 &self,
734 addr: Relocatable,
735 size: usize,
736 ) -> Result<Vec<MaybeRelocatable>, MemoryError> {
737 let mut values = Vec::with_capacity(size);
738
739 for i in 0..size {
740 values.push(match self.get(&(addr + i)?) {
741 Some(elem) => elem.into_owned(),
742 None => return Err(MemoryError::GetRangeMemoryGap(Box::new((addr, size)))),
743 });
744 }
745
746 Ok(values)
747 }
748
749 pub fn get_integer_range(
753 &'_ self,
754 addr: Relocatable,
755 size: usize,
756 ) -> Result<Vec<Cow<'_, Felt252>>, MemoryError> {
757 let mut values = Vec::new();
758
759 for i in 0..size {
760 values.push(self.get_integer((addr + i)?)?);
761 }
762
763 Ok(values)
764 }
765
766 pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result<Vec<u32>, MemoryError> {
769 let mut values = Vec::new();
770
771 for i in 0..size {
772 values.push(self.get_u32((addr + i)?)?);
773 }
774
775 Ok(values)
776 }
777
778 fn get_cell(&self, addr: Relocatable) -> Option<&MemoryCell> {
779 let (i, j) = from_relocatable_to_indexes(addr);
780 let data = if addr.segment_index < 0 {
781 &self.temp_data
782 } else {
783 &self.data
784 };
785 data.get(i)?.get(j)
786 }
787
788 #[cfg(test)]
789 pub(crate) fn get_cell_for_testing(&self, addr: Relocatable) -> Option<&MemoryCell> {
790 self.get_cell(addr)
791 }
792
793 pub fn is_accessed(&self, addr: &Relocatable) -> Result<bool, MemoryError> {
794 Ok(self
795 .get_cell(*addr)
796 .ok_or(MemoryError::UnknownMemoryCell(Box::new(*addr)))?
797 .is_accessed())
798 }
799
800 pub fn mark_as_accessed(&mut self, addr: Relocatable) {
801 let (i, j) = from_relocatable_to_indexes(addr);
802 let data = if addr.segment_index < 0 {
803 &mut self.temp_data
804 } else {
805 &mut self.data
806 };
807 let cell = data.get_mut(i).and_then(|x| x.get_mut(j));
808 if let Some(cell) = cell {
809 cell.mark_accessed()
810 }
811 }
812
813 pub fn get_amount_of_accessed_addresses_for_segment(
814 &self,
815 segment_index: usize,
816 ) -> Option<usize> {
817 let segment = self.data.get(segment_index)?;
818 Some(
819 segment
820 .iter()
821 .filter(|x| x.is_some() && x.is_accessed())
822 .count(),
823 )
824 }
825
826 pub(crate) fn insert_as_accessed<V>(
829 &mut self,
830 key: Relocatable,
831 val: V,
832 ) -> Result<(), MemoryError>
833 where
834 MaybeRelocatable: From<V>,
835 {
836 self.insert(key, val)?;
837 self.mark_as_accessed(key);
838 Ok(())
839 }
840}
841
842impl From<&Memory> for CairoPieMemory {
843 fn from(mem: &Memory) -> CairoPieMemory {
844 let mut pie_memory = Vec::default();
845 for (i, segment) in mem.data.iter().enumerate() {
846 for (j, cell) in segment.iter().enumerate() {
847 if let Some(value) = cell.get_value() {
848 pie_memory.push(((i, j), value))
849 }
850 }
851 }
852 CairoPieMemory(pie_memory)
853 }
854}
855
856impl fmt::Display for Memory {
857 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
858 for (i, segment) in self.temp_data.iter().enumerate() {
859 for (j, cell) in segment.iter().enumerate() {
860 if let Some(elem) = cell.get_value() {
861 let temp_segment = i + 1;
862 writeln!(f, "(-{temp_segment},{j}) : {elem}")?;
863 }
864 }
865 }
866 for (i, segment) in self.data.iter().enumerate() {
867 for (j, cell) in segment.iter().enumerate() {
868 if let Some(elem) = cell.get_value() {
869 writeln!(f, "({i},{j}) : {elem}")?;
870 }
871 }
872 }
873 Ok(())
874 }
875}
876
877pub(crate) trait RelocateValue<'a, Input: 'a, Output: 'a> {
879 fn relocate_value(&self, value: Input) -> Result<Output, MemoryError>;
880}
881
882#[cfg(not(feature = "extensive_hints"))]
883impl RelocateValue<'_, Relocatable, Relocatable> for Memory {
884 fn relocate_value(&self, addr: Relocatable) -> Result<Relocatable, MemoryError> {
885 if addr.segment_index < 0 {
886 if let Some(x) = self
889 .relocation_rules
890 .get(&(-(addr.segment_index + 1) as usize))
891 {
892 return (*x + addr.offset).map_err(MemoryError::Math);
893 }
894 }
895 Ok(addr)
896 }
897}
898#[cfg(feature = "extensive_hints")]
899impl RelocateValue<'_, Relocatable, MaybeRelocatable> for Memory {
900 fn relocate_value(&self, addr: Relocatable) -> Result<MaybeRelocatable, MemoryError> {
901 if addr.segment_index < 0 {
902 if let Some(x) = self
905 .relocation_rules
906 .get(&(-(addr.segment_index + 1) as usize))
907 {
908 return Ok(match x {
909 MaybeRelocatable::RelocatableValue(r) => {
910 (*r + addr.offset).map_err(MemoryError::Math)?.into()
911 }
912 MaybeRelocatable::Int(i) => i.into(),
913 });
914 }
915 }
916 Ok(addr.into())
917 }
918}
919
920impl<'a> RelocateValue<'a, &'a Felt252, &'a Felt252> for Memory {
921 fn relocate_value(&self, value: &'a Felt252) -> Result<&'a Felt252, MemoryError> {
922 Ok(value)
923 }
924}
925
926impl<'a> RelocateValue<'a, &'a MaybeRelocatable, Cow<'a, MaybeRelocatable>> for Memory {
927 fn relocate_value(
928 &self,
929 value: &'a MaybeRelocatable,
930 ) -> Result<Cow<'a, MaybeRelocatable>, MemoryError> {
931 Ok(match value {
932 MaybeRelocatable::Int(_) => Cow::Borrowed(value),
933 MaybeRelocatable::RelocatableValue(addr) => {
934 #[cfg(not(feature = "extensive_hints"))]
935 let v = self.relocate_value(*addr)?.into();
936 #[cfg(feature = "extensive_hints")]
937 let v = self.relocate_value(*addr)?;
938
939 Cow::Owned(v)
940 }
941 })
942 }
943}
944
945impl Default for Memory {
946 fn default() -> Self {
947 Self::new()
948 }
949}
950
951#[cfg(test)]
952mod memory_tests {
953
954 use super::*;
955 use crate::{
956 felt_hex, relocatable,
957 utils::test_utils::*,
958 vm::{
959 runners::builtin_runner::{
960 RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_STANDARD,
961 },
962 vm_memory::memory_segments::MemorySegmentManager,
963 },
964 };
965 use assert_matches::assert_matches;
966
967 use crate::vm::errors::memory_errors::MemoryError;
968
969 use crate::utils::test_utils::memory_from_memory;
970 use crate::utils::test_utils::memory_inner;
971
972 #[cfg(target_arch = "wasm32")]
973 use wasm_bindgen_test::*;
974
975 #[test]
976 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
977 fn insert_and_get_succesful() {
978 let key = Relocatable::from((0, 0));
979 let val = MaybeRelocatable::from(Felt252::from(5_u64));
980 let mut memory = Memory::new();
981 memory.data.push(Vec::new());
982 memory.insert(key, &val).unwrap();
983 assert_eq!(
984 memory.get(&key).unwrap().as_ref(),
985 &MaybeRelocatable::from(Felt252::from(5_u64))
986 );
987 }
988
989 #[test]
990 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
991 fn get_valuef_from_temp_segment() {
992 let mut memory = Memory::new();
993 memory.temp_data = vec![vec![
994 MemoryCell::NONE,
995 MemoryCell::NONE,
996 MemoryCell::new(mayberelocatable!(8)),
997 ]];
998 assert_eq!(
999 memory.get(&mayberelocatable!(-1, 2)).unwrap().as_ref(),
1000 &mayberelocatable!(8),
1001 );
1002 }
1003
1004 #[test]
1005 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1006 fn insert_value_in_temp_segment() {
1007 let key = Relocatable::from((-1, 3));
1008 let val = MaybeRelocatable::from(Felt252::from(8_u64));
1009 let mut memory = Memory::new();
1010 memory.temp_data.push(Vec::new());
1011 memory.insert(key, &val).unwrap();
1012 assert_eq!(
1013 memory.temp_data[0][3],
1014 MemoryCell::new(MaybeRelocatable::from(Felt252::from(8_u64)))
1015 );
1016 }
1017
1018 #[test]
1019 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1020 fn insert_and_get_from_temp_segment_succesful() {
1021 let key = Relocatable::from((-1, 0));
1022 let val = MaybeRelocatable::from(Felt252::from(5_u64));
1023 let mut memory = Memory::new();
1024 memory.temp_data.push(Vec::new());
1025 memory.insert(key, &val).unwrap();
1026 assert_eq!(
1027 memory.get(&key).unwrap().as_ref(),
1028 &MaybeRelocatable::from(Felt252::from(5_u64)),
1029 );
1030 }
1031
1032 #[test]
1033 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1034 fn insert_and_get_from_temp_segment_failed() {
1035 let key = relocatable!(-1, 1);
1036 let mut memory = Memory::new();
1037 memory.temp_data = vec![vec![
1038 MemoryCell::NONE,
1039 MemoryCell::new(mayberelocatable!(8)),
1040 ]];
1041 assert_eq!(
1042 memory.insert(key, &mayberelocatable!(5)),
1043 Err(MemoryError::InconsistentMemory(Box::new((
1044 relocatable!(-1, 1),
1045 mayberelocatable!(8),
1046 mayberelocatable!(5)
1047 ))))
1048 );
1049 }
1050
1051 #[test]
1052 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1053 fn get_non_allocated_memory() {
1054 let key = Relocatable::from((0, 0));
1055 let memory = Memory::new();
1056 assert_eq!(memory.get(&key), None);
1057 }
1058
1059 #[test]
1060 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1061 fn get_non_existant_element() {
1062 let key = Relocatable::from((0, 0));
1063 let memory = Memory::new();
1064 assert_eq!(memory.get(&key), None);
1065 }
1066
1067 #[test]
1068 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1069 fn insert_non_allocated_memory() {
1070 let key = Relocatable::from((0, 0));
1071 let val = MaybeRelocatable::from(Felt252::from(5_u64));
1072 let mut memory = Memory::new();
1073 let error = memory.insert(key, &val);
1074 assert_eq!(
1075 error,
1076 Err(MemoryError::UnallocatedSegment(Box::new((0, 0))))
1077 );
1078 }
1079
1080 #[test]
1081 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1082 fn insert_inconsistent_memory() {
1083 let key = Relocatable::from((0, 0));
1084 let val_a = MaybeRelocatable::from(Felt252::from(5_u64));
1085 let val_b = MaybeRelocatable::from(Felt252::from(6_u64));
1086 let mut memory = Memory::new();
1087 memory.data.push(Vec::new());
1088 memory
1089 .insert(key, &val_a)
1090 .expect("Unexpected memory insert fail");
1091 let error = memory.insert(key, &val_b);
1092 assert_eq!(
1093 error,
1094 Err(MemoryError::InconsistentMemory(Box::new((
1095 key, val_a, val_b
1096 ))))
1097 );
1098 }
1099
1100 #[test]
1101 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1102 fn insert_non_contiguous_element() {
1103 let key_a = Relocatable::from((0, 0));
1104 let key_b = Relocatable::from((0, 2));
1105 let val = MaybeRelocatable::from(Felt252::from(5_u64));
1106 let mut memory = Memory::new();
1107 memory.data.push(Vec::new());
1108 memory.insert(key_a, &val).unwrap();
1109 memory.insert(key_b, &val).unwrap();
1110 assert_eq!(memory.get(&key_b).unwrap().as_ref(), &val);
1111 }
1112
1113 #[test]
1114 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1115 fn insert_non_contiguous_element_memory_gaps_none() {
1116 let key_a = Relocatable::from((0, 0));
1117 let key_b = Relocatable::from((0, 5));
1118 let val = MaybeRelocatable::from(Felt252::from(5_u64));
1119 let mut memory = Memory::new();
1120 memory.data.push(Vec::new());
1121 memory.insert(key_a, &val).unwrap();
1122 memory.insert(key_b, &val).unwrap();
1123 assert_eq!(memory.get(&key_b).unwrap().as_ref(), &val);
1124 assert_eq!(memory.get(&MaybeRelocatable::from((0, 1))), None);
1125 assert_eq!(memory.get(&MaybeRelocatable::from((0, 2))), None);
1126 assert_eq!(memory.get(&MaybeRelocatable::from((0, 3))), None);
1127 assert_eq!(memory.get(&MaybeRelocatable::from((0, 4))), None);
1128 }
1129
1130 #[test]
1131 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1132 fn validate_existing_memory_for_range_check_within_bounds() {
1133 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1134 let mut segments = MemorySegmentManager::new();
1135 builtin.initialize_segments(&mut segments);
1136 builtin.add_validation_rule(&mut segments.memory);
1137 for _ in 0..3 {
1138 segments.add();
1139 }
1140
1141 segments
1142 .memory
1143 .insert(
1144 Relocatable::from((0, 0)),
1145 &MaybeRelocatable::from(Felt252::from(45_u64)),
1146 )
1147 .unwrap();
1148 segments.memory.validate_existing_memory().unwrap();
1149 assert!(segments
1150 .memory
1151 .validated_addresses
1152 .contains(&Relocatable::from((0, 0))));
1153 }
1154
1155 #[test]
1156 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1157 fn validate_existing_memory_for_range_check_outside_bounds() {
1158 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1159 let mut segments = MemorySegmentManager::new();
1160 segments.add();
1161 builtin.initialize_segments(&mut segments);
1162 segments
1163 .memory
1164 .insert(
1165 Relocatable::from((1, 0)),
1166 &MaybeRelocatable::from(Felt252::from(-10)),
1167 )
1168 .unwrap();
1169 builtin.add_validation_rule(&mut segments.memory);
1170 let error = segments.memory.validate_existing_memory();
1171 assert_eq!(
1172 error,
1173 Err(MemoryError::RangeCheckNumOutOfBounds(Box::new((
1174 Felt252::from(-10),
1175 Felt252::TWO.pow(128_u128)
1176 ))))
1177 );
1178 }
1179
1180 #[test]
1181 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1182 fn validate_existing_memory_for_invalid_signature() {
1183 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
1184 let mut segments = MemorySegmentManager::new();
1185 builtin.initialize_segments(&mut segments);
1186 segments.memory = memory![
1187 (
1188 (0, 0),
1189 (
1190 "874739451078007766457464989774322083649278607533249481151382481072868806602",
1191 10
1192 )
1193 ),
1194 (
1195 (0, 1),
1196 (
1197 "-1472574760335685482768423018116732869320670550222259018541069375211356613248",
1198 10
1199 )
1200 )
1201 ];
1202 builtin.add_validation_rule(&mut segments.memory);
1203 let error = segments.memory.validate_existing_memory();
1204 assert_eq!(
1205 error,
1206 Err(MemoryError::SignatureNotFound(Box::new((0, 0).into())))
1207 );
1208 }
1209
1210 #[test]
1211 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1212 fn validate_existing_memory_for_valid_signature() {
1213 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
1214
1215 let signature_r =
1216 felt_hex!("0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20");
1217 let signature_s =
1218 felt_hex!("0x405c3191ab3883ef2b763af35bc5f5d15b3b4e99461d70e84c654a351a7c81b");
1219
1220 builtin
1221 .add_signature(Relocatable::from((1, 0)), &(signature_r, signature_s))
1222 .unwrap();
1223
1224 let mut segments = MemorySegmentManager::new();
1225
1226 segments.memory = memory![
1227 (
1228 (1, 0),
1229 (
1230 "874739451078007766457464989774322083649278607533249481151382481072868806602",
1231 10
1232 )
1233 ),
1234 ((1, 1), 2)
1235 ];
1236
1237 builtin.initialize_segments(&mut segments);
1238
1239 builtin.add_validation_rule(&mut segments.memory);
1240
1241 let result = segments.memory.validate_existing_memory();
1242
1243 assert_eq!(result, Ok(()))
1244 }
1245
1246 #[test]
1247 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1248 fn validate_existing_memory_for_range_check_relocatable_value() {
1249 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1250 let mut segments = MemorySegmentManager::new();
1251 builtin.initialize_segments(&mut segments);
1252 segments.memory = memory![((0, 0), (0, 4))];
1253 builtin.add_validation_rule(&mut segments.memory);
1254 let error = segments.memory.validate_existing_memory();
1255 assert_eq!(
1256 error,
1257 Err(MemoryError::RangeCheckFoundNonInt(Box::new(relocatable!(
1258 0, 0
1259 ))))
1260 );
1261 }
1262
1263 #[test]
1264 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1265 fn validate_existing_memory_for_range_check_out_of_bounds_diff_segment() {
1266 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1267 let mut segments = MemorySegmentManager::new();
1268 segments.memory = Memory::new();
1269 segments.add();
1270 builtin.initialize_segments(&mut segments);
1271 segments
1272 .memory
1273 .insert(
1274 Relocatable::from((0, 0)),
1275 &MaybeRelocatable::from(Felt252::from(-45_i128)),
1276 )
1277 .unwrap();
1278 builtin.add_validation_rule(&mut segments.memory);
1279 assert_eq!(segments.memory.validate_existing_memory(), Ok(()));
1280 }
1281
1282 #[test]
1283 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1284 fn get_integer_valid() {
1285 let memory = memory![((0, 0), 10)];
1286 assert_eq!(
1287 memory
1288 .get_integer(Relocatable::from((0, 0)))
1289 .unwrap()
1290 .as_ref(),
1291 &Felt252::from(10)
1292 );
1293 }
1294
1295 #[test]
1296 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1297 fn get_integer_invalid_expected_integer() {
1298 let mut segments = MemorySegmentManager::new();
1299 segments.add();
1300 segments
1301 .memory
1302 .insert(Relocatable::from((0, 0)), &MaybeRelocatable::from((0, 10)))
1303 .unwrap();
1304 assert_matches!(
1305 segments.memory.get_integer(Relocatable::from((0, 0))),
1306 Err(MemoryError::ExpectedInteger(
1307 bx
1308 )) if *bx == Relocatable::from((0, 0))
1309 );
1310 }
1311
1312 #[test]
1313 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1314 fn get_u32_too_big() {
1315 let mut segments = MemorySegmentManager::new();
1316 segments.add();
1317 segments
1318 .memory
1319 .insert(Relocatable::from((0, 0)), &Felt252::from(1_u64 << 32))
1320 .unwrap();
1321 assert_matches!(
1322 segments.memory.get_u32(Relocatable::from((0, 0))),
1323 Err(MemoryError::Math(MathError::Felt252ToU32Conversion(
1324 bx
1325 ))) if *bx == Felt252::from(1_u64 << 32)
1326 );
1327 }
1328
1329 #[test]
1330 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1331 fn get_maybe_relocatable_valid_relocatable() {
1332 let memory = memory![((0, 0), (1, 0))];
1333 assert_eq!(
1334 memory
1335 .get_maybe_relocatable(Relocatable::from((0, 0)))
1336 .unwrap(),
1337 Relocatable::from((1, 0)).into()
1338 );
1339 }
1340
1341 #[test]
1342 fn get_maybe_relocatable_valid_integer() {
1343 let memory = memory![((0, 0), 10)];
1344 assert_eq!(
1345 memory
1346 .get_maybe_relocatable(Relocatable::from((0, 0)))
1347 .unwrap(),
1348 10.into()
1349 );
1350 }
1351
1352 #[test]
1353 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1354 fn default_memory() {
1355 let mem: Memory = Default::default();
1356 assert_eq!(mem.data.len(), 0);
1357 }
1358
1359 #[test]
1360 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1361 fn insert_and_get_temporary_succesful() {
1362 let mut memory = Memory::new();
1363 memory.temp_data.push(Vec::new());
1364
1365 let key = Relocatable::from((-1, 0));
1366 let val = MaybeRelocatable::from(Felt252::from(5));
1367 memory.insert(key, &val).unwrap();
1368
1369 assert_eq!(memory.get(&key).unwrap().as_ref(), &val);
1370 }
1371
1372 #[test]
1373 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1374 fn add_relocation_rule() {
1375 let mut memory = Memory::new();
1376
1377 assert_eq!(
1378 memory.add_relocation_rule((-1, 0).into(), (1, 2).into()),
1379 Ok(()),
1380 );
1381 assert_eq!(
1382 memory.add_relocation_rule((-2, 0).into(), (-1, 1).into()),
1383 Ok(()),
1384 );
1385 assert_eq!(
1386 memory.add_relocation_rule((5, 0).into(), (0, 0).into()),
1387 Err(MemoryError::AddressNotInTemporarySegment(5)),
1388 );
1389 assert_eq!(
1390 memory.add_relocation_rule((-3, 6).into(), (0, 0).into()),
1391 Err(MemoryError::NonZeroOffset(6)),
1392 );
1393 assert_eq!(
1394 memory.add_relocation_rule((-1, 0).into(), (0, 0).into()),
1395 Err(MemoryError::DuplicatedRelocation(-1)),
1396 );
1397 }
1398
1399 #[test]
1400 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1401 fn relocate_value_bigint() {
1402 let mut memory = Memory::new();
1403 memory
1404 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1405 .unwrap();
1406 memory
1407 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1408 .unwrap();
1409
1410 assert_eq!(
1412 memory
1413 .relocate_value(&MaybeRelocatable::Int(Felt252::from(0)))
1414 .unwrap(),
1415 Cow::Owned(MaybeRelocatable::Int(Felt252::from(0))),
1416 );
1417 }
1418
1419 #[test]
1420 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1421 fn relocate_value_mayberelocatable() {
1422 let mut memory = Memory::new();
1423 memory
1424 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1425 .unwrap();
1426 memory
1427 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1428 .unwrap();
1429
1430 assert_eq!(
1432 memory
1433 .relocate_value(&MaybeRelocatable::RelocatableValue((0, 0).into()))
1434 .unwrap(),
1435 Cow::Owned(MaybeRelocatable::RelocatableValue((0, 0).into())),
1436 );
1437 assert_eq!(
1438 memory
1439 .relocate_value(&MaybeRelocatable::RelocatableValue((5, 0).into()))
1440 .unwrap(),
1441 Cow::Owned(MaybeRelocatable::RelocatableValue((5, 0).into())),
1442 );
1443 }
1444
1445 #[test]
1446 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1447 fn relocate_value_mayberelocatable_temporary_segment_no_rules() {
1448 let mut memory = Memory::new();
1449 memory
1450 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1451 .unwrap();
1452 memory
1453 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1454 .unwrap();
1455
1456 assert_eq!(
1459 memory
1460 .relocate_value(&MaybeRelocatable::RelocatableValue((-5, 0).into()))
1461 .unwrap(),
1462 Cow::Owned(MaybeRelocatable::RelocatableValue((-5, 0).into())),
1463 );
1464 }
1465
1466 #[test]
1467 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1468 fn relocate_value_mayberelocatable_temporary_segment_rules() {
1469 let mut memory = Memory::new();
1470 memory
1471 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1472 .unwrap();
1473 memory
1474 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1475 .unwrap();
1476
1477 assert_eq!(
1480 memory
1481 .relocate_value(&MaybeRelocatable::RelocatableValue((-1, 0).into()))
1482 .unwrap(),
1483 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 0).into())),
1484 );
1485 assert_eq!(
1486 memory
1487 .relocate_value(&MaybeRelocatable::RelocatableValue((-2, 0).into()))
1488 .unwrap(),
1489 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 2).into())),
1490 );
1491 assert_eq!(
1492 memory
1493 .relocate_value(&MaybeRelocatable::RelocatableValue((-1, 5).into()))
1494 .unwrap(),
1495 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 5).into())),
1496 );
1497 assert_eq!(
1498 memory
1499 .relocate_value(&MaybeRelocatable::RelocatableValue((-2, 5).into()))
1500 .unwrap(),
1501 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 7).into())),
1502 );
1503 }
1504
1505 #[test]
1506 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1507 fn get_range_for_continuous_memory() {
1508 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
1509
1510 let value1 = MaybeRelocatable::from(Felt252::from(2));
1511 let value2 = MaybeRelocatable::from(Felt252::from(3));
1512 let value3 = MaybeRelocatable::from(Felt252::from(4));
1513
1514 let expected_vec = vec![
1515 Some(Cow::Borrowed(&value1)),
1516 Some(Cow::Borrowed(&value2)),
1517 Some(Cow::Borrowed(&value3)),
1518 ];
1519 assert_eq!(memory.get_range(Relocatable::from((1, 0)), 3), expected_vec);
1520 }
1521
1522 #[test]
1523 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1524 fn get_range_for_non_continuous_memory() {
1525 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
1526
1527 let value1 = MaybeRelocatable::from(Felt252::from(2));
1528 let value2 = MaybeRelocatable::from(Felt252::from(3));
1529 let value3 = MaybeRelocatable::from(Felt252::from(4));
1530
1531 let expected_vec = vec![
1532 Some(Cow::Borrowed(&value1)),
1533 Some(Cow::Borrowed(&value2)),
1534 None,
1535 Some(Cow::Borrowed(&value3)),
1536 ];
1537 assert_eq!(memory.get_range(Relocatable::from((1, 0)), 4), expected_vec);
1538 }
1539
1540 #[test]
1541 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1542 fn get_continuous_range_for_continuous_memory() {
1543 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
1544
1545 let value1 = MaybeRelocatable::from(Felt252::from(2));
1546 let value2 = MaybeRelocatable::from(Felt252::from(3));
1547 let value3 = MaybeRelocatable::from(Felt252::from(4));
1548
1549 let expected_vec = vec![value1, value2, value3];
1550 assert_eq!(
1551 memory.get_continuous_range(Relocatable::from((1, 0)), 3),
1552 Ok(expected_vec)
1553 );
1554 }
1555
1556 #[test]
1557 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1558 fn get_continuous_range_for_non_continuous_memory() {
1559 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
1560
1561 assert_eq!(
1562 memory.get_continuous_range(Relocatable::from((1, 0)), 3),
1563 Err(MemoryError::GetRangeMemoryGap(Box::new(((1, 0).into(), 3))))
1564 );
1565 }
1566
1567 #[test]
1568 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1569 fn get_u32_range_ok() {
1570 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)];
1571 let expected_vector = vec![1, 4294967295];
1572 assert_eq!(memory.get_u32_range((0, 1).into(), 2), Ok(expected_vector));
1573 }
1574
1575 #[test]
1576 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1577 fn get_u32_range_relocatable() {
1578 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)];
1579 assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into());
1580 }
1581
1582 #[test]
1583 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1584 fn get_u32_range_over_32_bits() {
1585 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)];
1586 assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64));
1587 }
1588
1589 #[test]
1590 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1591 fn get_u32_range_memory_gap() {
1592 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)];
1593 assert_matches!(memory.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into());
1594 }
1595
1596 #[test]
1598 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1599 fn relocate_memory_empty_relocation_rules() {
1600 let mut memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3)];
1601
1602 assert_eq!(memory.relocate_memory(), Ok(()));
1603 check_memory!(memory, ((0, 0), 1), ((0, 1), 2), ((0, 2), 3));
1604 }
1605
1606 #[test]
1607 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1608 fn relocate_memory_new_segment_with_gap() {
1609 let mut memory = memory![
1610 ((0, 0), 1),
1611 ((0, 1), (-1, 0)),
1612 ((0, 2), 3),
1613 ((1, 0), (-1, 1)),
1614 ((1, 1), 5),
1615 ((1, 2), (-1, 2)),
1616 ((-1, 0), 7),
1617 ((-1, 1), 8),
1618 ((-1, 2), 9)
1619 ];
1620 memory
1621 .add_relocation_rule((-1, 0).into(), (2, 1).into())
1622 .unwrap();
1623 memory.data.push(vec![]);
1624
1625 assert_eq!(memory.relocate_memory(), Ok(()));
1626 check_memory!(
1627 memory,
1628 ((0, 0), 1),
1629 ((0, 1), (2, 1)),
1630 ((0, 2), 3),
1631 ((1, 0), (2, 2)),
1632 ((1, 1), 5),
1633 ((1, 2), (2, 3)),
1634 ((2, 1), 7),
1635 ((2, 2), 8),
1636 ((2, 3), 9)
1637 );
1638 assert!(memory.temp_data.is_empty());
1639 }
1640
1641 #[test]
1642 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1643 fn relocate_memory_new_segment() {
1644 let mut memory = memory![
1645 ((0, 0), 1),
1646 ((0, 1), (-1, 0)),
1647 ((0, 2), 3),
1648 ((1, 0), (-1, 1)),
1649 ((1, 1), 5),
1650 ((1, 2), (-1, 2)),
1651 ((-1, 0), 7),
1652 ((-1, 1), 8),
1653 ((-1, 2), 9)
1654 ];
1655 memory
1656 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1657 .unwrap();
1658 memory.data.push(vec![]);
1659
1660 assert_eq!(memory.relocate_memory(), Ok(()));
1661
1662 check_memory!(
1663 memory,
1664 ((0, 0), 1),
1665 ((0, 1), (2, 0)),
1666 ((0, 2), 3),
1667 ((1, 0), (2, 1)),
1668 ((1, 1), 5),
1669 ((1, 2), (2, 2)),
1670 ((2, 0), 7),
1671 ((2, 1), 8),
1672 ((2, 2), 9)
1673 );
1674 assert!(memory.temp_data.is_empty());
1675 }
1676
1677 #[test]
1678 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1679 fn relocate_memory_new_segment_unallocated() {
1680 let mut memory = memory![
1681 ((0, 0), 1),
1682 ((0, 1), (-1, 0)),
1683 ((0, 2), 3),
1684 ((1, 0), (-1, 1)),
1685 ((1, 1), 5),
1686 ((1, 2), (-1, 2)),
1687 ((-1, 0), 7),
1688 ((-1, 1), 8),
1689 ((-1, 2), 9)
1690 ];
1691 memory
1692 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1693 .unwrap();
1694
1695 assert_eq!(
1696 memory.relocate_memory(),
1697 Err(MemoryError::UnallocatedSegment(Box::new((2, 2))))
1698 );
1699 }
1700
1701 #[test]
1702 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1703 fn relocate_memory_into_existing_segment() {
1704 let mut memory = memory![
1705 ((0, 0), 1),
1706 ((0, 1), (-1, 0)),
1707 ((0, 2), 3),
1708 ((1, 0), (-1, 1)),
1709 ((1, 1), 5),
1710 ((1, 2), (-1, 2)),
1711 ((-1, 0), 7),
1712 ((-1, 1), 8),
1713 ((-1, 2), 9)
1714 ];
1715 memory
1716 .add_relocation_rule((-1, 0).into(), (1, 3).into())
1717 .unwrap();
1718
1719 assert_eq!(memory.relocate_memory(), Ok(()));
1720
1721 check_memory!(
1722 memory,
1723 ((0, 0), 1),
1724 ((0, 1), (1, 3)),
1725 ((0, 2), 3),
1726 ((1, 0), (1, 4)),
1727 ((1, 1), 5),
1728 ((1, 2), (1, 5)),
1729 ((1, 3), 7),
1730 ((1, 4), 8),
1731 ((1, 5), 9)
1732 );
1733 assert!(memory.temp_data.is_empty());
1734 }
1735
1736 #[test]
1737 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1738 fn relocate_memory_into_existing_segment_inconsistent_memory() {
1739 let mut memory = memory![
1740 ((0, 0), 1),
1741 ((0, 1), (-1, 0)),
1742 ((0, 2), 3),
1743 ((1, 0), (-1, 1)),
1744 ((1, 1), 5),
1745 ((1, 2), (-1, 2)),
1746 ((-1, 0), 7),
1747 ((-1, 1), 8),
1748 ((-1, 2), 9)
1749 ];
1750 memory
1751 .add_relocation_rule((-1, 0).into(), (1, 0).into())
1752 .unwrap();
1753
1754 assert_eq!(
1755 memory.relocate_memory(),
1756 Err(MemoryError::InconsistentMemory(Box::new((
1757 (1, 0).into(),
1758 (1, 1).into(),
1759 7.into(),
1760 ))))
1761 );
1762 }
1763
1764 #[test]
1765 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1766 fn relocate_memory_new_segment_2_temporary_segments_one_relocated() {
1767 let mut memory = memory![
1768 ((0, 0), 1),
1769 ((0, 1), (-1, 0)),
1770 ((0, 2), 3),
1771 ((1, 0), (-1, 1)),
1772 ((1, 1), 5),
1773 ((1, 2), (-1, 2)),
1774 ((-1, 0), 7),
1775 ((-1, 1), 8),
1776 ((-1, 2), 9),
1777 ((-2, 0), 10),
1778 ((-2, 1), 11)
1779 ];
1780 memory
1781 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1782 .unwrap();
1783 memory.data.push(vec![]);
1784
1785 assert_eq!(memory.relocate_memory(), Ok(()));
1786 check_memory!(
1787 memory,
1788 ((0, 0), 1),
1789 ((0, 1), (2, 0)),
1790 ((0, 2), 3),
1791 ((1, 0), (2, 1)),
1792 ((1, 1), 5),
1793 ((1, 2), (2, 2)),
1794 ((2, 0), 7),
1795 ((2, 1), 8),
1796 ((2, 2), 9),
1797 ((-1, 0), 10),
1798 ((-1, 1), 11)
1799 );
1800 }
1801
1802 #[test]
1803 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1804 fn relocate_memory_new_segment_2_temporary_segments_relocated() {
1805 let mut memory = memory![
1806 ((0, 0), 1),
1807 ((0, 1), (-1, 0)),
1808 ((0, 2), 3),
1809 ((1, 0), (-1, 1)),
1810 ((1, 1), 5),
1811 ((1, 2), (-1, 2)),
1812 ((-1, 0), 7),
1813 ((-1, 1), 8),
1814 ((-1, 2), 9),
1815 ((-2, 0), 10),
1816 ((-2, 1), 11)
1817 ];
1818 memory.data.push(vec![]);
1819 memory
1820 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1821 .unwrap();
1822 memory.data.push(vec![]);
1823 memory
1824 .add_relocation_rule((-2, 0).into(), (3, 0).into())
1825 .unwrap();
1826
1827 assert_eq!(memory.relocate_memory(), Ok(()));
1828
1829 check_memory!(
1830 memory,
1831 ((0, 0), 1),
1832 ((0, 1), (2, 0)),
1833 ((0, 2), 3),
1834 ((1, 0), (2, 1)),
1835 ((1, 1), 5),
1836 ((1, 2), (2, 2)),
1837 ((2, 0), 7),
1838 ((2, 1), 8),
1839 ((2, 2), 9),
1840 ((3, 0), 10),
1841 ((3, 1), 11)
1842 );
1843 assert!(memory.temp_data.is_empty());
1844 }
1845
1846 #[test]
1847 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1848 fn test_memory_display() {
1849 let memory = memory![
1850 ((0, 0), 1),
1851 ((0, 1), (-1, 0)),
1852 ((0, 2), 3),
1853 ((1, 0), (-1, 1)),
1854 ((1, 1), 5),
1855 ((1, 2), (-1, 2)),
1856 ((-1, 0), (-1, 0)),
1857 ((-1, 1), 8),
1858 ((-1, 2), 9)
1859 ];
1860
1861 assert_eq!(
1862 format!("{}", memory),
1863 "(-1,0) : -1:0\n(-1,1) : 8\n(-1,2) : 9\n(0,0) : 1\n(0,1) : -1:0\n(0,2) : 3\n(1,0) : -1:1\n(1,1) : 5\n(1,2) : -1:2\n");
1864 }
1865
1866 #[test]
1867 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1868 fn relocate_memory_into_existing_segment_temporary_values_in_temporary_memory() {
1869 let mut memory = memory![
1870 ((0, 0), 1),
1871 ((0, 1), (-1, 0)),
1872 ((0, 2), 3),
1873 ((1, 0), (-1, 1)),
1874 ((1, 1), 5),
1875 ((1, 2), (-1, 2)),
1876 ((-1, 0), (-1, 0)),
1877 ((-1, 1), 8),
1878 ((-1, 2), 9)
1879 ];
1880 memory
1881 .add_relocation_rule((-1, 0).into(), (1, 3).into())
1882 .unwrap();
1883
1884 assert_eq!(memory.relocate_memory(), Ok(()));
1885 check_memory!(
1886 memory,
1887 ((0, 0), 1),
1888 ((0, 1), (1, 3)),
1889 ((0, 2), 3),
1890 ((1, 0), (1, 4)),
1891 ((1, 1), 5),
1892 ((1, 2), (1, 5)),
1893 ((1, 3), (1, 3)),
1894 ((1, 4), 8),
1895 ((1, 5), 9)
1896 );
1897 assert!(memory.temp_data.is_empty());
1898 }
1899
1900 #[test]
1901 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1902 fn relocate_address_with_rules() {
1903 let mut memory = Memory::new();
1904 memory
1905 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1906 .unwrap();
1907 memory
1908 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1909 .unwrap();
1910
1911 assert_eq!(
1912 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1913 MaybeRelocatable::RelocatableValue((2, 0).into()),
1914 );
1915 assert_eq!(
1916 Memory::relocate_address((-2, 1).into(), &memory.relocation_rules).unwrap(),
1917 MaybeRelocatable::RelocatableValue((2, 3).into()),
1918 );
1919 }
1920
1921 #[test]
1922 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1923 fn relocate_address_no_rules() {
1924 let memory = Memory::new();
1925 assert_eq!(
1926 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1927 MaybeRelocatable::RelocatableValue((-1, 0).into()),
1928 );
1929 assert_eq!(
1930 Memory::relocate_address((-2, 1).into(), &memory.relocation_rules).unwrap(),
1931 MaybeRelocatable::RelocatableValue((-2, 1).into()),
1932 );
1933 }
1934
1935 #[test]
1936 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1937 fn relocate_address_real_addr() {
1938 let memory = Memory::new();
1939 assert_eq!(
1940 Memory::relocate_address((1, 0).into(), &memory.relocation_rules).unwrap(),
1941 MaybeRelocatable::RelocatableValue((1, 0).into()),
1942 );
1943 assert_eq!(
1944 Memory::relocate_address((1, 1).into(), &memory.relocation_rules).unwrap(),
1945 MaybeRelocatable::RelocatableValue((1, 1).into()),
1946 );
1947 }
1948
1949 #[test]
1950 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1951 #[cfg(feature = "extensive_hints")]
1952 fn relocate_address_to_integer() {
1953 let mut memory = Memory::new();
1954 memory
1955 .add_relocation_rule((-1, 0).into(), 0.into())
1956 .unwrap();
1957 memory
1958 .add_relocation_rule((-2, 0).into(), 42.into())
1959 .unwrap();
1960
1961 assert_eq!(
1962 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1963 MaybeRelocatable::Int(0.into()),
1964 );
1965 assert_eq!(
1966 Memory::relocate_address((-2, 0).into(), &memory.relocation_rules).unwrap(),
1967 MaybeRelocatable::Int(42.into()),
1968 );
1969 }
1970
1971 #[test]
1972 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1973 #[cfg(feature = "extensive_hints")]
1974 fn relocate_address_integer_no_duplicates() {
1975 let mut memory = Memory::new();
1976 memory
1977 .add_relocation_rule((-1, 0).into(), 1.into())
1978 .unwrap();
1979 assert_eq!(
1980 memory.add_relocation_rule((-1, 0).into(), 42.into()),
1981 Err(MemoryError::DuplicatedRelocation(-1))
1982 );
1983 assert_eq!(
1984 memory.add_relocation_rule((-1, 0).into(), (2, 0).into()),
1985 Err(MemoryError::DuplicatedRelocation(-1))
1986 );
1987
1988 assert_eq!(
1989 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1990 MaybeRelocatable::Int(1.into()),
1991 );
1992
1993 memory
1994 .add_relocation_rule((-2, 0).into(), (3, 0).into())
1995 .unwrap();
1996 assert_eq!(
1997 memory.add_relocation_rule((-2, 0).into(), 1.into()),
1998 Err(MemoryError::DuplicatedRelocation(-2))
1999 );
2000
2001 assert_eq!(
2002 Memory::relocate_address((-2, 0).into(), &memory.relocation_rules).unwrap(),
2003 MaybeRelocatable::RelocatableValue((3, 0).into()),
2004 );
2005 }
2006
2007 #[test]
2008 fn mark_address_as_accessed() {
2009 let mut memory = memory![((0, 0), 0)];
2010 assert!(!memory.data[0][0].is_accessed());
2011 memory.mark_as_accessed(relocatable!(0, 0));
2012 assert!(memory.data[0][0].is_accessed());
2013 }
2014
2015 #[test]
2016 fn get_amount_of_accessed_addresses_for_segment_valid() {
2017 let mut memory = memory![((0, 0), 0)];
2018 assert_eq!(
2019 memory.get_amount_of_accessed_addresses_for_segment(0),
2020 Some(0)
2021 );
2022 memory.mark_as_accessed(relocatable!(0, 0));
2023 assert_eq!(
2024 memory.get_amount_of_accessed_addresses_for_segment(0),
2025 Some(1)
2026 );
2027 }
2028
2029 #[test]
2030 fn get_amount_of_accessed_addresses_for_segment_invalid_segment() {
2031 let memory = memory![((0, 0), 0)];
2032 assert_eq!(memory.get_amount_of_accessed_addresses_for_segment(1), None);
2033 }
2034
2035 #[test]
2036 fn memory_cell_new_is_not_accessed() {
2037 let cell = MemoryCell::new(mayberelocatable!(1));
2038 assert!(!cell.is_accessed())
2039 }
2040
2041 #[test]
2042 fn memory_cell_mark_accessed() {
2043 let mut cell = MemoryCell::new(mayberelocatable!(1));
2044 cell.mark_accessed();
2045 assert!(cell.is_accessed())
2046 }
2047
2048 #[test]
2049 fn memory_cell_get_value() {
2050 let cell = MemoryCell::new(mayberelocatable!(1));
2051 assert_eq!(cell.get_value(), Some(mayberelocatable!(1)));
2052 }
2053
2054 use core::cmp::Ordering::*;
2055
2056 fn check_memcmp(
2057 lhs: (isize, usize),
2058 rhs: (isize, usize),
2059 len: usize,
2060 ord: Ordering,
2061 pos: usize,
2062 ) {
2063 let mem = memory![
2064 ((-2, 0), 1),
2065 ((-2, 1), (1, 1)),
2066 ((-2, 3), 0),
2067 ((-2, 4), 0),
2068 ((-1, 0), 1),
2069 ((-1, 1), (1, 1)),
2070 ((-1, 3), 0),
2071 ((-1, 4), 3),
2072 ((0, 0), 1),
2073 ((0, 1), (1, 1)),
2074 ((0, 3), 0),
2075 ((0, 4), 0),
2076 ((1, 0), 1),
2077 ((1, 1), (1, 1)),
2078 ((1, 3), 0),
2079 ((1, 4), 3)
2080 ];
2081 assert_eq!((ord, pos), mem.memcmp(lhs.into(), rhs.into(), len));
2082 }
2083
2084 #[test]
2085 fn insert_alloc_fails_gracefully() {
2086 let mut mem = memory![((0, 0), 1)];
2087 let err = mem.insert((0, usize::MAX >> 1).into(), Felt252::ONE);
2088 assert_eq!(err, Err(MemoryError::VecCapacityExceeded));
2089 }
2090
2091 #[test]
2092 fn insert_overflow_fails_gracefully() {
2093 let mut mem = memory![((0, 0), 1)];
2094 let err = mem.insert((0, usize::MAX).into(), Felt252::ONE);
2095 assert_eq!(err, Err(MemoryError::VecCapacityExceeded));
2096 }
2097
2098 #[test]
2099 fn memcmp() {
2100 check_memcmp((0, 0), (0, 0), 3, Equal, 3);
2101 check_memcmp((0, 0), (1, 0), 3, Equal, 3);
2102 check_memcmp((0, 0), (1, 0), 5, Less, 4);
2103 check_memcmp((1, 0), (0, 0), 5, Greater, 4);
2104 check_memcmp((2, 2), (2, 5), 8, Equal, 0);
2105 check_memcmp((0, 0), (2, 5), 8, Greater, 0);
2106 check_memcmp((2, 5), (0, 0), 8, Less, 0);
2107 check_memcmp((-2, 0), (-2, 0), 3, Equal, 3);
2108 check_memcmp((-2, 0), (-1, 0), 3, Equal, 3);
2109 check_memcmp((-2, 0), (-1, 0), 5, Less, 4);
2110 check_memcmp((-1, 0), (-2, 0), 5, Greater, 4);
2111 check_memcmp((-3, 2), (-3, 5), 8, Equal, 0);
2112 check_memcmp((-2, 0), (-3, 5), 8, Greater, 0);
2113 check_memcmp((-3, 5), (-2, 0), 8, Less, 0);
2114 }
2115
2116 #[test]
2117 fn cairo_pie_memory_from_memory() {
2118 let memory = memory![((8, 9), 3), ((1, 2), 5), ((7, 6), (1, 2))];
2119
2120 assert_eq!(
2121 CairoPieMemory::from(&memory),
2122 CairoPieMemory(vec![
2123 ((1, 2), MaybeRelocatable::from(5)),
2124 ((7, 6), MaybeRelocatable::from((1, 2))),
2125 ((8, 9), MaybeRelocatable::from(3))
2126 ])
2127 )
2128 }
2129
2130 #[test]
2131 #[cfg(not(feature = "extensive_hints"))]
2132 fn flatten_relocation_rules_chain_happy() {
2133 let mut mem = Memory::new();
2134 mem.temp_data = vec![vec![], vec![]];
2136
2137 mem.relocation_rules.insert(0, Relocatable::from((-2, 3)));
2140 mem.relocation_rules.insert(1, Relocatable::from((10, 4)));
2141 mem.relocation_rules.insert(2, Relocatable::from((7, 1)));
2143
2144 assert_eq!(mem.flatten_relocation_rules(), Ok(()));
2145 assert_eq!(
2146 *mem.relocation_rules.get(&0).unwrap(),
2147 Relocatable::from((10, 7))
2148 );
2149 assert_eq!(
2150 *mem.relocation_rules.get(&1).unwrap(),
2151 Relocatable::from((10, 4))
2152 );
2153 assert_eq!(
2154 *mem.relocation_rules.get(&2).unwrap(),
2155 Relocatable::from((7, 1))
2156 );
2157 }
2158
2159 #[test]
2160 #[cfg(not(feature = "extensive_hints"))]
2161 fn flatten_relocation_rules_cycle_err() {
2162 let mut mem = Memory::new();
2163 mem.temp_data = vec![vec![]];
2164
2165 mem.relocation_rules.insert(0, Relocatable::from((-1, 0)));
2167
2168 assert_eq!(mem.flatten_relocation_rules(), Err(MemoryError::Relocation));
2169 }
2170
2171 #[test]
2172 #[cfg(feature = "extensive_hints")]
2173 fn flatten_relocation_rules_chain_happy_extensive_reloc_and_int() {
2174 let mut mem = Memory::new();
2175 mem.temp_data = vec![vec![], vec![], vec![], vec![], vec![]];
2176
2177 mem.relocation_rules.insert(
2182 0,
2183 MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 3))),
2184 );
2185 mem.relocation_rules.insert(
2186 1,
2187 MaybeRelocatable::RelocatableValue(Relocatable::from((10, 4))),
2188 );
2189
2190 mem.relocation_rules.insert(
2196 2,
2197 MaybeRelocatable::RelocatableValue(Relocatable::from((-4, 0))),
2198 );
2199 mem.relocation_rules.insert(
2200 3,
2201 MaybeRelocatable::RelocatableValue(Relocatable::from((-5, 0))),
2202 );
2203 mem.relocation_rules
2204 .insert(4, MaybeRelocatable::Int(Felt252::from(99)));
2205
2206 assert_eq!(mem.flatten_relocation_rules(), Ok(()));
2207
2208 assert_eq!(
2209 mem.relocation_rules.get(&0),
2210 Some(&MaybeRelocatable::RelocatableValue(Relocatable::from((
2211 10, 7
2212 ))))
2213 );
2214 assert_eq!(
2215 mem.relocation_rules.get(&1),
2216 Some(&MaybeRelocatable::RelocatableValue(Relocatable::from((
2217 10, 4
2218 ))))
2219 );
2220 assert_eq!(
2221 mem.relocation_rules.get(&2),
2222 Some(&MaybeRelocatable::Int(Felt252::from(99)))
2223 );
2224 }
2225
2226 #[test]
2227 #[cfg(feature = "extensive_hints")]
2228 fn flatten_relocation_rules_int_with_non_zero_offset_err() {
2229 let mut mem = Memory::new();
2230 mem.temp_data = vec![vec![], vec![], vec![]];
2232
2233 mem.relocation_rules.insert(
2237 0,
2238 MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 5))),
2239 );
2240 mem.relocation_rules.insert(
2241 1,
2242 MaybeRelocatable::RelocatableValue(Relocatable::from((-3, 0))),
2243 );
2244 mem.relocation_rules
2245 .insert(2, MaybeRelocatable::Int(Felt252::from(7)));
2246
2247 assert_eq!(
2248 mem.flatten_relocation_rules(),
2249 Err(MemoryError::NonZeroOffset(5))
2250 );
2251 }
2252
2253 #[test]
2254 #[cfg(feature = "extensive_hints")]
2255 fn flatten_relocation_rules_cycle_err_extensive() {
2256 let mut mem = Memory::new();
2257 mem.temp_data = vec![vec![], vec![]];
2258
2259 mem.relocation_rules.insert(
2263 0,
2264 MaybeRelocatable::RelocatableValue(Relocatable::from((-1, 0))),
2265 );
2266 mem.relocation_rules.insert(
2267 1,
2268 MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 0))),
2269 );
2270
2271 assert_eq!(mem.flatten_relocation_rules(), Err(MemoryError::Relocation));
2272 }
2273
2274 #[test]
2275 #[cfg(not(feature = "extensive_hints"))]
2276 fn flatten_relocation_rules_missing_next_err() {
2277 let mut mem = Memory::new();
2278 mem.temp_data = vec![vec![], vec![], vec![]];
2279
2280 mem.relocation_rules.insert(0, Relocatable::from((-4, 1)));
2283
2284 assert_eq!(
2285 mem.flatten_relocation_rules(),
2286 Err(MemoryError::UnmappedTemporarySegment(-4))
2287 );
2288 }
2289
2290 #[test]
2291 #[cfg(feature = "extensive_hints")]
2292 fn flatten_relocation_rules_missing_next_err_extensive() {
2293 let mut mem = Memory::new();
2294 mem.temp_data = vec![vec![], vec![], vec![]];
2295
2296 mem.relocation_rules.insert(
2299 0,
2300 MaybeRelocatable::RelocatableValue(Relocatable::from((-4, 0))),
2301 );
2302
2303 assert_eq!(
2304 mem.flatten_relocation_rules(),
2305 Err(MemoryError::UnmappedTemporarySegment(-4))
2306 );
2307 }
2308
2309 #[test]
2310 #[cfg(not(feature = "extensive_hints"))]
2311 fn relocate_memory_temp_chain_multi_hop() {
2312 let mut memory = Memory::new();
2313
2314 memory.temp_data = vec![
2318 vec![
2319 MemoryCell::new(mayberelocatable!(100)),
2320 MemoryCell::new(mayberelocatable!(200)),
2321 ],
2322 vec![
2323 MemoryCell::new(mayberelocatable!(7)),
2324 MemoryCell::new(mayberelocatable!(8)),
2325 MemoryCell::new(mayberelocatable!(9)),
2326 ],
2327 ];
2328
2329 memory
2334 .relocation_rules
2335 .insert(0, Relocatable::from((-2, 3)));
2336 memory
2337 .relocation_rules
2338 .insert(1, Relocatable::from((5, 10)));
2339
2340 memory.data.push(vec![
2346 MemoryCell::new(mayberelocatable!(-1, 0)),
2347 MemoryCell::new(mayberelocatable!(-1, 1)),
2348 MemoryCell::new(mayberelocatable!(-2, 0)),
2349 ]);
2350
2351 while memory.data.len() <= 5 {
2353 memory.data.push(Vec::new());
2354 }
2355
2356 assert_eq!(memory.relocate_memory(), Ok(()));
2357
2358 check_memory!(
2360 memory,
2361 ((0, 0), (5, 13)),
2362 ((0, 1), (5, 14)),
2363 ((0, 2), (5, 10)),
2364 ((5, 10), 7),
2365 ((5, 11), 8),
2366 ((5, 12), 9),
2367 ((5, 13), 100),
2368 ((5, 14), 200)
2369 );
2370 assert!(memory.temp_data.is_empty());
2371 }
2372
2373 #[test]
2374 #[cfg(feature = "extensive_hints")]
2375 fn relocate_memory_temp_chain_to_int_multi_hop() {
2376 let mut memory = Memory::new();
2377
2378 memory.temp_data = vec![
2382 vec![MemoryCell::new(mayberelocatable!(123))],
2383 vec![MemoryCell::new(mayberelocatable!(456))],
2384 ];
2385
2386 memory.relocation_rules.insert(
2391 0,
2392 MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 0))),
2393 );
2394 memory
2395 .relocation_rules
2396 .insert(1, MaybeRelocatable::Int(Felt252::from(99)));
2397
2398 memory
2401 .data
2402 .push(vec![MemoryCell::new(mayberelocatable!(-1, 0))]);
2403
2404 assert_eq!(memory.relocate_memory(), Ok(()));
2405
2406 assert_eq!(
2408 memory.data[0][0].get_value(),
2409 Some(MaybeRelocatable::Int(Felt252::from(99)))
2410 );
2411
2412 assert!(memory.temp_data.is_empty());
2414 }
2415}