1use alloc::collections::BTreeMap;
2use alloc::collections::btree_map::Entry;
3use alloc::vec::Vec;
4
5use super::{
6 AccountDeltaError,
7 ByteReader,
8 ByteWriter,
9 Deserializable,
10 DeserializationError,
11 Serializable,
12 Word,
13};
14use crate::account::{
15 StorageMap,
16 StorageMapKey,
17 StorageSlotContent,
18 StorageSlotName,
19 StorageSlotType,
20};
21use crate::{EMPTY_WORD, Felt, ZERO};
22
23#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct AccountStorageDelta {
31 deltas: BTreeMap<StorageSlotName, StorageSlotDelta>,
33}
34
35impl AccountStorageDelta {
36 pub fn new() -> Self {
38 Self { deltas: BTreeMap::new() }
39 }
40
41 pub fn from_raw(deltas: BTreeMap<StorageSlotName, StorageSlotDelta>) -> Self {
43 Self { deltas }
44 }
45
46 pub fn get(&self, slot_name: &StorageSlotName) -> Option<&StorageSlotDelta> {
48 self.deltas.get(slot_name)
49 }
50
51 pub(crate) fn slots(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageSlotDelta)> {
53 self.deltas.iter()
54 }
55
56 pub fn values(&self) -> impl Iterator<Item = (&StorageSlotName, &Word)> {
58 self.deltas.iter().filter_map(|(slot_name, slot_delta)| match slot_delta {
59 StorageSlotDelta::Value(word) => Some((slot_name, word)),
60 StorageSlotDelta::Map(_) => None,
61 })
62 }
63
64 pub fn maps(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageMapDelta)> {
66 self.deltas.iter().filter_map(|(slot_name, slot_delta)| match slot_delta {
67 StorageSlotDelta::Value(_) => None,
68 StorageSlotDelta::Map(map_delta) => Some((slot_name, map_delta)),
69 })
70 }
71
72 pub fn is_empty(&self) -> bool {
74 self.deltas.is_empty()
75 }
76
77 pub fn set_item(
87 &mut self,
88 slot_name: StorageSlotName,
89 new_slot_value: Word,
90 ) -> Result<(), AccountDeltaError> {
91 if !self.deltas.get(&slot_name).map(StorageSlotDelta::is_value).unwrap_or(true) {
92 return Err(AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name));
93 }
94
95 self.deltas.insert(slot_name, StorageSlotDelta::Value(new_slot_value));
96
97 Ok(())
98 }
99
100 pub fn set_map_item(
110 &mut self,
111 slot_name: StorageSlotName,
112 key: StorageMapKey,
113 new_value: Word,
114 ) -> Result<(), AccountDeltaError> {
115 match self
116 .deltas
117 .entry(slot_name.clone())
118 .or_insert(StorageSlotDelta::Map(StorageMapDelta::default()))
119 {
120 StorageSlotDelta::Value(_) => {
121 return Err(AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name));
122 },
123 StorageSlotDelta::Map(storage_map_delta) => {
124 storage_map_delta.insert(key, new_value);
125 },
126 };
127
128 Ok(())
129 }
130
131 pub fn insert_empty_map_delta(&mut self, slot_name: StorageSlotName) {
137 self.deltas.insert(slot_name, StorageSlotDelta::with_empty_map());
138 }
139
140 pub fn merge(&mut self, other: Self) -> Result<(), AccountDeltaError> {
142 for (slot_name, slot_delta) in other.deltas {
143 match self.deltas.entry(slot_name.clone()) {
144 Entry::Vacant(vacant_entry) => {
145 vacant_entry.insert(slot_delta);
146 },
147 Entry::Occupied(mut occupied_entry) => {
148 occupied_entry.get_mut().merge(slot_delta).ok_or_else(|| {
149 AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name)
150 })?;
151 },
152 }
153 }
154
155 Ok(())
156 }
157
158 fn cleared_values(&self) -> impl Iterator<Item = &StorageSlotName> {
160 self.values().filter_map(
161 |(slot_name, slot_value)| {
162 if slot_value.is_empty() { Some(slot_name) } else { None }
163 },
164 )
165 }
166
167 fn updated_values(&self) -> impl Iterator<Item = (&StorageSlotName, &Word)> {
169 self.values().filter_map(|(slot_name, slot_value)| {
170 if !slot_value.is_empty() {
171 Some((slot_name, slot_value))
172 } else {
173 None
174 }
175 })
176 }
177
178 pub(super) fn append_delta_elements(&self, elements: &mut Vec<Felt>) {
181 const DOMAIN_VALUE: Felt = Felt::new(2);
182 const DOMAIN_MAP: Felt = Felt::new(3);
183
184 for (slot_name, slot_delta) in self.deltas.iter() {
185 let slot_id = slot_name.id();
186
187 match slot_delta {
188 StorageSlotDelta::Value(new_value) => {
189 elements.extend_from_slice(&[
190 DOMAIN_VALUE,
191 ZERO,
192 slot_id.suffix(),
193 slot_id.prefix(),
194 ]);
195 elements.extend_from_slice(new_value.as_elements());
196 },
197 StorageSlotDelta::Map(map_delta) => {
198 for (key, value) in map_delta.entries() {
199 elements.extend_from_slice(key.as_elements());
200 elements.extend_from_slice(value.as_elements());
201 }
202
203 let num_changed_entries = Felt::try_from(map_delta.num_entries() as u64)
204 .expect(
205 "number of changed entries should not exceed max representable felt",
206 );
207
208 elements.extend_from_slice(&[
209 DOMAIN_MAP,
210 num_changed_entries,
211 slot_id.suffix(),
212 slot_id.prefix(),
213 ]);
214 elements.extend_from_slice(EMPTY_WORD.as_elements());
215 },
216 }
217 }
218 }
219
220 pub fn into_map(self) -> BTreeMap<StorageSlotName, StorageSlotDelta> {
222 self.deltas
223 }
224}
225
226impl Default for AccountStorageDelta {
227 fn default() -> Self {
228 Self::new()
229 }
230}
231
232impl Serializable for AccountStorageDelta {
233 fn write_into<W: ByteWriter>(&self, target: &mut W) {
234 let num_cleared_values = self.cleared_values().count();
235 let num_cleared_values =
236 u8::try_from(num_cleared_values).expect("number of slots should fit in u8");
237 let cleared_values = self.cleared_values();
238
239 let num_updated_values = self.updated_values().count();
240 let num_updated_values =
241 u8::try_from(num_updated_values).expect("number of slots should fit in u8");
242 let updated_values = self.updated_values();
243
244 let num_maps = self.maps().count();
245 let num_maps = u8::try_from(num_maps).expect("number of slots should fit in u8");
246 let maps = self.maps();
247
248 target.write_u8(num_cleared_values);
249 target.write_many(cleared_values);
250
251 target.write_u8(num_updated_values);
252 target.write_many(updated_values);
253
254 target.write_u8(num_maps);
255 target.write_many(maps);
256 }
257
258 fn get_size_hint(&self) -> usize {
259 let u8_size = 0u8.get_size_hint();
260
261 let mut storage_map_delta_size = 0;
262 for (slot_name, storage_map_delta) in self.maps() {
263 storage_map_delta_size += slot_name.get_size_hint() + storage_map_delta.get_size_hint();
266 }
267
268 u8_size * 3 +
270 self.cleared_values().fold(0, |acc, slot_name| acc + slot_name.get_size_hint()) +
272 self.updated_values().fold(0, |acc, (slot_name, slot_value)| {
274 acc + slot_name.get_size_hint() + slot_value.get_size_hint()
275 }) +
276 storage_map_delta_size
278 }
279}
280
281impl Deserializable for AccountStorageDelta {
282 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
283 let mut deltas = BTreeMap::new();
284
285 let num_cleared_values = source.read_u8()?;
286 for _ in 0..num_cleared_values {
287 let cleared_value: StorageSlotName = source.read()?;
288 deltas.insert(cleared_value, StorageSlotDelta::with_empty_value());
289 }
290
291 let num_updated_values = source.read_u8()?;
292 for _ in 0..num_updated_values {
293 let (updated_slot, updated_value) = source.read()?;
294 deltas.insert(updated_slot, StorageSlotDelta::Value(updated_value));
295 }
296
297 let num_maps = source.read_u8()? as usize;
298 for read_result in source.read_many_iter::<(StorageSlotName, StorageMapDelta)>(num_maps)? {
299 let (slot_name, map_delta) = read_result?;
300 deltas.insert(slot_name, StorageSlotDelta::Map(map_delta));
301 }
302
303 Ok(Self::from_raw(deltas))
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
316pub enum StorageSlotDelta {
317 Value(Word),
318 Map(StorageMapDelta),
319}
320
321impl StorageSlotDelta {
322 const VALUE: u8 = 0;
327
328 const MAP: u8 = 1;
330
331 pub fn with_empty_value() -> Self {
336 Self::Value(Word::empty())
337 }
338
339 pub fn with_empty_map() -> Self {
341 Self::Map(StorageMapDelta::default())
342 }
343
344 pub fn slot_type(&self) -> StorageSlotType {
349 match self {
350 StorageSlotDelta::Value(_) => StorageSlotType::Value,
351 StorageSlotDelta::Map(_) => StorageSlotType::Map,
352 }
353 }
354
355 pub fn is_value(&self) -> bool {
357 matches!(self, Self::Value(_))
358 }
359
360 pub fn is_map(&self) -> bool {
362 matches!(self, Self::Map(_))
363 }
364
365 pub fn unwrap_value(self) -> Word {
375 match self {
376 StorageSlotDelta::Value(value) => value,
377 StorageSlotDelta::Map(_) => panic!("called unwrap_value on a map slot delta"),
378 }
379 }
380
381 pub fn unwrap_map(self) -> StorageMapDelta {
388 match self {
389 StorageSlotDelta::Value(_) => panic!("called unwrap_map on a value slot delta"),
390 StorageSlotDelta::Map(map_delta) => map_delta,
391 }
392 }
393
394 #[must_use]
401 fn merge(&mut self, other: Self) -> Option<()> {
402 match (self, other) {
403 (StorageSlotDelta::Value(current_value), StorageSlotDelta::Value(new_value)) => {
404 *current_value = new_value;
405 },
406 (StorageSlotDelta::Map(current_map_delta), StorageSlotDelta::Map(new_map_delta)) => {
407 current_map_delta.merge(new_map_delta);
408 },
409 (..) => {
410 return None;
411 },
412 }
413
414 Some(())
415 }
416}
417
418impl From<StorageSlotContent> for StorageSlotDelta {
419 fn from(content: StorageSlotContent) -> Self {
420 match content {
421 StorageSlotContent::Value(word) => StorageSlotDelta::Value(word),
422 StorageSlotContent::Map(storage_map) => {
423 StorageSlotDelta::Map(StorageMapDelta::from(storage_map))
424 },
425 }
426 }
427}
428
429impl Serializable for StorageSlotDelta {
430 fn write_into<W: ByteWriter>(&self, target: &mut W) {
431 match self {
432 StorageSlotDelta::Value(value) => {
433 target.write_u8(Self::VALUE);
434 target.write(value);
435 },
436 StorageSlotDelta::Map(storage_map_delta) => {
437 target.write_u8(Self::MAP);
438 target.write(storage_map_delta);
439 },
440 }
441 }
442}
443
444impl Deserializable for StorageSlotDelta {
445 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
446 match source.read_u8()? {
447 Self::VALUE => {
448 let value = source.read()?;
449 Ok(Self::Value(value))
450 },
451 Self::MAP => {
452 let map_delta = source.read()?;
453 Ok(Self::Map(map_delta))
454 },
455 other => Err(DeserializationError::InvalidValue(format!(
456 "unknown storage slot delta variant {other}"
457 ))),
458 }
459 }
460}
461
462#[derive(Clone, Debug, Default, PartialEq, Eq)]
470pub struct StorageMapDelta(BTreeMap<StorageMapKey, Word>);
471
472impl StorageMapDelta {
473 pub fn new(map: BTreeMap<StorageMapKey, Word>) -> Self {
475 Self(map)
476 }
477
478 pub fn num_entries(&self) -> usize {
480 self.0.len()
481 }
482
483 pub fn entries(&self) -> &BTreeMap<StorageMapKey, Word> {
487 &self.0
488 }
489
490 pub fn insert(&mut self, key: StorageMapKey, value: Word) {
492 self.0.insert(key, value);
493 }
494
495 pub fn is_empty(&self) -> bool {
497 self.0.is_empty()
498 }
499
500 pub fn merge(&mut self, other: Self) {
502 self.0.extend(other.0);
504 }
505
506 pub fn as_map_mut(&mut self) -> &mut BTreeMap<StorageMapKey, Word> {
508 &mut self.0
509 }
510
511 fn cleared_keys(&self) -> impl Iterator<Item = &StorageMapKey> + '_ {
513 self.0.iter().filter(|&(_, value)| value.is_empty()).map(|(key, _)| key)
514 }
515
516 fn updated_entries(&self) -> impl Iterator<Item = (&StorageMapKey, &Word)> + '_ {
518 self.0.iter().filter_map(
519 |(key, value)| {
520 if !value.is_empty() { Some((key, value)) } else { None }
521 },
522 )
523 }
524}
525
526#[cfg(any(feature = "testing", test))]
527impl StorageMapDelta {
528 pub fn from_iters(
530 cleared_leaves: impl IntoIterator<Item = StorageMapKey>,
531 updated_leaves: impl IntoIterator<Item = (StorageMapKey, Word)>,
532 ) -> Self {
533 Self(BTreeMap::from_iter(
534 cleared_leaves.into_iter().map(|key| (key, EMPTY_WORD)).chain(updated_leaves),
535 ))
536 }
537
538 pub fn into_map(self) -> BTreeMap<StorageMapKey, Word> {
540 self.0
541 }
542}
543
544impl From<StorageMap> for StorageMapDelta {
546 fn from(map: StorageMap) -> Self {
547 StorageMapDelta::new(map.into_entries().into_iter().collect())
548 }
549}
550
551impl Serializable for StorageMapDelta {
552 fn write_into<W: ByteWriter>(&self, target: &mut W) {
553 let cleared: Vec<&StorageMapKey> = self.cleared_keys().collect();
554 let updated: Vec<(&StorageMapKey, &Word)> = self.updated_entries().collect();
555
556 target.write_usize(cleared.len());
557 target.write_many(cleared.iter());
558
559 target.write_usize(updated.len());
560 target.write_many(updated.iter());
561 }
562
563 fn get_size_hint(&self) -> usize {
564 let cleared_keys_count = self.cleared_keys().count();
565 let updated_entries_count = self.updated_entries().count();
566
567 cleared_keys_count.get_size_hint() +
569 cleared_keys_count * StorageMapKey::SERIALIZED_SIZE +
570
571 updated_entries_count.get_size_hint() +
573 updated_entries_count * (StorageMapKey::SERIALIZED_SIZE + Word::SERIALIZED_SIZE)
574 }
575}
576
577impl Deserializable for StorageMapDelta {
578 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
579 let mut map = BTreeMap::new();
580
581 let cleared_count = source.read_usize()?;
582 for _ in 0..cleared_count {
583 let cleared_key = source.read()?;
584 map.insert(cleared_key, EMPTY_WORD);
585 }
586
587 let updated_count = source.read_usize()?;
588 for _ in 0..updated_count {
589 let (updated_key, updated_value) = source.read()?;
590 map.insert(updated_key, updated_value);
591 }
592
593 Ok(Self::new(map))
594 }
595}
596
597#[cfg(test)]
601mod tests {
602 use anyhow::Context;
603 use assert_matches::assert_matches;
604
605 use super::{AccountStorageDelta, Deserializable, Serializable};
606 use crate::account::{StorageMapDelta, StorageMapKey, StorageSlotDelta, StorageSlotName};
607 use crate::errors::AccountDeltaError;
608 use crate::{ONE, Word};
609
610 #[test]
611 fn account_storage_delta_returns_err_on_slot_type_mismatch() {
612 let value_slot_name = StorageSlotName::mock(1);
613 let map_slot_name = StorageSlotName::mock(2);
614
615 let mut delta = AccountStorageDelta::from_iters(
616 [value_slot_name.clone()],
617 [],
618 [(map_slot_name.clone(), StorageMapDelta::default())],
619 );
620
621 let err = delta
622 .set_map_item(value_slot_name.clone(), StorageMapKey::empty(), Word::empty())
623 .unwrap_err();
624 assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
625 assert_eq!(value_slot_name, slot_name)
626 });
627
628 let err = delta.set_item(map_slot_name.clone(), Word::empty()).unwrap_err();
629 assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
630 assert_eq!(map_slot_name, slot_name)
631 });
632 }
633
634 #[test]
635 fn test_is_empty() {
636 let storage_delta = AccountStorageDelta::new();
637 assert!(storage_delta.is_empty());
638
639 let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
640 assert!(!storage_delta.is_empty());
641
642 let storage_delta = AccountStorageDelta::from_iters(
643 [],
644 [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
645 [],
646 );
647 assert!(!storage_delta.is_empty());
648
649 let storage_delta = AccountStorageDelta::from_iters(
650 [],
651 [],
652 [(StorageSlotName::mock(3), StorageMapDelta::default())],
653 );
654 assert!(!storage_delta.is_empty());
655 }
656
657 #[test]
658 fn test_serde_account_storage_delta() {
659 let storage_delta = AccountStorageDelta::new();
660 let serialized = storage_delta.to_bytes();
661 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
662 assert_eq!(deserialized, storage_delta);
663 assert_eq!(storage_delta.get_size_hint(), serialized.len());
664
665 let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
666 let serialized = storage_delta.to_bytes();
667 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
668 assert_eq!(deserialized, storage_delta);
669 assert_eq!(storage_delta.get_size_hint(), serialized.len());
670
671 let storage_delta = AccountStorageDelta::from_iters(
672 [],
673 [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
674 [],
675 );
676 let serialized = storage_delta.to_bytes();
677 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
678 assert_eq!(deserialized, storage_delta);
679 assert_eq!(storage_delta.get_size_hint(), serialized.len());
680
681 let storage_delta = AccountStorageDelta::from_iters(
682 [],
683 [],
684 [(StorageSlotName::mock(3), StorageMapDelta::default())],
685 );
686 let serialized = storage_delta.to_bytes();
687 let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
688 assert_eq!(deserialized, storage_delta);
689 assert_eq!(storage_delta.get_size_hint(), serialized.len());
690 }
691
692 #[test]
693 fn test_serde_storage_map_delta() {
694 let storage_map_delta = StorageMapDelta::default();
695 let serialized = storage_map_delta.to_bytes();
696 let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
697 assert_eq!(deserialized, storage_map_delta);
698
699 let storage_map_delta =
700 StorageMapDelta::from_iters([StorageMapKey::from_array([1, 1, 1, 1])], []);
701 let serialized = storage_map_delta.to_bytes();
702 let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
703 assert_eq!(deserialized, storage_map_delta);
704
705 let storage_map_delta = StorageMapDelta::from_iters(
706 [],
707 [(StorageMapKey::empty(), Word::from([ONE, ONE, ONE, ONE]))],
708 );
709 let serialized = storage_map_delta.to_bytes();
710 let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
711 assert_eq!(deserialized, storage_map_delta);
712 }
713
714 #[test]
715 fn test_serde_storage_slot_value_delta() {
716 let slot_delta = StorageSlotDelta::with_empty_value();
717 let serialized = slot_delta.to_bytes();
718 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
719 assert_eq!(deserialized, slot_delta);
720
721 let slot_delta = StorageSlotDelta::Value(Word::from([1, 2, 3, 4u32]));
722 let serialized = slot_delta.to_bytes();
723 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
724 assert_eq!(deserialized, slot_delta);
725 }
726
727 #[test]
728 fn test_serde_storage_slot_map_delta() {
729 let slot_delta = StorageSlotDelta::with_empty_map();
730 let serialized = slot_delta.to_bytes();
731 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
732 assert_eq!(deserialized, slot_delta);
733
734 let map_delta = StorageMapDelta::from_iters(
735 [StorageMapKey::from_array([1, 2, 3, 4])],
736 [(StorageMapKey::from_array([5, 6, 7, 8]), Word::from([3, 4, 5, 6u32]))],
737 );
738 let slot_delta = StorageSlotDelta::Map(map_delta);
739 let serialized = slot_delta.to_bytes();
740 let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
741 assert_eq!(deserialized, slot_delta);
742 }
743
744 #[rstest::rstest]
745 #[case::some_some(Some(1), Some(2), Some(2))]
746 #[case::none_some(None, Some(2), Some(2))]
747 #[case::some_none(Some(1), None, None)]
748 #[test]
749 fn merge_items(
750 #[case] x: Option<u32>,
751 #[case] y: Option<u32>,
752 #[case] expected: Option<u32>,
753 ) -> anyhow::Result<()> {
754 fn create_delta(item: Option<u32>) -> AccountStorageDelta {
756 let slot_name = StorageSlotName::mock(123);
757 let item = item.map(|x| (slot_name.clone(), Word::from([x, 0, 0, 0])));
758
759 AccountStorageDelta::new()
760 .add_cleared_items(item.is_none().then_some(slot_name.clone()))
761 .add_updated_values(item)
762 }
763
764 let mut delta_x = create_delta(x);
765 let delta_y = create_delta(y);
766 let expected = create_delta(expected);
767
768 delta_x.merge(delta_y).context("failed to merge deltas")?;
769
770 assert_eq!(delta_x, expected);
771
772 Ok(())
773 }
774
775 #[rstest::rstest]
776 #[case::some_some(Some(1), Some(2), Some(2))]
777 #[case::none_some(None, Some(2), Some(2))]
778 #[case::some_none(Some(1), None, None)]
779 #[test]
780 fn merge_maps(#[case] x: Option<u32>, #[case] y: Option<u32>, #[case] expected: Option<u32>) {
781 fn create_delta(value: Option<u32>) -> StorageMapDelta {
782 let key = StorageMapKey::from_array([10, 0, 0, 0]);
783 match value {
784 Some(value) => {
785 StorageMapDelta::from_iters([], [(key, Word::from([value, 0, 0, 0]))])
786 },
787 None => StorageMapDelta::from_iters([key], []),
788 }
789 }
790
791 let mut delta_x = create_delta(x);
792 let delta_y = create_delta(y);
793 let expected = create_delta(expected);
794
795 delta_x.merge(delta_y);
796
797 assert_eq!(delta_x, expected);
798 }
799}