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
18#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct AccountStorage {
32 slots: Vec<StorageSlot>,
33}
34
35impl AccountStorage {
36 pub const MAX_NUM_STORAGE_SLOTS: usize = 255;
38
39 pub fn new(slots: Vec<StorageSlot>) -> Result<AccountStorage, AccountError> {
49 let num_slots = slots.len();
50
51 if num_slots > Self::MAX_NUM_STORAGE_SLOTS {
52 return Err(AccountError::StorageTooManySlots(num_slots as u64));
53 }
54
55 Ok(Self { slots })
56 }
57
58 pub(super) fn from_components(
72 components: &[AccountComponent],
73 account_type: AccountType,
74 ) -> Result<AccountStorage, AccountError> {
75 let mut storage_slots = match account_type {
76 AccountType::FungibleFaucet => vec![StorageSlot::empty_value()],
77 AccountType::NonFungibleFaucet => vec![StorageSlot::empty_map()],
78 _ => vec![],
79 };
80
81 storage_slots
82 .extend(components.iter().flat_map(|component| component.storage_slots()).cloned());
83
84 Self::new(storage_slots)
85 }
86
87 pub fn slots(&self) -> &Vec<StorageSlot> {
92 &self.slots
93 }
94
95 pub fn commitment(&self) -> Digest {
97 build_slots_commitment(&self.slots)
98 }
99
100 pub fn as_elements(&self) -> Vec<Felt> {
108 slots_as_elements(self.slots())
109 }
110
111 pub fn get_item(&self, index: u8) -> Result<Digest, AccountError> {
116 self.slots
117 .get(index as usize)
118 .ok_or(AccountError::StorageIndexOutOfBounds {
119 slots_len: self.slots.len() as u8,
120 index,
121 })
122 .map(|slot| slot.value().into())
123 }
124
125 pub fn get_map_item(&self, index: u8, key: Word) -> Result<Word, AccountError> {
131 match self.slots.get(index as usize).ok_or(AccountError::StorageIndexOutOfBounds {
132 slots_len: self.slots.len() as u8,
133 index,
134 })? {
135 StorageSlot::Map(ref map) => Ok(map.get_value(&Digest::from(key))),
136 _ => Err(AccountError::StorageSlotNotMap(index)),
137 }
138 }
139
140 pub fn get_header(&self) -> AccountStorageHeader {
142 AccountStorageHeader::new(
143 self.slots.iter().map(|slot| (slot.slot_type(), slot.value())).collect(),
144 )
145 }
146
147 pub(super) fn apply_delta(&mut self, delta: &AccountStorageDelta) -> Result<(), AccountError> {
155 let len = self.slots.len() as u8;
156
157 for (&idx, map) in delta.maps().iter() {
159 let storage_slot = self
160 .slots
161 .get_mut(idx as usize)
162 .ok_or(AccountError::StorageIndexOutOfBounds { slots_len: len, index: idx })?;
163
164 let storage_map = match storage_slot {
165 StorageSlot::Map(map) => map,
166 _ => return Err(AccountError::StorageSlotNotMap(idx)),
167 };
168
169 storage_map.apply_delta(map);
170 }
171
172 for (&idx, &value) in delta.values().iter() {
174 self.set_item(idx, value)?;
175 }
176
177 Ok(())
178 }
179
180 pub fn set_item(&mut self, index: u8, value: Word) -> Result<Word, AccountError> {
189 let num_slots = self.slots.len();
191
192 if index as usize >= num_slots {
193 return Err(AccountError::StorageIndexOutOfBounds {
194 slots_len: self.slots.len() as u8,
195 index,
196 });
197 }
198
199 let old_value = match self.slots[index as usize] {
200 StorageSlot::Value(value) => value,
201 _ => return Err(AccountError::StorageSlotNotValue(index)),
203 };
204
205 self.slots[index as usize] = StorageSlot::Value(value);
207
208 Ok(old_value)
209 }
210
211 pub fn set_map_item(
220 &mut self,
221 index: u8,
222 key: Word,
223 value: Word,
224 ) -> Result<(Word, Word), AccountError> {
225 let num_slots = self.slots.len();
227
228 if index as usize >= num_slots {
229 return Err(AccountError::StorageIndexOutOfBounds {
230 slots_len: self.slots.len() as u8,
231 index,
232 });
233 }
234
235 let storage_map = match self.slots[index as usize] {
236 StorageSlot::Map(ref mut map) => map,
237 _ => return Err(AccountError::StorageSlotNotMap(index)),
238 };
239
240 let old_root = storage_map.root();
242
243 let old_value = storage_map.insert(key.into(), value);
245
246 Ok((old_root.into(), old_value))
247 }
248}
249
250impl IntoIterator for AccountStorage {
254 type Item = StorageSlot;
255 type IntoIter = alloc::vec::IntoIter<StorageSlot>;
256
257 fn into_iter(self) -> Self::IntoIter {
258 self.slots.into_iter()
259 }
260}
261
262fn slots_as_elements(slots: &[StorageSlot]) -> Vec<Felt> {
267 slots
268 .iter()
269 .flat_map(|slot| StorageSlotHeader::from(slot).as_elements())
270 .collect()
271}
272
273fn build_slots_commitment(slots: &[StorageSlot]) -> Digest {
275 let elements = slots_as_elements(slots);
276 Hasher::hash_elements(&elements)
277}
278
279impl Serializable for AccountStorage {
283 fn write_into<W: ByteWriter>(&self, target: &mut W) {
284 target.write_u8(self.slots().len() as u8);
285 target.write_many(self.slots());
286 }
287
288 fn get_size_hint(&self) -> usize {
289 let u8_size = 0u8.get_size_hint();
291 let mut size = u8_size;
292
293 for slot in self.slots() {
294 size += slot.get_size_hint();
295 }
296
297 size
298 }
299}
300
301impl Deserializable for AccountStorage {
302 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
303 let num_slots = source.read_u8()? as usize;
304 let slots = source.read_many::<StorageSlot>(num_slots)?;
305
306 Self::new(slots).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
307 }
308}
309
310#[cfg(test)]
314mod tests {
315 use super::{
316 build_slots_commitment, AccountStorage, Deserializable, Serializable, StorageMap, Word,
317 };
318 use crate::account::StorageSlot;
319
320 #[test]
321 fn test_serde_account_storage() {
322 let storage = AccountStorage::new(vec![]).unwrap();
324 let bytes = storage.to_bytes();
325 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
326
327 let storage = AccountStorage::new(vec![
329 StorageSlot::Value(Word::default()),
330 StorageSlot::Map(StorageMap::default()),
331 ])
332 .unwrap();
333 let bytes = storage.to_bytes();
334 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
335 }
336
337 #[test]
338 fn test_account_storage_slots_commitment() {
339 let storage = AccountStorage::mock();
340 let storage_slots_commitment = build_slots_commitment(storage.slots());
341 assert_eq!(storage_slots_commitment, storage.commitment())
342 }
343}