miden_protocol/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 Serializable,
13 Word,
14};
15use crate::account::{AccountComponent, AccountType};
16use crate::crypto::SequentialCommit;
17use crate::utils::sync::LazyLock;
18
19mod slot;
20pub use slot::{StorageSlot, StorageSlotContent, StorageSlotId, StorageSlotName, StorageSlotType};
21
22mod map;
23pub use map::{PartialStorageMap, StorageMap, StorageMapWitness};
24
25mod header;
26pub use header::{AccountStorageHeader, StorageSlotHeader};
27
28mod partial;
29pub use partial::PartialStorage;
30
31static FAUCET_SYSDATA_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
32 StorageSlotName::new("miden::protocol::faucet::sysdata")
33 .expect("storage slot name should be valid")
34});
35
36static RESERVED_SLOT_NAMES: LazyLock<Vec<StorageSlotName>> =
37 LazyLock::new(|| vec![FAUCET_SYSDATA_SLOT_NAME.clone()]);
38
39pub fn is_reserved_slot_name(slot_name: &StorageSlotName) -> bool {
41 RESERVED_SLOT_NAMES.iter().any(|reserved| reserved.id() == slot_name.id())
42}
43
44#[derive(Debug, Clone, Default, PartialEq, Eq)]
65pub struct AccountStorage {
66 slots: Vec<StorageSlot>,
67}
68
69impl AccountStorage {
70 pub const MAX_NUM_STORAGE_SLOTS: usize = 255;
72
73 pub fn new(mut slots: Vec<StorageSlot>) -> Result<AccountStorage, AccountError> {
86 let num_slots = slots.len();
87
88 if num_slots > Self::MAX_NUM_STORAGE_SLOTS {
89 return Err(AccountError::StorageTooManySlots(num_slots as u64));
90 }
91
92 slots.sort_unstable();
94
95 for slots in slots.windows(2) {
98 if slots[0].id() == slots[1].id() {
99 return Err(AccountError::DuplicateStorageSlotName(slots[0].name().clone()));
100 }
101 }
102
103 Ok(Self { slots })
104 }
105
106 pub(super) fn from_components(
121 components: Vec<AccountComponent>,
122 account_type: AccountType,
123 ) -> Result<AccountStorage, AccountError> {
124 let mut storage_slots = match account_type {
125 AccountType::FungibleFaucet => {
126 vec![StorageSlot::with_empty_value(Self::faucet_sysdata_slot().clone())]
127 },
128 AccountType::NonFungibleFaucet => {
129 vec![StorageSlot::with_empty_map(Self::faucet_sysdata_slot().clone())]
130 },
131 _ => vec![],
132 };
133
134 for component_slot in components.into_iter().flat_map(|component| {
135 let AccountComponent { storage_slots, .. } = component;
136 storage_slots.into_iter()
137 }) {
138 if is_reserved_slot_name(component_slot.name()) {
139 return Err(AccountError::StorageSlotNameMustNotBeFaucetSysdata);
140 }
141
142 storage_slots.push(component_slot);
143 }
144
145 Self::new(storage_slots)
146 }
147
148 pub fn faucet_sysdata_slot() -> &'static StorageSlotName {
153 &FAUCET_SYSDATA_SLOT_NAME
154 }
155
156 pub fn to_elements(&self) -> Vec<Felt> {
164 <Self as SequentialCommit>::to_elements(self)
165 }
166
167 pub fn to_commitment(&self) -> Word {
169 <Self as SequentialCommit>::to_commitment(self)
170 }
171
172 pub fn num_slots(&self) -> u8 {
174 self.slots.len() as u8
177 }
178
179 pub fn slots(&self) -> &[StorageSlot] {
181 &self.slots
182 }
183
184 pub fn into_slots(self) -> Vec<StorageSlot> {
186 self.slots
187 }
188
189 pub fn to_header(&self) -> AccountStorageHeader {
191 AccountStorageHeader::new(self.slots.iter().map(StorageSlotHeader::from).collect())
192 .expect("slots should be valid as ensured by AccountStorage")
193 }
194
195 pub fn get(&self, slot_name: &StorageSlotName) -> Option<&StorageSlot> {
198 self.slots.iter().find(|slot| slot.name().id() == slot_name.id())
199 }
200
201 fn get_mut(&mut self, slot_name: &StorageSlotName) -> Option<&mut StorageSlot> {
204 self.slots.iter_mut().find(|slot| slot.name().id() == slot_name.id())
205 }
206
207 pub fn get_item(&self, slot_name: &StorageSlotName) -> Result<Word, AccountError> {
214 self.get(slot_name)
215 .map(|slot| slot.content().value())
216 .ok_or_else(|| AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() })
217 }
218
219 pub fn get_map_item(
227 &self,
228 slot_name: &StorageSlotName,
229 key: Word,
230 ) -> Result<Word, AccountError> {
231 self.get(slot_name)
232 .ok_or_else(|| AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() })
233 .and_then(|slot| match slot.content() {
234 StorageSlotContent::Map(map) => Ok(map.get(&key)),
235 _ => Err(AccountError::StorageSlotNotMap(slot_name.clone())),
236 })
237 }
238
239 pub(super) fn apply_delta(&mut self, delta: &AccountStorageDelta) -> Result<(), AccountError> {
249 for (slot_name, &value) in delta.values() {
251 self.set_item(slot_name, value)?;
252 }
253
254 for (slot_name, map_delta) in delta.maps() {
256 let slot = self
257 .get_mut(slot_name)
258 .ok_or(AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() })?;
259
260 let storage_map = match slot.content_mut() {
261 StorageSlotContent::Map(map) => map,
262 _ => return Err(AccountError::StorageSlotNotMap(slot_name.clone())),
263 };
264
265 storage_map.apply_delta(map_delta)?;
266 }
267
268 Ok(())
269 }
270
271 pub fn set_item(
282 &mut self,
283 slot_name: &StorageSlotName,
284 value: Word,
285 ) -> Result<Word, AccountError> {
286 let slot = self.get_mut(slot_name).ok_or_else(|| {
287 AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() }
288 })?;
289
290 let StorageSlotContent::Value(old_value) = slot.content() else {
291 return Err(AccountError::StorageSlotNotValue(slot_name.clone()));
292 };
293 let old_value = *old_value;
294
295 let mut new_slot = StorageSlotContent::Value(value);
296 core::mem::swap(slot.content_mut(), &mut new_slot);
297
298 Ok(old_value)
299 }
300
301 pub fn set_map_item(
312 &mut self,
313 slot_name: &StorageSlotName,
314 raw_key: Word,
315 value: Word,
316 ) -> Result<(Word, Word), AccountError> {
317 let slot = self.get_mut(slot_name).ok_or_else(|| {
318 AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() }
319 })?;
320
321 let StorageSlotContent::Map(storage_map) = slot.content_mut() else {
322 return Err(AccountError::StorageSlotNotMap(slot_name.clone()));
323 };
324
325 let old_root = storage_map.root();
326
327 let old_value = storage_map.insert(raw_key, value)?;
328
329 Ok((old_root, old_value))
330 }
331}
332
333impl IntoIterator for AccountStorage {
337 type Item = StorageSlot;
338 type IntoIter = alloc::vec::IntoIter<StorageSlot>;
339
340 fn into_iter(self) -> Self::IntoIter {
341 self.slots.into_iter()
342 }
343}
344
345impl SequentialCommit for AccountStorage {
349 type Commitment = Word;
350
351 fn to_elements(&self) -> Vec<Felt> {
352 self.slots()
353 .iter()
354 .flat_map(|slot| {
355 StorageSlotHeader::new(
356 slot.name().clone(),
357 slot.content().slot_type(),
358 slot.content().value(),
359 )
360 .to_elements()
361 })
362 .collect()
363 }
364}
365
366impl Serializable for AccountStorage {
370 fn write_into<W: ByteWriter>(&self, target: &mut W) {
371 target.write_u8(self.slots().len() as u8);
372 target.write_many(self.slots());
373 }
374
375 fn get_size_hint(&self) -> usize {
376 let u8_size = 0u8.get_size_hint();
378 let mut size = u8_size;
379
380 for slot in self.slots() {
381 size += slot.get_size_hint();
382 }
383
384 size
385 }
386}
387
388impl Deserializable for AccountStorage {
389 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
390 let num_slots = source.read_u8()? as usize;
391 let slots = source.read_many::<StorageSlot>(num_slots)?;
392
393 Self::new(slots).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
394 }
395}
396
397#[cfg(test)]
401mod tests {
402 use assert_matches::assert_matches;
403
404 use super::{AccountStorage, Deserializable, Serializable};
405 use crate::account::{AccountStorageHeader, StorageSlot, StorageSlotHeader, StorageSlotName};
406 use crate::errors::AccountError;
407
408 #[test]
409 fn test_serde_account_storage() -> anyhow::Result<()> {
410 let storage = AccountStorage::new(vec![]).unwrap();
412 let bytes = storage.to_bytes();
413 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
414
415 let storage = AccountStorage::new(vec![
417 StorageSlot::with_empty_value(StorageSlotName::new("miden::test::value")?),
418 StorageSlot::with_empty_map(StorageSlotName::new("miden::test::map")?),
419 ])
420 .unwrap();
421 let bytes = storage.to_bytes();
422 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
423
424 Ok(())
425 }
426
427 #[test]
428 fn test_get_slot_by_name() -> anyhow::Result<()> {
429 let counter_slot = StorageSlotName::new("miden::test::counter")?;
430 let map_slot = StorageSlotName::new("miden::test::map")?;
431
432 let slots = vec![
433 StorageSlot::with_empty_value(counter_slot.clone()),
434 StorageSlot::with_empty_map(map_slot.clone()),
435 ];
436 let storage = AccountStorage::new(slots.clone())?;
437
438 assert_eq!(storage.get(&counter_slot).unwrap(), &slots[0]);
439 assert_eq!(storage.get(&map_slot).unwrap(), &slots[1]);
440
441 Ok(())
442 }
443
444 #[test]
445 fn test_account_storage_and_header_fail_on_duplicate_slot_name() -> anyhow::Result<()> {
446 let slot_name0 = StorageSlotName::mock(0);
447 let slot_name1 = StorageSlotName::mock(1);
448 let slot_name2 = StorageSlotName::mock(2);
449
450 let mut slots = vec![
451 StorageSlot::with_empty_value(slot_name0.clone()),
452 StorageSlot::with_empty_value(slot_name1.clone()),
453 StorageSlot::with_empty_map(slot_name0.clone()),
454 StorageSlot::with_empty_value(slot_name2.clone()),
455 ];
456
457 let err = AccountStorage::new(slots.clone()).unwrap_err();
460
461 assert_matches!(err, AccountError::DuplicateStorageSlotName(name) => {
462 assert_eq!(name, slot_name0);
463 });
464
465 slots.sort_unstable();
466 let err = AccountStorageHeader::new(slots.iter().map(StorageSlotHeader::from).collect())
467 .unwrap_err();
468
469 assert_matches!(err, AccountError::DuplicateStorageSlotName(name) => {
470 assert_eq!(name, slot_name0);
471 });
472
473 Ok(())
474 }
475}