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
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,13 @@
- [BREAKING] Modified `TransactionHeader` serialization to allow converting back into the native type after serialization ([#1759](https://github.com/0xMiden/node/issues/1759)).
- Removed `chain_tip` requirement from mempool subscription request ([#1771](https://github.com/0xMiden/node/pull/1771)).
- Moved bootstrap procedure to `miden-node validator bootstrap` command ([#1764](https://github.com/0xMiden/node/pull/1764)).
- [BREAKING] Removed `bundled` command; each component is now started as a separate process. Added `ntx-builder` CLI subcommand. Added `docker-compose.yml` for local multi-process deployment ([#1765](https://github.com/0xMiden/node/pull/1765)).
- NTX Builder now deactivates network accounts which crash repeatedly (configurable via `--ntx-builder.max-account-crashes`, default 10) ([#1712](https://github.com/0xMiden/miden-node/pull/1712)).


### Fixes

- Fixed network monitor looping on stale wallet nonce after node restarts by re-syncing wallet state from RPC after repeated failures ([#1748](https://github.com/0xMiden/node/pull/1748)).
- Fixed `bundled start` panicking due to duplicate `data_directory` clap argument name between `BundledCommand::Start` and `NtxBuilderConfig` ([#1732](https://github.com/0xMiden/node/pull/1732)).
- Fixed `bundled bootstrap` requiring `--validator.key.hex` or `--validator.key.kms-id` despite a default key being configured ([#1732](https://github.com/0xMiden/node/pull/1732)).
- Fixed incorrectly classifying private notes with the network attachment as network notes ([#1378](https://github.com/0xMiden/node/pull/1738)).
- Fixed accept header version negotiation rejecting all pre-release versions; pre-release label matching is now lenient, accepting any numeric suffix within the same label (e.g. `alpha.3` accepts `alpha.1`) ([#1755](https://github.com/0xMiden/node/pull/1755)).

Expand Down
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@ install-network-monitor: ## Installs network monitor binary

# --- docker --------------------------------------------------------------------------------------

.PHONY: compose-genesis
compose-genesis: ## Wipes node volumes and creates a fresh genesis block
$(CONTAINER_RUNTIME) compose down --volumes --remove-orphans
$(CONTAINER_RUNTIME) volume rm -f miden-node_genesis-data miden-node_store-data miden-node_validator-data miden-node_ntx-builder-data miden-node_accounts
$(CONTAINER_RUNTIME) compose --profile genesis run --rm genesis

.PHONY: compose-up
compose-up: ## Starts all node components via docker compose
$(CONTAINER_RUNTIME) compose up -d

.PHONY: compose-down
compose-down: ## Stops and removes all node containers via docker compose
$(CONTAINER_RUNTIME) compose down

.PHONY: compose-logs
compose-logs: ## Follows logs for all node components via docker compose
$(CONTAINER_RUNTIME) compose logs -f

.PHONY: docker-build-node
docker-build-node: ## Builds the Miden node using Docker (override with CONTAINER_RUNTIME=podman)
@CREATED=$$(date) && \
Expand Down
3 changes: 1 addition & 2 deletions bin/node/.env
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# For more info use -h on the relevant commands:
# miden-node bundled start -h
# miden-node <component> start -h
MIDEN_NODE_BLOCK_PRODUCER_URL=
MIDEN_NODE_VALIDATOR_URL=
MIDEN_NODE_NTX_BUILDER_URL=
MIDEN_NODE_BATCH_PROVER_URL=
MIDEN_NODE_BLOCK_PROVER_URL=
MIDEN_NODE_NTX_PROVER_URL=
Expand Down
2 changes: 1 addition & 1 deletion bin/node/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ COPY . .
RUN cargo build --release --locked --bin miden-node

# Base line runtime image with runtime dependencies installed.
FROM debian:bullseye-slim AS runtime-base
FROM debian:bookworm-slim AS runtime-base
RUN apt-get update && \
apt-get -y upgrade && \
apt-get install -y --no-install-recommends sqlite3 \
Expand Down
137 changes: 1 addition & 136 deletions bin/node/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::net::SocketAddr;
use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
use std::time::Duration;

use anyhow::Context;
use miden_node_block_producer::{
DEFAULT_BATCH_INTERVAL,
DEFAULT_BLOCK_INTERVAL,
Expand All @@ -14,11 +11,10 @@ use miden_node_utils::clap::duration_to_human_readable_string;
use miden_node_validator::ValidatorSigner;
use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SecretKey;
use miden_protocol::utils::Deserializable;
use tokio::net::TcpListener;
use url::Url;

pub mod block_producer;
pub mod bundled;
pub mod ntx_builder;
pub mod rpc;
pub mod store;
pub mod validator;
Expand Down Expand Up @@ -98,137 +94,6 @@ impl ValidatorKey {
}
}

/// Configuration for the Validator component when run in the bundled mode.
#[derive(clap::Args)]
pub struct BundledValidatorConfig {
/// Insecure, hex-encoded validator secret key for development and testing purposes.
/// Only used when the Validator URL argument is not set.
#[arg(
long = "validator.key",
env = ENV_VALIDATOR_KEY,
value_name = "VALIDATOR_KEY",
default_value = INSECURE_VALIDATOR_KEY_HEX
)]
validator_key: String,

/// The remote Validator's gRPC URL. If unset, will default to running a Validator
/// in-process. If set, the insecure key argument is ignored.
#[arg(long = "validator.url", env = ENV_VALIDATOR_URL, value_name = "URL")]
validator_url: Option<Url>,
}

impl BundledValidatorConfig {
/// Converts the [`BundledValidatorConfig`] into a URL and an optional [`SocketAddr`].
///
/// If the `validator_url` is set, it returns the URL and `None` for the [`SocketAddr`].
///
/// If `validator_url` is not set, it binds to a random port on localhost, creates a URL,
/// and returns the URL and the bound [`SocketAddr`].
async fn to_addresses(&self) -> anyhow::Result<(Url, Option<SocketAddr>)> {
if let Some(url) = &self.validator_url {
Ok((url.clone(), None))
} else {
let socket_addr = TcpListener::bind("127.0.0.1:0")
.await
.context("Failed to bind to validator gRPC endpoint")?
.local_addr()
.context("Failed to retrieve the validator's gRPC address")?;
let url = Url::parse(&format!("http://{socket_addr}"))
.context("Failed to parse Validator URL")?;
Ok((url, Some(socket_addr)))
}
}
}

/// Configuration for the Network Transaction Builder component.
#[derive(clap::Args)]
pub struct NtxBuilderConfig {
/// Disable spawning the network transaction builder.
#[arg(long = "no-ntx-builder", default_value_t = false)]
pub disabled: bool,

/// The remote transaction prover's gRPC url, used for the ntx builder. If unset,
/// will default to running a prover in-process which is expensive.
#[arg(long = "tx-prover.url", env = ENV_NTX_PROVER_URL, value_name = "URL")]
pub tx_prover_url: Option<Url>,

/// Interval at which to run the network transaction builder's ticker.
#[arg(
long = "ntx-builder.interval",
default_value = &duration_to_human_readable_string(DEFAULT_NTX_TICKER_INTERVAL),
value_parser = humantime::parse_duration,
value_name = "DURATION"
)]
pub ticker_interval: Duration,

/// Number of note scripts to cache locally.
///
/// Note scripts not in cache must first be retrieved from the store.
#[arg(
long = "ntx-builder.script-cache-size",
env = ENV_NTX_SCRIPT_CACHE_SIZE,
value_name = "NUM",
default_value_t = DEFAULT_NTX_SCRIPT_CACHE_SIZE
)]
pub script_cache_size: NonZeroUsize,

/// Duration after which an idle network account will deactivate.
///
/// An account is considered idle once it has no viable notes to consume.
/// A deactivated account will reactivate if targeted with new notes.
#[arg(
long = "ntx-builder.idle-timeout",
default_value = &duration_to_human_readable_string(DEFAULT_NTX_IDLE_TIMEOUT),
value_parser = humantime::parse_duration,
value_name = "DURATION"
)]
pub idle_timeout: Duration,

/// Maximum number of crashes before an account deactivated.
///
/// Once this limit is reached, no new transactions will be created for this account.
#[arg(
long = "ntx-builder.max-account-crashes",
default_value_t = 10,
value_name = "NUM"
)]
pub max_account_crashes: usize,

/// Directory for the ntx-builder's persistent database.
///
/// If not set, defaults to the node's data directory.
#[arg(long = "ntx-builder.data-directory", env = ENV_NTX_DATA_DIRECTORY, value_name = "DIR")]
pub ntx_data_directory: Option<PathBuf>,
}

impl NtxBuilderConfig {
/// Converts this CLI config into the ntx-builder's internal config.
///
/// The `node_data_directory` is used as the default location for the ntx-builder's database
/// if `--ntx-builder.data-directory` is not explicitly set.
pub fn into_builder_config(
self,
store_url: Url,
block_producer_url: Url,
validator_url: Url,
node_data_directory: &Path,
) -> miden_node_ntx_builder::NtxBuilderConfig {
let data_dir = self.ntx_data_directory.unwrap_or_else(|| node_data_directory.to_path_buf());
let database_filepath = data_dir.join("ntx-builder.sqlite3");

miden_node_ntx_builder::NtxBuilderConfig::new(
store_url,
block_producer_url,
validator_url,
database_filepath,
)
.with_tx_prover_url(self.tx_prover_url)
.with_script_cache_size(self.script_cache_size)
.with_idle_timeout(self.idle_timeout)
.with_max_account_crashes(self.max_account_crashes)
}
}

/// Configuration for the Block Producer component
#[derive(clap::Args)]
pub struct BlockProducerConfig {
Expand Down
135 changes: 135 additions & 0 deletions bin/node/src/commands/ntx_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::time::Duration;

use anyhow::Context;
use miden_node_utils::clap::duration_to_human_readable_string;
use url::Url;

use super::{
DEFAULT_NTX_IDLE_TIMEOUT,
DEFAULT_NTX_SCRIPT_CACHE_SIZE,
DEFAULT_NTX_TICKER_INTERVAL,
ENV_BLOCK_PRODUCER_URL,
ENV_ENABLE_OTEL,
ENV_NTX_DATA_DIRECTORY,
ENV_NTX_PROVER_URL,
ENV_NTX_SCRIPT_CACHE_SIZE,
ENV_STORE_NTX_BUILDER_URL,
ENV_VALIDATOR_URL,
};

#[derive(clap::Subcommand)]
pub enum NtxBuilderCommand {
/// Starts the network transaction builder component.
Start {
/// The store's ntx-builder service gRPC url.
#[arg(long = "store.url", env = ENV_STORE_NTX_BUILDER_URL, value_name = "URL")]
store_url: Url,

/// The block-producer's gRPC url.
#[arg(long = "block-producer.url", env = ENV_BLOCK_PRODUCER_URL, value_name = "URL")]
block_producer_url: Url,

/// The validator's gRPC url.
#[arg(long = "validator.url", env = ENV_VALIDATOR_URL, value_name = "URL")]
validator_url: Url,

/// The remote transaction prover's gRPC url. If unset, will default to running a
/// prover in-process which is expensive.
#[arg(long = "tx-prover.url", env = ENV_NTX_PROVER_URL, value_name = "URL")]
tx_prover_url: Option<Url>,

/// Interval at which to run the network transaction builder's ticker.
#[arg(
long = "interval",
default_value = &duration_to_human_readable_string(DEFAULT_NTX_TICKER_INTERVAL),
value_parser = humantime::parse_duration,
value_name = "DURATION"
)]
ticker_interval: Duration,

/// Number of note scripts to cache locally.
///
/// Note scripts not in cache must first be retrieved from the store.
#[arg(
long = "script-cache-size",
env = ENV_NTX_SCRIPT_CACHE_SIZE,
value_name = "NUM",
default_value_t = DEFAULT_NTX_SCRIPT_CACHE_SIZE
)]
script_cache_size: NonZeroUsize,

/// Duration after which an idle network account will deactivate.
///
/// An account is considered idle once it has no viable notes to consume.
/// A deactivated account will reactivate if targeted with new notes.
#[arg(
long = "idle-timeout",
default_value = &duration_to_human_readable_string(DEFAULT_NTX_IDLE_TIMEOUT),
value_parser = humantime::parse_duration,
value_name = "DURATION"
)]
idle_timeout: Duration,

/// Maximum number of crashes before an account deactivated.
///
/// Once this limit is reached, no new transactions will be created for this account.
#[arg(long = "max-account-crashes", default_value_t = 10, value_name = "NUM")]
max_account_crashes: usize,

/// Directory for the ntx-builder's persistent database.
#[arg(long = "data-directory", env = ENV_NTX_DATA_DIRECTORY, value_name = "DIR")]
data_directory: PathBuf,

/// Enables the exporting of traces for OpenTelemetry.
///
/// This can be further configured using environment variables as defined in the official
/// OpenTelemetry documentation. See our operator manual for further details.
#[arg(long = "enable-otel", default_value_t = false, env = ENV_ENABLE_OTEL, value_name = "BOOL")]
enable_otel: bool,
},
}

impl NtxBuilderCommand {
pub async fn handle(self) -> anyhow::Result<()> {
let Self::Start {
store_url,
block_producer_url,
validator_url,
tx_prover_url,
ticker_interval: _,
script_cache_size,
idle_timeout,
max_account_crashes,
data_directory,
enable_otel: _,
} = self;

let database_filepath = data_directory.join("ntx-builder.sqlite3");

let config = miden_node_ntx_builder::NtxBuilderConfig::new(
store_url,
block_producer_url,
validator_url,
database_filepath,
)
.with_tx_prover_url(tx_prover_url)
.with_script_cache_size(script_cache_size)
.with_idle_timeout(idle_timeout)
.with_max_account_crashes(max_account_crashes);

config
.build()
.await
.context("failed to initialize ntx builder")?
.run()
.await
.context("failed while running ntx builder component")
}

pub fn is_open_telemetry_enabled(&self) -> bool {
let Self::Start { enable_otel, .. } = self;
*enable_otel
}
}
4 changes: 1 addition & 3 deletions bin/node/src/commands/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ impl ValidatorCommand {

/// Bootstraps the genesis block: creates accounts, signs the block, and writes artifacts to
/// disk.
///
/// This is extracted as a free function so it can be reused by the bundled bootstrap command.
pub async fn bootstrap_genesis(
async fn bootstrap_genesis(
genesis_block_directory: &Path,
accounts_directory: &Path,
genesis_config: Option<&PathBuf>,
Expand Down
Loading
Loading