diff --git a/node/Cargo.lock b/node/Cargo.lock index 8f242b32..8fa65fa4 100644 --- a/node/Cargo.lock +++ b/node/Cargo.lock @@ -465,9 +465,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -475,9 +475,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -487,11 +487,11 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.51", @@ -1063,6 +1063,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.8" @@ -2172,7 +2178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools 0.11.0", "log", "multimap", @@ -3907,7 +3913,7 @@ name = "zksync_protobuf_build" version = "0.1.0" dependencies = [ "anyhow", - "heck", + "heck 0.4.1", "prettyplease", "proc-macro2", "prost-build", diff --git a/node/Cargo.toml b/node/Cargo.toml index 80f955fe..b37bc74f 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -50,7 +50,7 @@ assert_matches = "1.5.0" async-trait = "0.1.71" bit-vec = "0.6" blst = "0.3.10" -clap = { version = "4.3.3", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } criterion = "0.5.1" ed25519-dalek = { version = "2.0.0", features = ["rand_core"] } ff_ce = "0.14.3" diff --git a/node/tools/src/bin/test.rs b/node/tools/src/bin/test.rs new file mode 100644 index 00000000..f856a7dd --- /dev/null +++ b/node/tools/src/bin/test.rs @@ -0,0 +1,49 @@ +//! asdfasdf + +use clap::{command, Args, Parser}; +use std::path::PathBuf; + +/// Command-line application launching a node executor. +#[derive(Debug, Parser)] +/// asdfasdf +struct Cli { + /// Node configuration. + + /// Command line config + /// Full json config + #[arg(long, requires="node_key", conflicts_with_all=["config_file", "validator_key_file", "node_key_file"])] + config: Option, + /// Plain node key + #[arg(long, requires="config", conflicts_with_all=["config_file", "validator_key_file", "node_key_file"])] + node_key: Option, + /// Plain validator key + #[arg(long, conflicts_with_all=["config_file", "validator_key_file", "node_key_file"])] + validator_key: Option, + + /// Path to a validator key file. If set to an empty string, validator key will not be read + /// (i.e., a node will be initialized as a non-validator node). + #[arg(long, default_value = "./validator_key")] + validator_key_file: PathBuf, + /// Path to a JSON file with node configuration. + #[arg(long, default_value = "./config.json")] + config_file: PathBuf, + /// Path to a node key file. + #[arg(long, default_value = "./node_key")] + node_key_file: PathBuf, + + /// Path to the rocksdb database of the node. + #[arg(long, default_value = "./database")] + database: PathBuf, + /// Port for the RPC server. + #[arg(long)] + rpc_port: Option, +} + +/// adasdsa +#[tokio::main] +/// adasdsa +async fn main() -> anyhow::Result<()> { + let args: Cli = Cli::parse(); + dbg!(args); + Ok(()) +} diff --git a/node/tools/src/config.rs b/node/tools/src/config.rs index 8e95a328..ffb8410c 100644 --- a/node/tools/src/config.rs +++ b/node/tools/src/config.rs @@ -153,22 +153,32 @@ impl ProtoFmt for AppConfig { /// Configuration information. #[derive(Debug)] pub struct ConfigArgs<'a> { - /// Node configuration from command line. - pub config: Option, - /// Path to a JSON file with node configuration. - pub config_file: &'a Path, - /// Validator key as a string. - pub validator_key: Option, - /// Path to a validator key file. - pub validator_key_file: &'a Path, - /// Node key as a string. - pub node_key: Option, - /// Path to a node key file. - pub node_key_file: &'a Path, + /// Node configuration. + pub config_args: ConfigSource<'a>, /// Path to the rocksdb database. pub database: &'a Path, } +#[derive(Debug)] +pub enum ConfigSource<'a> { + CliConfig { + /// Node configuration from command line. + config: AppConfig, + /// Node key as a string. + node_key: node::SecretKey, + /// Validator key as a string. + validator_key: Option, + }, + PathConfig { + /// Path to a JSON file with node configuration. + config_file: &'a Path, + /// Path to a validator key file. + validator_key_file: &'a Path, + /// Path to a node key file. + node_key_file: &'a Path, + }, +} + pub struct Configs { pub app: AppConfig, pub validator_key: Option, @@ -179,50 +189,44 @@ pub struct Configs { impl<'a> ConfigArgs<'a> { // Loads configs from the file system. pub fn load(self) -> anyhow::Result { - Ok(Configs { - app: (|| { - let config = match self.config { - Some(app) => app, - None => { - let app = fs::read_to_string(self.config_file).context(format!( - "failed reading file: {}", - self.config_file.display() - ))?; - decode_json::>(&app) - .context("failed decoding JSON")? - .0 - } - }; - Ok::(config) - })() - .context("config")?, - - validator_key: self.validator_key.or({ - fs::read_to_string(self.validator_key_file) - .context(format!( - "failed reading file: {}", - self.validator_key_file.display() - )) + match self.config_args { + ConfigSource::CliConfig { + config, + node_key, + validator_key, + } => Ok(Configs { + app: config.clone(), + validator_key: validator_key.clone(), + node_key: node_key.clone(), + database: self.database.into(), + }), + ConfigSource::PathConfig { + config_file, + validator_key_file, + node_key_file, + } => Ok(Configs { + app: (|| { + let app = fs::read_to_string(config_file).context("failed reading file")?; + decode_json::>(&app).context("failed decoding JSON") + })() + .with_context(|| config_file.display().to_string())? + .0, + + validator_key: fs::read_to_string(validator_key_file) .ok() .map(|value| Text::new(&value).decode().context("failed decoding key")) - } - .transpose() - .context("validator key")?), - - node_key: self.node_key.or({ - fs::read_to_string(self.node_key_file) - .context(format!( - "failed reading file: {}", - self.node_key_file.display() - )) - .ok() - .map( |value| Text::new(&value).decode().context("failed decoding key")) - } - .transpose() - .context("node key")?).expect("Missing node key: Should provide --node-key, --node-key-file, or place a `node_key` file at root directory"), + .transpose() + .with_context(|| validator_key_file.display().to_string())?, - database: self.database.into(), - }) + node_key: (|| { + let key = fs::read_to_string(node_key_file).context("failed reading file")?; + Text::new(&key).decode().context("failed decoding key") + })() + .with_context(|| node_key_file.display().to_string())?, + + database: self.database.into(), + }), + } } } diff --git a/node/tools/src/lib.rs b/node/tools/src/lib.rs index 0490b9a1..9a6263b8 100644 --- a/node/tools/src/lib.rs +++ b/node/tools/src/lib.rs @@ -9,5 +9,5 @@ mod store; #[cfg(test)] mod tests; -pub use config::{decode_json, AppConfig, ConfigArgs, NodeAddr, NODES_PORT}; +pub use config::{decode_json, AppConfig, ConfigArgs, ConfigSource, NodeAddr, NODES_PORT}; pub use rpc::server::RPCServer; diff --git a/node/tools/src/main.rs b/node/tools/src/main.rs index bee127cb..0131bdf2 100644 --- a/node/tools/src/main.rs +++ b/node/tools/src/main.rs @@ -1,7 +1,7 @@ //! Main binary for the consensus node. It reads the configuration, initializes all parts of the node and //! manages communication between the actors. It is the main executable in this workspace. use anyhow::Context as _; -use clap::{Args, Parser}; +use clap::Parser; use std::{fs, io::IsTerminal as _, path::PathBuf}; use tracing::metadata::LevelFilter; use tracing_subscriber::{prelude::*, Registry}; @@ -9,21 +9,46 @@ use vise_exporter::MetricsExporter; use zksync_concurrency::{ctx, scope}; use zksync_consensus_crypto::{Text, TextFmt}; use zksync_consensus_roles::{node, validator}; -use zksync_consensus_tools::{decode_json, AppConfig, ConfigArgs, RPCServer}; +use zksync_consensus_tools::{decode_json, AppConfig, ConfigArgs, ConfigSource, RPCServer}; use zksync_protobuf::serde::Serde; /// Command-line application launching a node executor. #[derive(Debug, Parser)] struct Cli { - /// Node configuration. - #[command(flatten)] - config_grp: Config, - /// Validator key. - #[command(flatten)] - validator_key_grp: ValidatorKey, - /// Node key definition. - #[command(flatten)] - node_key_grp: NodeKey, + /// Full json config + #[arg(long, + value_parser(parse_config), + requires="node_key", + conflicts_with_all=["config_file", "validator_key_file", "node_key_file"])] + config: Option>, + /// Plain node key + #[arg(long, + value_parser(parse_key::), + requires="config", + conflicts_with_all=["config_file", "validator_key_file", "node_key_file"])] + node_key: Option, + /// Plain validator key + #[arg(long, + value_parser(parse_key::), + requires_all=["config", "node_key"], + conflicts_with_all=["config_file", "validator_key_file", "node_key_file"])] + validator_key: Option, + /// Path to a validator key file. If set to an empty string, validator key will not be read + /// (i.e., a node will be initialized as a non-validator node). + #[arg(long, + default_value = "./validator_key", + conflicts_with_all=["config", "validator_key", "node_key"])] + validator_key_file: PathBuf, + /// Path to a JSON file with node configuration. + #[arg(long, + default_value = "./config.json", + conflicts_with_all=["config", "validator_key", "node_key"])] + config_file: PathBuf, + /// Path to a node key file. + #[arg(long, + default_value = "./node_key", + conflicts_with_all=["config", "validator_key", "node_key"])] + node_key_file: PathBuf, /// Path to the rocksdb database of the node. #[arg(long, default_value = "./database")] database: PathBuf, @@ -32,49 +57,6 @@ struct Cli { rpc_port: Option, } -/// Node key definitions -#[derive(Debug, Args)] -#[group(required = false, multiple = false)] -struct NodeKey { - /// Set Node key in command line - #[arg(long, value_name = "node_key", value_parser(parse_key::))] - node_key: Option, - - /// Set a path to the node key file - #[arg(long, default_value = "./node_key")] - node_key_file: PathBuf, -} - -/// Validator key definitions: -/// If validator key is not set, and key file is not present, -/// a node will be initialized as a non-validator node. -#[derive(Debug, Args)] -#[group(required = false, multiple = false)] -struct ValidatorKey { - /// Set validator key directly in command line - #[arg(long, value_name = "validator_key", value_parser(parse_key::))] - validator_key: Option, - - /// Set path to node key file - #[arg(long, default_value = "./validator_key")] - validator_key_file: PathBuf, -} - -/// Configuration json. -/// Can be provided via cli arg or via file. -/// If none is present a config.json at root is expected -#[derive(Debug, Args)] -#[group(required = false, multiple = false)] -struct Config { - /// Provide configuration directly in command line - #[arg(long, value_name = "config", value_parser(parse_config))] - config: Option>, - - /// Set path to config file - #[arg(long, default_value = "./config.json")] - config_file: PathBuf, -} - /// Function to let clap parse the command line `config` argument fn parse_config(val: &str) -> anyhow::Result> { decode_json(val) @@ -88,13 +70,20 @@ fn parse_key(val: &str) -> anyhow::Result { impl Cli { /// Extracts configuration paths from these args. fn config_args(&self) -> ConfigArgs<'_> { + let config_args = match &self.config { + Some(config) => ConfigSource::CliConfig { + config: config.clone().0, + node_key: self.node_key.clone().unwrap(), // node_key is present as it is enforced by clap rules + validator_key: self.validator_key.clone(), + }, + None => ConfigSource::PathConfig { + config_file: &self.config_file, + validator_key_file: &self.validator_key_file, + node_key_file: &self.node_key_file, + }, + }; ConfigArgs { - config: self.config_grp.config.clone().map(|config| config.0), - config_file: &self.config_grp.config_file, - node_key: self.node_key_grp.node_key.clone(), - node_key_file: &self.node_key_grp.node_key_file, - validator_key: self.validator_key_grp.validator_key.clone(), - validator_key_file: &self.validator_key_grp.validator_key_file, + config_args, database: &self.database, } }