miden_objects/account/storage/
header.rs

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