Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a943e5a
refactor(ntx-builder): simplify coordinator-actor messaging with Notify
SantiagoPittella Feb 23, 2026
4419820
review: add DbError error case
SantiagoPittella Feb 24, 2026
2e765a9
chore: simplify matches
SantiagoPittella Feb 24, 2026
a1fa0f3
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Feb 24, 2026
6472314
review: rename transaction_exists, update query, improve docs
SantiagoPittella Feb 25, 2026
4d5f47e
review: update receiver docs
SantiagoPittella Feb 25, 2026
580f9cb
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Feb 25, 2026
9173443
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Feb 26, 2026
5c0fc2e
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Feb 27, 2026
a48e1a0
review: add miden_node_db::DatabaseError to ntx error
SantiagoPittella Mar 2, 2026
21d916b
review: improve actor shutdown reason mapping
SantiagoPittella Mar 2, 2026
4eb9574
review: remove db_query helper function
SantiagoPittella Mar 2, 2026
6b61ff5
review: propagate error on db write
SantiagoPittella Mar 2, 2026
c00237d
review: de-register actor on shutdown
SantiagoPittella Mar 2, 2026
6754bf9
review: send targeted everytime
SantiagoPittella Mar 2, 2026
1b190b1
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Mar 2, 2026
9763b65
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Mar 3, 2026
915d0ed
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Mar 4, 2026
7deb536
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Mar 6, 2026
6b2c7ff
review: use ?
SantiagoPittella Mar 9, 2026
4c75b51
review: replace run to return Result and remove matches
SantiagoPittella Mar 9, 2026
7ab6711
review: simplify actor shutdown
SantiagoPittella Mar 9, 2026
00a1a19
review: simplify queries using RETURNING
SantiagoPittella Mar 9, 2026
89703f4
review: remove negation from exists
SantiagoPittella Mar 9, 2026
820c0f5
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Mar 9, 2026
50748f7
review: use inspect_err
SantiagoPittella Mar 10, 2026
edd9d43
Merge branch 'next' into santiagopittella-ntx-simplify-actor-messages
SantiagoPittella Mar 10, 2026
429b63e
chore: refactor ntx-builder code org
SantiagoPittella Feb 24, 2026
2dbea7f
Merge next
Mirko-von-Leipzig Mar 11, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use miden_protocol::account::Account;
use miden_protocol::block::BlockHeader;
use miden_protocol::transaction::PartialBlockchain;

use crate::actor::inflight_note::InflightNetworkNote;
use crate::inflight_note::InflightNetworkNote;

// TRANSACTION CANDIDATE
// ================================================================================================
Expand Down
5 changes: 2 additions & 3 deletions crates/ntx-builder/src/actor/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ use tokio::task::JoinError;
use tracing::{Instrument, instrument};

use crate::COMPONENT;
use crate::actor::account_state::TransactionCandidate;
use crate::block_producer::BlockProducerClient;
use crate::actor::candidate::TransactionCandidate;
use crate::clients::{BlockProducerClient, StoreClient};
use crate::db::Db;
use crate::store::StoreClient;

#[derive(Debug, thiserror::Error)]
pub enum NtxError {
Expand Down
79 changes: 0 additions & 79 deletions crates/ntx-builder/src/actor/inflight_note.rs

This file was deleted.

79 changes: 5 additions & 74 deletions crates/ntx-builder/src/actor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
pub(crate) mod account_effect;
pub mod account_state;
pub mod candidate;
mod execute;
pub(crate) mod inflight_note;

use std::num::NonZeroUsize;
use std::sync::Arc;
use std::time::Duration;

use account_state::TransactionCandidate;
use candidate::TransactionCandidate;
use futures::FutureExt;
use miden_node_proto::clients::{Builder, ValidatorClient};
use miden_node_proto::domain::account::NetworkAccountId;
Expand All @@ -23,11 +21,10 @@ use tokio::sync::{AcquireError, Notify, RwLock, Semaphore, mpsc};
use tokio_util::sync::CancellationToken;
use url::Url;

use crate::actor::inflight_note::InflightNetworkNote;
use crate::block_producer::BlockProducerClient;
use crate::builder::ChainState;
use crate::chain_state::ChainState;
use crate::clients::{BlockProducerClient, StoreClient};
use crate::db::Db;
use crate::store::StoreClient;
use crate::inflight_note::InflightNetworkNote;

// ACTOR REQUESTS
// ================================================================================================
Expand Down Expand Up @@ -430,69 +427,3 @@ impl AccountActor {
let _ = ack_rx.await;
}
}

// HELPERS
// ================================================================================================

