miden_objects/account/storage/
header.rs

1use alloc::vec::Vec;
2
3use vm_core::{
4    utils::{ByteReader, ByteWriter, Deserializable, Serializable},
5    ZERO,
6};
7use vm_processor::DeserializationError;
8
9use super::{AccountStorage, Felt, StorageSlot, StorageSlotType, Word};
10use crate::AccountError;
11
12// ACCOUNT STORAGE HEADER
13// ================================================================================================
14
15/// Storage slot header is a lighter version of the [StorageSlot] storing only the type and the
16/// top-level value for the slot, and being, in fact, just a thin wrapper around a tuple.
17///
18/// That is, for complex storage slot (e.g., storage map), the header contains only the commitment
19/// to the underlying data.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct StorageSlotHeader(StorageSlotType, Word);
22
23impl StorageSlotHeader {
24    /// Returns a new instance of storage slot header from the provided storage slot type and value.
25    pub fn new(value: &(StorageSlotType, Word)) -> Self {
26        Self(value.0, value.1)
27    }
28
29    /// Returns this storage slot header as field elements.
30    ///
31    /// This is done by converting this storage slot into 8 field elements as follows:
32    /// ```text
33    /// [SLOT_VALUE, slot_type, 0, 0, 0]
34    /// ```
35    pub fn as_elements(&self) -> [Felt; StorageSlot::NUM_ELEMENTS_PER_STORAGE_SLOT] {
36        let mut elements = [ZERO; StorageSlot::NUM_ELEMENTS_PER_STORAGE_SLOT];
37        elements[0..4].copy_from_slice(&self.1);
38        elements[4..8].copy_from_slice(&self.0.as_word());
39        elements
40    }
41}
42
43impl From<&StorageSlot> for StorageSlotHeader {
44    fn from(value: &StorageSlot) -> Self {
45        Self(value.slot_type(), value.value())
46    }
47}
48
49/// Account storage header is a lighter version of the [AccountStorage] storing only the type and
50/// the top-level value for each storage slot.
51///
52/// That is, for complex storage slots (e.g., storage maps), the header contains only the commitment
53/// to the underlying data.
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct AccountStorageHeader {
56    slots: Vec<(StorageSlotType, Word)>,
57}
58
59impl AccountStorageHeader {
60    // CONSTRUCTOR
61    // --------------------------------------------------------------------------------------------
62
63    /// Returns a new instance of account storage header initialized with the provided slots.
64    ///
65    /// # Panics
66    /// - If the number of provided slots is greater than [AccountStorage::MAX_NUM_STORAGE_SLOTS].
67    pub fn new(slots: Vec<(StorageSlotType, Word)>) -> Self {
68        assert!(slots.len() <= AccountStorage::MAX_NUM_STORAGE_SLOTS);
69        Self { slots }
70    }
71
72    // PUBLIC ACCESSORS
73    // --------------------------------------------------------------------------------------------
74
75    /// Returns an iterator over the storage header slots.
76    pub fn slots(&self) -> impl Iterator<Item = &(StorageSlotType, Word)> {
77        self.slots.iter()
78    }
79
80    /// Returns the number of slots contained in the storage header.
81    pub fn num_slots(&self) -> usize {
82        self.slots.len()
83    }
84
85    /// Returns a slot contained in the storage header at a given index.
86    ///
87    /// # Errors
88    /// - If the index is out of bounds.
89    pub fn slot(&self, index: usize) -> Result<&(StorageSlotType, Word), AccountError> {
90        self.slots.get(index).ok_or(AccountError::StorageIndexOutOfBounds {
91            slots_len: self.slots.len() as u8,
92            index: index as u8,
93        })
94    }
95
96    /// Converts storage slots of this account storage header into a vector of field elements.
97    ///
98    /// This is done by first converting each storage slot into exactly 8 elements as follows:
99    /// ```text
100    /// [STORAGE_SLOT_VALUE, storage_slot_type, 0, 0, 0]
101    /// ```
102    /// And then concatenating the resulting elements into a single vector.
103    pub fn as_elements(&self) -> Vec<Felt> {
104        self.slots
105            .iter()
106            .flat_map(|slot| StorageSlotHeader::new(slot).as_elements())
107            .collect()
108    }
109}
110
111impl From<AccountStorage> for AccountStorageHeader {
112    fn from(value: AccountStorage) -> Self {
113        value.get_header()
114    }
115}
116
117// SERIALIZATION
118// ================================================================================================
119
120impl Serializable for AccountStorageHeader {
121    fn write_into<W: ByteWriter>(&self, target: &mut W) {
122        let len = self.slots.len() as u8;
123        target.write_u8(len);
124        target.write_many(self.slots())
125    }
126}
127
128impl Deserializable for AccountStorageHeader {
129    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
130        let len = source.read_u8()?;
131        let slots = source.read_many(len as usize)?;
132        // number of storage slots is guaranteed to be smaller than or equal to 255
133        Ok(Self::new(slots))
134    }
135}
136
137// TESTS
138// ================================================================================================
139
140#[cfg(test)]
141mod tests {
142    use vm_core::{
143        utils::{Deserializable, Serializable},
144        Felt,
145    };
146
147    use super::AccountStorageHeader;
148    use crate::account::{AccountStorage, StorageSlotType};
149
150    #[test]
151    fn test_from_account_storage() {
152        // create new storage header from AccountStorage
153        let slots = vec![
154            (StorageSlotType::Value, [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]),
155            (StorageSlotType::Value, [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)]),
156            (
157                StorageSlotType::Map,
158                [
159                    Felt::new(12405212884040084310),
160                    Felt::new(17614307840949763446),
161                    Felt::new(6101527485586301500),
162                    Felt::new(14442045877206841081),
163                ],
164            ),
165        ];
166
167        let expected_header = AccountStorageHeader { slots };
168        let account_storage = AccountStorage::mock();
169
170        assert_eq!(expected_header, AccountStorageHeader::from(account_storage))
171    }
172
173    #[test]
174    fn test_serde_account_storage_header() {
175        // create new storage header
176        let storage = AccountStorage::mock();
177        let storage_header = AccountStorageHeader::from(storage);
178
179        // serde storage header
180        let bytes = storage_header.to_bytes();
181        let deserialized = AccountStorageHeader::read_from_bytes(&bytes).unwrap();
182
183        // assert deserialized == storage header
184        assert_eq!(storage_header, deserialized);
185    }
186}