miden_objects/account/storage/
mod.rs1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use super::{
5 AccountError,
6 AccountStorageDelta,
7 ByteReader,
8 ByteWriter,
9 Deserializable,
10 DeserializationError,
11 Felt,
12 Hasher,
13 Serializable,
14 Word,
15};
16use crate::account::{AccountComponent, AccountType};
17
18mod slot;
19pub use slot::{SlotName, StorageSlot, StorageSlotType};
20
21mod map;
22pub use map::{PartialStorageMap, StorageMap, StorageMapWitness};
23
24mod header;
25pub use header::{AccountStorageHeader, StorageSlotHeader};
26
27mod partial;
28pub use partial::PartialStorage;
29
30#[derive(Debug, Clone, Default, PartialEq, Eq)]
43pub struct AccountStorage {
44 slots: Vec<StorageSlot>,
45}
46
47impl AccountStorage {
48 pub const MAX_NUM_STORAGE_SLOTS: usize = 255;
50
51 pub fn new(slots: Vec<StorageSlot>) -> Result<AccountStorage, AccountError> {
61 let num_slots = slots.len();
62
63 if num_slots > Self::MAX_NUM_STORAGE_SLOTS {
64 return Err(AccountError::StorageTooManySlots(num_slots as u64));
65 }
66
67 Ok(Self { slots })
68 }
69
70 pub(super) fn from_components(
84 components: &[AccountComponent],
85 account_type: AccountType,
86 ) -> Result<AccountStorage, AccountError> {
87 let mut storage_slots = match account_type {
88 AccountType::FungibleFaucet => vec![StorageSlot::empty_value()],
89 AccountType::NonFungibleFaucet => vec![StorageSlot::empty_map()],
90 _ => vec![],
91 };
92
93 storage_slots
94 .extend(components.iter().flat_map(|component| component.storage_slots()).cloned());
95
96 Self::new(storage_slots)
97 }
98
99 pub fn commitment(&self) -> Word {
104 build_slots_commitment(&self.slots)
105 }
106
107 pub fn num_slots(&self) -> u8 {
109 self.slots.len() as u8
112 }
113
114 pub fn slots(&self) -> &[StorageSlot] {
116 &self.slots
117 }
118
119 pub fn into_slots(self) -> Vec<StorageSlot> {
121 self.slots
122 }
123
124 pub fn to_header(&self) -> AccountStorageHeader {
126 AccountStorageHeader::new(
127 self.slots.iter().map(|slot| (slot.slot_type(), slot.value())).collect(),
128 )
129 }
130
131 pub fn get_item(&self, index: u8) -> Result<Word, AccountError> {
136 self.slots
137 .get(index as usize)
138 .ok_or(AccountError::StorageIndexOutOfBounds {
139 slots_len: self.slots.len() as u8,
140 index,
141 })
142 .map(|slot| slot.value())
143 }
144
145 pub fn get_map_item(&self, index: u8, key: Word) -> Result<Word, AccountError> {
151 match self.slots.get(index as usize).ok_or(AccountError::StorageIndexOutOfBounds {
152 slots_len: self.slots.len() as u8,
153 index,
154 })? {
155 StorageSlot::Map(map) => Ok(map.get(&key)),
156 _ => Err(AccountError::StorageSlotNotMap(index)),
157 }
158 }
159
160 pub fn as_elements(&self) -> Vec<Felt> {
168 slots_as_elements(self.slots())
169 }
170
171 pub(super) fn apply_delta(&mut self, delta: &AccountStorageDelta) -> Result<(), AccountError> {
179 let len = self.slots.len() as u8;
180
181 for (&idx, map) in delta.maps().iter() {
183 let storage_slot = self
184 .slots
185 .get_mut(idx as usize)
186 .ok_or(AccountError::StorageIndexOutOfBounds { slots_len: len, index: idx })?;
187
188 let storage_map = match storage_slot {
189 StorageSlot::Map(map) => map,
190 _ => return Err(AccountError::StorageSlotNotMap(idx)),
191 };
192
193 storage_map.apply_delta(map)?;
194 }
195
196 for (&idx, &value) in delta.values().iter() {
198 self.set_item(idx, value)?;
199 }
200
201 Ok(())
202 }
203
204 pub fn set_item(&mut self, index: u8, value: Word) -> Result<Word, AccountError> {
213 let num_slots = self.slots.len();
215
216 if index as usize >= num_slots {
217 return Err(AccountError::StorageIndexOutOfBounds {
218 slots_len: self.slots.len() as u8,
219 index,
220 });
221 }
222
223 let old_value = match self.slots[index as usize] {
224 StorageSlot::Value(value) => value,
225 _ => return Err(AccountError::StorageSlotNotValue(index)),
227 };
228
229 self.slots[index as usize] = StorageSlot::Value(value);
231
232 Ok(old_value)
233 }
234
235 pub fn set_map_item(
244 &mut self,
245 index: u8,
246 key: Word,
247 value: Word,
248 ) -> Result<(Word, Word), AccountError> {
249 let num_slots = self.slots.len();
251
252 if index as usize >= num_slots {
253 return Err(AccountError::StorageIndexOutOfBounds {
254 slots_len: self.slots.len() as u8,
255 index,
256 });
257 }
258
259 let storage_map = match self.slots[index as usize] {
260 StorageSlot::Map(ref mut map) => map,
261 _ => return Err(AccountError::StorageSlotNotMap(index)),
262 };
263
264 let old_root = storage_map.root();
266
267 let old_value = storage_map.insert(key, value)?;
269
270 Ok((old_root, old_value))
271 }
272}
273
274impl IntoIterator for AccountStorage {
278 type Item = StorageSlot;
279 type IntoIter = alloc::vec::IntoIter<StorageSlot>;
280
281 fn into_iter(self) -> Self::IntoIter {
282 self.slots.into_iter()
283 }
284}
285
286fn slots_as_elements(slots: &[StorageSlot]) -> Vec<Felt> {
291 slots
292 .iter()
293 .flat_map(|slot| StorageSlotHeader::from(slot).as_elements())
294 .collect()
295}
296
297pub fn build_slots_commitment(slots: &[StorageSlot]) -> Word {
299 let elements = slots_as_elements(slots);
300 Hasher::hash_elements(&elements)
301}
302
303impl Serializable for AccountStorage {
307 fn write_into<W: ByteWriter>(&self, target: &mut W) {
308 target.write_u8(self.slots().len() as u8);
309 target.write_many(self.slots());
310 }
311
312 fn get_size_hint(&self) -> usize {
313 let u8_size = 0u8.get_size_hint();
315 let mut size = u8_size;
316
317 for slot in self.slots() {
318 size += slot.get_size_hint();
319 }
320
321 size
322 }
323}
324
325impl Deserializable for AccountStorage {
326 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
327 let num_slots = source.read_u8()? as usize;
328 let slots = source.read_many::<StorageSlot>(num_slots)?;
329
330 Self::new(slots).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
331 }
332}
333
334#[cfg(test)]
338mod tests {
339 use super::{
340 AccountStorage,
341 Deserializable,
342 Serializable,
343 StorageMap,
344 Word,
345 build_slots_commitment,
346 };
347 use crate::account::StorageSlot;
348
349 #[test]
350 fn test_serde_account_storage() {
351 let storage = AccountStorage::new(vec![]).unwrap();
353 let bytes = storage.to_bytes();
354 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
355
356 let storage = AccountStorage::new(vec![
358 StorageSlot::Value(Word::empty()),
359 StorageSlot::Map(StorageMap::default()),
360 ])
361 .unwrap();
362 let bytes = storage.to_bytes();
363 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
364 }
365
366 #[test]
367 fn test_account_storage_slots_commitment() {
368 let storage = AccountStorage::mock();
369 let storage_slots_commitment = build_slots_commitment(storage.slots());
370 assert_eq!(storage_slots_commitment, storage.commitment())
371 }
372}