Skip to main content

miden_protocol/account/delta/
storage.rs

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// ACCOUNT STORAGE DELTA
24// ================================================================================================
25
26/// The [`AccountStorageDelta`] stores the differences between two states of account storage.
27///
28/// The delta consists of a map from [`StorageSlotName`] to [`StorageSlotDelta`].
29#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct AccountStorageDelta {
31    /// The updates to the slots of the account.
32    deltas: BTreeMap<StorageSlotName, StorageSlotDelta>,
33}
34
35impl AccountStorageDelta {
36    /// Creates a new, empty storage delta.
37    pub fn new() -> Self {
38        Self { deltas: BTreeMap::new() }
39    }
40
41    /// Creates a new storage delta from the provided slot deltas.
42    pub fn from_raw(deltas: BTreeMap<StorageSlotName, StorageSlotDelta>) -> Self {
43        Self { deltas }
44    }
45
46    /// Returns the delta for the provided slot name, or `None` if no delta exists.
47    pub fn get(&self, slot_name: &StorageSlotName) -> Option<&StorageSlotDelta> {
48        self.deltas.get(slot_name)
49    }
50
51    /// Returns an iterator over the slot deltas.
52    pub(crate) fn slots(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageSlotDelta)> {
53        self.deltas.iter()
54    }
55
56    /// Returns an iterator over the updated values in this storage delta.
57    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    /// Returns an iterator over the updated maps in this storage delta.
65    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    /// Returns true if storage delta contains no updates.
73    pub fn is_empty(&self) -> bool {
74        self.deltas.is_empty()
75    }
76
77    /// Tracks a slot change.
78    ///
79    /// This does not (and cannot) validate that the slot name _exists_ or that it points to a
80    /// _value_ slot in the corresponding account.
81    ///
82    /// # Errors
83    ///
84    /// Returns an error if:
85    /// - the slot name points to an existing slot that is not of type value.
86    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    /// Tracks a map item change.
101    ///
102    /// This does not (and cannot) validate that the slot name _exists_ or that it points to a
103    /// _map_ slot in the corresponding account.
104    ///
105    /// # Errors
106    ///
107    /// Returns an error if:
108    /// - the slot name points to an existing slot that is not of type map.
109    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    /// Inserts an empty storage map delta for the provided slot name.
132    ///
133    /// This is useful for full state deltas to represent an empty map in the delta.
134    ///
135    /// This overwrites the existing slot delta, if any.
136    pub fn insert_empty_map_delta(&mut self, slot_name: StorageSlotName) {
137        self.deltas.insert(slot_name, StorageSlotDelta::with_empty_map());
138    }
139
140    /// Merges another delta into this one, overwriting any existing values.
141    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    /// Returns an iterator of all the cleared storage slots.
159    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    /// Returns an iterator of all the updated storage slots.
168    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    /// Appends the storage slots delta to the given `elements` from which the delta commitment will
179    /// be computed.
180    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    /// Consumes self and returns the underlying map of the storage delta.
221    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            // The serialized size of each entry is the combination of slot (key) and the delta
264            // (value).
265            storage_map_delta_size += slot_name.get_size_hint() + storage_map_delta.get_size_hint();
266        }
267
268        // Length Prefixes
269        u8_size * 3 +
270        // Cleared Values
271        self.cleared_values().fold(0, |acc, slot_name| acc + slot_name.get_size_hint()) +
272        // Updated Values
273        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
277        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// STORAGE SLOT DELTA
308// ================================================================================================
309
310/// The delta of a single storage slot.
311///
312/// - [`StorageSlotDelta::Value`] contains the value to which a value slot is updated.
313/// - [`StorageSlotDelta::Map`] contains the [`StorageMapDelta`] which contains the key-value pairs
314///   that were updated in a map slot.
315#[derive(Debug, Clone, PartialEq, Eq)]
316pub enum StorageSlotDelta {
317    Value(Word),
318    Map(StorageMapDelta),
319}
320
321impl StorageSlotDelta {
322    // CONSTANTS
323    // ----------------------------------------------------------------------------------------
324
325    /// The type byte for value slot deltas.
326    const VALUE: u8 = 0;
327
328    /// The type byte for map slot deltas.
329    const MAP: u8 = 1;
330
331    // CONSTRUCTORS
332    // ----------------------------------------------------------------------------------------
333
334    /// Returns a new [`StorageSlotDelta::Value`] with an empty value.
335    pub fn with_empty_value() -> Self {
336        Self::Value(Word::empty())
337    }
338
339    /// Returns a new [`StorageSlotDelta::Map`] with an empty map delta.
340    pub fn with_empty_map() -> Self {
341        Self::Map(StorageMapDelta::default())
342    }
343
344    // ACCESSORS
345    // ----------------------------------------------------------------------------------------
346
347    /// Returns the [`StorageSlotType`] of this slot delta.
348    pub fn slot_type(&self) -> StorageSlotType {
349        match self {
350            StorageSlotDelta::Value(_) => StorageSlotType::Value,
351            StorageSlotDelta::Map(_) => StorageSlotType::Map,
352        }
353    }
354
355    /// Returns `true` if the slot delta is of type [`StorageSlotDelta::Value`], `false` otherwise.
356    pub fn is_value(&self) -> bool {
357        matches!(self, Self::Value(_))
358    }
359
360    /// Returns `true` if the slot delta is of type [`StorageSlotDelta::Map`], `false` otherwise.
361    pub fn is_map(&self) -> bool {
362        matches!(self, Self::Map(_))
363    }
364
365    // MUTATORS
366    // ----------------------------------------------------------------------------------------
367
368    /// Unwraps a value slot delta into a [`Word`].
369    ///
370    /// # Panics
371    ///
372    /// Panics if:
373    /// - `self` is not of type [`StorageSlotDelta::Value`].
374    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    /// Unwraps a map slot delta into a [`StorageMapDelta`].
382    ///
383    /// # Panics
384    ///
385    /// Panics if:
386    /// - `self` is not of type [`StorageSlotDelta::Map`].
387    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    /// Merges `other` into `self`.
395    ///
396    /// # Errors
397    ///
398    /// Returns `None` if:
399    /// - merging failed due to a slot type mismatch.
400    #[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// STORAGE MAP DELTA
463// ================================================================================================
464
465/// [StorageMapDelta] stores the differences between two states of account storage maps.
466///
467/// The differences are represented as leaf updates: a map of updated item key ([Word]) to
468/// value ([Word]). For cleared items the value is [EMPTY_WORD].
469#[derive(Clone, Debug, Default, PartialEq, Eq)]
470pub struct StorageMapDelta(BTreeMap<StorageMapKey, Word>);
471
472impl StorageMapDelta {
473    /// Creates a new storage map delta from the provided leaves.
474    pub fn new(map: BTreeMap<StorageMapKey, Word>) -> Self {
475        Self(map)
476    }
477
478    /// Returns the number of changed entries in this map delta.
479    pub fn num_entries(&self) -> usize {
480        self.0.len()
481    }
482
483    /// Returns a reference to the updated entries in this storage map delta.
484    ///
485    /// Note that the returned key is the [`StorageMapKey`].
486    pub fn entries(&self) -> &BTreeMap<StorageMapKey, Word> {
487        &self.0
488    }
489
490    /// Inserts an item into the storage map delta.
491    pub fn insert(&mut self, key: StorageMapKey, value: Word) {
492        self.0.insert(key, value);
493    }
494
495    /// Returns true if storage map delta contains no updates.
496    pub fn is_empty(&self) -> bool {
497        self.0.is_empty()
498    }
499
500    /// Merge `other` into this delta, giving precedence to `other`.
501    pub fn merge(&mut self, other: Self) {
502        // Aggregate the changes into a map such that `other` overwrites self.
503        self.0.extend(other.0);
504    }
505
506    /// Returns a mutable reference to the underlying map.
507    pub fn as_map_mut(&mut self) -> &mut BTreeMap<StorageMapKey, Word> {
508        &mut self.0
509    }
510
511    /// Returns an iterator of all the cleared keys in the storage map.
512    fn cleared_keys(&self) -> impl Iterator<Item = &StorageMapKey> + '_ {
513        self.0.iter().filter(|&(_, value)| value.is_empty()).map(|(key, _)| key)
514    }
515
516    /// Returns an iterator of all the updated entries in the storage map.
517    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    /// Creates a new [StorageMapDelta] from the provided iterators.
529    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    /// Consumes self and returns the underlying map.
539    pub fn into_map(self) -> BTreeMap<StorageMapKey, Word> {
540        self.0
541    }
542}
543
544/// Converts a [StorageMap] into a [StorageMapDelta] for initial delta construction.
545impl 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
568        cleared_keys_count.get_size_hint() +
569        cleared_keys_count * StorageMapKey::SERIALIZED_SIZE +
570
571        // Updated Entries
572        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// TESTS
598// ================================================================================================
599
600#[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        /// Creates a delta containing the item as an update if Some, else with the item cleared.
755        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}