/// Checks if the backoff block period has passed.
///
/// The number of blocks passed since the last attempt must be greater than or equal to
/// e^(0.25 * `attempt_count`) rounded to the nearest integer.
///
/// This evaluates to the following:
/// - After 1 attempt, the backoff period is 1 block.
/// - After 3 attempts, the backoff period is 2 blocks.
/// - After 10 attempts, the backoff period is 12 blocks.
/// - After 20 attempts, the backoff period is 148 blocks.
/// - etc...
#[expect(clippy::cast_precision_loss, clippy::cast_sign_loss)]
fn has_backoff_passed(
chain_tip: BlockNumber,
last_attempt: Option<BlockNumber>,
attempts: usize,
) -> bool {
if attempts == 0 {
return true;
}
// Compute the number of blocks passed since the last attempt.
let blocks_passed = last_attempt
.and_then(|last| chain_tip.checked_sub(last.as_u32()))
.unwrap_or_default();

// Compute the exponential backoff threshold: Δ = e^(0.25 * n).
let backoff_threshold = (0.25 * attempts as f64).exp().round() as usize;

// Check if the backoff period has passed.
blocks_passed.as_usize() > backoff_threshold
}

#[cfg(test)]
mod tests {
use miden_protocol::block::BlockNumber;

use super::has_backoff_passed;

#[rstest::rstest]
#[test]
#[case::all_zero(Some(BlockNumber::GENESIS), BlockNumber::GENESIS, 0, true)]
#[case::no_attempts(None, BlockNumber::GENESIS, 0, true)]
#[case::one_attempt(Some(BlockNumber::GENESIS), BlockNumber::from(2), 1, true)]
#[case::three_attempts(Some(BlockNumber::GENESIS), BlockNumber::from(3), 3, true)]
#[case::ten_attempts(Some(BlockNumber::GENESIS), BlockNumber::from(13), 10, true)]
#[case::twenty_attempts(Some(BlockNumber::GENESIS), BlockNumber::from(149), 20, true)]
#[case::one_attempt_false(Some(BlockNumber::GENESIS), BlockNumber::from(1), 1, false)]
#[case::three_attempts_false(Some(BlockNumber::GENESIS), BlockNumber::from(2), 3, false)]
#[case::ten_attempts_false(Some(BlockNumber::GENESIS), BlockNumber::from(12), 10, false)]
#[case::twenty_attempts_false(Some(BlockNumber::GENESIS), BlockNumber::from(148), 20, false)]
fn backoff_has_passed(
#[case] last_attempt_block_num: Option<BlockNumber>,
#[case] current_block_num: BlockNumber,
#[case] attempt_count: usize,
#[case] backoff_should_have_passed: bool,
) {
assert_eq!(
backoff_should_have_passed,
has_backoff_passed(current_block_num, last_attempt_block_num, attempt_count)
);
}
}
49 changes: 2 additions & 47 deletions crates/ntx-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,16 @@ use miden_node_proto::domain::account::NetworkAccountId;
use miden_node_proto::domain::mempool::MempoolEvent;
use miden_protocol::account::delta::AccountUpdateDetails;
use miden_protocol::block::BlockHeader;
use miden_protocol::crypto::merkle::mmr::PartialMmr;
use miden_protocol::transaction::PartialBlockchain;
use tokio::sync::{RwLock, mpsc};
use tokio_stream::StreamExt;
use tonic::Status;

use crate::NtxBuilderConfig;
use crate::actor::{AccountActorContext, AccountOrigin, ActorRequest};
use crate::chain_state::ChainState;
use crate::clients::StoreClient;
use crate::coordinator::Coordinator;
use crate::db::Db;
use crate::store::StoreClient;

// CHAIN STATE
// ================================================================================================

/// Contains information about the chain that is relevant to the [`NetworkTransactionBuilder`] and
/// all account actors managed by the [`Coordinator`].
///
/// The chain MMR stored here contains:
/// - The MMR peaks.
/// - Block headers and authentication paths for the last [`NtxBuilderConfig::max_block_count`]
/// blocks.
///
/// Authentication paths for older blocks are pruned because the NTX builder executes all notes as
/// "unauthenticated" (see [`InputNotes::from_unauthenticated_notes`]) and therefore does not need
/// to prove that input notes were created in specific past blocks.
#[derive(Debug, Clone)]
pub struct ChainState {
/// The current tip of the chain.
pub chain_tip_header: BlockHeader,
/// A partial representation of the chain MMR.
///
/// Contains block headers and authentication paths for the last
/// [`NtxBuilderConfig::max_block_count`] blocks only, since all notes are executed as
/// unauthenticated.
pub chain_mmr: Arc<PartialBlockchain>,
}

