miden_objects/account/storage/
map.rs

1use miden_crypto::merkle::{EmptySubtreeRoots, MerkleError};
2
3use super::{
4    ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Serializable, Word,
5};
6use crate::{
7    account::StorageMapDelta,
8    crypto::{
9        hash::rpo::RpoDigest,
10        merkle::{InnerNodeInfo, LeafIndex, SMT_DEPTH, Smt, SmtLeaf, SmtProof},
11    },
12};
13
14// ACCOUNT STORAGE MAP
15// ================================================================================================
16
17/// Empty storage map root.
18pub const EMPTY_STORAGE_MAP_ROOT: Digest =
19    *EmptySubtreeRoots::entry(StorageMap::STORAGE_MAP_TREE_DEPTH, 0);
20
21/// Account storage map is a Sparse Merkle Tree of depth 64. It can be used to store more data as
22/// there is in plain usage of the storage slots. The root of the SMT consumes one account storage
23/// slot.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct StorageMap {
26    map: Smt,
27}
28
29impl StorageMap {
30    // CONSTANTS
31    // --------------------------------------------------------------------------------------------
32
33    /// Depth of the storage tree.
34    pub const STORAGE_MAP_TREE_DEPTH: u8 = SMT_DEPTH;
35
36    /// The default value of empty leaves.
37    pub const EMPTY_VALUE: Word = Smt::EMPTY_VALUE;
38
39    // CONSTRUCTOR
40    // --------------------------------------------------------------------------------------------
41
42    /// Returns a new [StorageMap].
43    ///
44    /// All leaves in the returned tree are set to [Self::EMPTY_VALUE].
45    pub fn new() -> Self {
46        StorageMap { map: Smt::new() }
47    }
48
49    /// Creates a new [`StorageMap`] from the provided key-value entries.
50    ///
51    /// # Errors
52    ///
53    /// Returns an error if the provided entries contain multiple values for the same key.
54    pub fn with_entries(
55        entries: impl IntoIterator<Item = (RpoDigest, Word)>,
56    ) -> Result<Self, MerkleError> {
57        Smt::with_entries(entries).map(|map| StorageMap { map })
58    }
59
60    // PUBLIC ACCESSORS
61    // --------------------------------------------------------------------------------------------
62
63    pub const fn depth(&self) -> u8 {
64        SMT_DEPTH
65    }
66
67    pub fn root(&self) -> RpoDigest {
68        self.map.root() // Delegate to Smt's root method
69    }
70
71    pub fn get_leaf(&self, key: &RpoDigest) -> SmtLeaf {
72        self.map.get_leaf(key) // Delegate to Smt's get_leaf method
73    }
74
75    pub fn get_value(&self, key: &RpoDigest) -> Word {
76        self.map.get_value(key) // Delegate to Smt's get_value method
77    }
78
79    pub fn open(&self, key: &RpoDigest) -> SmtProof {
80        self.map.open(key) // Delegate to Smt's open method
81    }
82
83    // ITERATORS
84    // --------------------------------------------------------------------------------------------
85    pub fn leaves(&self) -> impl Iterator<Item = (LeafIndex<SMT_DEPTH>, &SmtLeaf)> {
86        self.map.leaves() // Delegate to Smt's leaves method
87    }
88
89    pub fn entries(&self) -> impl Iterator<Item = &(RpoDigest, Word)> {
90        self.map.entries() // Delegate to Smt's entries method
91    }
92
93    pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
94        self.map.inner_nodes() // Delegate to Smt's inner_nodes method
95    }
96
97    // DATA MUTATORS
98    // --------------------------------------------------------------------------------------------
99    pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word {
100        self.map.insert(key, value) // Delegate to Smt's insert method
101    }
102
103    /// Applies the provided delta to this account storage.
104    pub fn apply_delta(&mut self, delta: &StorageMapDelta) -> Digest {
105        // apply the updated and cleared leaves to the storage map
106        for (&key, &value) in delta.leaves().iter() {
107            self.insert(key, value);
108        }
109
110        self.root()
111    }
112}
113
114impl Default for StorageMap {
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120// SERIALIZATION
121// ================================================================================================
122
123impl Serializable for StorageMap {
124    fn write_into<W: ByteWriter>(&self, target: &mut W) {
125        self.map.write_into(target)
126    }
127
128    fn get_size_hint(&self) -> usize {
129        self.map.get_size_hint()
130    }
131}
132
133impl Deserializable for StorageMap {
134    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
135        let smt = Smt::read_from(source)?;
136        Ok(StorageMap { map: smt })
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use assert_matches::assert_matches;
143    use miden_crypto::{Felt, hash::rpo::RpoDigest, merkle::MerkleError};
144
145    use super::{Deserializable, EMPTY_STORAGE_MAP_ROOT, Serializable, StorageMap, Word};
146
147    #[test]
148    fn account_storage_serialization() {
149        // StorageMap for default types (empty map)
150        let storage_map_default = StorageMap::default();
151        let bytes = storage_map_default.to_bytes();
152        assert_eq!(storage_map_default, StorageMap::read_from_bytes(&bytes).unwrap());
153
154        // StorageMap with values
155        let storage_map_leaves_2: [(RpoDigest, Word); 2] = [
156            (
157                RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
158                [Felt::new(1_u64), Felt::new(2_u64), Felt::new(3_u64), Felt::new(4_u64)],
159            ),
160            (
161                RpoDigest::new([Felt::new(105), Felt::new(106), Felt::new(107), Felt::new(108)]),
162                [Felt::new(5_u64), Felt::new(6_u64), Felt::new(7_u64), Felt::new(8_u64)],
163            ),
164        ];
165        let storage_map = StorageMap::with_entries(storage_map_leaves_2).unwrap();
166
167        let bytes = storage_map.to_bytes();
168        assert_eq!(storage_map, StorageMap::read_from_bytes(&bytes).unwrap());
169    }
170
171    #[test]
172    fn test_empty_storage_map_constants() {
173        // If these values don't match, update the constants.
174        assert_eq!(StorageMap::default().root(), EMPTY_STORAGE_MAP_ROOT);
175    }
176
177    #[test]
178    fn account_storage_map_fails_on_duplicate_entries() {
179        // StorageMap with values
180        let storage_map_leaves_2: [(RpoDigest, Word); 2] = [
181            (
182                RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
183                [Felt::new(1_u64), Felt::new(2_u64), Felt::new(3_u64), Felt::new(4_u64)],
184            ),
185            (
186                RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
187                [Felt::new(5_u64), Felt::new(6_u64), Felt::new(7_u64), Felt::new(8_u64)],
188            ),
189        ];
190
191        let error = StorageMap::with_entries(storage_map_leaves_2).unwrap_err();
192        assert_matches!(error, MerkleError::DuplicateValuesForIndex(_));
193    }
194}