1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use super::{
5 AccountError,
6 AccountStoragePatch,
7 ByteReader,
8 ByteWriter,
9 Deserializable,
10 DeserializationError,
11 Felt,
12 Serializable,
13 Word,
14};
15use crate::account::{
16 AccountComponent,
17 StorageMapPatch,
18 StorageMapPatchEntries,
19 StorageSlotPatch,
20 StorageValuePatch,
21};
22use crate::crypto::SequentialCommit;
23
24pub(crate) mod slot;
25pub use slot::{StorageSlot, StorageSlotContent, StorageSlotId, StorageSlotName, StorageSlotType};
26
27mod map;
28pub use map::{PartialStorageMap, StorageMap, StorageMapKey, StorageMapKeyHash, StorageMapWitness};
29
30mod header;
31pub use header::{AccountStorageHeader, StorageSlotHeader};
32
33mod partial;
34pub use partial::PartialStorage;
35
36#[derive(Debug, Clone, Default, PartialEq, Eq)]
57pub struct AccountStorage {
58 slots: Vec<StorageSlot>,
59}
60
61impl AccountStorage {
62 pub const MAX_NUM_STORAGE_SLOTS: usize = 255;
64
65 pub fn new(mut slots: Vec<StorageSlot>) -> Result<AccountStorage, AccountError> {
78 let num_slots = slots.len();
79
80 if num_slots > Self::MAX_NUM_STORAGE_SLOTS {
81 return Err(AccountError::StorageTooManySlots(num_slots as u64));
82 }
83
84 slots.sort_unstable_by(|a, b| a.name().cmp(b.name()));
86
87 for slots in slots.windows(2) {
90 if slots[0].id() == slots[1].id() {
91 return Err(AccountError::DuplicateStorageSlotName(slots[0].name().clone()));
92 }
93 }
94
95 Ok(Self { slots })
96 }
97
98 pub(super) fn from_components(
106 components: Vec<AccountComponent>,
107 ) -> Result<AccountStorage, AccountError> {
108 let storage_slots = components
109 .into_iter()
110 .flat_map(|component| {
111 let AccountComponent { storage_slots, .. } = component;
112 storage_slots.into_iter()
113 })
114 .collect();
115
116 Self::new(storage_slots)
117 }
118
119 pub fn to_elements(&self) -> Vec<Felt> {
130 <Self as SequentialCommit>::to_elements(self)
131 }
132
133 pub fn to_commitment(&self) -> Word {
135 <Self as SequentialCommit>::to_commitment(self)
136 }
137
138 pub fn num_slots(&self) -> u8 {
140 self.slots.len() as u8
143 }
144
145 pub fn slots(&self) -> &[StorageSlot] {
147 &self.slots
148 }
149
150 pub fn into_slots(self) -> Vec<StorageSlot> {
152 self.slots
153 }
154
155 pub fn to_header(&self) -> AccountStorageHeader {
157 AccountStorageHeader::new(self.slots.iter().map(StorageSlotHeader::from).collect())
158 .expect("slots should be valid as ensured by AccountStorage")
159 }
160
161 pub fn get(&self, slot_name: &StorageSlotName) -> Option<&StorageSlot> {
164 self.slots.iter().find(|slot| slot.name().id() == slot_name.id())
165 }
166
167 fn get_mut(&mut self, slot_name: &StorageSlotName) -> Option<&mut StorageSlot> {
170 self.slots.iter_mut().find(|slot| slot.name().id() == slot_name.id())
171 }
172
173 pub fn get_item(&self, slot_name: &StorageSlotName) -> Result<Word, AccountError> {
180 self.get(slot_name)
181 .map(|slot| slot.content().value())
182 .ok_or_else(|| AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() })
183 }
184
185 pub fn get_map_item(
193 &self,
194 slot_name: &StorageSlotName,
195 key: StorageMapKey,
196 ) -> Result<Word, AccountError> {
197 self.get(slot_name)
198 .ok_or_else(|| AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() })
199 .and_then(|slot| match slot.content() {
200 StorageSlotContent::Map(map) => Ok(map.get(&key)),
201 _ => Err(AccountError::StorageSlotNotMap(slot_name.clone())),
202 })
203 }
204
205 pub(super) fn apply_patch(&mut self, patch: &AccountStoragePatch) -> Result<(), AccountError> {
215 for (slot_name, slot_patch) in patch.slots() {
216 match slot_patch {
217 StorageSlotPatch::Value(value_patch) => {
218 self.apply_value_patch(slot_name, value_patch)?
219 },
220 StorageSlotPatch::Map(map_patch) => self.apply_map_patch(slot_name, map_patch)?,
221 }
222 }
223
224 Ok(())
225 }
226
227 fn apply_value_patch(
229 &mut self,
230 slot_name: &StorageSlotName,
231 value_patch: &StorageValuePatch,
232 ) -> Result<(), AccountError> {
233 match value_patch {
234 StorageValuePatch::Create { value } => {
235 self.create_value_slot(slot_name.clone(), *value)?;
236 },
237 StorageValuePatch::Update { value } => {
238 self.set_item(slot_name, *value)?;
239 },
240 StorageValuePatch::Remove => {
241 self.remove_slot(slot_name)?;
242 },
243 }
244
245 Ok(())
246 }
247
248 fn apply_map_patch(
250 &mut self,
251 slot_name: &StorageSlotName,
252 map_patch: &StorageMapPatch,
253 ) -> Result<(), AccountError> {
254 match map_patch {
255 StorageMapPatch::Create { entries } => {
256 self.create_map_slot(slot_name.clone(), entries)?;
257 },
258 StorageMapPatch::Update { entries } => {
259 let slot = self.get_mut(slot_name).ok_or_else(|| {
260 AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() }
261 })?;
262
263 let storage_map = match slot.content_mut() {
264 StorageSlotContent::Map(map) => map,
265 _ => return Err(AccountError::StorageSlotNotMap(slot_name.clone())),
266 };
267
268 storage_map.apply_patch(entries)?;
269 },
270 StorageMapPatch::Remove => {
271 self.remove_slot(slot_name)?;
272 },
273 }
274
275 Ok(())
276 }
277
278 pub fn set_item(
289 &mut self,
290 slot_name: &StorageSlotName,
291 value: Word,
292 ) -> Result<Word, AccountError> {
293 let slot = self.get_mut(slot_name).ok_or_else(|| {
294 AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() }
295 })?;
296
297 let StorageSlotContent::Value(old_value) = slot.content() else {
298 return Err(AccountError::StorageSlotNotValue(slot_name.clone()));
299 };
300 let old_value = *old_value;
301
302 let mut new_slot = StorageSlotContent::Value(value);
303 core::mem::swap(slot.content_mut(), &mut new_slot);
304
305 Ok(old_value)
306 }
307
308 pub fn set_map_item(
319 &mut self,
320 slot_name: &StorageSlotName,
321 key: StorageMapKey,
322 value: Word,
323 ) -> Result<(Word, Word), AccountError> {
324 let slot = self.get_mut(slot_name).ok_or_else(|| {
325 AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() }
326 })?;
327
328 let StorageSlotContent::Map(storage_map) = slot.content_mut() else {
329 return Err(AccountError::StorageSlotNotMap(slot_name.clone()));
330 };
331
332 let old_root = storage_map.root();
333
334 let old_value = storage_map.insert(key, value)?;
335
336 Ok((old_root, old_value))
337 }
338
339 fn create_value_slot(
346 &mut self,
347 slot_name: StorageSlotName,
348 value: Word,
349 ) -> Result<(), AccountError> {
350 self.create_slot(StorageSlot::with_value(slot_name, value))
351 }
352
353 fn create_map_slot(
360 &mut self,
361 slot_name: StorageSlotName,
362 entries: &StorageMapPatchEntries,
363 ) -> Result<(), AccountError> {
364 let storage_map =
365 StorageMap::with_entries(entries.as_map().iter().map(|(key, value)| (*key, *value)))
366 .expect("map should contain only unique entries");
367
368 self.create_slot(StorageSlot::with_map(slot_name, storage_map))
369 }
370
371 fn remove_slot(&mut self, slot_name: &StorageSlotName) -> Result<(), AccountError> {
377 match self.slots.iter().position(|slot| slot.name().id() == slot_name.id()) {
378 Some(index) => {
379 self.slots.remove(index);
380 Ok(())
381 },
382 None => Err(AccountError::StorageSlotNameNotFound { slot_name: slot_name.clone() }),
383 }
384 }
385
386 fn create_slot(&mut self, slot: StorageSlot) -> Result<(), AccountError> {
397 match self.slots.binary_search_by(|existing| existing.name().cmp(slot.name())) {
398 Ok(index) => {
399 self.slots[index] = slot;
400 Ok(())
401 },
402 Err(index) => {
403 if self.slots.len() >= Self::MAX_NUM_STORAGE_SLOTS {
404 return Err(AccountError::StorageTooManySlots(self.slots.len() as u64 + 1));
405 }
406
407 self.slots.insert(index, slot);
408 Ok(())
409 },
410 }
411 }
412}
413
414impl IntoIterator for AccountStorage {
418 type Item = StorageSlot;
419 type IntoIter = alloc::vec::IntoIter<StorageSlot>;
420
421 fn into_iter(self) -> Self::IntoIter {
422 self.slots.into_iter()
423 }
424}
425
426impl SequentialCommit for AccountStorage {
430 type Commitment = Word;
431
432 fn to_elements(&self) -> Vec<Felt> {
433 self.slots()
434 .iter()
435 .flat_map(|slot| {
436 StorageSlotHeader::new(
437 slot.name().clone(),
438 slot.content().slot_type(),
439 slot.content().value(),
440 )
441 .to_elements()
442 })
443 .collect()
444 }
445}
446
447impl Serializable for AccountStorage {
451 fn write_into<W: ByteWriter>(&self, target: &mut W) {
452 target.write_u8(self.slots().len() as u8);
453 target.write_many(self.slots());
454 }
455
456 fn get_size_hint(&self) -> usize {
457 let u8_size = 0u8.get_size_hint();
459 let mut size = u8_size;
460
461 for slot in self.slots() {
462 size += slot.get_size_hint();
463 }
464
465 size
466 }
467}
468
469impl Deserializable for AccountStorage {
470 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
471 let num_slots = source.read_u8()? as usize;
472 let slots = source.read_many_iter::<StorageSlot>(num_slots)?.collect::<Result<_, _>>()?;
473
474 Self::new(slots).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
475 }
476}
477
478#[cfg(test)]
482mod tests {
483 use std::collections::BTreeMap;
484
485 use assert_matches::assert_matches;
486
487 use super::{AccountStorage, Deserializable, Serializable};
488 use crate::Word;
489 use crate::account::{
490 AccountStorageHeader,
491 AccountStoragePatch,
492 StorageSlot,
493 StorageSlotHeader,
494 StorageSlotName,
495 StorageSlotPatch,
496 StorageValuePatch,
497 };
498 use crate::errors::AccountError;
499
500 #[test]
501 fn test_serde_account_storage() -> anyhow::Result<()> {
502 let storage = AccountStorage::new(vec![]).unwrap();
504 let bytes = storage.to_bytes();
505 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
506
507 let storage = AccountStorage::new(vec![
509 StorageSlot::with_empty_value(StorageSlotName::new("miden::test::value")?),
510 StorageSlot::with_empty_map(StorageSlotName::new("miden::test::map")?),
511 ])
512 .unwrap();
513 let bytes = storage.to_bytes();
514 assert_eq!(storage, AccountStorage::read_from_bytes(&bytes).unwrap());
515
516 Ok(())
517 }
518
519 #[test]
520 fn test_get_slot_by_name() -> anyhow::Result<()> {
521 let counter_slot = StorageSlotName::new("miden::test::counter")?;
522 let map_slot = StorageSlotName::new("miden::test::map")?;
523
524 let slots = vec![
525 StorageSlot::with_empty_value(counter_slot.clone()),
526 StorageSlot::with_empty_map(map_slot.clone()),
527 ];
528 let storage = AccountStorage::new(slots.clone())?;
529
530 assert_eq!(storage.get(&counter_slot).unwrap(), &slots[0]);
531 assert_eq!(storage.get(&map_slot).unwrap(), &slots[1]);
532
533 Ok(())
534 }
535
536 #[test]
537 fn test_account_storage_and_header_fail_on_duplicate_slot_name() -> anyhow::Result<()> {
538 let slot_name0 = StorageSlotName::mock(0);
539 let slot_name1 = StorageSlotName::mock(1);
540 let slot_name2 = StorageSlotName::mock(2);
541
542 let mut slots = vec![
543 StorageSlot::with_empty_value(slot_name0.clone()),
544 StorageSlot::with_empty_value(slot_name1.clone()),
545 StorageSlot::with_empty_map(slot_name0.clone()),
546 StorageSlot::with_empty_value(slot_name2.clone()),
547 ];
548
549 let err = AccountStorage::new(slots.clone()).unwrap_err();
552
553 assert_matches!(err, AccountError::DuplicateStorageSlotName(name) => {
554 assert_eq!(name, slot_name0);
555 });
556
557 slots.sort_unstable_by(|a, b| a.name().cmp(b.name()));
558 let err = AccountStorageHeader::new(slots.iter().map(StorageSlotHeader::from).collect())
559 .unwrap_err();
560
561 assert_matches!(err, AccountError::DuplicateStorageSlotName(name) => {
562 assert_eq!(name, slot_name0);
563 });
564
565 Ok(())
566 }
567
568 #[test]
569 fn create_value_slot_recreates_existing() -> anyhow::Result<()> {
570 let slot_name = StorageSlotName::mock(4);
571 let mut storage = AccountStorage::new(vec![StorageSlot::with_value(
572 slot_name.clone(),
573 Word::from([1u32, 2, 3, 4]),
574 )])?;
575
576 let new_value = Word::from([5u32, 6, 7, 8]);
578 storage.create_value_slot(slot_name.clone(), new_value)?;
579
580 assert_eq!(storage.num_slots(), 1);
581 assert_eq!(storage.get_item(&slot_name)?, new_value);
582
583 Ok(())
584 }
585
586 #[test]
587 fn remove_slot_rejects_absent() -> anyhow::Result<()> {
588 let absent = StorageSlotName::new("miden::test::absent")?;
589 let mut storage = AccountStorage::default();
590
591 let err = storage.remove_slot(&absent).unwrap_err();
592 assert_matches!(err, AccountError::StorageSlotNameNotFound { slot_name } => {
593 assert_eq!(slot_name, absent);
594 });
595
596 Ok(())
597 }
598
599 #[test]
600 fn create_and_remove_value_slot_roundtrip() -> anyhow::Result<()> {
601 let existing0 = StorageSlotName::mock(1);
603 let existing1 = StorageSlotName::mock(7);
604 let created = StorageSlotName::mock(20);
605 assert!(existing0 < created);
606 assert!(created < existing1);
607
608 let value = Word::from([9u32, 8, 7, 6]);
609
610 let mut storage = AccountStorage::new(vec![
611 StorageSlot::with_value(existing0.clone(), value),
612 StorageSlot::with_value(existing1.clone(), value),
613 ])?;
614
615 storage.create_value_slot(created.clone(), value)?;
616 assert_eq!(storage.num_slots(), 3);
617 assert_eq!(storage.get_item(&created)?, value);
618 assert!(
619 storage.slots().is_sorted_by_key(|slot| slot.name()),
620 "slots should remain sorted after insertion"
621 );
622
623 assert_eq!(storage.get_item(&existing0)?, value, "existing slot should remain accessible");
624 assert_eq!(storage.get_item(&existing1)?, value, "existing slot should remain accessible");
625
626 storage.remove_slot(&created)?;
627 assert_eq!(storage.num_slots(), 2);
628 assert_matches!(
629 storage.get_item(&created).unwrap_err(),
630 AccountError::StorageSlotNameNotFound { .. }
631 );
632
633 Ok(())
634 }
635
636 #[test]
637 fn apply_storage_patch() -> anyhow::Result<()> {
638 let updated = StorageSlotName::mock(1);
639 let created = StorageSlotName::mock(2);
640 let removed = StorageSlotName::mock(3);
641
642 let init_value = Word::from([1u32, 2, 3, 4]);
643 let final_value = Word::from([6u32, 7, 8, 9]);
644
645 let mut storage = AccountStorage::new(vec![
646 StorageSlot::with_value(updated.clone(), init_value),
647 StorageSlot::with_value(removed.clone(), init_value),
648 ])?;
649
650 let patches = BTreeMap::from_iter([
651 (
652 created.clone(),
653 StorageSlotPatch::Value(StorageValuePatch::Create { value: final_value }),
654 ),
655 (
656 updated.clone(),
657 StorageSlotPatch::Value(StorageValuePatch::Update { value: final_value }),
658 ),
659 (removed.clone(), StorageSlotPatch::Value(StorageValuePatch::Remove)),
660 ]);
661 let patch = AccountStoragePatch::from_raw(patches)?;
662
663 storage.apply_patch(&patch)?;
664
665 assert_eq!(storage.num_slots(), 2);
666 assert_eq!(storage.get_item(&created)?, final_value);
667 assert_eq!(storage.get_item(&updated)?, final_value);
668 assert_eq!(storage.get(&removed), None);
669
670 Ok(())
671 }
672}