miden_objects/account/storage/
partial.rs1use alloc::collections::{BTreeMap, BTreeSet};
2
3use miden_core::utils::{Deserializable, Serializable};
4use miden_crypto::Word;
5use miden_crypto::merkle::{InnerNodeInfo, SmtLeaf};
6
7use super::{AccountStorage, AccountStorageHeader, StorageSlot};
8use crate::AccountError;
9use crate::account::PartialStorageMap;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct PartialStorage {
18 commitment: Word,
20 header: AccountStorageHeader,
22 maps: BTreeMap<Word, PartialStorageMap>,
25}
26
27impl PartialStorage {
28 pub fn new(
34 storage_header: AccountStorageHeader,
35 storage_maps: impl IntoIterator<Item = PartialStorageMap>,
36 ) -> Result<Self, AccountError> {
37 let storage_map_roots: BTreeSet<_> = storage_header.map_slot_roots().collect();
38 let mut maps = BTreeMap::new();
39 for smt in storage_maps {
40 if !storage_map_roots.contains(&smt.root()) {
42 return Err(AccountError::StorageMapRootNotFound(smt.root()));
43 }
44 maps.insert(smt.root(), smt);
45 }
46
47 let commitment = storage_header.compute_commitment();
48 Ok(Self { commitment, header: storage_header, maps })
49 }
50
51 pub fn header(&self) -> &AccountStorageHeader {
53 &self.header
54 }
55
56 pub fn commitment(&self) -> Word {
58 self.commitment
59 }
60
61 pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> {
69 self.maps.iter().flat_map(|(_, map)| map.inner_nodes())
70 }
71
72 pub fn maps(&self) -> impl Iterator<Item = &PartialStorageMap> + '_ {
74 self.maps.values()
75 }
76
77 pub fn leaves(&self) -> impl Iterator<Item = &SmtLeaf> + '_ {
79 self.maps().flat_map(|map| map.leaves()).map(|(_, leaf)| leaf)
80 }
81}
82
83impl From<&AccountStorage> for PartialStorage {
84 fn from(account_storage: &AccountStorage) -> Self {
89 let mut map_smts = BTreeMap::new();
90 for slot in account_storage.slots() {
91 if let StorageSlot::Map(map) = slot {
92 let smt: PartialStorageMap = map.clone().into();
93 map_smts.insert(smt.root(), smt);
94 }
95 }
96
97 let header: AccountStorageHeader = account_storage.to_header();
98 let commitment = header.compute_commitment();
99 PartialStorage { header, maps: map_smts, commitment }
100 }
101}
102
103impl Serializable for PartialStorage {
104 fn write_into<W: miden_core::utils::ByteWriter>(&self, target: &mut W) {
105 target.write(&self.header);
106 target.write(&self.maps);
107 }
108}
109
110impl Deserializable for PartialStorage {
111 fn read_from<R: miden_core::utils::ByteReader>(
112 source: &mut R,
113 ) -> Result<Self, miden_processor::DeserializationError> {
114 let header: AccountStorageHeader = source.read()?;
115 let map_smts: BTreeMap<Word, PartialStorageMap> = source.read()?;
116
117 let commitment = header.compute_commitment();
118
119 Ok(PartialStorage { header, maps: map_smts, commitment })
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use anyhow::Context;
126 use miden_core::Word;
127 use miden_crypto::merkle::PartialSmt;
128
129 use crate::account::{
130 AccountStorage,
131 AccountStorageHeader,
132 PartialStorage,
133 StorageMap,
134 StorageSlot,
135 };
136
137 #[test]
138 pub fn new_partial_storage() -> anyhow::Result<()> {
139 let map_key_present: Word = [1u64, 2, 3, 4].try_into()?;
140 let map_key_absent: Word = [9u64, 12, 18, 3].try_into()?;
141
142 let mut map_1 = StorageMap::new();
143 map_1.insert(map_key_absent, Word::try_from([1u64, 2, 3, 2])?);
144 map_1.insert(map_key_present, Word::try_from([5u64, 4, 3, 2])?);
145 assert_eq!(map_1.get(&map_key_present), [5u64, 4, 3, 2].try_into()?);
146
147 let storage = AccountStorage::new(vec![StorageSlot::Map(map_1.clone())]).unwrap();
148
149 let storage_header = AccountStorageHeader::from(&storage);
151 let proof = map_1.open(&map_key_present);
152 let partial_smt = PartialSmt::from_proofs([proof])?;
153
154 let partial_storage = PartialStorage::new(storage_header, [partial_smt.into()])
155 .context("creating partial storage")?;
156
157 let retrieved_map = partial_storage.maps.get(&partial_storage.header.slot(0)?.1).unwrap();
158 assert!(retrieved_map.open(&map_key_absent).is_err());
159 assert!(retrieved_map.open(&map_key_present).is_ok());
160 Ok(())
161 }
162}