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