Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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 @@ -31,12 +31,11 @@
- [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)).

### 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
113 changes: 1 addition & 112 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 @@ -97,113 +93,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,

/// 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)
}
}

/// Configuration for the Block Producer component
#[derive(clap::Args)]
pub struct BlockProducerConfig {
Expand Down
112 changes: 112 additions & 0 deletions bin/node/src/commands/ntx_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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_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,

/// 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,
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);

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
13 changes: 5 additions & 8 deletions bin/node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ pub struct Cli {
pub command: Command,
}

#[expect(clippy::large_enum_variant)]
#[derive(Subcommand)]
pub enum Command {
/// Commands related to the node's store component.
Expand All @@ -32,15 +31,13 @@ pub enum Command {
#[command(subcommand)]
BlockProducer(commands::block_producer::BlockProducerCommand),

// Commands related to the node's validator component.
/// Commands related to the node's validator component.
#[command(subcommand)]
Validator(commands::validator::ValidatorCommand),

/// Commands relevant to running all components in the same process.
///
/// This is the recommended way to run the node at the moment.
/// Commands related to the node's network transaction builder component.
#[command(subcommand)]
Bundled(commands::bundled::BundledCommand),
NtxBuilder(commands::ntx_builder::NtxBuilderCommand),
}

impl Command {
Expand All @@ -53,7 +50,7 @@ impl Command {
Command::Rpc(subcommand) => subcommand.is_open_telemetry_enabled(),
Command::BlockProducer(subcommand) => subcommand.is_open_telemetry_enabled(),
Command::Validator(subcommand) => subcommand.is_open_telemetry_enabled(),
Command::Bundled(subcommand) => subcommand.is_open_telemetry_enabled(),
Command::NtxBuilder(subcommand) => subcommand.is_open_telemetry_enabled(),
} {
OpenTelemetry::Enabled
} else {
Expand All @@ -67,7 +64,7 @@ impl Command {
Command::Store(store_command) => store_command.handle().await,
Command::BlockProducer(block_producer_command) => block_producer_command.handle().await,
Command::Validator(validator) => validator.handle().await,
Command::Bundled(node) => node.handle().await,
Command::NtxBuilder(ntx_builder) => ntx_builder.handle().await,
}
}
}
Expand Down
Loading
Loading