miden_objects/account/storage/
header.rs1use alloc::vec::Vec;
2
3use super::{AccountStorage, Felt, Hasher, StorageSlot, StorageSlotType, Word};
4use crate::utils::serde::{
5 ByteReader,
6 ByteWriter,
7 Deserializable,
8 DeserializationError,
9 Serializable,
10};
11use crate::{AccountError, ZERO};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct StorageSlotHeader(StorageSlotType, Word);
23
24impl StorageSlotHeader {
25 pub fn new(value: &(StorageSlotType, Word)) -> Self {
27 Self(value.0, value.1)
28 }
29
30 pub fn as_elements(&self) -> [Felt; StorageSlot::NUM_ELEMENTS_PER_STORAGE_SLOT] {
37 let mut elements = [ZERO; StorageSlot::NUM_ELEMENTS_PER_STORAGE_SLOT];
38 elements[0..4].copy_from_slice(self.1.as_elements());
39 elements[4..8].copy_from_slice(self.0.as_word().as_elements());
40 elements
41 }
42}
43
44impl From<&StorageSlot> for StorageSlotHeader {
45 fn from(value: &StorageSlot) -> Self {
46 Self(value.slot_type(), value.value())
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct AccountStorageHeader {
57 slots: Vec<(StorageSlotType, Word)>,
58}
59
60impl AccountStorageHeader {
61 pub fn new(slots: Vec<(StorageSlotType, Word)>) -> Self {
69 assert!(slots.len() <= AccountStorage::MAX_NUM_STORAGE_SLOTS);
70 Self { slots }
71 }
72
73 pub fn slots(&self) -> impl Iterator<Item = &(StorageSlotType, Word)> {
78 self.slots.iter()
79 }
80
81 pub fn map_slot_roots(&self) -> impl Iterator<Item = Word> {
83 self.slots
84 .iter()
85 .filter(|(slot_type, _)| matches!(slot_type, StorageSlotType::Map))
86 .map(|x| x.1)
87 }
88
89 pub fn num_slots(&self) -> u8 {
91 self.slots.len() as u8
93 }
94
95 pub fn slot(&self, index: usize) -> Result<&(StorageSlotType, Word), AccountError> {
100 self.slots.get(index).ok_or(AccountError::StorageIndexOutOfBounds {
101 slots_len: self.slots.len() as u8,
102 index: index as u8,
103 })
104 }
105
106 pub fn compute_commitment(&self) -> Word {
109 Hasher::hash_elements(&self.as_elements())
110 }
111
112 pub fn is_map_slot(&self, index: usize) -> Result<bool, AccountError> {
117 match self.slot(index)?.0 {
118 StorageSlotType::Map => Ok(true),
119 StorageSlotType::Value => Ok(false),
120 }
121 }
122
123 pub fn as_elements(&self) -> Vec<Felt> {
131 self.slots
132 .iter()
133 .flat_map(|slot| StorageSlotHeader::new(slot).as_elements())
134 .collect()
135 }
136}
137
138impl From<&AccountStorage> for AccountStorageHeader {
139 fn from(value: &AccountStorage) -> Self {
140 value.to_header()
141 }
142}
143
144impl Serializable for AccountStorageHeader {
148 fn write_into<W: ByteWriter>(&self, target: &mut W) {
149 let len = self.slots.len() as u8;
150 target.write_u8(len);
151 target.write_many(self.slots())
152 }
153}
154
155impl Deserializable for AccountStorageHeader {
156 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
157 let len = source.read_u8()?;
158 let slots = source.read_many(len as usize)?;
159 Ok(Self::new(slots))
161 }
162}
163
164#[cfg(test)]
168mod tests {
169 use miden_core::Felt;
170 use miden_core::utils::{Deserializable, Serializable};
171
172 use super::AccountStorageHeader;
173 use crate::Word;
174 use crate::account::{AccountStorage, StorageSlotType};
175
176 #[test]
177 fn test_from_account_storage() {
178 let storage_map = AccountStorage::mock_map();
179
180 let slots = vec![
182 (StorageSlotType::Value, Word::from([1, 2, 3, 4u32])),
183 (
184 StorageSlotType::Value,
185 Word::from([Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)]),
186 ),
187 (StorageSlotType::Map, storage_map.root()),
188 ];
189
190 let expected_header = AccountStorageHeader { slots };
191 let account_storage = AccountStorage::mock();
192
193 assert_eq!(expected_header, AccountStorageHeader::from(&account_storage))
194 }
195
196 #[test]
197 fn test_serde_account_storage_header() {
198 let storage = AccountStorage::mock();
200 let storage_header = AccountStorageHeader::from(&storage);
201
202 let bytes = storage_header.to_bytes();
204 let deserialized = AccountStorageHeader::read_from_bytes(&bytes).unwrap();
205
206 assert_eq!(storage_header, deserialized);
208 }
209}