From b7b5dd7ec9a765542a20d77be8e8defde92b0a50 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Fri, 12 Jul 2024 07:52:09 +0100 Subject: [PATCH] Change DB Manager Clap usage to derive (#5898) * implement clap derive for the db manager * tweak some clap configs * make cli local * add global to help flag * fmt * Merge branch 'unstable' of https://github.com/sigp/lighthouse into HEAD * merge * add enum constraints to flag --- Cargo.lock | 14 ++ Cargo.toml | 2 +- beacon_node/src/config.rs | 11 +- book/src/help_general.md | 2 +- database_manager/Cargo.toml | 1 + database_manager/src/cli.rs | 229 ++++++++++++++++++++++++ database_manager/src/lib.rs | 343 ++++++++---------------------------- lighthouse/src/cli.rs | 9 + lighthouse/src/main.rs | 25 +-- 9 files changed, 349 insertions(+), 287 deletions(-) create mode 100644 database_manager/src/cli.rs create mode 100644 lighthouse/src/cli.rs diff --git a/Cargo.lock b/Cargo.lock index 317b30d960..28f1284068 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,6 +1340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -1355,6 +1356,18 @@ dependencies = [ "terminal_size", ] +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "clap_lex" version = "0.7.0" @@ -1824,6 +1837,7 @@ dependencies = [ "clap_utils", "environment", "hex", + "serde", "slog", "store", "strum", diff --git a/Cargo.toml b/Cargo.toml index b3532dda35..a76ee7e236 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,7 @@ bincode = "1" bitvec = "1" byteorder = "1" bytes = "1" -clap = { version = "4.5.4", features = ["cargo", "wrap_help"] } +clap = { version = "4.5.4", features = ["derive", "cargo", "wrap_help"] } # Turn off c-kzg's default features which include `blst/portable`. We can turn on blst's portable # feature ourselves when desired. c-kzg = { version = "1", default-features = false } diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 35fad0718c..b3c91631c0 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -402,7 +402,10 @@ pub fn get_config( client_config.blobs_db_path = Some(PathBuf::from(blobs_db_dir)); } - let (sprp, sprp_explicit) = get_slots_per_restore_point::(cli_args)?; + let (sprp, sprp_explicit) = get_slots_per_restore_point::(clap_utils::parse_optional( + cli_args, + "slots-per-restore-point", + )?)?; client_config.store.slots_per_restore_point = sprp; client_config.store.slots_per_restore_point_set_explicitly = sprp_explicit; @@ -1476,11 +1479,9 @@ pub fn get_data_dir(cli_args: &ArgMatches) -> PathBuf { /// /// Return `(sprp, set_explicitly)` where `set_explicitly` is `true` if the user provided the value. pub fn get_slots_per_restore_point( - cli_args: &ArgMatches, + slots_per_restore_point: Option, ) -> Result<(u64, bool), String> { - if let Some(slots_per_restore_point) = - clap_utils::parse_optional(cli_args, "slots-per-restore-point")? - { + if let Some(slots_per_restore_point) = slots_per_restore_point { Ok((slots_per_restore_point, true)) } else { let default = std::cmp::min( diff --git a/book/src/help_general.md b/book/src/help_general.md index a8cd459614..47ebe60983 100644 --- a/book/src/help_general.md +++ b/book/src/help_general.md @@ -23,7 +23,7 @@ Commands: is the recommended way to provide a network boot-node since it has a reduced attack surface compared to a full beacon node. database_manager - Manage a beacon node database [aliases: db] + Manage a beacon node database. [aliases: db] validator_client When connected to a beacon node, performs the duties of a staked validator (e.g., proposing blocks and attestations). [aliases: v, vc, diff --git a/database_manager/Cargo.toml b/database_manager/Cargo.toml index 250188e2db..96176f3fba 100644 --- a/database_manager/Cargo.toml +++ b/database_manager/Cargo.toml @@ -14,3 +14,4 @@ store = { workspace = true } types = { workspace = true } slog = { workspace = true } strum = { workspace = true } +serde = { workspace = true } diff --git a/database_manager/src/cli.rs b/database_manager/src/cli.rs new file mode 100644 index 0000000000..5521b97805 --- /dev/null +++ b/database_manager/src/cli.rs @@ -0,0 +1,229 @@ +pub use clap::{Arg, ArgAction, Args, Command, FromArgMatches, Parser}; +use clap_utils::get_color_style; +use clap_utils::FLAG_HEADER; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +use crate::InspectTarget; + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap( + name = "database_manager", + visible_alias = "db", + about = "Manage a beacon node database.", + styles = get_color_style(), + next_line_help = true, + term_width = 80, + disable_help_flag = true, + disable_help_subcommand = true, + display_order = 0, +)] +pub struct DatabaseManager { + #[clap( + long, + value_name = "SLOT_COUNT", + help = "Specifies how often a freezer DB restore point should be stored. \ + Cannot be changed after initialization. \ + [default: 2048 (mainnet) or 64 (minimal)]", + display_order = 0 + )] + pub slots_per_restore_point: Option, + + #[clap( + long, + value_name = "DIR", + help = "Data directory for the freezer database.", + display_order = 0 + )] + pub freezer_dir: Option, + + #[clap( + long, + value_name = "EPOCHS", + default_value_t = 0, + help = "The margin for blob pruning in epochs. The oldest blobs are pruned \ + up until data_availability_boundary - blob_prune_margin_epochs.", + display_order = 0 + )] + pub blob_prune_margin_epochs: u64, + + #[clap( + long, + value_name = "DIR", + help = "Data directory for the blobs database.", + display_order = 0 + )] + pub blobs_dir: Option, + + #[clap( + long, + global = true, + help = "Prints help information", + action = clap::ArgAction::HelpLong, + display_order = 0, + help_heading = FLAG_HEADER + )] + help: Option, + + #[clap(subcommand)] + pub subcommand: DatabaseManagerSubcommand, +} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap(rename_all = "kebab-case")] +pub enum DatabaseManagerSubcommand { + Migrate(Migrate), + Inspect(Inspect), + Version(Version), + PrunePayloads(PrunePayloads), + PruneBlobs(PruneBlobs), + PruneStates(PruneStates), + Compact(Compact), +} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap(about = "Migrate the database to a specific schema version.")] +pub struct Migrate { + #[clap( + long, + value_name = "VERSION", + help = "Schema version to migrate to", + display_order = 0 + )] + pub to: u64, +} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap(about = "Inspect raw database values.")] +pub struct Inspect { + #[clap( + long, + value_name = "TAG", + help = "3-byte column ID (see `DBColumn`)", + display_order = 0 + )] + pub column: String, + + #[clap( + long, + value_enum, + value_name = "TARGET", + default_value_t = InspectTarget::ValueSizes, + help = "Select the type of output to show", + display_order = 0, + )] + pub output: InspectTarget, + + #[clap( + long, + value_name = "N", + help = "Skip over the first N keys", + display_order = 0 + )] + pub skip: Option, + + #[clap( + long, + value_name = "N", + help = "Output at most N keys", + display_order = 0 + )] + pub limit: Option, + + #[clap( + long, + conflicts_with = "blobs_db", + help = "Inspect the freezer DB rather than the hot DB", + display_order = 0, + help_heading = FLAG_HEADER + )] + pub freezer: bool, + + #[clap( + long, + conflicts_with = "freezer", + help = "Inspect the blobs DB rather than the hot DB", + display_order = 0, + help_heading = FLAG_HEADER + )] + pub blobs_db: bool, + + #[clap( + long, + value_name = "DIR", + help = "Base directory for the output files. Defaults to the current directory", + display_order = 0 + )] + pub output_dir: Option, +} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap(about = "Display database schema version.", visible_aliases = &["v"])] +pub struct Version {} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap( + about = "Prune finalized execution payloads.", + alias = "prune_payloads" +)] +pub struct PrunePayloads {} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap( + about = "Prune blobs older than data availability boundary.", + alias = "prune_blobs" +)] +pub struct PruneBlobs {} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap( + about = "Prune all beacon states from the freezer database.", + alias = "prune_states" +)] +pub struct PruneStates { + #[clap( + long, + help = "Commit to pruning states irreversably. Without this flag the command will \ + just check that the database is capable of being pruned.", + help_heading = FLAG_HEADER, + )] + pub confirm: bool, +} + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[clap(about = "Compact database manually.")] +pub struct Compact { + #[clap( + long, + value_name = "TAG", + help = "3-byte column ID (see `DBColumn`)", + display_order = 0 + )] + pub column: String, + + #[clap( + long, + conflicts_with = "blobs_db", + help = "Inspect the freezer DB rather than the hot DB", + display_order = 0, + help_heading = FLAG_HEADER + )] + pub freezer: bool, + + #[clap( + long, + conflicts_with = "freezer", + help = "Inspect the blobs DB rather than the hot DB", + display_order = 0, + help_heading = FLAG_HEADER + )] + pub blobs_db: bool, + + #[clap( + long, + value_name = "DIR", + help = "Base directory for the output files. Defaults to the current directory", + display_order = 0 + )] + pub output_dir: Option, +} diff --git a/database_manager/src/lib.rs b/database_manager/src/lib.rs index fafff0f0f9..c5344f1f92 100644 --- a/database_manager/src/lib.rs +++ b/database_manager/src/lib.rs @@ -1,11 +1,17 @@ +pub mod cli; +use crate::cli::DatabaseManager; +use crate::cli::Migrate; +use crate::cli::PruneStates; use beacon_chain::{ builder::Witness, eth1_chain::CachingEth1Backend, schema_change::migrate_schema, slot_clock::SystemTimeSlotClock, }; use beacon_node::{get_data_dir, get_slots_per_restore_point, ClientConfig}; -use clap::{Arg, ArgAction, ArgMatches, Command}; -use clap_utils::{get_color_style, FLAG_HEADER}; +use clap::ArgMatches; +use clap::ValueEnum; +use cli::{Compact, Inspect}; use environment::{Environment, RuntimeContext}; +use serde::{Deserialize, Serialize}; use slog::{info, warn, Logger}; use std::fs; use std::io::Write; @@ -16,250 +22,30 @@ use store::{ metadata::{SchemaVersion, CURRENT_SCHEMA_VERSION}, DBColumn, HotColdDB, KeyValueStore, LevelDB, }; -use strum::{EnumString, EnumVariantNames, VariantNames}; +use strum::{EnumString, EnumVariantNames}; use types::{BeaconState, EthSpec, Slot}; -pub const CMD: &str = "database_manager"; - -pub fn version_cli_app() -> Command { - Command::new("version") - .visible_aliases(["v"]) - .styles(get_color_style()) - .about("Display database schema version") -} - -pub fn migrate_cli_app() -> Command { - Command::new("migrate") - .styles(get_color_style()) - .about("Migrate the database to a specific schema version") - .arg( - Arg::new("to") - .long("to") - .value_name("VERSION") - .help("Schema version to migrate to") - .action(ArgAction::Set) - .required(true), - ) -} - -pub fn inspect_cli_app() -> Command { - Command::new("inspect") - .styles(get_color_style()) - .about("Inspect raw database values") - .arg( - Arg::new("column") - .long("column") - .value_name("TAG") - .help("3-byte column ID (see `DBColumn`)") - .action(ArgAction::Set) - .required(true) - .display_order(0), - ) - .arg( - Arg::new("output") - .long("output") - .value_name("TARGET") - .help("Select the type of output to show") - .default_value("sizes") - .value_parser(InspectTarget::VARIANTS.to_vec()) - .display_order(0), - ) - .arg( - Arg::new("skip") - .long("skip") - .value_name("N") - .help("Skip over the first N keys") - .display_order(0), - ) - .arg( - Arg::new("limit") - .long("limit") - .value_name("N") - .help("Output at most N keys") - .display_order(0), - ) - .arg( - Arg::new("freezer") - .long("freezer") - .help("Inspect the freezer DB rather than the hot DB") - .action(ArgAction::SetTrue) - .help_heading(FLAG_HEADER) - .conflicts_with("blobs-db") - .display_order(0), - ) - .arg( - Arg::new("blobs-db") - .long("blobs-db") - .help("Inspect the blobs DB rather than the hot DB") - .action(ArgAction::SetTrue) - .help_heading(FLAG_HEADER) - .conflicts_with("freezer") - .display_order(0), - ) - .arg( - Arg::new("output-dir") - .long("output-dir") - .value_name("DIR") - .help("Base directory for the output files. Defaults to the current directory") - .action(ArgAction::Set) - .display_order(0), - ) -} - -pub fn compact_cli_app() -> Command { - Command::new("compact") - .styles(get_color_style()) - .about("Compact database manually") - .arg( - Arg::new("column") - .long("column") - .value_name("TAG") - .help("3-byte column ID (see `DBColumn`)") - .action(ArgAction::Set) - .required(true) - .display_order(0), - ) - .arg( - Arg::new("freezer") - .long("freezer") - .help("Inspect the freezer DB rather than the hot DB") - .action(ArgAction::SetTrue) - .help_heading(FLAG_HEADER) - .conflicts_with("blobs-db") - .display_order(0), - ) - .arg( - Arg::new("blobs-db") - .long("blobs-db") - .help("Inspect the blobs DB rather than the hot DB") - .action(ArgAction::SetTrue) - .help_heading(FLAG_HEADER) - .conflicts_with("freezer") - .display_order(0), - ) -} - -pub fn prune_payloads_app() -> Command { - Command::new("prune-payloads") - .alias("prune_payloads") - .styles(get_color_style()) - .about("Prune finalized execution payloads") -} - -pub fn prune_blobs_app() -> Command { - Command::new("prune-blobs") - .alias("prune_blobs") - .styles(get_color_style()) - .about("Prune blobs older than data availability boundary") -} - -pub fn prune_states_app() -> Command { - Command::new("prune-states") - .alias("prune_states") - .arg( - Arg::new("confirm") - .long("confirm") - .help( - "Commit to pruning states irreversably. Without this flag the command will \ - just check that the database is capable of being pruned.", - ) - .action(ArgAction::SetTrue) - .help_heading(FLAG_HEADER) - .display_order(0), - ) - .styles(get_color_style()) - .about("Prune all beacon states from the freezer database") -} - -pub fn cli_app() -> Command { - Command::new(CMD) - .display_order(0) - .visible_aliases(["db"]) - .styles(get_color_style()) - .about("Manage a beacon node database") - .arg( - Arg::new("help") - .long("help") - .short('h') - .help("Prints help information") - .action(ArgAction::HelpLong) - .display_order(0) - .help_heading(FLAG_HEADER), - ) - .arg( - Arg::new("slots-per-restore-point") - .long("slots-per-restore-point") - .value_name("SLOT_COUNT") - .help( - "Specifies how often a freezer DB restore point should be stored. \ - Cannot be changed after initialization. \ - [default: 2048 (mainnet) or 64 (minimal)]", - ) - .action(ArgAction::Set) - .display_order(0), - ) - .arg( - Arg::new("freezer-dir") - .long("freezer-dir") - .value_name("DIR") - .help("Data directory for the freezer database.") - .action(ArgAction::Set) - .display_order(0), - ) - .arg( - Arg::new("blob-prune-margin-epochs") - .long("blob-prune-margin-epochs") - .value_name("EPOCHS") - .help( - "The margin for blob pruning in epochs. The oldest blobs are pruned \ - up until data_availability_boundary - blob_prune_margin_epochs.", - ) - .action(ArgAction::Set) - .default_value("0") - .display_order(0), - ) - .arg( - Arg::new("blobs-dir") - .long("blobs-dir") - .value_name("DIR") - .help("Data directory for the blobs database.") - .action(ArgAction::Set) - .display_order(0), - ) - .subcommand(migrate_cli_app()) - .subcommand(version_cli_app()) - .subcommand(inspect_cli_app()) - .subcommand(compact_cli_app()) - .subcommand(prune_payloads_app()) - .subcommand(prune_blobs_app()) - .subcommand(prune_states_app()) -} - fn parse_client_config( cli_args: &ArgMatches, + database_manager_config: &DatabaseManager, _env: &Environment, ) -> Result { let mut client_config = ClientConfig::default(); client_config.set_data_dir(get_data_dir(cli_args)); + client_config + .freezer_db_path + .clone_from(&database_manager_config.freezer_dir); + client_config + .blobs_db_path + .clone_from(&database_manager_config.blobs_dir); - if let Some(freezer_dir) = clap_utils::parse_optional(cli_args, "freezer-dir")? { - client_config.freezer_db_path = Some(freezer_dir); - } + let (sprp, sprp_explicit) = + get_slots_per_restore_point::(database_manager_config.slots_per_restore_point)?; - if let Some(blobs_db_dir) = clap_utils::parse_optional(cli_args, "blobs-dir")? { - client_config.blobs_db_path = Some(blobs_db_dir); - } - - let (sprp, sprp_explicit) = get_slots_per_restore_point::(cli_args)?; client_config.store.slots_per_restore_point = sprp; client_config.store.slots_per_restore_point_set_explicitly = sprp_explicit; - - if let Some(blob_prune_margin_epochs) = - clap_utils::parse_optional(cli_args, "blob-prune-margin-epochs")? - { - client_config.store.blob_prune_margin_epochs = blob_prune_margin_epochs; - } + client_config.store.blob_prune_margin_epochs = database_manager_config.blob_prune_margin_epochs; Ok(client_config) } @@ -301,15 +87,21 @@ pub fn display_db_version( Ok(()) } -#[derive(Debug, PartialEq, Eq, EnumString, EnumVariantNames)] +#[derive( + Debug, PartialEq, Eq, Clone, EnumString, Deserialize, Serialize, EnumVariantNames, ValueEnum, +)] pub enum InspectTarget { #[strum(serialize = "sizes")] + #[clap(name = "sizes")] ValueSizes, #[strum(serialize = "total")] + #[clap(name = "total")] ValueTotal, #[strum(serialize = "values")] + #[clap(name = "values")] Values, #[strum(serialize = "gaps")] + #[clap(name = "gaps")] Gaps, } @@ -324,16 +116,18 @@ pub struct InspectConfig { output_dir: PathBuf, } -fn parse_inspect_config(cli_args: &ArgMatches) -> Result { - let column = clap_utils::parse_required(cli_args, "column")?; - let target = clap_utils::parse_required(cli_args, "output")?; - let skip = clap_utils::parse_optional(cli_args, "skip")?; - let limit = clap_utils::parse_optional(cli_args, "limit")?; - let freezer = cli_args.get_flag("freezer"); - let blobs_db = cli_args.get_flag("blobs-db"); +fn parse_inspect_config(inspect_config: &Inspect) -> Result { + let column: DBColumn = inspect_config + .column + .parse() + .map_err(|e| format!("Unable to parse column flag: {e:?}"))?; + let target: InspectTarget = inspect_config.output.clone(); + let skip = inspect_config.skip; + let limit = inspect_config.limit; + let freezer = inspect_config.freezer; + let blobs_db = inspect_config.blobs_db; - let output_dir: PathBuf = - clap_utils::parse_optional(cli_args, "output-dir")?.unwrap_or_else(PathBuf::new); + let output_dir: PathBuf = inspect_config.output_dir.clone().unwrap_or_default(); Ok(InspectConfig { column, target, @@ -450,10 +244,13 @@ pub struct CompactConfig { blobs_db: bool, } -fn parse_compact_config(cli_args: &ArgMatches) -> Result { - let column = clap_utils::parse_required(cli_args, "column")?; - let freezer = cli_args.get_flag("freezer"); - let blobs_db = cli_args.get_flag("blobs-db"); +fn parse_compact_config(compact_config: &Compact) -> Result { + let column: DBColumn = compact_config + .column + .parse() + .expect("column is a required field"); + let freezer = compact_config.freezer; + let blobs_db = compact_config.blobs_db; Ok(CompactConfig { column, freezer, @@ -492,8 +289,8 @@ pub struct MigrateConfig { to: SchemaVersion, } -fn parse_migrate_config(cli_args: &ArgMatches) -> Result { - let to = SchemaVersion(clap_utils::parse_required(cli_args, "to")?); +fn parse_migrate_config(migrate_config: &Migrate) -> Result { + let to = SchemaVersion(migrate_config.to); Ok(MigrateConfig { to }) } @@ -595,9 +392,10 @@ pub fn prune_blobs( pub struct PruneStatesConfig { confirm: bool, } - -fn parse_prune_states_config(cli_args: &ArgMatches) -> Result { - let confirm = cli_args.get_flag("confirm"); +fn parse_prune_states_config( + prune_states_config: &PruneStates, +) -> Result { + let confirm = prune_states_config.confirm; Ok(PruneStatesConfig { confirm }) } @@ -676,33 +474,35 @@ pub fn prune_states( } /// Run the database manager, returning an error string if the operation did not succeed. -pub fn run(cli_args: &ArgMatches, env: Environment) -> Result<(), String> { - let client_config = parse_client_config(cli_args, &env)?; +pub fn run( + cli_args: &ArgMatches, + db_manager_config: &DatabaseManager, + env: Environment, +) -> Result<(), String> { + let client_config = parse_client_config(cli_args, db_manager_config, &env)?; let context = env.core_context(); let log = context.log().clone(); let format_err = |e| format!("Fatal error: {:?}", e); - match cli_args.subcommand() { - Some(("version", _)) => { - display_db_version(client_config, &context, log).map_err(format_err) - } - Some(("migrate", cli_args)) => { - let migrate_config = parse_migrate_config(cli_args)?; + match &db_manager_config.subcommand { + cli::DatabaseManagerSubcommand::Migrate(migrate_config) => { + let migrate_config = parse_migrate_config(migrate_config)?; migrate_db(migrate_config, client_config, &context, log).map_err(format_err) } - Some(("inspect", cli_args)) => { - let inspect_config = parse_inspect_config(cli_args)?; + cli::DatabaseManagerSubcommand::Inspect(inspect_config) => { + let inspect_config = parse_inspect_config(inspect_config)?; inspect_db::(inspect_config, client_config) } - Some(("compact", cli_args)) => { - let compact_config = parse_compact_config(cli_args)?; - compact_db::(compact_config, client_config, log).map_err(format_err) + cli::DatabaseManagerSubcommand::Version(_) => { + display_db_version(client_config, &context, log).map_err(format_err) } - Some(("prune-payloads", _)) => { + cli::DatabaseManagerSubcommand::PrunePayloads(_) => { prune_payloads(client_config, &context, log).map_err(format_err) } - Some(("prune-blobs", _)) => prune_blobs(client_config, &context, log).map_err(format_err), - Some(("prune-states", cli_args)) => { + cli::DatabaseManagerSubcommand::PruneBlobs(_) => { + prune_blobs(client_config, &context, log).map_err(format_err) + } + cli::DatabaseManagerSubcommand::PruneStates(prune_states_config) => { let executor = env.core_context().executor; let network_config = context .eth2_network_config @@ -722,10 +522,13 @@ pub fn run(cli_args: &ArgMatches, env: Environment) -> Result<(), .map_err(|e| format!("Error getting genesis state: {e}"))? .ok_or("Genesis state missing")?; - let prune_config = parse_prune_states_config(cli_args)?; + let prune_config = parse_prune_states_config(prune_states_config)?; prune_states(client_config, prune_config, genesis_state, &context, log) } - _ => Err("Unknown subcommand, for help `lighthouse database_manager --help`".into()), + cli::DatabaseManagerSubcommand::Compact(compact_config) => { + let compact_config = parse_compact_config(compact_config)?; + compact_db::(compact_config, client_config, log).map_err(format_err) + } } } diff --git a/lighthouse/src/cli.rs b/lighthouse/src/cli.rs new file mode 100644 index 0000000000..90d3e811eb --- /dev/null +++ b/lighthouse/src/cli.rs @@ -0,0 +1,9 @@ +use clap::Parser; +use database_manager::cli::DatabaseManager; +use serde::{Deserialize, Serialize}; + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +pub enum LighthouseSubcommands { + #[clap(name = "database_manager")] + DatabaseManager(DatabaseManager), +} diff --git a/lighthouse/src/main.rs b/lighthouse/src/main.rs index a7521d5f8c..d6d670738a 100644 --- a/lighthouse/src/main.rs +++ b/lighthouse/src/main.rs @@ -1,10 +1,14 @@ +mod cli; mod metrics; use beacon_node::ProductionBeaconNode; +use clap::FromArgMatches; +use clap::Subcommand; use clap::{Arg, ArgAction, ArgMatches, Command}; use clap_utils::{ flags::DISABLE_MALLOC_TUNING_FLAG, get_color_style, get_eth2_network_config, FLAG_HEADER, }; +use cli::LighthouseSubcommands; use directory::{parse_path_or_default, DEFAULT_BEACON_NODE_DIR, DEFAULT_VALIDATOR_DIR}; use environment::{EnvironmentBuilder, LoggerConfig}; use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK, HARDCODED_NET_NAMES}; @@ -87,7 +91,7 @@ fn main() { } // Parse the CLI parameters. - let matches = Command::new("Lighthouse") + let cli = Command::new("Lighthouse") .version(SHORT_VERSION.as_str()) .author("Sigma Prime ") .styles(get_color_style()) @@ -409,9 +413,11 @@ fn main() { .subcommand(boot_node::cli_app()) .subcommand(validator_client::cli_app()) .subcommand(account_manager::cli_app()) - .subcommand(database_manager::cli_app()) - .subcommand(validator_manager::cli_app()) - .get_matches(); + .subcommand(validator_manager::cli_app()); + + let cli = LighthouseSubcommands::augment_subcommands(cli); + + let matches = cli.get_matches(); // Configure the allocator early in the process, before it has the chance to use the default values for // anything important. @@ -676,14 +682,13 @@ fn run( return Ok(()); } - if let Some(sub_matches) = matches.subcommand_matches(database_manager::CMD) { + if let Ok(LighthouseSubcommands::DatabaseManager(db_manager_config)) = + LighthouseSubcommands::from_arg_matches(matches) + { info!(log, "Running database manager for {} network", network_name); - // Pass the entire `environment` to the database manager so it can run blocking operations. - database_manager::run(sub_matches, environment)?; - - // Exit as soon as database manager returns control. + database_manager::run(matches, &db_manager_config, environment)?; return Ok(()); - } + }; info!(log, "Lighthouse started"; "version" => VERSION); info!(