//! Command line and defaults. No clap: the arguments are few and the miner parses by hand too. use std::path::PathBuf; #[derive(Clone, Debug)] pub struct Config { /// gRPC nodes; the first builds templates and confirms blocks, every one receives found blocks pub nodes: Vec, /// The first node's EVM JSON-RPC (payouts, chain id) pub evm_rpc: String, /// Where members connect (spec 9.3: 4461 mainnet, 4462 testnet, 4463 devnet) pub listen: String, /// The stats API and the web page pub http: String, pub data_dir: PathBuf, /// The payout key file (JSON, created when missing, mode 0600); its address is the pool's coinbase address pub payout_key: PathBuf, pub fee_percent: f64, pub min_payout_ign: f64, pub pplns_window_blocks: f64, pub payout_interval_s: u64, pub dry_run: bool, pub network: String, pub share_interval_s: u64, pub min_shift: u32, pub max_shift: u32, pub stale_grace_ms: u64, /// A pending block older than this many DAA scores and not blue is an orphan pub orphan_after_daa: u64, pub name: String, /// The address members connect to, shown on the page (host:port) pub public_url: String, /// Shares sampled at shifts above this are still verified in v0 (spec sample_shift 8 is an allowance, not a duty) pub verify_threads: usize, pub snapshot_interval_s: u64, } impl Config { pub fn usage() -> ! { eprintln!( "usage: igneum-pool [--node grpc://127.0.0.1:26610]... [--evm-rpc http://127.0.0.1:26790] [--listen 0.0.0.0:4463]\n\ \x20 [--http 127.0.0.1:4480] [--data-dir ./data] [--payout-key ] [--fee-percent 1] [--min-payout 1.0]\n\ \x20 [--pplns-window 2.0] [--payout-interval-s 60] [--dry-run] [--network devnet|testnet|mainnet]\n\ \x20 [--share-interval-s 10] [--min-shift 0] [--max-shift 60] [--stale-grace-ms 2000] [--orphan-after-daa 120]\n\ \x20 [--name \"Igneum pool\"] [--public-url host:4463] [--verify-threads 2] [--snapshot-interval-s 15]" ); std::process::exit(2) } pub fn from_args(args: &[String]) -> Config { let mut c = Config { nodes: Vec::new(), evm_rpc: String::new(), listen: String::new(), http: "127.0.0.1:4480".into(), data_dir: PathBuf::from("data"), payout_key: PathBuf::new(), fee_percent: 1.0, min_payout_ign: 1.0, pplns_window_blocks: 2.0, payout_interval_s: 60, dry_run: false, network: "devnet".into(), share_interval_s: 10, min_shift: 0, max_shift: 60, stale_grace_ms: 2000, orphan_after_daa: 120, name: "Igneum pool".into(), public_url: String::new(), verify_threads: 2, snapshot_interval_s: 15, }; let mut i = 0; while i < args.len() { let a = args[i].as_str(); let mut val = || -> String { i += 1; args.get(i).cloned().unwrap_or_else(|| Config::usage()) }; match a { "--node" => c.nodes.push(val()), "--evm-rpc" => c.evm_rpc = val(), "--listen" => c.listen = val(), "--http" => c.http = val(), "--data-dir" => c.data_dir = PathBuf::from(val()), "--payout-key" => c.payout_key = PathBuf::from(val()), "--fee-percent" => c.fee_percent = val().parse().unwrap_or_else(|_| Config::usage()), "--min-payout" => c.min_payout_ign = val().parse().unwrap_or_else(|_| Config::usage()), "--pplns-window" => c.pplns_window_blocks = val().parse().unwrap_or_else(|_| Config::usage()), "--payout-interval-s" => c.payout_interval_s = val().parse().unwrap_or_else(|_| Config::usage()), "--dry-run" => c.dry_run = true, "--network" => c.network = val(), "--share-interval-s" => c.share_interval_s = val().parse().unwrap_or_else(|_| Config::usage()), "--min-shift" => c.min_shift = val().parse().unwrap_or_else(|_| Config::usage()), "--max-shift" => c.max_shift = val().parse().unwrap_or_else(|_| Config::usage()), "--stale-grace-ms" => c.stale_grace_ms = val().parse().unwrap_or_else(|_| Config::usage()), "--orphan-after-daa" => c.orphan_after_daa = val().parse().unwrap_or_else(|_| Config::usage()), "--name" => c.name = val(), "--public-url" => c.public_url = val(), "--verify-threads" => c.verify_threads = val().parse::().unwrap_or_else(|_| Config::usage()).max(1), "--snapshot-interval-s" => c.snapshot_interval_s = val().parse().unwrap_or_else(|_| Config::usage()), "-h" | "--help" => Config::usage(), _ => Config::usage(), } i += 1; } if c.nodes.is_empty() { c.nodes.push("grpc://127.0.0.1:26610".into()); } let (port, evm_port) = match c.network.as_str() { "mainnet" => (4461, 8545), "testnet" => (4462, 26890), _ => (4463, 26790), }; if c.listen.is_empty() { c.listen = format!("0.0.0.0:{port}"); } if c.evm_rpc.is_empty() { c.evm_rpc = format!("http://127.0.0.1:{evm_port}"); } if c.payout_key.as_os_str().is_empty() { c.payout_key = c.data_dir.join("payout-key.json"); } if c.public_url.is_empty() { c.public_url = c.listen.replace("0.0.0.0", "127.0.0.1"); } if c.fee_percent < 0.0 || c.fee_percent > 100.0 || c.pplns_window_blocks <= 0.0 || c.min_shift > c.max_shift { Config::usage(); } c } pub fn chain_id(&self) -> u64 { match self.network.as_str() { "mainnet" => 4461, "testnet" => 4462, _ => 4463, } } }