miden_objects/account/
header.rs

1use alloc::vec::Vec;
2
3use super::{Account, AccountId, Digest, Felt, PartialAccount, ZERO, hash_account};
4use crate::utils::serde::{Deserializable, Serializable};
5
6// ACCOUNT HEADER
7// ================================================================================================
8
9/// A header of an account which contains information that succinctly describes the state of the
10/// components of the account.
11///
12/// The [AccountHeader] is composed of:
13/// - id: the account ID ([`AccountId`]) of the account.
14/// - nonce: the nonce of the account.
15/// - vault_root: a commitment to the account's vault ([super::AssetVault]).
16/// - storage_commitment: a commitment to the account's storage ([super::AccountStorage]).
17/// - code_commitment: a commitment to the account's code ([super::AccountCode]).
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct AccountHeader {
20    id: AccountId,
21    nonce: Felt,
22    vault_root: Digest,
23    storage_commitment: Digest,
24    code_commitment: Digest,
25}
26
27impl AccountHeader {
28    // CONSTRUCTORS
29    // --------------------------------------------------------------------------------------------
30    /// Creates a new [AccountHeader].
31    pub fn new(
32        id: AccountId,
33        nonce: Felt,
34        vault_root: Digest,
35        storage_commitment: Digest,
36        code_commitment: Digest,
37    ) -> Self {
38        Self {
39            id,
40            nonce,
41            vault_root,
42            storage_commitment,
43            code_commitment,
44        }
45    }
46
47    // PUBLIC ACCESSORS
48    // --------------------------------------------------------------------------------------------
49
50    /// Returns the commitment of this account.
51    ///
52    /// The commitment of an account is computed as hash(id, nonce, vault_root, storage_commitment,
53    /// code_commitment). Computing the account commitment requires 2 permutations of the hash
54    /// function.
55    pub fn commitment(&self) -> Digest {
56        hash_account(
57            self.id,
58            self.nonce,
59            self.vault_root,
60            self.storage_commitment,
61            self.code_commitment,
62        )
63    }
64
65    /// Returns the id of this account.
66    pub fn id(&self) -> AccountId {
67        self.id
68    }
69
70    /// Returns the nonce of this account.
71    pub fn nonce(&self) -> Felt {
72        self.nonce
73    }
74
75    /// Returns the vault root of this account.
76    pub fn vault_root(&self) -> Digest {
77        self.vault_root
78    }
79
80    /// Returns the storage commitment of this account.
81    pub fn storage_commitment(&self) -> Digest {
82        self.storage_commitment
83    }
84
85    /// Returns the code commitment of this account.
86    pub fn code_commitment(&self) -> Digest {
87        self.code_commitment
88    }
89
90    /// Converts the account header into a vector of field elements.
91    ///
92    /// This is done by first converting the account header data into an array of Words as follows:
93    /// ```text
94    /// [
95    ///     [account_id_suffix, account_id_prefix, 0, account_nonce]
96    ///     [VAULT_ROOT]
97    ///     [STORAGE_COMMITMENT]
98    ///     [CODE_COMMITMENT]
99    /// ]
100    /// ```
101    /// And then concatenating the resulting elements into a single vector.
102    pub fn as_elements(&self) -> Vec<Felt> {
103        [
104            &[self.id.suffix(), self.id.prefix().as_felt(), ZERO, self.nonce],
105            self.vault_root.as_elements(),
106            self.storage_commitment.as_elements(),
107            self.code_commitment.as_elements(),
108        ]
109        .concat()
110    }
111}
112
113impl From<PartialAccount> for AccountHeader {
114    fn from(account: PartialAccount) -> Self {
115        (&account).into()
116    }
117}
118
119impl From<&PartialAccount> for AccountHeader {
120    fn from(account: &PartialAccount) -> Self {
121        Self {
122            id: account.id(),
123            nonce: account.nonce(),
124            vault_root: account.vault().root(),
125            storage_commitment: account.storage().commitment(),
126            code_commitment: account.code().commitment(),
127        }
128    }
129}
130
131impl From<Account> for AccountHeader {
132    fn from(account: Account) -> Self {
133        (&account).into()
134    }
135}
136
137impl From<&Account> for AccountHeader {
138    fn from(account: &Account) -> Self {
139        Self {
140            id: account.id(),
141            nonce: account.nonce(),
142            vault_root: account.vault().root(),
143            storage_commitment: account.storage().commitment(),
144            code_commitment: account.code().commitment(),
145        }
146    }
147}
148
149impl Serializable for AccountHeader {
150    fn write_into<W: vm_core::utils::ByteWriter>(&self, target: &mut W) {
151        self.id.write_into(target);
152        self.nonce.write_into(target);
153        self.vault_root.write_into(target);
154        self.storage_commitment.write_into(target);
155        self.code_commitment.write_into(target);
156    }
157}
158
159impl Deserializable for AccountHeader {
160    fn read_from<R: vm_core::utils::ByteReader>(
161        source: &mut R,
162    ) -> Result<Self, vm_processor::DeserializationError> {
163        let id = AccountId::read_from(source)?;
164        let nonce = Felt::read_from(source)?;
165        let vault_root = Digest::read_from(source)?;
166        let storage_commitment = Digest::read_from(source)?;
167        let code_commitment = Digest::read_from(source)?;
168
169        Ok(AccountHeader {
170            id,
171            nonce,
172            vault_root,
173            storage_commitment,
174            code_commitment,
175        })
176    }
177}
178
179// TESTS
180// ================================================================================================
181
182#[cfg(test)]
183mod tests {
184    use vm_core::{
185        Felt,
186        utils::{Deserializable, Serializable},
187    };
188
189    use super::AccountHeader;
190    use crate::{
191        account::{StorageSlot, tests::build_account},
192        asset::FungibleAsset,
193    };
194
195    #[test]
196    fn test_serde_account_storage() {
197        let init_nonce = Felt::new(1);
198        let asset_0 = FungibleAsset::mock(99);
199        let word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)];
200        let storage_slot = StorageSlot::Value(word);
201        let account = build_account(vec![asset_0], init_nonce, vec![storage_slot]);
202
203        let account_header: AccountHeader = account.into();
204
205        let header_bytes = account_header.to_bytes();
206        let deserialized_header = AccountHeader::read_from_bytes(&header_bytes).unwrap();
207        assert_eq!(deserialized_header, account_header);
208    }
209}