miden_objects/account/
header.rs

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