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::{StorageMap, StorageSlotContent, StorageSlotName, StorageSlotType};
15use crate::{EMPTY_WORD, Felt, LexicographicWord, ZERO};
16
17// ACCOUNT STORAGE DELTA
18// ================================================================================================
19
20/// The [`AccountStorageDelta`] stores the differences between two states of account storage.
21///
22/// The delta consists of a map from [`StorageSlotName`] to [`StorageSlotDelta`].
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct AccountStorageDelta {
25    /// The updates to the slots of the account.
26    deltas: BTreeMap<StorageSlotName, StorageSlotDelta>,
27}
28
29impl AccountStorageDelta {
30    /// Creates a new, empty storage delta.
31    pub fn new() -> Self {
32        Self { deltas: BTreeMap::new() }
33    }
34
35    /// Creates a new storage delta from the provided slot deltas.
36    pub fn from_raw(deltas: BTreeMap<StorageSlotName, StorageSlotDelta>) -> Self {
37        Self { deltas }
38    }
39
40    /// Returns the delta for the provided slot name, or `None` if no delta exists.
41    pub fn get(&self, slot_name: &StorageSlotName) -> Option<&StorageSlotDelta> {
42        self.deltas.get(slot_name)
43    }
44
45    /// Returns an iterator over the slot deltas.
46    pub(crate) fn slots(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageSlotDelta)> {
47        self.deltas.iter()
48    }
49
50    /// Returns an iterator over the updated values in this storage delta.
51    pub fn values(&self) -> impl Iterator<Item = (&StorageSlotName, &Word)> {
52        self.deltas.iter().filter_map(|(slot_name, slot_delta)| match slot_delta {
53            StorageSlotDelta::Value(word) => Some((slot_name, word)),
54            StorageSlotDelta::Map(_) => None,
55        })
56    }
57
58    /// Returns an iterator over the updated maps in this storage delta.
59    pub fn maps(&self) -> impl Iterator<Item = (&StorageSlotName, &StorageMapDelta)> {
60        self.deltas.iter().filter_map(|(slot_name, slot_delta)| match slot_delta {
61            StorageSlotDelta::Value(_) => None,
62            StorageSlotDelta::Map(map_delta) => Some((slot_name, map_delta)),
63        })
64    }
65
66    /// Returns true if storage delta contains no updates.
67    pub fn is_empty(&self) -> bool {
68        self.deltas.is_empty()
69    }
70
71    /// Tracks a slot change.
72    ///
73    /// This does not (and cannot) validate that the slot name _exists_ or that it points to a
74    /// _value_ slot in the corresponding account.
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if:
79    /// - the slot name points to an existing slot that is not of type value.
80    pub fn set_item(
81        &mut self,
82        slot_name: StorageSlotName,
83        new_slot_value: Word,
84    ) -> Result<(), AccountDeltaError> {
85        if !self.deltas.get(&slot_name).map(StorageSlotDelta::is_value).unwrap_or(true) {
86            return Err(AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name));
87        }
88
89        self.deltas.insert(slot_name, StorageSlotDelta::Value(new_slot_value));
90
91        Ok(())
92    }
93
94    /// Tracks a map item change.
95    ///
96    /// This does not (and cannot) validate that the slot name _exists_ or that it points to a
97    /// _map_ slot in the corresponding account.
98    ///
99    /// # Errors
100    ///
101    /// Returns an error if:
102    /// - the slot name points to an existing slot that is not of type map.
103    pub fn set_map_item(
104        &mut self,
105        slot_name: StorageSlotName,
106        key: Word,
107        new_value: Word,
108    ) -> Result<(), AccountDeltaError> {
109        match self
110            .deltas
111            .entry(slot_name.clone())
112            .or_insert(StorageSlotDelta::Map(StorageMapDelta::default()))
113        {
114            StorageSlotDelta::Value(_) => {
115                return Err(AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name));
116            },
117            StorageSlotDelta::Map(storage_map_delta) => {
118                storage_map_delta.insert(key, new_value);
119            },
120        };
121
122        Ok(())
123    }
124
125    /// Inserts an empty storage map delta for the provided slot name.
126    ///
127    /// This is useful for full state deltas to represent an empty map in the delta.
128    ///
129    /// This overwrites the existing slot delta, if any.
130    pub fn insert_empty_map_delta(&mut self, slot_name: StorageSlotName) {
131        self.deltas.insert(slot_name, StorageSlotDelta::with_empty_map());
132    }
133
134    /// Merges another delta into this one, overwriting any existing values.
135    pub fn merge(&mut self, other: Self) -> Result<(), AccountDeltaError> {
136        for (slot_name, slot_delta) in other.deltas {
137            match self.deltas.entry(slot_name.clone()) {
138                Entry::Vacant(vacant_entry) => {
139                    vacant_entry.insert(slot_delta);
140                },
141                Entry::Occupied(mut occupied_entry) => {
142                    occupied_entry.get_mut().merge(slot_delta).ok_or_else(|| {
143                        AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name)
144                    })?;
145                },
146            }
147        }
148
149        Ok(())
150    }
151
152    /// Returns an iterator of all the cleared storage slots.
153    fn cleared_values(&self) -> impl Iterator<Item = &StorageSlotName> {
154        self.values().filter_map(
155            |(slot_name, slot_value)| {
156                if slot_value.is_empty() { Some(slot_name) } else { None }
157            },
158        )
159    }
160
161    /// Returns an iterator of all the updated storage slots.
162    fn updated_values(&self) -> impl Iterator<Item = (&StorageSlotName, &Word)> {
163        self.values().filter_map(|(slot_name, slot_value)| {
164            if !slot_value.is_empty() {
165                Some((slot_name, slot_value))
166            } else {
167                None
168            }
169        })
170    }
171
172    /// Appends the storage slots delta to the given `elements` from which the delta commitment will
173    /// be computed.
174    pub(super) fn append_delta_elements(&self, elements: &mut Vec<Felt>) {
175        const DOMAIN_VALUE: Felt = Felt::new(2);
176        const DOMAIN_MAP: Felt = Felt::new(3);
177
178        for (slot_name, slot_delta) in self.deltas.iter() {
179            let slot_id = slot_name.id();
180
181            match slot_delta {
182                StorageSlotDelta::Value(new_value) => {
183                    elements.extend_from_slice(&[
184                        DOMAIN_VALUE,
185                        ZERO,
186                        slot_id.suffix(),
187                        slot_id.prefix(),
188                    ]);
189                    elements.extend_from_slice(new_value.as_elements());
190                },
191                StorageSlotDelta::Map(map_delta) => {
192                    for (key, value) in map_delta.entries() {
193                        elements.extend_from_slice(key.inner().as_elements());
194                        elements.extend_from_slice(value.as_elements());
195                    }
196
197                    let num_changed_entries = Felt::try_from(map_delta.num_entries()).expect(
198                        "number of changed entries should not exceed max representable felt",
199                    );
200
201                    elements.extend_from_slice(&[
202                        DOMAIN_MAP,
203                        num_changed_entries,
204                        slot_id.suffix(),
205                        slot_id.prefix(),
206                    ]);
207                    elements.extend_from_slice(EMPTY_WORD.as_elements());
208                },
209            }
210        }
211    }
212
213    /// Consumes self and returns the underlying map of the storage delta.
214    pub fn into_map(self) -> BTreeMap<StorageSlotName, StorageSlotDelta> {
215        self.deltas
216    }
217}
218
219impl Default for AccountStorageDelta {
220    fn default() -> Self {
221        Self::new()
222    }
223}
224
225impl Serializable for AccountStorageDelta {
226    fn write_into<W: ByteWriter>(&self, target: &mut W) {
227        let num_cleared_values = self.cleared_values().count();
228        let num_cleared_values =
229            u8::try_from(num_cleared_values).expect("number of slots should fit in u8");
230        let cleared_values = self.cleared_values();
231
232        let num_updated_values = self.updated_values().count();
233        let num_updated_values =
234            u8::try_from(num_updated_values).expect("number of slots should fit in u8");
235        let updated_values = self.updated_values();
236
237        let num_maps = self.maps().count();
238        let num_maps = u8::try_from(num_maps).expect("number of slots should fit in u8");
239        let maps = self.maps();
240
241        target.write_u8(num_cleared_values);
242        target.write_many(cleared_values);
243
244        target.write_u8(num_updated_values);
245        target.write_many(updated_values);
246
247        target.write_u8(num_maps);
248        target.write_many(maps);
249    }
250
251    fn get_size_hint(&self) -> usize {
252        let u8_size = 0u8.get_size_hint();
253
254        let mut storage_map_delta_size = 0;
255        for (slot_name, storage_map_delta) in self.maps() {
256            // The serialized size of each entry is the combination of slot (key) and the delta
257            // (value).
258            storage_map_delta_size += slot_name.get_size_hint() + storage_map_delta.get_size_hint();
259        }
260
261        // Length Prefixes
262        u8_size * 3 +
263        // Cleared Values
264        self.cleared_values().fold(0, |acc, slot_name| acc + slot_name.get_size_hint()) +
265        // Updated Values
266        self.updated_values().fold(0, |acc, (slot_name, slot_value)| {
267            acc + slot_name.get_size_hint() + slot_value.get_size_hint()
268        }) +
269        // Storage Map Delta
270        storage_map_delta_size
271    }
272}
273
274impl Deserializable for AccountStorageDelta {
275    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
276        let mut deltas = BTreeMap::new();
277
278        let num_cleared_values = source.read_u8()?;
279        for _ in 0..num_cleared_values {
280            let cleared_value: StorageSlotName = source.read()?;
281            deltas.insert(cleared_value, StorageSlotDelta::with_empty_value());
282        }
283
284        let num_updated_values = source.read_u8()?;
285        for _ in 0..num_updated_values {
286            let (updated_slot, updated_value) = source.read()?;
287            deltas.insert(updated_slot, StorageSlotDelta::Value(updated_value));
288        }
289
290        let num_maps = source.read_u8()? as usize;
291        deltas.extend(
292            source
293                .read_many::<(StorageSlotName, StorageMapDelta)>(num_maps)?
294                .into_iter()
295                .map(|(slot_name, map_delta)| (slot_name, StorageSlotDelta::Map(map_delta))),
296        );
297
298        Ok(Self::from_raw(deltas))
299    }
300}
301
302// STORAGE SLOT DELTA
303// ================================================================================================
304
305/// The delta of a single storage slot.
306///
307/// - [`StorageSlotDelta::Value`] contains the value to which a value slot is updated.
308/// - [`StorageSlotDelta::Map`] contains the [`StorageMapDelta`] which contains the key-value pairs
309///   that were updated in a map slot.
310#[derive(Debug, Clone, PartialEq, Eq)]
311pub enum StorageSlotDelta {
312    Value(Word),
313    Map(StorageMapDelta),
314}
315
316impl StorageSlotDelta {
317    // CONSTANTS
318    // ----------------------------------------------------------------------------------------
319
320    /// The type byte for value slot deltas.
321    const VALUE: u8 = 0;
322
323    /// The type byte for map slot deltas.
324    const MAP: u8 = 1;
325
326    // CONSTRUCTORS
327    // ----------------------------------------------------------------------------------------
328
329    /// Returns a new [`StorageSlotDelta::Value`] with an empty value.
330    pub fn with_empty_value() -> Self {
331        Self::Value(Word::empty())
332    }
333
334    /// Returns a new [`StorageSlotDelta::Map`] with an empty map delta.
335    pub fn with_empty_map() -> Self {
336        Self::Map(StorageMapDelta::default())
337    }
338
339    // ACCESSORS
340    // ----------------------------------------------------------------------------------------
341
342    /// Returns the [`StorageSlotType`] of this slot delta.
343    pub fn slot_type(&self) -> StorageSlotType {
344        match self {
345            StorageSlotDelta::Value(_) => StorageSlotType::Value,
346            StorageSlotDelta::Map(_) => StorageSlotType::Map,
347        }
348    }
349
350    /// Returns `true` if the slot delta is of type [`StorageSlotDelta::Value`], `false` otherwise.
351    pub fn is_value(&self) -> bool {
352        matches!(self, Self::Value(_))
353    }
354
355    /// Returns `true` if the slot delta is of type [`StorageSlotDelta::Map`], `false` otherwise.
356    pub fn is_map(&self) -> bool {
357        matches!(self, Self::Map(_))
358    }
359
360    // MUTATORS
361    // ----------------------------------------------------------------------------------------
362
363    /// Unwraps a value slot delta into a [`Word`].
364    ///
365    /// # Panics
366    ///
367    /// Panics if:
368    /// - `self` is not of type [`StorageSlotDelta::Value`].
369    pub fn unwrap_value(self) -> Word {
370        match self {
371            StorageSlotDelta::Value(value) => value,
372            StorageSlotDelta::Map(_) => panic!("called unwrap_value on a map slot delta"),
373        }
374    }
375
376    /// Unwraps a map slot delta into a [`StorageMapDelta`].
377    ///
378    /// # Panics
379    ///
380    /// Panics if:
381    /// - `self` is not of type [`StorageSlotDelta::Map`].
382    pub fn unwrap_map(self) -> StorageMapDelta {
383        match self {
384            StorageSlotDelta::Value(_) => panic!("called unwrap_map on a value slot delta"),
385            StorageSlotDelta::Map(map_delta) => map_delta,
386        }
387    }
388
389    /// Merges `other` into `self`.
390    ///
391    /// # Errors
392    ///
393    /// Returns `None` if:
394    /// - merging failed due to a slot type mismatch.
395    #[must_use]
396    fn merge(&mut self, other: Self) -> Option<()> {
397        match (self, other) {
398            (StorageSlotDelta::Value(current_value), StorageSlotDelta::Value(new_value)) => {
399                *current_value = new_value;
400            },
401            (StorageSlotDelta::Map(current_map_delta), StorageSlotDelta::Map(new_map_delta)) => {
402                current_map_delta.merge(new_map_delta);
403            },
404            (..) => {
405                return None;
406            },
407        }
408
409        Some(())
410    }
411}
412
413impl From<StorageSlotContent> for StorageSlotDelta {
414    fn from(content: StorageSlotContent) -> Self {
415        match content {
416            StorageSlotContent::Value(word) => StorageSlotDelta::Value(word),
417            StorageSlotContent::Map(storage_map) => {
418                StorageSlotDelta::Map(StorageMapDelta::from(storage_map))
419            },
420        }
421    }
422}
423
424impl Serializable for StorageSlotDelta {
425    fn write_into<W: ByteWriter>(&self, target: &mut W) {
426        match self {
427            StorageSlotDelta::Value(value) => {
428                target.write_u8(Self::VALUE);
429                target.write(value);
430            },
431            StorageSlotDelta::Map(storage_map_delta) => {
432                target.write_u8(Self::MAP);
433                target.write(storage_map_delta);
434            },
435        }
436    }
437}
438
439impl Deserializable for StorageSlotDelta {
440    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
441        match source.read_u8()? {
442            Self::VALUE => {
443                let value = source.read()?;
444                Ok(Self::Value(value))
445            },
446            Self::MAP => {
447                let map_delta = source.read()?;
448                Ok(Self::Map(map_delta))
449            },
450            other => Err(DeserializationError::InvalidValue(format!(
451                "unknown storage slot delta variant {other}"
452            ))),
453        }
454    }
455}
456
457// STORAGE MAP DELTA
458// ================================================================================================
459
460/// [StorageMapDelta] stores the differences between two states of account storage maps.
461///
462/// The differences are represented as leaf updates: a map of updated item key ([Word]) to
463/// value ([Word]). For cleared items the value is [EMPTY_WORD].
464///
465/// The [`LexicographicWord`] wrapper is necessary to order the keys in the same way as the
466/// in-kernel account delta which uses a link map.
467#[derive(Clone, Debug, Default, PartialEq, Eq)]
468pub struct StorageMapDelta(BTreeMap<LexicographicWord, Word>);
469
470impl StorageMapDelta {
471    /// Creates a new storage map delta from the provided leaves.
472    pub fn new(map: BTreeMap<LexicographicWord, Word>) -> Self {
473        Self(map)
474    }
475
476    /// Returns the number of changed entries in this map delta.
477    pub fn num_entries(&self) -> usize {
478        self.0.len()
479    }
480
481    /// Returns a reference to the updated entries in this storage map delta.
482    ///
483    /// Note that the returned key is the raw map key.
484    pub fn entries(&self) -> &BTreeMap<LexicographicWord, Word> {
485        &self.0
486    }
487
488    /// Inserts an item into the storage map delta.
489    pub fn insert(&mut self, raw_key: Word, value: Word) {
490        self.0.insert(LexicographicWord::new(raw_key), value);
491    }
492
493    /// Returns true if storage map delta contains no updates.
494    pub fn is_empty(&self) -> bool {
495        self.0.is_empty()
496    }
497
498    /// Merge `other` into this delta, giving precedence to `other`.
499    pub fn merge(&mut self, other: Self) {
500        // Aggregate the changes into a map such that `other` overwrites self.
501        self.0.extend(other.0);
502    }
503
504    /// Returns a mutable reference to the underlying map.
505    pub fn as_map_mut(&mut self) -> &mut BTreeMap<LexicographicWord, Word> {
506        &mut self.0
507    }
508
509    /// Returns an iterator of all the cleared keys in the storage map.
510    fn cleared_keys(&self) -> impl Iterator<Item = &Word> + '_ {
511        self.0.iter().filter(|&(_, value)| value.is_empty()).map(|(key, _)| key.inner())
512    }
513
514    /// Returns an iterator of all the updated entries in the storage map.
515    fn updated_entries(&self) -> impl Iterator<Item = (&Word, &Word)> + '_ {
516        self.0.iter().filter_map(|(key, value)| {
517            if !value.is_empty() {
518                Some((key.inner(), value))
519            } else {
520                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 = Word>,
531        updated_leaves: impl IntoIterator<Item = (Word, Word)>,
532    ) -> Self {
533        Self(BTreeMap::from_iter(
534            cleared_leaves
535                .into_iter()
536                .map(|key| (LexicographicWord::new(key), EMPTY_WORD))
537                .chain(
538                    updated_leaves
539                        .into_iter()
540                        .map(|(key, value)| (LexicographicWord::new(key), value)),
541                ),
542        ))
543    }
544
545    /// Consumes self and returns the underlying map.
546    pub fn into_map(self) -> BTreeMap<LexicographicWord, Word> {
547        self.0
548    }
549}
550
551/// Converts a [StorageMap] into a [StorageMapDelta] for initial delta construction.
552impl From<StorageMap> for StorageMapDelta {
553    fn from(map: StorageMap) -> Self {
554        StorageMapDelta::new(
555            map.into_entries()
556                .into_iter()
557                .map(|(key, value)| (LexicographicWord::new(key), value))
558                .collect(),
559        )
560    }
561}
562
563impl Serializable for StorageMapDelta {
564    fn write_into<W: ByteWriter>(&self, target: &mut W) {
565        let cleared: Vec<&Word> = self.cleared_keys().collect();
566        let updated: Vec<(&Word, &Word)> = self.updated_entries().collect();
567
568        target.write_usize(cleared.len());
569        target.write_many(cleared.iter());
570
571        target.write_usize(updated.len());
572        target.write_many(updated.iter());
573    }
574
575    fn get_size_hint(&self) -> usize {
576        let word_size = EMPTY_WORD.get_size_hint();
577
578        let cleared_keys_count = self.cleared_keys().count();
579        let updated_entries_count = self.updated_entries().count();
580
581        // Cleared Keys
582        cleared_keys_count.get_size_hint() +
583        cleared_keys_count * Word::SERIALIZED_SIZE +
584
585        // Updated Entries
586        updated_entries_count.get_size_hint() +
587        updated_entries_count * (Word::SERIALIZED_SIZE + word_size)
588    }
589}
590
591impl Deserializable for StorageMapDelta {
592    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
593        let mut map = BTreeMap::new();
594
595        let cleared_count = source.read_usize()?;
596        for _ in 0..cleared_count {
597            let cleared_key = source.read()?;
598            map.insert(LexicographicWord::new(cleared_key), EMPTY_WORD);
599        }
600
601        let updated_count = source.read_usize()?;
602        for _ in 0..updated_count {
603            let (updated_key, updated_value) = source.read()?;
604            map.insert(LexicographicWord::new(updated_key), updated_value);
605        }
606
607        Ok(Self::new(map))
608    }
609}
610
611// TESTS
612// ================================================================================================
613
614#[cfg(test)]
615mod tests {
616    use anyhow::Context;
617    use assert_matches::assert_matches;
618
619    use super::{AccountStorageDelta, Deserializable, Serializable};
620    use crate::account::{StorageMapDelta, StorageSlotDelta, StorageSlotName};
621    use crate::errors::AccountDeltaError;
622    use crate::{ONE, Word};
623
624    #[test]
625    fn account_storage_delta_returns_err_on_slot_type_mismatch() {
626        let value_slot_name = StorageSlotName::mock(1);
627        let map_slot_name = StorageSlotName::mock(2);
628
629        let mut delta = AccountStorageDelta::from_iters(
630            [value_slot_name.clone()],
631            [],
632            [(map_slot_name.clone(), StorageMapDelta::default())],
633        );
634
635        let err = delta
636            .set_map_item(value_slot_name.clone(), Word::empty(), Word::empty())
637            .unwrap_err();
638        assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
639            assert_eq!(value_slot_name, slot_name)
640        });
641
642        let err = delta.set_item(map_slot_name.clone(), Word::empty()).unwrap_err();
643        assert_matches!(err, AccountDeltaError::StorageSlotUsedAsDifferentTypes(slot_name) => {
644            assert_eq!(map_slot_name, slot_name)
645        });
646    }
647
648    #[test]
649    fn test_is_empty() {
650        let storage_delta = AccountStorageDelta::new();
651        assert!(storage_delta.is_empty());
652
653        let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
654        assert!(!storage_delta.is_empty());
655
656        let storage_delta = AccountStorageDelta::from_iters(
657            [],
658            [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
659            [],
660        );
661        assert!(!storage_delta.is_empty());
662
663        let storage_delta = AccountStorageDelta::from_iters(
664            [],
665            [],
666            [(StorageSlotName::mock(3), StorageMapDelta::default())],
667        );
668        assert!(!storage_delta.is_empty());
669    }
670
671    #[test]
672    fn test_serde_account_storage_delta() {
673        let storage_delta = AccountStorageDelta::new();
674        let serialized = storage_delta.to_bytes();
675        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
676        assert_eq!(deserialized, storage_delta);
677
678        let storage_delta = AccountStorageDelta::from_iters([StorageSlotName::mock(1)], [], []);
679        let serialized = storage_delta.to_bytes();
680        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
681        assert_eq!(deserialized, storage_delta);
682
683        let storage_delta = AccountStorageDelta::from_iters(
684            [],
685            [(StorageSlotName::mock(2), Word::from([ONE, ONE, ONE, ONE]))],
686            [],
687        );
688        let serialized = storage_delta.to_bytes();
689        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
690        assert_eq!(deserialized, storage_delta);
691
692        let storage_delta = AccountStorageDelta::from_iters(
693            [],
694            [],
695            [(StorageSlotName::mock(3), StorageMapDelta::default())],
696        );
697        let serialized = storage_delta.to_bytes();
698        let deserialized = AccountStorageDelta::read_from_bytes(&serialized).unwrap();
699        assert_eq!(deserialized, storage_delta);
700    }
701
702    #[test]
703    fn test_serde_storage_map_delta() {
704        let storage_map_delta = StorageMapDelta::default();
705        let serialized = storage_map_delta.to_bytes();
706        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
707        assert_eq!(deserialized, storage_map_delta);
708
709        let storage_map_delta = StorageMapDelta::from_iters([Word::from([ONE, ONE, ONE, ONE])], []);
710        let serialized = storage_map_delta.to_bytes();
711        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
712        assert_eq!(deserialized, storage_map_delta);
713
714        let storage_map_delta =
715            StorageMapDelta::from_iters([], [(Word::empty(), Word::from([ONE, ONE, ONE, ONE]))]);
716        let serialized = storage_map_delta.to_bytes();
717        let deserialized = StorageMapDelta::read_from_bytes(&serialized).unwrap();
718        assert_eq!(deserialized, storage_map_delta);
719    }
720
721    #[test]
722    fn test_serde_storage_slot_value_delta() {
723        let slot_delta = StorageSlotDelta::with_empty_value();
724        let serialized = slot_delta.to_bytes();
725        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
726        assert_eq!(deserialized, slot_delta);
727
728        let slot_delta = StorageSlotDelta::Value(Word::from([1, 2, 3, 4u32]));
729        let serialized = slot_delta.to_bytes();
730        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
731        assert_eq!(deserialized, slot_delta);
732    }
733
734    #[test]
735    fn test_serde_storage_slot_map_delta() {
736        let slot_delta = StorageSlotDelta::with_empty_map();
737        let serialized = slot_delta.to_bytes();
738        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
739        assert_eq!(deserialized, slot_delta);
740
741        let map_delta = StorageMapDelta::from_iters(
742            [Word::from([1, 2, 3, 4u32])],
743            [(Word::from([5, 6, 7, 8u32]), Word::from([3, 4, 5, 6u32]))],
744        );
745        let slot_delta = StorageSlotDelta::Map(map_delta);
746        let serialized = slot_delta.to_bytes();
747        let deserialized = StorageSlotDelta::read_from_bytes(&serialized).unwrap();
748        assert_eq!(deserialized, slot_delta);
749    }
750
751    #[rstest::rstest]
752    #[case::some_some(Some(1), Some(2), Some(2))]
753    #[case::none_some(None, Some(2), Some(2))]
754    #[case::some_none(Some(1), None, None)]
755    #[test]
756    fn merge_items(
757        #[case] x: Option<u32>,
758        #[case] y: Option<u32>,
759        #[case] expected: Option<u32>,
760    ) -> anyhow::Result<()> {
761        /// Creates a delta containing the item as an update if Some, else with the item cleared.
762        fn create_delta(item: Option<u32>) -> AccountStorageDelta {
763            let slot_name = StorageSlotName::mock(123);
764            let item = item.map(|x| (slot_name.clone(), Word::from([x, 0, 0, 0])));
765
766            AccountStorageDelta::new()
767                .add_cleared_items(item.is_none().then_some(slot_name.clone()))
768                .add_updated_values(item)
769        }
770
771        let mut delta_x = create_delta(x);
772        let delta_y = create_delta(y);
773        let expected = create_delta(expected);
774
775        delta_x.merge(delta_y).context("failed to merge deltas")?;
776
777        assert_eq!(delta_x, expected);
778
779        Ok(())
780    }
781
782    #[rstest::rstest]
783    #[case::some_some(Some(1), Some(2), Some(2))]
784    #[case::none_some(None, Some(2), Some(2))]
785    #[case::some_none(Some(1), None, None)]
786    #[test]
787    fn merge_maps(#[case] x: Option<u32>, #[case] y: Option<u32>, #[case] expected: Option<u32>) {
788        fn create_delta(value: Option<u32>) -> StorageMapDelta {
789            let key = Word::from([10u32, 0, 0, 0]);
790            match value {
791                Some(value) => {
792                    StorageMapDelta::from_iters([], [(key, Word::from([value, 0, 0, 0]))])
793                },
794                None => StorageMapDelta::from_iters([key], []),
795            }
796        }
797
798        let mut delta_x = create_delta(x);
799        let delta_y = create_delta(y);
800        let expected = create_delta(expected);
801
802        delta_x.merge(delta_y);
803
804        assert_eq!(delta_x, expected);
805    }
806}