From cd71f689cdcd7c2ef99dd5af9d943196cfa3bf3a Mon Sep 17 00:00:00 2001 From: Alessandro Mazza <121622391+alessandromazza98@users.noreply.github.com> Date: Thu, 31 Aug 2023 03:58:02 +0200 Subject: [PATCH] feat: add a CLI flag for secondary nodes (#4029) Co-authored-by: Matthias Seitz --- bin/reth/src/cli/mod.rs | 18 ++++++++- bin/reth/src/node/mod.rs | 80 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/bin/reth/src/cli/mod.rs b/bin/reth/src/cli/mod.rs index d63ed72636..79b0ab00a6 100644 --- a/bin/reth/src/cli/mod.rs +++ b/bin/reth/src/cli/mod.rs @@ -10,7 +10,7 @@ use crate::{ stage, test_vectors, version::{LONG_VERSION, SHORT_VERSION}, }; -use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum}; +use clap::{value_parser, ArgAction, Args, Parser, Subcommand, ValueEnum}; use reth_primitives::ChainSpec; use reth_tracing::{ tracing::{metadata::LevelFilter, Level, Subscriber}, @@ -50,6 +50,22 @@ pub struct Cli { )] chain: Arc, + /// Add a new instance of a node. + /// + /// Configures the ports of the node to avoid conflicts with the defaults. + /// This is useful for running multiple nodes on the same machine. + /// + /// Max number of instances is 200. It is chosen in a way so that it's not possible to have + /// port numbers that conflict with each other. + /// + /// Changes to the following port numbers: + /// - DISCOVERY_PORT: default + `instance` - 1 + /// - AUTH_PORT: default + `instance` * 100 - 100 + /// - HTTP_RPC_PORT: default - `instance` + 1 + /// - WS_RPC_PORT: default + `instance` * 2 - 2 + #[arg(long, value_name = "INSTANCE", global = true, default_value_t = 1, value_parser = value_parser!(u16).range(..=200))] + instance: u16, + #[clap(flatten)] logs: Logs, diff --git a/bin/reth/src/node/mod.rs b/bin/reth/src/node/mod.rs index 84e0452489..b85ff1c68a 100644 --- a/bin/reth/src/node/mod.rs +++ b/bin/reth/src/node/mod.rs @@ -20,7 +20,7 @@ use crate::{ utils::get_single_header, version::SHORT_VERSION, }; -use clap::Parser; +use clap::{value_parser, Parser}; use eyre::Context; use fdlimit::raise_fd_limit; use futures::{future::Either, pin_mut, stream, stream_select, StreamExt}; @@ -127,9 +127,25 @@ pub struct NodeCommand { #[arg(long, value_name = "SOCKET", value_parser = parse_socket_address, help_heading = "Metrics")] pub metrics: Option, + /// Add a new instance of a node. + /// + /// Configures the ports of the node to avoid conflicts with the defaults. + /// This is useful for running multiple nodes on the same machine. + /// + /// Max number of instances is 200. It is chosen in a way so that it's not possible to have + /// port numbers that conflict with each other. + /// + /// Changes to the following port numbers: + /// - DISCOVERY_PORT: default + `instance` - 1 + /// - AUTH_PORT: default + `instance` * 100 - 100 + /// - HTTP_RPC_PORT: default - `instance` + 1 + /// - WS_RPC_PORT: default + `instance` * 2 - 2 + #[arg(long, value_name = "INSTANCE", global = true, default_value_t = 1, value_parser = value_parser!(u16).range(..=200))] + pub instance: u16, + /// Overrides the KZG trusted setup by reading from the supplied file. #[arg(long, value_name = "PATH")] - trusted_setup_file: Option, + pub trusted_setup_file: Option, /// All networking related arguments #[clap(flatten)] @@ -177,6 +193,7 @@ impl NodeCommand { chain, metrics, trusted_setup_file, + instance, network, rpc, txpool, @@ -192,6 +209,7 @@ impl NodeCommand { config, chain, metrics, + instance, trusted_setup_file, network, rpc, @@ -487,6 +505,9 @@ impl NodeCommand { let default_jwt_path = data_dir.jwt_path(); let jwt_secret = self.rpc.jwt_secret(default_jwt_path)?; + // adjust rpc port numbers based on instance number + self.adjust_instance_ports(); + // Start RPC servers let (_rpc_server, _auth_server) = self .rpc @@ -733,11 +754,19 @@ impl NodeCommand { .set_head(head) .listener_addr(SocketAddr::V4(SocketAddrV4::new( Ipv4Addr::UNSPECIFIED, - self.network.port.unwrap_or(DEFAULT_DISCOVERY_PORT), + // set discovery port based on instance number + match self.network.port { + Some(port) => port + self.instance - 1, + None => DEFAULT_DISCOVERY_PORT + self.instance - 1, + }, ))) .discovery_addr(SocketAddr::V4(SocketAddrV4::new( Ipv4Addr::UNSPECIFIED, - self.network.discovery.port.unwrap_or(DEFAULT_DISCOVERY_PORT), + // set discovery port based on instance number + match self.network.port { + Some(port) => port + self.instance - 1, + None => DEFAULT_DISCOVERY_PORT + self.instance - 1, + }, ))) .build(ProviderFactory::new(db, self.chain.clone())) } @@ -845,6 +874,16 @@ impl NodeCommand { Ok(pipeline) } + + /// Change rpc port numbers based on the instance number. + fn adjust_instance_ports(&mut self) { + // auth port is scaled by a factor of instance * 100 + self.rpc.auth_port += self.instance * 100 - 100; + // http port is scaled by a factor of -instance + self.rpc.http_port -= self.instance - 1; + // ws port is scaled by a factor of instance * 2 + self.rpc.ws_port += self.instance * 2 - 2; + } } /// Drives the [NetworkManager] future until a [Shutdown](reth_tasks::shutdown::Shutdown) signal is @@ -976,4 +1015,37 @@ mod tests { assert!(cmd.dev.dev); } + + #[test] + fn parse_instance() { + let mut cmd = NodeCommand::<()>::parse_from(["reth"]); + cmd.adjust_instance_ports(); + cmd.network.port = Some(DEFAULT_DISCOVERY_PORT + cmd.instance - 1); + // check rpc port numbers + assert_eq!(cmd.rpc.auth_port, 8551); + assert_eq!(cmd.rpc.http_port, 8545); + assert_eq!(cmd.rpc.ws_port, 8546); + // check network listening port number + assert_eq!(cmd.network.port.unwrap(), 30303); + + let mut cmd = NodeCommand::<()>::parse_from(["reth", "--instance", "2"]); + cmd.adjust_instance_ports(); + cmd.network.port = Some(DEFAULT_DISCOVERY_PORT + cmd.instance - 1); + // check rpc port numbers + assert_eq!(cmd.rpc.auth_port, 8651); + assert_eq!(cmd.rpc.http_port, 8544); + assert_eq!(cmd.rpc.ws_port, 8548); + // check network listening port number + assert_eq!(cmd.network.port.unwrap(), 30304); + + let mut cmd = NodeCommand::<()>::parse_from(["reth", "--instance", "3"]); + cmd.adjust_instance_ports(); + cmd.network.port = Some(DEFAULT_DISCOVERY_PORT + cmd.instance - 1); + // check rpc port numbers + assert_eq!(cmd.rpc.auth_port, 8751); + assert_eq!(cmd.rpc.http_port, 8543); + assert_eq!(cmd.rpc.ws_port, 8550); + // check network listening port number + assert_eq!(cmd.network.port.unwrap(), 30305); + } }