1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use miden_core::utils::{ByteReader, ByteWriter, Deserializable, Serializable};
5use miden_crypto::merkle::{MerkleError, MutationSet, Smt, SmtLeaf};
6use miden_processor::{DeserializationError, SMT_DEPTH};
7
8use crate::account::{AccountId, AccountIdPrefix};
9use crate::block::AccountWitness;
10use crate::errors::AccountTreeError;
11use crate::{Felt, Word};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct AccountTree {
26 smt: Smt,
27}
28
29impl AccountTree {
30 pub const DEPTH: u8 = SMT_DEPTH;
35
36 pub(super) const KEY_SUFFIX_IDX: usize = 2;
38 pub(super) const KEY_PREFIX_IDX: usize = 3;
40
41 pub fn new() -> Self {
46 AccountTree { smt: Smt::new() }
47 }
48
49 pub fn with_entries<I>(
61 entries: impl IntoIterator<Item = (AccountId, Word), IntoIter = I>,
62 ) -> Result<Self, AccountTreeError>
63 where
64 I: ExactSizeIterator<Item = (AccountId, Word)>,
65 {
66 let entries = entries.into_iter();
67 let num_accounts = entries.len();
68
69 let smt = Smt::with_entries(
70 entries.map(|(id, commitment)| (Self::id_to_smt_key(id), commitment)),
71 )
72 .map_err(|err| {
73 let MerkleError::DuplicateValuesForIndex(leaf_idx) = err else {
74 unreachable!("the only error returned by Smt::with_entries is of this type");
75 };
76
77 AccountTreeError::DuplicateStateCommitments {
80 prefix: AccountIdPrefix::new_unchecked(
81 Felt::try_from(leaf_idx).expect("leaf index should be a valid felt"),
82 ),
83 }
84 })?;
85
86 if smt.num_leaves() < num_accounts {
90 for (leaf_idx, leaf) in smt.leaves() {
91 if leaf.num_entries() >= 2 {
92 return Err(AccountTreeError::DuplicateIdPrefix {
96 duplicate_prefix: AccountIdPrefix::new_unchecked(
97 Felt::try_from(leaf_idx.value())
98 .expect("leaf index should be a valid felt"),
99 ),
100 });
101 }
102 }
103 }
104
105 Ok(AccountTree { smt })
106 }
107
108 pub fn open(&self, account_id: AccountId) -> AccountWitness {
116 let key = Self::id_to_smt_key(account_id);
117 let proof = self.smt.open(&key);
118
119 AccountWitness::from_smt_proof(account_id, proof)
120 }
121
122 pub fn get(&self, account_id: AccountId) -> Word {
124 let key = Self::id_to_smt_key(account_id);
125 self.smt.get_value(&key)
126 }
127
128 pub fn root(&self) -> Word {
130 self.smt.root()
131 }
132
133 pub fn contains_account_id_prefix(&self, account_id_prefix: AccountIdPrefix) -> bool {
135 let key = Self::id_prefix_to_smt_key(account_id_prefix);
136 let is_empty = matches!(self.smt.get_leaf(&key), SmtLeaf::Empty(_));
137 !is_empty
138 }
139
140 pub fn num_accounts(&self) -> usize {
142 self.smt.num_leaves()
145 }
146
147 pub fn account_commitments(&self) -> impl Iterator<Item = (AccountId, Word)> {
149 self.smt.leaves().map(|(_leaf_idx, leaf)| {
150 let SmtLeaf::Single((key, commitment)) = leaf else {
154 unreachable!("empty and multiple variant should never be encountered")
155 };
156
157 (
158 AccountId::try_from([key[Self::KEY_PREFIX_IDX], key[Self::KEY_SUFFIX_IDX]])
160 .expect("account tree should only contain valid IDs"),
161 *commitment,
162 )
163 })
164 }
165
166 pub fn compute_mutations(
184 &self,
185 account_commitments: impl IntoIterator<Item = (AccountId, Word)>,
186 ) -> Result<AccountMutationSet, AccountTreeError> {
187 let mutation_set = self.smt.compute_mutations(
188 account_commitments
189 .into_iter()
190 .map(|(id, commitment)| (Self::id_to_smt_key(id), commitment)),
191 );
192
193 for id_key in mutation_set.new_pairs().keys() {
194 match self.smt.get_leaf(id_key) {
196 SmtLeaf::Empty(_) => (),
198 SmtLeaf::Single((existing_key, _)) => {
199 if existing_key != *id_key {
202 return Err(AccountTreeError::DuplicateIdPrefix {
203 duplicate_prefix: Self::smt_key_to_id(*id_key).prefix(),
204 });
205 }
206 },
207 SmtLeaf::Multiple(_) => {
208 unreachable!(
209 "account tree should never contain duplicate ID prefixes and therefore never a multiple leaf"
210 )
211 },
212 }
213 }
214
215 Ok(AccountMutationSet::new(mutation_set))
216 }
217
218 pub fn insert(
232 &mut self,
233 account_id: AccountId,
234 state_commitment: Word,
235 ) -> Result<Word, AccountTreeError> {
236 let key = Self::id_to_smt_key(account_id);
237 let prev_value = self.smt.insert(key, state_commitment);
238
239 if self.smt.get_leaf(&key).num_entries() >= 2 {
242 return Err(AccountTreeError::DuplicateIdPrefix {
243 duplicate_prefix: account_id.prefix(),
244 });
245 }
246
247 Ok(prev_value)
248 }
249
250 pub fn apply_mutations(
257 &mut self,
258 mutations: AccountMutationSet,
259 ) -> Result<(), AccountTreeError> {
260 self.smt
261 .apply_mutations(mutations.into_mutation_set())
262 .map_err(AccountTreeError::ApplyMutations)
263 }
264
265 pub(super) fn id_to_smt_key(account_id: AccountId) -> Word {
270 let mut key = Word::empty();
273 key[Self::KEY_SUFFIX_IDX] = account_id.suffix();
274 key[Self::KEY_PREFIX_IDX] = account_id.prefix().as_felt();
275
276 key
277 }
278
279 fn id_prefix_to_smt_key(account_id: AccountIdPrefix) -> Word {
281 let mut key = Word::empty();
284 key[Self::KEY_PREFIX_IDX] = account_id.as_felt();
285
286 key
287 }
288
289 pub(super) fn smt_key_to_id(key: Word) -> AccountId {
297 AccountId::try_from([key[Self::KEY_PREFIX_IDX], key[Self::KEY_SUFFIX_IDX]])
298 .expect("account tree should only contain valid IDs")
299 }
300}
301
302impl Default for AccountTree {
303 fn default() -> Self {
304 Self::new()
305 }
306}
307
308impl Serializable for AccountTree {
312 fn write_into<W: ByteWriter>(&self, target: &mut W) {
313 self.account_commitments().collect::<Vec<_>>().write_into(target);
314 }
315}
316
317impl Deserializable for AccountTree {
318 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
319 let entries = Vec::<(AccountId, Word)>::read_from(source)?;
320 Self::with_entries(entries)
321 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
322 }
323}
324
325#[derive(Debug, Clone, PartialEq, Eq)]
335pub struct AccountMutationSet {
336 mutation_set: MutationSet<{ AccountTree::DEPTH }, Word, Word>,
337}
338
339impl AccountMutationSet {
340 fn new(mutation_set: MutationSet<{ AccountTree::DEPTH }, Word, Word>) -> Self {
345 Self { mutation_set }
346 }
347
348 pub fn as_mutation_set(&self) -> &MutationSet<{ AccountTree::DEPTH }, Word, Word> {
353 &self.mutation_set
354 }
355
356 pub fn into_mutation_set(self) -> MutationSet<{ AccountTree::DEPTH }, Word, Word> {
361 self.mutation_set
362 }
363}
364
365#[cfg(test)]
369pub(super) mod tests {
370 use std::vec::Vec;
371
372 use assert_matches::assert_matches;
373
374 use super::*;
375 use crate::account::{AccountStorageMode, AccountType};
376 use crate::testing::account_id::{AccountIdBuilder, account_id};
377
378 pub(crate) fn setup_duplicate_prefix_ids() -> [(AccountId, Word); 2] {
379 let id0 = AccountId::try_from(account_id(
380 AccountType::FungibleFaucet,
381 AccountStorageMode::Public,
382 0xaabb_ccdd,
383 ))
384 .unwrap();
385 let id1 = AccountId::try_from(account_id(
386 AccountType::FungibleFaucet,
387 AccountStorageMode::Public,
388 0xaabb_ccff,
389 ))
390 .unwrap();
391 assert_eq!(id0.prefix(), id1.prefix(), "test requires that these ids have the same prefix");
392
393 let commitment0 = Word::from([0, 0, 0, 42u32]);
394 let commitment1 = Word::from([0, 0, 0, 24u32]);
395
396 assert_eq!(id0.prefix(), id1.prefix(), "test requires that these ids have the same prefix");
397 [(id0, commitment0), (id1, commitment1)]
398 }
399
400 #[test]
401 fn insert_fails_on_duplicate_prefix() {
402 let mut tree = AccountTree::new();
403 let [(id0, commitment0), (id1, commitment1)] = setup_duplicate_prefix_ids();
404
405 tree.insert(id0, commitment0).unwrap();
406 assert_eq!(tree.get(id0), commitment0);
407
408 let err = tree.insert(id1, commitment1).unwrap_err();
409
410 assert_matches!(err, AccountTreeError::DuplicateIdPrefix {
411 duplicate_prefix
412 } if duplicate_prefix == id0.prefix());
413 }
414
415 #[test]
416 fn with_entries_fails_on_duplicate_prefix() {
417 let entries = setup_duplicate_prefix_ids();
418
419 let err = AccountTree::with_entries(entries.iter().copied()).unwrap_err();
420
421 assert_matches!(err, AccountTreeError::DuplicateIdPrefix {
422 duplicate_prefix
423 } if duplicate_prefix == entries[0].0.prefix());
424 }
425
426 #[test]
427 fn insert_succeeds_on_multiple_updates() {
428 let mut tree = AccountTree::new();
429 let [(id0, commitment0), (_, commitment1)] = setup_duplicate_prefix_ids();
430
431 tree.insert(id0, commitment0).unwrap();
432 tree.insert(id0, commitment1).unwrap();
433 assert_eq!(tree.get(id0), commitment1);
434 }
435
436 #[test]
437 fn apply_mutations() {
438 let id0 = AccountIdBuilder::new().build_with_seed([5; 32]);
439 let id1 = AccountIdBuilder::new().build_with_seed([6; 32]);
440 let id2 = AccountIdBuilder::new().build_with_seed([7; 32]);
441
442 let digest0 = Word::from([0, 0, 0, 1u32]);
443 let digest1 = Word::from([0, 0, 0, 2u32]);
444 let digest2 = Word::from([0, 0, 0, 3u32]);
445 let digest3 = Word::from([0, 0, 0, 4u32]);
446
447 let mut tree = AccountTree::with_entries([(id0, digest0), (id1, digest1)]).unwrap();
448
449 let mutations = tree
450 .compute_mutations([(id0, digest1), (id1, digest2), (id2, digest3)])
451 .unwrap();
452
453 tree.apply_mutations(mutations).unwrap();
454
455 assert_eq!(tree.num_accounts(), 3);
456 assert_eq!(tree.get(id0), digest1);
457 assert_eq!(tree.get(id1), digest2);
458 assert_eq!(tree.get(id2), digest3);
459 }
460
461 #[test]
462 fn duplicates_in_compute_mutations() {
463 let [pair0, pair1] = setup_duplicate_prefix_ids();
464 let id2 = AccountIdBuilder::new().build_with_seed([5; 32]);
465 let commitment2 = Word::from([0, 0, 0, 99u32]);
466
467 let tree = AccountTree::with_entries([pair0, (id2, commitment2)]).unwrap();
468
469 let err = tree.compute_mutations([pair1]).unwrap_err();
470
471 assert_matches!(err, AccountTreeError::DuplicateIdPrefix {
472 duplicate_prefix
473 } if duplicate_prefix == pair1.0.prefix());
474 }
475
476 #[test]
477 fn account_commitments() {
478 let id0 = AccountIdBuilder::new().build_with_seed([5; 32]);
479 let id1 = AccountIdBuilder::new().build_with_seed([6; 32]);
480 let id2 = AccountIdBuilder::new().build_with_seed([7; 32]);
481
482 let digest0 = Word::from([0, 0, 0, 1u32]);
483 let digest1 = Word::from([0, 0, 0, 2u32]);
484 let digest2 = Word::from([0, 0, 0, 3u32]);
485 let empty_digest = Word::empty();
486
487 let mut tree =
488 AccountTree::with_entries([(id0, digest0), (id1, digest1), (id2, digest2)]).unwrap();
489
490 tree.insert(id2, empty_digest).unwrap();
492
493 assert_eq!(tree.num_accounts(), 2);
494
495 let accounts: Vec<_> = tree.account_commitments().collect();
496 assert_eq!(accounts.len(), 2);
497 assert!(accounts.contains(&(id0, digest0)));
498 assert!(accounts.contains(&(id1, digest1)));
499 }
500
501 #[test]
502 fn account_witness() {
503 let id0 = AccountIdBuilder::new().build_with_seed([5; 32]);
504 let id1 = AccountIdBuilder::new().build_with_seed([6; 32]);
505
506 let digest0 = Word::from([0, 0, 0, 1u32]);
507 let digest1 = Word::from([0, 0, 0, 2u32]);
508
509 let tree = AccountTree::with_entries([(id0, digest0), (id1, digest1)]).unwrap();
510
511 assert_eq!(tree.num_accounts(), 2);
512
513 for id in [id0, id1] {
514 let (control_path, control_leaf) =
515 tree.smt.open(&AccountTree::id_to_smt_key(id)).into_parts();
516 let witness = tree.open(id);
517
518 assert_eq!(witness.leaf(), control_leaf);
519 assert_eq!(witness.path(), &control_path);
520 }
521 }
522
523 #[test]
524 fn contains_account_prefix() {
525 let [pair0, pair1] = setup_duplicate_prefix_ids();
527 let tree = AccountTree::with_entries([(pair0.0, pair0.1)]).unwrap();
528 assert_eq!(tree.num_accounts(), 1);
529
530 assert!(tree.contains_account_id_prefix(pair0.0.prefix()));
532
533 assert!(tree.contains_account_id_prefix(pair1.0.prefix()));
535
536 let id1 = AccountIdBuilder::new().build_with_seed([7; 32]);
538 assert!(!tree.contains_account_id_prefix(id1.prefix()));
539 }
540}