impl ChainState {
/// Constructs a new instance of [`ChainState`].
pub(crate) fn new(chain_tip_header: BlockHeader, chain_mmr: PartialMmr) -> Self {
let chain_mmr = PartialBlockchain::new(chain_mmr, [])
.expect("partial blockchain should build from partial mmr");
Self {
chain_tip_header,
chain_mmr: Arc::new(chain_mmr),
}
}

/// Consumes the chain state and returns the chain tip header and the partial blockchain as a
/// tuple.
pub fn into_parts(self) -> (BlockHeader, Arc<PartialBlockchain>) {
(self.chain_tip_header, self.chain_mmr)
}
}

// NETWORK TRANSACTION BUILDER
// ================================================================================================
Expand Down
49 changes: 49 additions & 0 deletions crates/ntx-builder/src/chain_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use std::sync::Arc;

use miden_protocol::block::BlockHeader;
use miden_protocol::crypto::merkle::mmr::PartialMmr;
use miden_protocol::transaction::PartialBlockchain;

// CHAIN STATE
// ================================================================================================

/// Contains information about the chain that is relevant to the [`NetworkTransactionBuilder`] and
/// all account actors managed by the [`Coordinator`].
///
/// The chain MMR stored here contains:
/// - The MMR peaks.
/// - Block headers and authentication paths for the last
/// [`NtxBuilderConfig::max_block_count`](crate::NtxBuilderConfig::max_block_count) blocks.
///
/// Authentication paths for older blocks are pruned because the NTX builder executes all notes as
/// "unauthenticated" (see [`InputNotes::from_unauthenticated_notes`]) and therefore does not need
/// to prove that input notes were created in specific past blocks.
#[derive(Debug, Clone)]
pub struct ChainState {
/// The current tip of the chain.
pub chain_tip_header: BlockHeader,
/// A partial representation of the chain MMR.
///
/// Contains block headers and authentication paths for the last
/// [`NtxBuilderConfig::max_block_count`](crate::NtxBuilderConfig::max_block_count) blocks
/// only, since all notes are executed as unauthenticated.
pub chain_mmr: Arc<PartialBlockchain>,
}

impl ChainState {
/// Constructs a new instance of [`ChainState`].
pub(crate) fn new(chain_tip_header: BlockHeader, chain_mmr: PartialMmr) -> Self {
let chain_mmr = PartialBlockchain::new(chain_mmr, [])
.expect("partial blockchain should build from partial mmr");
Self {
chain_tip_header,
chain_mmr: Arc::new(chain_mmr),
}
}

/// Consumes the chain state and returns the chain tip header and the partial blockchain as a
/// tuple.
pub fn into_parts(self) -> (BlockHeader, Arc<PartialBlockchain>) {
(self.chain_tip_header, self.chain_mmr)
}
}
5 changes: 5 additions & 0 deletions crates/ntx-builder/src/clients/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod block_producer;
mod store;

pub use block_producer::BlockProducerClient;
pub use store::StoreClient;
2 changes: 1 addition & 1 deletion crates/ntx-builder/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use miden_standards::note::AccountTargetNetworkNote;
use tracing::{info, instrument};

use crate::COMPONENT;
use crate::actor::inflight_note::InflightNetworkNote;
use crate::db::migrations::apply_migrations;
use crate::db::models::queries;
use crate::inflight_note::InflightNetworkNote;

pub(crate) mod models;

Expand Down
1 change: 1 addition & 0 deletions crates/ntx-builder/src/db/models/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod account_effect;
pub(crate) mod conv;

pub mod queries;
2 changes: 1 addition & 1 deletion crates/ntx-builder/src/db/models/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use miden_protocol::transaction::TransactionId;
use miden_standards::note::AccountTargetNetworkNote;
use miden_tx::utils::Serializable;

use crate::actor::account_effect::NetworkAccountEffect;
use super::account_effect::NetworkAccountEffect;
use crate::db::models::conv as conversions;
use crate::db::schema;

Expand Down
2 changes: 1 addition & 1 deletion crates/ntx-builder/src/db/models/queries/notes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use miden_protocol::note::{Note, Nullifier};
use miden_standards::note::AccountTargetNetworkNote;
use miden_tx::utils::{Deserializable, Serializable};

use crate::actor::inflight_note::InflightNetworkNote;
use crate::db::models::conv as conversions;
use crate::db::schema;
use crate::inflight_note::InflightNetworkNote;

// MODELS
// ================================================================================================
Expand Down
Loading
Loading