miden_objects/account/storage/
partial.rs

1use alloc::vec::Vec;
2
3use miden_crypto::merkle::{InnerNodeInfo, SmtLeaf, SmtProof};
4use vm_core::utils::{Deserializable, Serializable};
5use vm_processor::Digest;
6
7use super::{AccountStorage, AccountStorageHeader, StorageSlot};
8use crate::AccountError;
9
10/// A partial representation of an account storage, containing only a subset of the storage data.
11///
12/// Partial storage is used to provide verifiable access to specific segments of account storage
13/// without the need to provide the full storage data. It contains all needed parts for loading
14/// account storage data into the transaction kernel.
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct PartialStorage {
17    /// Commitment of the account's storage slots.
18    commitment: Digest,
19    /// Account's storage header, containing top-level slot values.
20    header: AccountStorageHeader,
21    /// Merkle proofs for a subset of the account's storage maps keys
22    storage_map_proofs: Vec<SmtProof>,
23}
24
25impl PartialStorage {
26    /// Returns a new instance of partial storage with the specified header and storage map proofs.
27    ///
28    /// The storage commitment is computed during instantiation based on the provided header.
29    pub fn new(header: AccountStorageHeader, storage_map_proofs: Vec<SmtProof>) -> Self {
30        let commitment = header.compute_commitment();
31        PartialStorage { header, storage_map_proofs, commitment }
32    }
33
34    /// Returns a reference to the storage map proofs of this partial storage.
35    pub fn storage_map_proofs(&self) -> &[SmtProof] {
36        &self.storage_map_proofs
37    }
38
39    /// Returns a reference to the header of this partial storage.
40    pub fn header(&self) -> &AccountStorageHeader {
41        &self.header
42    }
43
44    /// Returns the commitment of this partial storage.
45    pub fn commitment(&self) -> Digest {
46        self.commitment
47    }
48
49    /// Returns the value of the storage slot at the specified slot index.
50    ///
51    /// # Errors:
52    /// - If the index is out of bounds
53    pub fn get_item(&self, index: u8) -> Result<Digest, AccountError> {
54        self.header.slot(index as usize).map(|(_type, value)| value.into())
55    }
56
57    // TODO: Add from account storage with (slot/[key])?
58
59    /// Returns an iterator over inner nodes of all storage map proofs contained in this
60    /// partial storage.
61    pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> {
62        // SAFETY: any u64 value is a valid SMT leaf index
63        self.storage_map_proofs.iter().flat_map(|proof| {
64            proof
65                .path()
66                .inner_nodes(proof.leaf().index().value(), proof.leaf().hash())
67                .expect("invalid SMT leaf index")
68        })
69    }
70
71    /// Returns an iterator over leaves of all storage map entries contained in this partial
72    /// storage.
73    pub fn leaves(&self) -> impl Iterator<Item = &SmtLeaf> {
74        self.storage_map_proofs.iter().map(SmtProof::leaf)
75    }
76}
77
78impl From<&AccountStorage> for PartialStorage {
79    /// Converts a full account storage into a partial storage representation.
80    ///
81    /// This creates a partial storage that contains proofs for all key-value pairs
82    /// in all map slots of the account storage.
83    fn from(account_storage: &AccountStorage) -> Self {
84        let mut storage_map_proofs = Vec::with_capacity(account_storage.slots().len());
85        for slot in account_storage.slots() {
86            if let StorageSlot::Map(map) = slot {
87                let proofs: Vec<SmtProof> = map.entries().map(|(key, _)| map.open(key)).collect();
88                storage_map_proofs.extend(proofs);
89            }
90        }
91
92        let header: AccountStorageHeader = account_storage.to_header();
93        let commitment = header.compute_commitment();
94        PartialStorage { header, storage_map_proofs, commitment }
95    }
96}
97
98impl Serializable for PartialStorage {
99    fn write_into<W: vm_core::utils::ByteWriter>(&self, target: &mut W) {
100        target.write(&self.header);
101        target.write(&self.storage_map_proofs);
102    }
103}
104
105impl Deserializable for PartialStorage {
106    fn read_from<R: vm_core::utils::ByteReader>(
107        source: &mut R,
108    ) -> Result<Self, vm_processor::DeserializationError> {
109        let header: AccountStorageHeader = source.read()?;
110        let storage_map_proofs: Vec<SmtProof> = source.read()?;
111
112        let commitment = header.compute_commitment();
113
114        Ok(PartialStorage { header, storage_map_proofs, commitment })
115    }
116}