From c5586f71c0460e098cc5e1ba00dd98ea15b9444b Mon Sep 17 00:00:00 2001 From: sergerad Date: Wed, 6 May 2026 15:00:58 +1200 Subject: [PATCH 01/10] Move bind URLs to ports --- bin/node/.env | 14 ++-- bin/node/src/commands/block_producer.rs | 18 ++--- bin/node/src/commands/ntx_builder.rs | 20 ++--- bin/node/src/commands/rpc.rs | 19 +++-- bin/node/src/commands/store.rs | 98 ++++++++++++------------- bin/node/src/commands/validator.rs | 16 ++-- 6 files changed, 85 insertions(+), 100 deletions(-) diff --git a/bin/node/.env b/bin/node/.env index dbb635521..628969f0e 100644 --- a/bin/node/.env +++ b/bin/node/.env @@ -6,7 +6,7 @@ MIDEN_NODE_ENABLE_OTEL=true MIDEN_NODE_DATA_DIRECTORY= # Block Producer -MIDEN_NODE_BLOCK_PRODUCER_URL= +MIDEN_NODE_BLOCK_PRODUCER_PORT= MIDEN_NODE_BLOCK_PRODUCER_STORE_URL= MIDEN_NODE_BLOCK_PRODUCER_VALIDATOR_URL= MIDEN_NODE_BLOCK_PRODUCER_MAX_TXS_PER_BATCH= @@ -15,27 +15,27 @@ MIDEN_NODE_BLOCK_PRODUCER_MEMPOOL_TX_CAPACITY= MIDEN_NODE_BLOCK_PRODUCER_BATCH_PROVER_URL= # Store -MIDEN_NODE_STORE_RPC_URL= +MIDEN_NODE_STORE_RPC_PORT= MIDEN_NODE_STORE_UPSTREAM_RPC_URL= -MIDEN_NODE_STORE_NTX_BUILDER_URL= -MIDEN_NODE_STORE_BLOCK_PRODUCER_URL= +MIDEN_NODE_STORE_NTX_BUILDER_PORT= +MIDEN_NODE_STORE_BLOCK_PRODUCER_PORT= MIDEN_NODE_STORE_BLOCK_PROVER_URL= # RPC -MIDEN_NODE_RPC_URL=http://0.0.0.0:57291 +MIDEN_NODE_RPC_PORT=57291 MIDEN_NODE_RPC_STORE_URL= MIDEN_NODE_RPC_BLOCK_PRODUCER_URL= MIDEN_NODE_RPC_VALIDATOR_URL= MIDEN_NODE_RPC_NTX_BUILDER_URL= # Validator -MIDEN_NODE_VALIDATOR_URL= +MIDEN_NODE_VALIDATOR_PORT= MIDEN_NODE_VALIDATOR_GENESIS_CONFIG_FILE= MIDEN_NODE_VALIDATOR_KEY= MIDEN_NODE_VALIDATOR_KMS_KEY_ID= # NTX Builder -MIDEN_NODE_NTX_BUILDER_URL= +MIDEN_NODE_NTX_BUILDER_PORT= MIDEN_NODE_NTX_BUILDER_STORE_URL= MIDEN_NODE_NTX_BUILDER_BLOCK_PRODUCER_URL= MIDEN_NODE_NTX_BUILDER_VALIDATOR_URL= diff --git a/bin/node/src/commands/block_producer.rs b/bin/node/src/commands/block_producer.rs index 7ca830e87..75c2f244a 100644 --- a/bin/node/src/commands/block_producer.rs +++ b/bin/node/src/commands/block_producer.rs @@ -10,12 +10,11 @@ use miden_node_block_producer::{ DEFAULT_MAX_TXS_PER_BATCH, }; use miden_node_utils::clap::{GrpcOptionsInternal, duration_to_human_readable_string}; -use miden_node_utils::grpc::UrlExt; use url::Url; use super::ENV_ENABLE_OTEL; -const ENV_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_URL"; +const ENV_PORT: &str = "MIDEN_NODE_BLOCK_PRODUCER_PORT"; const ENV_STORE_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_STORE_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_VALIDATOR_URL"; const ENV_MAX_TXS_PER_BATCH: &str = "MIDEN_NODE_BLOCK_PRODUCER_MAX_TXS_PER_BATCH"; @@ -30,9 +29,9 @@ const ENV_BATCH_PROVER_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_BATCH_PROVER_URL"; pub enum BlockProducerCommand { /// Starts the block-producer component. Start { - /// Url at which to serve the gRPC API. - #[arg(env = ENV_URL)] - url: Url, + /// Port at which to serve the gRPC API. + #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] + port: u16, /// The store's block-producer service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL)] @@ -60,7 +59,7 @@ pub enum BlockProducerCommand { impl BlockProducerCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - url, + port, store_url, validator_url, block_producer, @@ -68,8 +67,7 @@ impl BlockProducerCommand { grpc_options, } = self; - let block_producer_address = - url.to_socket().context("Failed to extract socket address from store URL")?; + let block_producer_address = std::net::SocketAddr::from(([0, 0, 0, 0], port)); // Runtime validation for protocol constraints if block_producer.max_batches_per_block > miden_protocol::MAX_BATCHES_PER_BLOCK { @@ -123,7 +121,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_batches_per_block() { let cmd = BlockProducerCommand::Start { - url: dummy_url(), + port: 1234, store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { @@ -146,7 +144,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_txs_per_batch() { let cmd = BlockProducerCommand::Start { - url: dummy_url(), + port: 1234, store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { diff --git a/bin/node/src/commands/ntx_builder.rs b/bin/node/src/commands/ntx_builder.rs index f88931347..13b6c8deb 100644 --- a/bin/node/src/commands/ntx_builder.rs +++ b/bin/node/src/commands/ntx_builder.rs @@ -4,14 +4,13 @@ use std::time::Duration; use anyhow::Context; use miden_node_utils::clap::duration_to_human_readable_string; -use miden_node_utils::grpc::UrlExt; use tokio::net::TcpListener; use url::Url; use super::ENV_ENABLE_OTEL; use crate::commands::ENV_DATA_DIRECTORY; -const ENV_URL: &str = "MIDEN_NODE_NTX_BUILDER_URL"; +const ENV_PORT: &str = "MIDEN_NODE_NTX_BUILDER_PORT"; const ENV_STORE_URL: &str = "MIDEN_NODE_NTX_BUILDER_STORE_URL"; const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_NTX_BUILDER_BLOCK_PRODUCER_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_NTX_BUILDER_VALIDATOR_URL"; @@ -27,9 +26,9 @@ const DEFAULT_MAX_CYCLES: u32 = 1 << 18; pub enum NtxBuilderCommand { /// Starts the network transaction builder component. Start { - /// Url at which to serve the ntx-builder's gRPC API. - #[arg(long = "url", env = ENV_URL, value_name = "URL")] - url: Option, + /// Port at which to serve the ntx-builder's gRPC API. + #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] + port: Option, /// The store's ntx-builder service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -105,7 +104,7 @@ pub enum NtxBuilderCommand { impl NtxBuilderCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - url, + port, store_url, block_producer_url, validator_url, @@ -118,14 +117,11 @@ impl NtxBuilderCommand { enable_otel: _, } = self; - let listener = if let Some(url) = url { - let addr = url - .to_socket() - .context("Failed to extract socket address from ntx-builder URL")?; + let listener = if let Some(port) = port { Some( - TcpListener::bind(addr) + TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], port))) .await - .context("Failed to bind to ntx-builder's gRPC URL")?, + .context("Failed to bind to ntx-builder's gRPC port")?, ) } else { None diff --git a/bin/node/src/commands/rpc.rs b/bin/node/src/commands/rpc.rs index b9c6ea7e5..f29d3a0d8 100644 --- a/bin/node/src/commands/rpc.rs +++ b/bin/node/src/commands/rpc.rs @@ -1,12 +1,11 @@ use anyhow::Context; use miden_node_rpc::Rpc; use miden_node_utils::clap::GrpcOptionsExternal; -use miden_node_utils::grpc::UrlExt; use url::Url; use super::ENV_ENABLE_OTEL; -const ENV_URL: &str = "MIDEN_NODE_RPC_URL"; +const ENV_PORT: &str = "MIDEN_NODE_RPC_PORT"; const ENV_STORE_URL: &str = "MIDEN_NODE_RPC_STORE_URL"; const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_RPC_BLOCK_PRODUCER_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_RPC_VALIDATOR_URL"; @@ -16,9 +15,9 @@ const ENV_NTX_BUILDER_URL: &str = "MIDEN_NODE_RPC_NTX_BUILDER_URL"; pub enum RpcCommand { /// Starts the RPC component. Start { - /// Url at which to serve the gRPC API. - #[arg(long = "url", env = ENV_URL, value_name = "URL")] - url: Url, + /// Port at which to serve the gRPC API. + #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] + port: u16, /// The store's RPC service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -52,7 +51,7 @@ pub enum RpcCommand { impl RpcCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - url, + port, store_url, block_producer_url, validator_url, @@ -61,10 +60,10 @@ impl RpcCommand { grpc_options, } = self; - let listener = url.to_socket().context("Failed to extract socket address from RPC URL")?; - let listener = tokio::net::TcpListener::bind(listener) - .await - .context("Failed to bind to RPC's gRPC URL")?; + let listener = + tokio::net::TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], port))) + .await + .context("Failed to bind to RPC's gRPC port")?; Rpc { listener, diff --git a/bin/node/src/commands/store.rs b/bin/node/src/commands/store.rs index 53ce60054..432d7d6d8 100644 --- a/bin/node/src/commands/store.rs +++ b/bin/node/src/commands/store.rs @@ -6,7 +6,6 @@ use miden_node_store::genesis::GenesisBlock; use miden_node_store::{DEFAULT_MAX_CONCURRENT_PROOFS, Store, StoreMode}; use miden_node_utils::clap::{GrpcOptionsInternal, StorageOptions}; use miden_node_utils::fs::ensure_empty_directory; -use miden_node_utils::grpc::UrlExt; use miden_protocol::block::SignedBlock; use miden_protocol::utils::serde::Deserializable; use url::Url; @@ -14,10 +13,10 @@ use url::Url; use super::ENV_ENABLE_OTEL; use crate::commands::ENV_DATA_DIRECTORY; -const ENV_URL: &str = "MIDEN_NODE_STORE_RPC_URL"; +const ENV_RPC_PORT: &str = "MIDEN_NODE_STORE_RPC_PORT"; const ENV_UPSTREAM_URL: &str = "MIDEN_NODE_STORE_UPSTREAM_RPC_URL"; -const ENV_NTX_BUILDER_URL: &str = "MIDEN_NODE_STORE_NTX_BUILDER_URL"; -const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_STORE_BLOCK_PRODUCER_URL"; +const ENV_NTX_BUILDER_PORT: &str = "MIDEN_NODE_STORE_NTX_BUILDER_PORT"; +const ENV_BLOCK_PRODUCER_PORT: &str = "MIDEN_NODE_STORE_BLOCK_PRODUCER_PORT"; const ENV_BLOCK_PROVER_URL: &str = "MIDEN_NODE_STORE_BLOCK_PROVER_URL"; #[derive(clap::Subcommand)] @@ -39,17 +38,17 @@ pub enum StoreCommand { /// In this mode the store accepts blocks from a block producer via a dedicated gRPC endpoint /// and runs the proof scheduler to generate block proofs. Start { - /// Url at which to serve the store's RPC API. - #[arg(long = "rpc.url", env = ENV_URL, value_name = "URL")] - rpc_url: Url, + /// Port at which to serve the store's RPC API. + #[arg(long = "rpc.port", env = ENV_RPC_PORT, value_name = "PORT")] + rpc_port: u16, - /// Url at which to serve the store's network transaction builder API. - #[arg(long = "ntx-builder.url", env = ENV_NTX_BUILDER_URL, value_name = "URL")] - ntx_builder_url: Url, + /// Port at which to serve the store's network transaction builder API. + #[arg(long = "ntx-builder.port", env = ENV_NTX_BUILDER_PORT, value_name = "PORT")] + ntx_builder_port: u16, - /// Url at which to serve the store's block producer API. - #[arg(long = "block-producer.url", env = ENV_BLOCK_PRODUCER_URL, value_name = "URL")] - block_producer_url: Url, + /// Port at which to serve the store's block producer API. + #[arg(long = "block-producer.port", env = ENV_BLOCK_PRODUCER_PORT, value_name = "PORT")] + block_producer_port: u16, /// The remote block prover's gRPC url. If not provided, a local block prover will be used. #[arg(long = "block-prover.url", env = ENV_BLOCK_PROVER_URL, value_name = "URL")] @@ -87,9 +86,9 @@ pub enum StoreCommand { /// Only the `Rpc` and `StoreReplica` gRPC services are exposed — the `BlockProducer` and /// `NtxBuilder` services are not started and no proof scheduler runs. StartReplica { - /// Url at which to serve the store's RPC API. - #[arg(long = "rpc.url", env = ENV_URL, value_name = "URL")] - url: Url, + /// Port at which to serve the store's RPC API. + #[arg(long = "rpc.port", env = ENV_RPC_PORT, value_name = "PORT")] + rpc_port: u16, /// gRPC URL of the upstream store's `StoreReplica` endpoint to sync blocks from. #[arg(long = "upstream-store.url", env = ENV_UPSTREAM_URL, value_name = "URL")] @@ -120,9 +119,9 @@ impl StoreCommand { bootstrap_store(&data_directory, &genesis_block) }, StoreCommand::Start { - rpc_url, - ntx_builder_url, - block_producer_url, + rpc_port, + ntx_builder_port, + block_producer_port, block_prover_url, data_directory, enable_otel: _, @@ -131,9 +130,9 @@ impl StoreCommand { storage_options, } => { Self::start( - rpc_url, - ntx_builder_url, - block_producer_url, + rpc_port, + ntx_builder_port, + block_producer_port, block_prover_url, data_directory, grpc_options, @@ -143,7 +142,7 @@ impl StoreCommand { .await }, StoreCommand::StartReplica { - url: rpc_url, + rpc_port, upstream_store_url, data_directory, enable_otel: _, @@ -151,7 +150,7 @@ impl StoreCommand { storage_options, } => { Self::start_replica( - rpc_url, + rpc_port, upstream_store_url, data_directory, grpc_options, @@ -173,35 +172,34 @@ impl StoreCommand { #[expect(clippy::too_many_arguments)] async fn start( - rpc_url: Url, - ntx_builder_url: Url, - block_producer_url: Url, + rpc_port: u16, + ntx_builder_port: u16, + block_producer_port: u16, block_prover_url: Option, data_directory: PathBuf, grpc_options: GrpcOptionsInternal, max_concurrent_proofs: NonZeroUsize, storage_options: StorageOptions, ) -> anyhow::Result<()> { - let rpc_listener = rpc_url - .to_socket() - .context("Failed to extract socket address from store RPC URL")?; - let rpc_listener = tokio::net::TcpListener::bind(rpc_listener) - .await - .context("Failed to bind to store's RPC gRPC URL")?; + let rpc_listener = + tokio::net::TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], rpc_port))) + .await + .context("Failed to bind to store's RPC gRPC port")?; - let ntx_builder_addr = ntx_builder_url - .to_socket() - .context("Failed to extract socket address from store ntx-builder URL")?; - let ntx_builder_listener = tokio::net::TcpListener::bind(ntx_builder_addr) - .await - .context("Failed to bind to store's ntx-builder gRPC URL")?; + let ntx_builder_listener = tokio::net::TcpListener::bind(std::net::SocketAddr::from(( + [0, 0, 0, 0], + ntx_builder_port, + ))) + .await + .context("Failed to bind to store's ntx-builder gRPC port")?; - let block_producer_addr = block_producer_url - .to_socket() - .context("Failed to extract socket address from store block-producer URL")?; - let block_producer_listener = tokio::net::TcpListener::bind(block_producer_addr) + let block_producer_listener = + tokio::net::TcpListener::bind(std::net::SocketAddr::from(( + [0, 0, 0, 0], + block_producer_port, + ))) .await - .context("Failed to bind to store's block-producer gRPC URL")?; + .context("Failed to bind to store's block-producer gRPC port")?; Store { rpc_listener, @@ -221,18 +219,16 @@ impl StoreCommand { } async fn start_replica( - rpc_url: Url, + rpc_port: u16, upstream_store_url: Url, data_directory: PathBuf, grpc_options: GrpcOptionsInternal, storage_options: StorageOptions, ) -> anyhow::Result<()> { - let rpc_listener = rpc_url - .to_socket() - .context("Failed to extract socket address from store RPC URL")?; - let rpc_listener = tokio::net::TcpListener::bind(rpc_listener) - .await - .context("Failed to bind to store's RPC gRPC URL")?; + let rpc_listener = + tokio::net::TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], rpc_port))) + .await + .context("Failed to bind to store's RPC gRPC port")?; Store { rpc_listener, diff --git a/bin/node/src/commands/validator.rs b/bin/node/src/commands/validator.rs index 807f5fa12..a478284c1 100644 --- a/bin/node/src/commands/validator.rs +++ b/bin/node/src/commands/validator.rs @@ -5,16 +5,14 @@ use anyhow::Context; use miden_node_store::genesis::config::{AccountFileWithName, GenesisConfig}; use miden_node_utils::clap::GrpcOptionsInternal; use miden_node_utils::fs::ensure_empty_directory; -use miden_node_utils::grpc::UrlExt; use miden_node_utils::signer::BlockSigner; use miden_node_validator::{Validator, ValidatorSigner}; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SecretKey; use miden_protocol::utils::serde::{Deserializable, Serializable}; -use url::Url; use crate::commands::{ENV_DATA_DIRECTORY, ENV_ENABLE_OTEL}; -const ENV_URL: &str = "MIDEN_NODE_VALIDATOR_URL"; +const ENV_PORT: &str = "MIDEN_NODE_VALIDATOR_PORT"; const ENV_GENESIS_CONFIG_FILE: &str = "MIDEN_NODE_VALIDATOR_GENESIS_CONFIG_FILE"; const ENV_KEY: &str = "MIDEN_NODE_VALIDATOR_KEY"; const ENV_KMS_KEY_ID: &str = "MIDEN_NODE_VALIDATOR_KMS_KEY_ID"; @@ -54,9 +52,9 @@ pub enum ValidatorCommand { /// Starts the validator component. Start { - /// Url at which to serve the gRPC API. - #[arg(env = ENV_URL)] - url: Url, + /// Port at which to serve the gRPC API. + #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] + port: u16, /// Enables the exporting of traces for OpenTelemetry. /// @@ -120,16 +118,14 @@ impl ValidatorCommand { .await }, Self::Start { - url, + port, grpc_options, validator_key, data_directory, kms_key_id, .. } => { - let address = url - .to_socket() - .context("failed to extract socket address from validator URL")?; + let address = SocketAddr::from(([0, 0, 0, 0], port)); // Run validator with KMS key backend if key id provided. if let Some(kms_key_id) = kms_key_id { From d00f9c5047cada522e49a81f375236cd8903c18c Mon Sep 17 00:00:00 2001 From: sergerad Date: Wed, 6 May 2026 15:05:07 +1200 Subject: [PATCH 02/10] Lint and changelog --- CHANGELOG.md | 1 + bin/node/src/commands/store.rs | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f75985f5..20a4d6282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Added a `replica` mode to the store, which streams blocks from an upstream master store ([#1987](https://github.com/0xMiden/node/pull/1987)). - Added `StoreReplica` gRPC service with endpoints for streaming blocks and proofs ([#1987](https://github.com/0xMiden/node/pull/1987)). - Replaced the network monitor's JavaScript dashboard with a server-rendered Maud + HTMX frontend ([#2024](https://github.com/0xMiden/node/pull/2024)). +- [BREAKING] Replaced binding URL env vars and CLI flags with binding ports ([#2054](https://github.com/0xMiden/node/pull/2054)). ## v0.14.10 (2026-05-29) diff --git a/bin/node/src/commands/store.rs b/bin/node/src/commands/store.rs index 432d7d6d8..28e401c0e 100644 --- a/bin/node/src/commands/store.rs +++ b/bin/node/src/commands/store.rs @@ -193,13 +193,12 @@ impl StoreCommand { .await .context("Failed to bind to store's ntx-builder gRPC port")?; - let block_producer_listener = - tokio::net::TcpListener::bind(std::net::SocketAddr::from(( - [0, 0, 0, 0], - block_producer_port, - ))) - .await - .context("Failed to bind to store's block-producer gRPC port")?; + let block_producer_listener = tokio::net::TcpListener::bind(std::net::SocketAddr::from(( + [0, 0, 0, 0], + block_producer_port, + ))) + .await + .context("Failed to bind to store's block-producer gRPC port")?; Store { rpc_listener, From 6d5ce36db0cf79ab361dbb625a63fbcbd4150d6c Mon Sep 17 00:00:00 2001 From: sergerad Date: Wed, 6 May 2026 15:33:21 +1200 Subject: [PATCH 03/10] Update compose usage.md and run-node.sh --- docker-compose.yml | 12 ++--- docs/external/src/operator/usage.md | 14 ++--- scripts/run-node.sh | 80 ++++++++++++++--------------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index cd5594507..01c734398 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,9 +34,9 @@ services: - 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 + - --rpc.port=50001 + - --ntx-builder.port=50002 + - --block-producer.port=50003 - --data-directory=/data/store - --account_tree.rocksdb.max_cache_size=4294967296 - --account_tree.rocksdb.max_open_fds=512 @@ -60,7 +60,7 @@ services: - miden-node - validator - start - - http://0.0.0.0:50101 + - --port=50101 - --data-directory=/data/validator ports: - "50101:50101" @@ -76,7 +76,7 @@ services: - miden-node - block-producer - start - - http://0.0.0.0:50201 + - --port=50201 - --store.url=http://store:50003 - --validator.url=http://validator:50101 ports: @@ -93,7 +93,7 @@ services: - miden-node - rpc - start - - --url=http://0.0.0.0:57291 + - --port=57291 - --store.url=http://store:50001 - --block-producer.url=http://block-producer:50201 - --validator.url=http://validator:50101 diff --git a/docs/external/src/operator/usage.md b/docs/external/src/operator/usage.md index 62d05b31a..5955495b9 100644 --- a/docs/external/src/operator/usage.md +++ b/docs/external/src/operator/usage.md @@ -160,23 +160,23 @@ 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 \ + --rpc.port 50001 \ + --ntx-builder.port 50002 \ + --block-producer.port 50003 \ --data-directory /tmp/store # Start the validator -miden-node validator start http://0.0.0.0:50101 \ +miden-node validator start --port 50101 \ --data-directory /tmp/validator # Start the block producer -miden-node block-producer start http://0.0.0.0:50201 \ +miden-node block-producer start --port 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 \ + --port 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 @@ -226,7 +226,7 @@ Compaction parallelism is set automatically to the number of available CPU cores ```sh miden-node store start \ --data-directory data \ - --rpc.url http://0.0.0.0:57291 \ + --rpc.port 57291 \ --account_tree.rocksdb.max_cache_size 4294967296 \ --account_tree.rocksdb.max_open_fds 512 \ --nullifier_tree.rocksdb.max_cache_size 4294967296 \ diff --git a/scripts/run-node.sh b/scripts/run-node.sh index a9621917a..aabc280b6 100755 --- a/scripts/run-node.sh +++ b/scripts/run-node.sh @@ -19,19 +19,19 @@ NTX_BUILDER_DIR="/tmp/ntx-builder" ACCOUNTS_DIR="/tmp/accounts" # Primary store (block-producer mode): 3 APIs. -STORE_RPC_URL="http://0.0.0.0:50001" -STORE_NTX_BUILDER_URL="http://0.0.0.0:50002" -STORE_BLOCK_PRODUCER_URL="http://0.0.0.0:50003" +STORE_RPC_PORT=50001 +STORE_NTX_BUILDER_PORT=50002 +STORE_BLOCK_PRODUCER_PORT=50003 # Replica stores expose only the RPC API (no block-producer or ntx-builder endpoints). -STORE_REPLICA_1_RPC_URL="http://0.0.0.0:50011" -STORE_REPLICA_2_RPC_URL="http://0.0.0.0:50021" +STORE_REPLICA_1_RPC_PORT=50011 +STORE_REPLICA_2_RPC_PORT=50021 -VALIDATOR_URL="http://0.0.0.0:50101" -BLOCK_PRODUCER_URL="http://0.0.0.0:50201" -RPC_URL="http://0.0.0.0:57291" -RPC_REPLICA_1_URL="http://0.0.0.0:57292" -RPC_REPLICA_2_URL="http://0.0.0.0:57293" +VALIDATOR_PORT=50101 +BLOCK_PRODUCER_PORT=50201 +RPC_PORT=57291 +RPC_REPLICA_1_PORT=57292 +RPC_REPLICA_2_PORT=57293 PIDS=() @@ -106,9 +106,9 @@ echo "=== Starting components ===" echo "Starting store (block-producer mode)..." $BINARY store start \ - --rpc.url "$STORE_RPC_URL" \ - --ntx-builder.url "$STORE_NTX_BUILDER_URL" \ - --block-producer.url "$STORE_BLOCK_PRODUCER_URL" \ + --rpc.port "$STORE_RPC_PORT" \ + --ntx-builder.port "$STORE_NTX_BUILDER_PORT" \ + --block-producer.port "$STORE_BLOCK_PRODUCER_PORT" \ --data-directory "$STORE_DIR" & PIDS+=($!) @@ -118,7 +118,7 @@ if [[ -n "$KMS_KEY_ID" ]]; then fi echo "Starting validator..." -$BINARY validator start "$VALIDATOR_URL" \ +$BINARY validator start --port "$VALIDATOR_PORT" \ --data-directory "$VALIDATOR_DIR" \ "${KMS_START_ARGS[@]+"${KMS_START_ARGS[@]}"}" & PIDS+=($!) @@ -127,60 +127,60 @@ PIDS+=($!) sleep 2 # Replica 1 syncs from the primary store. -echo "Starting store replica 1 (upstream: primary store at $STORE_RPC_URL)..." +echo "Starting store replica 1 (upstream: primary store at 127.0.0.1:$STORE_RPC_PORT)..." $BINARY store start-replica \ - --rpc.url "$STORE_REPLICA_1_RPC_URL" \ - --upstream-store.url "$STORE_RPC_URL" \ + --rpc.port "$STORE_REPLICA_1_RPC_PORT" \ + --upstream-store.url "http://127.0.0.1:$STORE_RPC_PORT" \ --data-directory "$STORE_REPLICA_1_DIR" & PIDS+=($!) # Replica 2 syncs from replica 1, proving replicas can act as upstreams. -echo "Starting store replica 2 (upstream: replica 1 at $STORE_REPLICA_1_RPC_URL)..." +echo "Starting store replica 2 (upstream: replica 1 at 127.0.0.1:$STORE_REPLICA_1_RPC_PORT)..." $BINARY store start-replica \ - --rpc.url "$STORE_REPLICA_2_RPC_URL" \ - --upstream-store.url "$STORE_REPLICA_1_RPC_URL" \ + --rpc.port "$STORE_REPLICA_2_RPC_PORT" \ + --upstream-store.url "http://127.0.0.1:$STORE_REPLICA_1_RPC_PORT" \ --data-directory "$STORE_REPLICA_2_DIR" & PIDS+=($!) echo "Starting block producer..." -$BINARY block-producer start "$BLOCK_PRODUCER_URL" \ - --store.url "http://127.0.0.1:50003" \ - --validator.url "http://127.0.0.1:50101" & +$BINARY block-producer start --port "$BLOCK_PRODUCER_PORT" \ + --store.url "http://127.0.0.1:$STORE_BLOCK_PRODUCER_PORT" \ + --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & PIDS+=($!) echo "Starting RPC server (primary store)..." $BINARY rpc start \ - --url "$RPC_URL" \ - --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" & + --port "$RPC_PORT" \ + --store.url "http://127.0.0.1:$STORE_RPC_PORT" \ + --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ + --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & PIDS+=($!) echo "Starting RPC server (replica 1)..." $BINARY rpc start \ - --url "$RPC_REPLICA_1_URL" \ - --store.url "http://127.0.0.1:50011" \ - --block-producer.url "http://127.0.0.1:50201" \ - --validator.url "http://127.0.0.1:50101" & + --port "$RPC_REPLICA_1_PORT" \ + --store.url "http://127.0.0.1:$STORE_REPLICA_1_RPC_PORT" \ + --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ + --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & PIDS+=($!) echo "Starting RPC server (replica 2)..." $BINARY rpc start \ - --url "$RPC_REPLICA_2_URL" \ - --store.url "http://127.0.0.1:50021" \ - --block-producer.url "http://127.0.0.1:50201" \ - --validator.url "http://127.0.0.1:50101" & + --port "$RPC_REPLICA_2_PORT" \ + --store.url "http://127.0.0.1:$STORE_REPLICA_2_RPC_PORT" \ + --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ + --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & PIDS+=($!) echo "Starting network transaction builder..." $BINARY 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" \ + --store.url "http://127.0.0.1:$STORE_NTX_BUILDER_PORT" \ + --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ + --validator.url "http://127.0.0.1:$VALIDATOR_PORT" \ --data-directory "$NTX_BUILDER_DIR" & PIDS+=($!) echo "=== All components running. Ctrl+C to stop. ===" -echo "=== Block propagation chain: $STORE_RPC_URL -> $STORE_REPLICA_1_RPC_URL -> $STORE_REPLICA_2_RPC_URL ===" -echo "=== RPC endpoints: $RPC_URL, $RPC_REPLICA_1_URL, $RPC_REPLICA_2_URL ===" +echo "=== Block propagation chain: :$STORE_RPC_PORT -> :$STORE_REPLICA_1_RPC_PORT -> :$STORE_REPLICA_2_RPC_PORT ===" +echo "=== RPC endpoints: :$RPC_PORT, :$RPC_REPLICA_1_PORT, :$RPC_REPLICA_2_PORT ===" wait From 9ec725ccbb1bab9f506b3feefdbae6dc0be6a360 Mon Sep 17 00:00:00 2001 From: sergerad Date: Thu, 7 May 2026 13:14:49 +1200 Subject: [PATCH 04/10] Move to socket env / args --- bin/node/.env | 14 ++-- bin/node/src/commands/block_producer.rs | 17 ++--- bin/node/src/commands/ntx_builder.rs | 17 ++--- bin/node/src/commands/rpc.rs | 19 +++--- bin/node/src/commands/store.rs | 87 ++++++++++++------------- bin/node/src/commands/validator.rs | 12 ++-- docker-compose.yml | 12 ++-- docs/external/src/operator/usage.md | 14 ++-- scripts/run-node.sh | 20 +++--- 9 files changed, 104 insertions(+), 108 deletions(-) diff --git a/bin/node/.env b/bin/node/.env index 628969f0e..f140e70b5 100644 --- a/bin/node/.env +++ b/bin/node/.env @@ -6,7 +6,7 @@ MIDEN_NODE_ENABLE_OTEL=true MIDEN_NODE_DATA_DIRECTORY= # Block Producer -MIDEN_NODE_BLOCK_PRODUCER_PORT= +MIDEN_NODE_BLOCK_PRODUCER_SOCKET= MIDEN_NODE_BLOCK_PRODUCER_STORE_URL= MIDEN_NODE_BLOCK_PRODUCER_VALIDATOR_URL= MIDEN_NODE_BLOCK_PRODUCER_MAX_TXS_PER_BATCH= @@ -15,27 +15,27 @@ MIDEN_NODE_BLOCK_PRODUCER_MEMPOOL_TX_CAPACITY= MIDEN_NODE_BLOCK_PRODUCER_BATCH_PROVER_URL= # Store -MIDEN_NODE_STORE_RPC_PORT= +MIDEN_NODE_STORE_RPC_SOCKET= MIDEN_NODE_STORE_UPSTREAM_RPC_URL= -MIDEN_NODE_STORE_NTX_BUILDER_PORT= -MIDEN_NODE_STORE_BLOCK_PRODUCER_PORT= +MIDEN_NODE_STORE_NTX_BUILDER_SOCKET= +MIDEN_NODE_STORE_BLOCK_PRODUCER_SOCKET= MIDEN_NODE_STORE_BLOCK_PROVER_URL= # RPC -MIDEN_NODE_RPC_PORT=57291 +MIDEN_NODE_RPC_SOCKET=0.0.0.0:57291 MIDEN_NODE_RPC_STORE_URL= MIDEN_NODE_RPC_BLOCK_PRODUCER_URL= MIDEN_NODE_RPC_VALIDATOR_URL= MIDEN_NODE_RPC_NTX_BUILDER_URL= # Validator -MIDEN_NODE_VALIDATOR_PORT= +MIDEN_NODE_VALIDATOR_SOCKET= MIDEN_NODE_VALIDATOR_GENESIS_CONFIG_FILE= MIDEN_NODE_VALIDATOR_KEY= MIDEN_NODE_VALIDATOR_KMS_KEY_ID= # NTX Builder -MIDEN_NODE_NTX_BUILDER_PORT= +MIDEN_NODE_NTX_BUILDER_SOCKET= MIDEN_NODE_NTX_BUILDER_STORE_URL= MIDEN_NODE_NTX_BUILDER_BLOCK_PRODUCER_URL= MIDEN_NODE_NTX_BUILDER_VALIDATOR_URL= diff --git a/bin/node/src/commands/block_producer.rs b/bin/node/src/commands/block_producer.rs index 75c2f244a..d8babd478 100644 --- a/bin/node/src/commands/block_producer.rs +++ b/bin/node/src/commands/block_producer.rs @@ -1,3 +1,4 @@ +use std::net::SocketAddr; use std::num::NonZeroUsize; use std::time::Duration; @@ -14,7 +15,7 @@ use url::Url; use super::ENV_ENABLE_OTEL; -const ENV_PORT: &str = "MIDEN_NODE_BLOCK_PRODUCER_PORT"; +const ENV_SOCKET: &str = "MIDEN_NODE_BLOCK_PRODUCER_SOCKET"; const ENV_STORE_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_STORE_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_VALIDATOR_URL"; const ENV_MAX_TXS_PER_BATCH: &str = "MIDEN_NODE_BLOCK_PRODUCER_MAX_TXS_PER_BATCH"; @@ -29,9 +30,9 @@ const ENV_BATCH_PROVER_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_BATCH_PROVER_URL"; pub enum BlockProducerCommand { /// Starts the block-producer component. Start { - /// Port at which to serve the gRPC API. - #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] - port: u16, + /// Socket address at which to serve the gRPC API. + #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] + socket: SocketAddr, /// The store's block-producer service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL)] @@ -59,7 +60,7 @@ pub enum BlockProducerCommand { impl BlockProducerCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - port, + socket, store_url, validator_url, block_producer, @@ -67,7 +68,7 @@ impl BlockProducerCommand { grpc_options, } = self; - let block_producer_address = std::net::SocketAddr::from(([0, 0, 0, 0], port)); + let block_producer_address = socket; // Runtime validation for protocol constraints if block_producer.max_batches_per_block > miden_protocol::MAX_BATCHES_PER_BLOCK { @@ -121,7 +122,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_batches_per_block() { let cmd = BlockProducerCommand::Start { - port: 1234, + socket: "0.0.0.0:1234".parse().unwrap(), store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { @@ -144,7 +145,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_txs_per_batch() { let cmd = BlockProducerCommand::Start { - port: 1234, + socket: "0.0.0.0:1234".parse().unwrap(), store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { diff --git a/bin/node/src/commands/ntx_builder.rs b/bin/node/src/commands/ntx_builder.rs index 13b6c8deb..8e6400828 100644 --- a/bin/node/src/commands/ntx_builder.rs +++ b/bin/node/src/commands/ntx_builder.rs @@ -1,3 +1,4 @@ +use std::net::SocketAddr; use std::num::NonZeroUsize; use std::path::PathBuf; use std::time::Duration; @@ -10,7 +11,7 @@ use url::Url; use super::ENV_ENABLE_OTEL; use crate::commands::ENV_DATA_DIRECTORY; -const ENV_PORT: &str = "MIDEN_NODE_NTX_BUILDER_PORT"; +const ENV_SOCKET: &str = "MIDEN_NODE_NTX_BUILDER_SOCKET"; const ENV_STORE_URL: &str = "MIDEN_NODE_NTX_BUILDER_STORE_URL"; const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_NTX_BUILDER_BLOCK_PRODUCER_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_NTX_BUILDER_VALIDATOR_URL"; @@ -26,9 +27,9 @@ const DEFAULT_MAX_CYCLES: u32 = 1 << 18; pub enum NtxBuilderCommand { /// Starts the network transaction builder component. Start { - /// Port at which to serve the ntx-builder's gRPC API. - #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] - port: Option, + /// Socket address at which to serve the ntx-builder's gRPC API. + #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] + socket: Option, /// The store's ntx-builder service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -104,7 +105,7 @@ pub enum NtxBuilderCommand { impl NtxBuilderCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - port, + socket, store_url, block_producer_url, validator_url, @@ -117,11 +118,11 @@ impl NtxBuilderCommand { enable_otel: _, } = self; - let listener = if let Some(port) = port { + let listener = if let Some(socket) = socket { Some( - TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], port))) + TcpListener::bind(socket) .await - .context("Failed to bind to ntx-builder's gRPC port")?, + .context("Failed to bind to ntx-builder's gRPC socket")?, ) } else { None diff --git a/bin/node/src/commands/rpc.rs b/bin/node/src/commands/rpc.rs index f29d3a0d8..9a11f5be2 100644 --- a/bin/node/src/commands/rpc.rs +++ b/bin/node/src/commands/rpc.rs @@ -1,3 +1,5 @@ +use std::net::SocketAddr; + use anyhow::Context; use miden_node_rpc::Rpc; use miden_node_utils::clap::GrpcOptionsExternal; @@ -5,7 +7,7 @@ use url::Url; use super::ENV_ENABLE_OTEL; -const ENV_PORT: &str = "MIDEN_NODE_RPC_PORT"; +const ENV_SOCKET: &str = "MIDEN_NODE_RPC_SOCKET"; const ENV_STORE_URL: &str = "MIDEN_NODE_RPC_STORE_URL"; const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_RPC_BLOCK_PRODUCER_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_RPC_VALIDATOR_URL"; @@ -15,9 +17,9 @@ const ENV_NTX_BUILDER_URL: &str = "MIDEN_NODE_RPC_NTX_BUILDER_URL"; pub enum RpcCommand { /// Starts the RPC component. Start { - /// Port at which to serve the gRPC API. - #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] - port: u16, + /// Socket address at which to serve the gRPC API. + #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] + socket: SocketAddr, /// The store's RPC service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -51,7 +53,7 @@ pub enum RpcCommand { impl RpcCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - port, + socket, store_url, block_producer_url, validator_url, @@ -60,10 +62,9 @@ impl RpcCommand { grpc_options, } = self; - let listener = - tokio::net::TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], port))) - .await - .context("Failed to bind to RPC's gRPC port")?; + let listener = tokio::net::TcpListener::bind(socket) + .await + .context("Failed to bind to RPC's gRPC socket")?; Rpc { listener, diff --git a/bin/node/src/commands/store.rs b/bin/node/src/commands/store.rs index 28e401c0e..3288d8122 100644 --- a/bin/node/src/commands/store.rs +++ b/bin/node/src/commands/store.rs @@ -1,3 +1,4 @@ +use std::net::SocketAddr; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; @@ -13,10 +14,10 @@ use url::Url; use super::ENV_ENABLE_OTEL; use crate::commands::ENV_DATA_DIRECTORY; -const ENV_RPC_PORT: &str = "MIDEN_NODE_STORE_RPC_PORT"; +const ENV_RPC_SOCKET: &str = "MIDEN_NODE_STORE_RPC_SOCKET"; const ENV_UPSTREAM_URL: &str = "MIDEN_NODE_STORE_UPSTREAM_RPC_URL"; -const ENV_NTX_BUILDER_PORT: &str = "MIDEN_NODE_STORE_NTX_BUILDER_PORT"; -const ENV_BLOCK_PRODUCER_PORT: &str = "MIDEN_NODE_STORE_BLOCK_PRODUCER_PORT"; +const ENV_NTX_BUILDER_SOCKET: &str = "MIDEN_NODE_STORE_NTX_BUILDER_SOCKET"; +const ENV_BLOCK_PRODUCER_SOCKET: &str = "MIDEN_NODE_STORE_BLOCK_PRODUCER_SOCKET"; const ENV_BLOCK_PROVER_URL: &str = "MIDEN_NODE_STORE_BLOCK_PROVER_URL"; #[derive(clap::Subcommand)] @@ -38,17 +39,17 @@ pub enum StoreCommand { /// In this mode the store accepts blocks from a block producer via a dedicated gRPC endpoint /// and runs the proof scheduler to generate block proofs. Start { - /// Port at which to serve the store's RPC API. - #[arg(long = "rpc.port", env = ENV_RPC_PORT, value_name = "PORT")] - rpc_port: u16, + /// Socket address at which to serve the store's RPC API. + #[arg(long = "rpc.socket", env = ENV_RPC_SOCKET, value_name = "SOCKET")] + rpc_socket: SocketAddr, - /// Port at which to serve the store's network transaction builder API. - #[arg(long = "ntx-builder.port", env = ENV_NTX_BUILDER_PORT, value_name = "PORT")] - ntx_builder_port: u16, + /// Socket address at which to serve the store's network transaction builder API. + #[arg(long = "ntx-builder.socket", env = ENV_NTX_BUILDER_SOCKET, value_name = "SOCKET")] + ntx_builder_socket: SocketAddr, - /// Port at which to serve the store's block producer API. - #[arg(long = "block-producer.port", env = ENV_BLOCK_PRODUCER_PORT, value_name = "PORT")] - block_producer_port: u16, + /// Socket address at which to serve the store's block producer API. + #[arg(long = "block-producer.socket", env = ENV_BLOCK_PRODUCER_SOCKET, value_name = "SOCKET")] + block_producer_socket: SocketAddr, /// The remote block prover's gRPC url. If not provided, a local block prover will be used. #[arg(long = "block-prover.url", env = ENV_BLOCK_PROVER_URL, value_name = "URL")] @@ -86,9 +87,9 @@ pub enum StoreCommand { /// Only the `Rpc` and `StoreReplica` gRPC services are exposed — the `BlockProducer` and /// `NtxBuilder` services are not started and no proof scheduler runs. StartReplica { - /// Port at which to serve the store's RPC API. - #[arg(long = "rpc.port", env = ENV_RPC_PORT, value_name = "PORT")] - rpc_port: u16, + /// Socket address at which to serve the store's RPC API. + #[arg(long = "rpc.socket", env = ENV_RPC_SOCKET, value_name = "SOCKET")] + rpc_socket: SocketAddr, /// gRPC URL of the upstream store's `StoreReplica` endpoint to sync blocks from. #[arg(long = "upstream-store.url", env = ENV_UPSTREAM_URL, value_name = "URL")] @@ -119,9 +120,9 @@ impl StoreCommand { bootstrap_store(&data_directory, &genesis_block) }, StoreCommand::Start { - rpc_port, - ntx_builder_port, - block_producer_port, + rpc_socket, + ntx_builder_socket, + block_producer_socket, block_prover_url, data_directory, enable_otel: _, @@ -130,9 +131,9 @@ impl StoreCommand { storage_options, } => { Self::start( - rpc_port, - ntx_builder_port, - block_producer_port, + rpc_socket, + ntx_builder_socket, + block_producer_socket, block_prover_url, data_directory, grpc_options, @@ -142,7 +143,7 @@ impl StoreCommand { .await }, StoreCommand::StartReplica { - rpc_port, + rpc_socket, upstream_store_url, data_directory, enable_otel: _, @@ -150,7 +151,7 @@ impl StoreCommand { storage_options, } => { Self::start_replica( - rpc_port, + rpc_socket, upstream_store_url, data_directory, grpc_options, @@ -172,33 +173,26 @@ impl StoreCommand { #[expect(clippy::too_many_arguments)] async fn start( - rpc_port: u16, - ntx_builder_port: u16, - block_producer_port: u16, + rpc_socket: SocketAddr, + ntx_builder_socket: SocketAddr, + block_producer_socket: SocketAddr, block_prover_url: Option, data_directory: PathBuf, grpc_options: GrpcOptionsInternal, max_concurrent_proofs: NonZeroUsize, storage_options: StorageOptions, ) -> anyhow::Result<()> { - let rpc_listener = - tokio::net::TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], rpc_port))) - .await - .context("Failed to bind to store's RPC gRPC port")?; + let rpc_listener = tokio::net::TcpListener::bind(rpc_socket) + .await + .context("Failed to bind to store's RPC gRPC socket")?; - let ntx_builder_listener = tokio::net::TcpListener::bind(std::net::SocketAddr::from(( - [0, 0, 0, 0], - ntx_builder_port, - ))) - .await - .context("Failed to bind to store's ntx-builder gRPC port")?; + let ntx_builder_listener = tokio::net::TcpListener::bind(ntx_builder_socket) + .await + .context("Failed to bind to store's ntx-builder gRPC socket")?; - let block_producer_listener = tokio::net::TcpListener::bind(std::net::SocketAddr::from(( - [0, 0, 0, 0], - block_producer_port, - ))) - .await - .context("Failed to bind to store's block-producer gRPC port")?; + let block_producer_listener = tokio::net::TcpListener::bind(block_producer_socket) + .await + .context("Failed to bind to store's block-producer gRPC socket")?; Store { rpc_listener, @@ -218,16 +212,15 @@ impl StoreCommand { } async fn start_replica( - rpc_port: u16, + rpc_socket: SocketAddr, upstream_store_url: Url, data_directory: PathBuf, grpc_options: GrpcOptionsInternal, storage_options: StorageOptions, ) -> anyhow::Result<()> { - let rpc_listener = - tokio::net::TcpListener::bind(std::net::SocketAddr::from(([0, 0, 0, 0], rpc_port))) - .await - .context("Failed to bind to store's RPC gRPC port")?; + let rpc_listener = tokio::net::TcpListener::bind(rpc_socket) + .await + .context("Failed to bind to store's RPC gRPC socket")?; Store { rpc_listener, diff --git a/bin/node/src/commands/validator.rs b/bin/node/src/commands/validator.rs index a478284c1..64d2c6837 100644 --- a/bin/node/src/commands/validator.rs +++ b/bin/node/src/commands/validator.rs @@ -12,7 +12,7 @@ use miden_protocol::utils::serde::{Deserializable, Serializable}; use crate::commands::{ENV_DATA_DIRECTORY, ENV_ENABLE_OTEL}; -const ENV_PORT: &str = "MIDEN_NODE_VALIDATOR_PORT"; +const ENV_SOCKET: &str = "MIDEN_NODE_VALIDATOR_SOCKET"; const ENV_GENESIS_CONFIG_FILE: &str = "MIDEN_NODE_VALIDATOR_GENESIS_CONFIG_FILE"; const ENV_KEY: &str = "MIDEN_NODE_VALIDATOR_KEY"; const ENV_KMS_KEY_ID: &str = "MIDEN_NODE_VALIDATOR_KMS_KEY_ID"; @@ -52,9 +52,9 @@ pub enum ValidatorCommand { /// Starts the validator component. Start { - /// Port at which to serve the gRPC API. - #[arg(long = "port", env = ENV_PORT, value_name = "PORT")] - port: u16, + /// Socket address at which to serve the gRPC API. + #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] + socket: std::net::SocketAddr, /// Enables the exporting of traces for OpenTelemetry. /// @@ -118,14 +118,14 @@ impl ValidatorCommand { .await }, Self::Start { - port, + socket, grpc_options, validator_key, data_directory, kms_key_id, .. } => { - let address = SocketAddr::from(([0, 0, 0, 0], port)); + let address = socket; // Run validator with KMS key backend if key id provided. if let Some(kms_key_id) = kms_key_id { diff --git a/docker-compose.yml b/docker-compose.yml index 01c734398..4607f3790 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,9 +34,9 @@ services: - miden-node - store - start - - --rpc.port=50001 - - --ntx-builder.port=50002 - - --block-producer.port=50003 + - --rpc.socket=0.0.0.0:50001 + - --ntx-builder.socket=0.0.0.0:50002 + - --block-producer.socket=0.0.0.0:50003 - --data-directory=/data/store - --account_tree.rocksdb.max_cache_size=4294967296 - --account_tree.rocksdb.max_open_fds=512 @@ -60,7 +60,7 @@ services: - miden-node - validator - start - - --port=50101 + - --socket=0.0.0.0:50101 - --data-directory=/data/validator ports: - "50101:50101" @@ -76,7 +76,7 @@ services: - miden-node - block-producer - start - - --port=50201 + - --socket=0.0.0.0:50201 - --store.url=http://store:50003 - --validator.url=http://validator:50101 ports: @@ -93,7 +93,7 @@ services: - miden-node - rpc - start - - --port=57291 + - --socket=0.0.0.0:57291 - --store.url=http://store:50001 - --block-producer.url=http://block-producer:50201 - --validator.url=http://validator:50101 diff --git a/docs/external/src/operator/usage.md b/docs/external/src/operator/usage.md index 5955495b9..aff5264b9 100644 --- a/docs/external/src/operator/usage.md +++ b/docs/external/src/operator/usage.md @@ -160,23 +160,23 @@ Each component can also be started as a standalone process. For example: ```sh # Start the store miden-node store start \ - --rpc.port 50001 \ - --ntx-builder.port 50002 \ - --block-producer.port 50003 \ + --rpc.socket 0.0.0.0:50001 \ + --ntx-builder.socket 0.0.0.0:50002 \ + --block-producer.socket 0.0.0.0:50003 \ --data-directory /tmp/store # Start the validator -miden-node validator start --port 50101 \ +miden-node validator start --socket 0.0.0.0:50101 \ --data-directory /tmp/validator # Start the block producer -miden-node block-producer start --port 50201 \ +miden-node block-producer start --socket 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 \ - --port 57291 \ + --socket 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 @@ -226,7 +226,7 @@ Compaction parallelism is set automatically to the number of available CPU cores ```sh miden-node store start \ --data-directory data \ - --rpc.port 57291 \ + --rpc.socket 0.0.0.0:57291 \ --account_tree.rocksdb.max_cache_size 4294967296 \ --account_tree.rocksdb.max_open_fds 512 \ --nullifier_tree.rocksdb.max_cache_size 4294967296 \ diff --git a/scripts/run-node.sh b/scripts/run-node.sh index aabc280b6..6d9ac8935 100755 --- a/scripts/run-node.sh +++ b/scripts/run-node.sh @@ -106,9 +106,9 @@ echo "=== Starting components ===" echo "Starting store (block-producer mode)..." $BINARY store start \ - --rpc.port "$STORE_RPC_PORT" \ - --ntx-builder.port "$STORE_NTX_BUILDER_PORT" \ - --block-producer.port "$STORE_BLOCK_PRODUCER_PORT" \ + --rpc.socket "0.0.0.0:$STORE_RPC_PORT" \ + --ntx-builder.socket "0.0.0.0:$STORE_NTX_BUILDER_PORT" \ + --block-producer.socket "0.0.0.0:$STORE_BLOCK_PRODUCER_PORT" \ --data-directory "$STORE_DIR" & PIDS+=($!) @@ -118,7 +118,7 @@ if [[ -n "$KMS_KEY_ID" ]]; then fi echo "Starting validator..." -$BINARY validator start --port "$VALIDATOR_PORT" \ +$BINARY validator start --socket "0.0.0.0:$VALIDATOR_PORT" \ --data-directory "$VALIDATOR_DIR" \ "${KMS_START_ARGS[@]+"${KMS_START_ARGS[@]}"}" & PIDS+=($!) @@ -129,7 +129,7 @@ sleep 2 # Replica 1 syncs from the primary store. echo "Starting store replica 1 (upstream: primary store at 127.0.0.1:$STORE_RPC_PORT)..." $BINARY store start-replica \ - --rpc.port "$STORE_REPLICA_1_RPC_PORT" \ + --rpc.socket "0.0.0.0:$STORE_REPLICA_1_RPC_PORT" \ --upstream-store.url "http://127.0.0.1:$STORE_RPC_PORT" \ --data-directory "$STORE_REPLICA_1_DIR" & PIDS+=($!) @@ -137,20 +137,20 @@ PIDS+=($!) # Replica 2 syncs from replica 1, proving replicas can act as upstreams. echo "Starting store replica 2 (upstream: replica 1 at 127.0.0.1:$STORE_REPLICA_1_RPC_PORT)..." $BINARY store start-replica \ - --rpc.port "$STORE_REPLICA_2_RPC_PORT" \ + --rpc.socket "0.0.0.0:$STORE_REPLICA_2_RPC_PORT" \ --upstream-store.url "http://127.0.0.1:$STORE_REPLICA_1_RPC_PORT" \ --data-directory "$STORE_REPLICA_2_DIR" & PIDS+=($!) echo "Starting block producer..." -$BINARY block-producer start --port "$BLOCK_PRODUCER_PORT" \ +$BINARY block-producer start --socket "0.0.0.0:$BLOCK_PRODUCER_PORT" \ --store.url "http://127.0.0.1:$STORE_BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & PIDS+=($!) echo "Starting RPC server (primary store)..." $BINARY rpc start \ - --port "$RPC_PORT" \ + --socket "0.0.0.0:$RPC_PORT" \ --store.url "http://127.0.0.1:$STORE_RPC_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & @@ -158,7 +158,7 @@ PIDS+=($!) echo "Starting RPC server (replica 1)..." $BINARY rpc start \ - --port "$RPC_REPLICA_1_PORT" \ + --socket "0.0.0.0:$RPC_REPLICA_1_PORT" \ --store.url "http://127.0.0.1:$STORE_REPLICA_1_RPC_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & @@ -166,7 +166,7 @@ PIDS+=($!) echo "Starting RPC server (replica 2)..." $BINARY rpc start \ - --port "$RPC_REPLICA_2_PORT" \ + --socket "0.0.0.0:$RPC_REPLICA_2_PORT" \ --store.url "http://127.0.0.1:$STORE_REPLICA_2_RPC_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & From ebe76f8baad1f699e4532f05f026f92b169d5761 Mon Sep 17 00:00:00 2001 From: sergerad Date: Thu, 7 May 2026 13:18:51 +1200 Subject: [PATCH 05/10] RM option for ntx builder arg --- bin/node/src/commands/ntx_builder.rs | 14 ++++---------- crates/ntx-builder/src/builder.rs | 14 ++++++-------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/bin/node/src/commands/ntx_builder.rs b/bin/node/src/commands/ntx_builder.rs index 8e6400828..955fdfbdd 100644 --- a/bin/node/src/commands/ntx_builder.rs +++ b/bin/node/src/commands/ntx_builder.rs @@ -29,7 +29,7 @@ pub enum NtxBuilderCommand { Start { /// Socket address at which to serve the ntx-builder's gRPC API. #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] - socket: Option, + socket: SocketAddr, /// The store's ntx-builder service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -118,15 +118,9 @@ impl NtxBuilderCommand { enable_otel: _, } = self; - let listener = if let Some(socket) = socket { - Some( - TcpListener::bind(socket) - .await - .context("Failed to bind to ntx-builder's gRPC socket")?, - ) - } else { - None - }; + let listener = TcpListener::bind(socket) + .await + .context("Failed to bind to ntx-builder's gRPC socket")?; let database_filepath = data_directory.join("ntx-builder.sqlite3"); diff --git a/crates/ntx-builder/src/builder.rs b/crates/ntx-builder/src/builder.rs index 12bc442a8..7b823f7c1 100644 --- a/crates/ntx-builder/src/builder.rs +++ b/crates/ntx-builder/src/builder.rs @@ -104,16 +104,14 @@ impl NetworkTransactionBuilder { /// - An actor encounters a fatal error /// - The account loader task fails /// - The gRPC server fails - pub async fn run(self, listener: Option) -> anyhow::Result<()> { + pub async fn run(self, listener: TcpListener) -> anyhow::Result<()> { let mut join_set = JoinSet::new(); - // Start the gRPC server if a listener is provided. - if let Some(listener) = listener { - let server = NtxBuilderRpcServer::new(self.db.clone(), self.config.max_note_attempts); - join_set.spawn(async move { - server.serve(listener).await.context("ntx-builder gRPC server failed") - }); - } + // Start the gRPC server. + let server = NtxBuilderRpcServer::new(self.db.clone(), self.config.max_note_attempts); + join_set.spawn(async move { + server.serve(listener).await.context("ntx-builder gRPC server failed") + }); join_set.spawn(self.run_event_loop()); From 6e7227dd5c2b38c84cff3f0bef315644863c0325 Mon Sep 17 00:00:00 2001 From: sergerad Date: Thu, 7 May 2026 13:19:41 +1200 Subject: [PATCH 06/10] Reword changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5835ea67b..5f6cd93f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,8 @@ - Added a `replica` mode to the store, which streams blocks from an upstream master store ([#1987](https://github.com/0xMiden/node/pull/1987)). - Added `StoreReplica` gRPC service with endpoints for streaming blocks and proofs ([#1987](https://github.com/0xMiden/node/pull/1987)). - Replaced the network monitor's JavaScript dashboard with a server-rendered Maud + HTMX frontend ([#2024](https://github.com/0xMiden/node/pull/2024)). -- [BREAKING] Replaced binding URL env vars and CLI flags with binding ports ([#2054](https://github.com/0xMiden/node/pull/2054)). - [BREAKING] Removed `CheckNullifiers` endpoint ([#2049](https://github.com/0xMiden/node/pull/2049)). +- [BREAKING] Replaced binding URL env vars and CLI flags with sockets ([#2054](https://github.com/0xMiden/node/pull/2054)). ## v0.14.10 (2026-05-29) From 25d7472ba40d31ec3f0c4c7cf9ce101111a53b66 Mon Sep 17 00:00:00 2001 From: sergerad Date: Thu, 7 May 2026 13:22:47 +1200 Subject: [PATCH 07/10] Update run script --- docker-compose.yml | 1 + docs/external/src/operator/usage.md | 1 + scripts/run-node.sh | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4607f3790..804bf7d43 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -113,6 +113,7 @@ services: - miden-node - ntx-builder - start + - --socket=0.0.0.0:50301 - --store.url=http://store:50002 - --block-producer.url=http://block-producer:50201 - --validator.url=http://validator:50101 diff --git a/docs/external/src/operator/usage.md b/docs/external/src/operator/usage.md index aff5264b9..e6f4e6860 100644 --- a/docs/external/src/operator/usage.md +++ b/docs/external/src/operator/usage.md @@ -183,6 +183,7 @@ miden-node rpc start \ # Start the network transaction builder miden-node ntx-builder start \ + --socket 0.0.0.0:50301 \ --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 \ diff --git a/scripts/run-node.sh b/scripts/run-node.sh index 6d9ac8935..fc8589644 100755 --- a/scripts/run-node.sh +++ b/scripts/run-node.sh @@ -29,6 +29,7 @@ STORE_REPLICA_2_RPC_PORT=50021 VALIDATOR_PORT=50101 BLOCK_PRODUCER_PORT=50201 +NTX_BUILDER_PORT=50301 RPC_PORT=57291 RPC_REPLICA_1_PORT=57292 RPC_REPLICA_2_PORT=57293 @@ -47,7 +48,7 @@ trap cleanup EXIT INT TERM # --- Kill processes on required ports --- -PORTS=(50001 50002 50003 50011 50021 50101 50201 57291 57292 57293) +PORTS=(50001 50002 50003 50011 50021 50101 50201 50301 57291 57292 57293) echo "=== Killing processes on required ports ===" for port in "${PORTS[@]}"; do pids=$(lsof -ti :"$port" 2>/dev/null || true) @@ -174,6 +175,7 @@ PIDS+=($!) echo "Starting network transaction builder..." $BINARY ntx-builder start \ + --socket "0.0.0.0:$NTX_BUILDER_PORT" \ --store.url "http://127.0.0.1:$STORE_NTX_BUILDER_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" \ From 9498b2227a336b57d40a89202f27ed25c31a8434 Mon Sep 17 00:00:00 2001 From: sergerad Date: Fri, 8 May 2026 12:13:38 +1200 Subject: [PATCH 08/10] Use [:1]:0 --- bin/node/src/commands/block_producer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/node/src/commands/block_producer.rs b/bin/node/src/commands/block_producer.rs index d8babd478..790befef6 100644 --- a/bin/node/src/commands/block_producer.rs +++ b/bin/node/src/commands/block_producer.rs @@ -122,7 +122,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_batches_per_block() { let cmd = BlockProducerCommand::Start { - socket: "0.0.0.0:1234".parse().unwrap(), + socket: "[::1]:0".parse().unwrap(), store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { @@ -145,7 +145,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_txs_per_batch() { let cmd = BlockProducerCommand::Start { - socket: "0.0.0.0:1234".parse().unwrap(), + socket: "[::1]:0".parse().unwrap(), store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { From 15158aae65ead51c65250964350a3cbafdec31df Mon Sep 17 00:00:00 2001 From: sergerad Date: Fri, 8 May 2026 12:20:48 +1200 Subject: [PATCH 09/10] Rename socket to listen --- CHANGELOG.md | 3 +- bin/node/.env | 14 +++---- bin/node/src/commands/block_producer.rs | 14 +++---- bin/node/src/commands/ntx_builder.rs | 10 ++--- bin/node/src/commands/rpc.rs | 10 ++--- bin/node/src/commands/store.rs | 54 ++++++++++++------------- bin/node/src/commands/validator.rs | 10 ++--- docker-compose.yml | 14 +++---- docs/external/src/operator/usage.md | 16 ++++---- scripts/run-node.sh | 22 +++++----- 10 files changed, 84 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f6cd93f3..6b0a8c3a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ - Added `StoreReplica` gRPC service with endpoints for streaming blocks and proofs ([#1987](https://github.com/0xMiden/node/pull/1987)). - Replaced the network monitor's JavaScript dashboard with a server-rendered Maud + HTMX frontend ([#2024](https://github.com/0xMiden/node/pull/2024)). - [BREAKING] Removed `CheckNullifiers` endpoint ([#2049](https://github.com/0xMiden/node/pull/2049)). -- [BREAKING] Replaced binding URL env vars and CLI flags with sockets ([#2054](https://github.com/0xMiden/node/pull/2054)). +- [BREAKING] Replaced binding URL env vars and CLI flags with listen socket addresses ([#2054](https://github.com/0xMiden/node/pull/2054)). +- [BREAKING] Renamed `--url` CLI flags and `*_URL` env vars to `--listen` / `*_LISTEN` across all components. ## v0.14.10 (2026-05-29) diff --git a/bin/node/.env b/bin/node/.env index f140e70b5..cd3de70d8 100644 --- a/bin/node/.env +++ b/bin/node/.env @@ -6,7 +6,7 @@ MIDEN_NODE_ENABLE_OTEL=true MIDEN_NODE_DATA_DIRECTORY= # Block Producer -MIDEN_NODE_BLOCK_PRODUCER_SOCKET= +MIDEN_NODE_BLOCK_PRODUCER_LISTEN= MIDEN_NODE_BLOCK_PRODUCER_STORE_URL= MIDEN_NODE_BLOCK_PRODUCER_VALIDATOR_URL= MIDEN_NODE_BLOCK_PRODUCER_MAX_TXS_PER_BATCH= @@ -15,27 +15,27 @@ MIDEN_NODE_BLOCK_PRODUCER_MEMPOOL_TX_CAPACITY= MIDEN_NODE_BLOCK_PRODUCER_BATCH_PROVER_URL= # Store -MIDEN_NODE_STORE_RPC_SOCKET= +MIDEN_NODE_STORE_RPC_LISTEN= MIDEN_NODE_STORE_UPSTREAM_RPC_URL= -MIDEN_NODE_STORE_NTX_BUILDER_SOCKET= -MIDEN_NODE_STORE_BLOCK_PRODUCER_SOCKET= +MIDEN_NODE_STORE_NTX_BUILDER_LISTEN= +MIDEN_NODE_STORE_BLOCK_PRODUCER_LISTEN= MIDEN_NODE_STORE_BLOCK_PROVER_URL= # RPC -MIDEN_NODE_RPC_SOCKET=0.0.0.0:57291 +MIDEN_NODE_RPC_LISTEN=0.0.0.0:57291 MIDEN_NODE_RPC_STORE_URL= MIDEN_NODE_RPC_BLOCK_PRODUCER_URL= MIDEN_NODE_RPC_VALIDATOR_URL= MIDEN_NODE_RPC_NTX_BUILDER_URL= # Validator -MIDEN_NODE_VALIDATOR_SOCKET= +MIDEN_NODE_VALIDATOR_LISTEN= MIDEN_NODE_VALIDATOR_GENESIS_CONFIG_FILE= MIDEN_NODE_VALIDATOR_KEY= MIDEN_NODE_VALIDATOR_KMS_KEY_ID= # NTX Builder -MIDEN_NODE_NTX_BUILDER_SOCKET= +MIDEN_NODE_NTX_BUILDER_LISTEN= MIDEN_NODE_NTX_BUILDER_STORE_URL= MIDEN_NODE_NTX_BUILDER_BLOCK_PRODUCER_URL= MIDEN_NODE_NTX_BUILDER_VALIDATOR_URL= diff --git a/bin/node/src/commands/block_producer.rs b/bin/node/src/commands/block_producer.rs index 790befef6..b92186823 100644 --- a/bin/node/src/commands/block_producer.rs +++ b/bin/node/src/commands/block_producer.rs @@ -15,7 +15,7 @@ use url::Url; use super::ENV_ENABLE_OTEL; -const ENV_SOCKET: &str = "MIDEN_NODE_BLOCK_PRODUCER_SOCKET"; +const ENV_LISTEN: &str = "MIDEN_NODE_BLOCK_PRODUCER_LISTEN"; const ENV_STORE_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_STORE_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_BLOCK_PRODUCER_VALIDATOR_URL"; const ENV_MAX_TXS_PER_BATCH: &str = "MIDEN_NODE_BLOCK_PRODUCER_MAX_TXS_PER_BATCH"; @@ -31,8 +31,8 @@ pub enum BlockProducerCommand { /// Starts the block-producer component. Start { /// Socket address at which to serve the gRPC API. - #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] - socket: SocketAddr, + #[arg(long = "listen", env = ENV_LISTEN, value_name = "LISTEN")] + listen: SocketAddr, /// The store's block-producer service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL)] @@ -60,7 +60,7 @@ pub enum BlockProducerCommand { impl BlockProducerCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - socket, + listen, store_url, validator_url, block_producer, @@ -68,7 +68,7 @@ impl BlockProducerCommand { grpc_options, } = self; - let block_producer_address = socket; + let block_producer_address = listen; // Runtime validation for protocol constraints if block_producer.max_batches_per_block > miden_protocol::MAX_BATCHES_PER_BLOCK { @@ -122,7 +122,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_batches_per_block() { let cmd = BlockProducerCommand::Start { - socket: "[::1]:0".parse().unwrap(), + listen: "[::1]:0".parse().unwrap(), store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { @@ -145,7 +145,7 @@ mod tests { #[tokio::test] async fn rejects_too_large_max_txs_per_batch() { let cmd = BlockProducerCommand::Start { - socket: "[::1]:0".parse().unwrap(), + listen: "[::1]:0".parse().unwrap(), store_url: dummy_url(), validator_url: dummy_url(), block_producer: BlockProducerConfig { diff --git a/bin/node/src/commands/ntx_builder.rs b/bin/node/src/commands/ntx_builder.rs index 955fdfbdd..e1165b6bc 100644 --- a/bin/node/src/commands/ntx_builder.rs +++ b/bin/node/src/commands/ntx_builder.rs @@ -11,7 +11,7 @@ use url::Url; use super::ENV_ENABLE_OTEL; use crate::commands::ENV_DATA_DIRECTORY; -const ENV_SOCKET: &str = "MIDEN_NODE_NTX_BUILDER_SOCKET"; +const ENV_LISTEN: &str = "MIDEN_NODE_NTX_BUILDER_LISTEN"; const ENV_STORE_URL: &str = "MIDEN_NODE_NTX_BUILDER_STORE_URL"; const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_NTX_BUILDER_BLOCK_PRODUCER_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_NTX_BUILDER_VALIDATOR_URL"; @@ -28,8 +28,8 @@ pub enum NtxBuilderCommand { /// Starts the network transaction builder component. Start { /// Socket address at which to serve the ntx-builder's gRPC API. - #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] - socket: SocketAddr, + #[arg(long = "listen", env = ENV_LISTEN, value_name = "LISTEN")] + listen: SocketAddr, /// The store's ntx-builder service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -105,7 +105,7 @@ pub enum NtxBuilderCommand { impl NtxBuilderCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - socket, + listen, store_url, block_producer_url, validator_url, @@ -118,7 +118,7 @@ impl NtxBuilderCommand { enable_otel: _, } = self; - let listener = TcpListener::bind(socket) + let listener = TcpListener::bind(listen) .await .context("Failed to bind to ntx-builder's gRPC socket")?; diff --git a/bin/node/src/commands/rpc.rs b/bin/node/src/commands/rpc.rs index 9a11f5be2..3e055cfff 100644 --- a/bin/node/src/commands/rpc.rs +++ b/bin/node/src/commands/rpc.rs @@ -7,7 +7,7 @@ use url::Url; use super::ENV_ENABLE_OTEL; -const ENV_SOCKET: &str = "MIDEN_NODE_RPC_SOCKET"; +const ENV_LISTEN: &str = "MIDEN_NODE_RPC_LISTEN"; const ENV_STORE_URL: &str = "MIDEN_NODE_RPC_STORE_URL"; const ENV_BLOCK_PRODUCER_URL: &str = "MIDEN_NODE_RPC_BLOCK_PRODUCER_URL"; const ENV_VALIDATOR_URL: &str = "MIDEN_NODE_RPC_VALIDATOR_URL"; @@ -18,8 +18,8 @@ pub enum RpcCommand { /// Starts the RPC component. Start { /// Socket address at which to serve the gRPC API. - #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] - socket: SocketAddr, + #[arg(long = "listen", env = ENV_LISTEN, value_name = "LISTEN")] + listen: SocketAddr, /// The store's RPC service gRPC url. #[arg(long = "store.url", env = ENV_STORE_URL, value_name = "URL")] @@ -53,7 +53,7 @@ pub enum RpcCommand { impl RpcCommand { pub async fn handle(self) -> anyhow::Result<()> { let Self::Start { - socket, + listen, store_url, block_producer_url, validator_url, @@ -62,7 +62,7 @@ impl RpcCommand { grpc_options, } = self; - let listener = tokio::net::TcpListener::bind(socket) + let listener = tokio::net::TcpListener::bind(listen) .await .context("Failed to bind to RPC's gRPC socket")?; diff --git a/bin/node/src/commands/store.rs b/bin/node/src/commands/store.rs index 3288d8122..7e88ce86d 100644 --- a/bin/node/src/commands/store.rs +++ b/bin/node/src/commands/store.rs @@ -14,10 +14,10 @@ use url::Url; use super::ENV_ENABLE_OTEL; use crate::commands::ENV_DATA_DIRECTORY; -const ENV_RPC_SOCKET: &str = "MIDEN_NODE_STORE_RPC_SOCKET"; +const ENV_RPC_LISTEN: &str = "MIDEN_NODE_STORE_RPC_LISTEN"; const ENV_UPSTREAM_URL: &str = "MIDEN_NODE_STORE_UPSTREAM_RPC_URL"; -const ENV_NTX_BUILDER_SOCKET: &str = "MIDEN_NODE_STORE_NTX_BUILDER_SOCKET"; -const ENV_BLOCK_PRODUCER_SOCKET: &str = "MIDEN_NODE_STORE_BLOCK_PRODUCER_SOCKET"; +const ENV_NTX_BUILDER_LISTEN: &str = "MIDEN_NODE_STORE_NTX_BUILDER_LISTEN"; +const ENV_BLOCK_PRODUCER_LISTEN: &str = "MIDEN_NODE_STORE_BLOCK_PRODUCER_LISTEN"; const ENV_BLOCK_PROVER_URL: &str = "MIDEN_NODE_STORE_BLOCK_PROVER_URL"; #[derive(clap::Subcommand)] @@ -40,16 +40,16 @@ pub enum StoreCommand { /// and runs the proof scheduler to generate block proofs. Start { /// Socket address at which to serve the store's RPC API. - #[arg(long = "rpc.socket", env = ENV_RPC_SOCKET, value_name = "SOCKET")] - rpc_socket: SocketAddr, + #[arg(long = "rpc.listen", env = ENV_RPC_LISTEN, value_name = "LISTEN")] + rpc_listen: SocketAddr, /// Socket address at which to serve the store's network transaction builder API. - #[arg(long = "ntx-builder.socket", env = ENV_NTX_BUILDER_SOCKET, value_name = "SOCKET")] - ntx_builder_socket: SocketAddr, + #[arg(long = "ntx-builder.listen", env = ENV_NTX_BUILDER_LISTEN, value_name = "LISTEN")] + ntx_builder_listen: SocketAddr, /// Socket address at which to serve the store's block producer API. - #[arg(long = "block-producer.socket", env = ENV_BLOCK_PRODUCER_SOCKET, value_name = "SOCKET")] - block_producer_socket: SocketAddr, + #[arg(long = "block-producer.listen", env = ENV_BLOCK_PRODUCER_LISTEN, value_name = "LISTEN")] + block_producer_listen: SocketAddr, /// The remote block prover's gRPC url. If not provided, a local block prover will be used. #[arg(long = "block-prover.url", env = ENV_BLOCK_PROVER_URL, value_name = "URL")] @@ -88,8 +88,8 @@ pub enum StoreCommand { /// `NtxBuilder` services are not started and no proof scheduler runs. StartReplica { /// Socket address at which to serve the store's RPC API. - #[arg(long = "rpc.socket", env = ENV_RPC_SOCKET, value_name = "SOCKET")] - rpc_socket: SocketAddr, + #[arg(long = "rpc.listen", env = ENV_RPC_LISTEN, value_name = "LISTEN")] + rpc_listen: SocketAddr, /// gRPC URL of the upstream store's `StoreReplica` endpoint to sync blocks from. #[arg(long = "upstream-store.url", env = ENV_UPSTREAM_URL, value_name = "URL")] @@ -120,9 +120,9 @@ impl StoreCommand { bootstrap_store(&data_directory, &genesis_block) }, StoreCommand::Start { - rpc_socket, - ntx_builder_socket, - block_producer_socket, + rpc_listen, + ntx_builder_listen, + block_producer_listen, block_prover_url, data_directory, enable_otel: _, @@ -131,9 +131,9 @@ impl StoreCommand { storage_options, } => { Self::start( - rpc_socket, - ntx_builder_socket, - block_producer_socket, + rpc_listen, + ntx_builder_listen, + block_producer_listen, block_prover_url, data_directory, grpc_options, @@ -143,7 +143,7 @@ impl StoreCommand { .await }, StoreCommand::StartReplica { - rpc_socket, + rpc_listen, upstream_store_url, data_directory, enable_otel: _, @@ -151,7 +151,7 @@ impl StoreCommand { storage_options, } => { Self::start_replica( - rpc_socket, + rpc_listen, upstream_store_url, data_directory, grpc_options, @@ -173,24 +173,24 @@ impl StoreCommand { #[expect(clippy::too_many_arguments)] async fn start( - rpc_socket: SocketAddr, - ntx_builder_socket: SocketAddr, - block_producer_socket: SocketAddr, + rpc_listen: SocketAddr, + ntx_builder_listen: SocketAddr, + block_producer_listen: SocketAddr, block_prover_url: Option, data_directory: PathBuf, grpc_options: GrpcOptionsInternal, max_concurrent_proofs: NonZeroUsize, storage_options: StorageOptions, ) -> anyhow::Result<()> { - let rpc_listener = tokio::net::TcpListener::bind(rpc_socket) + let rpc_listener = tokio::net::TcpListener::bind(rpc_listen) .await .context("Failed to bind to store's RPC gRPC socket")?; - let ntx_builder_listener = tokio::net::TcpListener::bind(ntx_builder_socket) + let ntx_builder_listener = tokio::net::TcpListener::bind(ntx_builder_listen) .await .context("Failed to bind to store's ntx-builder gRPC socket")?; - let block_producer_listener = tokio::net::TcpListener::bind(block_producer_socket) + let block_producer_listener = tokio::net::TcpListener::bind(block_producer_listen) .await .context("Failed to bind to store's block-producer gRPC socket")?; @@ -212,13 +212,13 @@ impl StoreCommand { } async fn start_replica( - rpc_socket: SocketAddr, + rpc_listen: SocketAddr, upstream_store_url: Url, data_directory: PathBuf, grpc_options: GrpcOptionsInternal, storage_options: StorageOptions, ) -> anyhow::Result<()> { - let rpc_listener = tokio::net::TcpListener::bind(rpc_socket) + let rpc_listener = tokio::net::TcpListener::bind(rpc_listen) .await .context("Failed to bind to store's RPC gRPC socket")?; diff --git a/bin/node/src/commands/validator.rs b/bin/node/src/commands/validator.rs index 64d2c6837..41b16a3c0 100644 --- a/bin/node/src/commands/validator.rs +++ b/bin/node/src/commands/validator.rs @@ -12,7 +12,7 @@ use miden_protocol::utils::serde::{Deserializable, Serializable}; use crate::commands::{ENV_DATA_DIRECTORY, ENV_ENABLE_OTEL}; -const ENV_SOCKET: &str = "MIDEN_NODE_VALIDATOR_SOCKET"; +const ENV_LISTEN: &str = "MIDEN_NODE_VALIDATOR_LISTEN"; const ENV_GENESIS_CONFIG_FILE: &str = "MIDEN_NODE_VALIDATOR_GENESIS_CONFIG_FILE"; const ENV_KEY: &str = "MIDEN_NODE_VALIDATOR_KEY"; const ENV_KMS_KEY_ID: &str = "MIDEN_NODE_VALIDATOR_KMS_KEY_ID"; @@ -53,8 +53,8 @@ pub enum ValidatorCommand { /// Starts the validator component. Start { /// Socket address at which to serve the gRPC API. - #[arg(long = "socket", env = ENV_SOCKET, value_name = "SOCKET")] - socket: std::net::SocketAddr, + #[arg(long = "listen", env = ENV_LISTEN, value_name = "LISTEN")] + listen: std::net::SocketAddr, /// Enables the exporting of traces for OpenTelemetry. /// @@ -118,14 +118,14 @@ impl ValidatorCommand { .await }, Self::Start { - socket, + listen, grpc_options, validator_key, data_directory, kms_key_id, .. } => { - let address = socket; + let address = listen; // Run validator with KMS key backend if key id provided. if let Some(kms_key_id) = kms_key_id { diff --git a/docker-compose.yml b/docker-compose.yml index 804bf7d43..5d6220d42 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,9 +34,9 @@ services: - miden-node - store - start - - --rpc.socket=0.0.0.0:50001 - - --ntx-builder.socket=0.0.0.0:50002 - - --block-producer.socket=0.0.0.0:50003 + - --rpc.listen=0.0.0.0:50001 + - --ntx-builder.listen=0.0.0.0:50002 + - --block-producer.listen=0.0.0.0:50003 - --data-directory=/data/store - --account_tree.rocksdb.max_cache_size=4294967296 - --account_tree.rocksdb.max_open_fds=512 @@ -60,7 +60,7 @@ services: - miden-node - validator - start - - --socket=0.0.0.0:50101 + - --listen=0.0.0.0:50101 - --data-directory=/data/validator ports: - "50101:50101" @@ -76,7 +76,7 @@ services: - miden-node - block-producer - start - - --socket=0.0.0.0:50201 + - --listen=0.0.0.0:50201 - --store.url=http://store:50003 - --validator.url=http://validator:50101 ports: @@ -93,7 +93,7 @@ services: - miden-node - rpc - start - - --socket=0.0.0.0:57291 + - --listen=0.0.0.0:57291 - --store.url=http://store:50001 - --block-producer.url=http://block-producer:50201 - --validator.url=http://validator:50101 @@ -113,7 +113,7 @@ services: - miden-node - ntx-builder - start - - --socket=0.0.0.0:50301 + - --listen=0.0.0.0:50301 - --store.url=http://store:50002 - --block-producer.url=http://block-producer:50201 - --validator.url=http://validator:50101 diff --git a/docs/external/src/operator/usage.md b/docs/external/src/operator/usage.md index e6f4e6860..d51d007ab 100644 --- a/docs/external/src/operator/usage.md +++ b/docs/external/src/operator/usage.md @@ -160,30 +160,30 @@ Each component can also be started as a standalone process. For example: ```sh # Start the store miden-node store start \ - --rpc.socket 0.0.0.0:50001 \ - --ntx-builder.socket 0.0.0.0:50002 \ - --block-producer.socket 0.0.0.0:50003 \ + --rpc.listen 0.0.0.0:50001 \ + --ntx-builder.listen 0.0.0.0:50002 \ + --block-producer.listen 0.0.0.0:50003 \ --data-directory /tmp/store # Start the validator -miden-node validator start --socket 0.0.0.0:50101 \ +miden-node validator start --listen 0.0.0.0:50101 \ --data-directory /tmp/validator # Start the block producer -miden-node block-producer start --socket 0.0.0.0:50201 \ +miden-node block-producer start --listen 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 \ - --socket 0.0.0.0:57291 \ + --listen 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 \ - --socket 0.0.0.0:50301 \ + --listen 0.0.0.0:50301 \ --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 \ @@ -227,7 +227,7 @@ Compaction parallelism is set automatically to the number of available CPU cores ```sh miden-node store start \ --data-directory data \ - --rpc.socket 0.0.0.0:57291 \ + --rpc.listen 0.0.0.0:57291 \ --account_tree.rocksdb.max_cache_size 4294967296 \ --account_tree.rocksdb.max_open_fds 512 \ --nullifier_tree.rocksdb.max_cache_size 4294967296 \ diff --git a/scripts/run-node.sh b/scripts/run-node.sh index fc8589644..553f73ab7 100755 --- a/scripts/run-node.sh +++ b/scripts/run-node.sh @@ -107,9 +107,9 @@ echo "=== Starting components ===" echo "Starting store (block-producer mode)..." $BINARY store start \ - --rpc.socket "0.0.0.0:$STORE_RPC_PORT" \ - --ntx-builder.socket "0.0.0.0:$STORE_NTX_BUILDER_PORT" \ - --block-producer.socket "0.0.0.0:$STORE_BLOCK_PRODUCER_PORT" \ + --rpc.listen "0.0.0.0:$STORE_RPC_PORT" \ + --ntx-builder.listen "0.0.0.0:$STORE_NTX_BUILDER_PORT" \ + --block-producer.listen "0.0.0.0:$STORE_BLOCK_PRODUCER_PORT" \ --data-directory "$STORE_DIR" & PIDS+=($!) @@ -119,7 +119,7 @@ if [[ -n "$KMS_KEY_ID" ]]; then fi echo "Starting validator..." -$BINARY validator start --socket "0.0.0.0:$VALIDATOR_PORT" \ +$BINARY validator start --listen "0.0.0.0:$VALIDATOR_PORT" \ --data-directory "$VALIDATOR_DIR" \ "${KMS_START_ARGS[@]+"${KMS_START_ARGS[@]}"}" & PIDS+=($!) @@ -130,7 +130,7 @@ sleep 2 # Replica 1 syncs from the primary store. echo "Starting store replica 1 (upstream: primary store at 127.0.0.1:$STORE_RPC_PORT)..." $BINARY store start-replica \ - --rpc.socket "0.0.0.0:$STORE_REPLICA_1_RPC_PORT" \ + --rpc.listen "0.0.0.0:$STORE_REPLICA_1_RPC_PORT" \ --upstream-store.url "http://127.0.0.1:$STORE_RPC_PORT" \ --data-directory "$STORE_REPLICA_1_DIR" & PIDS+=($!) @@ -138,20 +138,20 @@ PIDS+=($!) # Replica 2 syncs from replica 1, proving replicas can act as upstreams. echo "Starting store replica 2 (upstream: replica 1 at 127.0.0.1:$STORE_REPLICA_1_RPC_PORT)..." $BINARY store start-replica \ - --rpc.socket "0.0.0.0:$STORE_REPLICA_2_RPC_PORT" \ + --rpc.listen "0.0.0.0:$STORE_REPLICA_2_RPC_PORT" \ --upstream-store.url "http://127.0.0.1:$STORE_REPLICA_1_RPC_PORT" \ --data-directory "$STORE_REPLICA_2_DIR" & PIDS+=($!) echo "Starting block producer..." -$BINARY block-producer start --socket "0.0.0.0:$BLOCK_PRODUCER_PORT" \ +$BINARY block-producer start --listen "0.0.0.0:$BLOCK_PRODUCER_PORT" \ --store.url "http://127.0.0.1:$STORE_BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & PIDS+=($!) echo "Starting RPC server (primary store)..." $BINARY rpc start \ - --socket "0.0.0.0:$RPC_PORT" \ + --listen "0.0.0.0:$RPC_PORT" \ --store.url "http://127.0.0.1:$STORE_RPC_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & @@ -159,7 +159,7 @@ PIDS+=($!) echo "Starting RPC server (replica 1)..." $BINARY rpc start \ - --socket "0.0.0.0:$RPC_REPLICA_1_PORT" \ + --listen "0.0.0.0:$RPC_REPLICA_1_PORT" \ --store.url "http://127.0.0.1:$STORE_REPLICA_1_RPC_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & @@ -167,7 +167,7 @@ PIDS+=($!) echo "Starting RPC server (replica 2)..." $BINARY rpc start \ - --socket "0.0.0.0:$RPC_REPLICA_2_PORT" \ + --listen "0.0.0.0:$RPC_REPLICA_2_PORT" \ --store.url "http://127.0.0.1:$STORE_REPLICA_2_RPC_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" & @@ -175,7 +175,7 @@ PIDS+=($!) echo "Starting network transaction builder..." $BINARY ntx-builder start \ - --socket "0.0.0.0:$NTX_BUILDER_PORT" \ + --listen "0.0.0.0:$NTX_BUILDER_PORT" \ --store.url "http://127.0.0.1:$STORE_NTX_BUILDER_PORT" \ --block-producer.url "http://127.0.0.1:$BLOCK_PRODUCER_PORT" \ --validator.url "http://127.0.0.1:$VALIDATOR_PORT" \ From 26f916598092b74e1007a29f4602ed833166c059 Mon Sep 17 00:00:00 2001 From: sergerad Date: Fri, 8 May 2026 12:21:13 +1200 Subject: [PATCH 10/10] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba41614a8..9a36a7487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,8 @@ - Replaced the network monitor's JavaScript dashboard with a server-rendered Maud + HTMX frontend ([#2024](https://github.com/0xMiden/node/pull/2024)). - [BREAKING] Removed `CheckNullifiers` endpoint ([#2049](https://github.com/0xMiden/node/pull/2049)). - [BREAKING] Replaced binding URL env vars and CLI flags with listen socket addresses ([#2054](https://github.com/0xMiden/node/pull/2054)). -- [BREAKING] Renamed `--url` CLI flags and `*_URL` env vars to `--listen` / `*_LISTEN` across all components. - [BREAKING] `BlockRange.block_to` is now required for all RPC endpoints ([#2056](https://github.com/0xMiden/node/pull/2056)). +- [BREAKING] Renamed `--url` CLI flags and `*_URL` env vars to `--listen` / `*_LISTEN` across all components. ## v0.14.10 (2026-05-29)