From f56131cc3864f6fcdde6090eaf288249f3636fdd Mon Sep 17 00:00:00 2001 From: BigFish2086 Date: Sat, 28 Jun 2025 16:50:50 +0300 Subject: [PATCH 1/4] feat(use-clap-for-kdf): use clap to parse CLI-Args #2215 - had to set clap version to "=v4.2" in Cargo.toml, because cargo was trying to fetch clap version 4.5 and it requires a higher version of rust tool-chain (1.74) and the current one is (1.72) - clap provides both "-h" or "--help" for the help - override the behaviour of the help to be able to show the same message as before with the version of KDF_VERSION provided by the git-commit - modes & subcommands like `btc2kmd`, `events`, `vanity`, `update_config` weren't actually used or handled by the code, so I removed them --- Cargo.lock | 121 ++++++++++++++++++++++++++++ Cargo.toml | 2 +- mm2src/mm2_main/Cargo.toml | 3 +- mm2src/mm2_main/src/mm2.rs | 161 +++++++++++++++---------------------- 4 files changed, 190 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6cd5560d8..639f334220 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "anyhow" version = "1.0.89" @@ -769,6 +818,48 @@ dependencies = [ "zeroize", ] +[[package]] +name = "clap" +version = "4.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +dependencies = [ + "heck 0.4.0", + "proc-macro2", + "quote 1.0.37", + "syn 2.0.77", +] + +[[package]] +name = "clap_lex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + [[package]] name = "cloudabi" version = "0.0.3" @@ -951,6 +1042,12 @@ dependencies = [ "url", ] +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "common" version = "0.1.0" @@ -2499,6 +2596,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" @@ -2917,6 +3020,17 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi 0.5.2", + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "itertools" version = "0.10.3" @@ -4066,6 +4180,7 @@ dependencies = [ "cfg-if 1.0.0", "chain", "chrono", + "clap", "coins", "coins_activation", "common", @@ -7683,6 +7798,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "utxo_signer" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index dd317f0d87..7f3c4d415d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ cc = "1.0" cipher = "0.4.4" chrono = "0.4.23" cfg-if = "1.0" -clap = { version = "4.2", features = ["derive"] } +clap = { version = "=4.2", features = ["derive"] } cosmrs = { version = "0.16", default-features = false } crossbeam = "0.8" crossbeam-channel = "0.5.1" diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index b2fe520cfb..a754e560d2 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -33,9 +33,10 @@ async-trait.workspace = true bitcrypto = { path = "../mm2_bitcoin/crypto" } blake2.workspace = true bytes.workspace = true +cfg-if.workspace = true chain = { path = "../mm2_bitcoin/chain" } chrono.workspace = true -cfg-if.workspace = true +clap.workspace = true coins = { path = "../coins" } coins_activation = { path = "../coins_activation" } common = { path = "../common" } diff --git a/mm2src/mm2_main/src/mm2.rs b/mm2src/mm2_main/src/mm2.rs index 37ad202ed8..4cf46a1199 100644 --- a/mm2src/mm2_main/src/mm2.rs +++ b/mm2src/mm2_main/src/mm2.rs @@ -58,10 +58,7 @@ use std::sync::atomic::Ordering; use gstuff::slurp; use serde_json::{self as json, Value as Json}; -use std::env; -use std::ffi::OsString; use std::process::exit; -use std::ptr::null; use std::str; pub use self::lp_native_dex::init_hw; @@ -84,11 +81,68 @@ pub mod rpc; mod swap_versioning; #[cfg(all(target_arch = "wasm32", test))] mod wasm_tests; +use clap::{CommandFactory, Parser}; + pub const PASSWORD_MAXIMUM_CONSECUTIVE_CHARACTERS: usize = 3; #[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] const CUSTOM_PAYMENT_LOCKTIME_DEFAULT: u64 = 900; +const EXTRA_HELP_MESSAGE: &str = r#" +Some (but not all) of the JSON configuration parameters (* - required): + + NB: The 'coins' command-line configuration must have the lowercased coin names in the 'name' field, + {"coins": [{"name": "dash", "coin": "DASH", ...}, ...], ...}. + coins .. Information about the currencies: their ticker symbols, names, ports, addresses, etc. + If the field isn't present on the command line then we try loading it from the 'coins' file. + dbdir .. MM database path. 'DB' by default. + gui .. The information about GUI app using KDF instance. Included in swap statuses shared with network. + .. It's recommended to put essential info to this field (application name, OS, version, etc). + .. e.g. AtomicDEX iOS 1.0.1000. + myipaddr .. IP address to bind to for P2P networking. + netid .. Subnetwork. Affects ports and keys. + passphrase * .. Wallet seed. + Compressed WIFs and hexadecimal ECDSA keys (prefixed with 0x) are also accepted. + rpccors .. Access-Control-Allow-Origin header value to be used in all the RPC responses. + Default is currently 'http://localhost:3000' + rpcip .. IP address to bind to for RPC server. Overrides the 127.0.0.1 default + rpc_password .. RPC password used to authorize non-public RPC calls + MM generates password from passphrase if this field is not set + rpc_local_only .. MM forbids some RPC requests from not loopback (localhost) IPs as additional security measure. + Defaults to `true`, set `false` to disable. `Use with caution`. + rpcport .. If > 1000 overrides the 7783 default. + i_am_seed .. Activate the seed node mode (acting as a relay for kdf clients). + Defaults to `false`. + seednodes .. Seednode IPs that node will use. + At least one seed IP must be present if the node is not a seed itself. + wif .. `1` to add WIFs to the information we provide about a coin. + +Environment variables: + + MM_CONF_PATH .. File path. MM2 will try to load the JSON configuration from this file. + File must contain valid json with structure mentioned above. + Defaults to `MM2.json` + MM_COINS_PATH .. File path. MM2 will try to load coins data from this file. + File must contain valid json. + Recommended: https://github.com/komodoplatform/coins/blob/master/coins. + Defaults to `coins`. + MM_LOG .. File path. Must end with '.log'. MM will log to this file. + +See also the online documentation at +https://komodoplatform.com/en/docs +"#; + +#[derive(Parser, Debug)] +#[command(about="Komodo DeFi Framework Daemon", long_about=None, after_help=EXTRA_HELP_MESSAGE)] +pub struct Cli { + /// JSON configuration string - will be used instead of the json config file + pub config: Option, + + /// Print version + #[clap(short, long)] + pub version: bool, +} + pub struct LpMainParams { conf: Json, filter: Option, @@ -201,115 +255,32 @@ fn spawn_ctrl_c_handler(ctx: MmArc) { }); } -fn help() { - const HELP_MSG: &str = r#"Command-line options. -The first command-line argument is special and designates the mode. - - help .. Display this message. - btc2kmd {WIF or BTC} .. Convert a BTC WIF into a KMD WIF. - events .. Listen to a feed coming from a separate MM daemon and print it to stdout. - vanity {substring} .. Tries to find an address with the given substring. - update_config {SRC} {DST} .. Update the configuration of coins from the SRC config and save it to DST file. - {JSON configuration} .. Run the MarketMaker daemon. - -Some (but not all) of the JSON configuration parameters (* - required): - - NB: The 'coins' command-line configuration must have the lowercased coin names in the 'name' field, - {"coins": [{"name": "dash", "coin": "DASH", ...}, ...], ...}. - coins .. Information about the currencies: their ticker symbols, names, ports, addresses, etc. - If the field isn't present on the command line then we try loading it from the 'coins' file. - dbdir .. MM database path. 'DB' by default. - gui .. The information about GUI app using KDF instance. Included in swap statuses shared with network. - .. It's recommended to put essential info to this field (application name, OS, version, etc). - .. e.g. AtomicDEX iOS 1.0.1000. - myipaddr .. IP address to bind to for P2P networking. - netid .. Subnetwork. Affects ports and keys. - passphrase * .. Wallet seed. - Compressed WIFs and hexadecimal ECDSA keys (prefixed with 0x) are also accepted. - rpccors .. Access-Control-Allow-Origin header value to be used in all the RPC responses. - Default is currently 'http://localhost:3000' - rpcip .. IP address to bind to for RPC server. Overrides the 127.0.0.1 default - rpc_password .. RPC password used to authorize non-public RPC calls - MM generates password from passphrase if this field is not set - rpc_local_only .. MM forbids some RPC requests from not loopback (localhost) IPs as additional security measure. - Defaults to `true`, set `false` to disable. `Use with caution`. - rpcport .. If > 1000 overrides the 7783 default. - i_am_seed .. Activate the seed node mode (acting as a relay for kdf clients). - Defaults to `false`. - seednodes .. Seednode IPs that node will use. - At least one seed IP must be present if the node is not a seed itself. - wif .. `1` to add WIFs to the information we provide about a coin. - -Environment variables: - - MM_CONF_PATH .. File path. MM2 will try to load the JSON configuration from this file. - File must contain valid json with structure mentioned above. - Defaults to `MM2.json` - MM_COINS_PATH .. File path. MM2 will try to load coins data from this file. - File must contain valid json. - Recommended: https://github.com/komodoplatform/coins/blob/master/coins. - Defaults to `coins`. - MM_LOG .. File path. Must end with '.log'. MM will log to this file. - -See also the online documentation at -https://komodoplatform.com/en/docs -"#; - - println!("{}", HELP_MSG); -} - #[cfg(not(target_arch = "wasm32"))] #[allow(dead_code)] // Not used by mm2_lib. pub fn mm2_main(version: String, datetime: String) { - use libc::c_char; - init_crash_reports(); - // Temporarily simulate `argv[]` for the C version of the main method. - let args: Vec = env::args() - .map(|mut arg| { - arg.push('\0'); - arg - }) - .collect(); - let mut args: Vec<*const c_char> = args.iter().map(|s| s.as_ptr() as *const c_char).collect(); - args.push(null()); - - let args_os: Vec = env::args_os().collect(); - - // NB: The first argument is special, being used as the mode switcher. - // The other arguments might be used to pass the data to the various MM modes, - // we're not checking them for the mode switches in order not to risk [untrusted] data being mistaken for a mode switch. - let first_arg = args_os.get(1).and_then(|arg| arg.to_str()); - - if first_arg == Some("--version") || first_arg == Some("-v") || first_arg == Some("version") { - println!("Komodo DeFi Framework: {version}"); - return; - } - - if first_arg == Some("--help") || first_arg == Some("-h") || first_arg == Some("help") { - help(); + let cli = Cli::parse(); + if cli.version { + println!("{}: {}", Cli::command().get_about().unwrap(), version); return; } - if cfg!(windows) && first_arg == Some("/?") { - help(); - return; - } + let json_config = cli.config.as_deref(); log!("Komodo DeFi Framework {} DT {}", version, datetime); - if let Err(err) = run_lp_main(first_arg, &|_| (), version, datetime) { + if let Err(err) = run_lp_main(json_config, &|_| (), version, datetime) { log!("{}", err); exit(1); } } #[cfg(not(target_arch = "wasm32"))] -/// Parses and returns the `first_arg` as JSON. -/// Attempts to load the config from `MM2.json` file if `first_arg` is None -pub fn get_mm2config(first_arg: Option<&str>) -> Result { - let conf = match first_arg { +/// Parses and returns the `json_config` as JSON. +/// Attempts to load the config from `MM2.json` file if `json_config` is None +pub fn get_mm2config(json_config: Option<&str>) -> Result { + let conf = match json_config { Some(s) => s.to_owned(), None => { let conf_path = common::kdf_config_file().map_err(|e| e.to_string())?; From 7074d525f1a7c1c2c5bf2ce2ed2b37ccc59becf8 Mon Sep 17 00:00:00 2001 From: BigFish2086 Date: Sun, 6 Jul 2025 09:36:29 +0300 Subject: [PATCH 2/4] fix(use-clap-for-cli): remove '=' from Cargo.toml as the Cargo.lock file is already created. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7f3c4d415d..dd317f0d87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ cc = "1.0" cipher = "0.4.4" chrono = "0.4.23" cfg-if = "1.0" -clap = { version = "=4.2", features = ["derive"] } +clap = { version = "4.2", features = ["derive"] } cosmrs = { version = "0.16", default-features = false } crossbeam = "0.8" crossbeam-channel = "0.5.1" From 726791a98b2c953bd3980f12277b69e4c2d8b694 Mon Sep 17 00:00:00 2001 From: BigFish2086 Date: Sun, 6 Jul 2025 09:37:48 +0300 Subject: [PATCH 3/4] fix(use-clap-for-cli): hard-code the version output prefix to keep it like before --- mm2src/mm2_main/src/mm2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/mm2.rs b/mm2src/mm2_main/src/mm2.rs index 4cf46a1199..c15b1a25e6 100644 --- a/mm2src/mm2_main/src/mm2.rs +++ b/mm2src/mm2_main/src/mm2.rs @@ -262,7 +262,7 @@ pub fn mm2_main(version: String, datetime: String) { let cli = Cli::parse(); if cli.version { - println!("{}: {}", Cli::command().get_about().unwrap(), version); + println!("Komodo DeFi Framework: {version}"); return; } From 2d62ceedc7c6cc009b3082dbe66241d37b4295fa Mon Sep 17 00:00:00 2001 From: BigFish2086 Date: Sun, 6 Jul 2025 09:39:09 +0300 Subject: [PATCH 4/4] fix(use-clap-for-cli): remove reference for the JSON parameters from help as they can quickly become obsolete and outdated. --- mm2src/mm2_main/src/mm2.rs | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/mm2src/mm2_main/src/mm2.rs b/mm2src/mm2_main/src/mm2.rs index c15b1a25e6..00309615cb 100644 --- a/mm2src/mm2_main/src/mm2.rs +++ b/mm2src/mm2_main/src/mm2.rs @@ -81,7 +81,7 @@ pub mod rpc; mod swap_versioning; #[cfg(all(target_arch = "wasm32", test))] mod wasm_tests; -use clap::{CommandFactory, Parser}; +use clap::Parser; pub const PASSWORD_MAXIMUM_CONSECUTIVE_CHARACTERS: usize = 3; @@ -89,34 +89,6 @@ pub const PASSWORD_MAXIMUM_CONSECUTIVE_CHARACTERS: usize = 3; const CUSTOM_PAYMENT_LOCKTIME_DEFAULT: u64 = 900; const EXTRA_HELP_MESSAGE: &str = r#" -Some (but not all) of the JSON configuration parameters (* - required): - - NB: The 'coins' command-line configuration must have the lowercased coin names in the 'name' field, - {"coins": [{"name": "dash", "coin": "DASH", ...}, ...], ...}. - coins .. Information about the currencies: their ticker symbols, names, ports, addresses, etc. - If the field isn't present on the command line then we try loading it from the 'coins' file. - dbdir .. MM database path. 'DB' by default. - gui .. The information about GUI app using KDF instance. Included in swap statuses shared with network. - .. It's recommended to put essential info to this field (application name, OS, version, etc). - .. e.g. AtomicDEX iOS 1.0.1000. - myipaddr .. IP address to bind to for P2P networking. - netid .. Subnetwork. Affects ports and keys. - passphrase * .. Wallet seed. - Compressed WIFs and hexadecimal ECDSA keys (prefixed with 0x) are also accepted. - rpccors .. Access-Control-Allow-Origin header value to be used in all the RPC responses. - Default is currently 'http://localhost:3000' - rpcip .. IP address to bind to for RPC server. Overrides the 127.0.0.1 default - rpc_password .. RPC password used to authorize non-public RPC calls - MM generates password from passphrase if this field is not set - rpc_local_only .. MM forbids some RPC requests from not loopback (localhost) IPs as additional security measure. - Defaults to `true`, set `false` to disable. `Use with caution`. - rpcport .. If > 1000 overrides the 7783 default. - i_am_seed .. Activate the seed node mode (acting as a relay for kdf clients). - Defaults to `false`. - seednodes .. Seednode IPs that node will use. - At least one seed IP must be present if the node is not a seed itself. - wif .. `1` to add WIFs to the information we provide about a coin. - Environment variables: MM_CONF_PATH .. File path. MM2 will try to load the JSON configuration from this file.