miden_objects/account/storage/
mod.rs1use alloc::{string::ToString, vec::Vec};
2
3use super::{
4 AccountError, AccountStorageDelta, ByteReader, ByteWriter, Deserializable,
5 DeserializationError, Digest, Felt, Hasher, Serializable, Word,
6};
7use crate::account::{AccountComponent, AccountType};
8
9mod slot;
10pub use slot::{StorageSlot, StorageSlotType};
11
12mod map;
13pub use map::StorageMap;
14
15mod header;
16pub use header::{AccountStorageHeader, StorageSlotHeader};
17
18mod partial;
19pub use partial::PartialStorage;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct AccountStorage {
35 slots: Vec<StorageSlot>,
36}
37
38impl AccountStorage {
39 pub const MAX_NUM_STORAGE_SLOTS: usize = 255;
41
42 pub fn new(slots: Vec<StorageSlot>) -> Result<AccountStorage, AccountError> {
52 let num_slots = slots.len();
53
54 if num_slots > Self::MAX_NUM_STORAGE_SLOTS {
55 return Err(AccountError::StorageTooManySlots(num_slots as u64));
56 }
57
58 Ok(Self { slots })
59 }
60
61 pub(super) fn from_components(
75 components: &[AccountComponent],
76 account_type: AccountType,
77 ) -> Result<AccountStorage, AccountError> {
78 let mut storage_slots = match account_type {
79 AccountType::FungibleFaucet => vec![StorageSlot::empty_value()],
80 AccountType::NonFungibleFaucet => vec![StorageSlot::empty_map()],
81 _ => vec![],
82 };
83
84 storage_slots
85 .extend(components.iter().flat_map(|component| component.storage_slots()).cloned());
86
87 Self::new(storage_slots)
88 }
89
90 pub fn commitment(&self) -> Digest {
95 build_slots_commitment(&self.slots)
96 }
97
98 pub fn slots(&self) -> &Vec<StorageSlot> {
100 &self.slots
101 }
102
103 pub fn to_header(&self) -> AccountStorageHeader {
105 AccountStorageHeader::new(
106 self.slots.iter().map(|slot| (slot.slot_type(), slot.value())).collect(),
107 )
108 }
109
110 pub fn get_item(&self, index: u8) -> Result<Digest, AccountError> {
115 self.slots
116 .get(index as usize)
117 .ok_or(AccountError::StorageIndexOutOfBounds {
118 slots_len: self.slots.len() as u8,
119 index,
120 })
121 .map(|slot| slot.value().into())
122 }
123
124 pub fn get_map_item(&self, index: u8, key: Word) -> Result<Word, AccountError> {
130 match self.slots.get(index as usize).ok_or(AccountError::StorageIndexOutOfBounds {
131 slots_len: self.slots.len() as u8,
132 index,
133 })? {
134 StorageSlot::Map(map) => Ok(map.get(&Digest::from(key))),
135 _ => Err(AccountError::StorageSlotNotMap(index)),
136 }
137 }
138
139 pub fn as_elements(&self) -> Vec<Felt> {
147 slots_as_elements(self.slots())
148 }
149
150 pub(super) fn apply_delta(&mut self, delta: &AccountStorageDelta) -> Result<(), AccountError> {
158 let len = self.slots.len() as u8;
159
160 for (&idx, map) in delta.maps().iter() {
162 let storage_slot = self
163 .slots
164 .get_mut(idx as usize)
165 .ok_or(AccountError::StorageIndexOutOfBounds { slots_len: len, index: idx })?;
166
167 let storage_map = match storage_slot {
168 StorageSlot::Map(map) => map,
169 _ => return Err(AccountError::StorageSlotNotMap(idx)),
170 };
171
172 storage_map.apply_delta(map);
173 }
174
175 for (&idx, &value) in delta.values().iter() {
177 self.set_item(idx, value)?;
178 }
179
180 Ok(())
181 }
182
183 pub fn set_item(&mut self, index: u8, value: Word) -> Result<Word, AccountError> {
192 let num_slots = self.slots.len();
194
195 if index as usize >= num_slots {
196 return Err(AccountError::StorageIndexOutOfBounds {
197 slots_len: self.slots.len() as u8,
198 index,
199 });
200 }
201
202 let old_value = match self.slots[index as usize] {
203 StorageSlot::Value(value) => value,
204 _ => return Err(AccountError::StorageSlotNotValue(index)),
206 };
207
208 self.slots[index as usize] = StorageSlot::Value(value);
210
211 Ok(old_value)
212 }
213
214 pub fn set_map_item(
223 &mut self,
224 index: u8,
225 key: Word,
226 value: Word,
227 ) -> Result<(Word, Word), AccountError> {
228 let num_slots = self.slots.len();
230
231 if index as usize >= num_slots {
232 return Err(AccountError::StorageIndexOutOfBounds {
233 slots_len: self.slots.len() as u8,
234 index,
235 });
236 }
237
238 let storage_map = match self.slots[index as usize] {
239 StorageSlot::Map(ref mut map) => map,
240 _ => return Err(AccountError::StorageSlotNotMap(index)),
241 };
242
243 let old_root = storage_map.root();
245
246 let old_value = storage_map.insert(key.into(), value);
248
249 Ok((old_root.into(), old_value))
250 }
251}
252
253impl IntoIterator for AccountStorage {
257 type Item = StorageSlot;
258 type IntoIter = alloc::vec::IntoIter<StorageSlot>;
259
260 fn into_iter(self) -> Self::IntoIter {
261 self.slots.into_iter()
262 }
263}
264
265fn slots_as_elements(slots: &[StorageSlot]) -> Vec<Felt> {
270 slots
271 .iter()
272 .flat_map(|slot| StorageSlotHeader::from(slot).as_elements())
273 .collect()
274}
275
276pub fn build_slots_commitment(slots: &[StorageSlot]) -> Digest {
278 let elements = slots_as_elements(slots);
279 Hasher::hash_elements(&elements)
280}
281
282impl Serializable for AccountStorage {
286 fn write_into<W: ByteWriter>(&self, target: &mut W) {
287 target.write_u8(self.slots().len() as u8);
288 target.write_many(self.slots());
289 }
290
291 fn get_size_hint(&self) -> usize {
292 let u8_size = 0u8.get_size_hint();
294 let mut size = u8_size;
295
296 for slot in self.slots() {
297 size += slot.get_size_hint();
298 }
299
300 size
301 }
302}
303
304impl Deserializable for AccountStorage {
305 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
306 let num_slots = source.read_u8()? as usize;
307 let slots = source.read_many::<StorageSlot>(num_slots)?;
308
309 Self::new(slots).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
310 }
311}
312
313#[cfg(test)]
317mod tests {
318 use super::{
319 AccountStorage, Deserializable, Serializable, StorageMap, Word, build_slots_commitment,
320 };
321 use crate::account::StorageSlot;
322
323 #[test]
324 fn test_serde_account_storage() {
325 let storage = AccountStorage::new(vec![]).unwrap();
327 let bytes = storage.to_bytes();
328 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
329
330 let storage = AccountStorage::new(vec![
332 StorageSlot::Value(Word::default()),
333 StorageSlot::Map(StorageMap::default()),
334 ])
335 .unwrap();
336 let bytes = storage.to_bytes();
337 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
338 }
339
340 #[test]
341 fn test_account_storage_slots_commitment() {
342 let storage = AccountStorage::mock();
343 let storage_slots_commitment = build_slots_commitment(storage.slots());
344 assert_eq!(storage_slots_commitment, storage.commitment())
345 }
346}