diff --git a/Cargo.lock b/Cargo.lock index 8e5d808787..44c8d18421 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,6 +426,13 @@ dependencies = [ "serde", ] +[[package]] +name = "build-information" +version = "0.1.0" +dependencies = [ + "vergen 7.2.1", +] + [[package]] name = "bumpalo" version = "3.9.1" @@ -598,41 +605,51 @@ version = "3.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" dependencies = [ - "atty", "bitflags", - "clap_derive", - "clap_lex", + "clap_lex 0.2.4", "indexmap", - "once_cell", - "strsim", - "termcolor", "textwrap 0.15.0", ] [[package]] -name = "clap_complete" -version = "3.2.4" +name = "clap" +version = "4.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4179da71abd56c26b54dd0c248cc081c1f43b0a1a7e8448e28e57a29baa993d" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" dependencies = [ - "clap 3.2.8", + "atty", + "bitflags", + "clap_derive", + "clap_lex 0.3.0", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_complete" +version = "4.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" +dependencies = [ + "clap 4.0.26", ] [[package]] name = "clap_complete_fig" -version = "3.2.4" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed37b4c0c1214673eba6ad8ea31666626bf72be98ffb323067d973c48b4964b9" +checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3" dependencies = [ - "clap 3.2.8", + "clap 4.0.26", "clap_complete", ] [[package]] name = "clap_derive" -version = "3.2.7" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -650,6 +667,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "client-connections" version = "0.1.0" @@ -766,7 +792,7 @@ dependencies = [ name = "completions" version = "0.1.0" dependencies = [ - "clap 3.2.8", + "clap 4.0.26", "clap_complete", "clap_complete_fig", ] @@ -1005,7 +1031,7 @@ version = "0.1.0" dependencies = [ "bip39", "cfg-if 0.1.10", - "clap 3.2.8", + "clap 4.0.26", "coconut-interface", "completions", "config", @@ -1765,7 +1791,7 @@ name = "explorer-api" version = "1.1.1" dependencies = [ "chrono", - "clap 3.2.8", + "clap 4.0.26", "contracts-common", "dotenv", "humantime-serde", @@ -3211,9 +3237,11 @@ version = "1.1.4" dependencies = [ "anyhow", "async-trait", + "bip39", "bs58", + "build-information", "cfg-if 1.0.0", - "clap 3.2.8", + "clap 4.0.26", "coconut-bandwidth-contract-common", "coconut-dkg-common", "coconut-interface", @@ -3234,6 +3262,7 @@ dependencies = [ "getset", "humantime-serde", "inclusion-probability", + "lazy_static", "log", "logging", "mixnet-contract-common", @@ -3265,7 +3294,6 @@ dependencies = [ "ts-rs", "url", "validator-client", - "vergen 7.2.1", "version-checker", ] @@ -3307,7 +3335,7 @@ dependencies = [ "base64", "bip39", "bs58", - "clap 3.2.8", + "clap 4.0.26", "clap_complete", "clap_complete_fig", "dotenv", @@ -3331,7 +3359,7 @@ dependencies = [ "bip39", "bs58", "cfg-if 1.0.0", - "clap 3.2.8", + "clap 4.0.26", "comfy-table", "cosmrs", "cosmwasm-std", @@ -3357,7 +3385,8 @@ dependencies = [ name = "nym-client" version = "1.1.4" dependencies = [ - "clap 3.2.8", + "build-information", + "clap 4.0.26", "client-connections", "client-core", "coconut-interface", @@ -3370,6 +3399,7 @@ dependencies = [ "futures", "gateway-client", "gateway-requests", + "lazy_static", "log", "logging", "network-defaults", @@ -3387,7 +3417,6 @@ dependencies = [ "topology", "url", "validator-client", - "vergen 5.1.17", "version-checker", "websocket-requests", ] @@ -3400,7 +3429,8 @@ dependencies = [ "async-trait", "bip39", "bs58", - "clap 3.2.8", + "build-information", + "clap 4.0.26", "coconut-interface", "colored", "completions", @@ -3413,6 +3443,7 @@ dependencies = [ "futures", "gateway-requests", "humantime-serde", + "lazy_static", "log", "logging", "mixnet-client", @@ -3435,7 +3466,6 @@ dependencies = [ "tokio-util 0.7.3", "url", "validator-client", - "vergen 5.1.17", "version-checker", ] @@ -3445,7 +3475,8 @@ version = "1.1.4" dependencies = [ "anyhow", "bs58", - "clap 3.2.8", + "build-information", + "clap 4.0.26", "colored", "completions", "config", @@ -3477,7 +3508,6 @@ dependencies = [ "topology", "url", "validator-client", - "vergen 5.1.17", "version-checker", ] @@ -3486,7 +3516,7 @@ name = "nym-network-requester" version = "1.1.4" dependencies = [ "async-trait", - "clap 3.2.8", + "clap 4.0.26", "client-connections", "completions", "dirs", @@ -3549,7 +3579,8 @@ dependencies = [ name = "nym-socks5-client" version = "1.1.4" dependencies = [ - "clap 3.2.8", + "build-information", + "clap 4.0.26", "client-connections", "client-core", "coconut-interface", @@ -3562,6 +3593,7 @@ dependencies = [ "futures", "gateway-client", "gateway-requests", + "lazy_static", "log", "logging", "network-defaults", @@ -3582,7 +3614,6 @@ dependencies = [ "topology", "url", "validator-client", - "vergen 5.1.17", "version-checker", ] diff --git a/Cargo.toml b/Cargo.toml index c3afc28de5..e756fc7bf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ members = [ "common/coconut-interface", "common/commands", "common/config", + "common/build-information", "common/cosmwasm-smart-contracts/coconut-bandwidth-contract", "common/cosmwasm-smart-contracts/coconut-dkg", "common/cosmwasm-smart-contracts/contracts-common", diff --git a/clients/client-core/src/init/mod.rs b/clients/client-core/src/init/mod.rs index 820e229a35..4d012d366b 100644 --- a/clients/client-core/src/init/mod.rs +++ b/clients/client-core/src/init/mod.rs @@ -64,6 +64,7 @@ impl Display for InitResults { /// it will do the sensible thing. pub async fn setup_gateway( register_gateway: bool, + // TODO: this should get refactored to instead take Option user_chosen_gateway_id: Option, config: &Config, ) -> Result diff --git a/clients/credential/Cargo.toml b/clients/credential/Cargo.toml index ccf241b1cb..ff2326b1b1 100644 --- a/clients/credential/Cargo.toml +++ b/clients/credential/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] bip39 = "1.0.1" cfg-if = "0.1" -clap = { version = "3.2", features = ["cargo", "derive"] } +clap = { version = "4.0", features = ["cargo", "derive"] } rand = "0.7.3" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0" diff --git a/clients/credential/src/main.rs b/clients/credential/src/main.rs index f413673626..b7524e6c7b 100644 --- a/clients/credential/src/main.rs +++ b/clients/credential/src/main.rs @@ -31,7 +31,7 @@ cfg_if::cfg_if! { #[tokio::main] async fn main() -> Result<()> { let args = Cli::parse(); - setup_env(args.config_env_file.clone()); + setup_env(args.config_env_file.as_ref()); let bin_name = "nym-credential-client"; match args.command { @@ -42,8 +42,8 @@ cfg_if::cfg_if! { let state = deposit(&r.nymd_url, &r.mnemonic, r.amount).await?; get_credential(&state, shared_storage).await?; } - Command::Completions(c) => c.generate(&mut crate::Cli::into_app(), bin_name), - Command::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name) + Command::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name), + Command::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name) } Ok(()) diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index d97f7748fb..a27cedd423 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -20,8 +20,9 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it # and the single instance of abortable we have should really be refactored anyway url = "2.2" -clap = { version = "3.2", features = ["cargo", "derive"] } +clap = { version = "4.0", features = ["cargo", "derive"] } dirs = "4.0" +lazy_static = "1.4.0" log = "0.4" # self explanatory pretty_env_logger = "0.4" # for formatting log messages rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use @@ -33,6 +34,7 @@ tokio = { version = "1.21.2", features = ["rt-multi-thread", "net", "signal"] } tokio-tungstenite = "0.14" # websocket ## internal +build-information = { path = "../../common/build-information" } client-core = { path = "../client-core", features = ["fs-surb-storage"] } client-connections = { path = "../../common/client-connections" } coconut-interface = { path = "../../common/coconut-interface", optional = true } @@ -58,6 +60,3 @@ coconut = ["coconut-interface", "credentials", "credentials/coconut", "gateway-r [dev-dependencies] serde_json = "1.0" # for the "textsend" example - -[build-dependencies] -vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index 8c04ceb126..d8f9f59f90 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -8,6 +8,7 @@ use crate::{ }; use clap::Args; use config::NymConfig; +use crypto::asymmetric::identity; use nymsphinx::addressing::clients::Recipient; use serde::Serialize; use std::fmt::Display; @@ -21,7 +22,7 @@ pub(crate) struct Init { /// Id of the gateway we are going to connect to. #[clap(long)] - gateway: Option, + gateway: Option, /// Force register gateway. WARNING: this will overwrite any existing keys for the given id, /// potentially causing loss of access. @@ -29,14 +30,14 @@ pub(crate) struct Init { force_register_gateway: bool, /// Comma separated list of rest endpoints of the nymd validators - #[clap(long)] #[cfg(feature = "coconut")] - nymd_validators: Option, + #[clap(long, value_delimiter = ',')] + nymd_validators: Option>, /// Comma separated list of rest endpoints of the API validators - #[clap(long, alias = "api_validators")] + #[clap(long, alias = "api_validators", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nym_apis: Option, + nym_apis: Option>, /// Whether to not start the websocket #[clap(long)] @@ -48,11 +49,11 @@ pub(crate) struct Init { /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init - #[clap(long, hidden = true)] + #[clap(long, hide = true)] fastmode: bool, /// Disable loop cover traffic and the Poisson rate limiter (for debugging only) - #[clap(long, hidden = true)] + #[clap(long, hide = true)] no_cover: bool, /// Set this client to work in a enabled credentials mode that would attempt to use gateway @@ -130,7 +131,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { let register_gateway = !already_init || user_wants_force_register; // Attempt to use a user-provided gateway, if possible - let user_chosen_gateway_id = args.gateway.clone(); + let user_chosen_gateway_id = args.gateway; // Load and potentially override config let mut config = override_config(Config::new(id), OverrideConfig::from(args.clone())); @@ -139,7 +140,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { // one but with keys kept, or reusing the gateway configuration. let gateway = client_core::init::setup_gateway::( register_gateway, - user_chosen_gateway_id, + user_chosen_gateway_id.map(|id| id.to_base58_string()), config.get_base(), ) .await diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index c2ad5ec9f6..a6fabe615f 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -1,54 +1,30 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use std::error::Error; - use crate::client::config::{Config, SocketType}; +use build_information::BinaryBuildInformation; use clap::CommandFactory; use clap::{Parser, Subcommand}; use completions::{fig_generate, ArgShell}; +use lazy_static::lazy_static; +use std::error::Error; pub(crate) mod init; pub(crate) mod run; pub(crate) mod upgrade; -fn long_version() -> String { - format!( - r#" -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -"#, - "Build Timestamp:", - env!("VERGEN_BUILD_TIMESTAMP"), - "Build Version:", - env!("VERGEN_BUILD_SEMVER"), - "Commit SHA:", - env!("VERGEN_GIT_SHA"), - "Commit Date:", - env!("VERGEN_GIT_COMMIT_TIMESTAMP"), - "Commit Branch:", - env!("VERGEN_GIT_BRANCH"), - "rustc Version:", - env!("VERGEN_RUSTC_SEMVER"), - "rustc Channel:", - env!("VERGEN_RUSTC_CHANNEL"), - "cargo Profile:", - env!("VERGEN_CARGO_PROFILE"), - ) +lazy_static! { + pub static ref PRETTY_BUILD_INFORMATION: String = + BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print(); } -fn long_version_static() -> &'static str { - Box::leak(long_version().into_boxed_str()) +// Helper for passing LONG_VERSION to clap +fn pretty_build_info_static() -> &'static str { + &PRETTY_BUILD_INFORMATION } #[derive(Parser)] -#[clap(author = "Nymtech", version, long_version = long_version_static(), about)] +#[clap(author = "Nymtech", version, long_version = pretty_build_info_static(), about)] pub(crate) struct Cli { /// Path pointing to an env file that configures the client. #[clap(short, long)] @@ -76,14 +52,14 @@ pub(crate) enum Commands { // Configuration that can be overridden. pub(crate) struct OverrideConfig { - nym_apis: Option, + nym_apis: Option>, disable_socket: bool, port: Option, fastmode: bool, no_cover: bool, #[cfg(feature = "coconut")] - nymd_validators: Option, + nymd_validators: Option>, #[cfg(feature = "coconut")] enabled_credentials_mode: bool, } @@ -95,17 +71,15 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box init::execute(m).await?, Commands::Run(m) => run::execute(m).await?, Commands::Upgrade(m) => upgrade::execute(m), - Commands::Completions(s) => s.generate(&mut Cli::into_app(), bin_name), - Commands::GenerateFigSpec => fig_generate(&mut Cli::into_app(), bin_name), + Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), + Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), } Ok(()) } pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config { - if let Some(raw_validators) = args.nym_apis { - config - .get_base_mut() - .set_custom_nym_apis(config::parse_urls(&raw_validators)); + if let Some(nym_apis) = args.nym_apis { + config.get_base_mut().set_custom_nym_apis(nym_apis); } else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() { let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR) .expect("api validator not set"); @@ -124,10 +98,8 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi #[cfg(feature = "coconut")] { - if let Some(raw_validators) = args.nymd_validators { - config - .get_base_mut() - .set_custom_validators(config::parse_urls(&raw_validators)); + if let Some(nymd_validators) = args.nymd_validators { + config.get_base_mut().set_custom_validators(nymd_validators); } else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() { let raw_validators = std::env::var(network_defaults::var_names::NYMD_VALIDATOR) .expect("nymd validator not set"); diff --git a/clients/native/src/commands/run.rs b/clients/native/src/commands/run.rs index db3d0cedad..1a3f9ae097 100644 --- a/clients/native/src/commands/run.rs +++ b/clients/native/src/commands/run.rs @@ -11,6 +11,7 @@ use crate::{ use clap::Args; use config::NymConfig; +use crypto::asymmetric::identity; use log::*; use version_checker::is_minor_version_compatible; @@ -21,19 +22,19 @@ pub(crate) struct Run { id: String, /// Comma separated list of rest endpoints of the nymd validators - #[clap(long)] #[cfg(feature = "coconut")] - nymd_validators: Option, + #[clap(long, value_delimiter = ',')] + nymd_validators: Option>, /// Comma separated list of rest endpoints of the API validators - #[clap(long, alias = "api_validators")] + #[clap(long, alias = "api_validators", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nym_apis: Option, + nym_apis: Option>, /// Id of the gateway we want to connect to. If overridden, it is user's responsibility to /// ensure prior registration happened #[clap(long)] - gateway: Option, + gateway: Option, /// Whether to not start the websocket #[clap(long)] @@ -45,11 +46,11 @@ pub(crate) struct Run { /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init - #[clap(long, hidden = true)] + #[clap(long, hide = true)] fastmode: bool, /// Disable loop cover traffic and the Poisson rate limiter (for debugging only) - #[clap(long, hidden = true)] + #[clap(long, hide = true)] no_cover: bool, /// Set this client to work in a enabled credentials mode that would attempt to use gateway diff --git a/clients/native/src/main.rs b/clients/native/src/main.rs index 972eef1925..edb7c56f1a 100644 --- a/clients/native/src/main.rs +++ b/clients/native/src/main.rs @@ -18,7 +18,7 @@ async fn main() -> Result<(), Box> { println!("{}", banner()); let args = commands::Cli::parse(); - setup_env(args.config_env_file.clone()); + setup_env(args.config_env_file.as_ref()); commands::execute(&args).await } diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index add5a3ee58..daaaf3fc0d 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -11,9 +11,10 @@ name = "nym_socks5" path = "src/lib.rs" [dependencies] -clap = { version = "3.2", features = ["cargo", "derive"] } +clap = { version = "4.0", features = ["cargo", "derive"] } dirs = "4.0" futures = "0.3" +lazy_static = "1.4.0" log = "0.4" pin-project = "1.0" pretty_env_logger = "0.4" @@ -26,6 +27,7 @@ tokio = { version = "1.21.2", features = ["rt-multi-thread", "net", "signal"] } url = "2.2" # internal +build-information = { path = "../../common/build-information" } client-core = { path = "../client-core", features = ["fs-surb-storage"] } client-connections = { path = "../../common/client-connections" } coconut-interface = { path = "../../common/coconut-interface", optional = true } @@ -51,6 +53,3 @@ version-checker = { path = "../../common/version-checker" } [features] coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut", "client-core/coconut"] eth = [] - -[build-dependencies] -vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } diff --git a/clients/socks5/build.rs b/clients/socks5/build.rs deleted file mode 100644 index 01b3a20dc6..0000000000 --- a/clients/socks5/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2021 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use vergen::{vergen, Config}; - -fn main() { - vergen(Config::default()).expect("failed to extract build metadata") -} diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 48f2ae0ec9..35fe398685 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -8,6 +8,7 @@ use crate::{ }; use clap::Args; use config::NymConfig; +use crypto::asymmetric::identity; use nymsphinx::addressing::clients::Recipient; use serde::Serialize; use std::fmt::Display; @@ -21,7 +22,7 @@ pub(crate) struct Init { /// Address of the socks5 provider to send messages to. #[clap(long)] - provider: String, + provider: Recipient, /// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. /// While this is going to hide its actual address information, it will make the actual communication @@ -34,7 +35,7 @@ pub(crate) struct Init { /// Id of the gateway we are going to connect to. #[clap(long)] - gateway: Option, + gateway: Option, /// Force register gateway. WARNING: this will overwrite any existing keys for the given id, /// potentially causing loss of access. @@ -43,13 +44,13 @@ pub(crate) struct Init { /// Comma separated list of rest endpoints of the nymd validators #[cfg(feature = "coconut")] - #[clap(long)] - nymd_validators: Option, + #[clap(long, value_delimiter = ',')] + nymd_validators: Option>, /// Comma separated list of rest endpoints of the API validators - #[clap(long, alias = "api_validators")] + #[clap(long, alias = "api_validators", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nym_apis: Option, + nym_apis: Option>, /// Port for the socket to listen on in all subsequent runs #[clap(short, long)] @@ -57,11 +58,11 @@ pub(crate) struct Init { /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init - #[clap(long, hidden = true)] + #[clap(long, hide = true)] fastmode: bool, /// Disable loop cover traffic and the Poisson rate limiter (for debugging only) - #[clap(long, hidden = true)] + #[clap(long, hide = true)] no_cover: bool, /// Set this client to work in a enabled credentials mode that would attempt to use gateway @@ -140,11 +141,11 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> { let register_gateway = !already_init || user_wants_force_register; // Attempt to use a user-provided gateway, if possible - let user_chosen_gateway_id = args.gateway.clone(); + let user_chosen_gateway_id = args.gateway; // Load and potentially override config let mut config = override_config( - Config::new(id, provider_address), + Config::new(id, &provider_address.to_string()), OverrideConfig::from(args.clone()), ); @@ -152,7 +153,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> { // one but with keys kept, or reusing the gateway configuration. let gateway = client_core::init::setup_gateway::( register_gateway, - user_chosen_gateway_id, + user_chosen_gateway_id.map(|id| id.to_base58_string()), config.get_base(), ) .await diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index 39368dfb64..2e6f2dd3a7 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -1,55 +1,31 @@ -// Copyright 2021 - Nym Technologies SA +// Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use std::error::Error; - use crate::client::config::Config; +use build_information::BinaryBuildInformation; use clap::CommandFactory; use clap::{Parser, Subcommand}; use completions::{fig_generate, ArgShell}; use config::parse_urls; +use lazy_static::lazy_static; +use std::error::Error; pub mod init; pub(crate) mod run; pub(crate) mod upgrade; -fn long_version() -> String { - format!( - r#" -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -"#, - "Build Timestamp:", - env!("VERGEN_BUILD_TIMESTAMP"), - "Build Version:", - env!("VERGEN_BUILD_SEMVER"), - "Commit SHA:", - env!("VERGEN_GIT_SHA"), - "Commit Date:", - env!("VERGEN_GIT_COMMIT_TIMESTAMP"), - "Commit Branch:", - env!("VERGEN_GIT_BRANCH"), - "rustc Version:", - env!("VERGEN_RUSTC_SEMVER"), - "rustc Channel:", - env!("VERGEN_RUSTC_CHANNEL"), - "cargo Profile:", - env!("VERGEN_CARGO_PROFILE"), - ) +lazy_static! { + pub static ref PRETTY_BUILD_INFORMATION: String = + BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print(); } -fn long_version_static() -> &'static str { - Box::leak(long_version().into_boxed_str()) +// Helper for passing LONG_VERSION to clap +fn pretty_build_info_static() -> &'static str { + &PRETTY_BUILD_INFORMATION } #[derive(Parser)] -#[clap(author = "Nymtech", version, long_version = long_version_static(), about)] +#[clap(author = "Nymtech", version, long_version = pretty_build_info_static(), about)] pub(crate) struct Cli { /// Path pointing to an env file that configures the client. #[clap(short, long)] @@ -79,14 +55,14 @@ pub(crate) enum Commands { // Configuration that can be overridden. pub(crate) struct OverrideConfig { - nym_apis: Option, + nym_apis: Option>, port: Option, use_anonymous_replies: bool, fastmode: bool, no_cover: bool, #[cfg(feature = "coconut")] - nymd_validators: Option, + nymd_validators: Option>, #[cfg(feature = "coconut")] enabled_credentials_mode: bool, } @@ -98,17 +74,15 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box init::execute(m).await?, Commands::Run(m) => run::execute(m).await?, Commands::Upgrade(m) => upgrade::execute(m), - Commands::Completions(s) => s.generate(&mut Cli::into_app(), bin_name), - Commands::GenerateFigSpec => fig_generate(&mut Cli::into_app(), bin_name), + Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), + Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), } Ok(()) } pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config { - if let Some(raw_validators) = args.nym_apis { - config - .get_base_mut() - .set_custom_nym_apis(parse_urls(&raw_validators)); + if let Some(nym_apis) = args.nym_apis { + config.get_base_mut().set_custom_nym_apis(nym_apis); } else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) { config .get_base_mut() @@ -125,10 +99,8 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi #[cfg(feature = "coconut")] { - if let Some(raw_validators) = args.nymd_validators { - config - .get_base_mut() - .set_custom_validators(parse_urls(&raw_validators)); + if let Some(nymd_validators) = args.nymd_validators { + config.get_base_mut().set_custom_validators(nymd_validators); } else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::NYMD_VALIDATOR) { diff --git a/clients/socks5/src/commands/run.rs b/clients/socks5/src/commands/run.rs index a92715aa97..b85a4f9244 100644 --- a/clients/socks5/src/commands/run.rs +++ b/clients/socks5/src/commands/run.rs @@ -9,7 +9,9 @@ use crate::{ use clap::Args; use config::NymConfig; +use crypto::asymmetric::identity; use log::*; +use nymsphinx::addressing::clients::Recipient; use version_checker::is_minor_version_compatible; #[derive(Args, Clone)] @@ -33,21 +35,21 @@ pub(crate) struct Run { /// Address of the socks5 provider to send messages to. #[clap(long)] - provider: Option, + provider: Option, /// Id of the gateway we want to connect to. If overridden, it is user's responsibility to /// ensure prior registration happened #[clap(long)] - gateway: Option, + gateway: Option, /// Comma separated list of rest endpoints of the nymd validators #[cfg(feature = "coconut")] - #[clap(long)] - nymd_validators: Option, + #[clap(long, value_delimiter = ',')] + nymd_validators: Option>, /// Comma separated list of rest endpoints of the Nym APIs - #[clap(long)] - nym_apis: Option, + #[clap(long, value_delimiter = ',')] + nym_apis: Option>, /// Port for the socket to listen on #[clap(short, long)] @@ -55,11 +57,11 @@ pub(crate) struct Run { /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init - #[clap(long, hidden = true)] + #[clap(long, hide = true)] fastmode: bool, /// Disable loop cover traffic and the Poisson rate limiter (for debugging only) - #[clap(long, hidden = true)] + #[clap(long, hide = true)] no_cover: bool, /// Set this client to work in a enabled credentials mode that would attempt to use gateway diff --git a/clients/socks5/src/main.rs b/clients/socks5/src/main.rs index ea0071f538..6dcd9183ab 100644 --- a/clients/socks5/src/main.rs +++ b/clients/socks5/src/main.rs @@ -18,7 +18,7 @@ async fn main() -> Result<(), Box> { println!("{}", banner()); let args = commands::Cli::parse(); - setup_env(args.config_env_file.clone()); + setup_env(args.config_env_file.as_ref()); commands::execute(&args).await } diff --git a/common/build-information/Cargo.toml b/common/build-information/Cargo.toml new file mode 100644 index 0000000000..0f56bec7f1 --- /dev/null +++ b/common/build-information/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "build-information" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[build-dependencies] +vergen = { version = "7", default-features = false, features = ["build", "git", "rustc", "cargo"] } diff --git a/clients/native/build.rs b/common/build-information/build.rs similarity index 71% rename from clients/native/build.rs rename to common/build-information/build.rs index 01b3a20dc6..b909ce42c4 100644 --- a/clients/native/build.rs +++ b/common/build-information/build.rs @@ -1,4 +1,4 @@ -// Copyright 2021 - Nym Technologies SA +// Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use vergen::{vergen, Config}; diff --git a/common/build-information/src/lib.rs b/common/build-information/src/lib.rs new file mode 100644 index 0000000000..f2060154f0 --- /dev/null +++ b/common/build-information/src/lib.rs @@ -0,0 +1,86 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +// TODO: at a later date this crate should probably also expose `ContractBuildInformation` +// and be used by our smart contracts + +pub struct BinaryBuildInformation { + // VERGEN_BUILD_TIMESTAMP + /// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`. + pub build_timestamp: &'static str, + + // VERGEN_BUILD_SEMVER + /// Provides the build version, for example `0.1.0-9-g46f83e1`. + pub build_version: &'static str, + + // VERGEN_GIT_SHA + /// Provides the hash of the commit that was used for the build, for example `46f83e112520533338245862d366f6a02cef07d4`. + pub commit_sha: &'static str, + + // VERGEN_GIT_COMMIT_TIMESTAMP + /// Provides the timestamp of the commit that was used for the build, for example `2021-02-23T08:08:02-05:00`. + pub commit_timestamp: &'static str, + + // VERGEN_GIT_BRANCH + /// Provides the name of the git branch that was used for the build, for example `master`. + pub commit_branch: &'static str, + + // VERGEN_RUSTC_SEMVER + /// Provides the rustc version that was used for the build, for example `1.52.0-nightly`. + pub rustc_version: &'static str, + + // VERGEN_RUSTC_CHANNEL + /// Provides the rustc channel that was used for the build, for example `nightly`. + pub rustc_channel: &'static str, + + // VERGEN_CARGO_PROFILE + /// Provides the cargo profile that was used for the build, for example `debug`. + pub cargo_profile: &'static str, +} + +impl BinaryBuildInformation { + // explicitly require the build_version to be passed as it's binary specific + pub const fn new(build_version: &'static str) -> Self { + BinaryBuildInformation { + build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"), + build_version, + commit_sha: env!("VERGEN_GIT_SHA"), + commit_timestamp: env!("VERGEN_GIT_COMMIT_TIMESTAMP"), + commit_branch: env!("VERGEN_GIT_BRANCH"), + rustc_version: env!("VERGEN_RUSTC_SEMVER"), + rustc_channel: env!("VERGEN_RUSTC_CHANNEL"), + cargo_profile: env!("VERGEN_CARGO_PROFILE"), + } + } + + pub fn pretty_print(&self) -> String { + format!( + r#" +{:<20}{} +{:<20}{} +{:<20}{} +{:<20}{} +{:<20}{} +{:<20}{} +{:<20}{} +{:<20}{} +"#, + "Build Timestamp:", + self.build_timestamp, + "Build Version:", + self.build_version, + "Commit SHA:", + self.commit_sha, + "Commit Date:", + self.commit_timestamp, + "Commit Branch:", + self.commit_branch, + "rustc Version:", + self.rustc_version, + "rustc Channel:", + self.rustc_channel, + "cargo Profile:", + self.cargo_profile, + ) + } +} diff --git a/common/commands/Cargo.toml b/common/commands/Cargo.toml index ce0195cce4..c54589d078 100644 --- a/common/commands/Cargo.toml +++ b/common/commands/Cargo.toml @@ -10,7 +10,7 @@ bip39 = "1.0.1" bs58 = "0.4" comfy-table = "6.0.0" cfg-if = "1.0.0" -clap = { version = "3.2", features = ["derive"] } +clap = { version = "4.0", features = ["derive"] } handlebars = "3.0.1" humantime-serde = "1.0" k256 = { version = "0.10", features = ["ecdsa", "sha256"] } diff --git a/common/commands/src/context/mod.rs b/common/commands/src/context/mod.rs index 3a21634afb..ae612af1dd 100644 --- a/common/commands/src/context/mod.rs +++ b/common/commands/src/context/mod.rs @@ -32,7 +32,7 @@ pub struct ClientArgs { pub fn get_network_details(args: &ClientArgs) -> Result { // let the network defaults crate handle setting up the env vars if the file arg is set, otherwise // it will default to what is already in env vars, falling back to mainnet - setup_env(args.config_env_file.clone()); + setup_env(args.config_env_file.as_ref()); // override the env vars with user supplied arguments, if set if let Some(nymd_url) = args.nymd_url.as_ref() { diff --git a/common/completions/Cargo.toml b/common/completions/Cargo.toml index ace1f76e7f..53a5fa1eed 100644 --- a/common/completions/Cargo.toml +++ b/common/completions/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "3.2", features = ["derive"] } -clap_complete = "3.2" -clap_complete_fig = "3.2" \ No newline at end of file +clap = { version = "4.0", features = ["derive"] } +clap_complete = "4.0" +clap_complete_fig = "4.0" \ No newline at end of file diff --git a/common/completions/src/lib.rs b/common/completions/src/lib.rs index 8526c18d4f..15344ec834 100644 --- a/common/completions/src/lib.rs +++ b/common/completions/src/lib.rs @@ -1,5 +1,5 @@ use clap::builder::Command; -use clap::clap_derive::ArgEnum; +use clap::clap_derive::ValueEnum; use clap::Args; use clap_complete::generator::generate; use clap_complete::Shell as ClapShell; @@ -14,7 +14,7 @@ pub fn fig_generate(command: &mut Command, name: &str) { ) } -#[derive(ArgEnum, Copy, Clone)] +#[derive(ValueEnum, Copy, Clone)] pub enum Shell { Bash, Elvish, @@ -25,7 +25,7 @@ pub enum Shell { #[derive(Args, Copy, Clone)] pub struct ArgShell { - #[clap(arg_enum, value_name = "SHELL")] + #[clap(value_enum, value_name = "SHELL")] shell: Shell, } diff --git a/common/config/src/lib.rs b/common/config/src/lib.rs index eb53cd698b..b3a19661aa 100644 --- a/common/config/src/lib.rs +++ b/common/config/src/lib.rs @@ -118,6 +118,7 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned { } } +// this function is only used for parsing values from the network defaults and thus the "expect" there are fine pub fn parse_urls(raw: &str) -> Vec { raw.split(',') .map(|raw_url| { diff --git a/common/crypto/src/asymmetric/identity/mod.rs b/common/crypto/src/asymmetric/identity/mod.rs index 836f6c70e0..d8f6e2983c 100644 --- a/common/crypto/src/asymmetric/identity/mod.rs +++ b/common/crypto/src/asymmetric/identity/mod.rs @@ -7,6 +7,7 @@ pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATUR use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH}; use pemstore::traits::{PemStorableKey, PemStorableKeyPair}; use std::fmt::{self, Display, Formatter}; +use std::str::FromStr; use thiserror::Error; #[cfg(feature = "rand")] @@ -141,6 +142,14 @@ impl PublicKey { } } +impl FromStr for PublicKey { + type Err = Ed25519RecoveryError; + + fn from_str(s: &str) -> Result { + PublicKey::from_base58_string(s) + } +} + #[cfg(feature = "serde")] impl Serialize for PublicKey { fn serialize(&self, serializer: S) -> Result diff --git a/common/network-defaults/src/lib.rs b/common/network-defaults/src/lib.rs index 3a2daeed42..664bfbb117 100644 --- a/common/network-defaults/src/lib.rs +++ b/common/network-defaults/src/lib.rs @@ -289,7 +289,7 @@ impl ValidatorDetails { } } -pub fn setup_env(config_env_file: Option) { +pub fn setup_env(config_env_file: Option<&PathBuf>) { match std::env::var(var_names::CONFIGURED) { // if the configuration is not already set in the env vars Err(std::env::VarError::NotPresent) => { diff --git a/common/nymsphinx/addressing/src/clients.rs b/common/nymsphinx/addressing/src/clients.rs index fd7235a9b7..29f7051c6c 100644 --- a/common/nymsphinx/addressing/src/clients.rs +++ b/common/nymsphinx/addressing/src/clients.rs @@ -10,6 +10,7 @@ use nymsphinx_types::Destination; use serde::de::{Error as SerdeError, Unexpected, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt::{self, Formatter}; +use std::str::FromStr; use thiserror::Error; // Not entirely sure whether this is the correct place for those, but let's see how it's going @@ -225,6 +226,14 @@ impl std::fmt::Display for Recipient { } } +impl FromStr for Recipient { + type Err = RecipientFormattingError; + + fn from_str(s: &str) -> Result { + Recipient::try_from_base58_string(s) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/explorer-api/Cargo.toml b/explorer-api/Cargo.toml index 514bfb4852..8832f18372 100644 --- a/explorer-api/Cargo.toml +++ b/explorer-api/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] chrono = { version = "0.4.19", features = ["serde"] } -clap = { version = "3.2", features = ["cargo", "derive"] } +clap = { version = "4.0", features = ["cargo", "derive"] } humantime-serde = "1.0" isocountry = "0.3.2" itertools = "0.10.3" diff --git a/explorer-api/src/main.rs b/explorer-api/src/main.rs index e1a02c57ea..ecfde18949 100644 --- a/explorer-api/src/main.rs +++ b/explorer-api/src/main.rs @@ -8,7 +8,7 @@ use dotenv::dotenv; use log::info; use logging::setup_logging; use network_defaults::setup_env; -use task::TaskManager; +use task::{wait_for_signal, TaskManager}; mod buy_terms; pub(crate) mod cache; @@ -35,7 +35,7 @@ async fn main() { dotenv().ok(); setup_logging(); let args = commands::Cli::parse(); - setup_env(args.config_env_file); + setup_env(args.config_env_file.as_ref()); let mut explorer_api = ExplorerApi::new(); explorer_api.run().await; } @@ -88,31 +88,3 @@ impl ExplorerApi { log::info!("Stopping explorer API"); } } - -#[cfg(unix)] -async fn wait_for_signal() { - use tokio::signal::unix::{signal, SignalKind}; - let mut sigterm = signal(SignalKind::terminate()).expect("Failed to setup SIGTERM channel"); - let mut sigquit = signal(SignalKind::quit()).expect("Failed to setup SIGQUIT channel"); - - tokio::select! { - _ = tokio::signal::ctrl_c() => { - log::info!("Received SIGINT"); - }, - _ = sigterm.recv() => { - log::info!("Received SIGTERM"); - } - _ = sigquit.recv() => { - log::info!("Received SIGQUIT"); - } - } -} - -#[cfg(not(unix))] -async fn wait_for_signal() { - tokio::select! { - _ = tokio::signal::ctrl_c() => { - log::info!("Received SIGINT"); - }, - } -} diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 81fdd10c8b..8dbe55f59d 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -19,13 +19,14 @@ anyhow = "1.0.53" async-trait = { version = "0.1.51" } bip39 = "1.0.1" bs58 = "0.4.0" -clap = { version = "3.2", features = ["cargo", "derive"] } +clap = { version = "4.0", features = ["cargo", "derive"] } colored = "2.0" dashmap = "4.0" dirs = "4.0" dotenv = "0.15.0" futures = "0.3" humantime-serde = "1.0.1" +lazy_static = "1.4.0" log = "0.4" once_cell = "1.7.2" pretty_env_logger = "0.4" @@ -51,6 +52,7 @@ tokio-util = { version = "0.7.3", features = ["codec"] } url = { version = "2.2", features = ["serde"] } # internal +build-information = { path = "../common/build-information" } coconut-interface = { path = "../common/coconut-interface", optional = true } credentials = { path = "../common/credentials" } config = { path = "../common/config" } @@ -85,10 +87,4 @@ sqlx = { version = "0.5", features = [ "sqlite", "macros", "migrate", -] } -vergen = { version = "5", default-features = false, features = [ - "build", - "git", - "rustc", - "cargo", -] } +] } \ No newline at end of file diff --git a/gateway/build.rs b/gateway/build.rs index 16bdf16335..98ad043036 100644 --- a/gateway/build.rs +++ b/gateway/build.rs @@ -1,6 +1,5 @@ use sqlx::{Connection, SqliteConnection}; use std::env; -use vergen::{vergen, Config}; #[tokio::main] async fn main() { @@ -23,6 +22,4 @@ async fn main() { // for some strange reason we need to add a leading `/` to the windows path even though it's // not a valid windows path... but hey, it works... println!("cargo:rustc-env=DATABASE_URL=sqlite:///{}", &database_path); - - vergen(Config::default()).expect("failed to extract build metadata") } diff --git a/gateway/src/commands/init.rs b/gateway/src/commands/init.rs index dab529958f..6bd9ca1d84 100644 --- a/gateway/src/commands/init.rs +++ b/gateway/src/commands/init.rs @@ -1,4 +1,4 @@ -// Copyright 2020 - Nym Technologies SA +// Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::{ @@ -8,6 +8,9 @@ use crate::{ use clap::Args; use config::NymConfig; use crypto::asymmetric::{encryption, identity}; +use std::net::IpAddr; +use std::path::PathBuf; +use validator_client::nymd; #[derive(Args, Clone)] pub struct Init { @@ -17,11 +20,11 @@ pub struct Init { /// The custom host on which the gateway will be running for receiving sphinx packets #[clap(long)] - host: String, + host: IpAddr, /// The wallet address you will use to bond this gateway, e.g. nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9 #[clap(long)] - wallet_address: String, + wallet_address: nymd::AccountId, /// The port on which the gateway will be listening for sphinx packets #[clap(long)] @@ -33,26 +36,27 @@ pub struct Init { /// The host that will be reported to the directory server #[clap(long)] + // TODO: could this be changed to `Option`? announce_host: Option, /// Path to sqlite database containing all gateway persistent data #[clap(long)] - datastore: Option, + datastore: Option, /// Comma separated list of endpoints of nym APIs - #[clap(long, alias = "validator_apis")] + #[clap(long, alias = "validator_apis", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nym_apis: Option, + nym_apis: Option>, /// Comma separated list of endpoints of the validator #[cfg(feature = "coconut")] - #[clap(long, alias = "validators")] + #[clap(long, alias = "validators", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nymd_validators: Option, + nymd_validators: Option>, /// Cosmos wallet mnemonic needed for double spending protection #[clap(long)] - mnemonic: Option, + mnemonic: Option, /// Set this gateway to work only with coconut credentials; that would disallow clients to /// bypass bandwidth credential requirement @@ -66,7 +70,7 @@ pub struct Init { /// URL where a statistics aggregator is running. The default value is a Nym aggregator server #[clap(long)] - statistics_service_url: Option, + statistics_service_url: Option, } impl From for OverrideConfig { @@ -163,12 +167,12 @@ mod tests { async fn create_gateway_with_in_mem_storage() { let args = Init { id: "foo-id".to_string(), - host: "foo-host".to_string(), - wallet_address: "n1z9egw0knv47nmur0p8vk4rcx59h9gg4zjx9ede".to_string(), + host: "1.1.1.1".parse().unwrap(), + wallet_address: "n1z9egw0knv47nmur0p8vk4rcx59h9gg4zjx9ede".parse().unwrap(), mix_port: Some(42), clients_port: Some(43), announce_host: Some("foo-announce-host".to_string()), - datastore: Some("foo-datastore".to_string()), + datastore: Some("/foo-datastore".parse().unwrap()), nym_apis: None, mnemonic: None, statistics_service_url: None, diff --git a/gateway/src/commands/mod.rs b/gateway/src/commands/mod.rs index 46bfbc69a3..61f39b7bb5 100644 --- a/gateway/src/commands/mod.rs +++ b/gateway/src/commands/mod.rs @@ -1,19 +1,20 @@ -// Copyright 2020 - Nym Technologies SA +// Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use std::{process, str::FromStr}; - use crate::{config::Config, Cli}; use clap::CommandFactory; use clap::Subcommand; use colored::Colorize; use completions::{fig_generate, ArgShell}; -use config::parse_urls; use crypto::bech32_address_validation; use network_defaults::mainnet::read_var_if_not_default; use network_defaults::var_names::{ API_VALIDATOR, BECH32_PREFIX, CONFIGURED, STATISTICS_SERVICE_DOMAIN_ADDRESS, }; +use std::net::IpAddr; +use std::path::PathBuf; +use std::process; +use validator_client::nymd::{self}; pub(crate) mod init; pub(crate) mod node_details; @@ -47,19 +48,19 @@ pub(crate) enum Commands { // Configuration that can be overridden. pub(crate) struct OverrideConfig { - host: Option, - wallet_address: Option, + host: Option, + wallet_address: Option, mix_port: Option, clients_port: Option, - datastore: Option, + datastore: Option, announce_host: Option, enabled_statistics: Option, - statistics_service_url: Option, - nym_apis: Option, - mnemonic: Option, + statistics_service_url: Option, + nym_apis: Option>, + mnemonic: Option, #[cfg(feature = "coconut")] - nymd_validators: Option, + nymd_validators: Option>, #[cfg(feature = "coconut")] only_coconut_credentials: bool, } @@ -73,8 +74,8 @@ pub(crate) async fn execute(args: Cli) { Commands::Run(m) => run::execute(m).await, Commands::Sign(m) => sign::execute(m), Commands::Upgrade(m) => upgrade::execute(m).await, - Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name), - Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name), + Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name), + Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name), } } @@ -104,12 +105,8 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi config = config.with_enabled_statistics(enabled_statistics); } - if let Some(raw_url) = args.statistics_service_url { - config = config.with_custom_statistics_service_url( - raw_url - .parse() - .expect("the provided statistics service url is invalid!"), - ); + if let Some(url) = args.statistics_service_url { + config = config.with_custom_statistics_service_url(url); } else if std::env::var(CONFIGURED).is_ok() { if let Some(raw_url) = read_var_if_not_default(STATISTICS_SERVICE_DOMAIN_ADDRESS) { config = config.with_custom_statistics_service_url( @@ -120,8 +117,8 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi } } - if let Some(raw_validators) = args.nym_apis { - config = config.with_custom_nym_apis(parse_urls(&raw_validators)); + if let Some(nym_apis) = args.nym_apis { + config = config.with_custom_nym_apis(nym_apis); } else if std::env::var(CONFIGURED).is_ok() { if let Some(raw_validators) = read_var_if_not_default(API_VALIDATOR) { config = config.with_custom_nym_apis(::config::parse_urls(&raw_validators)) @@ -129,9 +126,9 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi } if let Some(wallet_address) = args.wallet_address { - let trimmed = wallet_address.trim(); - validate_bech32_address_or_exit(trimmed); - config = config.with_wallet_address(trimmed); + // perform extra validation to ensure we have correct prefix + validate_bech32_address_or_exit(wallet_address.as_ref()); + config = config.with_wallet_address(wallet_address); } if let Some(datastore_path) = args.datastore { @@ -139,17 +136,15 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi } if let Some(cosmos_mnemonic) = args.mnemonic { - config = config.with_cosmos_mnemonic( - bip39::Mnemonic::from_str(&cosmos_mnemonic).expect("Provided mnemonic is invalid"), - ); + config = config.with_cosmos_mnemonic(cosmos_mnemonic); } #[cfg(feature = "coconut")] { use network_defaults::var_names::NYMD_VALIDATOR; - if let Some(ref raw_validators) = args.nymd_validators { - config = config.with_custom_validator_nymd(parse_urls(raw_validators)); + if let Some(nymd_validators) = args.nymd_validators { + config = config.with_custom_validator_nymd(nymd_validators); } else if std::env::var(CONFIGURED).is_ok() { if let Some(raw_validators) = read_var_if_not_default(NYMD_VALIDATOR) { config = config.with_custom_validator_nymd(::config::parse_urls(&raw_validators)) diff --git a/gateway/src/commands/run.rs b/gateway/src/commands/run.rs index 369822bf88..c3ceb04b57 100644 --- a/gateway/src/commands/run.rs +++ b/gateway/src/commands/run.rs @@ -1,4 +1,4 @@ -// Copyright 2020 - Nym Technologies SA +// Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::{ @@ -8,6 +8,9 @@ use crate::{ use clap::Args; use config::NymConfig; use log::*; +use std::net::IpAddr; +use std::path::PathBuf; +use validator_client::nymd; #[derive(Args, Clone)] pub struct Run { @@ -17,11 +20,11 @@ pub struct Run { /// The custom host on which the gateway will be running for receiving sphinx packets #[clap(long)] - host: Option, + host: Option, /// The wallet address you will use to bond this gateway, e.g. nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9 #[clap(long)] - wallet_address: Option, + wallet_address: Option, /// The port on which the gateway will be listening for sphinx packets #[clap(long)] @@ -33,26 +36,27 @@ pub struct Run { /// The host that will be reported to the directory server #[clap(long)] + // TODO: could this be changed to `Option`? announce_host: Option, /// Path to sqlite database containing all gateway persistent data #[clap(long)] - datastore: Option, + datastore: Option, /// Comma separated list of endpoints of nym APIs - #[clap(long, alias = "validator_apis")] + #[clap(long, alias = "validator_apis", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nym_apis: Option, + nym_apis: Option>, /// Comma separated list of endpoints of the validator #[cfg(feature = "coconut")] - #[clap(long, alias = "validators")] + #[clap(long, alias = "validators", value_delimiter = ',')] // the alias here is included for backwards compatibility (1.1.4 and before) - nymd_validators: Option, + nymd_validators: Option>, /// Cosmos wallet mnemonic #[clap(long)] - mnemonic: Option, + mnemonic: Option, /// Set this gateway to work only with coconut credentials; that would disallow clients to /// bypass bandwidth credential requirement @@ -66,7 +70,7 @@ pub struct Run { /// URL where a statistics aggregator is running. The default value is a Nym aggregator server #[clap(long)] - statistics_service_url: Option, + statistics_service_url: Option, } impl From for OverrideConfig { diff --git a/gateway/src/commands/sign.rs b/gateway/src/commands/sign.rs index 696ebdc859..63052c6084 100644 --- a/gateway/src/commands/sign.rs +++ b/gateway/src/commands/sign.rs @@ -1,8 +1,9 @@ // Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::commands::validate_bech32_address_or_exit; use crate::{ - commands::{validate_bech32_address_or_exit, version_check}, + commands::version_check, config::{persistence::pathfinder::GatewayPathfinder, Config}, }; use anyhow::{anyhow, Result}; @@ -10,9 +11,10 @@ use clap::{ArgGroup, Args}; use config::NymConfig; use crypto::asymmetric::identity; use log::error; +use validator_client::nymd; #[derive(Args, Clone)] -#[clap(group(ArgGroup::new("sign").required(true).args(&["wallet-address", "text"])))] +#[clap(group(ArgGroup::new("sign").required(true).args(&["wallet_address", "text"])))] pub struct Sign { /// The id of the mixnode you want to sign with #[clap(long)] @@ -20,7 +22,7 @@ pub struct Sign { /// Signs your blockchain address with your identity key #[clap(long)] - wallet_address: Option, + wallet_address: Option, /// Signs an arbitrary piece of text with your identity key #[clap(long)] @@ -29,7 +31,7 @@ pub struct Sign { enum SignedTarget { Text(String), - Address(String), + Address(nymd::AccountId), } impl TryFrom for SignedTarget { @@ -58,15 +60,12 @@ pub fn load_identity_keys(pathfinder: &GatewayPathfinder) -> identity::KeyPair { identity_keypair } -fn print_signed_address(private_key: &identity::PrivateKey, raw_address: &str) { - let trimmed = raw_address.trim(); - validate_bech32_address_or_exit(trimmed); - let signature = private_key.sign_text(trimmed); +fn print_signed_address(private_key: &identity::PrivateKey, wallet_address: nymd::AccountId) { + // perform extra validation to ensure we have correct prefix + validate_bech32_address_or_exit(wallet_address.as_ref()); - println!( - "The base58-encoded signature on '{}' is: {}", - trimmed, signature - ); + let signature = private_key.sign_text(wallet_address.as_ref()); + println!("The base58-encoded signature on '{wallet_address}' is: {signature}",); } fn print_signed_text(private_key: &identity::PrivateKey, text: &str) { @@ -113,6 +112,6 @@ pub fn execute(args: &Sign) { match signed_target { SignedTarget::Text(text) => print_signed_text(identity_keypair.private_key(), &text), - SignedTarget::Address(addr) => print_signed_address(identity_keypair.private_key(), &addr), + SignedTarget::Address(addr) => print_signed_address(identity_keypair.private_key(), addr), } } diff --git a/gateway/src/commands/upgrade.rs b/gateway/src/commands/upgrade.rs index de3549b4f1..6f61401248 100644 --- a/gateway/src/commands/upgrade.rs +++ b/gateway/src/commands/upgrade.rs @@ -103,7 +103,7 @@ fn minor_0_12_upgrade( print_start_upgrade(config_version, &to_version); - let upgraded_config = config.with_custom_version(to_version.to_string().as_ref()); + let upgraded_config = config.with_custom_version(to_version.to_string()); upgraded_config.save_to_file(None).unwrap_or_else(|err| { eprintln!("failed to overwrite config file! - {err}"); diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index e562ec2496..e2c863f34e 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -4,7 +4,6 @@ use crate::config::template::config_template; use config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT}; use config::NymConfig; -use log::error; use network_defaults::mainnet::{API_VALIDATOR, NYMD_VALIDATOR, STATISTICS_SERVICE_DOMAIN_ADDRESS}; use serde::{Deserialize, Serialize}; use std::net::IpAddr; @@ -12,6 +11,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::time::Duration; use url::Url; +use validator_client::nymd; pub mod persistence; mod template; @@ -160,16 +160,8 @@ impl Config { self } - pub fn with_listening_address>(mut self, listening_address: S) -> Self { - let listening_address_string = listening_address.into(); - if let Ok(ip_addr) = listening_address_string.parse() { - self.gateway.listening_address = ip_addr; - } else { - error!( - "failed to change listening address. the provided value ({}) was invalid", - listening_address_string - ); - } + pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self { + self.gateway.listening_address = listening_address; self } @@ -193,18 +185,18 @@ impl Config { self } - pub fn with_custom_persistent_store>(mut self, store_dir: S) -> Self { - self.gateway.persistent_storage = PathBuf::from(store_dir.into()); + pub fn with_custom_persistent_store(mut self, store_dir: PathBuf) -> Self { + self.gateway.persistent_storage = store_dir; self } - pub fn with_custom_version(mut self, version: &str) -> Self { - self.gateway.version = version.to_string(); + pub fn with_custom_version>(mut self, version: S) -> Self { + self.gateway.version = version.into(); self } - pub fn with_wallet_address(mut self, wallet_address: &str) -> Self { - self.gateway.wallet_address = wallet_address.to_string(); + pub fn with_wallet_address(mut self, wallet_address: nymd::AccountId) -> Self { + self.gateway.wallet_address = Some(wallet_address); self } @@ -303,8 +295,8 @@ impl Config { &self.gateway.version } - pub fn get_wallet_address(&self) -> &str { - &self.gateway.wallet_address + pub fn get_wallet_address(&self) -> Option { + self.gateway.wallet_address.clone() } } @@ -378,7 +370,8 @@ pub struct Gateway { persistent_storage: PathBuf, /// The Cosmos wallet address that will control this gateway - wallet_address: String, + // the only reason this is an Option is because of the lack of existence of a sane default value + wallet_address: Option, } impl Gateway { @@ -424,7 +417,7 @@ impl Default for Gateway { cosmos_mnemonic: bip39::Mnemonic::from_str("exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day").unwrap(), nym_root_directory: Config::default_root_directory(), persistent_storage: Default::default(), - wallet_address: "nymXXXXXXXX".to_string(), + wallet_address: None, } } } diff --git a/gateway/src/main.rs b/gateway/src/main.rs index bfcfd0e563..30858ec629 100644 --- a/gateway/src/main.rs +++ b/gateway/src/main.rs @@ -1,24 +1,28 @@ // Copyright 2020 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use build_information::BinaryBuildInformation; use clap::{crate_version, Parser}; +use lazy_static::lazy_static; use logging::setup_logging; use network_defaults::setup_env; -use once_cell::sync::OnceCell; mod commands; mod config; mod node; -static LONG_VERSION: OnceCell = OnceCell::new(); +lazy_static! { + pub static ref PRETTY_BUILD_INFORMATION: String = + BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print(); +} -// Helper for passing LONG_ABOUT to clap -fn long_version_static() -> &'static str { - LONG_VERSION.get().expect("Failed to get long about text") +// Helper for passing LONG_VERSION to clap +fn pretty_build_info_static() -> &'static str { + &PRETTY_BUILD_INFORMATION } #[derive(Parser)] -#[clap(author = "Nymtech", version, about, long_version = long_version_static())] +#[clap(author = "Nymtech", version, about, long_version = pretty_build_info_static())] struct Cli { /// Path pointing to an env file that configures the gateway. #[clap(short, long)] @@ -32,12 +36,9 @@ struct Cli { async fn main() { setup_logging(); println!("{}", banner()); - LONG_VERSION - .set(long_version()) - .expect("Failed to set long about text"); let args = Cli::parse(); - setup_env(args.config_env_file.clone()); + setup_env(args.config_env_file.as_ref()); commands::execute(args).await; } @@ -58,37 +59,6 @@ fn banner() -> String { ) } -fn long_version() -> String { - format!( - r#" -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -"#, - "Build Timestamp:", - env!("VERGEN_BUILD_TIMESTAMP"), - "Build Version:", - env!("VERGEN_BUILD_SEMVER"), - "Commit SHA:", - env!("VERGEN_GIT_SHA"), - "Commit Date:", - env!("VERGEN_GIT_COMMIT_TIMESTAMP"), - "Commit Branch:", - env!("VERGEN_GIT_BRANCH"), - "rustc Version:", - env!("VERGEN_RUSTC_SEMVER"), - "rustc Channel:", - env!("VERGEN_RUSTC_CHANNEL"), - "cargo Profile:", - env!("VERGEN_CARGO_PROFILE") - ) -} - #[cfg(test)] mod tests { use super::*; @@ -96,9 +66,6 @@ mod tests { #[test] fn verify_cli() { - LONG_VERSION - .set(long_version()) - .expect("Failed to set long about text"); Cli::command().debug_assert(); } } diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 7500302787..ead37ec62a 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -1,19 +1,20 @@ -// Copyright 2020 - Nym Technologies SA +// Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use self::storage::PersistentStorage; use crate::commands::sign::load_identity_keys; use crate::commands::validate_bech32_address_or_exit; +use crate::config::persistence::pathfinder::GatewayPathfinder; use crate::config::Config; use crate::node::client_handling::active_clients::ActiveClientsStore; use crate::node::client_handling::websocket; use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler; use crate::node::statistics::collector::GatewayStatisticsCollector; use crate::node::storage::Storage; +use colored::Colorize; use crypto::asymmetric::{encryption, identity}; use log::*; use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder}; -#[cfg(feature = "coconut")] -use network_defaults::NymNetworkDetails; use rand::seq::SliceRandom; use rand::thread_rng; use statistics_common::collector::StatisticsSender; @@ -21,16 +22,15 @@ use std::net::SocketAddr; use std::process; use std::sync::Arc; -use crate::config::persistence::pathfinder::GatewayPathfinder; #[cfg(feature = "coconut")] use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier; #[cfg(feature = "coconut")] use credentials::coconut::utils::obtain_aggregate_verification_key; #[cfg(feature = "coconut")] +use network_defaults::NymNetworkDetails; +#[cfg(feature = "coconut")] use validator_client::{Client, CoconutApiClient}; -use self::storage::PersistentStorage; - pub(crate) mod client_handling; pub(crate) mod mixnet_handling; pub(crate) mod statistics; @@ -117,9 +117,15 @@ where fn generate_owner_signature(&self) -> String { let pathfinder = GatewayPathfinder::new_from_config(&self.config); let identity_keypair = load_identity_keys(&pathfinder); - let address = self.config.get_wallet_address(); - validate_bech32_address_or_exit(address); - let verification_code = identity_keypair.private_key().sign_text(address); + let Some(address) = self.config.get_wallet_address() else { + let error_message = "Error: gateway hasn't set its wallet address".red(); + println!("{error_message}"); + println!("Exiting..."); + process::exit(1); + }; + // perform extra validation to ensure we have correct prefix + validate_bech32_address_or_exit(address.as_ref()); + let verification_code = identity_keypair.private_key().sign_text(address.as_ref()); verification_code } diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index 776b7594f3..b4e53f7af3 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.58.1" [dependencies] anyhow = "1.0.40" bs58 = "0.4.0" -clap = { version = "3.2", features = ["cargo", "derive"] } +clap = { version = "4.0", features = ["cargo", "derive"] } colored = "2.0" cupid = "0.6.1" dirs = "4.0" @@ -38,6 +38,7 @@ toml = "0.5.8" url = { version = "2.2", features = ["serde"] } ## internal +build-information = { path = "../common/build-information" } config = { path="../common/config" } crypto = { path="../common/crypto" } completions = { path="../common/completions" } @@ -57,6 +58,3 @@ tokio = { version="1.21.2", features = ["rt-multi-thread", "net", "signal", "tes nymsphinx-types = { path = "../common/nymsphinx/types" } nymsphinx-params = { path = "../common/nymsphinx/params" } - -[build-dependencies] -vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } diff --git a/mixnode/build.rs b/mixnode/build.rs deleted file mode 100644 index 01b3a20dc6..0000000000 --- a/mixnode/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2021 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use vergen::{vergen, Config}; - -fn main() { - vergen(Config::default()).expect("failed to extract build metadata") -} diff --git a/mixnode/src/commands/init.rs b/mixnode/src/commands/init.rs index d3e6036ba0..81e61eb5ac 100644 --- a/mixnode/src/commands/init.rs +++ b/mixnode/src/commands/init.rs @@ -1,14 +1,15 @@ // Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use super::OverrideConfig; use crate::config::Config; use crate::node::MixNode; use crate::{commands::override_config, config::persistence::pathfinder::MixNodePathfinder}; use clap::Args; use config::NymConfig; use crypto::asymmetric::{encryption, identity}; - -use super::OverrideConfig; +use std::net::IpAddr; +use validator_client::nymd; #[derive(Args, Clone)] pub(crate) struct Init { @@ -18,11 +19,11 @@ pub(crate) struct Init { /// The host on which the mixnode will be running #[clap(long)] - host: String, + host: IpAddr, /// The wallet address you will use to bond this mixnode, e.g. nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9 #[clap(long)] - wallet_address: String, + wallet_address: nymd::AccountId, /// The port on which the mixnode will be listening for mix packets #[clap(long)] @@ -42,8 +43,8 @@ pub(crate) struct Init { /// Comma separated list of nym-api endpoints of the validators // the alias here is included for backwards compatibility (1.1.4 and before) - #[clap(long, alias = "validators")] - nym_apis: Option, + #[clap(long, alias = "validators", value_delimiter = ',')] + nym_apis: Option>, } impl From for OverrideConfig { diff --git a/mixnode/src/commands/mod.rs b/mixnode/src/commands/mod.rs index 7eaf4b5347..ffff8b0d9e 100644 --- a/mixnode/src/commands/mod.rs +++ b/mixnode/src/commands/mod.rs @@ -1,19 +1,17 @@ // Copyright 2020 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use std::process; - use crate::{config::Config, Cli}; use clap::CommandFactory; use clap::Subcommand; use colored::Colorize; use completions::{fig_generate, ArgShell}; use config::defaults::mainnet::read_var_if_not_default; -use config::{ - defaults::var_names::{API_VALIDATOR, BECH32_PREFIX, CONFIGURED}, - parse_urls, -}; +use config::defaults::var_names::{API_VALIDATOR, BECH32_PREFIX, CONFIGURED}; use crypto::bech32_address_validation; +use std::net::IpAddr; +use std::process; +use validator_client::nymd; mod describe; mod init; @@ -52,13 +50,13 @@ pub(crate) enum Commands { // Configuration that can be overridden. struct OverrideConfig { id: String, - host: Option, - wallet_address: Option, + host: Option, + wallet_address: Option, mix_port: Option, verloc_port: Option, http_api_port: Option, announce_host: Option, - nym_apis: Option, + nym_apis: Option>, } pub(crate) async fn execute(args: Cli) { @@ -71,8 +69,8 @@ pub(crate) async fn execute(args: Cli) { Commands::Sign(m) => sign::execute(&m), Commands::Upgrade(m) => upgrade::execute(&m), Commands::NodeDetails(m) => node_details::execute(&m), - Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name), - Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name), + Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name), + Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name), } } @@ -95,8 +93,8 @@ fn override_config(mut config: Config, args: OverrideConfig) -> Config { config = config.with_http_api_port(port); } - if let Some(ref raw_validators) = args.nym_apis { - config = config.with_custom_nym_apis(parse_urls(raw_validators)); + if let Some(nym_apis) = args.nym_apis { + config = config.with_custom_nym_apis(nym_apis); } else if std::env::var(CONFIGURED).is_ok() { if let Some(raw_validators) = read_var_if_not_default(API_VALIDATOR) { config = config.with_custom_nym_apis(::config::parse_urls(&raw_validators)) @@ -110,10 +108,10 @@ fn override_config(mut config: Config, args: OverrideConfig) -> Config { config = config.announce_address_from_listening_address() } - if let Some(ref wallet_address) = args.wallet_address { - let trimmed = wallet_address.trim(); - validate_bech32_address_or_exit(trimmed); - config = config.with_wallet_address(trimmed); + if let Some(wallet_address) = args.wallet_address { + // perform extra validation to ensure we have correct prefix + validate_bech32_address_or_exit(wallet_address.as_ref()); + config = config.with_wallet_address(wallet_address); } config diff --git a/mixnode/src/commands/run.rs b/mixnode/src/commands/run.rs index 37786730fe..859ea2406a 100644 --- a/mixnode/src/commands/run.rs +++ b/mixnode/src/commands/run.rs @@ -1,13 +1,14 @@ // Copyright 2020 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use super::OverrideConfig; use crate::commands::{override_config, version_check}; use crate::config::Config; use crate::node::MixNode; use clap::Args; use config::NymConfig; - -use super::OverrideConfig; +use std::net::IpAddr; +use validator_client::nymd; #[derive(Args, Clone)] pub(crate) struct Run { @@ -17,11 +18,11 @@ pub(crate) struct Run { /// The custom host on which the mixnode will be running #[clap(long)] - host: Option, + host: Option, /// The wallet address you will use to bond this mixnode, e.g. nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9 #[clap(long)] - wallet_address: Option, + wallet_address: Option, /// The port on which the mixnode will be listening for mix packets #[clap(long)] @@ -41,8 +42,8 @@ pub(crate) struct Run { /// Comma separated list of nym-api endpoints of the validators // the alias here is included for backwards compatibility (1.1.4 and before) - #[clap(long, alias = "validators")] - nym_apis: Option, + #[clap(long, alias = "validators", value_delimiter = ',')] + nym_apis: Option>, } impl From for OverrideConfig { diff --git a/mixnode/src/commands/sign.rs b/mixnode/src/commands/sign.rs index 5967e99dd0..e9b137be79 100644 --- a/mixnode/src/commands/sign.rs +++ b/mixnode/src/commands/sign.rs @@ -11,11 +11,12 @@ use clap::{ArgGroup, Args}; use config::NymConfig; use crypto::asymmetric::identity; use log::error; +use validator_client::nymd; use super::version_check; #[derive(Args, Clone)] -#[clap(group(ArgGroup::new("sign").required(true).args(&["wallet-address", "text"])))] +#[clap(group(ArgGroup::new("sign").required(true).args(&["wallet_address", "text"])))] pub(crate) struct Sign { /// The id of the mixnode you want to sign with #[clap(long)] @@ -24,7 +25,7 @@ pub(crate) struct Sign { /// Signs your blockchain address with your identity key // the alias here is included for backwards compatibility (1.1.4 and before) #[clap(long, alias = "address")] - wallet_address: Option, + wallet_address: Option, /// Signs an arbitrary piece of text with your identity key #[clap(long)] @@ -33,7 +34,7 @@ pub(crate) struct Sign { enum SignedTarget { Text(String), - Address(String), + Address(nymd::AccountId), } impl TryFrom for SignedTarget { @@ -53,15 +54,12 @@ impl TryFrom for SignedTarget { } } -fn print_signed_address(private_key: &identity::PrivateKey, raw_address: &str) { - let trimmed = raw_address.trim(); - validate_bech32_address_or_exit(trimmed); - let signature = private_key.sign_text(trimmed); +fn print_signed_address(private_key: &identity::PrivateKey, wallet_address: nymd::AccountId) { + // perform extra validation to ensure we have correct prefix + validate_bech32_address_or_exit(wallet_address.as_ref()); - println!( - "The base58-encoded signature on '{}' is: {}", - trimmed, signature - ); + let signature = private_key.sign_text(wallet_address.as_ref()); + println!("The base58-encoded signature on '{wallet_address}' is: {signature}",); } fn print_signed_text(private_key: &identity::PrivateKey, text: &str) { @@ -108,6 +106,6 @@ pub(crate) fn execute(args: &Sign) { match signed_target { SignedTarget::Text(text) => print_signed_text(identity_keypair.private_key(), &text), - SignedTarget::Address(addr) => print_signed_address(identity_keypair.private_key(), &addr), + SignedTarget::Address(addr) => print_signed_address(identity_keypair.private_key(), addr), } } diff --git a/mixnode/src/config/mod.rs b/mixnode/src/config/mod.rs index bc9278bc85..8941e555f2 100644 --- a/mixnode/src/config/mod.rs +++ b/mixnode/src/config/mod.rs @@ -13,6 +13,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::time::Duration; use url::Url; +use validator_client::nymd; pub mod persistence; mod template; @@ -160,16 +161,8 @@ impl Config { self } - pub fn with_listening_address>(mut self, listening_address: S) -> Self { - let listening_address_string = listening_address.into(); - if let Ok(ip_addr) = listening_address_string.parse() { - self.mixnode.listening_address = ip_addr - } else { - error!( - "failed to change listening address. the provided value ({}) was invalid", - listening_address_string - ) - } + pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self { + self.mixnode.listening_address = listening_address; self } @@ -203,8 +196,8 @@ impl Config { self } - pub fn with_wallet_address(mut self, wallet_address: &str) -> Self { - self.mixnode.wallet_address = wallet_address.to_string(); + pub fn with_wallet_address(mut self, wallet_address: nymd::AccountId) -> Self { + self.mixnode.wallet_address = Some(wallet_address); self } @@ -317,8 +310,8 @@ impl Config { self.verloc.retry_timeout } - pub fn get_wallet_address(&self) -> &str { - &self.mixnode.wallet_address + pub fn get_wallet_address(&self) -> Option { + self.mixnode.wallet_address.clone() } } @@ -377,7 +370,8 @@ struct MixNode { nym_root_directory: PathBuf, /// The Cosmos wallet address that will control this mixnode - wallet_address: String, + // the only reason this is an Option is because of the lack of existence of a sane default value + wallet_address: Option, } impl MixNode { @@ -414,7 +408,7 @@ impl Default for MixNode { public_sphinx_key_file: Default::default(), nym_api_urls: vec![Url::from_str(API_VALIDATOR).expect("Invalid default API URL")], nym_root_directory: Config::default_root_directory(), - wallet_address: "nymXXXXXXXX".to_string(), + wallet_address: None, } } } diff --git a/mixnode/src/main.rs b/mixnode/src/main.rs index ac0b99c1bf..8090ff1b10 100644 --- a/mixnode/src/main.rs +++ b/mixnode/src/main.rs @@ -1,10 +1,11 @@ +// Copyright 2020-2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + #[macro_use] extern crate rocket; -// Copyright 2020 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - use ::config::defaults::setup_env; +use build_information::BinaryBuildInformation; use clap::{crate_version, Parser}; use lazy_static::lazy_static; use logging::setup_logging; @@ -14,16 +15,17 @@ mod config; mod node; lazy_static! { - pub static ref LONG_VERSION: String = long_version(); + pub static ref PRETTY_BUILD_INFORMATION: String = + BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print(); } // Helper for passing LONG_VERSION to clap -fn long_version_static() -> &'static str { - &LONG_VERSION +fn pretty_build_info_static() -> &'static str { + &PRETTY_BUILD_INFORMATION } #[derive(Parser)] -#[clap(author = "Nymtech", version, about, long_version = long_version_static())] +#[clap(author = "Nymtech", version, about, long_version = pretty_build_info_static())] struct Cli { /// Path pointing to an env file that configures the mixnode. #[clap(short, long)] @@ -39,7 +41,7 @@ async fn main() { println!("{}", banner()); let args = Cli::parse(); - setup_env(args.config_env_file.clone()); + setup_env(args.config_env_file.as_ref()); commands::execute(args).await; } @@ -60,37 +62,6 @@ fn banner() -> String { ) } -fn long_version() -> String { - format!( - r#" -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -"#, - "Build Timestamp:", - env!("VERGEN_BUILD_TIMESTAMP"), - "Build Version:", - env!("VERGEN_BUILD_SEMVER"), - "Commit SHA:", - env!("VERGEN_GIT_SHA"), - "Commit Date:", - env!("VERGEN_GIT_COMMIT_TIMESTAMP"), - "Commit Branch:", - env!("VERGEN_GIT_BRANCH"), - "rustc Version:", - env!("VERGEN_RUSTC_SEMVER"), - "rustc Channel:", - env!("VERGEN_RUSTC_CHANNEL"), - "cargo Profile:", - env!("VERGEN_CARGO_PROFILE") - ) -} - #[cfg(test)] mod tests { use super::*; diff --git a/mixnode/src/node/mod.rs b/mixnode/src/node/mod.rs index 9fdbff3ebb..3195ebe099 100644 --- a/mixnode/src/node/mod.rs +++ b/mixnode/src/node/mod.rs @@ -18,6 +18,7 @@ use crate::node::node_description::NodeDescription; use crate::node::node_statistics::SharedNodeStats; use crate::node::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSender}; use ::crypto::asymmetric::{encryption, identity}; +use colored::Colorize; use config::NymConfig; use log::{error, info, warn}; use mixnode_common::verloc::{self, AtomicVerlocResult, VerlocMeasurer}; @@ -87,9 +88,15 @@ impl MixNode { fn generate_owner_signature(&self) -> String { let pathfinder = MixNodePathfinder::new_from_config(&self.config); let identity_keypair = Self::load_identity_keys(&pathfinder); - let address = self.config.get_wallet_address(); - validate_bech32_address_or_exit(address); - let verification_code = identity_keypair.private_key().sign_text(address); + let Some(address) = self.config.get_wallet_address() else { + let error_message = "Error: mixnode hasn't set its wallet address".red(); + println!("{error_message}"); + println!("Exiting..."); + process::exit(1); + }; + // perform extra validation to ensure we have correct prefix + validate_bech32_address_or_exit(address.as_ref()); + let verification_code = identity_keypair.private_key().sign_text(address.as_ref()); verification_code } @@ -118,7 +125,10 @@ impl MixNode { ); println!( "You are bonding to wallet address: {}\n\n", - self.config.get_wallet_address() + self.config + .get_wallet_address() + .map(|addr| addr.to_string()) + .unwrap_or_else(|| "UNSPECIFIED".to_string()) ); } diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index 0417d93043..a790bdc4db 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -17,13 +17,15 @@ rust-version = "1.56" [dependencies] async-trait = "0.1.52" bs58 = {version = "0.4.0", optional = true } +bip39 = "1" cfg-if = "1.0" -clap = { version = "3.2", features = ["cargo"] } +clap = { version = "4.0", features = ["cargo", "derive"] } console-subscriber = { version = "0.1.1", optional = true } # validator-api needs to be built with RUSTFLAGS="--cfg tokio_unstable" dirs = "4.0" dotenv = "0.15.0" futures = "0.3.24" humantime-serde = "1.0" +lazy_static = "1.4.0" log = "0.4.17" pin-project = "1.0" pretty_env_logger = "0.4.0" @@ -63,6 +65,7 @@ rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger"] } schemars = { version = "0.8", features = ["preserve_order"] } ## internal +build-information = { path = "../common/build-information" } coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" } coconut-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg", optional = true } coconut-interface = { path = "../common/coconut-interface", optional = true } @@ -115,12 +118,6 @@ sqlx = { version = "0.6.2", features = [ "macros", "migrate", ] } -vergen = { version = "7", default-features = false, features = [ - "build", - "git", - "rustc", - "cargo", -] } [dev-dependencies] cw3 = "0.13.4" diff --git a/nym-api/build.rs b/nym-api/build.rs index 6c92dffc59..cdd97f9505 100644 --- a/nym-api/build.rs +++ b/nym-api/build.rs @@ -1,6 +1,5 @@ use sqlx::{Connection, SqliteConnection}; use std::env; -use vergen::{vergen, Config}; #[tokio::main] async fn main() { @@ -23,6 +22,4 @@ async fn main() { // for some strange reason we need to add a leading `/` to the windows path even though it's // not a valid windows path... but hey, it works... println!("cargo:rustc-env=DATABASE_URL=sqlite:///{}", &database_path); - - vergen(Config::default()).expect("failed to extract build metadata") } diff --git a/nym-api/src/main.rs b/nym-api/src/main.rs index 777fbad09d..aa2981d90f 100644 --- a/nym-api/src/main.rs +++ b/nym-api/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2020 - Nym Technologies SA +// Copyright 2020-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 #[macro_use] @@ -6,6 +6,7 @@ extern crate rocket; use crate::config::Config; use crate::contract_cache::ValidatorCacheRefresher; +use crate::epoch_operations::RewardedSetUpdater; use crate::network_monitor::NetworkMonitorBuilder; use crate::node_status_api::uptime_updater::HistoricalUptimeUpdater; use crate::nymd_client::Client; @@ -15,9 +16,12 @@ use ::config::defaults::setup_env; use ::config::defaults::var_names::{CONFIGURED, MIXNET_CONTRACT_ADDRESS, MIX_DENOM}; use ::config::NymConfig; use anyhow::Result; -use clap::{crate_version, App, Arg, ArgMatches}; +use build_information::BinaryBuildInformation; +use clap::Parser; use contract_cache::ValidatorCache; +use lazy_static::lazy_static; use log::{info, warn}; +use logging::setup_logging; use node_status_api::NodeStatusCache; use okapi::openapi3::OpenApi; use rocket::fairing::AdHoc; @@ -26,27 +30,21 @@ use rocket::{Ignite, Rocket}; use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors}; use rocket_okapi::mount_endpoints_and_merged_docs; use rocket_okapi::swagger_ui::make_swagger_ui; -use std::path::PathBuf; -use std::str::FromStr; use std::sync::Arc; use std::time::Duration; use std::{fs, process}; -use task::TaskManager; +use task::{wait_for_signal, TaskManager}; use tokio::sync::Notify; -#[cfg(feature = "coconut")] -use url::Url; -use validator_client::nymd::SigningNymdClient; +use validator_client::nymd::{self, SigningNymdClient}; -use crate::epoch_operations::RewardedSetUpdater; #[cfg(feature = "coconut")] use coconut::{ comm::QueryCommunicationChannel, dkg::controller::{init_keypair, DkgController}, InternalSignRequest, }; -use logging::setup_logging; #[cfg(feature = "coconut")] -use validator_client::nymd::bip32::secp256k1::elliptic_curve::rand_core::OsRng; +use rand::rngs::OsRng; pub(crate) mod config; pub(crate) mod contract_cache; @@ -60,150 +58,92 @@ mod swagger; #[cfg(feature = "coconut")] mod coconut; -const ID: &str = "id"; -const CONFIG_ENV_FILE: &str = "config-env-file"; -const MONITORING_ENABLED: &str = "enable-monitor"; -const REWARDING_ENABLED: &str = "enable-rewarding"; -const MIXNET_CONTRACT_ARG: &str = "mixnet-contract"; -const MNEMONIC_ARG: &str = "mnemonic"; -const WRITE_CONFIG_ARG: &str = "save-config"; -const NYMD_VALIDATOR_ARG: &str = "nymd-validator"; -const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode"; - -#[cfg(feature = "coconut")] -const ANNOUNCE_ADDRESS: &str = "announce-address"; -#[cfg(feature = "coconut")] -const COCONUT_ENABLED: &str = "enable-coconut"; - -const REWARDING_MONITOR_THRESHOLD_ARG: &str = "monitor-threshold"; - -const MIN_MIXNODE_RELIABILITY_ARG: &str = "min_mixnode_reliability"; -const MIN_GATEWAY_RELIABILITY_ARG: &str = "min_gateway_reliability"; - -fn long_version() -> String { - format!( - r#" -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -{:<20}{} -"#, - "Build Timestamp:", - env!("VERGEN_BUILD_TIMESTAMP"), - "Build Version:", - env!("VERGEN_BUILD_SEMVER"), - "Commit SHA:", - env!("VERGEN_GIT_SHA"), - "Commit Date:", - env!("VERGEN_GIT_COMMIT_TIMESTAMP"), - "Commit Branch:", - env!("VERGEN_GIT_BRANCH"), - "rustc Version:", - env!("VERGEN_RUSTC_SEMVER"), - "rustc Channel:", - env!("VERGEN_RUSTC_CHANNEL"), - "cargo Profile:", - env!("VERGEN_CARGO_PROFILE") - ) +lazy_static! { + pub static ref PRETTY_BUILD_INFORMATION: String = + BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print(); } -fn parse_args() -> ArgMatches { - let build_details = long_version(); - let base_app = App::new("Nym API") - .version(crate_version!()) - .long_version(&*build_details) - .author("Nymtech") - .arg( - Arg::with_name(CONFIG_ENV_FILE) - .help("Path pointing to an env file that configures the Nym API") - .long(CONFIG_ENV_FILE) - .short('c') - .takes_value(true) - ) - .arg( - Arg::with_name(ID) - .help("Id of the nym-api we want to run") - .long(ID) - .takes_value(true) - ) - .arg( - Arg::with_name(MONITORING_ENABLED) - .help("specifies whether a network monitoring is enabled on this API") - .long(MONITORING_ENABLED) - .short('m') - ) - .arg( - Arg::with_name(REWARDING_ENABLED) - .help("specifies whether a network rewarding is enabled on this API") - .long(REWARDING_ENABLED) - .short('r') - .requires_all(&[MONITORING_ENABLED, MNEMONIC_ARG]) - ) - .arg( - Arg::with_name(NYMD_VALIDATOR_ARG) - .help("Endpoint to nymd instance from which the monitor will grab nodes to test") - .long(NYMD_VALIDATOR_ARG) - .takes_value(true) - ) - .arg(Arg::with_name(MIXNET_CONTRACT_ARG) - .long(MIXNET_CONTRACT_ARG) - .help("Address of the mixnet contract managing the network") - .takes_value(true), - ) - .arg(Arg::with_name(MNEMONIC_ARG) - .long(MNEMONIC_ARG) - .help("Mnemonic of the network monitor used for rewarding operators") - .takes_value(true) - ) - .arg( - Arg::with_name(WRITE_CONFIG_ARG) - .help("specifies whether a config file based on provided arguments should be saved to a file") - .long(WRITE_CONFIG_ARG) - .short('w') - ) - .arg( - Arg::with_name(REWARDING_MONITOR_THRESHOLD_ARG) - .help("Specifies the minimum percentage of monitor test run data present in order to distribute rewards for given interval.") - .takes_value(true) - .long(REWARDING_MONITOR_THRESHOLD_ARG) - ) - .arg( - Arg::with_name(MIN_MIXNODE_RELIABILITY_ARG) - .long(MIN_MIXNODE_RELIABILITY_ARG) - .help("Mixnodes with reliability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.") - .takes_value(true) - ) - .arg( - Arg::with_name(MIN_GATEWAY_RELIABILITY_ARG) - .long(MIN_GATEWAY_RELIABILITY_ARG) - .help("Gateways with reliability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.") - .takes_value(true) - ) - .arg( - Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME) - .long(ENABLED_CREDENTIALS_MODE_ARG_NAME) - .help("Set this nym api to work in a enabled credentials that would attempt to use gateway with the bandwidth credential requirement") - ); +// Helper for passing LONG_VERSION to clap +fn pretty_build_info_static() -> &'static str { + &PRETTY_BUILD_INFORMATION +} +// explicitly defined custom parser (as opposed to just using +// #[arg(value_parser = clap::value_parser!(u8).range(0..100))] +// for better error message +fn threshold_in_range(s: &str) -> Result { + let threshold: usize = s + .parse() + .map_err(|_| format!("`{s}` isn't a valid threshold number"))?; + if threshold > 100 { + Err(format!("{threshold} is not within the range 0-100")) + } else { + Ok(threshold as u8) + } +} + +#[derive(Parser)] +#[clap(author = "Nymtech", version, long_version = pretty_build_info_static(), about)] +struct ApiArgs { + /// Path pointing to an env file that configures the Nym API. + #[clap(short, long)] + config_env_file: Option, + + /// Id of the nym-api we want to run + #[clap(long)] + id: Option, + + /// Specifies whether network monitoring is enabled on this API + #[clap(short = 'm', long)] + enable_monitor: bool, + + /// Specifies whether network rewarding is enabled on this API + #[clap(short = 'r', long, requires = "enable_monitor", requires = "mnemonic")] + enable_rewarding: bool, + + /// Endpoint to nymd instance from which the monitor will grab nodes to test + #[clap(long)] + nymd_validator: Option, + + /// Address of the mixnet contract managing the network + #[clap(long)] + mixnet_contract: Option, + + /// Mnemonic of the network monitor used for rewarding operators + // even though we're currently converting the mnemonic to string (and then back to the concrete type) + // at least we're getting immediate validation when passing the arguments + #[clap(long)] + mnemonic: Option, + + /// Specifies whether a config file based on provided arguments should be saved to a file + #[clap(short = 'w', long)] + save_config: bool, + + /// Specifies the minimum percentage of monitor test run data present in order to distribute rewards for given interval. + #[clap(long, value_parser = threshold_in_range)] + monitor_threshold: Option, + + /// Mixnodes with reliability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set. + #[clap(long, value_parser = threshold_in_range)] + min_mixnode_reliability: Option, + + /// Gateways with reliability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set. + #[clap(long, value_parser = threshold_in_range)] + min_gateway_reliability: Option, + + /// Set this nym api to work in a enabled credentials that would attempt to use gateway with the bandwidth credential requirement + #[clap(long)] + enabled_credentials_mode: bool, + + /// Announced address where coconut clients will connect. #[cfg(feature = "coconut")] - let base_app = base_app - .arg( - Arg::with_name(ANNOUNCE_ADDRESS) - .help("Announced address where coconut clients will connect.") - .long(ANNOUNCE_ADDRESS) - .takes_value(true), - ) - .arg( - Arg::with_name(COCONUT_ENABLED) - .help("Flag to indicate whether coconut signer authority is enabled on this API") - .requires_all(&[MNEMONIC_ARG, ANNOUNCE_ADDRESS]) - .long(COCONUT_ENABLED), - ); - base_app.get_matches() + #[clap(long)] + announce_address: Option, + + /// Flag to indicate whether coconut signer authority is enabled on this API + #[cfg(feature = "coconut")] + #[clap(long, requires = "mnemonic", requires = "announce-address")] + enable_coconut: bool, } async fn wait_for_interrupt(mut shutdown: TaskManager) { @@ -218,122 +158,55 @@ async fn wait_for_interrupt(mut shutdown: TaskManager) { log::info!("Stopping nym API"); } -#[cfg(unix)] -async fn wait_for_signal() { - use tokio::signal::unix::{signal, SignalKind}; - let mut sigterm = signal(SignalKind::terminate()).expect("Failed to setup SIGTERM channel"); - let mut sigquit = signal(SignalKind::quit()).expect("Failed to setup SIGQUIT channel"); - - tokio::select! { - _ = tokio::signal::ctrl_c() => { - log::info!("Received SIGINT"); - }, - _ = sigterm.recv() => { - log::info!("Received SIGTERM"); - } - _ = sigquit.recv() => { - log::info!("Received SIGQUIT"); - } - } -} - -#[cfg(not(unix))] -async fn wait_for_signal() { - tokio::select! { - _ = tokio::signal::ctrl_c() => { - log::info!("Received SIGINT"); - }, - } -} - -fn override_config(mut config: Config, matches: &ArgMatches) -> Config { - if let Some(id) = matches.value_of(ID) { - fs::create_dir_all(Config::default_config_directory(Some(id))) +fn override_config(mut config: Config, args: ApiArgs) -> Config { + if let Some(id) = args.id { + fs::create_dir_all(Config::default_config_directory(Some(&id))) .expect("Could not create config directory"); - fs::create_dir_all(Config::default_data_directory(Some(id))) + fs::create_dir_all(Config::default_data_directory(Some(&id))) .expect("Could not create data directory"); - config = config.with_id(id); + config = config.with_id(&id); } - if matches.is_present(MONITORING_ENABLED) { - config = config.with_network_monitor_enabled(true) + config = config + .with_network_monitor_enabled(args.enable_monitor) + .with_rewarding_enabled(args.enable_rewarding) + .with_disabled_credentials_mode(!args.enabled_credentials_mode); + + if let Some(nymd_validator) = args.nymd_validator { + config = config.with_custom_nymd_validator(nymd_validator); } - if matches.is_present(REWARDING_ENABLED) { - config = config.with_rewarding_enabled(true) - } - - #[cfg(feature = "coconut")] - if matches.is_present(COCONUT_ENABLED) { - config = config.with_coconut_signer_enabled(true) - } - - #[cfg(feature = "coconut")] - if let Some(announce_address) = matches.value_of(ANNOUNCE_ADDRESS) { - config = config.with_announce_address( - Url::parse(announce_address).expect("Could not parse announce address"), - ); - } - - if let Some(raw_validator) = matches.value_of(NYMD_VALIDATOR_ARG) { - let parsed = match raw_validator.parse() { - Err(err) => { - error!("Passed validator argument is invalid - {err}"); - process::exit(1) - } - Ok(url) => url, - }; - config = config.with_custom_nymd_validator(parsed); - } - - if let Some(mixnet_contract) = matches.value_of(MIXNET_CONTRACT_ARG) { - config = config.with_custom_mixnet_contract(mixnet_contract) + if let Some(mixnet_contract) = args.mixnet_contract { + config = config.with_custom_mixnet_contract(mixnet_contract.to_string()) } else if std::env::var(CONFIGURED).is_ok() { if let Some(mixnet_contract) = read_var_if_not_default(MIXNET_CONTRACT_ADDRESS) { config = config.with_custom_mixnet_contract(mixnet_contract) } } - - if let Some(mnemonic) = matches.value_of(MNEMONIC_ARG) { - config = config.with_mnemonic(mnemonic) + if let Some(mnemonic) = args.mnemonic { + config = config.with_mnemonic(mnemonic.to_string()) } - if let Some(monitor_threshold) = matches - .value_of(REWARDING_MONITOR_THRESHOLD_ARG) - .map(|t| t.parse::()) - { - let monitor_threshold = - monitor_threshold.expect("Provided monitor threshold is not a number!"); - assert!( - monitor_threshold <= 100, - "Provided monitor threshold is greater than 100!" - ); + if let Some(monitor_threshold) = args.monitor_threshold { config = config.with_minimum_interval_monitor_threshold(monitor_threshold) } - if let Some(reliability) = matches - .value_of(MIN_MIXNODE_RELIABILITY_ARG) - .map(|t| t.parse::()) - { - config = config.with_min_mixnode_reliability( - reliability.expect("Provided reliability is not a u8 number!"), - ) + if let Some(reliability) = args.min_mixnode_reliability { + config = config.with_min_mixnode_reliability(reliability) } - if let Some(reliability) = matches - .value_of(MIN_GATEWAY_RELIABILITY_ARG) - .map(|t| t.parse::()) - { - config = config.with_min_gateway_reliability( - reliability.expect("Provided reliability is not a u8 number!"), - ) + if let Some(reliability) = args.min_gateway_reliability { + config = config.with_min_gateway_reliability(reliability) } - if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) { - config = config.with_disabled_credentials_mode(false) + #[cfg(feature = "coconut")] + if let Some(announce_address) = args.announce_address { + config = config + .with_announce_address(announce_address) + .with_coconut_signer_enabled(args.enable_coconut); } - if matches.is_present(WRITE_CONFIG_ARG) { + if args.save_config { info!("Saving the configuration to a file"); if let Err(err) = config.save_to_file(None) { error!("Failed to write config to a file - {err}"); @@ -490,11 +363,11 @@ fn get_servers() -> Vec { }] } -async fn run_nym_api(matches: ArgMatches) -> Result<()> { +async fn run_nym_api(args: ApiArgs) -> Result<()> { let system_version = env!("CARGO_PKG_VERSION"); // try to load config from the file, if it doesn't exist, use default values - let id = matches.value_of(ID); + let id = args.id.as_deref(); let (config, _already_inited) = match Config::load_from_file(id) { Ok(cfg) => (cfg, true), Err(_) => { @@ -503,14 +376,14 @@ async fn run_nym_api(matches: ArgMatches) -> Result<()> { .into_string() .unwrap(); warn!( - "Could not load the configuration file from {}. Either the file did not exist or was malformed. Using the default values instead", - config_path + "Could not load the configuration file from {config_path}. Either the file did not exist or was malformed. Using the default values instead", ); (Config::new(), false) } }; - let config = override_config(config, &matches); + let save_to_file = args.save_config; + let config = override_config(config, args); #[cfg(feature = "coconut")] if !_already_inited { @@ -518,9 +391,16 @@ async fn run_nym_api(matches: ArgMatches) -> Result<()> { } // if we just wanted to write data to the config, exit - if matches.is_present(WRITE_CONFIG_ARG) { - return Ok(()); + if save_to_file { + info!("Saving the configuration to a file"); + if let Err(err) = config.save_to_file(None) { + error!("Failed to write config to a file - {err}"); + process::exit(1) + } else { + return Ok(()); + } } + let mix_denom = std::env::var(MIX_DENOM).expect("mix denom not set"); let signing_nymd_client = Client::new_signing(&config); @@ -660,10 +540,7 @@ async fn main() -> Result<()> { }} setup_logging(); - let args = parse_args(); - let config_env_file = args - .value_of(CONFIG_ENV_FILE) - .map(|s| PathBuf::from_str(s).expect("invalid env config file")); - setup_env(config_env_file); + let args = ApiArgs::parse(); + setup_env(args.config_env_file.as_ref()); run_nym_api(args).await } diff --git a/nym-connect/Cargo.lock b/nym-connect/Cargo.lock index b96753bb3c..2b9b7ab8a0 100644 --- a/nym-connect/Cargo.lock +++ b/nym-connect/Cargo.lock @@ -407,6 +407,13 @@ dependencies = [ "memchr", ] +[[package]] +name = "build-information" +version = "0.1.0" +dependencies = [ + "vergen 7.4.4", +] + [[package]] name = "bumpalo" version = "3.11.0" @@ -566,35 +573,33 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.22" +version = "4.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", "once_cell", "strsim", "termcolor", - "textwrap", ] [[package]] name = "clap_complete" -version = "3.2.5" +version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" +checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" dependencies = [ "clap", ] [[package]] name = "clap_complete_fig" -version = "3.2.4" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed37b4c0c1214673eba6ad8ea31666626bf72be98ffb323067d973c48b4964b9" +checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3" dependencies = [ "clap", "clap_complete", @@ -602,9 +607,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -615,9 +620,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] @@ -1583,7 +1588,16 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2953d1df47ac0eb70086ccabf0275aa8da8591a28bd358ee2b52bd9f9e3ff9e9" dependencies = [ - "enum-iterator-derive", + "enum-iterator-derive 0.8.1", +] + +[[package]] +name = "enum-iterator" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a0ac4aeb3a18f92eaf09c6bb9b3ac30ff61ca95514fc58cbead1c9a6bf5401" +dependencies = [ + "enum-iterator-derive 1.1.0", ] [[package]] @@ -1597,6 +1611,17 @@ dependencies = [ "syn", ] +[[package]] +name = "enum-iterator-derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.7.1" @@ -3440,6 +3465,7 @@ dependencies = [ name = "nym-socks5-client" version = "1.1.4" dependencies = [ + "build-information", "clap", "client-connections", "client-core", @@ -3451,6 +3477,7 @@ dependencies = [ "futures", "gateway-client", "gateway-requests", + "lazy_static", "log", "logging", "network-defaults", @@ -3471,7 +3498,6 @@ dependencies = [ "topology", "url", "validator-client", - "vergen", "version-checker", ] @@ -6028,12 +6054,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" - [[package]] name = "thin-slice" version = "0.1.1" @@ -6538,7 +6558,7 @@ dependencies = [ "anyhow", "cfg-if", "chrono", - "enum-iterator", + "enum-iterator 0.8.1", "getset", "git2", "rustc_version 0.4.0", @@ -6546,6 +6566,23 @@ dependencies = [ "thiserror", ] +[[package]] +name = "vergen" +version = "7.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efadd36bc6fde40c6048443897d69511a19161c0756cb704ed403f8dfd2b7d1c" +dependencies = [ + "anyhow", + "cfg-if", + "enum-iterator 1.1.3", + "getset", + "git2", + "rustc_version 0.4.0", + "rustversion", + "thiserror", + "time 0.3.17", +] + [[package]] name = "version-checker" version = "0.1.0" @@ -6582,7 +6619,7 @@ dependencies = [ "schemars", "serde", "thiserror", - "vergen", + "vergen 5.1.17", "vesting-contract-common", ] diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 25e16a69a1..0a9ba7103f 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -167,7 +167,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -511,26 +511,24 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.20" +version = "4.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ - "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", + "is-terminal", "once_cell", "strsim", "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -541,9 +539,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] @@ -1339,6 +1337,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "execute" version = "0.1.0" @@ -2016,6 +2035,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -2284,12 +2312,34 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] + [[package]] name = "ipnet" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys 0.42.0", +] + [[package]] name = "itertools" version = "0.10.3" @@ -2460,6 +2510,12 @@ dependencies = [ "safemem", ] +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.6" @@ -2613,7 +2669,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -2765,7 +2821,7 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] @@ -3009,7 +3065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23a407004a1033f53e93f9b45580d14de23928faad187384f891507c9b0c045" dependencies = [ "pathdiff", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -3130,7 +3186,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec 1.8.0", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -3960,6 +4016,20 @@ dependencies = [ "semver 1.0.6", ] +[[package]] +name = "rustix" +version = "0.36.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.42.0", +] + [[package]] name = "rustls" version = "0.19.1" @@ -4967,12 +5037,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - [[package]] name = "thin-slice" version = "0.1.1" @@ -5749,12 +5813,33 @@ dependencies = [ "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + [[package]] name = "windows-tokens" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" @@ -5773,6 +5858,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + [[package]] name = "windows_i686_gnu" version = "0.36.1" @@ -5791,6 +5882,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + [[package]] name = "windows_i686_msvc" version = "0.36.1" @@ -5809,6 +5906,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" @@ -5827,6 +5930,18 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" @@ -5845,6 +5960,12 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "winreg" version = "0.7.0" diff --git a/nym-wallet/nym-wallet-recovery-cli/Cargo.toml b/nym-wallet/nym-wallet-recovery-cli/Cargo.toml index 909467a6e0..3f2569adfd 100644 --- a/nym-wallet/nym-wallet-recovery-cli/Cargo.toml +++ b/nym-wallet/nym-wallet-recovery-cli/Cargo.toml @@ -11,7 +11,7 @@ anyhow = "1.0" argon2 = "0.4" base64 = "0.13" bip39 = "1.0" -clap = { version = "3.2", features = ["derive"] } +clap = { version = "4.0", features = ["derive"] } log = "0.4" pretty_env_logger = "0.4" serde_json = "1.0.0" diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index d693ed4422..eca04d024e 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -12,7 +12,7 @@ rust-version = "1.65" [dependencies] async-trait = { version = "0.1.51" } -clap = {version = "3.2", features = ["derive"]} +clap = {version = "4.0", features = ["derive"]} dirs = "4.0" futures = "0.3.24" ipnetwork = "0.20.0" diff --git a/service-providers/network-requester/src/main.rs b/service-providers/network-requester/src/main.rs index 3534f4b749..2b585dfe13 100644 --- a/service-providers/network-requester/src/main.rs +++ b/service-providers/network-requester/src/main.rs @@ -98,8 +98,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { match &args.command { Commands::Run(r) => r.execute().await?, - Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name), - Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name), + Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name), + Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name), } Ok(()) } diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index ddc21464ff..b919419faf 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" [dependencies] base64 = "0.13.0" bs58 = "0.4" -clap = { version = "3.2", features = ["derive"] } -clap_complete = "3.2" -clap_complete_fig = "3.2" +clap = { version = "4.0", features = ["derive"] } +clap_complete = "4.0" +clap_complete_fig = "4.0" dotenv = "0.15.0" log = "0.4" pretty_env_logger = "0.4"