From 0bbb8e45783c91a8ac1c48b90b42652eaeb14a11 Mon Sep 17 00:00:00 2001 From: refcell Date: Sat, 31 Aug 2024 19:40:44 -0400 Subject: [PATCH] feat(hera): Subcommands (#63) ### Description > [!WARNING] > > Blocked by https://github.com/paradigmxyz/op-rs/pull/62. Splits the `hera` command into `network` and `node` subcommands to clean up the binary entrypoints. --- bin/hera/src/globals.rs | 19 ++++++++++ bin/hera/src/main.rs | 79 +++++++++++++++++------------------------ bin/hera/src/network.rs | 68 +++++++++++++++++++++++++++++++++++ bin/hera/src/node.rs | 17 +++++++++ 4 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 bin/hera/src/globals.rs create mode 100644 bin/hera/src/network.rs create mode 100644 bin/hera/src/node.rs diff --git a/bin/hera/src/globals.rs b/bin/hera/src/globals.rs new file mode 100644 index 0000000..6009e5c --- /dev/null +++ b/bin/hera/src/globals.rs @@ -0,0 +1,19 @@ +//! Global arguments for the Hera CLI. + +use clap::Parser; + +/// Global arguments for the Hera CLI. +#[derive(Parser, Clone, Debug)] +pub(crate) struct GlobalArgs { + /// The L2 chain ID to use. + #[clap(long, short = 'c', default_value = "10", help = "The L2 chain ID to use")] + pub l2_chain_id: u64, + /// A port to serve prometheus metrics on. + #[clap( + long, + short = 'm', + default_value = "9090", + help = "The port to serve prometheus metrics on" + )] + pub metrics_port: u16, +} diff --git a/bin/hera/src/main.rs b/bin/hera/src/main.rs index a030e45..bc132cd 100644 --- a/bin/hera/src/main.rs +++ b/bin/hera/src/main.rs @@ -4,60 +4,47 @@ #![doc(issue_tracker_base_url = "https://github.com/paradigmxyz/op-rs/issues/")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use clap::Parser; +use clap::{Parser, Subcommand}; use eyre::Result; -use op_net::driver::NetworkDriver; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use superchain_registry::ROLLUP_CONFIGS; -/// The default L2 chain ID to use. This corresponds to OP Mainnet. -pub const DEFAULT_L2_CHAIN_ID: u64 = 10; +mod globals; +mod network; +mod node; /// The Hera CLI Arguments. -#[derive(Debug, Clone, Parser)] -pub struct HeraArgs { - /// Chain ID of the L2 network - #[clap(long = "hera.l2-chain-id", default_value_t = DEFAULT_L2_CHAIN_ID)] - pub l2_chain_id: u64, +#[derive(Parser, Clone, Debug)] +#[command(author, version, about, long_about = None)] +pub(crate) struct HeraArgs { + /// Global arguments for the Hera CLI. + #[clap(flatten)] + pub global: globals::GlobalArgs, + /// The subcommand to run. + #[clap(subcommand)] + pub subcommand: HeraSubcommand, +} + +/// Subcommands for the CLI. +#[derive(Debug, Clone, Subcommand)] +pub(crate) enum HeraSubcommand { + /// Run the standalone Hera node. + Node(node::NodeCommand), + /// Networking utility commands. + Network(network::NetworkCommand), } #[tokio::main] async fn main() -> Result<()> { + // Parse arguments. let args = HeraArgs::parse(); - rollup::init_telemetry_stack(8090)?; - - tracing::info!("Hera OP Stack Rollup node"); - - let signer = ROLLUP_CONFIGS - .get(&args.l2_chain_id) - .ok_or(eyre::eyre!("No rollup config found for chain ID"))? - .genesis - .system_config - .as_ref() - .ok_or(eyre::eyre!("No system config found for chain ID"))? - .batcher_address; - let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 9099); - let mut driver = NetworkDriver::builder() - .with_chain_id(args.l2_chain_id) - .with_unsafe_block_signer(signer) - .with_gossip_addr(socket) - .build() - .expect("Failed to builder network driver"); - - // Call `.start()` on the driver. - let recv = driver.take_unsafe_block_recv().ok_or(eyre::eyre!("No unsafe block receiver"))?; - driver.start().expect("Failed to start network driver"); - - tracing::info!("NetworkDriver started successfully."); - - loop { - match recv.recv() { - Ok(block) => { - tracing::info!("Received unsafe block: {:?}", block); - } - Err(e) => { - tracing::warn!("Failed to receive unsafe block: {:?}", e); - } - } + + // Initialize the telemetry stack. + rollup::init_telemetry_stack(args.global.metrics_port)?; + + // Dispatch on subcommand. + match args.subcommand { + HeraSubcommand::Node(node) => node.run(&args.global).await?, + HeraSubcommand::Network(network) => network.run(&args.global).await?, } + + Ok(()) } diff --git a/bin/hera/src/network.rs b/bin/hera/src/network.rs new file mode 100644 index 0000000..d31e9d4 --- /dev/null +++ b/bin/hera/src/network.rs @@ -0,0 +1,68 @@ +//! Networking subcommand for Hera. + +use crate::globals::GlobalArgs; +use clap::Args; +use eyre::Result; +use op_net::driver::NetworkDriver; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use superchain_registry::ROLLUP_CONFIGS; + +/// The Hera network subcommand. +#[derive(Debug, Clone, Args)] +#[non_exhaustive] +pub struct NetworkCommand { + /// Run the peer discovery service. + #[clap(long, short = 'p', help = "Runs peer discovery")] + pub disc: bool, + /// Run the gossip driver. + #[clap(long, short = 'g', help = "Runs the unsafe block gossipping service")] + pub gossip: bool, + /// Port to listen for gossip on. + #[clap(long, short = 'l', default_value = "9099", help = "Port to listen for gossip on")] + pub gossip_port: u16, +} + +impl NetworkCommand { + /// Run the network subcommand. + pub async fn run(&self, args: &GlobalArgs) -> Result<()> { + if self.disc { + println!("Running peer discovery"); + } + if self.gossip { + println!("Running gossip driver"); + } + let signer = ROLLUP_CONFIGS + .get(&args.l2_chain_id) + .ok_or(eyre::eyre!("No rollup config found for chain ID"))? + .genesis + .system_config + .as_ref() + .ok_or(eyre::eyre!("No system config found for chain ID"))? + .batcher_address; + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), self.gossip_port); + let mut driver = NetworkDriver::builder() + .with_chain_id(args.l2_chain_id) + .with_unsafe_block_signer(signer) + .with_gossip_addr(socket) + .build() + .expect("Failed to builder network driver"); + + // Call `.start()` on the driver. + let recv = + driver.take_unsafe_block_recv().ok_or(eyre::eyre!("No unsafe block receiver"))?; + driver.start().expect("Failed to start network driver"); + + tracing::info!("NetworkDriver started successfully."); + + loop { + match recv.recv() { + Ok(block) => { + tracing::info!("Received unsafe block: {:?}", block); + } + Err(e) => { + tracing::warn!("Failed to receive unsafe block: {:?}", e); + } + } + } + } +} diff --git a/bin/hera/src/node.rs b/bin/hera/src/node.rs new file mode 100644 index 0000000..ce28077 --- /dev/null +++ b/bin/hera/src/node.rs @@ -0,0 +1,17 @@ +//! Node subcommand for Hera. + +use crate::globals::GlobalArgs; +use clap::Args; +use eyre::Result; + +/// The Hera node subcommand. +#[derive(Debug, Clone, Args)] +#[non_exhaustive] +pub struct NodeCommand {} + +impl NodeCommand { + /// Run the node subcommand. + pub async fn run(&self, _args: &GlobalArgs) -> Result<()> { + unimplemented!() + } +}