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()).expect(
204                        "number of changed entries should not exceed max representable felt",
205                    );
206
207                    elements.extend_from_slice(&[
208                        DOMAIN_MAP,
209                        num_changed_entries,
210                        slot_id.suffix(),
211                        slot_id.prefix(),
212                    ]);
213                    elements.extend_from_slice(EMPTY_WORD.as_elements());
214                },
215            }
216        }
217    }
218
219    /// Consumes self and returns the underlying map of the storage delta.
220    pub fn into_map(self) -> BTreeMap<StorageSlotName, StorageSlotDelta> {
221        self.deltas
222    }
223}
224
225impl Default for AccountStorageDelta {
226    fn default() -> Self {
227        Self::new()
228    }
229}
230
231impl Serializable for AccountStorageDelta {
232    fn write_into<W: ByteWriter>(&self, target: &mut W) {
233        let num_cleared_values = self.cleared_values().count();
234        let num_cleared_values =
235            u8::try_from(num_cleared_values).expect("number of slots should fit in u8");
236        let cleared_values = self.cleared_values();
237
238        let num_updated_values = self.updated_values().count();
239        let num_updated_values =
240            u8::try_from(num_updated_values).expect("number of slots should fit in u8");
241        let updated_values = self.updated_values();
242
243        let num_maps = self.maps().count();
244        let num_maps = u8::try_from(num_maps).expect("number of slots should fit in u8");
245        let maps = self.maps();
246
247        target.write_u8(num_cleared_values);
248        target.write_many(cleared_values);
249
250        target.write_u8(num_updated_values);
251        target.write_many(updated_values);
252
253        target.write_u8(num_maps);
254        target.write_many(maps);
255    }
256
257    fn get_size_hint(&self) -> usize {
258        let u8_size = 0u8.get_size_hint();
259
260        let mut storage_map_delta_size = 0;
261        for (slot_name, storage_map_delta) in self.maps() {
262            // The serialized size of each entry is the combination of slot (key) and the delta
263            // (value).
264            storage_map_delta_size += slot_name.get_size_hint() + storage_map_delta.get_size_hint();
265        }
266
267        // Length Prefixes
268        u8_size * 3 +
269        // Cleared Values
270        self.cleared_values().fold(0, |acc, slot_name| acc + slot_name.get_size_hint()) +
271        // Updated Values
272        self.updated_values().fold(0, |acc, (slot_name, slot_value)| {
273            acc + slot_name.get_size_hint() + slot_value.get_size_hint()
274        }) +
275        // Storage Map Delta
276        storage_map_delta_size
277    }
278}
279
280impl Deserializable for AccountStorageDelta {
281    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
282        let mut deltas = BTreeMap::new();
283
284        let num_cleared_values = source.read_u8()?;
285        for _ in 0..num_cleared_values {
286            let cleared_value: StorageSlotName = source.read()?;
287            deltas.insert(cleared_value, StorageSlotDelta::with_empty_value());
288        }
289
290        let num_updated_values = source.read_u8()?;
291        for _ in 0..num_updated_values {
292            let (updated_slot, updated_value) = source.read()?;
293            deltas.insert(updated_slot, StorageSlotDelta::Value(updated_value));
294        }
295
296        let num_maps = source.read_u8()? as usize;
297        deltas.extend(
298            source
299                .read_many::<(StorageSlotName, StorageMapDelta)>(num_maps)?
300                .into_iter()
301                .map(|(slot_name, map_delta)| (slot_name, StorageSlotDelta::Map(map_delta))),
302        );
303
304        Ok(Self::from_raw(deltas))
305    }
306}
307
308// STORAGE SLOT DELTA
309// ================================================================================================
310
311/// The delta of a single storage slot.
312///
313/// - [`StorageSlotDelta::Value`] contains the value to which a value slot is updated.
314/// - [`StorageSlotDelta::Map`] contains the [`StorageMapDelta`] which contains the key-value pairs
315///   that were updated in a map slot.
316#[derive(Debug, Clone, PartialEq, Eq)]
317pub enum StorageSlotDelta {
318    Value(Word),
319    Map(StorageMapDelta),
320}
321
322impl StorageSlotDelta {
323    // CONSTANTS
324    // ----------------------------------------------------------------------------------------
325
326    /// The type byte for value slot deltas.
327    const VALUE: u8 = 0;
328
329    /// The type byte for map slot deltas.
330    const MAP: u8 = 1;
331
332    // CONSTRUCTORS
333    // ----------------------------------------------------------------------------------------
334
335    /// Returns a new [`StorageSlotDelta::Value`] with an empty value.
336    pub fn with_empty_value() -> Self {
337        Self::Value(Word::empty())
338    }
339
340    /// Returns a new [`StorageSlotDelta::Map`] with an empty map delta.
341    pub fn with_empty_map() -> Self {
342        Self::Map(StorageMapDelta::default())
343    }
344
345    // ACCESSORS
346    // ----------------------------------------------------------------------------------------
347
348    /// Returns the [`StorageSlotType`] of this slot delta.
349    pub fn slot_type(&self) -> StorageSlotType {
350        match self {
351            StorageSlotDelta::Value(_) => StorageSlotType::Value,
352            StorageSlotDelta::Map(_) => StorageSlotType::Map,
353        }
354    }
355
356    /// Returns `true` if the slot delta is of type [`StorageSlotDelta::Value`], `false` otherwise.
357    pub fn is_value(&self) -> bool {
358        matches!(self, Self::Value(_))
359    }
360
361    /// Returns `true` if the slot delta is of type [`StorageSlotDelta::Map`], `false` otherwise.
362    pub fn is_map(&self) -> bool {
363        matches!(self, Self::Map(_))
364    }
365
366    // MUTATORS
367    // ----------------------------------------------------------------------------------------
368
369    /// Unwraps a value slot delta into a [`Word`].
370    ///
371    /// # Panics
372    ///
373    /// Panics if:
374    /// - `self` is not of type [`StorageSlotDelta::Value`].
375    pub fn unwrap_value(self) -> Word {
376        match self {
377            StorageSlotDelta::Value(value) => value,
378            StorageSlotDelta::Map(_) => panic!("called unwrap_value on a map slot delta"),
379        }
380    }
381
382    /// Unwraps a map slot delta into a [`StorageMapDelta`].
383    ///
384    /// # Panics
385    ///
386    /// Panics if:
387    /// - `self` is not of type [`StorageSlotDelta::Map`].
388    pub fn unwrap_map(self) -> StorageMapDelta {
389        match self {
390            StorageSlotDelta::Value(_) => panic!("called unwrap_map on a value slot delta"),
391            StorageSlotDelta::Map(map_delta) => map_delta,
392        }
393    }
394
395    /// Merges `other` into `self`.
396    ///
397    /// # Errors
398    ///
399    /// Returns `None` if:
400    /// - merging failed due to a slot type mismatch.
401    #[must_use]
402    fn merge(&mut self, other: Self) -> Option<()> {
403        match (self, other) {
404            (StorageSlotDelta::Value(current_value), StorageSlotDelta::Value(new_value)) => {
405                *current_value = new_value;
406            },
407            (StorageSlotDelta::Map(current_map_delta), StorageSlotDelta::Map(new_map_delta)) => {
408                current_map_delta.merge(new_map_delta);
409            },
410            (..) => {
411                return None;
412            },
413        }
414
415        Some(())
416    }
417}
418
419impl From<StorageSlotContent> for StorageSlotDelta {
420    fn from(content: StorageSlotContent) -> Self {
421        match content {
422            StorageSlotContent::Value(word) => StorageSlotDelta::Value(word),
423            StorageSlotContent::Map(storage_map) => {
424                StorageSlotDelta::Map(StorageMapDelta::from(storage_map))
425            },
426        }
427    }
428}
429
430impl Serializable for StorageSlotDelta {
431    fn write_into<W: ByteWriter>(&self, target: &mut W) {
432        match self {
433            StorageSlotDelta::Value(value) => {
434                target.write_u8(Self::VALUE);
435                target.write(value);
436            },
437            StorageSlotDelta::Map(storage_map_delta) => {
438                target.write_u8(Self::MAP);
439                target.write(storage_map_delta);
440            },
441        }
442    }
443}
444
445impl Deserializable for StorageSlotDelta {
446    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
447        match source.read_u8()? {
448            Self::VALUE => {
449                let value = source.read()?;
450                Ok(Self::Value(value))
451            },
452            Self::MAP => {
453                let map_delta = source.read()?;
454                Ok(Self::Map(map_delta))
455            },
456            other => Err(DeserializationError::InvalidValue(format!(
457                "unknown storage slot delta variant {other}"
458            ))),
459        }
460    }
461}
462
463// STORAGE MAP DELTA
464// ================================================================================================
465
466/// [StorageMapDelta] stores the differences between two states of account storage maps.
467///
468/// The differences are represented as leaf updates: a map of updated item key ([Word]) to
469/// value ([Word]). For cleared items the value is [EMPTY_WORD].
470///
471/// The [`LexicographicWord`] wrapper is necessary to order the keys in the same way as the
472/// in-kernel account delta which uses a link map.
473#[derive(Clone, Debug, Default, PartialEq, Eq)]
474pub struct StorageMapDelta(BTreeMap<LexicographicWord<StorageMapKey>, Word>);
475
476impl StorageMapDelta {
477    /// Creates a new storage map delta from the provided leaves.
478    pub fn new(map: BTreeMap<LexicographicWord<StorageMapKey>, Word>) -> Self {
479        Self(map)
480    }
481
482    /// Returns the number of changed entries in this map delta.
483    pub fn num_entries(&self) -> usize {
484        self.0.len()
485    }
486
487    /// Returns a reference to the updated entries in this storage map delta.
488    ///
489    /// Note that the returned key is the [`StorageMapKey`].
490    pub fn entries(&self) -> &BTreeMap<LexicographicWord<StorageMapKey>, Word> {
491        &self.0
492    }
493
494    /// Inserts an item into the storage map delta.
495    pub fn insert(&mut self, key: StorageMapKey, value: Word) {
496        self.0.insert(LexicographicWord::new(key), value);
497    }
498
499    /// Returns true if storage map delta contains no updates.
500    pub fn is_empty(&self) -> bool {
501        self.0.is_empty()
502    }
503
504    /// Merge `other` into this delta, giving precedence to `other`.
505    pub fn merge(&mut self, other: Self) {
506        // Aggregate the changes into a map such that `other` overwrites self.
507        self.0.extend(other.0);
508    }
509
510    /// Returns a mutable reference to the underlying map.
511    pub fn as_map_mut(&mut self) -> &mut BTreeMap<LexicographicWord<StorageMapKey>, Word> {
512        &mut self.0
513    }
514
515    /// Returns an iterator of all the cleared keys in the storage map.
516    fn cleared_keys(&self) -> impl Iterator<Item = &StorageMapKey> + '_ {
517        self.0.iter().filter(|&(_, value)| value.is_empty()).map(|(key, _)| key.inner())
518    }
519
520    /// Returns an iterator of all the updated entries in the storage map.
521    fn updated_entries(&self) -> impl Iterator<Item = (&StorageMapKey, &Word)> + '_ {
522        self.0.iter().filter_map(|(key, value)| {
523            if !value.is_empty() {
524                Some((key.inner(), value))
525            } else {
526                None
527            }
528        })
529    }
530}
531
532#[cfg(any(feature = "testing", test))]
533impl StorageMapDelta {
534    /// Creates a new [StorageMapDelta] from the provided iterators.
535    pub fn from_iters(
536        cleared_leaves: impl IntoIterator<Item = StorageMapKey>,
537        updated_leaves: impl IntoIterator<Item = (StorageMapKey, Word)>,
538    ) -> Self {
539        Self(BTreeMap::from_iter(
540            cleared_leaves
541                .into_iter()
542                .map(|key| (LexicographicWord::new(key), EMPTY_WORD))
543                .chain(
544                    updated_leaves
545                        .into_iter()
546                        .map(|(key, value)| (LexicographicWord::new(key), value)),
547                ),
548        ))
549    }
550
551    /// Consumes self and returns the underlying map.
552    pub fn into_map(self) -> BTreeMap<LexicographicWord<StorageMapKey>, Word> {
553        self.0
554    }
555}
556
557/// Converts a [StorageMap] into a [StorageMapDelta] for initial delta construction.
558impl From<StorageMap> for StorageMapDelta {
559    fn from(map: StorageMap) -> Self {
560        StorageMapDelta::new(
561            map.into_entries()
562                .into_iter()
563                .map(|(key, value)| (LexicographicWord::new(key), value))
564                .collect(),
565        )
566    }
567}
568
569impl Serializable for StorageMapDelta {
570    fn write_into<W: ByteWriter>(&self, target: &mut W) {
571        let cleared: Vec<&StorageMapKey> = self.cleared_keys().collect();
572        let updated: Vec<(&StorageMapKey, &Word)> = self.updated_entries().collect();
573
574        target.write_usize(cleared.len());
575        target.write_many(cleared.iter());
576
577        target.write_usize(updated.len());
578        target.write_many(updated.iter());
579    }
580
581    fn get_size_hint(&self) -> usize {
582        let cleared_keys_count = self.cleared_keys().count();
583        let updated_entries_count = self.updated_entries().count();
584
585        // Cleared Keys
586        cleared_keys_count.get_size_hint() +
587        cleared_keys_count * StorageMapKey::SERIALIZED_SIZE +
588
589        // Updated Entries
590        updated_entries_count.get_size_hint() +
591        updated_entries_count * (StorageMapKey::SERIALIZED_SIZE + Word::SERIALIZED_SIZE)
592    }
593}
594
595impl Deserializable for StorageMapDelta {
596    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
597        let mut map = BTreeMap::new();
598
599        let cleared_count = source.read_usize()?;
600        for _ in 0..cleared_count {
601            let cleared_key = source.read()?;
602            map.insert(LexicographicWord::new(cleared_key), EMPTY_WORD);
603        }
604
605        let updated_count = source.read_usize()?;
606        for _ in 0..updated_count {
607            let (updated_key, updated_value) = source.read()?;
608            map.insert(LexicographicWord::new(updated_key), updated_value);
609        }
610
611        Ok(Self::new(map))
612    }
613}
614
615// TESTS
616// ================================================================================================
617
618#[cfg(test)]
619mod tests {
620    use anyhow::Context;
621    use assert_matches::assert_matches;
622
623    use super::{AccountStorageDelta, Deserializable, Serializable};
624    use crate::account::{StorageMapDelta, StorageMapKey, StorageSlotDelta, StorageSlotName};
625    use crate::errors::AccountDeltaError;
626    use crate::{ONE, Word};
627
628    #[test]
629    fn account_storage_delta_returns_err_on_slot_type_mismatch() {
630        let value_slot_name = StorageSlotName::mock(1);
631        let map_slot_name = StorageSlotName::mock(2);
632
633        let mut delta = AccountStorageDelta::from_iters(
634            [value_slot_name.clone()],
635            [],
636            [(map_slot_name.clone(), StorageMapDelta::default())],
637        );
638
639        let err = delta
640            .set_map_item(value_slot_name.clone(), StorageMapKey::empty(), Word::empty())
641            .unwrap_err();
642        assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
643            assert_eq!(value_slot_name, slot_name)
644        });
645
646        let err = delta.set_item(map_slot_name.clone(), Word::empty()).unwrap_err();
647        assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
648            assert_eq!(map_slot_name, slot_name)
649        });
650    }
651
652    #[test]
653    fn test_is_empty() {
654        let storage_delta = AccountStorageDelta::new();
655        assert!(storage_delta.is_empty());
656
657        let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
658        assert!(!storage_delta.is_empty());
659
660        let storage_delta = AccountStorageDelta::from_iters(
661            [],
662            [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
663            [],
664        );
665        assert!(!storage_delta.is_empty());
666
667        let storage_delta = AccountStorageDelta::from_iters(
668            [],
669            [],
670            [(StorageSlotName::mock(3), StorageMapDelta::default())],
671        );
672        assert!(!storage_delta.is_empty());
673    }
674
675    #[test]
676    fn test_serde_account_storage_delta() {
677        let storage_delta = AccountStorageDelta::new();
678        let serialized = storage_delta.to_bytes();
679        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
680        assert_eq!(deserialized, storage_delta);
681        assert_eq!(storage_delta.get_size_hint(), serialized.len());
682
683        let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
684        let serialized = storage_delta.to_bytes();
685        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
686        assert_eq!(deserialized, storage_delta);
687        assert_eq!(storage_delta.get_size_hint(), serialized.len());
688
689        let storage_delta = AccountStorageDelta::from_iters(
690            [],
691            [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
692            [],
693        );
694        let serialized = storage_delta.to_bytes();
695        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
696        assert_eq!(deserialized, storage_delta);
697        assert_eq!(storage_delta.get_size_hint(), serialized.len());
698
699        let storage_delta = AccountStorageDelta::from_iters(
700            [],
701            [],
702            [(StorageSlotName::mock(3), StorageMapDelta::default())],
703        );
704        let serialized = storage_delta.to_bytes();
705        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
706        assert_eq!(deserialized, storage_delta);
707        assert_eq!(storage_delta.get_size_hint(), serialized.len());
708    }
709
710    #[test]
711    fn test_serde_storage_map_delta() {
712        let storage_map_delta = StorageMapDelta::default();
713        let serialized = storage_map_delta.to_bytes();
714        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
715        assert_eq!(deserialized, storage_map_delta);
716
717        let storage_map_delta =
718            StorageMapDelta::from_iters([StorageMapKey::from_array([1, 1, 1, 1])], []);
719        let serialized = storage_map_delta.to_bytes();
720        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
721        assert_eq!(deserialized, storage_map_delta);
722
723        let storage_map_delta = StorageMapDelta::from_iters(
724            [],
725            [(StorageMapKey::empty(), Word::from([ONE, ONE, ONE, ONE]))],
726        );
727        let serialized = storage_map_delta.to_bytes();
728        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
729        assert_eq!(deserialized, storage_map_delta);
730    }
731
732    #[test]
733    fn test_serde_storage_slot_value_delta() {
734        let slot_delta = StorageSlotDelta::with_empty_value();
735        let serialized = slot_delta.to_bytes();
736        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
737        assert_eq!(deserialized, slot_delta);
738
739        let slot_delta = StorageSlotDelta::Value(Word::from([1, 2, 3, 4u32]));
740        let serialized = slot_delta.to_bytes();
741        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
742        assert_eq!(deserialized, slot_delta);
743    }
744
745    #[test]
746    fn test_serde_storage_slot_map_delta() {
747        let slot_delta = StorageSlotDelta::with_empty_map();
748        let serialized = slot_delta.to_bytes();
749        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
750        assert_eq!(deserialized, slot_delta);
751
752        let map_delta = StorageMapDelta::from_iters(
753            [StorageMapKey::from_array([1, 2, 3, 4])],
754            [(StorageMapKey::from_array([5, 6, 7, 8]), Word::from([3, 4, 5, 6u32]))],
755        );
756        let slot_delta = StorageSlotDelta::Map(map_delta);
757        let serialized = slot_delta.to_bytes();
758        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
759        assert_eq!(deserialized, slot_delta);
760    }
761
762    #[rstest::rstest]
763    #[case::some_some(Some(1), Some(2), Some(2))]
764    #[case::none_some(None, Some(2), Some(2))]
765    #[case::some_none(Some(1), None, None)]
766    #[test]
767    fn merge_items(
768        #[case] x: Option<u32>,
769        #[case] y: Option<u32>,
770        #[case] expected: Option<u32>,
771    ) -> anyhow::Result<()> {
772        /// Creates a delta containing the item as an update if Some, else with the item cleared.
773        fn create_delta(item: Option<u32>) -> AccountStorageDelta {
774            let slot_name = StorageSlotName::mock(123);
775            let item = item.map(|x| (slot_name.clone(), Word::from([x, 0, 0, 0])));
776
777            AccountStorageDelta::new()
778                .add_cleared_items(item.is_none().then_some(slot_name.clone()))
779                .add_updated_values(item)
780        }
781
782        let mut delta_x = create_delta(x);
783        let delta_y = create_delta(y);
784        let expected = create_delta(expected);
785
786        delta_x.merge(delta_y).context("failed to merge deltas")?;
787
788        assert_eq!(delta_x, expected);
789
790        Ok(())
791    }
792
793    #[rstest::rstest]
794    #[case::some_some(Some(1), Some(2), Some(2))]
795    #[case::none_some(None, Some(2), Some(2))]
796    #[case::some_none(Some(1), None, None)]
797    #[test]
798    fn merge_maps(#[case] x: Option<u32>, #[case] y: Option<u32>, #[case] expected: Option<u32>) {
799        fn create_delta(value: Option<u32>) -> StorageMapDelta {
800            let key = StorageMapKey::from_array([10, 0, 0, 0]);
801            match value {
802                Some(value) => {
803                    StorageMapDelta::from_iters([], [(key, Word::from([value, 0, 0, 0]))])
804                },
805                None => StorageMapDelta::from_iters([key], []),
806            }
807        }
808
809        let mut delta_x = create_delta(x);
810        let delta_y = create_delta(y);
811        let expected = create_delta(expected);
812
813        delta_x.merge(delta_y);
814
815        assert_eq!(delta_x, expected);
816    }
817}