From d9d058ac3607f5754c058d61e4d50257312e67ae Mon Sep 17 00:00:00 2001 From: sergerad Date: Thu, 12 Mar 2026 19:49:11 +1300 Subject: [PATCH 1/4] docker compose --- CHANGELOG.md | 3 +- Makefile | 18 ++++ bin/node/.env | 3 +- bin/node/Dockerfile | 2 +- bin/node/src/commands/mod.rs | 113 +-------------------- bin/node/src/commands/ntx_builder.rs | 112 +++++++++++++++++++++ bin/node/src/commands/validator.rs | 4 +- bin/node/src/main.rs | 13 +-- docker-compose.yml | 104 +++++++++++++++++++ docs/external/src/operator/monitoring.md | 10 +- docs/external/src/operator/usage.md | 121 +++++++++++++++-------- 11 files changed, 330 insertions(+), 173 deletions(-) create mode 100644 bin/node/src/commands/ntx_builder.rs create mode 100644 docker-compose.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 926a8edd11..8ba86cd4bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)). diff --git a/Makefile b/Makefile index 33ab72a885..9127ce6317 100644 --- a/Makefile +++ b/Makefile @@ -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) && \ diff --git a/bin/node/.env b/bin/node/.env index 51a04794f9..51cfaa3f1e 100644 --- a/bin/node/.env +++ b/bin/node/.env @@ -1,8 +1,7 @@ # For more info use -h on the relevant commands: -# miden-node bundled start -h +# miden-node 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= diff --git a/bin/node/Dockerfile b/bin/node/Dockerfile index bf41b46d38..e6f387b3ef 100644 --- a/bin/node/Dockerfile +++ b/bin/node/Dockerfile @@ -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 \ diff --git a/bin/node/src/commands/mod.rs b/bin/node/src/commands/mod.rs index 9d3951cf0c..daabf1193f 100644 --- a/bin/node/src/commands/mod.rs +++ b/bin/node/src/commands/mod.rs @@ -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, @@ -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; @@ -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, -} - -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)> { - 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, - - /// 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, -} - -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 { diff --git a/bin/node/src/commands/ntx_builder.rs b/bin/node/src/commands/ntx_builder.rs new file mode 100644 index 0000000000..650b15d03a --- /dev/null +++ b/bin/node/src/commands/ntx_builder.rs @@ -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, + + /// 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 + } +} diff --git a/bin/node/src/commands/validator.rs b/bin/node/src/commands/validator.rs index 0068578891..01bb9ea6ff 100644 --- a/bin/node/src/commands/validator.rs +++ b/bin/node/src/commands/validator.rs @@ -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>, diff --git a/bin/node/src/main.rs b/bin/node/src/main.rs index 40bc187aa3..9ce6e63877 100644 --- a/bin/node/src/main.rs +++ b/bin/node/src/main.rs @@ -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. @@ -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 { @@ -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 { @@ -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, } } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..767fbb7829 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,104 @@ +services: + genesis: + image: miden-node-image + pull_policy: if_not_present + profiles: + - genesis + volumes: + - genesis-data:/genesis + - store-data:/store + - accounts:/accounts + entrypoint: ["/bin/sh", "-c"] + command: + - | + set -e + echo "Bootstrapping validator (creating genesis block)..." + miden-node validator bootstrap \ + --genesis-block-directory /genesis \ + --accounts-directory /accounts + echo "Bootstrapping store..." + miden-node store bootstrap \ + --data-directory /store \ + --genesis-block /genesis/genesis.dat + + store: + image: miden-node-image + pull_policy: if_not_present + volumes: + - store-data:/data + command: + - miden-node + - store + - start + - --rpc.url=http://0.0.0.0:50001 + - --ntx-builder.url=http://0.0.0.0:50002 + - --block-producer.url=http://0.0.0.0:50003 + - --data-directory=/data + ports: + - "50001:50001" + - "50002:50002" + - "50003:50003" + + validator: + image: miden-node-image + pull_policy: if_not_present + volumes: + - validator-data:/data + environment: + - MIDEN_NODE_ENABLE_OTEL=false + command: + - miden-node + - validator + - start + - http://0.0.0.0:50101 + - --data-directory=/data + ports: + - "50101:50101" + + block-producer: + image: miden-node-image + pull_policy: if_not_present + command: + - miden-node + - block-producer + - start + - http://0.0.0.0:50201 + - --store.url=http://store:50003 + - --validator.url=http://validator:50101 + ports: + - "50201:50201" + + rpc: + image: miden-node-image + pull_policy: if_not_present + command: + - miden-node + - rpc + - start + - --url=http://0.0.0.0:57291 + - --store.url=http://store:50001 + - --block-producer.url=http://block-producer:50201 + - --validator.url=http://validator:50101 + ports: + - "57291:57291" + + ntx-builder: + image: miden-node-image + pull_policy: if_not_present + volumes: + - ntx-builder-data:/data + command: + - miden-node + - ntx-builder + - start + - --store.url=http://store:50002 + - --block-producer.url=http://block-producer:50201 + - --validator.url=http://validator:50101 + - --data-directory=/data + +volumes: + genesis-data: + store-data: + validator-data: + ntx-builder-data: + accounts: diff --git a/docs/external/src/operator/monitoring.md b/docs/external/src/operator/monitoring.md index 9e3ba945cd..623e215bd4 100644 --- a/docs/external/src/operator/monitoring.md +++ b/docs/external/src/operator/monitoring.md @@ -118,7 +118,7 @@ The available log levels are `trace`, `debug`, `info` (default), `warn`, `error` export RUST_LOG=debug ``` -The verbosity can also be specified by component (when running them as a single process): +The verbosity can also be specified by component: ```sh export RUST_LOG=warn,block-producer=debug,rpc=error @@ -129,10 +129,12 @@ The above would set the general level to `warn`, and the `block-producer` and `r ## Configuration -The OpenTelemetry trace exporter is enabled by adding the `--enable-otel` flag to the node's start command: +The OpenTelemetry trace exporter is enabled by adding the `--enable-otel` flag to each component's start command: ```sh -miden-node bundled start --enable-otel +miden-node store start --enable-otel <...> +miden-node block-producer start --enable-otel <...> +miden-node rpc start --enable-otel <...> ``` The exporter can be configured using environment variables as specified in the official @@ -153,7 +155,7 @@ This is based off Honeycomb's OpenTelemetry ```sh OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io:443 \ OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key" \ -miden-node bundled start --enable-otel +miden-node store start --enable-otel <...> ``` ### Honeycomb queries, triggers and board examples diff --git a/docs/external/src/operator/usage.md b/docs/external/src/operator/usage.md index ce4b699b14..5eab98c455 100644 --- a/docs/external/src/operator/usage.md +++ b/docs/external/src/operator/usage.md @@ -4,10 +4,10 @@ sidebar_position: 4 # Configuration and Usage -As outlined in the [Architecture](./architecture) chapter, the node consists of several components which can be run -separately or as a single bundled process. At present, the recommended way to operate a node is in bundled mode and is -what this guide will focus on. Operating the components separately is very similar and should be relatively -straight-forward to derive from these instructions. +As outlined in the [Architecture](./architecture) chapter, the node consists of several components which are run +as separate processes. The recommended way to operate a node locally is using `docker compose`, which starts each +component in its own container and automatically bootstraps on first run. Operating the components without Docker +is also straightforward using the individual CLI subcommands. This guide focuses on basic usage. To discover more advanced options we recommend exploring the various help menus which can be accessed by appending `--help` to any of the commands. @@ -15,27 +15,19 @@ which can be accessed by appending `--help` to any of the commands. ## Bootstrapping The first step in starting a new Miden network is to initialize the genesis block data. This is a -one-off operation using the `bootstrap` command and by default the genesis block will contain a single -faucet account. +two-step process: first the validator signs and creates the genesis block, then the store initializes +its database from that block. By default the genesis block will contain a single faucet account. ```sh -# Create a folder to store the node's data. -mkdir data - -# Bootstrap the node. -# -# This creates the node's database and initializes it with the genesis data. -# -# The genesis block currently contains a single public faucet account. The -# secret for this account is stored in the `` -# file. This file is not used by the node and should instead by used wherever -# you intend to operate this faucet account. -# -# For example, you could operate a public faucet using our faucet reference -# implementation whose operation is described in a later section. -miden-node bundled bootstrap \ - --data-directory data \ - --accounts-directory . +# Step 1: Validator bootstrap — create the signed genesis block and account files. +miden-node validator bootstrap \ + --genesis-block-directory genesis-data \ + --accounts-directory accounts + +# Step 2: Store bootstrap — initialize the store database from the genesis block. +miden-node store bootstrap \ + --data-directory store-data \ + --genesis-block genesis-data/genesis.dat ``` You can also configure the account and asset data in the genesis block by passing in a toml configuration file. @@ -44,9 +36,9 @@ transactions to achieve the desired state. Any account secrets will be written t the provided `--accounts-directory` path in the process. ```sh -miden-node bundled bootstrap \ - --data-directory data \ - --accounts-directory . \ +miden-node validator bootstrap \ + --genesis-block-directory genesis-data \ + --accounts-directory accounts \ --genesis-config-file genesis.toml ``` @@ -110,18 +102,74 @@ path = "eth_faucet.mac" ## Operation -Start the node with the desired public gRPC server address. +### Using docker compose + +Build the Docker image and start the node. Bootstrap happens automatically on first run: + +```sh +make docker-build-node +make compose-genesis +make compose-up +``` + +Follow logs: + +```sh +make compose-logs +``` + +Stop the node: ```sh -miden-node bundled start \ - --data-directory data \ - --rpc.url http://0.0.0.0:57291 +make compose-down +``` + +Teardown and regenesis: + +```sh +make compose-genesis +``` + +### Running components individually + +Each component can also be started as a standalone process. For example: + +```sh +# Start the store +miden-node store start \ + --rpc.url http://0.0.0.0:50001 \ + --ntx-builder.url http://0.0.0.0:50002 \ + --block-producer.url http://0.0.0.0:50003 \ + --data-directory store-data + +# Start the validator +miden-node validator start http://0.0.0.0:50101 \ + --data-directory validator-data + +# Start the block producer +miden-node block-producer start http://0.0.0.0:50201 \ + --store.url http://127.0.0.1:50003 \ + --validator.url http://127.0.0.1:50101 + +# Start the RPC server +miden-node rpc start \ + --url http://0.0.0.0:57291 \ + --store.url http://127.0.0.1:50001 \ + --block-producer.url http://127.0.0.1:50201 \ + --validator.url http://127.0.0.1:50101 + +# Start the network transaction builder +miden-node ntx-builder start \ + --store.url http://127.0.0.1:50002 \ + --block-producer.url http://127.0.0.1:50201 \ + --validator.url http://127.0.0.1:50101 \ + --data-directory ntx-builder-data ``` ### gRPC server limits and timeouts The RPC component enforces per-request timeouts, per-IP rate limits, and global concurrency caps. Configure these -settings for bundled or standalone RPC with the following options: +settings with the following options: - `--grpc.timeout` (default `10s`): Maximum request duration before the server drops the request. - `--grpc.max_connection_age` (default `30m`): Maximum lifetime of a connection before the server closes it. @@ -129,19 +177,10 @@ settings for bundled or standalone RPC with the following options: - `--grpc.replenish_per_sec` (default `16`): Per-IP request credits replenished per second. - `--grpc.max_global_connections` (default `1000`): Maximum concurrent gRPC connections across all clients. -## Systemd - -Our [Debian packages](./installation.md#debian-package) install a systemd service which operates the node in `bundled` -mode. You'll still need to run the [bootstrapping](#bootstrapping) process before the node can be started. - -You can inspect the service file with `systemctl cat miden-node` or alternatively you can see it in -our repository in the `packaging` folder. For the bootstrapping process be sure to specify the data-directory as -expected by the systemd file. - ## Environment variables Most configuration options can also be configured using environment variables as an alternative to providing the values -via the command-line. This is useful for certain deployment options like `docker` or `systemd`, where they can be easier +via the command-line. This is useful for certain deployment options like `docker`, where they can be easier to define or inject instead of changing the underlying command line options. These are especially convenient where multiple different configuration profiles are used. Write the environment From 7a7e59435df3ab67ed8476b16205ff70cb0b68bd Mon Sep 17 00:00:00 2001 From: sergerad Date: Thu, 12 Mar 2026 19:53:24 +1300 Subject: [PATCH 2/4] fix otel flag in readme --- docs/external/src/operator/monitoring.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/external/src/operator/monitoring.md b/docs/external/src/operator/monitoring.md index 623e215bd4..fe28c54ffd 100644 --- a/docs/external/src/operator/monitoring.md +++ b/docs/external/src/operator/monitoring.md @@ -132,9 +132,9 @@ The above would set the general level to `warn`, and the `block-producer` and `r The OpenTelemetry trace exporter is enabled by adding the `--enable-otel` flag to each component's start command: ```sh -miden-node store start --enable-otel <...> -miden-node block-producer start --enable-otel <...> -miden-node rpc start --enable-otel <...> +miden-node store start --enable-otel +miden-node block-producer start --enable-otel +miden-node rpc start --enable-otel ``` The exporter can be configured using environment variables as specified in the official @@ -155,7 +155,7 @@ This is based off Honeycomb's OpenTelemetry ```sh OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io:443 \ OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key" \ -miden-node store start --enable-otel <...> +miden-node store start --enable-otel ``` ### Honeycomb queries, triggers and board examples From cf2574d248319c28e233fac5466198513cee4d01 Mon Sep 17 00:00:00 2001 From: sergerad Date: Fri, 13 Mar 2026 13:18:03 +1300 Subject: [PATCH 3/4] reintegrate ntx command updates from next --- bin/node/src/commands/mod.rs | 1 + bin/node/src/commands/ntx_builder.rs | 17 ++++++++++++++++- docs/external/src/operator/usage.md | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/bin/node/src/commands/mod.rs b/bin/node/src/commands/mod.rs index daabf1193f..0112c88905 100644 --- a/bin/node/src/commands/mod.rs +++ b/bin/node/src/commands/mod.rs @@ -45,6 +45,7 @@ const ENV_VALIDATOR_KMS_KEY_ID: &str = "MIDEN_NODE_VALIDATOR_KMS_KEY_ID"; const ENV_NTX_DATA_DIRECTORY: &str = "MIDEN_NODE_NTX_DATA_DIRECTORY"; const DEFAULT_NTX_TICKER_INTERVAL: Duration = Duration::from_millis(200); +const DEFAULT_NTX_IDLE_TIMEOUT: Duration = Duration::from_secs(5 * 60); const DEFAULT_NTX_SCRIPT_CACHE_SIZE: NonZeroUsize = NonZeroUsize::new(1000).unwrap(); /// Configuration for the Validator key used to sign blocks. diff --git a/bin/node/src/commands/ntx_builder.rs b/bin/node/src/commands/ntx_builder.rs index 650b15d03a..7f295e56aa 100644 --- a/bin/node/src/commands/ntx_builder.rs +++ b/bin/node/src/commands/ntx_builder.rs @@ -7,6 +7,7 @@ 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, @@ -59,6 +60,18 @@ pub enum NtxBuilderCommand { )] 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, + /// Directory for the ntx-builder's persistent database. #[arg(long = "data-directory", env = ENV_NTX_DATA_DIRECTORY, value_name = "DIR")] data_directory: PathBuf, @@ -81,6 +94,7 @@ impl NtxBuilderCommand { tx_prover_url, ticker_interval: _, script_cache_size, + idle_timeout, data_directory, enable_otel: _, } = self; @@ -94,7 +108,8 @@ impl NtxBuilderCommand { database_filepath, ) .with_tx_prover_url(tx_prover_url) - .with_script_cache_size(script_cache_size); + .with_script_cache_size(script_cache_size) + .with_idle_timeout(idle_timeout); config .build() diff --git a/docs/external/src/operator/usage.md b/docs/external/src/operator/usage.md index 0d08ec8d28..a4c4e68095 100644 --- a/docs/external/src/operator/usage.md +++ b/docs/external/src/operator/usage.md @@ -201,7 +201,7 @@ are exposed as CLI flags (also available as environment variables): Compaction parallelism is set automatically to the number of available CPU cores. ```sh -miden-node start \ +miden-node store start \ --data-directory data \ --rpc.url http://0.0.0.0:57291 \ --account_tree.rocksdb.max_cache_size 4294967296 \ From 6eb958853b1b32d02c33e6cf00293957045a1cc1 Mon Sep 17 00:00:00 2001 From: sergerad Date: Fri, 13 Mar 2026 13:58:45 +1300 Subject: [PATCH 4/4] fix flags --- crates/utils/src/clap/rocksdb.rs | 4 ++++ docker-compose.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/crates/utils/src/clap/rocksdb.rs b/crates/utils/src/clap/rocksdb.rs index 9b752205d2..ad02742a18 100644 --- a/crates/utils/src/clap/rocksdb.rs +++ b/crates/utils/src/clap/rocksdb.rs @@ -12,12 +12,14 @@ pub(crate) const BENCH_ROCKSDB_MAX_OPEN_FDS: i32 = 512; #[derive(clap::Args, Clone, Debug, PartialEq, Eq)] pub struct NullifierTreeRocksDbOptions { #[arg( + id = "nullifier_tree.rocksdb.max_open_fds", long = "nullifier_tree.rocksdb.max_open_fds", default_value_t = DEFAULT_ROCKSDB_MAX_OPEN_FDS, value_name = "NULLIFIER_TREE__ROCKSDB__MAX_OPEN_FDS" )] pub max_open_fds: i32, #[arg( + id = "nullifier_tree.rocksdb.max_cache_size", long = "nullifier_tree.rocksdb.max_cache_size", default_value_t = DEFAULT_ROCKSDB_CACHE_SIZE, value_name = "NULLIFIER_TREE__ROCKSDB__CACHE_SIZE" @@ -35,12 +37,14 @@ impl Default for NullifierTreeRocksDbOptions { #[derive(clap::Args, Clone, Debug, PartialEq, Eq)] pub struct AccountTreeRocksDbOptions { #[arg( + id = "account_tree.rocksdb.max_open_fds", long = "account_tree.rocksdb.max_open_fds", default_value_t = DEFAULT_ROCKSDB_MAX_OPEN_FDS, value_name = "ACCOUNT_TREE__ROCKSDB__MAX_OPEN_FDS" )] pub max_open_fds: i32, #[arg( + id = "account_tree.rocksdb.max_cache_size", long = "account_tree.rocksdb.max_cache_size", default_value_t = DEFAULT_ROCKSDB_CACHE_SIZE, value_name = "ACCOUNT_TREE__ROCKSDB__CACHE_SIZE" diff --git a/docker-compose.yml b/docker-compose.yml index 767fbb7829..4ce7aa5204 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,10 @@ services: - --ntx-builder.url=http://0.0.0.0:50002 - --block-producer.url=http://0.0.0.0:50003 - --data-directory=/data + - --account_tree.rocksdb.max_cache_size=4294967296 + - --account_tree.rocksdb.max_open_fds=512 + - --nullifier_tree.rocksdb.max_cache_size=4294967296 + - --nullifier_tree.rocksdb.max_open_fds=512 ports: - "50001:50001" - "50002:50002"