Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v0.13.5 (TBD)

- OpenTelemetry traces are now flushed before program termination on panic ([#1643](https://github.com/0xMiden/miden-node/pull/1643)).
- Added support for the note transport layer in the network monitor ([#1660](https://github.com/0xMiden/miden-node/pull/1660)).

## v0.13.4 (2026-02-04)

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ tokio = { features = ["rt-multi-thread"], version = "1.46" }
tokio-stream = { version = "0.1" }
toml = { version = "0.9" }
tonic = { default-features = false, version = "0.14" }
tonic-health = { version = "0.14" }
tonic-prost = { version = "0.14" }
tonic-prost-build = { version = "0.14" }
tonic-reflection = { version = "0.14" }
Expand Down
2 changes: 2 additions & 0 deletions bin/network-monitor/.env
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ MIDEN_MONITOR_COUNTER_INCREMENT_INTERVAL=30s
MIDEN_MONITOR_COUNTER_LATENCY_TIMEOUT=2m
# explorer checks
MIDEN_MONITOR_EXPLORER_URL=https://scan-backend-devnet-miden.eu-central-8.gateway.fm/graphql
# note transport checks
MIDEN_MONITOR_NOTE_TRANSPORT_URL=https://transport.miden.io
1 change: 1 addition & 0 deletions bin/network-monitor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ serde_json = { version = "1.0" }
sha2 = { version = "0.10" }
tokio = { features = ["full"], workspace = true }
tonic = { features = ["codegen", "tls-native-roots", "transport"], workspace = true }
tonic-health = { workspace = true }
tracing = { workspace = true }
url = { features = ["serde"], workspace = true }
9 changes: 9 additions & 0 deletions bin/network-monitor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ miden-network-monitor start --faucet-url http://localhost:8080 --enable-otel
- `--remote-prover-urls`: Comma-separated list of remote prover URLs. If omitted or empty, prover tasks are disabled.
- `--faucet-url`: Faucet service URL for testing. If omitted, faucet testing is disabled.
- `--explorer-url`: Explorer service GraphQL endpoint. If omitted, explorer checks are disabled.
- `--note-transport-url`: Note transport service URL for health checking. If omitted, note transport checks are disabled.
- `--disable-ntx-service`: Disable the network transaction service checks (enabled by default). The network transaction service consists of two components: counter increment (sending increment transactions) and counter tracking (monitoring counter value changes).
- `--remote-prover-test-interval`: Interval at which to test the remote provers services (default: `2m`)
- `--faucet-test-interval`: Interval at which to test the faucet services (default: `2m`)
Expand All @@ -54,6 +55,7 @@ If command-line arguments are not provided, the application falls back to enviro
- `MIDEN_MONITOR_REMOTE_PROVER_URLS`: Comma-separated list of remote prover URLs. If unset or empty, prover tasks are disabled.
- `MIDEN_MONITOR_FAUCET_URL`: Faucet service URL for testing. If unset, faucet testing is disabled.
- `MIDEN_MONITOR_EXPLORER_URL`: Explorer service GraphQL endpoint. If unset, explorer checks are disabled.
- `MIDEN_MONITOR_NOTE_TRANSPORT_URL`: Note transport service URL for health checking. If unset, note transport checks are disabled.
- `MIDEN_MONITOR_DISABLE_NTX_SERVICE`: Set to `true` to disable the network transaction service checks (enabled by default). This affects both counter increment and tracking components.
- `MIDEN_MONITOR_REMOTE_PROVER_TEST_INTERVAL`: Interval at which to test the remote provers services
- `MIDEN_MONITOR_FAUCET_TEST_INTERVAL`: Interval at which to test the faucet services
Expand All @@ -78,6 +80,7 @@ Starts the network monitoring service with the web dashboard. RPC status is alwa
- Prover checks/tests: enabled when `--remote-prover-urls` (or `MIDEN_MONITOR_REMOTE_PROVER_URLS`) is provided
- Faucet testing: enabled when `--faucet-url` (or `MIDEN_MONITOR_FAUCET_URL`) is provided
- Network transaction service: enabled when `--disable-ntx-service=false` or unset (or `MIDEN_MONITOR_DISABLE_NTX_SERVICE=false` or unset)
- Note transport checks: enabled when `--note-transport-url` (or `MIDEN_MONITOR_NOTE_TRANSPORT_URL`) is provided

```bash
# Start with default configuration (RPC only)
Expand Down Expand Up @@ -205,6 +208,12 @@ The monitor application provides real-time status monitoring for the following M
- Pending notes: How many transactions are queued/unprocessed
- Last updated timestamp

### Note Transport
- **Service Health**: Checks the note transport service via the standard gRPC Health Checking Protocol
- **Metrics**:
- Service URL
- gRPC serving status (Serving, NotServing, Unknown)

## User Interface

The web dashboard provides a clean, responsive interface with the following features:
Expand Down
24 changes: 23 additions & 1 deletion bin/network-monitor/assets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ function updateDisplay() {
detailsHtml = `
<div class="service-details">
${details.RpcStatus ? `
${details.RpcStatus.url ? `
<div class="detail-item"><strong>URL:</strong> ${details.RpcStatus.url}${renderCopyButton(details.RpcStatus.url, 'URL')}</div>
` : ''}
<div class="detail-item"><strong>Version:</strong> ${details.RpcStatus.version}</div>
${details.RpcStatus.genesis_commitment ? `
<div class="detail-item">
Expand Down Expand Up @@ -472,7 +475,7 @@ function updateDisplay() {
` : ''}
${details.RemoteProverStatus ? `
<div class="nested-status">
<strong>Prover Status (${details.RemoteProverStatus.url}):</strong>
<strong>Prover Status (${details.RemoteProverStatus.url}):</strong>${renderCopyButton(details.RemoteProverStatus.url, 'URL')}
<div class="detail-item"><strong>Version:</strong> ${details.RemoteProverStatus.version}</div>
<div class="nested-status">
<strong>Supported Proof Type:</strong> ${details.RemoteProverStatus.supported_proof_type}
Expand All @@ -496,6 +499,10 @@ function updateDisplay() {
<div class="nested-status">
<strong>Faucet:</strong>
<div class="test-metrics ${service.status === 'Healthy' ? 'healthy' : 'unhealthy'}">
<div class="metric-row">
<span class="metric-label">URL:</span>
<span class="metric-value">${details.FaucetTest.url}${renderCopyButton(details.FaucetTest.url, 'URL')}</span>
</div>
<div class="metric-row">
<span class="metric-label">Success Rate:</span>
<span class="metric-value">${formatSuccessRate(details.FaucetTest.success_count, details.FaucetTest.failure_count)}</span>
Expand Down Expand Up @@ -616,6 +623,21 @@ function updateDisplay() {
</div>
</div>
` : ''}
${details.NoteTransportStatus ? `
<div class="nested-status">
<strong>Note Transport:</strong>
<div class="test-metrics ${service.status === 'Healthy' ? 'healthy' : 'unhealthy'}">
<div class="metric-row">
<span class="metric-label">URL:</span>
<span class="metric-value">${details.NoteTransportStatus.url}${renderCopyButton(details.NoteTransportStatus.url, 'URL')}</span>
</div>
<div class="metric-row">
<span class="metric-label">Serving Status:</span>
<span class="metric-value">${details.NoteTransportStatus.serving_status}</span>
</div>
</div>
</div>
` : ''}
${service.testDetails ? `
<div class="nested-status">
<strong>Proof Generation Testing (${service.testDetails.proof_type}):</strong>
Expand Down
8 changes: 8 additions & 0 deletions bin/network-monitor/src/commands/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ pub async fn start_monitor(config: MonitorConfig) -> Result<()> {
None
};

// Initialize the note transport status checker task.
let note_transport_rx = if config.note_transport_url.is_some() {
Some(tasks.spawn_note_transport_checker(&config).await?)
} else {
None
};

// Initialize the prover checkers & tests tasks, only if URLs were provided.
let prover_rxs = if config.remote_prover_urls.is_empty() {
debug!(target: COMPONENT, "No remote prover URLs configured, skipping prover tasks");
Expand Down Expand Up @@ -85,6 +92,7 @@ pub async fn start_monitor(config: MonitorConfig) -> Result<()> {
ntx_increment: ntx_increment_rx,
ntx_tracking: ntx_tracking_rx,
explorer: explorer_rx,
note_transport: note_transport_rx,
};
tasks.spawn_http_server(server_state, &config);

Expand Down
8 changes: 8 additions & 0 deletions bin/network-monitor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ pub struct MonitorConfig {
)]
pub explorer_url: Option<Url>,

/// The URL of the note transport service.
#[arg(
long = "note-transport-url",
env = "MIDEN_MONITOR_NOTE_TRANSPORT_URL",
help = "The URL of the note transport service"
)]
pub note_transport_url: Option<Url>,

/// Maximum time without a chain tip update before marking RPC as unhealthy.
///
/// If the chain tip does not increment within this duration, the RPC service will be
Expand Down
2 changes: 2 additions & 0 deletions bin/network-monitor/src/faucet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const MINT_AMOUNT: u64 = 1_000_000; // 1 token with 6 decimals
/// Details of a faucet test.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FaucetTestDetails {
pub url: String,
pub test_duration_ms: u64,
pub success_count: u64,
pub failure_count: u64,
Expand Down Expand Up @@ -129,6 +130,7 @@ pub async fn run_faucet_test_task(
let test_duration_ms = start_time.elapsed().as_millis() as u64;

let test_details = FaucetTestDetails {
url: faucet_url.to_string(),
test_duration_ms,
success_count,
failure_count,
Expand Down
18 changes: 12 additions & 6 deletions bin/network-monitor/src/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct ServerState {
pub ntx_increment: Option<watch::Receiver<ServiceStatus>>,
pub ntx_tracking: Option<watch::Receiver<ServiceStatus>>,
pub explorer: Option<watch::Receiver<ServiceStatus>>,
pub note_transport: Option<watch::Receiver<ServiceStatus>>,
}

/// Runs the frontend server.
Expand Down Expand Up @@ -77,9 +78,9 @@ async fn get_status(
// Collect RPC status
services.push(server_state.rpc.borrow().clone());

// Collect explorer status if available
if let Some(explorer_rx) = &server_state.explorer {
services.push(explorer_rx.borrow().clone());
// Collect faucet status if available
if let Some(faucet_rx) = &server_state.faucet {
services.push(faucet_rx.borrow().clone());
}

// Collect all remote prover statuses
Expand All @@ -88,9 +89,9 @@ async fn get_status(
services.push(prover_test_rx.borrow().clone());
}

// Collect faucet status if available
if let Some(faucet_rx) = &server_state.faucet {
services.push(faucet_rx.borrow().clone());
// Collect explorer status if available
if let Some(explorer_rx) = &server_state.explorer {
services.push(explorer_rx.borrow().clone());
}

// Collect counter increment status if enabled
Expand All @@ -103,6 +104,11 @@ async fn get_status(
services.push(ntx_tracking_rx.borrow().clone());
}

// Collect note transport status if available
if let Some(note_transport_rx) = &server_state.note_transport {
services.push(note_transport_rx.borrow().clone());
}

let network_status = NetworkStatus { services, last_updated: current_time };

axum::response::Json(network_status)
Expand Down
1 change: 1 addition & 0 deletions bin/network-monitor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod explorer;
pub mod faucet;
pub mod frontend;
mod monitor;
pub mod note_transport;
pub mod remote_prover;
pub mod status;

Expand Down
35 changes: 35 additions & 0 deletions bin/network-monitor/src/monitor/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::deploy::ensure_accounts_exist;
use crate::explorer::{initial_explorer_status, run_explorer_status_task};
use crate::faucet::run_faucet_test_task;
use crate::frontend::{ServerState, serve};
use crate::note_transport::{initial_note_transport_status, run_note_transport_status_task};
use crate::remote_prover::{ProofType, generate_prover_test_payload, run_remote_prover_test_task};
use crate::status::{
ServiceStatus,
Expand Down Expand Up @@ -142,6 +143,39 @@ impl Tasks {
Ok(explorer_status_rx)
}

/// Spawn the note transport status checker task.
#[instrument(target = COMPONENT, name = "tasks.spawn-note-transport-checker", skip_all)]
pub async fn spawn_note_transport_checker(
&mut self,
config: &MonitorConfig,
) -> Result<Receiver<ServiceStatus>> {
let note_transport_url =
config.note_transport_url.clone().expect("Note transport URL exists");
let name = "Note Transport".to_string();
let status_check_interval = config.status_check_interval;
let request_timeout = config.request_timeout;
let (tx, rx) = watch::channel(initial_note_transport_status());

let id = self
.handles
.spawn(async move {
run_note_transport_status_task(
note_transport_url,
name,
tx,
status_check_interval,
request_timeout,
)
.await;
})
.id();
self.names.insert(id, "note-transport-checker".to_string());

println!("Spawned note transport status checker task");

Ok(rx)
}

/// Spawn prover status and test tasks for all configured provers.
#[instrument(
parent = None,
Expand Down Expand Up @@ -287,6 +321,7 @@ impl Tasks {
last_checked: current_time,
error: None,
details: crate::status::ServiceDetails::FaucetTest(crate::faucet::FaucetTestDetails {
url: config.faucet_url.as_ref().expect("faucet URL exists").to_string(),
test_duration_ms: 0,
success_count: 0,
failure_count: 0,
Expand Down
Loading
Loading