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)]
40#[repr(align(32))]
41pub(crate) struct MemoryCell([u64; 4]);
42
43impl MemoryCell {
44 pub const NONE_MASK: u64 = 1 << 63;
45 pub const ACCESS_MASK: u64 = 1 << 62;
46 pub const RELOCATABLE_MASK: u64 = 1 << 61;
47 pub const NONE: Self = Self([Self::NONE_MASK, 0, 0, 0]);
48
49 pub fn new(value: MaybeRelocatable) -> Self {
50 value.into()
51 }
52
53 pub fn is_none(&self) -> bool {
54 self.0[0] & Self::NONE_MASK == Self::NONE_MASK
55 }
56
57 pub fn is_some(&self) -> bool {
58 !self.is_none()
59 }
60
61 pub fn mark_accessed(&mut self) {
62 self.0[0] |= Self::ACCESS_MASK;
63 }
64
65 pub fn is_accessed(&self) -> bool {
66 self.0[0] & Self::ACCESS_MASK == Self::ACCESS_MASK
67 }
68
69 pub fn get_value(&self) -> Option<MaybeRelocatable> {
70 self.is_some().then(|| (*self).into())
71 }
72}
73
74impl From<MaybeRelocatable> for MemoryCell {
75 fn from(value: MaybeRelocatable) -> Self {
76 match value {
77 MaybeRelocatable::Int(x) => Self(x.to_raw()),
78 MaybeRelocatable::RelocatableValue(x) => Self([
79 Self::RELOCATABLE_MASK,
80 0,
81 usize::from_ne_bytes(x.segment_index.to_ne_bytes()) as u64,
83 x.offset as u64,
84 ]),
85 }
86 }
87}
88
89impl From<MemoryCell> for MaybeRelocatable {
90 fn from(cell: MemoryCell) -> Self {
91 debug_assert!(cell.is_some());
92 let flags = cell.0[0];
93 match flags & MemoryCell::RELOCATABLE_MASK {
94 MemoryCell::RELOCATABLE_MASK => Self::from((
95 isize::from_ne_bytes((cell.0[2] as usize).to_ne_bytes()),
97 cell.0[3] as usize,
98 )),
99 _ => {
100 let mut value = cell.0;
101 value[0] &= 0x0fffffffffffffff;
103 Self::Int(Felt252::from_raw(value))
104 }
105 }
106 }
107}
108
109pub struct AddressSet(Vec<bv::BitVec>);
110
111impl AddressSet {
112 pub(crate) fn new() -> Self {
113 Self(Vec::new())
114 }
115
116 pub(crate) fn contains(&self, addr: &Relocatable) -> bool {
117 let segment = addr.segment_index;
118 if segment.is_negative() {
119 return false;
120 }
121
122 self.0
123 .get(segment as usize)
124 .and_then(|segment| segment.get(addr.offset))
125 .map(|bit| *bit)
126 .unwrap_or(false)
127 }
128
129 pub(crate) fn extend(&mut self, addresses: &[Relocatable]) {
130 for addr in addresses {
131 let segment = addr.segment_index;
132 if segment.is_negative() {
133 continue;
134 }
135 let segment = segment as usize;
136 if segment >= self.0.len() {
137 self.0.resize(segment + 1, bv::BitVec::new());
138 }
139
140 let offset = addr.offset;
141 if offset >= self.0[segment].len() {
142 self.0[segment].resize(offset + 1, false);
143 }
144 self.0[segment].replace(offset, true);
145 }
146 }
147}
148
149#[cfg(test)]
150impl AddressSet {
151 pub(crate) fn len(&self) -> usize {
152 self.0
153 .iter()
154 .map(|segment| segment.iter().map(|bit| *bit as usize).sum::<usize>())
155 .sum()
156 }
157}
158
159pub struct Memory {
160 pub(crate) data: Vec<Vec<MemoryCell>>,
161 pub(crate) temp_data: Vec<Vec<MemoryCell>>,
167 #[cfg(not(feature = "extensive_hints"))]
170 pub(crate) relocation_rules: HashMap<usize, Relocatable>,
171 #[cfg(feature = "extensive_hints")]
172 pub(crate) relocation_rules: HashMap<usize, MaybeRelocatable>,
173 pub validated_addresses: AddressSet,
174 validation_rules: Vec<Option<ValidationRule>>,
175}
176
177impl Memory {
178 pub fn new() -> Memory {
179 Memory {
180 data: Vec::new(),
181 temp_data: Vec::new(),
182 relocation_rules: HashMap::new(),
183 validated_addresses: AddressSet::new(),
184 validation_rules: Vec::with_capacity(7),
185 }
186 }
187
188 fn get_segment(&mut self, key: Relocatable) -> Result<&mut Vec<MemoryCell>, MemoryError> {
189 let (value_index, _) = from_relocatable_to_indexes(key);
190 let data = if key.segment_index.is_negative() {
191 &mut self.temp_data
192 } else {
193 &mut self.data
194 };
195 let data_len = data.len();
196 data.get_mut(value_index)
197 .ok_or_else(|| MemoryError::UnallocatedSegment(Box::new((value_index, data_len))))
198 }
199
200 pub fn insert<V>(&mut self, key: Relocatable, val: V) -> Result<(), MemoryError>
205 where
206 MaybeRelocatable: From<V>,
207 {
208 let val = MaybeRelocatable::from(val);
209 let segment = self.get_segment(key)?;
210 let (_, value_offset) = from_relocatable_to_indexes(key);
211
212 let (len, capacity) = (segment.len(), segment.capacity());
215 if len <= value_offset {
216 let new_len = value_offset
217 .checked_add(1)
218 .ok_or(MemoryError::VecCapacityExceeded)?;
219 segment
220 .try_reserve(new_len.saturating_sub(capacity))
221 .map_err(|_| MemoryError::VecCapacityExceeded)?;
222 segment.resize(new_len, MemoryCell::NONE);
223 }
224 match segment[value_offset].get_value() {
227 None => segment[value_offset] = MemoryCell::new(val),
228 Some(current_cell) => {
229 if current_cell != val {
230 return Err(MemoryError::InconsistentMemory(Box::new((
232 key,
233 current_cell,
234 val,
235 ))));
236 }
237 }
238 };
239 self.validate_memory_cell(key)
240 }
241
242 pub(crate) fn delete_unaccessed(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
243 let (_, offset) = from_relocatable_to_indexes(addr);
244 let segment = self.get_segment(addr)?;
245
246 if offset >= segment.len() {
248 return Err(MemoryError::UnsetUnallocatedCell(addr));
249 }
250
251 if segment[offset].is_accessed() {
253 return Err(MemoryError::UnsetAccessedCell(addr));
254 }
255
256 segment[offset] = MemoryCell::NONE;
258 Ok(())
259 }
260
261 pub(crate) fn get<'a, 'b: 'a, K: 'a>(&'b self, key: &'a K) -> Option<Cow<'b, MaybeRelocatable>>
263 where
264 Relocatable: TryFrom<&'a K>,
265 {
266 let relocatable: Relocatable = key.try_into().ok()?;
267
268 let data = if relocatable.segment_index.is_negative() {
269 &self.temp_data
270 } else {
271 &self.data
272 };
273 let (i, j) = from_relocatable_to_indexes(relocatable);
274 let value = data.get(i)?.get(j)?.get_value()?;
275 Some(Cow::Owned(self.relocate_value(&value).ok()?.into_owned()))
276 }
277
278 #[cfg(not(feature = "extensive_hints"))]
280 fn relocate_address(
281 addr: Relocatable,
282 relocation_rules: &HashMap<usize, Relocatable>,
283 ) -> Result<MaybeRelocatable, MemoryError> {
284 if addr.segment_index < 0 {
285 if let Some(x) = relocation_rules.get(&(-(addr.segment_index + 1) as usize)) {
288 return Ok((*x + addr.offset)?.into());
289 }
290 }
291 Ok(addr.into())
292 }
293 #[cfg(feature = "extensive_hints")]
294 fn relocate_address(
295 addr: Relocatable,
296 relocation_rules: &HashMap<usize, MaybeRelocatable>,
297 ) -> Result<MaybeRelocatable, MemoryError> {
298 if addr.segment_index < 0 {
299 if let Some(x) = relocation_rules.get(&(-(addr.segment_index + 1) as usize)) {
302 return Ok(match x {
303 MaybeRelocatable::RelocatableValue(r) => (*r + addr.offset)?.into(),
304 MaybeRelocatable::Int(i) => i.into(),
305 });
306 }
307 }
308 Ok(addr.into())
309 }
310
311 pub fn relocate_memory(&mut self) -> Result<(), MemoryError> {
313 if self.relocation_rules.is_empty() || self.temp_data.is_empty() {
314 return Ok(());
315 }
316 for segment in self.data.iter_mut().chain(self.temp_data.iter_mut()) {
318 for cell in segment.iter_mut() {
319 let value = cell.get_value();
320 match value {
321 Some(MaybeRelocatable::RelocatableValue(addr)) if addr.segment_index < 0 => {
322 let mut new_cell = MemoryCell::new(Memory::relocate_address(
323 addr,
324 &self.relocation_rules,
325 )?);
326 if cell.is_accessed() {
327 new_cell.mark_accessed();
328 }
329 *cell = new_cell;
330 }
331 _ => {}
332 }
333 }
334 }
335 for index in (0..self.temp_data.len()).rev() {
337 if let Some(base_addr) = self.relocation_rules.get(&index) {
338 let data_segment = self.temp_data.remove(index);
339
340 #[cfg(feature = "extensive_hints")]
341 let base_addr = match base_addr {
342 MaybeRelocatable::RelocatableValue(addr) => addr,
343 MaybeRelocatable::Int(_) => {
344 continue;
345 }
346 };
347
348 let mut addr = *base_addr;
350 if let Some(s) = self.data.get_mut(addr.segment_index as usize) {
351 s.reserve_exact(data_segment.len())
352 }
353 for cell in data_segment {
354 if let Some(v) = cell.get_value() {
355 self.insert(addr, v)?;
357 if cell.is_accessed() {
359 self.mark_as_accessed(addr)
360 }
361 }
362 addr = (addr + 1)?;
363 }
364 }
365 }
366 self.relocation_rules.clear();
367 Ok(())
368 }
369 #[cfg(not(feature = "extensive_hints"))]
380 pub(crate) fn add_relocation_rule(
381 &mut self,
382 src_ptr: Relocatable,
383 dst_ptr: Relocatable,
384 ) -> Result<(), MemoryError> {
385 if src_ptr.segment_index >= 0 {
386 return Err(MemoryError::AddressNotInTemporarySegment(
387 src_ptr.segment_index,
388 ));
389 }
390 if src_ptr.offset != 0 {
391 return Err(MemoryError::NonZeroOffset(src_ptr.offset));
392 }
393
394 let segment_index = -(src_ptr.segment_index + 1) as usize;
397 if self.relocation_rules.contains_key(&segment_index) {
398 return Err(MemoryError::DuplicatedRelocation(src_ptr.segment_index));
399 }
400
401 self.relocation_rules.insert(segment_index, dst_ptr);
402 Ok(())
403 }
404 #[cfg(feature = "extensive_hints")]
405 pub(crate) fn add_relocation_rule(
406 &mut self,
407 src_ptr: Relocatable,
408 dst: MaybeRelocatable,
409 ) -> Result<(), MemoryError> {
410 if src_ptr.segment_index >= 0 {
411 return Err(MemoryError::AddressNotInTemporarySegment(
412 src_ptr.segment_index,
413 ));
414 }
415 if src_ptr.offset != 0 {
416 return Err(MemoryError::NonZeroOffset(src_ptr.offset));
417 }
418
419 let segment_index = -(src_ptr.segment_index + 1) as usize;
422 if self.relocation_rules.contains_key(&segment_index) {
423 return Err(MemoryError::DuplicatedRelocation(src_ptr.segment_index));
424 }
425
426 self.relocation_rules.insert(segment_index, dst);
427 Ok(())
428 }
429
430 pub fn get_integer(&self, key: Relocatable) -> Result<Cow<Felt252>, MemoryError> {
433 match self
434 .get(&key)
435 .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
436 {
437 Cow::Borrowed(MaybeRelocatable::Int(int)) => Ok(Cow::Borrowed(int)),
438 Cow::Owned(MaybeRelocatable::Int(int)) => Ok(Cow::Owned(int)),
439 _ => Err(MemoryError::ExpectedInteger(Box::new(key))),
440 }
441 }
442
443 pub fn get_u32(&self, key: Relocatable) -> Result<u32, MemoryError> {
446 let felt = self.get_integer(key)?.into_owned();
447 felt.to_u32()
448 .ok_or_else(|| MemoryError::Math(MathError::Felt252ToU32Conversion(Box::new(felt))))
449 }
450
451 pub fn get_usize(&self, key: Relocatable) -> Result<usize, MemoryError> {
454 let felt = self.get_integer(key)?.into_owned();
455 felt.to_usize()
456 .ok_or_else(|| MemoryError::Math(MathError::Felt252ToUsizeConversion(Box::new(felt))))
457 }
458
459 pub fn get_relocatable(&self, key: Relocatable) -> Result<Relocatable, MemoryError> {
462 match self
463 .get(&key)
464 .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
465 {
466 Cow::Borrowed(MaybeRelocatable::RelocatableValue(rel)) => Ok(*rel),
467 Cow::Owned(MaybeRelocatable::RelocatableValue(rel)) => Ok(rel),
468 _ => Err(MemoryError::ExpectedRelocatable(Box::new(key))),
469 }
470 }
471
472 pub fn get_maybe_relocatable(&self, key: Relocatable) -> Result<MaybeRelocatable, MemoryError> {
475 match self
476 .get(&key)
477 .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
478 {
479 Cow::Borrowed(maybe_rel) => Ok(maybe_rel.clone()),
481 Cow::Owned(maybe_rel) => Ok(maybe_rel),
482 }
483 }
484
485 pub fn insert_value<T: Into<MaybeRelocatable>>(
488 &mut self,
489 key: Relocatable,
490 val: T,
491 ) -> Result<(), MemoryError> {
492 self.insert(key, &val.into())
493 }
494
495 pub fn add_validation_rule(&mut self, segment_index: usize, rule: ValidationRule) {
496 if segment_index >= self.validation_rules.len() {
497 self.validation_rules
499 .resize_with(segment_index + 1, || None);
500 }
501 self.validation_rules.insert(segment_index, Some(rule));
502 }
503
504 fn validate_memory_cell(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
505 if let Some(Some(rule)) = addr
506 .segment_index
507 .to_usize()
508 .and_then(|x| self.validation_rules.get(x))
509 {
510 if !self.validated_addresses.contains(&addr) {
511 self.validated_addresses
512 .extend(rule.0(self, addr)?.as_slice());
513 }
514 }
515 Ok(())
516 }
517
518 pub fn validate_existing_memory(&mut self) -> Result<(), MemoryError> {
520 for (index, rule) in self.validation_rules.iter().enumerate() {
521 if index >= self.data.len() {
522 continue;
523 }
524 let Some(rule) = rule else {
525 continue;
526 };
527 for offset in 0..self.data[index].len() {
528 let addr = Relocatable::from((index as isize, offset));
529 if !self.validated_addresses.contains(&addr) {
530 self.validated_addresses
531 .extend(rule.0(self, addr)?.as_slice());
532 }
533 }
534 }
535 Ok(())
536 }
537
538 pub(crate) fn memcmp(
547 &self,
548 lhs: Relocatable,
549 rhs: Relocatable,
550 len: usize,
551 ) -> (Ordering, usize) {
552 let get_segment = |idx: isize| {
553 if idx.is_negative() {
554 self.temp_data.get(-(idx + 1) as usize)
555 } else {
556 self.data.get(idx as usize)
557 }
558 };
559 match (
560 get_segment(lhs.segment_index),
561 get_segment(rhs.segment_index),
562 ) {
563 (None, None) => {
564 return (Ordering::Equal, 0);
565 }
566 (Some(_), None) => {
567 return (Ordering::Greater, 0);
568 }
569 (None, Some(_)) => {
570 return (Ordering::Less, 0);
571 }
572 (Some(lhs_segment), Some(rhs_segment)) => {
573 let (lhs_start, rhs_start) = (lhs.offset, rhs.offset);
574 for i in 0..len {
575 let (lhs, rhs) = (
576 lhs_segment.get(lhs_start + i),
577 rhs_segment.get(rhs_start + i),
578 );
579 let ord = lhs.cmp(&rhs);
580 if ord == Ordering::Equal {
581 continue;
582 }
583 return (ord, i);
584 }
585 }
586 };
587 (Ordering::Equal, len)
588 }
589
590 pub(crate) fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
599 if lhs == rhs {
600 return true;
601 }
602 let get_segment = |idx: isize| {
603 if idx.is_negative() {
604 self.temp_data.get(-(idx + 1) as usize)
605 } else {
606 self.data.get(idx as usize)
607 }
608 };
609 match (
610 get_segment(lhs.segment_index).and_then(|s| s.get(lhs.offset..)),
611 get_segment(rhs.segment_index).and_then(|s| s.get(rhs.offset..)),
612 ) {
613 (Some(lhs), Some(rhs)) => {
614 let (lhs_len, rhs_len) = (lhs.len().min(len), rhs.len().min(len));
615 if lhs_len != rhs_len {
616 return false;
617 }
618 lhs[..lhs_len] == rhs[..rhs_len]
619 }
620 (None, None) => true,
621 _ => false,
622 }
623 }
624
625 pub fn get_range(&self, addr: Relocatable, size: usize) -> Vec<Option<Cow<MaybeRelocatable>>> {
628 let mut values = Vec::new();
629
630 for i in 0..size {
631 values.push((addr + i).ok().and_then(|x| self.get(&x)));
632 }
633
634 values
635 }
636
637 pub fn get_continuous_range(
640 &self,
641 addr: Relocatable,
642 size: usize,
643 ) -> Result<Vec<MaybeRelocatable>, MemoryError> {
644 let mut values = Vec::with_capacity(size);
645
646 for i in 0..size {
647 values.push(match self.get(&(addr + i)?) {
648 Some(elem) => elem.into_owned(),
649 None => return Err(MemoryError::GetRangeMemoryGap(Box::new((addr, size)))),
650 });
651 }
652
653 Ok(values)
654 }
655
656 pub fn get_integer_range(
660 &self,
661 addr: Relocatable,
662 size: usize,
663 ) -> Result<Vec<Cow<Felt252>>, MemoryError> {
664 let mut values = Vec::new();
665
666 for i in 0..size {
667 values.push(self.get_integer((addr + i)?)?);
668 }
669
670 Ok(values)
671 }
672
673 pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result<Vec<u32>, MemoryError> {
676 let mut values = Vec::new();
677
678 for i in 0..size {
679 values.push(self.get_u32((addr + i)?)?);
680 }
681
682 Ok(values)
683 }
684
685 fn get_cell(&self, addr: Relocatable) -> Option<&MemoryCell> {
686 let (i, j) = from_relocatable_to_indexes(addr);
687 let data = if addr.segment_index < 0 {
688 &self.temp_data
689 } else {
690 &self.data
691 };
692 data.get(i)?.get(j)
693 }
694
695 #[cfg(test)]
696 pub(crate) fn get_cell_for_testing(&self, addr: Relocatable) -> Option<&MemoryCell> {
697 self.get_cell(addr)
698 }
699
700 pub fn is_accessed(&self, addr: &Relocatable) -> Result<bool, MemoryError> {
701 Ok(self
702 .get_cell(*addr)
703 .ok_or(MemoryError::UnknownMemoryCell(Box::new(*addr)))?
704 .is_accessed())
705 }
706
707 pub fn mark_as_accessed(&mut self, addr: Relocatable) {
708 let (i, j) = from_relocatable_to_indexes(addr);
709 let data = if addr.segment_index < 0 {
710 &mut self.temp_data
711 } else {
712 &mut self.data
713 };
714 let cell = data.get_mut(i).and_then(|x| x.get_mut(j));
715 if let Some(cell) = cell {
716 cell.mark_accessed()
717 }
718 }
719
720 pub fn get_amount_of_accessed_addresses_for_segment(
721 &self,
722 segment_index: usize,
723 ) -> Option<usize> {
724 let segment = self.data.get(segment_index)?;
725 Some(
726 segment
727 .iter()
728 .filter(|x| x.is_some() && x.is_accessed())
729 .count(),
730 )
731 }
732
733 pub(crate) fn insert_as_accessed<V>(
736 &mut self,
737 key: Relocatable,
738 val: V,
739 ) -> Result<(), MemoryError>
740 where
741 MaybeRelocatable: From<V>,
742 {
743 self.insert(key, val)?;
744 self.mark_as_accessed(key);
745 Ok(())
746 }
747}
748
749impl From<&Memory> for CairoPieMemory {
750 fn from(mem: &Memory) -> CairoPieMemory {
751 let mut pie_memory = Vec::default();
752 for (i, segment) in mem.data.iter().enumerate() {
753 for (j, cell) in segment.iter().enumerate() {
754 if let Some(value) = cell.get_value() {
755 pie_memory.push(((i, j), value))
756 }
757 }
758 }
759 CairoPieMemory(pie_memory)
760 }
761}
762
763impl fmt::Display for Memory {
764 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
765 for (i, segment) in self.temp_data.iter().enumerate() {
766 for (j, cell) in segment.iter().enumerate() {
767 if let Some(elem) = cell.get_value() {
768 let temp_segment = i + 1;
769 writeln!(f, "(-{temp_segment},{j}) : {elem}")?;
770 }
771 }
772 }
773 for (i, segment) in self.data.iter().enumerate() {
774 for (j, cell) in segment.iter().enumerate() {
775 if let Some(elem) = cell.get_value() {
776 writeln!(f, "({i},{j}) : {elem}")?;
777 }
778 }
779 }
780 Ok(())
781 }
782}
783
784pub(crate) trait RelocateValue<'a, Input: 'a, Output: 'a> {
786 fn relocate_value(&self, value: Input) -> Result<Output, MemoryError>;
787}
788
789#[cfg(not(feature = "extensive_hints"))]
790impl RelocateValue<'_, Relocatable, Relocatable> for Memory {
791 fn relocate_value(&self, addr: Relocatable) -> Result<Relocatable, MemoryError> {
792 if addr.segment_index < 0 {
793 if let Some(x) = self
796 .relocation_rules
797 .get(&(-(addr.segment_index + 1) as usize))
798 {
799 return (*x + addr.offset).map_err(MemoryError::Math);
800 }
801 }
802 Ok(addr)
803 }
804}
805#[cfg(feature = "extensive_hints")]
806impl RelocateValue<'_, Relocatable, MaybeRelocatable> for Memory {
807 fn relocate_value(&self, addr: Relocatable) -> Result<MaybeRelocatable, MemoryError> {
808 if addr.segment_index < 0 {
809 if let Some(x) = self
812 .relocation_rules
813 .get(&(-(addr.segment_index + 1) as usize))
814 {
815 return Ok(match x {
816 MaybeRelocatable::RelocatableValue(r) => {
817 (*r + addr.offset).map_err(MemoryError::Math)?.into()
818 }
819 MaybeRelocatable::Int(i) => i.into(),
820 });
821 }
822 }
823 Ok(addr.into())
824 }
825}
826
827impl<'a> RelocateValue<'a, &'a Felt252, &'a Felt252> for Memory {
828 fn relocate_value(&self, value: &'a Felt252) -> Result<&'a Felt252, MemoryError> {
829 Ok(value)
830 }
831}
832
833impl<'a> RelocateValue<'a, &'a MaybeRelocatable, Cow<'a, MaybeRelocatable>> for Memory {
834 fn relocate_value(
835 &self,
836 value: &'a MaybeRelocatable,
837 ) -> Result<Cow<'a, MaybeRelocatable>, MemoryError> {
838 Ok(match value {
839 MaybeRelocatable::Int(_) => Cow::Borrowed(value),
840 MaybeRelocatable::RelocatableValue(addr) => {
841 #[cfg(not(feature = "extensive_hints"))]
842 let v = self.relocate_value(*addr)?.into();
843 #[cfg(feature = "extensive_hints")]
844 let v = self.relocate_value(*addr)?;
845
846 Cow::Owned(v)
847 }
848 })
849 }
850}
851
852impl Default for Memory {
853 fn default() -> Self {
854 Self::new()
855 }
856}
857
858#[cfg(test)]
859mod memory_tests {
860
861 use super::*;
862 use crate::{
863 felt_hex, relocatable,
864 utils::test_utils::*,
865 vm::{
866 runners::builtin_runner::{
867 RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_STANDARD,
868 },
869 vm_memory::memory_segments::MemorySegmentManager,
870 },
871 };
872 use assert_matches::assert_matches;
873
874 use crate::vm::errors::memory_errors::MemoryError;
875
876 use crate::utils::test_utils::memory_from_memory;
877 use crate::utils::test_utils::memory_inner;
878
879 #[cfg(target_arch = "wasm32")]
880 use wasm_bindgen_test::*;
881
882 #[test]
883 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
884 fn insert_and_get_succesful() {
885 let key = Relocatable::from((0, 0));
886 let val = MaybeRelocatable::from(Felt252::from(5_u64));
887 let mut memory = Memory::new();
888 memory.data.push(Vec::new());
889 memory.insert(key, &val).unwrap();
890 assert_eq!(
891 memory.get(&key).unwrap().as_ref(),
892 &MaybeRelocatable::from(Felt252::from(5_u64))
893 );
894 }
895
896 #[test]
897 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
898 fn get_valuef_from_temp_segment() {
899 let mut memory = Memory::new();
900 memory.temp_data = vec![vec![
901 MemoryCell::NONE,
902 MemoryCell::NONE,
903 MemoryCell::new(mayberelocatable!(8)),
904 ]];
905 assert_eq!(
906 memory.get(&mayberelocatable!(-1, 2)).unwrap().as_ref(),
907 &mayberelocatable!(8),
908 );
909 }
910
911 #[test]
912 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
913 fn insert_value_in_temp_segment() {
914 let key = Relocatable::from((-1, 3));
915 let val = MaybeRelocatable::from(Felt252::from(8_u64));
916 let mut memory = Memory::new();
917 memory.temp_data.push(Vec::new());
918 memory.insert(key, &val).unwrap();
919 assert_eq!(
920 memory.temp_data[0][3],
921 MemoryCell::new(MaybeRelocatable::from(Felt252::from(8_u64)))
922 );
923 }
924
925 #[test]
926 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
927 fn insert_and_get_from_temp_segment_succesful() {
928 let key = Relocatable::from((-1, 0));
929 let val = MaybeRelocatable::from(Felt252::from(5_u64));
930 let mut memory = Memory::new();
931 memory.temp_data.push(Vec::new());
932 memory.insert(key, &val).unwrap();
933 assert_eq!(
934 memory.get(&key).unwrap().as_ref(),
935 &MaybeRelocatable::from(Felt252::from(5_u64)),
936 );
937 }
938
939 #[test]
940 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
941 fn insert_and_get_from_temp_segment_failed() {
942 let key = relocatable!(-1, 1);
943 let mut memory = Memory::new();
944 memory.temp_data = vec![vec![
945 MemoryCell::NONE,
946 MemoryCell::new(mayberelocatable!(8)),
947 ]];
948 assert_eq!(
949 memory.insert(key, &mayberelocatable!(5)),
950 Err(MemoryError::InconsistentMemory(Box::new((
951 relocatable!(-1, 1),
952 mayberelocatable!(8),
953 mayberelocatable!(5)
954 ))))
955 );
956 }
957
958 #[test]
959 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
960 fn get_non_allocated_memory() {
961 let key = Relocatable::from((0, 0));
962 let memory = Memory::new();
963 assert_eq!(memory.get(&key), None);
964 }
965
966 #[test]
967 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
968 fn get_non_existant_element() {
969 let key = Relocatable::from((0, 0));
970 let memory = Memory::new();
971 assert_eq!(memory.get(&key), None);
972 }
973
974 #[test]
975 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
976 fn insert_non_allocated_memory() {
977 let key = Relocatable::from((0, 0));
978 let val = MaybeRelocatable::from(Felt252::from(5_u64));
979 let mut memory = Memory::new();
980 let error = memory.insert(key, &val);
981 assert_eq!(
982 error,
983 Err(MemoryError::UnallocatedSegment(Box::new((0, 0))))
984 );
985 }
986
987 #[test]
988 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
989 fn insert_inconsistent_memory() {
990 let key = Relocatable::from((0, 0));
991 let val_a = MaybeRelocatable::from(Felt252::from(5_u64));
992 let val_b = MaybeRelocatable::from(Felt252::from(6_u64));
993 let mut memory = Memory::new();
994 memory.data.push(Vec::new());
995 memory
996 .insert(key, &val_a)
997 .expect("Unexpected memory insert fail");
998 let error = memory.insert(key, &val_b);
999 assert_eq!(
1000 error,
1001 Err(MemoryError::InconsistentMemory(Box::new((
1002 key, val_a, val_b
1003 ))))
1004 );
1005 }
1006
1007 #[test]
1008 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1009 fn insert_non_contiguous_element() {
1010 let key_a = Relocatable::from((0, 0));
1011 let key_b = Relocatable::from((0, 2));
1012 let val = MaybeRelocatable::from(Felt252::from(5_u64));
1013 let mut memory = Memory::new();
1014 memory.data.push(Vec::new());
1015 memory.insert(key_a, &val).unwrap();
1016 memory.insert(key_b, &val).unwrap();
1017 assert_eq!(memory.get(&key_b).unwrap().as_ref(), &val);
1018 }
1019
1020 #[test]
1021 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1022 fn insert_non_contiguous_element_memory_gaps_none() {
1023 let key_a = Relocatable::from((0, 0));
1024 let key_b = Relocatable::from((0, 5));
1025 let val = MaybeRelocatable::from(Felt252::from(5_u64));
1026 let mut memory = Memory::new();
1027 memory.data.push(Vec::new());
1028 memory.insert(key_a, &val).unwrap();
1029 memory.insert(key_b, &val).unwrap();
1030 assert_eq!(memory.get(&key_b).unwrap().as_ref(), &val);
1031 assert_eq!(memory.get(&MaybeRelocatable::from((0, 1))), None);
1032 assert_eq!(memory.get(&MaybeRelocatable::from((0, 2))), None);
1033 assert_eq!(memory.get(&MaybeRelocatable::from((0, 3))), None);
1034 assert_eq!(memory.get(&MaybeRelocatable::from((0, 4))), None);
1035 }
1036
1037 #[test]
1038 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1039 fn validate_existing_memory_for_range_check_within_bounds() {
1040 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1041 let mut segments = MemorySegmentManager::new();
1042 builtin.initialize_segments(&mut segments);
1043 builtin.add_validation_rule(&mut segments.memory);
1044 for _ in 0..3 {
1045 segments.add();
1046 }
1047
1048 segments
1049 .memory
1050 .insert(
1051 Relocatable::from((0, 0)),
1052 &MaybeRelocatable::from(Felt252::from(45_u64)),
1053 )
1054 .unwrap();
1055 segments.memory.validate_existing_memory().unwrap();
1056 assert!(segments
1057 .memory
1058 .validated_addresses
1059 .contains(&Relocatable::from((0, 0))));
1060 }
1061
1062 #[test]
1063 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1064 fn validate_existing_memory_for_range_check_outside_bounds() {
1065 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1066 let mut segments = MemorySegmentManager::new();
1067 segments.add();
1068 builtin.initialize_segments(&mut segments);
1069 segments
1070 .memory
1071 .insert(
1072 Relocatable::from((1, 0)),
1073 &MaybeRelocatable::from(Felt252::from(-10)),
1074 )
1075 .unwrap();
1076 builtin.add_validation_rule(&mut segments.memory);
1077 let error = segments.memory.validate_existing_memory();
1078 assert_eq!(
1079 error,
1080 Err(MemoryError::RangeCheckNumOutOfBounds(Box::new((
1081 Felt252::from(-10),
1082 Felt252::TWO.pow(128_u128)
1083 ))))
1084 );
1085 }
1086
1087 #[test]
1088 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1089 fn validate_existing_memory_for_invalid_signature() {
1090 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
1091 let mut segments = MemorySegmentManager::new();
1092 builtin.initialize_segments(&mut segments);
1093 segments.memory = memory![
1094 (
1095 (0, 0),
1096 (
1097 "874739451078007766457464989774322083649278607533249481151382481072868806602",
1098 10
1099 )
1100 ),
1101 (
1102 (0, 1),
1103 (
1104 "-1472574760335685482768423018116732869320670550222259018541069375211356613248",
1105 10
1106 )
1107 )
1108 ];
1109 builtin.add_validation_rule(&mut segments.memory);
1110 let error = segments.memory.validate_existing_memory();
1111 assert_eq!(
1112 error,
1113 Err(MemoryError::SignatureNotFound(Box::new((0, 0).into())))
1114 );
1115 }
1116
1117 #[test]
1118 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1119 fn validate_existing_memory_for_valid_signature() {
1120 let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
1121
1122 let signature_r =
1123 felt_hex!("0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20");
1124 let signature_s =
1125 felt_hex!("0x405c3191ab3883ef2b763af35bc5f5d15b3b4e99461d70e84c654a351a7c81b");
1126
1127 builtin
1128 .add_signature(Relocatable::from((1, 0)), &(signature_r, signature_s))
1129 .unwrap();
1130
1131 let mut segments = MemorySegmentManager::new();
1132
1133 segments.memory = memory![
1134 (
1135 (1, 0),
1136 (
1137 "874739451078007766457464989774322083649278607533249481151382481072868806602",
1138 10
1139 )
1140 ),
1141 ((1, 1), 2)
1142 ];
1143
1144 builtin.initialize_segments(&mut segments);
1145
1146 builtin.add_validation_rule(&mut segments.memory);
1147
1148 let result = segments.memory.validate_existing_memory();
1149
1150 assert_eq!(result, Ok(()))
1151 }
1152
1153 #[test]
1154 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1155 fn validate_existing_memory_for_range_check_relocatable_value() {
1156 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1157 let mut segments = MemorySegmentManager::new();
1158 builtin.initialize_segments(&mut segments);
1159 segments.memory = memory![((0, 0), (0, 4))];
1160 builtin.add_validation_rule(&mut segments.memory);
1161 let error = segments.memory.validate_existing_memory();
1162 assert_eq!(
1163 error,
1164 Err(MemoryError::RangeCheckFoundNonInt(Box::new(relocatable!(
1165 0, 0
1166 ))))
1167 );
1168 }
1169
1170 #[test]
1171 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1172 fn validate_existing_memory_for_range_check_out_of_bounds_diff_segment() {
1173 let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1174 let mut segments = MemorySegmentManager::new();
1175 segments.memory = Memory::new();
1176 segments.add();
1177 builtin.initialize_segments(&mut segments);
1178 segments
1179 .memory
1180 .insert(
1181 Relocatable::from((0, 0)),
1182 &MaybeRelocatable::from(Felt252::from(-45_i128)),
1183 )
1184 .unwrap();
1185 builtin.add_validation_rule(&mut segments.memory);
1186 assert_eq!(segments.memory.validate_existing_memory(), Ok(()));
1187 }
1188
1189 #[test]
1190 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1191 fn get_integer_valid() {
1192 let memory = memory![((0, 0), 10)];
1193 assert_eq!(
1194 memory
1195 .get_integer(Relocatable::from((0, 0)))
1196 .unwrap()
1197 .as_ref(),
1198 &Felt252::from(10)
1199 );
1200 }
1201
1202 #[test]
1203 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1204 fn get_integer_invalid_expected_integer() {
1205 let mut segments = MemorySegmentManager::new();
1206 segments.add();
1207 segments
1208 .memory
1209 .insert(Relocatable::from((0, 0)), &MaybeRelocatable::from((0, 10)))
1210 .unwrap();
1211 assert_matches!(
1212 segments.memory.get_integer(Relocatable::from((0, 0))),
1213 Err(MemoryError::ExpectedInteger(
1214 bx
1215 )) if *bx == Relocatable::from((0, 0))
1216 );
1217 }
1218
1219 #[test]
1220 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1221 fn get_u32_too_big() {
1222 let mut segments = MemorySegmentManager::new();
1223 segments.add();
1224 segments
1225 .memory
1226 .insert(Relocatable::from((0, 0)), &Felt252::from(1_u64 << 32))
1227 .unwrap();
1228 assert_matches!(
1229 segments.memory.get_u32(Relocatable::from((0, 0))),
1230 Err(MemoryError::Math(MathError::Felt252ToU32Conversion(
1231 bx
1232 ))) if *bx == Felt252::from(1_u64 << 32)
1233 );
1234 }
1235
1236 #[test]
1237 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1238 fn get_maybe_relocatable_valid_relocatable() {
1239 let memory = memory![((0, 0), (1, 0))];
1240 assert_eq!(
1241 memory
1242 .get_maybe_relocatable(Relocatable::from((0, 0)))
1243 .unwrap(),
1244 Relocatable::from((1, 0)).into()
1245 );
1246 }
1247
1248 #[test]
1249 fn get_maybe_relocatable_valid_integer() {
1250 let memory = memory![((0, 0), 10)];
1251 assert_eq!(
1252 memory
1253 .get_maybe_relocatable(Relocatable::from((0, 0)))
1254 .unwrap(),
1255 10.into()
1256 );
1257 }
1258
1259 #[test]
1260 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1261 fn default_memory() {
1262 let mem: Memory = Default::default();
1263 assert_eq!(mem.data.len(), 0);
1264 }
1265
1266 #[test]
1267 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1268 fn insert_and_get_temporary_succesful() {
1269 let mut memory = Memory::new();
1270 memory.temp_data.push(Vec::new());
1271
1272 let key = Relocatable::from((-1, 0));
1273 let val = MaybeRelocatable::from(Felt252::from(5));
1274 memory.insert(key, &val).unwrap();
1275
1276 assert_eq!(memory.get(&key).unwrap().as_ref(), &val);
1277 }
1278
1279 #[test]
1280 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1281 fn add_relocation_rule() {
1282 let mut memory = Memory::new();
1283
1284 assert_eq!(
1285 memory.add_relocation_rule((-1, 0).into(), (1, 2).into()),
1286 Ok(()),
1287 );
1288 assert_eq!(
1289 memory.add_relocation_rule((-2, 0).into(), (-1, 1).into()),
1290 Ok(()),
1291 );
1292 assert_eq!(
1293 memory.add_relocation_rule((5, 0).into(), (0, 0).into()),
1294 Err(MemoryError::AddressNotInTemporarySegment(5)),
1295 );
1296 assert_eq!(
1297 memory.add_relocation_rule((-3, 6).into(), (0, 0).into()),
1298 Err(MemoryError::NonZeroOffset(6)),
1299 );
1300 assert_eq!(
1301 memory.add_relocation_rule((-1, 0).into(), (0, 0).into()),
1302 Err(MemoryError::DuplicatedRelocation(-1)),
1303 );
1304 }
1305
1306 #[test]
1307 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1308 fn relocate_value_bigint() {
1309 let mut memory = Memory::new();
1310 memory
1311 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1312 .unwrap();
1313 memory
1314 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1315 .unwrap();
1316
1317 assert_eq!(
1319 memory
1320 .relocate_value(&MaybeRelocatable::Int(Felt252::from(0)))
1321 .unwrap(),
1322 Cow::Owned(MaybeRelocatable::Int(Felt252::from(0))),
1323 );
1324 }
1325
1326 #[test]
1327 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1328 fn relocate_value_mayberelocatable() {
1329 let mut memory = Memory::new();
1330 memory
1331 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1332 .unwrap();
1333 memory
1334 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1335 .unwrap();
1336
1337 assert_eq!(
1339 memory
1340 .relocate_value(&MaybeRelocatable::RelocatableValue((0, 0).into()))
1341 .unwrap(),
1342 Cow::Owned(MaybeRelocatable::RelocatableValue((0, 0).into())),
1343 );
1344 assert_eq!(
1345 memory
1346 .relocate_value(&MaybeRelocatable::RelocatableValue((5, 0).into()))
1347 .unwrap(),
1348 Cow::Owned(MaybeRelocatable::RelocatableValue((5, 0).into())),
1349 );
1350 }
1351
1352 #[test]
1353 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1354 fn relocate_value_mayberelocatable_temporary_segment_no_rules() {
1355 let mut memory = Memory::new();
1356 memory
1357 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1358 .unwrap();
1359 memory
1360 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1361 .unwrap();
1362
1363 assert_eq!(
1366 memory
1367 .relocate_value(&MaybeRelocatable::RelocatableValue((-5, 0).into()))
1368 .unwrap(),
1369 Cow::Owned(MaybeRelocatable::RelocatableValue((-5, 0).into())),
1370 );
1371 }
1372
1373 #[test]
1374 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1375 fn relocate_value_mayberelocatable_temporary_segment_rules() {
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!(
1387 memory
1388 .relocate_value(&MaybeRelocatable::RelocatableValue((-1, 0).into()))
1389 .unwrap(),
1390 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 0).into())),
1391 );
1392 assert_eq!(
1393 memory
1394 .relocate_value(&MaybeRelocatable::RelocatableValue((-2, 0).into()))
1395 .unwrap(),
1396 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 2).into())),
1397 );
1398 assert_eq!(
1399 memory
1400 .relocate_value(&MaybeRelocatable::RelocatableValue((-1, 5).into()))
1401 .unwrap(),
1402 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 5).into())),
1403 );
1404 assert_eq!(
1405 memory
1406 .relocate_value(&MaybeRelocatable::RelocatableValue((-2, 5).into()))
1407 .unwrap(),
1408 Cow::Owned(MaybeRelocatable::RelocatableValue((2, 7).into())),
1409 );
1410 }
1411
1412 #[test]
1413 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1414 fn get_range_for_continuous_memory() {
1415 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
1416
1417 let value1 = MaybeRelocatable::from(Felt252::from(2));
1418 let value2 = MaybeRelocatable::from(Felt252::from(3));
1419 let value3 = MaybeRelocatable::from(Felt252::from(4));
1420
1421 let expected_vec = vec![
1422 Some(Cow::Borrowed(&value1)),
1423 Some(Cow::Borrowed(&value2)),
1424 Some(Cow::Borrowed(&value3)),
1425 ];
1426 assert_eq!(memory.get_range(Relocatable::from((1, 0)), 3), expected_vec);
1427 }
1428
1429 #[test]
1430 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1431 fn get_range_for_non_continuous_memory() {
1432 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
1433
1434 let value1 = MaybeRelocatable::from(Felt252::from(2));
1435 let value2 = MaybeRelocatable::from(Felt252::from(3));
1436 let value3 = MaybeRelocatable::from(Felt252::from(4));
1437
1438 let expected_vec = vec![
1439 Some(Cow::Borrowed(&value1)),
1440 Some(Cow::Borrowed(&value2)),
1441 None,
1442 Some(Cow::Borrowed(&value3)),
1443 ];
1444 assert_eq!(memory.get_range(Relocatable::from((1, 0)), 4), expected_vec);
1445 }
1446
1447 #[test]
1448 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1449 fn get_continuous_range_for_continuous_memory() {
1450 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
1451
1452 let value1 = MaybeRelocatable::from(Felt252::from(2));
1453 let value2 = MaybeRelocatable::from(Felt252::from(3));
1454 let value3 = MaybeRelocatable::from(Felt252::from(4));
1455
1456 let expected_vec = vec![value1, value2, value3];
1457 assert_eq!(
1458 memory.get_continuous_range(Relocatable::from((1, 0)), 3),
1459 Ok(expected_vec)
1460 );
1461 }
1462
1463 #[test]
1464 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1465 fn get_continuous_range_for_non_continuous_memory() {
1466 let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
1467
1468 assert_eq!(
1469 memory.get_continuous_range(Relocatable::from((1, 0)), 3),
1470 Err(MemoryError::GetRangeMemoryGap(Box::new(((1, 0).into(), 3))))
1471 );
1472 }
1473
1474 #[test]
1475 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1476 fn get_u32_range_ok() {
1477 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)];
1478 let expected_vector = vec![1, 4294967295];
1479 assert_eq!(memory.get_u32_range((0, 1).into(), 2), Ok(expected_vector));
1480 }
1481
1482 #[test]
1483 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1484 fn get_u32_range_relocatable() {
1485 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)];
1486 assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into());
1487 }
1488
1489 #[test]
1490 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1491 fn get_u32_range_over_32_bits() {
1492 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)];
1493 assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64));
1494 }
1495
1496 #[test]
1497 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1498 fn get_u32_range_memory_gap() {
1499 let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)];
1500 assert_matches!(memory.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into());
1501 }
1502
1503 #[test]
1505 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1506 fn relocate_memory_empty_relocation_rules() {
1507 let mut memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3)];
1508
1509 assert_eq!(memory.relocate_memory(), Ok(()));
1510 check_memory!(memory, ((0, 0), 1), ((0, 1), 2), ((0, 2), 3));
1511 }
1512
1513 #[test]
1514 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1515 fn relocate_memory_new_segment_with_gap() {
1516 let mut memory = memory![
1517 ((0, 0), 1),
1518 ((0, 1), (-1, 0)),
1519 ((0, 2), 3),
1520 ((1, 0), (-1, 1)),
1521 ((1, 1), 5),
1522 ((1, 2), (-1, 2)),
1523 ((-1, 0), 7),
1524 ((-1, 1), 8),
1525 ((-1, 2), 9)
1526 ];
1527 memory
1528 .add_relocation_rule((-1, 0).into(), (2, 1).into())
1529 .unwrap();
1530 memory.data.push(vec![]);
1531
1532 assert_eq!(memory.relocate_memory(), Ok(()));
1533 check_memory!(
1534 memory,
1535 ((0, 0), 1),
1536 ((0, 1), (2, 1)),
1537 ((0, 2), 3),
1538 ((1, 0), (2, 2)),
1539 ((1, 1), 5),
1540 ((1, 2), (2, 3)),
1541 ((2, 1), 7),
1542 ((2, 2), 8),
1543 ((2, 3), 9)
1544 );
1545 assert!(memory.temp_data.is_empty());
1546 }
1547
1548 #[test]
1549 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1550 fn relocate_memory_new_segment() {
1551 let mut memory = memory![
1552 ((0, 0), 1),
1553 ((0, 1), (-1, 0)),
1554 ((0, 2), 3),
1555 ((1, 0), (-1, 1)),
1556 ((1, 1), 5),
1557 ((1, 2), (-1, 2)),
1558 ((-1, 0), 7),
1559 ((-1, 1), 8),
1560 ((-1, 2), 9)
1561 ];
1562 memory
1563 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1564 .unwrap();
1565 memory.data.push(vec![]);
1566
1567 assert_eq!(memory.relocate_memory(), Ok(()));
1568
1569 check_memory!(
1570 memory,
1571 ((0, 0), 1),
1572 ((0, 1), (2, 0)),
1573 ((0, 2), 3),
1574 ((1, 0), (2, 1)),
1575 ((1, 1), 5),
1576 ((1, 2), (2, 2)),
1577 ((2, 0), 7),
1578 ((2, 1), 8),
1579 ((2, 2), 9)
1580 );
1581 assert!(memory.temp_data.is_empty());
1582 }
1583
1584 #[test]
1585 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1586 fn relocate_memory_new_segment_unallocated() {
1587 let mut memory = memory![
1588 ((0, 0), 1),
1589 ((0, 1), (-1, 0)),
1590 ((0, 2), 3),
1591 ((1, 0), (-1, 1)),
1592 ((1, 1), 5),
1593 ((1, 2), (-1, 2)),
1594 ((-1, 0), 7),
1595 ((-1, 1), 8),
1596 ((-1, 2), 9)
1597 ];
1598 memory
1599 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1600 .unwrap();
1601
1602 assert_eq!(
1603 memory.relocate_memory(),
1604 Err(MemoryError::UnallocatedSegment(Box::new((2, 2))))
1605 );
1606 }
1607
1608 #[test]
1609 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1610 fn relocate_memory_into_existing_segment() {
1611 let mut memory = memory![
1612 ((0, 0), 1),
1613 ((0, 1), (-1, 0)),
1614 ((0, 2), 3),
1615 ((1, 0), (-1, 1)),
1616 ((1, 1), 5),
1617 ((1, 2), (-1, 2)),
1618 ((-1, 0), 7),
1619 ((-1, 1), 8),
1620 ((-1, 2), 9)
1621 ];
1622 memory
1623 .add_relocation_rule((-1, 0).into(), (1, 3).into())
1624 .unwrap();
1625
1626 assert_eq!(memory.relocate_memory(), Ok(()));
1627
1628 check_memory!(
1629 memory,
1630 ((0, 0), 1),
1631 ((0, 1), (1, 3)),
1632 ((0, 2), 3),
1633 ((1, 0), (1, 4)),
1634 ((1, 1), 5),
1635 ((1, 2), (1, 5)),
1636 ((1, 3), 7),
1637 ((1, 4), 8),
1638 ((1, 5), 9)
1639 );
1640 assert!(memory.temp_data.is_empty());
1641 }
1642
1643 #[test]
1644 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1645 fn relocate_memory_into_existing_segment_inconsistent_memory() {
1646 let mut memory = memory![
1647 ((0, 0), 1),
1648 ((0, 1), (-1, 0)),
1649 ((0, 2), 3),
1650 ((1, 0), (-1, 1)),
1651 ((1, 1), 5),
1652 ((1, 2), (-1, 2)),
1653 ((-1, 0), 7),
1654 ((-1, 1), 8),
1655 ((-1, 2), 9)
1656 ];
1657 memory
1658 .add_relocation_rule((-1, 0).into(), (1, 0).into())
1659 .unwrap();
1660
1661 assert_eq!(
1662 memory.relocate_memory(),
1663 Err(MemoryError::InconsistentMemory(Box::new((
1664 (1, 0).into(),
1665 (1, 1).into(),
1666 7.into(),
1667 ))))
1668 );
1669 }
1670
1671 #[test]
1672 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1673 fn relocate_memory_new_segment_2_temporary_segments_one_relocated() {
1674 let mut memory = memory![
1675 ((0, 0), 1),
1676 ((0, 1), (-1, 0)),
1677 ((0, 2), 3),
1678 ((1, 0), (-1, 1)),
1679 ((1, 1), 5),
1680 ((1, 2), (-1, 2)),
1681 ((-1, 0), 7),
1682 ((-1, 1), 8),
1683 ((-1, 2), 9),
1684 ((-2, 0), 10),
1685 ((-2, 1), 11)
1686 ];
1687 memory
1688 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1689 .unwrap();
1690 memory.data.push(vec![]);
1691
1692 assert_eq!(memory.relocate_memory(), Ok(()));
1693 check_memory!(
1694 memory,
1695 ((0, 0), 1),
1696 ((0, 1), (2, 0)),
1697 ((0, 2), 3),
1698 ((1, 0), (2, 1)),
1699 ((1, 1), 5),
1700 ((1, 2), (2, 2)),
1701 ((2, 0), 7),
1702 ((2, 1), 8),
1703 ((2, 2), 9),
1704 ((-1, 0), 10),
1705 ((-1, 1), 11)
1706 );
1707 }
1708
1709 #[test]
1710 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1711 fn relocate_memory_new_segment_2_temporary_segments_relocated() {
1712 let mut memory = memory![
1713 ((0, 0), 1),
1714 ((0, 1), (-1, 0)),
1715 ((0, 2), 3),
1716 ((1, 0), (-1, 1)),
1717 ((1, 1), 5),
1718 ((1, 2), (-1, 2)),
1719 ((-1, 0), 7),
1720 ((-1, 1), 8),
1721 ((-1, 2), 9),
1722 ((-2, 0), 10),
1723 ((-2, 1), 11)
1724 ];
1725 memory.data.push(vec![]);
1726 memory
1727 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1728 .unwrap();
1729 memory.data.push(vec![]);
1730 memory
1731 .add_relocation_rule((-2, 0).into(), (3, 0).into())
1732 .unwrap();
1733
1734 assert_eq!(memory.relocate_memory(), Ok(()));
1735
1736 check_memory!(
1737 memory,
1738 ((0, 0), 1),
1739 ((0, 1), (2, 0)),
1740 ((0, 2), 3),
1741 ((1, 0), (2, 1)),
1742 ((1, 1), 5),
1743 ((1, 2), (2, 2)),
1744 ((2, 0), 7),
1745 ((2, 1), 8),
1746 ((2, 2), 9),
1747 ((3, 0), 10),
1748 ((3, 1), 11)
1749 );
1750 assert!(memory.temp_data.is_empty());
1751 }
1752
1753 #[test]
1754 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1755 fn test_memory_display() {
1756 let memory = memory![
1757 ((0, 0), 1),
1758 ((0, 1), (-1, 0)),
1759 ((0, 2), 3),
1760 ((1, 0), (-1, 1)),
1761 ((1, 1), 5),
1762 ((1, 2), (-1, 2)),
1763 ((-1, 0), (-1, 0)),
1764 ((-1, 1), 8),
1765 ((-1, 2), 9)
1766 ];
1767
1768 assert_eq!(
1769 format!("{}", memory),
1770 "(-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");
1771 }
1772
1773 #[test]
1774 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1775 fn relocate_memory_into_existing_segment_temporary_values_in_temporary_memory() {
1776 let mut memory = memory![
1777 ((0, 0), 1),
1778 ((0, 1), (-1, 0)),
1779 ((0, 2), 3),
1780 ((1, 0), (-1, 1)),
1781 ((1, 1), 5),
1782 ((1, 2), (-1, 2)),
1783 ((-1, 0), (-1, 0)),
1784 ((-1, 1), 8),
1785 ((-1, 2), 9)
1786 ];
1787 memory
1788 .add_relocation_rule((-1, 0).into(), (1, 3).into())
1789 .unwrap();
1790
1791 assert_eq!(memory.relocate_memory(), Ok(()));
1792 check_memory!(
1793 memory,
1794 ((0, 0), 1),
1795 ((0, 1), (1, 3)),
1796 ((0, 2), 3),
1797 ((1, 0), (1, 4)),
1798 ((1, 1), 5),
1799 ((1, 2), (1, 5)),
1800 ((1, 3), (1, 3)),
1801 ((1, 4), 8),
1802 ((1, 5), 9)
1803 );
1804 assert!(memory.temp_data.is_empty());
1805 }
1806
1807 #[test]
1808 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1809 fn relocate_address_with_rules() {
1810 let mut memory = Memory::new();
1811 memory
1812 .add_relocation_rule((-1, 0).into(), (2, 0).into())
1813 .unwrap();
1814 memory
1815 .add_relocation_rule((-2, 0).into(), (2, 2).into())
1816 .unwrap();
1817
1818 assert_eq!(
1819 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1820 MaybeRelocatable::RelocatableValue((2, 0).into()),
1821 );
1822 assert_eq!(
1823 Memory::relocate_address((-2, 1).into(), &memory.relocation_rules).unwrap(),
1824 MaybeRelocatable::RelocatableValue((2, 3).into()),
1825 );
1826 }
1827
1828 #[test]
1829 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1830 fn relocate_address_no_rules() {
1831 let memory = Memory::new();
1832 assert_eq!(
1833 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1834 MaybeRelocatable::RelocatableValue((-1, 0).into()),
1835 );
1836 assert_eq!(
1837 Memory::relocate_address((-2, 1).into(), &memory.relocation_rules).unwrap(),
1838 MaybeRelocatable::RelocatableValue((-2, 1).into()),
1839 );
1840 }
1841
1842 #[test]
1843 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1844 fn relocate_address_real_addr() {
1845 let memory = Memory::new();
1846 assert_eq!(
1847 Memory::relocate_address((1, 0).into(), &memory.relocation_rules).unwrap(),
1848 MaybeRelocatable::RelocatableValue((1, 0).into()),
1849 );
1850 assert_eq!(
1851 Memory::relocate_address((1, 1).into(), &memory.relocation_rules).unwrap(),
1852 MaybeRelocatable::RelocatableValue((1, 1).into()),
1853 );
1854 }
1855
1856 #[test]
1857 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1858 #[cfg(feature = "extensive_hints")]
1859 fn relocate_address_to_integer() {
1860 let mut memory = Memory::new();
1861 memory
1862 .add_relocation_rule((-1, 0).into(), 0.into())
1863 .unwrap();
1864 memory
1865 .add_relocation_rule((-2, 0).into(), 42.into())
1866 .unwrap();
1867
1868 assert_eq!(
1869 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1870 MaybeRelocatable::Int(0.into()),
1871 );
1872 assert_eq!(
1873 Memory::relocate_address((-2, 0).into(), &memory.relocation_rules).unwrap(),
1874 MaybeRelocatable::Int(42.into()),
1875 );
1876 }
1877
1878 #[test]
1879 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1880 #[cfg(feature = "extensive_hints")]
1881 fn relocate_address_integer_no_duplicates() {
1882 let mut memory = Memory::new();
1883 memory
1884 .add_relocation_rule((-1, 0).into(), 1.into())
1885 .unwrap();
1886 assert_eq!(
1887 memory.add_relocation_rule((-1, 0).into(), 42.into()),
1888 Err(MemoryError::DuplicatedRelocation(-1))
1889 );
1890 assert_eq!(
1891 memory.add_relocation_rule((-1, 0).into(), (2, 0).into()),
1892 Err(MemoryError::DuplicatedRelocation(-1))
1893 );
1894
1895 assert_eq!(
1896 Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1897 MaybeRelocatable::Int(1.into()),
1898 );
1899
1900 memory
1901 .add_relocation_rule((-2, 0).into(), (3, 0).into())
1902 .unwrap();
1903 assert_eq!(
1904 memory.add_relocation_rule((-2, 0).into(), 1.into()),
1905 Err(MemoryError::DuplicatedRelocation(-2))
1906 );
1907
1908 assert_eq!(
1909 Memory::relocate_address((-2, 0).into(), &memory.relocation_rules).unwrap(),
1910 MaybeRelocatable::RelocatableValue((3, 0).into()),
1911 );
1912 }
1913
1914 #[test]
1915 fn mark_address_as_accessed() {
1916 let mut memory = memory![((0, 0), 0)];
1917 assert!(!memory.data[0][0].is_accessed());
1918 memory.mark_as_accessed(relocatable!(0, 0));
1919 assert!(memory.data[0][0].is_accessed());
1920 }
1921
1922 #[test]
1923 fn get_amount_of_accessed_addresses_for_segment_valid() {
1924 let mut memory = memory![((0, 0), 0)];
1925 assert_eq!(
1926 memory.get_amount_of_accessed_addresses_for_segment(0),
1927 Some(0)
1928 );
1929 memory.mark_as_accessed(relocatable!(0, 0));
1930 assert_eq!(
1931 memory.get_amount_of_accessed_addresses_for_segment(0),
1932 Some(1)
1933 );
1934 }
1935
1936 #[test]
1937 fn get_amount_of_accessed_addresses_for_segment_invalid_segment() {
1938 let memory = memory![((0, 0), 0)];
1939 assert_eq!(memory.get_amount_of_accessed_addresses_for_segment(1), None);
1940 }
1941
1942 #[test]
1943 fn memory_cell_new_is_not_accessed() {
1944 let cell = MemoryCell::new(mayberelocatable!(1));
1945 assert!(!cell.is_accessed())
1946 }
1947
1948 #[test]
1949 fn memory_cell_mark_accessed() {
1950 let mut cell = MemoryCell::new(mayberelocatable!(1));
1951 cell.mark_accessed();
1952 assert!(cell.is_accessed())
1953 }
1954
1955 #[test]
1956 fn memory_cell_get_value() {
1957 let cell = MemoryCell::new(mayberelocatable!(1));
1958 assert_eq!(cell.get_value(), Some(mayberelocatable!(1)));
1959 }
1960
1961 use core::cmp::Ordering::*;
1962
1963 fn check_memcmp(
1964 lhs: (isize, usize),
1965 rhs: (isize, usize),
1966 len: usize,
1967 ord: Ordering,
1968 pos: usize,
1969 ) {
1970 let mem = memory![
1971 ((-2, 0), 1),
1972 ((-2, 1), (1, 1)),
1973 ((-2, 3), 0),
1974 ((-2, 4), 0),
1975 ((-1, 0), 1),
1976 ((-1, 1), (1, 1)),
1977 ((-1, 3), 0),
1978 ((-1, 4), 3),
1979 ((0, 0), 1),
1980 ((0, 1), (1, 1)),
1981 ((0, 3), 0),
1982 ((0, 4), 0),
1983 ((1, 0), 1),
1984 ((1, 1), (1, 1)),
1985 ((1, 3), 0),
1986 ((1, 4), 3)
1987 ];
1988 assert_eq!((ord, pos), mem.memcmp(lhs.into(), rhs.into(), len));
1989 }
1990
1991 #[test]
1992 fn insert_alloc_fails_gracefully() {
1993 let mut mem = memory![((0, 0), 1)];
1994 let err = mem.insert((0, usize::MAX >> 1).into(), Felt252::ONE);
1995 assert_eq!(err, Err(MemoryError::VecCapacityExceeded));
1996 }
1997
1998 #[test]
1999 fn insert_overflow_fails_gracefully() {
2000 let mut mem = memory![((0, 0), 1)];
2001 let err = mem.insert((0, usize::MAX).into(), Felt252::ONE);
2002 assert_eq!(err, Err(MemoryError::VecCapacityExceeded));
2003 }
2004
2005 #[test]
2006 fn memcmp() {
2007 check_memcmp((0, 0), (0, 0), 3, Equal, 3);
2008 check_memcmp((0, 0), (1, 0), 3, Equal, 3);
2009 check_memcmp((0, 0), (1, 0), 5, Less, 4);
2010 check_memcmp((1, 0), (0, 0), 5, Greater, 4);
2011 check_memcmp((2, 2), (2, 5), 8, Equal, 0);
2012 check_memcmp((0, 0), (2, 5), 8, Greater, 0);
2013 check_memcmp((2, 5), (0, 0), 8, Less, 0);
2014 check_memcmp((-2, 0), (-2, 0), 3, Equal, 3);
2015 check_memcmp((-2, 0), (-1, 0), 3, Equal, 3);
2016 check_memcmp((-2, 0), (-1, 0), 5, Less, 4);
2017 check_memcmp((-1, 0), (-2, 0), 5, Greater, 4);
2018 check_memcmp((-3, 2), (-3, 5), 8, Equal, 0);
2019 check_memcmp((-2, 0), (-3, 5), 8, Greater, 0);
2020 check_memcmp((-3, 5), (-2, 0), 8, Less, 0);
2021 }
2022
2023 #[test]
2024 fn cairo_pie_memory_from_memory() {
2025 let memory = memory![((8, 9), 3), ((1, 2), 5), ((7, 6), (1, 2))];
2026
2027 assert_eq!(
2028 CairoPieMemory::from(&memory),
2029 CairoPieMemory(vec![
2030 ((1, 2), MaybeRelocatable::from(5)),
2031 ((7, 6), MaybeRelocatable::from((1, 2))),
2032 ((8, 9), MaybeRelocatable::from(3))
2033 ])
2034 )
2035 }
2036}