From 0f542bb5fdecae76352ecdd52484fd016117aa5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:02:05 -0300 Subject: [PATCH] refactor(cli): move CliOptions into a dedicated cli module main.rs had grown to mix CLI parsing with node orchestration. Extract the CliOptions clap struct into its own bin/ethlambda/src/cli.rs so the flag surface lives in one place and main.rs reads as orchestration only. --- bin/ethlambda/src/cli.rs | 87 +++++++++++++++++++++++++++++++++++++++ bin/ethlambda/src/main.rs | 83 +------------------------------------ 2 files changed, 89 insertions(+), 81 deletions(-) create mode 100644 bin/ethlambda/src/cli.rs diff --git a/bin/ethlambda/src/cli.rs b/bin/ethlambda/src/cli.rs new file mode 100644 index 00000000..848a2446 --- /dev/null +++ b/bin/ethlambda/src/cli.rs @@ -0,0 +1,87 @@ +//! Command-line interface for the ethlambda binary. + +use std::net::IpAddr; +use std::path::PathBuf; + +use crate::version; + +#[derive(Debug, clap::Parser)] +#[command(name = "ethlambda", author = "LambdaClass", version = version::CLIENT_VERSION, about = "ethlambda consensus client")] +pub(crate) struct CliOptions { + /// Path to the chain genesis config (e.g., config.yaml). + #[arg(long)] + pub(crate) genesis: PathBuf, + /// Path to the validator registry (e.g., annotated_validators.yaml). + #[arg(long)] + pub(crate) validators: PathBuf, + /// Path to the bootnode list (e.g., nodes.yaml). + #[arg(long)] + pub(crate) bootnodes: PathBuf, + /// Path to validator-config.yaml (validator name registry for metrics labels). + #[arg(long)] + pub(crate) validator_config: PathBuf, + /// Directory containing per-validator XMSS keys (e.g., hash-sig-keys/). + #[arg(long)] + pub(crate) hash_sig_keys_dir: PathBuf, + #[arg(long, default_value = "9000")] + pub(crate) gossipsub_port: u16, + #[arg(long, default_value = "127.0.0.1")] + pub(crate) http_address: IpAddr, + #[arg(long, default_value = "5052")] + pub(crate) api_port: u16, + #[arg(long, default_value = "5054")] + pub(crate) metrics_port: u16, + #[arg(long)] + pub(crate) node_key: PathBuf, + /// The node ID to look up in annotated_validators.yaml (e.g., "ethlambda_0") + #[arg(long)] + pub(crate) node_id: String, + /// Base URL(s) of checkpoint-sync peer API servers (e.g., http://peer:5052). + /// When set, skips genesis initialization and fetches the finalized state + /// and block from each peer's `/lean/v0/states/finalized` and + /// `/lean/v0/blocks/finalized` endpoints. For backward compatibility, a + /// URL ending in `/lean/v0/states/finalized` is accepted and the trailing + /// path is stripped. + /// + /// Multiple URLs may be supplied for redundancy, either comma-separated + /// (`--checkpoint-sync-url u1,u2`) or by repeating the flag + /// (`--checkpoint-sync-url u1 --checkpoint-sync-url u2`). URLs are tried + /// in order; the first one that succeeds is used and any failures fall + /// over to the next URL. Startup only aborts if every URL fails. + #[arg(long, value_delimiter = ',')] + pub(crate) checkpoint_sync_url: Vec, + /// Whether this node acts as a committee aggregator. + /// + /// Seeds the initial value of the live aggregator flag shared by the + /// blockchain actor and the admin API. The flag can be toggled at + /// runtime via `POST /lean/v0/admin/aggregator`. Runtime toggles do + /// NOT persist across restarts and do NOT update gossip subnet + /// subscriptions, which are frozen at startup — standby aggregators + /// should boot with this flag enabled to establish subscriptions, then + /// use the admin endpoint to rotate duties (hot-standby model). + #[arg(long, default_value = "false")] + pub(crate) is_aggregator: bool, + /// Number of attestation committees (subnets) per slot. + /// + /// If unset, falls back to `config.attestation_committee_count` from + /// `validator-config.yaml` in the network config dir, or `1` if that + /// field is also absent. + #[arg(long, value_parser = clap::value_parser!(u64).range(1..))] + pub(crate) attestation_committee_count: Option, + /// Subnet IDs this aggregator should subscribe to (comma-separated). + /// Requires --is-aggregator. Defaults to the subnets of the node's validators. + #[arg(long, value_delimiter = ',', requires = "is_aggregator")] + pub(crate) aggregate_subnet_ids: Option>, + /// Directory for RocksDB storage + #[arg(long, default_value = "./data")] + pub(crate) data_dir: PathBuf, + /// Disable the sync-gate's suppression of validator duties. + /// + /// By default a node that judges itself to be syncing (local head lagging + /// wall clock while the network still progresses) skips block proposal, + /// attestation production, and aggregate re-derivation. With this flag the + /// sync state is still tracked and exported via `lean_node_sync_status`, + /// but it no longer suppresses any duty: the gate becomes observe-only. + #[arg(long, default_value = "false")] + pub(crate) disable_duty_sync_gate: bool, +} diff --git a/bin/ethlambda/src/main.rs b/bin/ethlambda/src/main.rs index 20f6fd48..d85b3e8d 100644 --- a/bin/ethlambda/src/main.rs +++ b/bin/ethlambda/src/main.rs @@ -1,4 +1,5 @@ mod checkpoint_sync; +mod cli; mod fd_limit; mod version; @@ -31,6 +32,7 @@ use std::{ use tokio_util::sync::CancellationToken; use clap::Parser; +use cli::CliOptions; use ethlambda_blockchain::MILLISECONDS_PER_SLOT; use ethlambda_blockchain::key_manager::ValidatorKeyPair; use ethlambda_network_api::{InitBlockChain, InitP2P, ToBlockChainToP2PRef, ToP2PToBlockChainRef}; @@ -61,87 +63,6 @@ const ASCII_ART: &str = r#" \___|\__|_| |_|_|\__,_|_| |_| |_|_.__/ \__,_|\__,_| "#; -#[derive(Debug, clap::Parser)] -#[command(name = "ethlambda", author = "LambdaClass", version = version::CLIENT_VERSION, about = "ethlambda consensus client")] -struct CliOptions { - /// Path to the chain genesis config (e.g., config.yaml). - #[arg(long)] - genesis: PathBuf, - /// Path to the validator registry (e.g., annotated_validators.yaml). - #[arg(long)] - validators: PathBuf, - /// Path to the bootnode list (e.g., nodes.yaml). - #[arg(long)] - bootnodes: PathBuf, - /// Path to validator-config.yaml (validator name registry for metrics labels). - #[arg(long)] - validator_config: PathBuf, - /// Directory containing per-validator XMSS keys (e.g., hash-sig-keys/). - #[arg(long)] - hash_sig_keys_dir: PathBuf, - #[arg(long, default_value = "9000")] - gossipsub_port: u16, - #[arg(long, default_value = "127.0.0.1")] - http_address: IpAddr, - #[arg(long, default_value = "5052")] - api_port: u16, - #[arg(long, default_value = "5054")] - metrics_port: u16, - #[arg(long)] - node_key: PathBuf, - /// The node ID to look up in annotated_validators.yaml (e.g., "ethlambda_0") - #[arg(long)] - node_id: String, - /// Base URL(s) of checkpoint-sync peer API servers (e.g., http://peer:5052). - /// When set, skips genesis initialization and fetches the finalized state - /// and block from each peer's `/lean/v0/states/finalized` and - /// `/lean/v0/blocks/finalized` endpoints. For backward compatibility, a - /// URL ending in `/lean/v0/states/finalized` is accepted and the trailing - /// path is stripped. - /// - /// Multiple URLs may be supplied for redundancy, either comma-separated - /// (`--checkpoint-sync-url u1,u2`) or by repeating the flag - /// (`--checkpoint-sync-url u1 --checkpoint-sync-url u2`). URLs are tried - /// in order; the first one that succeeds is used and any failures fall - /// over to the next URL. Startup only aborts if every URL fails. - #[arg(long, value_delimiter = ',')] - checkpoint_sync_url: Vec, - /// Whether this node acts as a committee aggregator. - /// - /// Seeds the initial value of the live aggregator flag shared by the - /// blockchain actor and the admin API. The flag can be toggled at - /// runtime via `POST /lean/v0/admin/aggregator`. Runtime toggles do - /// NOT persist across restarts and do NOT update gossip subnet - /// subscriptions, which are frozen at startup — standby aggregators - /// should boot with this flag enabled to establish subscriptions, then - /// use the admin endpoint to rotate duties (hot-standby model). - #[arg(long, default_value = "false")] - is_aggregator: bool, - /// Number of attestation committees (subnets) per slot. - /// - /// If unset, falls back to `config.attestation_committee_count` from - /// `validator-config.yaml` in the network config dir, or `1` if that - /// field is also absent. - #[arg(long, value_parser = clap::value_parser!(u64).range(1..))] - attestation_committee_count: Option, - /// Subnet IDs this aggregator should subscribe to (comma-separated). - /// Requires --is-aggregator. Defaults to the subnets of the node's validators. - #[arg(long, value_delimiter = ',', requires = "is_aggregator")] - aggregate_subnet_ids: Option>, - /// Directory for RocksDB storage - #[arg(long, default_value = "./data")] - data_dir: PathBuf, - /// Disable the sync-gate's suppression of validator duties. - /// - /// By default a node that judges itself to be syncing (local head lagging - /// wall clock while the network still progresses) skips block proposal, - /// attestation production, and aggregate re-derivation. With this flag the - /// sync state is still tracked and exported via `lean_node_sync_status`, - /// but it no longer suppresses any duty: the gate becomes observe-only. - #[arg(long, default_value = "false")] - disable_duty_sync_gate: bool, -} - // Shadow single-steps execution in a discrete-event simulation, so the default // multi-threaded runtime's worker threads add only scheduling noise, never // parallelism. Use a single-threaded runtime under Shadow. This is an