miden_objects/account/storage/
map.rs1use alloc::collections::BTreeMap;
2
3use miden_crypto::merkle::EmptySubtreeRoots;
4use vm_core::EMPTY_WORD;
5
6use super::{
7 ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Serializable, Word,
8};
9use crate::{
10 Hasher,
11 account::StorageMapDelta,
12 crypto::{
13 hash::rpo::RpoDigest,
14 merkle::{InnerNodeInfo, LeafIndex, SMT_DEPTH, Smt, SmtLeaf, SmtProof},
15 },
16 errors::StorageMapError,
17};
18
19pub const EMPTY_STORAGE_MAP_ROOT: Digest = *EmptySubtreeRoots::entry(StorageMap::TREE_DEPTH, 0);
24
25#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct StorageMap {
44 smt: Smt,
46 map: BTreeMap<RpoDigest, Word>,
51}
52
53impl StorageMap {
54 pub const TREE_DEPTH: u8 = SMT_DEPTH;
59
60 pub const EMPTY_VALUE: Word = Smt::EMPTY_VALUE;
62
63 pub fn new() -> Self {
70 StorageMap { smt: Smt::new(), map: BTreeMap::new() }
71 }
72
73 pub fn with_entries<I: ExactSizeIterator<Item = (RpoDigest, Word)>>(
80 entries: impl IntoIterator<Item = (RpoDigest, Word), IntoIter = I>,
81 ) -> Result<Self, StorageMapError> {
82 let mut map = BTreeMap::new();
83
84 for (key, value) in entries {
85 if let Some(prev_value) = map.insert(key, value) {
86 return Err(StorageMapError::DuplicateKey {
87 key,
88 value0: prev_value,
89 value1: value,
90 });
91 }
92 }
93
94 Ok(Self::from_btree_map(map))
95 }
96
97 fn from_btree_map(map: BTreeMap<RpoDigest, Word>) -> Self {
99 let hashed_keys_iter = map.iter().map(|(key, value)| (Self::hash_key(*key), *value));
100 let smt = Smt::with_entries(hashed_keys_iter)
101 .expect("btree maps should not contain duplicate keys");
102
103 StorageMap { smt, map }
104 }
105
106 pub fn root(&self) -> RpoDigest {
111 self.smt.root()
112 }
113
114 pub fn get(&self, key: &RpoDigest) -> Word {
117 self.map.get(key).copied().unwrap_or_default()
118 }
119
120 pub fn open(&self, key: &RpoDigest) -> SmtProof {
124 let key = Self::hash_key(*key);
125 self.smt.open(&key)
126 }
127
128 pub fn leaves(&self) -> impl Iterator<Item = (LeafIndex<SMT_DEPTH>, &SmtLeaf)> {
133 self.smt.leaves() }
135
136 pub fn entries(&self) -> impl Iterator<Item = (&RpoDigest, &Word)> {
138 self.map.iter()
139 }
140
141 pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
143 self.smt.inner_nodes() }
145
146 pub fn insert(&mut self, key: RpoDigest, value: Word) -> Word {
154 if value == EMPTY_WORD {
155 self.map.remove(&key);
156 } else {
157 self.map.insert(key, value);
158 }
159
160 let key = Self::hash_key(key);
161 self.smt.insert(key, value) }
163
164 pub fn apply_delta(&mut self, delta: &StorageMapDelta) -> Digest {
166 for (&key, &value) in delta.leaves().iter() {
168 self.insert(key, value);
169 }
170
171 self.root()
172 }
173
174 pub fn into_entries(self) -> BTreeMap<RpoDigest, Word> {
176 self.map
177 }
178
179 pub fn hash_key(key: RpoDigest) -> RpoDigest {
181 Hasher::hash_elements(key.as_elements())
182 }
183}
184
185impl Default for StorageMap {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191impl Serializable for StorageMap {
195 fn write_into<W: ByteWriter>(&self, target: &mut W) {
196 self.map.write_into(target);
197 }
198
199 fn get_size_hint(&self) -> usize {
200 self.smt.get_size_hint()
201 }
202}
203
204impl Deserializable for StorageMap {
205 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
206 let map = BTreeMap::read_from(source)?;
207 Ok(Self::from_btree_map(map))
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use assert_matches::assert_matches;
214 use miden_crypto::{Felt, hash::rpo::RpoDigest};
215
216 use super::{Deserializable, EMPTY_STORAGE_MAP_ROOT, Serializable, StorageMap, Word};
217 use crate::errors::StorageMapError;
218
219 #[test]
220 fn account_storage_serialization() {
221 let storage_map_default = StorageMap::default();
223 let bytes = storage_map_default.to_bytes();
224 assert_eq!(storage_map_default, StorageMap::read_from_bytes(&bytes).unwrap());
225
226 let storage_map_leaves_2: [(RpoDigest, Word); 2] = [
228 (
229 RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
230 [Felt::new(1_u64), Felt::new(2_u64), Felt::new(3_u64), Felt::new(4_u64)],
231 ),
232 (
233 RpoDigest::new([Felt::new(105), Felt::new(106), Felt::new(107), Felt::new(108)]),
234 [Felt::new(5_u64), Felt::new(6_u64), Felt::new(7_u64), Felt::new(8_u64)],
235 ),
236 ];
237 let storage_map = StorageMap::with_entries(storage_map_leaves_2).unwrap();
238
239 let bytes = storage_map.to_bytes();
240 let deserialized_map = StorageMap::read_from_bytes(&bytes).unwrap();
241
242 assert_eq!(storage_map.root(), deserialized_map.root());
243
244 assert_eq!(storage_map, deserialized_map);
245 }
246
247 #[test]
248 fn test_empty_storage_map_constants() {
249 assert_eq!(StorageMap::default().root(), EMPTY_STORAGE_MAP_ROOT);
251 }
252
253 #[test]
254 fn account_storage_map_fails_on_duplicate_entries() {
255 let storage_map_leaves_2: [(RpoDigest, Word); 2] = [
257 (
258 RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
259 [Felt::new(1_u64), Felt::new(2_u64), Felt::new(3_u64), Felt::new(4_u64)],
260 ),
261 (
262 RpoDigest::new([Felt::new(101), Felt::new(102), Felt::new(103), Felt::new(104)]),
263 [Felt::new(5_u64), Felt::new(6_u64), Felt::new(7_u64), Felt::new(8_u64)],
264 ),
265 ];
266
267 let error = StorageMap::with_entries(storage_map_leaves_2).unwrap_err();
268 assert_matches!(error, StorageMapError::DuplicateKey { .. });
269 }
270}