miden_protocol/account/
header.rs1use alloc::vec::Vec;
2
3use super::{Account, AccountId, Felt, PartialAccount};
4use crate::crypto::SequentialCommit;
5use crate::errors::AccountError;
6use crate::transaction::memory::{
7 ACCT_CODE_COMMITMENT_OFFSET,
8 ACCT_DATA_MEM_SIZE,
9 ACCT_ID_AND_NONCE_OFFSET,
10 ACCT_ID_PREFIX_IDX,
11 ACCT_ID_SUFFIX_IDX,
12 ACCT_NONCE_IDX,
13 ACCT_STORAGE_COMMITMENT_OFFSET,
14 ACCT_VAULT_ROOT_OFFSET,
15 MemoryOffset,
16};
17use crate::utils::serde::{
18 ByteReader,
19 ByteWriter,
20 Deserializable,
21 DeserializationError,
22 Serializable,
23};
24use crate::{WORD_SIZE, Word, WordError};
25
26#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct AccountHeader {
40 id: AccountId,
41 nonce: Felt,
42 vault_root: Word,
43 storage_commitment: Word,
44 code_commitment: Word,
45}
46
47impl AccountHeader {
48 pub fn new(
52 id: AccountId,
53 nonce: Felt,
54 vault_root: Word,
55 storage_commitment: Word,
56 code_commitment: Word,
57 ) -> Self {
58 Self {
59 id,
60 nonce,
61 vault_root,
62 storage_commitment,
63 code_commitment,
64 }
65 }
66
67 pub(crate) fn try_from_elements(elements: &[Felt]) -> Result<AccountHeader, AccountError> {
71 if elements.len() != ACCT_DATA_MEM_SIZE {
72 return Err(AccountError::HeaderDataIncorrectLength {
73 actual: elements.len(),
74 expected: ACCT_DATA_MEM_SIZE,
75 });
76 }
77
78 let id = AccountId::try_from_elements(
79 elements[ACCT_ID_AND_NONCE_OFFSET as usize + ACCT_ID_SUFFIX_IDX],
80 elements[ACCT_ID_AND_NONCE_OFFSET as usize + ACCT_ID_PREFIX_IDX],
81 )
82 .map_err(AccountError::FinalAccountHeaderIdParsingFailed)?;
83 let nonce = elements[ACCT_ID_AND_NONCE_OFFSET as usize + ACCT_NONCE_IDX];
84 let vault_root = parse_word(elements, ACCT_VAULT_ROOT_OFFSET)
85 .expect("we should have sliced off exactly 4 bytes");
86 let storage_commitment = parse_word(elements, ACCT_STORAGE_COMMITMENT_OFFSET)
87 .expect("we should have sliced off exactly 4 bytes");
88 let code_commitment = parse_word(elements, ACCT_CODE_COMMITMENT_OFFSET)
89 .expect("we should have sliced off exactly 4 bytes");
90
91 Ok(AccountHeader::new(id, nonce, vault_root, storage_commitment, code_commitment))
92 }
93
94 pub fn to_commitment(&self) -> Word {
103 <Self as SequentialCommit>::to_commitment(self)
104 }
105
106 pub fn id(&self) -> AccountId {
108 self.id
109 }
110
111 pub fn nonce(&self) -> Felt {
113 self.nonce
114 }
115
116 pub fn vault_root(&self) -> Word {
118 self.vault_root
119 }
120
121 pub fn storage_commitment(&self) -> Word {
123 self.storage_commitment
124 }
125
126 pub fn code_commitment(&self) -> Word {
128 self.code_commitment
129 }
130
131 pub fn to_elements(&self) -> Vec<Felt> {
143 <Self as SequentialCommit>::to_elements(self)
144 }
145}
146
147impl From<PartialAccount> for AccountHeader {
148 fn from(account: PartialAccount) -> Self {
149 (&account).into()
150 }
151}
152
153impl From<&PartialAccount> for AccountHeader {
154 fn from(account: &PartialAccount) -> Self {
155 Self {
156 id: account.id(),
157 nonce: account.nonce(),
158 vault_root: account.vault().root(),
159 storage_commitment: account.storage().commitment(),
160 code_commitment: account.code().commitment(),
161 }
162 }
163}
164
165impl From<Account> for AccountHeader {
166 fn from(account: Account) -> Self {
167 (&account).into()
168 }
169}
170
171impl From<&Account> for AccountHeader {
172 fn from(account: &Account) -> Self {
173 Self {
174 id: account.id(),
175 nonce: account.nonce(),
176 vault_root: account.vault().root(),
177 storage_commitment: account.storage().to_commitment(),
178 code_commitment: account.code().commitment(),
179 }
180 }
181}
182
183impl SequentialCommit for AccountHeader {
184 type Commitment = Word;
185
186 fn to_elements(&self) -> Vec<Felt> {
187 let mut id_nonce = Word::empty();
188 id_nonce[ACCT_NONCE_IDX] = self.nonce;
189 id_nonce[ACCT_ID_SUFFIX_IDX] = self.id.suffix();
190 id_nonce[ACCT_ID_PREFIX_IDX] = self.id.prefix().as_felt();
191
192 [
193 id_nonce.as_elements(),
194 self.vault_root.as_elements(),
195 self.storage_commitment.as_elements(),
196 self.code_commitment.as_elements(),
197 ]
198 .concat()
199 }
200}
201
202impl Serializable for AccountHeader {
206 fn write_into<W: ByteWriter>(&self, target: &mut W) {
207 self.id.write_into(target);
208 self.nonce.write_into(target);
209 self.vault_root.write_into(target);
210 self.storage_commitment.write_into(target);
211 self.code_commitment.write_into(target);
212 }
213}
214
215impl Deserializable for AccountHeader {
216 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
217 let id = AccountId::read_from(source)?;
218 let nonce = Felt::read_from(source)?;
219 let vault_root = Word::read_from(source)?;
220 let storage_commitment = Word::read_from(source)?;
221 let code_commitment = Word::read_from(source)?;
222
223 Ok(AccountHeader {
224 id,
225 nonce,
226 vault_root,
227 storage_commitment,
228 code_commitment,
229 })
230 }
231}
232
233fn parse_word(data: &[Felt], offset: MemoryOffset) -> Result<Word, WordError> {
238 Word::try_from(&data[offset as usize..offset as usize + WORD_SIZE])
239}
240
241#[cfg(test)]
245mod tests {
246 use miden_core::Felt;
247
248 use super::AccountHeader;
249 use crate::Word;
250 use crate::account::StorageSlotContent;
251 use crate::account::tests::build_account;
252 use crate::asset::FungibleAsset;
253 use crate::utils::serde::{Deserializable, Serializable};
254
255 #[test]
256 fn test_serde_account_storage() {
257 let init_nonce = Felt::new(1);
258 let asset_0 = FungibleAsset::mock(99);
259 let word = Word::from([1, 2, 3, 4u32]);
260 let storage_slot = StorageSlotContent::Value(word);
261 let account = build_account(vec![asset_0], init_nonce, vec![storage_slot]);
262
263 let account_header: AccountHeader = account.into();
264
265 let header_bytes = account_header.to_bytes();
266 let deserialized_header = AccountHeader::read_from_bytes(&header_bytes).unwrap();
267 assert_eq!(deserialized_header, account_header);
268 }
269}