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, LexicographicWord, 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.inner().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///
470/// The [`LexicographicWord`] wrapper is necessary to order the keys in the same way as the
471/// in-kernel account delta which uses a link map.
472#[derive(Clone, Debug, Default, PartialEq, Eq)]
473pub struct StorageMapDelta(BTreeMap<LexicographicWord<StorageMapKey>, Word>);
474
475impl StorageMapDelta {
476    /// Creates a new storage map delta from the provided leaves.
477    pub fn new(map: BTreeMap<LexicographicWord<StorageMapKey>, Word>) -> Self {
478        Self(map)
479    }
480
481    /// Returns the number of changed entries in this map delta.
482    pub fn num_entries(&self) -> usize {
483        self.0.len()
484    }
485
486    /// Returns a reference to the updated entries in this storage map delta.
487    ///
488    /// Note that the returned key is the [`StorageMapKey`].
489    pub fn entries(&self) -> &BTreeMap<LexicographicWord<StorageMapKey>, Word> {
490        &self.0
491    }
492
493    /// Inserts an item into the storage map delta.
494    pub fn insert(&mut self, key: StorageMapKey, value: Word) {
495        self.0.insert(LexicographicWord::new(key), value);
496    }
497
498    /// Returns true if storage map delta contains no updates.
499    pub fn is_empty(&self) -> bool {
500        self.0.is_empty()
501    }
502
503    /// Merge `other` into this delta, giving precedence to `other`.
504    pub fn merge(&mut self, other: Self) {
505        // Aggregate the changes into a map such that `other` overwrites self.
506        self.0.extend(other.0);
507    }
508
509    /// Returns a mutable reference to the underlying map.
510    pub fn as_map_mut(&mut self) -> &mut BTreeMap<LexicographicWord<StorageMapKey>, Word> {
511        &mut self.0
512    }
513
514    /// Returns an iterator of all the cleared keys in the storage map.
515    fn cleared_keys(&self) -> impl Iterator<Item = &StorageMapKey> + '_ {
516        self.0.iter().filter(|&(_, value)| value.is_empty()).map(|(key, _)| key.inner())
517    }
518
519    /// Returns an iterator of all the updated entries in the storage map.
520    fn updated_entries(&self) -> impl Iterator<Item = (&StorageMapKey, &Word)> + '_ {
521        self.0.iter().filter_map(|(key, value)| {
522            if !value.is_empty() {
523                Some((key.inner(), value))
524            } else {
525                None
526            }
527        })
528    }
529}
530
531#[cfg(any(feature = "testing", test))]
532impl StorageMapDelta {
533    /// Creates a new [StorageMapDelta] from the provided iterators.
534    pub fn from_iters(
535        cleared_leaves: impl IntoIterator<Item = StorageMapKey>,
536        updated_leaves: impl IntoIterator<Item = (StorageMapKey, Word)>,
537    ) -> Self {
538        Self(BTreeMap::from_iter(
539            cleared_leaves
540                .into_iter()
541                .map(|key| (LexicographicWord::new(key), EMPTY_WORD))
542                .chain(
543                    updated_leaves
544                        .into_iter()
545                        .map(|(key, value)| (LexicographicWord::new(key), value)),
546                ),
547        ))
548    }
549
550    /// Consumes self and returns the underlying map.
551    pub fn into_map(self) -> BTreeMap<LexicographicWord<StorageMapKey>, Word> {
552        self.0
553    }
554}
555
556/// Converts a [StorageMap] into a [StorageMapDelta] for initial delta construction.
557impl From<StorageMap> for StorageMapDelta {
558    fn from(map: StorageMap) -> Self {
559        StorageMapDelta::new(
560            map.into_entries()
561                .into_iter()
562                .map(|(key, value)| (LexicographicWord::new(key), value))
563                .collect(),
564        )
565    }
566}
567
568impl Serializable for StorageMapDelta {
569    fn write_into<W: ByteWriter>(&self, target: &mut W) {
570        let cleared: Vec<&StorageMapKey> = self.cleared_keys().collect();
571        let updated: Vec<(&StorageMapKey, &Word)> = self.updated_entries().collect();
572
573        target.write_usize(cleared.len());
574        target.write_many(cleared.iter());
575
576        target.write_usize(updated.len());
577        target.write_many(updated.iter());
578    }
579
580    fn get_size_hint(&self) -> usize {
581        let cleared_keys_count = self.cleared_keys().count();
582        let updated_entries_count = self.updated_entries().count();
583
584        // Cleared Keys
585        cleared_keys_count.get_size_hint() +
586        cleared_keys_count * StorageMapKey::SERIALIZED_SIZE +
587
588        // Updated Entries
589        updated_entries_count.get_size_hint() +
590        updated_entries_count * (StorageMapKey::SERIALIZED_SIZE + Word::SERIALIZED_SIZE)
591    }
592}
593
594impl Deserializable for StorageMapDelta {
595    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
596        let mut map = BTreeMap::new();
597
598        let cleared_count = source.read_usize()?;
599        for _ in 0..cleared_count {
600            let cleared_key = source.read()?;
601            map.insert(LexicographicWord::new(cleared_key), EMPTY_WORD);
602        }
603
604        let updated_count = source.read_usize()?;
605        for _ in 0..updated_count {
606            let (updated_key, updated_value) = source.read()?;
607            map.insert(LexicographicWord::new(updated_key), updated_value);
608        }
609
610        Ok(Self::new(map))
611    }
612}
613
614// TESTS
615// ================================================================================================
616
617#[cfg(test)]
618mod tests {
619    use anyhow::Context;
620    use assert_matches::assert_matches;
621
622    use super::{AccountStorageDelta, Deserializable, Serializable};
623    use crate::account::{StorageMapDelta, StorageMapKey, StorageSlotDelta, StorageSlotName};
624    use crate::errors::AccountDeltaError;
625    use crate::{ONE, Word};
626
627    #[test]
628    fn account_storage_delta_returns_err_on_slot_type_mismatch() {
629        let value_slot_name = StorageSlotName::mock(1);
630        let map_slot_name = StorageSlotName::mock(2);
631
632        let mut delta = AccountStorageDelta::from_iters(
633            [value_slot_name.clone()],
634            [],
635            [(map_slot_name.clone(), StorageMapDelta::default())],
636        );
637
638        let err = delta
639            .set_map_item(value_slot_name.clone(), StorageMapKey::empty(), Word::empty())
640            .unwrap_err();
641        assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
642            assert_eq!(value_slot_name, slot_name)
643        });
644
645        let err = delta.set_item(map_slot_name.clone(), Word::empty()).unwrap_err();
646        assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
647            assert_eq!(map_slot_name, slot_name)
648        });
649    }
650
651    #[test]
652    fn test_is_empty() {
653        let storage_delta = AccountStorageDelta::new();
654        assert!(storage_delta.is_empty());
655
656        let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
657        assert!(!storage_delta.is_empty());
658
659        let storage_delta = AccountStorageDelta::from_iters(
660            [],
661            [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
662            [],
663        );
664        assert!(!storage_delta.is_empty());
665
666        let storage_delta = AccountStorageDelta::from_iters(
667            [],
668            [],
669            [(StorageSlotName::mock(3), StorageMapDelta::default())],
670        );
671        assert!(!storage_delta.is_empty());
672    }
673
674    #[test]
675    fn test_serde_account_storage_delta() {
676        let storage_delta = AccountStorageDelta::new();
677        let serialized = storage_delta.to_bytes();
678        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
679        assert_eq!(deserialized, storage_delta);
680        assert_eq!(storage_delta.get_size_hint(), serialized.len());
681
682        let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
683        let serialized = storage_delta.to_bytes();
684        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
685        assert_eq!(deserialized, storage_delta);
686        assert_eq!(storage_delta.get_size_hint(), serialized.len());
687
688        let storage_delta = AccountStorageDelta::from_iters(
689            [],
690            [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
691            [],
692        );
693        let serialized = storage_delta.to_bytes();
694        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
695        assert_eq!(deserialized, storage_delta);
696        assert_eq!(storage_delta.get_size_hint(), serialized.len());
697
698        let storage_delta = AccountStorageDelta::from_iters(
699            [],
700            [],
701            [(StorageSlotName::mock(3), StorageMapDelta::default())],
702        );
703        let serialized = storage_delta.to_bytes();
704        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
705        assert_eq!(deserialized, storage_delta);
706        assert_eq!(storage_delta.get_size_hint(), serialized.len());
707    }
708
709    #[test]
710    fn test_serde_storage_map_delta() {
711        let storage_map_delta = StorageMapDelta::default();
712        let serialized = storage_map_delta.to_bytes();
713        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
714        assert_eq!(deserialized, storage_map_delta);
715
716        let storage_map_delta =
717            StorageMapDelta::from_iters([StorageMapKey::from_array([1, 1, 1, 1])], []);
718        let serialized = storage_map_delta.to_bytes();
719        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
720        assert_eq!(deserialized, storage_map_delta);
721
722        let storage_map_delta = StorageMapDelta::from_iters(
723            [],
724            [(StorageMapKey::empty(), Word::from([ONE, ONE, ONE, ONE]))],
725        );
726        let serialized = storage_map_delta.to_bytes();
727        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
728        assert_eq!(deserialized, storage_map_delta);
729    }
730
731    #[test]
732    fn test_serde_storage_slot_value_delta() {
733        let slot_delta = StorageSlotDelta::with_empty_value();
734        let serialized = slot_delta.to_bytes();
735        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
736        assert_eq!(deserialized, slot_delta);
737
738        let slot_delta = StorageSlotDelta::Value(Word::from([1, 2, 3, 4u32]));
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    #[test]
745    fn test_serde_storage_slot_map_delta() {
746        let slot_delta = StorageSlotDelta::with_empty_map();
747        let serialized = slot_delta.to_bytes();
748        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
749        assert_eq!(deserialized, slot_delta);
750
751        let map_delta = StorageMapDelta::from_iters(
752            [StorageMapKey::from_array([1, 2, 3, 4])],
753            [(StorageMapKey::from_array([5, 6, 7, 8]), Word::from([3, 4, 5, 6u32]))],
754        );
755        let slot_delta = StorageSlotDelta::Map(map_delta);
756        let serialized = slot_delta.to_bytes();
757        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
758        assert_eq!(deserialized, slot_delta);
759    }
760
761    #[rstest::rstest]
762    #[case::some_some(Some(1), Some(2), Some(2))]
763    #[case::none_some(None, Some(2), Some(2))]
764    #[case::some_none(Some(1), None, None)]
765    #[test]
766    fn merge_items(
767        #[case] x: Option<u32>,
768        #[case] y: Option<u32>,
769        #[case] expected: Option<u32>,
770    ) -> anyhow::Result<()> {
771        /// Creates a delta containing the item as an update if Some, else with the item cleared.
772        fn create_delta(item: Option<u32>) -> AccountStorageDelta {
773            let slot_name = StorageSlotName::mock(123);
774            let item = item.map(|x| (slot_name.clone(), Word::from([x, 0, 0, 0])));
775
776            AccountStorageDelta::new()
777                .add_cleared_items(item.is_none().then_some(slot_name.clone()))
778                .add_updated_values(item)
779        }
780
781        let mut delta_x = create_delta(x);
782        let delta_y = create_delta(y);
783        let expected = create_delta(expected);
784
785        delta_x.merge(delta_y).context("failed to merge deltas")?;
786
787        assert_eq!(delta_x, expected);
788
789        Ok(())
790    }
791
792    #[rstest::rstest]
793    #[case::some_some(Some(1), Some(2), Some(2))]
794    #[case::none_some(None, Some(2), Some(2))]
795    #[case::some_none(Some(1), None, None)]
796    #[test]
797    fn merge_maps(#[case] x: Option<u32>, #[case] y: Option<u32>, #[case] expected: Option<u32>) {
798        fn create_delta(value: Option<u32>) -> StorageMapDelta {
799            let key = StorageMapKey::from_array([10, 0, 0, 0]);
800            match value {
801                Some(value) => {
802                    StorageMapDelta::from_iters([], [(key, Word::from([value, 0, 0, 0]))])
803                },
804                None => StorageMapDelta::from_iters([key], []),
805            }
806        }
807
808        let mut delta_x = create_delta(x);
809        let delta_y = create_delta(y);
810        let expected = create_delta(expected);
811
812        delta_x.merge(delta_y);
813
814        assert_eq!(delta_x, expected);
815    }
816}