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::{Deserializable, Serializable};
18use crate::{WORD_SIZE, Word, WordError};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct AccountHeader {
34 id: AccountId,
35 nonce: Felt,
36 vault_root: Word,
37 storage_commitment: Word,
38 code_commitment: Word,
39}
40
41impl AccountHeader {
42 pub fn new(
46 id: AccountId,
47 nonce: Felt,
48 vault_root: Word,
49 storage_commitment: Word,
50 code_commitment: Word,
51 ) -> Self {
52 Self {
53 id,
54 nonce,
55 vault_root,
56 storage_commitment,
57 code_commitment,
58 }
59 }
60
61 pub(crate) fn try_from_elements(elements: &[Felt]) -> Result<AccountHeader, AccountError> {
65 if elements.len() != ACCT_DATA_MEM_SIZE {
66 return Err(AccountError::HeaderDataIncorrectLength {
67 actual: elements.len(),
68 expected: ACCT_DATA_MEM_SIZE,
69 });
70 }
71
72 let id = AccountId::try_from([
73 elements[ACCT_ID_AND_NONCE_OFFSET as usize + ACCT_ID_PREFIX_IDX],
74 elements[ACCT_ID_AND_NONCE_OFFSET as usize + ACCT_ID_SUFFIX_IDX],
75 ])
76 .map_err(AccountError::FinalAccountHeaderIdParsingFailed)?;
77 let nonce = elements[ACCT_ID_AND_NONCE_OFFSET as usize + ACCT_NONCE_IDX];
78 let vault_root = parse_word(elements, ACCT_VAULT_ROOT_OFFSET)
79 .expect("we should have sliced off exactly 4 bytes");
80 let storage_commitment = parse_word(elements, ACCT_STORAGE_COMMITMENT_OFFSET)
81 .expect("we should have sliced off exactly 4 bytes");
82 let code_commitment = parse_word(elements, ACCT_CODE_COMMITMENT_OFFSET)
83 .expect("we should have sliced off exactly 4 bytes");
84
85 Ok(AccountHeader::new(id, nonce, vault_root, storage_commitment, code_commitment))
86 }
87
88 pub fn to_commitment(&self) -> Word {
97 <Self as SequentialCommit>::to_commitment(self)
98 }
99
100 pub fn id(&self) -> AccountId {
102 self.id
103 }
104
105 pub fn nonce(&self) -> Felt {
107 self.nonce
108 }
109
110 pub fn vault_root(&self) -> Word {
112 self.vault_root
113 }
114
115 pub fn storage_commitment(&self) -> Word {
117 self.storage_commitment
118 }
119
120 pub fn code_commitment(&self) -> Word {
122 self.code_commitment
123 }
124
125 pub fn to_elements(&self) -> Vec<Felt> {
137 <Self as SequentialCommit>::to_elements(self)
138 }
139}
140
141impl From<PartialAccount> for AccountHeader {
142 fn from(account: PartialAccount) -> Self {
143 (&account).into()
144 }
145}
146
147impl From<&PartialAccount> for AccountHeader {
148 fn from(account: &PartialAccount) -> Self {
149 Self {
150 id: account.id(),
151 nonce: account.nonce(),
152 vault_root: account.vault().root(),
153 storage_commitment: account.storage().commitment(),
154 code_commitment: account.code().commitment(),
155 }
156 }
157}
158
159impl From<Account> for AccountHeader {
160 fn from(account: Account) -> Self {
161 (&account).into()
162 }
163}
164
165impl From<&Account> for AccountHeader {
166 fn from(account: &Account) -> Self {
167 Self {
168 id: account.id(),
169 nonce: account.nonce(),
170 vault_root: account.vault().root(),
171 storage_commitment: account.storage().to_commitment(),
172 code_commitment: account.code().commitment(),
173 }
174 }
175}
176
177impl SequentialCommit for AccountHeader {
178 type Commitment = Word;
179
180 fn to_elements(&self) -> Vec<Felt> {
181 let mut id_nonce = Word::empty();
182 id_nonce[ACCT_NONCE_IDX] = self.nonce;
183 id_nonce[ACCT_ID_SUFFIX_IDX] = self.id.suffix();
184 id_nonce[ACCT_ID_PREFIX_IDX] = self.id.prefix().as_felt();
185
186 [
187 id_nonce.as_elements(),
188 self.vault_root.as_elements(),
189 self.storage_commitment.as_elements(),
190 self.code_commitment.as_elements(),
191 ]
192 .concat()
193 }
194}
195
196impl Serializable for AccountHeader {
200 fn write_into<W: miden_core::utils::ByteWriter>(&self, target: &mut W) {
201 self.id.write_into(target);
202 self.nonce.write_into(target);
203 self.vault_root.write_into(target);
204 self.storage_commitment.write_into(target);
205 self.code_commitment.write_into(target);
206 }
207}
208
209impl Deserializable for AccountHeader {
210 fn read_from<R: miden_core::utils::ByteReader>(
211 source: &mut R,
212 ) -> Result<Self, miden_processor::DeserializationError> {
213 let id = AccountId::read_from(source)?;
214 let nonce = Felt::read_from(source)?;
215 let vault_root = Word::read_from(source)?;
216 let storage_commitment = Word::read_from(source)?;
217 let code_commitment = Word::read_from(source)?;
218
219 Ok(AccountHeader {
220 id,
221 nonce,
222 vault_root,
223 storage_commitment,
224 code_commitment,
225 })
226 }
227}
228
229fn parse_word(data: &[Felt], offset: MemoryOffset) -> Result<Word, WordError> {
234 Word::try_from(&data[offset as usize..offset as usize + WORD_SIZE])
235}
236
237#[cfg(test)]
241mod tests {
242 use miden_core::Felt;
243 use miden_core::utils::{Deserializable, Serializable};
244
245 use super::AccountHeader;
246 use crate::Word;
247 use crate::account::StorageSlotContent;
248 use crate::account::tests::build_account;
249 use crate::asset::FungibleAsset;
250
251 #[test]
252 fn test_serde_account_storage() {
253 let init_nonce = Felt::new(1);
254 let asset_0 = FungibleAsset::mock(99);
255 let word = Word::from([1, 2, 3, 4u32]);
256 let storage_slot = StorageSlotContent::Value(word);
257 let account = build_account(vec![asset_0], init_nonce, vec![storage_slot]);
258
259 let account_header: AccountHeader = account.into();
260
261 let header_bytes = account_header.to_bytes();
262 let deserialized_header = AccountHeader::read_from_bytes(&header_bytes).unwrap();
263 assert_eq!(deserialized_header, account_header);
264 }
265}