depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

commit 643cd6cf56acd87de54d2278ecfcf8c0266e3235
parent 7fce22cf8134ad6986070ca4ef41fe8a474f81b9
Author: Antoine A <>
Date:   Tue,  8 Mar 2022 15:05:23 +0100

Better config parsing

Diffstat:
Mbtc-wire/src/bin/btc-wire-utils.rs | 7+++----
Mbtc-wire/src/lib.rs | 29++++++++++++++---------------
Mbtc-wire/src/main.rs | 8++++----
Mcommon/src/config.rs | 112++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Meth-wire/src/bin/eth-wire-utils.rs | 6+++---
Meth-wire/src/lib.rs | 27+++++++++++++--------------
Meth-wire/src/main.rs | 9+++++----
Minstrumentation/src/main.rs | 2+-
Mmakefile | 2+-
Mwire-gateway/src/main.rs | 28++++++++++++++--------------
10 files changed, 126 insertions(+), 104 deletions(-)

diff --git a/btc-wire/src/bin/btc-wire-utils.rs b/btc-wire/src/bin/btc-wire-utils.rs @@ -80,9 +80,8 @@ pub fn auto_wallet(rpc: &mut Rpc, config: &BitcoinConfig, name: &str) -> (Rpc, A fn main() { common::log::init(); let args = Args::parse(); - let (taler_config, currency) = load_taler_config(args.config.as_deref()); - let btc_config = - BitcoinConfig::load(args.datadir.unwrap_or(taler_config.custom), currency).unwrap(); + let (taler_config, path, currency) = load_taler_config(args.config.as_deref()); + let btc_config = BitcoinConfig::load(args.datadir.unwrap_or(path), currency).unwrap(); let mut rpc = Rpc::common(&btc_config).unwrap(); match args.cmd { @@ -118,7 +117,7 @@ fn main() { } Cmd::Resetdb => { let hash: BlockHash = rpc.get_genesis().unwrap(); - let mut db = taler_config.db_config.connect(NoTls).unwrap(); + let mut db = taler_config.db_config().connect(NoTls).unwrap(); let mut tx = db.transaction().unwrap(); // Clear transaction tables and reset state tx.execute("DELETE FROM tx_in", &[]).unwrap(); diff --git a/btc-wire/src/lib.rs b/btc-wire/src/lib.rs @@ -162,29 +162,28 @@ pub struct WireState { impl WireState { pub fn load_taler_config(file: Option<&Path>) -> Self { - let (taler_config, currency) = load_taler_config(file); - let btc_config = BitcoinConfig::load(taler_config.custom, currency) - .expect("Failed to read bitcoin configuration file"); - let init_confirmation = taler_config.confirmation.unwrap_or(DEFAULT_CONFIRMATION) as u32; + let (taler_config, path, currency) = load_taler_config(file); + let btc_config = + BitcoinConfig::load(path, currency).expect("Failed to read bitcoin configuration file"); + let init_confirmation = taler_config.confirmation().unwrap_or(DEFAULT_CONFIRMATION) as u32; Self { confirmation: AtomicU32::new(init_confirmation), max_confirmation: init_confirmation * 2, - btc_config, - bounce_fee: config_bounce_fee(&taler_config.bounce_fee, currency), - lifetime: taler_config.wire_lifetime, - bump_delay: taler_config.bump_delay, - base_url: taler_config.base_url, - db_config: taler_config.db_config, + bounce_fee: config_bounce_fee(&taler_config.bounce_fee(), currency), + lifetime: taler_config.wire_lifetime(), + bump_delay: taler_config.bump_delay(), + base_url: taler_config.base_url(), + db_config: taler_config.db_config(), currency, + btc_config, } } } // Load taler config with btc-wire specific config -pub fn load_taler_config(file: Option<&Path>) -> (TalerConfig<PathBuf>, CurrencyBtc) { - let config = TalerConfig::load_with_custom(file, |dep| { - common::config::path(dep, "CONF_PATH").unwrap_or_else(default_data_dir) - }); +pub fn load_taler_config(file: Option<&Path>) -> (TalerConfig, PathBuf, CurrencyBtc) { + let config = TalerConfig::load(file); + let path = config.path("CONF_PATH").unwrap_or_else(default_data_dir); let currency = match config.currency { Currency::BTC(it) => it, _ => fail(format!( @@ -192,7 +191,7 @@ pub fn load_taler_config(file: Option<&Path>) -> (TalerConfig<PathBuf>, Currency config.currency.to_str() )), }; - (config, currency) + (config, path, currency) } // Parse bitcoin amount from config bounce fee diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -64,16 +64,16 @@ fn main() { fn init(config: Option<PathBuf>, init: Init) { // Parse taler config - let (taler_config, currency) = load_taler_config(config.as_deref()); + let (taler_config, path, currency) = load_taler_config(config.as_deref()); // Connect to database let mut db = taler_config - .db_config + .db_config() .connect(NoTls) .expect("Failed to connect to database"); // Parse bitcoin config - let btc_conf = BitcoinConfig::load(taler_config.custom, currency) - .expect("Failed to load bitcoin configuration"); + let btc_conf = + BitcoinConfig::load(path, currency).expect("Failed to load bitcoin configuration"); // Connect to bitcoin node let mut rpc = Rpc::common(&btc_conf).expect("Failed to connect to bitcoin RPC server"); match init { diff --git a/common/src/config.rs b/common/src/config.rs @@ -28,33 +28,14 @@ use crate::{ pub use ini; // Depolymerizer taler config -pub struct TalerConfig<T> { - // common - pub db_config: postgres::Config, +pub struct TalerConfig { + conf: Ini, + section_name: &'static str, pub currency: Currency, - pub base_url: Url, - // wire-gateway - pub http_lifetime: Option<u32>, - pub port: u16, - pub unix_path: Option<PathBuf>, - // wire common - pub confirmation: Option<u16>, - pub bounce_fee: Option<String>, - pub wire_lifetime: Option<u32>, - pub bump_delay: Option<u32>, - pub payto: Option<Url>, - // custom config - pub custom: T, } -impl TalerConfig<()> { +impl TalerConfig { pub fn load(file: Option<&Path>) -> Self { - Self::load_with_custom(file, |_| {}) - } -} - -impl<T> TalerConfig<T> { - pub fn load_with_custom(file: Option<&Path>, lambda: fn(&Properties) -> T) -> Self { // Load config using taler-config let mut cmd = Command::new("taler-config"); cmd.arg("-d"); @@ -87,32 +68,75 @@ impl<T> TalerConfig<T> { Currency::ETH(_) => "depolymerizer-ethereum", }; - let dep = section(&conf, section_name); Self { - db_config: required(dep, "DB_URL", postgres), + conf, + section_name, currency, - base_url: required(section(&conf, "exchange"), "BASE_URL", url), - confirmation: nb(dep, "CONFIRMATION"), - bounce_fee: string(dep, "BOUNCE_FEE"), - wire_lifetime: nb(dep, "WIRE_LIFETIME") - .and_then(|nb| (nb != 0).then(|| Some(nb))) - .unwrap_or(None), - bump_delay: nb(dep, "BUMP_DELAY") - .and_then(|nb| (nb != 0).then(|| Some(nb))) - .unwrap_or(None), - port: nb(dep, "PORT").unwrap_or(8080), - unix_path: path(dep, "UNIXPATH"), - payto: url(dep, "PAYTO"), - http_lifetime: nb(dep, "HTTP_LIFETIME") - .and_then(|nb| (nb != 0).then(|| Some(nb))) - .unwrap_or(None), - custom: lambda(dep), } } - // Enforce payto requirement - pub fn require_payto(&self) -> Url { - expect_config(self.payto.clone(), "PAYTO") + fn section(&self) -> &Properties { + section(&self.conf, self.section_name) + } + + fn non_zero_option(&self, name: &str) -> Option<u32> { + nb(self.section(), name) + .and_then(|nb| (nb != 0).then(|| Some(nb))) + .unwrap_or(None) + } +} + +impl TalerConfig { + /* ----- Common ----- */ + + pub fn db_config(&self) -> postgres::Config { + required(self.section(), "DB_URL", postgres) + } + + pub fn base_url(&self) -> Url { + required(section(&self.conf, "exchange"), "BASE_URL", url) + } + + /* ----- Wire Gateway ----- */ + + pub fn payto(&self) -> Url { + required(self.section(), "PAYTO", url) + } + + pub fn port(&self) -> u16 { + nb(self.section(), "PORT").unwrap_or(8080) + } + + pub fn unix_path(&self) -> Option<PathBuf> { + path(self.section(), "UNIXPATH") + } + + pub fn http_lifetime(&self) -> Option<u32> { + self.non_zero_option("HTTP_LIFETIME") + } + + /* ----- Wire Common ----- */ + + pub fn confirmation(&self) -> Option<u16> { + nb(self.section(), "CONFIRMATION") + } + + pub fn bounce_fee(&self) -> Option<String> { + string(self.section(), "BOUNCE_FEE") + } + + pub fn wire_lifetime(&self) -> Option<u32> { + self.non_zero_option("WIRE_LIFETIME") + } + + pub fn bump_delay(&self) -> Option<u32> { + self.non_zero_option("BUMP_DELAY") + } + + /* ----- Custom ----- */ + + pub fn path(&self, name: &str) -> Option<PathBuf> { + path(self.section(), name) } } diff --git a/eth-wire/src/bin/eth-wire-utils.rs b/eth-wire/src/bin/eth-wire-utils.rs @@ -104,9 +104,9 @@ enum Cmd { fn main() { init(); let args: Args = Args::parse(); - let (taler_config, currency) = load_taler_config(args.config.as_deref()); + let (taler_config, ipc_path, currency) = load_taler_config(args.config.as_deref()); - let ipc_path = args.datadir.unwrap_or(taler_config.custom); + let ipc_path = args.datadir.unwrap_or(ipc_path); let mut rpc = Rpc::new(ipc_path).unwrap(); let passwd = password(); match args.cmd { @@ -167,7 +167,7 @@ fn main() { } Cmd::Resetdb => { let block = rpc.earliest_block().unwrap(); - let mut db = taler_config.db_config.connect(NoTls).unwrap(); + let mut db = taler_config.db_config().connect(NoTls).unwrap(); let mut tx = db.transaction().unwrap(); // Clear transaction tables and reset state tx.execute("DELETE FROM tx_in", &[]).unwrap(); diff --git a/eth-wire/src/lib.rs b/eth-wire/src/lib.rs @@ -233,19 +233,19 @@ pub struct WireState { impl WireState { pub fn load_taler_config(file: Option<&Path>) -> Self { - let (taler_config, currency) = load_taler_config(file); - let init_confirmation = taler_config.confirmation.unwrap_or(DEFAULT_CONFIRMATION) as u32; - let payto = taler_config.require_payto(); + let (taler_config, ipc_path, currency) = load_taler_config(file); + let init_confirmation = taler_config.confirmation().unwrap_or(DEFAULT_CONFIRMATION) as u32; + let payto = taler_config.payto(); Self { confirmation: AtomicU32::new(init_confirmation), max_confirmations: init_confirmation * 2, address: eth_payto_addr(&payto).unwrap(), - ipc_path: taler_config.custom, - bounce_fee: config_bounce_fee(&taler_config.bounce_fee, currency), - lifetime: taler_config.wire_lifetime, - bump_delay: taler_config.bump_delay, - base_url: taler_config.base_url, - db_config: taler_config.db_config, + ipc_path, + bounce_fee: config_bounce_fee(&taler_config.bounce_fee(), currency), + lifetime: taler_config.wire_lifetime(), + bump_delay: taler_config.bump_delay(), + base_url: taler_config.base_url(), + db_config: taler_config.db_config(), payto, currency, } @@ -253,10 +253,9 @@ impl WireState { } // Load taler config with eth-wire specific config -pub fn load_taler_config(file: Option<&Path>) -> (TalerConfig<PathBuf>, CurrencyEth) { - let config = TalerConfig::load_with_custom(file, |dep| { - common::config::path(dep, "IPC_PATH").unwrap_or_else(default_data_dir) - }); +pub fn load_taler_config(file: Option<&Path>) -> (TalerConfig, PathBuf, CurrencyEth) { + let config = TalerConfig::load(file); + let path = config.path("IPC_PATH").unwrap_or_else(default_data_dir); let currency = match config.currency { Currency::ETH(it) => it, _ => fail(format!( @@ -264,7 +263,7 @@ pub fn load_taler_config(file: Option<&Path>) -> (TalerConfig<PathBuf>, Currency config.currency.to_str() )), }; - (config, currency) + (config, path, currency) } // Parse ethereum value from config bounce fee diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs @@ -19,8 +19,9 @@ use std::path::PathBuf; use clap::StructOpt; use common::{named_spawn, password, postgres::NoTls, reconnect::auto_reconnect_db}; use eth_wire::{ + load_taler_config, rpc::{auto_rpc_common, auto_rpc_wallet, Rpc, RpcClient}, - SyncState, WireState, load_taler_config, + SyncState, WireState, }; use ethereum_types::H160; use loops::{analysis::analysis, watcher::watcher, worker::worker}; @@ -59,14 +60,14 @@ fn main() { fn init(config: Option<PathBuf>, init: Init) { // Parse taler config - let (taler_config, _) = load_taler_config(config.as_deref()); + let (taler_config, ipc_path, _) = load_taler_config(config.as_deref()); // Connect to database let mut db = taler_config - .db_config + .db_config() .connect(NoTls) .expect("Failed to connect to database"); // Connect to ethereum node - let mut rpc = Rpc::new(taler_config.custom).expect("Failed to connect to ethereum RPC server"); + let mut rpc = Rpc::new(ipc_path).expect("Failed to connect to ethereum RPC server"); match init { Init::Initdb => { diff --git a/instrumentation/src/main.rs b/instrumentation/src/main.rs @@ -94,7 +94,7 @@ pub fn main() { common::log::init(); let args = Args::parse(); let taler_config = TalerConfig::load(args.config.as_deref()); - let base_url = format!("http://localhost:{}", taler_config.port); + let base_url = format!("http://localhost:{}", taler_config.port()); match taler_config.currency { Currency::BTC(_) => btc_test(args.config.as_deref(), &base_url), diff --git a/makefile b/makefile @@ -35,7 +35,7 @@ test_eth: install_test test/eth/bumpfee.sh test/eth/maxfee.sh -test: test_gateway test_eth test_btc +test: test_gateway test_btc test_eth segwit_demo: cargo run --release --bin segwit-demo \ No newline at end of file diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs @@ -109,17 +109,17 @@ async fn main() { common::log::log::warn!("Running with test admin endpoint unsuitable for production"); // Parse postgres url - let config = &taler_config.db_config; + let db_config = taler_config.db_config(); // TODO find a way to clean this ugly mess let mut cfg = deadpool_postgres::Config::new(); - cfg.user = config.get_user().map(|it| it.to_string()); - cfg.password = config + cfg.user = db_config.get_user().map(|it| it.to_string()); + cfg.password = db_config .get_password() .map(|it| String::from_utf8(it.to_vec()).unwrap()); - cfg.dbname = config.get_dbname().map(|it| it.to_string()); - cfg.options = config.get_options().map(|it| it.to_string()); + cfg.dbname = db_config.get_dbname().map(|it| it.to_string()); + cfg.options = db_config.get_options().map(|it| it.to_string()); cfg.host = Some( - config + db_config .get_hosts() .iter() .map(|it| match it { @@ -129,18 +129,18 @@ async fn main() { }) .collect(), ); - cfg.ports = Some(config.get_ports().to_vec()); - cfg.application_name = config.get_application_name().map(|it| it.to_string()); - cfg.connect_timeout = config.get_connect_timeout().cloned(); + cfg.ports = Some(db_config.get_ports().to_vec()); + cfg.application_name = db_config.get_application_name().map(|it| it.to_string()); + cfg.connect_timeout = db_config.get_connect_timeout().cloned(); let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap(); - let payto = taler_config.require_payto(); + let payto = taler_config.payto(); let state = ServerState { pool, notify: Notify::new(), - lifetime: taler_config.http_lifetime.map(AtomicU32::new), + lifetime: taler_config.http_lifetime().map(AtomicU32::new), status: AtomicBool::new(true), - db_config: taler_config.db_config, + db_config, payto, currency: taler_config.currency, }; @@ -190,7 +190,7 @@ async fn main() { if let Err(e) = server.await { error!("server: {}", e); } - } else if let Some(path) = taler_config.unix_path { + } else if let Some(path) = taler_config.unix_path() { use hyperlocal::UnixServerExt; info!("Server listening on unix domain socket {:?}", path); if let Err(err) = std::fs::remove_file(&path) { @@ -206,7 +206,7 @@ async fn main() { error!("server: {}", e); } } else { - let addr = ([0, 0, 0, 0], taler_config.port).into(); + let addr = ([0, 0, 0, 0], taler_config.port()).into(); info!("Server listening on http://{}", &addr); let server = Server::bind(&addr) .serve(make_service)