Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

### Changes
- Added validation of leaf type on CLAIM note processing to prevent message leaves from being processed as asset claims ([#2730](https://github.com/0xMiden/protocol/pull/2730)).

- Added `AssetAmount` wrapper type for validated fungible asset amounts ([#2721](https://github.com/0xMiden/protocol/pull/2721)).
- [BREAKING] Renamed `ProvenBatch::new` to `new_unchecked` ([#2687](https://github.com/0xMiden/miden-base/issues/2687)).
- Added `ShortCapitalString` type and related `TokenSymbol` and `RoleSymbol` types ([#2690](https://github.com/0xMiden/protocol/pull/2690)).
- [BREAKING] Renamed the guarded multisig component-facing APIs from `multisig_guardian` / `AuthMultisigGuardian` to `guarded_multisig` / `AuthGuardedMultisig`, while retaining the `guardian` auth namespace and guardian-specific procedures.
- Added shared `ProcedurePolicy` for AuthMultisig ([#2670](https://github.com/0xMiden/protocol/pull/2670)).
- [BREAKING] Changed `NoteType` encoding from 2 bits to 1 and makes `NoteType::Private` the default ([#2691](https://github.com/0xMiden/miden-base/issues/2691)).
- Added `BlockNumber::saturating_sub()` ([#2660](https://github.com/0xMiden/protocol/issues/2660)).
- Added `NullifierTreeBackendReader` and `AccountTreeBackendReader` traits ([#2755](https://github.com/0xMiden/protocol/pull/2755)).

## 0.14.3 (2026-04-07)

Expand Down
12 changes: 4 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ rstest = { version = "0.26" }
serde = { default-features = false, version = "1.0" }
thiserror = { default-features = false, version = "2.0" }
tokio = { default-features = false, features = ["sync"], version = "1" }

[patch.crates-io]
miden-crypto = { branch = "sergerad-largesmt-reader-trait", git = "https://github.com/0xmiden/crypto" }
miden-serde-utils = { branch = "sergerad-largesmt-reader-trait", git = "https://github.com/0xmiden/crypto" }
156 changes: 95 additions & 61 deletions crates/miden-protocol/src/block/account_tree/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ use super::{AccountId, AccountIdKey, AccountIdPrefix, AccountTree, AccountTreeEr
use crate::Word;
use crate::crypto::merkle::MerkleError;
#[cfg(feature = "std")]
use crate::crypto::merkle::smt::{LargeSmt, LargeSmtError, SmtStorage};
use crate::crypto::merkle::smt::{LargeSmt, LargeSmtError, SmtStorage, SmtStorageReader};
use crate::crypto::merkle::smt::{LeafIndex, MutationSet, SMT_DEPTH, Smt, SmtLeaf, SmtProof};

// ACCOUNT TREE BACKEND
// ACCOUNT TREE BACKEND READER
// ================================================================================================

/// This trait abstracts over different SMT backends (e.g., `Smt` and `LargeSmt`) to allow
/// the `AccountTree` to work with either implementation transparently.
///
/// This trait contains only read-only methods. For write methods, see
/// [`AccountTreeBackend`].
///
/// Implementors must provide `Default` for creating empty instances. Users should
/// instantiate the backend directly (potentially with entries) and then pass it to
/// [`AccountTree::new`].
pub trait AccountTreeBackend: Sized {
pub trait AccountTreeBackendReader: Sized {
type Error: core::error::Error + Send + 'static;

/// Returns the number of leaves in the SMT.
Expand All @@ -29,6 +32,27 @@ pub trait AccountTreeBackend: Sized {
/// Opens the leaf at the given key, returning a Merkle proof.
fn open(&self, key: &Word) -> SmtProof;

/// Returns the value associated with the given key.
fn get_value(&self, key: &Word) -> Word;

/// Returns the leaf at the given key.
fn get_leaf(&self, key: &Word) -> SmtLeaf;

/// Returns the root of the SMT.
fn root(&self) -> Word;
}

// ACCOUNT TREE BACKEND
// ================================================================================================

/// Extension trait for [`AccountTreeBackendReader`] that provides write methods.
pub trait AccountTreeBackend: AccountTreeBackendReader {
/// Computes the mutation set required to apply the given updates to the SMT.
fn compute_mutations(
&self,
updates: Vec<(Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error>;

/// Applies the given mutation set to the SMT.
fn apply_mutations(
&mut self,
Expand All @@ -43,29 +67,14 @@ pub trait AccountTreeBackend: Sized {
set: MutationSet<SMT_DEPTH, Word, Word>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error>;

/// Computes the mutation set required to apply the given updates to the SMT.
fn compute_mutations(
&self,
updates: Vec<(Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error>;

/// Inserts a key-value pair into the SMT, returning the previous value at that key.
fn insert(&mut self, key: Word, value: Word) -> Result<Word, Self::Error>;

/// Returns the value associated with the given key.
fn get_value(&self, key: &Word) -> Word;

/// Returns the leaf at the given key.
fn get_leaf(&self, key: &Word) -> SmtLeaf;

/// Returns the root of the SMT.
fn root(&self) -> Word;
}

// BACKEND IMPLEMENTATION FOR SMT
// BACKEND READER IMPLEMENTATION FOR SMT
// ================================================================================================

impl AccountTreeBackend for Smt {
impl AccountTreeBackendReader for Smt {
type Error = MerkleError;

fn num_leaves(&self) -> usize {
Expand All @@ -80,6 +89,30 @@ impl AccountTreeBackend for Smt {
Smt::open(self, key)
}

fn get_value(&self, key: &Word) -> Word {
Smt::get_value(self, key)
}

fn get_leaf(&self, key: &Word) -> SmtLeaf {
Smt::get_leaf(self, key)
}

fn root(&self) -> Word {
Smt::root(self)
}
}

// BACKEND IMPLEMENTATION FOR SMT
// ================================================================================================

impl AccountTreeBackend for Smt {
fn compute_mutations(
&self,
updates: Vec<(Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error> {
Smt::compute_mutations(self, updates)
}

fn apply_mutations(
&mut self,
set: MutationSet<SMT_DEPTH, Word, Word>,
Expand All @@ -94,37 +127,18 @@ impl AccountTreeBackend for Smt {
Smt::apply_mutations_with_reversion(self, set)
}

fn compute_mutations(
&self,
updates: Vec<(Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error> {
Smt::compute_mutations(self, updates)
}

fn insert(&mut self, key: Word, value: Word) -> Result<Word, Self::Error> {
Smt::insert(self, key, value)
}

fn get_value(&self, key: &Word) -> Word {
Smt::get_value(self, key)
}

fn get_leaf(&self, key: &Word) -> SmtLeaf {
Smt::get_leaf(self, key)
}

fn root(&self) -> Word {
Smt::root(self)
}
}

// BACKEND IMPLEMENTATION FOR LARGE SMT
// BACKEND READER IMPLEMENTATION FOR LARGE SMT
// ================================================================================================

#[cfg(feature = "std")]
impl<Backend> AccountTreeBackend for LargeSmt<Backend>
impl<Backend> AccountTreeBackendReader for LargeSmt<Backend>
where
Backend: SmtStorage,
Backend: SmtStorageReader,
{
type Error = MerkleError;

Expand All @@ -140,6 +154,34 @@ where
LargeSmt::open(self, key)
}

fn get_value(&self, key: &Word) -> Word {
LargeSmt::get_value(self, key)
}

fn get_leaf(&self, key: &Word) -> SmtLeaf {
LargeSmt::get_leaf(self, key)
}

fn root(&self) -> Word {
LargeSmt::root(self)
}
}

// BACKEND IMPLEMENTATION FOR LARGE SMT
// ================================================================================================

#[cfg(feature = "std")]
impl<Backend> AccountTreeBackend for LargeSmt<Backend>
where
Backend: SmtStorage,
{
fn compute_mutations(
&self,
updates: Vec<(Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error> {
LargeSmt::compute_mutations(self, updates).map_err(large_smt_error_to_merkle_error)
}

fn apply_mutations(
&mut self,
set: MutationSet<SMT_DEPTH, Word, Word>,
Expand All @@ -154,28 +196,9 @@ where
LargeSmt::apply_mutations_with_reversion(self, set).map_err(large_smt_error_to_merkle_error)
}

fn compute_mutations(
&self,
updates: Vec<(Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error> {
LargeSmt::compute_mutations(self, updates).map_err(large_smt_error_to_merkle_error)
}

fn insert(&mut self, key: Word, value: Word) -> Result<Word, Self::Error> {
LargeSmt::insert(self, key, value)
}

fn get_value(&self, key: &Word) -> Word {
LargeSmt::get_value(self, key)
}

fn get_leaf(&self, key: &Word) -> SmtLeaf {
LargeSmt::get_leaf(self, key)
}

fn root(&self) -> Word {
LargeSmt::root(self)
}
}

// CONVENIENCE METHODS
Expand Down Expand Up @@ -223,6 +246,17 @@ impl AccountTree<Smt> {
}
}

#[cfg(feature = "std")]
impl<Backend> AccountTree<LargeSmt<Backend>>
where
Backend: SmtStorage,
{
/// Returns a read-only account tree backed by a reader view of this tree's storage.
pub fn reader(&self) -> AccountTree<LargeSmt<Backend::Reader>> {
AccountTree::new_unchecked(self.smt.reader())
}
}

// HELPER FUNCTIONS
// ================================================================================================

Expand Down
41 changes: 23 additions & 18 deletions crates/miden-protocol/src/block/account_tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod witness;
pub use witness::AccountWitness;

mod backend;
pub use backend::AccountTreeBackend;
pub use backend::{AccountTreeBackend, AccountTreeBackendReader};

mod account_id_key;
pub use account_id_key::AccountIdKey;
Expand Down Expand Up @@ -53,7 +53,7 @@ where

impl<S> AccountTree<S>
where
S: AccountTreeBackend<Error = MerkleError>,
S: AccountTreeBackendReader<Error = MerkleError>,
{
// CONSTANTS
// --------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -188,6 +188,27 @@ where
})
}

// HELPERS
// --------------------------------------------------------------------------------------------

/// Returns the SMT key of the given account ID prefix.
fn id_prefix_to_smt_key(account_id: AccountIdPrefix) -> Word {
// We construct this in such a way that we're forced to use the constants, so that when
// they're updated, the other usages of the constants are also updated.
let mut key = Word::empty();
key[Self::KEY_PREFIX_IDX] = account_id.as_felt();

key
}
}

impl<S> AccountTree<S>
where
S: AccountTreeBackend<Error = MerkleError>,
{
// PUBLIC MUTATORS
// --------------------------------------------------------------------------------------------

/// Computes the necessary changes to insert the specified (account ID, state commitment) pairs
/// into this tree, allowing for validation before applying those changes.
///
Expand Down Expand Up @@ -245,9 +266,6 @@ where
Ok(AccountMutationSet::new(mutation_set))
}

// PUBLIC MUTATORS
// --------------------------------------------------------------------------------------------

/// Inserts the state commitment for the given account ID, returning the previous state
/// commitment associated with that ID.
///
Expand Down Expand Up @@ -314,19 +332,6 @@ where
.map_err(AccountTreeError::ApplyMutations)?;
Ok(AccountMutationSet::new(reversion))
}

// HELPERS
// --------------------------------------------------------------------------------------------

/// Returns the SMT key of the given account ID prefix.
fn id_prefix_to_smt_key(account_id: AccountIdPrefix) -> Word {
// We construct this in such a way that we're forced to use the constants, so that when
// they're updated, the other usages of the constants are also updated.
let mut key = Word::empty();
key[Self::KEY_PREFIX_IDX] = account_id.as_felt();

key
}
}

// SERIALIZATION
Expand Down
Loading
Loading