Skip to content
Open
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
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 @@ -53,10 +53,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
75 changes: 0 additions & 75 deletions crates/ntx-builder/src/actor/inflight_note.rs

This file was deleted.

77 changes: 4 additions & 73 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,10 +21,9 @@ use tokio::sync::{AcquireError, Notify, RwLock, Semaphore, mpsc};
use tokio_util::sync::CancellationToken;
use url::Url;

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;

/// Converts a database result into an `ActorShutdownReason` error, logging the error on failure.
fn db_query<T>(
Expand Down Expand Up @@ -446,69 +443,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_protocol::transaction::TransactionId;
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 @@ -9,7 +9,7 @@ use miden_protocol::block::{BlockHeader, BlockNumber};
use miden_protocol::note::Nullifier;
use miden_protocol::transaction::TransactionId;

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 @@ -7,9 +7,9 @@ use miden_node_proto::domain::note::SingleTargetNetworkNote;
use miden_protocol::block::BlockNumber;
use miden_protocol::note::Nullifier;

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