depolymerization

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

commit 3e080b281767c1d9623cf97091d2e4e1c01b450c
parent da0d6bcab7fb18212298a55a104333fb3e101a76
Author: Antoine A <>
Date:   Mon, 14 Feb 2022 19:40:44 +0100

Use taler amount format for bounce fee in config

Diffstat:
MREADME.md | 12++++++------
Mbtc-wire/src/loops/analysis.rs | 4++--
Mbtc-wire/src/loops/worker.rs | 3+--
Mbtc-wire/src/main.rs | 27+++++++++++++++++++++++----
Mcommon/src/config.rs | 24++++++++++++------------
Meth-wire/src/loops.rs | 21++++++++++++++++++++-
Meth-wire/src/loops/analysis.rs | 8+++++---
Meth-wire/src/loops/watcher.rs | 2+-
Meth-wire/src/loops/worker.rs | 7+++++--
Meth-wire/src/main.rs | 40+++++++++++++++++++++-------------------
Meth-wire/src/rpc.rs | 2+-
Mtest/conf/taler_btc_bump.conf | 2+-
Mtest/conf/taler_btc_lifetime.conf | 2+-
13 files changed, 99 insertions(+), 55 deletions(-)

diff --git a/README.md b/README.md @@ -15,14 +15,14 @@ The configuration is based on [taler.conf](https://docs.taler.net/manpages/taler ``` ini # taler.conf - common config [taler] -CURRENCY = ___ +CURRENCY = ___ [exchange] -BASE_URL = https://___ +BASE_URL = https://___ [depolymerizer-___] -DB_URL = postgres://___ -PAYTO = payto://___ +DB_URL = postgres://___ +PAYTO = payto://___ ``` ### Process lifetime @@ -35,9 +35,9 @@ done. ``` ini [depolymerizer-___] # Number of requests to serve before gateway shutdown (0 mean never) -HTTP_LIFETIME = 0 +HTTP_LIFETIME = 0 # Number of worker's loops before wire implementation shutdown (0 mean never) -WIRE_LIFETIME = 0 +WIRE_LIFETIME = 0 ``` ### Stuck transaction diff --git a/btc-wire/src/loops/analysis.rs b/btc-wire/src/loops/analysis.rs @@ -53,11 +53,11 @@ pub fn analysis(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &Wire // If new fork is bigger than the current confirmation if fork > current_conf { // Max two time the configuration - let new_conf = fork.min(state.config.confirmation * 2); + let new_conf = fork.min(state.max_confirmation); state.confirmation.store(new_conf, Ordering::SeqCst); warn!( "analysis: found dangerous fork of {} blocks, adapt confirmation to {} blocks capped at {}, you should update taler.conf", - fork, new_conf, state.config.confirmation * 2 + fork, new_conf, state.max_confirmation ); } } diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs @@ -119,9 +119,8 @@ pub fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireSt ); } - let bounce_fee = BtcAmount::from_sat(state.config.bounce_fee); // Send requested bounce - while bounce(db, rpc, &bounce_fee)? {} + while bounce(db, rpc, &state.bounce_fee)? {} } Ok(()) diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -13,18 +13,21 @@ You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -use bitcoin::Network; +use bitcoin::{Amount as BtcAmount, Network}; use btc_wire::{ config::{BitcoinConfig, WIRE_WALLET_NAME}, rpc::{auto_reconnect_rpc, Rpc}, rpc_utils::default_data_dir, }; use common::{ + api_common::Amount, config::{load_btc_config, BtcConfig}, log::log::info, - reconnect::auto_reconnect_db, named_spawn, + named_spawn, + reconnect::auto_reconnect_db, }; -use std::{sync::atomic::AtomicU16, thread::JoinHandle}; +use std::{str::FromStr, sync::atomic::AtomicU16}; +use taler_util::taler_to_btc; use crate::loops::{analysis::analysis, watcher::watcher, worker::worker}; @@ -34,9 +37,22 @@ mod metadata; mod sql; mod taler_util; +const DEFAULT_CONFIRMATION: u16 = 6; +const DEFAULT_BOUNCE_FEE: &'static str = "BTC:0.00001"; + pub struct WireState { confirmation: AtomicU16, + max_confirmation: u16, config: BtcConfig, + bounce_fee: BtcAmount, +} + +fn config_bounce_fee(config: &BtcConfig) -> BtcAmount { + let config = config.bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE); + Amount::from_str(&config) + .ok() + .and_then(|a| taler_to_btc(&a).ok()) + .expect("config value BOUNCE_FEE is no a valid bitcoin amount") } fn main() { @@ -68,8 +84,11 @@ fn main() { }; info!("Running on {} chain", chain_name); + let init_confirmation = config.confirmation.unwrap_or(DEFAULT_CONFIRMATION); let state: &'static WireState = Box::leak(Box::new(WireState { - confirmation: AtomicU16::new(config.confirmation), + confirmation: AtomicU16::new(init_confirmation), + max_confirmation: init_confirmation * 2, + bounce_fee: config_bounce_fee(&config), config, })); diff --git a/common/src/config.rs b/common/src/config.rs @@ -92,26 +92,24 @@ impl Config for GatewayConfig { // TODO currency name as const generic #[derive(Debug, Clone, PartialEq, Eq)] -pub struct WireConfig<const DEFAULT_FEE: u64, const DEFAULT_CONFIRMATION: u16> { +pub struct WireConfig { pub base_url: Url, - pub confirmation: u16, - pub bounce_fee: u64, + pub confirmation: Option<u16>, + pub bounce_fee: Option<String>, pub wire_lifetime: Option<u32>, pub bump_delay: Option<u32>, pub payto: Url, pub core: CoreConfig, } -impl<const DEFAULT_FEE: u64, const DEFAULT_CONFIRMATION: u16> Config - for WireConfig<DEFAULT_FEE, DEFAULT_CONFIRMATION> -{ +impl Config for WireConfig { fn load_from_ini(ini: &Ini, currency: &str, dep: &Properties) -> Self { let ex = section(ini, "exchange"); - Self { + let config = Self { base_url: require(ex, "BASE_URL", url), payto: require(dep, "PAYTO", url), - confirmation: nb(dep, "CONFIRMATION").unwrap_or(DEFAULT_CONFIRMATION), - bounce_fee: nb(dep, "BOUNCE_FEE").unwrap_or(DEFAULT_FEE), + 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), @@ -119,11 +117,13 @@ impl<const DEFAULT_FEE: u64, const DEFAULT_CONFIRMATION: u16> Config .and_then(|nb| (nb != 0).then(|| Some(nb))) .unwrap_or(None), core: CoreConfig::load_from_ini(ini, currency, dep), - } + }; + assert_eq!(config.core.currency, currency); + return config; } } -pub type BtcConfig = WireConfig<1000, 6>; +pub type BtcConfig = WireConfig; pub fn load_btc_config(path: Option<&str>) -> BtcConfig { let config = WireConfig::load_taler_config(path); @@ -131,7 +131,7 @@ pub fn load_btc_config(path: Option<&str>) -> BtcConfig { return config; } -pub type EthConfig = WireConfig<10_000_000_000_000, 24>; +pub type EthConfig = WireConfig; pub fn load_eth_config(path: Option<&str>) -> EthConfig { let config = WireConfig::load_taler_config(path); diff --git a/eth-wire/src/loops.rs b/eth-wire/src/loops.rs @@ -14,6 +14,25 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +use common::postgres; +use eth_wire::rpc; + +use crate::fail_point::Injected; + +pub mod analysis; pub mod watcher; pub mod worker; -pub mod analysis; + +#[derive(Debug, thiserror::Error)] +pub enum LoopError { + #[error(transparent)] + RPC(#[from] rpc::Error), + #[error(transparent)] + DB(#[from] postgres::Error), + #[error("Another eth-wire process is running concurrently")] + Concurrency, + #[error(transparent)] + Injected(#[from] Injected), +} + +pub type LoopResult<T> = Result<T, LoopError>; diff --git a/eth-wire/src/loops/analysis.rs b/eth-wire/src/loops/analysis.rs @@ -24,7 +24,9 @@ use common::{ use eth_wire::rpc::{AutoReconnectRPC, Rpc}; use ethereum_types::{H256, U64}; -use crate::{LoopResult, WireState}; +use crate::WireState; + +use super::LoopResult; /// Analyse blockchain behavior and adapt confirmations in real time pub fn analysis(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireState) { @@ -48,11 +50,11 @@ pub fn analysis(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &Wire // If new fork is bigger than the current confirmation if fork > current_conf { // Max two time the configuration - let new_conf = fork.min(state.config.confirmation * 2); + let new_conf = fork.min(state.max_confirmations); state.confirmation.store(new_conf, Ordering::SeqCst); warn!( "analysis: found dangerous fork of {} blocks, adapt confirmation to {} blocks capped at {}, you should update taler.conf", - fork, new_conf, state.config.confirmation * 2 + fork, new_conf, state.max_confirmations ); } } diff --git a/eth-wire/src/loops/watcher.rs b/eth-wire/src/loops/watcher.rs @@ -16,7 +16,7 @@ use common::{log::log::error, reconnect::AutoReconnectDb}; use eth_wire::rpc::AutoReconnectRPC; -use crate::LoopResult; +use super::LoopResult; /// Wait for new block and notify arrival with postgreSQL notifications pub fn watcher(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb) { diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs @@ -33,10 +33,13 @@ use ethereum_types::{Address, H256, U256, U64}; use crate::{ fail_point::fail_point, + loops::LoopError, sql::{sql_addr, sql_eth_amount, sql_hash}, - LoopError, LoopResult, WireState, + WireState, }; +use super::LoopResult; + pub fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireState) { let mut lifetime = state.config.wire_lifetime; let mut status = true; @@ -95,7 +98,7 @@ pub fn worker(mut rpc: AutoReconnectRPC, mut db: AutoReconnectDb, state: &WireSt while withdraw(db, rpc, state)? {} // Send requested bounce - while bounce(db, rpc, U256::from(state.config.bounce_fee))? {} + while bounce(db, rpc, state.bounce_fee)? {} } Ok(()) })(); diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs @@ -14,54 +14,56 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -use std::sync::atomic::AtomicU16; +use std::{str::FromStr, sync::atomic::AtomicU16}; use common::{ + api_common::Amount, config::{load_eth_config, EthConfig}, - named_spawn, postgres, + named_spawn, reconnect::auto_reconnect_db, }; use eth_wire::{ - rpc::{self, auto_reconnect_rpc}, - taler_util::eth_payto_addr, + rpc::auto_reconnect_rpc, + taler_util::{eth_payto_addr, taler_to_eth}, }; -use ethereum_types::H160; -use fail_point::Injected; +use ethereum_types::{H160, U256}; use loops::{analysis::analysis, watcher::watcher, worker::worker}; mod fail_point; mod loops; mod sql; +const DEFAULT_CONFIRMATION: u16 = 24; +const DEFAULT_BOUNCE_FEE: &'static str = "ETH:0.00001"; + pub struct WireState { confirmation: AtomicU16, + max_confirmations: u16, address: H160, config: EthConfig, + bounce_fee: U256, } -#[derive(Debug, thiserror::Error)] -pub enum LoopError { - #[error(transparent)] - RPC(#[from] rpc::Error), - #[error(transparent)] - DB(#[from] postgres::Error), - #[error("Another eth-wire process is running concurrently")] - Concurrency, - #[error(transparent)] - Injected(#[from] Injected), +fn config_bounce_fee(config: &EthConfig) -> U256 { + let config = config.bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE); + Amount::from_str(&config) + .ok() + .and_then(|a| taler_to_eth(&a).ok()) + .expect("config value BOUNCE_FEE is no a valid ethereum amount") } -pub type LoopResult<T> = Result<T, LoopError>; - fn main() { common::log::init(); let path = std::env::args().nth(1).unwrap(); let config = load_eth_config(Some(&path)); + let init_confirmation = config.confirmation.unwrap_or(DEFAULT_CONFIRMATION); let state: &'static WireState = Box::leak(Box::new(WireState { - confirmation: AtomicU16::new(config.confirmation), + confirmation: AtomicU16::new(init_confirmation), + max_confirmations: init_confirmation * 2, address: eth_payto_addr(&config.payto).unwrap(), + bounce_fee: config_bounce_fee(&config), config, })); diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs @@ -22,7 +22,7 @@ use common::{log::log::error, reconnect::AutoReconnect, url::Url}; use ethereum_types::{Address, H256, U256, U64}; use serde::de::DeserializeOwned; -use serde_json::{error::Category, Value}; +use serde_json::error::Category; use std::{ fmt::Debug, io::{self, BufWriter, ErrorKind, Read, Write}, diff --git a/test/conf/taler_btc_bump.conf b/test/conf/taler_btc_bump.conf @@ -1,5 +1,5 @@ [taler] -CURRENCY = BTC +CURRENCY = BTC [exchange] BASE_URL = http://test.com diff --git a/test/conf/taler_btc_lifetime.conf b/test/conf/taler_btc_lifetime.conf @@ -1,5 +1,5 @@ [taler] -CURRENCY = BTC +CURRENCY = BTC [exchange] BASE_URL = http://test.com