From 049b7bc3299fbe8cd84126efc465eb8692cdc519 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 27 Jan 2021 13:33:32 +1100 Subject: [PATCH] Separate settings from config Settings to be used internally to pass configuration to swap execution. Config to be used for reading/writing configuration parameters to file. Eventually the settings can be created from config. --- swap/src/bitcoin.rs | 4 +- swap/src/bitcoin/wallet.rs | 12 ++-- swap/src/config.rs | 109 ------------------------------- swap/src/lib.rs | 1 + swap/src/main.rs | 26 ++++---- swap/src/protocol/alice.rs | 21 +++--- swap/src/protocol/alice/steps.rs | 25 +++---- swap/src/protocol/alice/swap.rs | 41 ++++++------ swap/src/protocol/bob.rs | 27 ++++---- swap/src/protocol/bob/state.rs | 10 ++- swap/src/protocol/bob/swap.rs | 26 ++++---- swap/src/settings.rs | 108 ++++++++++++++++++++++++++++++ swap/tests/testutils/mod.rs | 29 ++++---- 13 files changed, 224 insertions(+), 215 deletions(-) create mode 100644 swap/src/settings.rs diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 3511e395..4bf6d590 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -10,7 +10,7 @@ pub use ::bitcoin::{util::amount::Amount, Address, Network, Transaction, Txid}; pub use ecdsa_fun::{adaptor::EncryptedSignature, fun::Scalar, Signature}; pub use wallet::Wallet; -use crate::{bitcoin::timelocks::BlockHeight, config::Config}; +use crate::{bitcoin::timelocks::BlockHeight, settings::Protocol}; use ::bitcoin::{ hashes::{hex::ToHex, Hash}, secp256k1, @@ -208,7 +208,7 @@ pub trait WatchForRawTransaction { #[async_trait] pub trait WaitForTransactionFinality { - async fn wait_for_transaction_finality(&self, txid: Txid, config: Config) -> Result<()>; + async fn wait_for_transaction_finality(&self, txid: Txid, settings: Protocol) -> Result<()>; } #[async_trait] diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index cecfd62e..3c7199a2 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -4,7 +4,7 @@ use crate::{ GetBlockHeight, GetNetwork, GetRawTransaction, SignTxLock, Transaction, TransactionBlockHeight, TxLock, WaitForTransactionFinality, WatchForRawTransaction, }, - config::Config, + settings, }; use ::bitcoin::{util::psbt::PartiallySignedTransaction, Txid}; use anyhow::{Context, Result}; @@ -170,17 +170,21 @@ impl TransactionBlockHeight for Wallet { #[async_trait] impl WaitForTransactionFinality for Wallet { - async fn wait_for_transaction_finality(&self, txid: Txid, config: Config) -> Result<()> { + async fn wait_for_transaction_finality( + &self, + txid: Txid, + settings: settings::Protocol, + ) -> Result<()> { // TODO(Franck): This assumes that bitcoind runs with txindex=1 // Divide by 4 to not check too often yet still be aware of the new block early // on. - let mut interval = interval(config.bitcoin_avg_block_time / 4); + let mut interval = interval(settings.bitcoin_avg_block_time / 4); loop { let tx = self.inner.client.get_raw_transaction_verbose(txid).await?; if let Some(confirmations) = tx.confirmations { - if confirmations >= config.bitcoin_finality_confirmations { + if confirmations >= settings.bitcoin_finality_confirmations { break; } } diff --git a/swap/src/config.rs b/swap/src/config.rs index 8ef318c2..01fbddaa 100644 --- a/swap/src/config.rs +++ b/swap/src/config.rs @@ -1,110 +1 @@ pub mod seed; - -use crate::bitcoin::Timelock; -use conquer_once::Lazy; -use std::time::Duration; - -#[derive(Debug, Copy, Clone)] -pub struct Config { - pub bob_time_to_act: Duration, - pub bitcoin_finality_confirmations: u32, - pub bitcoin_avg_block_time: Duration, - pub monero_finality_confirmations: u32, - pub bitcoin_cancel_timelock: Timelock, - pub bitcoin_punish_timelock: Timelock, - pub bitcoin_network: bitcoin::Network, - pub monero_network: monero::Network, -} - -impl Config { - pub fn mainnet() -> Self { - Self { - bob_time_to_act: *mainnet::BOB_TIME_TO_ACT, - bitcoin_finality_confirmations: mainnet::BITCOIN_FINALITY_CONFIRMATIONS, - bitcoin_avg_block_time: *mainnet::BITCOIN_AVG_BLOCK_TIME, - monero_finality_confirmations: mainnet::MONERO_FINALITY_CONFIRMATIONS, - bitcoin_cancel_timelock: mainnet::BITCOIN_CANCEL_TIMELOCK, - bitcoin_punish_timelock: mainnet::BITCOIN_PUNISH_TIMELOCK, - bitcoin_network: bitcoin::Network::Bitcoin, - monero_network: monero::Network::Mainnet, - } - } - - pub fn testnet() -> Self { - Self { - bob_time_to_act: *testnet::BOB_TIME_TO_ACT, - bitcoin_finality_confirmations: testnet::BITCOIN_FINALITY_CONFIRMATIONS, - bitcoin_avg_block_time: *testnet::BITCOIN_AVG_BLOCK_TIME, - monero_finality_confirmations: testnet::MONERO_FINALITY_CONFIRMATIONS, - bitcoin_cancel_timelock: testnet::BITCOIN_CANCEL_TIMELOCK, - bitcoin_punish_timelock: testnet::BITCOIN_PUNISH_TIMELOCK, - bitcoin_network: bitcoin::Network::Testnet, - monero_network: monero::Network::Stagenet, - } - } - - pub fn regtest() -> Self { - Self { - bob_time_to_act: *regtest::BOB_TIME_TO_ACT, - bitcoin_finality_confirmations: regtest::BITCOIN_FINALITY_CONFIRMATIONS, - bitcoin_avg_block_time: *regtest::BITCOIN_AVG_BLOCK_TIME, - monero_finality_confirmations: regtest::MONERO_FINALITY_CONFIRMATIONS, - bitcoin_cancel_timelock: regtest::BITCOIN_CANCEL_TIMELOCK, - bitcoin_punish_timelock: regtest::BITCOIN_PUNISH_TIMELOCK, - bitcoin_network: bitcoin::Network::Regtest, - monero_network: monero::Network::default(), - } - } -} - -mod mainnet { - use super::*; - - // For each step, we are giving Bob 10 minutes to act. - pub static BOB_TIME_TO_ACT: Lazy = Lazy::new(|| Duration::from_secs(10 * 60)); - - pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 3; - - pub static BITCOIN_AVG_BLOCK_TIME: Lazy = Lazy::new(|| Duration::from_secs(10 * 60)); - - pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 15; - - // Set to 12 hours, arbitrary value to be reviewed properly - pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(72); - pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(72); -} - -mod testnet { - use super::*; - - pub static BOB_TIME_TO_ACT: Lazy = Lazy::new(|| Duration::from_secs(60 * 60)); - - // This does not reflect recommended values for mainnet! - pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 1; - - pub static BITCOIN_AVG_BLOCK_TIME: Lazy = Lazy::new(|| Duration::from_secs(5 * 60)); - - // This does not reflect recommended values for mainnet! - pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 5; - - // This does not reflect recommended values for mainnet! - pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(12); - pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(6); -} - -mod regtest { - use super::*; - - // In test, we set a shorter time to fail fast - pub static BOB_TIME_TO_ACT: Lazy = Lazy::new(|| Duration::from_secs(30)); - - pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 1; - - pub static BITCOIN_AVG_BLOCK_TIME: Lazy = Lazy::new(|| Duration::from_secs(5)); - - pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 1; - - pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(50); - - pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(50); -} diff --git a/swap/src/lib.rs b/swap/src/lib.rs index 5e51f8d5..22b7c4a5 100644 --- a/swap/src/lib.rs +++ b/swap/src/lib.rs @@ -23,6 +23,7 @@ pub mod monero; pub mod network; pub mod protocol; pub mod seed; +pub mod settings; pub mod trace; mod fs; diff --git a/swap/src/main.rs b/swap/src/main.rs index e5c23fad..476c88be 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -14,7 +14,6 @@ use crate::cli::{Command, Options, Resume}; use anyhow::{Context, Result}; -use config::Config; use database::Database; use prettytable::{row, Table}; use protocol::{alice, bob, bob::Builder, SwapAmounts}; @@ -31,6 +30,7 @@ pub mod monero; pub mod network; pub mod protocol; pub mod seed; +pub mod settings; pub mod trace; mod cli; @@ -45,7 +45,7 @@ async fn main() -> Result<()> { init_tracing(LevelFilter::Info).expect("initialize tracing"); let opt = Options::from_args(); - let config = Config::testnet(); + let settings = settings::Protocol::testnet(); info!( "Database and Seed will be stored in directory: {}", @@ -76,7 +76,7 @@ async fn main() -> Result<()> { bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, - config, + settings, ) .await?; @@ -89,7 +89,7 @@ async fn main() -> Result<()> { let alice_factory = alice::Builder::new( seed, - config, + settings, swap_id, Arc::new(bitcoin_wallet), Arc::new(monero_wallet), @@ -121,7 +121,7 @@ async fn main() -> Result<()> { bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, - config, + settings, ) .await?; @@ -140,7 +140,7 @@ async fn main() -> Result<()> { Arc::new(monero_wallet), alice_addr, alice_peer_id, - config, + settings, ); let (swap, event_loop) = bob_factory.with_init_params(swap_amounts).build().await?; @@ -172,13 +172,13 @@ async fn main() -> Result<()> { bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, - config, + settings, ) .await?; let alice_factory = alice::Builder::new( seed, - config, + settings, swap_id, Arc::new(bitcoin_wallet), Arc::new(monero_wallet), @@ -203,7 +203,7 @@ async fn main() -> Result<()> { bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, - config, + settings, ) .await?; @@ -215,7 +215,7 @@ async fn main() -> Result<()> { Arc::new(monero_wallet), alice_addr, alice_peer_id, - config, + settings, ); let (swap, event_loop) = bob_factory.build().await?; @@ -231,17 +231,17 @@ async fn setup_wallets( bitcoind_url: url::Url, bitcoin_wallet_name: &str, monero_wallet_rpc_url: url::Url, - config: Config, + settings: settings::Protocol, ) -> Result<(bitcoin::Wallet, monero::Wallet)> { let bitcoin_wallet = - bitcoin::Wallet::new(bitcoin_wallet_name, bitcoind_url, config.bitcoin_network).await?; + bitcoin::Wallet::new(bitcoin_wallet_name, bitcoind_url, settings.bitcoin_network).await?; let bitcoin_balance = bitcoin_wallet.balance().await?; info!( "Connection to Bitcoin wallet succeeded, balance: {}", bitcoin_balance ); - let monero_wallet = monero::Wallet::new(monero_wallet_rpc_url, config.monero_network); + let monero_wallet = monero::Wallet::new(monero_wallet_rpc_url, settings.monero_network); let monero_balance = monero_wallet.get_balance().await?; info!( "Connection to Monero wallet succeeded, balance: {}", diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index 22af28df..0af0b17c 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -10,9 +10,7 @@ pub use self::{ transfer_proof::TransferProof, }; use crate::{ - bitcoin, - config::Config, - database, + bitcoin, database, database::Database, monero, network::{ @@ -23,6 +21,7 @@ use crate::{ }, protocol::{bob, bob::EncryptedSignature, SwapAmounts}, seed::Seed, + settings, }; use anyhow::{bail, Result}; use libp2p::{ @@ -49,7 +48,7 @@ pub struct Swap { pub event_loop_handle: EventLoopHandle, pub bitcoin_wallet: Arc, pub monero_wallet: Arc, - pub config: Config, + pub settings: settings::Protocol, pub swap_id: Uuid, pub db: Database, } @@ -59,7 +58,7 @@ pub struct Builder { identity: Keypair, peer_id: PeerId, db_path: PathBuf, - config: Config, + settings: settings::Protocol, listen_address: Multiaddr, @@ -77,7 +76,7 @@ enum InitParams { impl Builder { pub async fn new( seed: Seed, - config: Config, + settings: settings::Protocol, swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, @@ -93,7 +92,7 @@ impl Builder { identity, peer_id, db_path, - config, + settings, listen_address, bitcoin_wallet, monero_wallet, @@ -124,7 +123,7 @@ impl Builder { event_loop_handle, bitcoin_wallet: self.bitcoin_wallet, monero_wallet: self.monero_wallet, - config: self.config, + settings: self.settings, db, state: initial_state, swap_id: self.swap_id, @@ -154,7 +153,7 @@ impl Builder { event_loop_handle, bitcoin_wallet: self.bitcoin_wallet, monero_wallet: self.monero_wallet, - config: self.config, + settings: self.settings, swap_id: self.swap_id, db, }, @@ -195,8 +194,8 @@ impl Builder { v_a, amounts.btc, amounts.xmr, - self.config.bitcoin_cancel_timelock, - self.config.bitcoin_punish_timelock, + self.settings.bitcoin_cancel_timelock, + self.settings.bitcoin_punish_timelock, redeem_address, punish_address, ); diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index 37de2b34..512fce4a 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -7,7 +7,6 @@ use crate::{ TransactionBlockHeight, TxCancel, TxLock, TxRefund, WaitForTransactionFinality, WatchForRawTransaction, }, - config::Config, monero, monero::Transfer, protocol::{ @@ -15,6 +14,7 @@ use crate::{ alice::{event_loop::EventLoopHandle, SwapResponse, TransferProof}, SwapAmounts, }, + settings, }; use anyhow::{Context, Result}; use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic}; @@ -33,19 +33,19 @@ pub async fn negotiate( state0: alice::State0, xmr_amount: monero::Amount, event_loop_handle: &mut EventLoopHandle, - config: Config, + settings: settings::Protocol, ) -> Result<(PeerId, alice::State3)> { trace!("Starting negotiate"); // todo: we can move this out, we dont need to timeout here let bob_peer_id = timeout( - config.bob_time_to_act, + settings.bob_time_to_act, event_loop_handle.recv_conn_established(), ) .await .context("Failed to receive dial connection from Bob")??; - let event = timeout(config.bob_time_to_act, event_loop_handle.recv_request()) + let event = timeout(settings.bob_time_to_act, event_loop_handle.recv_request()) .await .context("Failed to receive swap request from Bob")??; @@ -54,7 +54,7 @@ pub async fn negotiate( .await?; let (bob_message0, channel) = - timeout(config.bob_time_to_act, event_loop_handle.recv_message0()).await??; + timeout(settings.bob_time_to_act, event_loop_handle.recv_message0()).await??; let alice_message0 = state0.next_message(&mut OsRng); event_loop_handle @@ -64,7 +64,7 @@ pub async fn negotiate( let state1 = state0.receive(bob_message0)?; let (bob_message1, channel) = - timeout(config.bob_time_to_act, event_loop_handle.recv_message1()).await??; + timeout(settings.bob_time_to_act, event_loop_handle.recv_message1()).await??; let state2 = state1.receive(bob_message1); @@ -72,7 +72,8 @@ pub async fn negotiate( .send_message1(channel, state2.next_message()) .await?; - let bob_message2 = timeout(config.bob_time_to_act, event_loop_handle.recv_message2()).await??; + let bob_message2 = + timeout(settings.bob_time_to_act, event_loop_handle.recv_message2()).await??; let state3 = state2.receive(bob_message2)?; @@ -84,14 +85,14 @@ pub async fn negotiate( pub async fn wait_for_locked_bitcoin( lock_bitcoin_txid: bitcoin::Txid, bitcoin_wallet: Arc, - config: Config, + settings: settings::Protocol, ) -> Result<()> where W: WatchForRawTransaction + WaitForTransactionFinality, { // We assume we will see Bob's transaction in the mempool first. timeout( - config.bob_time_to_act, + settings.bob_time_to_act, bitcoin_wallet.watch_for_raw_transaction(lock_bitcoin_txid), ) .await @@ -99,7 +100,7 @@ where // // We saw the transaction in the mempool, waiting for it to be confirmed. bitcoin_wallet - .wait_for_transaction_finality(lock_bitcoin_txid, config) + .wait_for_transaction_finality(lock_bitcoin_txid, settings) .await?; Ok(()) @@ -324,7 +325,7 @@ pub fn build_bitcoin_punish_transaction( pub async fn publish_bitcoin_punish_transaction( punish_tx: bitcoin::Transaction, bitcoin_wallet: Arc, - config: Config, + settings: settings::Protocol, ) -> Result where W: BroadcastSignedTransaction + WaitForTransactionFinality, @@ -334,7 +335,7 @@ where .await?; bitcoin_wallet - .wait_for_transaction_finality(txid, config) + .wait_for_transaction_finality(txid, settings) .await?; Ok(txid) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 2abe8e67..a69c280a 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -6,7 +6,6 @@ use crate::{ timelocks::ExpiredTimelocks, TransactionBlockHeight, WaitForTransactionFinality, WatchForRawTransaction, }, - config::Config, database, database::Database, monero, @@ -25,6 +24,7 @@ use crate::{ AliceState, }, }, + settings, }; use anyhow::{bail, Result}; use async_recursion::async_recursion; @@ -65,7 +65,7 @@ pub async fn run_until( swap.event_loop_handle, swap.bitcoin_wallet, swap.monero_wallet, - swap.config, + swap.settings, swap.swap_id, swap.db, ) @@ -81,7 +81,7 @@ async fn run_until_internal( mut event_loop_handle: EventLoopHandle, bitcoin_wallet: Arc, monero_wallet: Arc, - config: Config, + settings: settings::Protocol, swap_id: Uuid, db: Database, ) -> Result { @@ -92,7 +92,7 @@ async fn run_until_internal( match state { AliceState::Started { amounts, state0 } => { let (bob_peer_id, state3) = - negotiate(state0, amounts.xmr, &mut event_loop_handle, config).await?; + negotiate(state0, amounts.xmr, &mut event_loop_handle, settings).await?; let state = AliceState::Negotiated { bob_peer_id, @@ -109,7 +109,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet, monero_wallet, - config, + settings, swap_id, db, ) @@ -120,9 +120,12 @@ async fn run_until_internal( bob_peer_id, amounts, } => { - let _ = - wait_for_locked_bitcoin(state3.tx_lock.txid(), bitcoin_wallet.clone(), config) - .await?; + let _ = wait_for_locked_bitcoin( + state3.tx_lock.txid(), + bitcoin_wallet.clone(), + settings, + ) + .await?; let state = AliceState::BtcLocked { bob_peer_id, @@ -139,7 +142,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet, monero_wallet, - config, + settings, swap_id, db, ) @@ -170,7 +173,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet, monero_wallet, - config, + settings, swap_id, db, ) @@ -208,7 +211,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet.clone(), monero_wallet, - config, + settings, swap_id, db, ) @@ -234,7 +237,7 @@ async fn run_until_internal( { Ok(txid) => { let publishded_redeem_tx = bitcoin_wallet - .wait_for_transaction_finality(txid, config) + .wait_for_transaction_finality(txid, settings) .await; match publishded_redeem_tx { @@ -280,7 +283,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet, monero_wallet, - config, + settings, swap_id, db, ) @@ -307,7 +310,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet, monero_wallet, - config, + settings, swap_id, db, ) @@ -341,7 +344,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet.clone(), monero_wallet, - config, + settings, swap_id, db, ) @@ -366,7 +369,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet.clone(), monero_wallet, - config, + settings, swap_id, db, ) @@ -401,7 +404,7 @@ async fn run_until_internal( let punish_tx_finalised = publish_bitcoin_punish_transaction( signed_tx_punish, bitcoin_wallet.clone(), - config, + settings, ); let refund_tx_seen = bitcoin_wallet.watch_for_raw_transaction(tx_refund.txid()); @@ -421,7 +424,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet.clone(), monero_wallet, - config, + settings, swap_id, db, ) @@ -445,7 +448,7 @@ async fn run_until_internal( event_loop_handle, bitcoin_wallet.clone(), monero_wallet, - config, + settings, swap_id, db, ) diff --git a/swap/src/protocol/bob.rs b/swap/src/protocol/bob.rs index f4ca2e52..ff7d7c6c 100644 --- a/swap/src/protocol/bob.rs +++ b/swap/src/protocol/bob.rs @@ -1,9 +1,7 @@ //! Run an XMR/BTC swap in the role of Bob. //! Bob holds BTC and wishes receive XMR. use crate::{ - bitcoin, - config::Config, - database, + bitcoin, database, database::Database, monero, network, network::{ @@ -12,6 +10,7 @@ use crate::{ }, protocol::{alice, bob, SwapAmounts}, seed::Seed, + settings, }; use anyhow::{bail, Result}; use libp2p::{core::Multiaddr, identity::Keypair, NetworkBehaviour, PeerId}; @@ -48,7 +47,7 @@ pub struct Swap { pub db: Database, pub bitcoin_wallet: Arc, pub monero_wallet: Arc, - pub config: Config, + pub settings: settings::Protocol, pub swap_id: Uuid, } @@ -65,7 +64,7 @@ pub struct Builder { monero_wallet: Arc, init_params: InitParams, - config: Config, + settings: settings::Protocol, } enum InitParams { @@ -83,7 +82,7 @@ impl Builder { monero_wallet: Arc, alice_address: Multiaddr, alice_peer_id: PeerId, - config: Config, + settings: settings::Protocol, ) -> Self { let identity = network::Seed::new(seed).derive_libp2p_identity(); let peer_id = identity.public().into_peer_id(); @@ -98,7 +97,7 @@ impl Builder { bitcoin_wallet, monero_wallet, init_params: InitParams::None, - config, + settings, } } @@ -113,7 +112,7 @@ impl Builder { match self.init_params { InitParams::New { swap_amounts } => { let initial_state = self - .make_initial_state(swap_amounts.btc, swap_amounts.xmr, self.config) + .make_initial_state(swap_amounts.btc, swap_amounts.xmr, self.settings) .await?; let (event_loop, event_loop_handle) = self.init_event_loop()?; @@ -128,7 +127,7 @@ impl Builder { bitcoin_wallet: self.bitcoin_wallet.clone(), monero_wallet: self.monero_wallet.clone(), swap_id: self.swap_id, - config: self.config, + settings: self.settings, }, event_loop, )) @@ -157,7 +156,7 @@ impl Builder { bitcoin_wallet: self.bitcoin_wallet.clone(), monero_wallet: self.monero_wallet.clone(), swap_id: self.swap_id, - config: self.config, + settings: self.settings, }, event_loop, )) @@ -183,7 +182,7 @@ impl Builder { &self, btc_to_swap: bitcoin::Amount, xmr_to_swap: monero::Amount, - config: Config, + settings: settings::Protocol, ) -> Result { let amounts = SwapAmounts { btc: btc_to_swap, @@ -195,10 +194,10 @@ impl Builder { &mut OsRng, btc_to_swap, xmr_to_swap, - config.bitcoin_cancel_timelock, - config.bitcoin_punish_timelock, + settings.bitcoin_cancel_timelock, + settings.bitcoin_punish_timelock, refund_address, - config.monero_finality_confirmations, + settings.monero_finality_confirmations, ); Ok(BobState::Started { state0, amounts }) diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index 74f09ca2..51054153 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -6,10 +6,10 @@ use crate::{ GetBlockHeight, GetNetwork, GetRawTransaction, Transaction, TransactionBlockHeight, TxCancel, Txid, WatchForRawTransaction, }, - config::Config, monero, monero::{monero_private_key, TransferProof}, protocol::{alice, bob, bob::EncryptedSignature, SwapAmounts}, + settings, }; use anyhow::{anyhow, Result}; use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic, Signature}; @@ -556,7 +556,11 @@ impl State4 { .await } - pub async fn refund_btc(&self, bitcoin_wallet: &W, config: Config) -> Result<()> + pub async fn refund_btc( + &self, + bitcoin_wallet: &W, + settings: settings::Protocol, + ) -> Result<()> where W: bitcoin::BroadcastSignedTransaction + bitcoin::WaitForTransactionFinality, { @@ -581,7 +585,7 @@ impl State4 { .await?; bitcoin_wallet - .wait_for_transaction_finality(txid, config) + .wait_for_transaction_finality(txid, settings) .await?; Ok(()) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 767372be..54e84f74 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1,13 +1,13 @@ use crate::{ bitcoin, bitcoin::timelocks::ExpiredTimelocks, - config::Config, database::{Database, Swap}, monero, protocol::{ bob::{self, event_loop::EventLoopHandle, state::*, SwapRequest}, SwapAmounts, }, + settings, }; use anyhow::{bail, Result}; use async_recursion::async_recursion; @@ -45,7 +45,7 @@ pub async fn run_until( swap.monero_wallet, OsRng, swap.swap_id, - swap.config, + swap.settings, ) .await } @@ -62,7 +62,7 @@ async fn run_until_internal( monero_wallet: Arc, mut rng: R, swap_id: Uuid, - config: Config, + settings: settings::Protocol, ) -> Result where R: RngCore + CryptoRng + Send, @@ -96,7 +96,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -118,7 +118,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -171,7 +171,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -218,7 +218,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -261,7 +261,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -297,7 +297,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -319,7 +319,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -345,7 +345,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } @@ -356,7 +356,7 @@ where bail!("Internal error: canceled state reached before cancel timelock was expired"); } ExpiredTimelocks::Cancel => { - state.refund_btc(bitcoin_wallet.as_ref(), config).await?; + state.refund_btc(bitcoin_wallet.as_ref(), settings).await?; BobState::BtcRefunded(state) } ExpiredTimelocks::Punish => BobState::BtcPunished { @@ -375,7 +375,7 @@ where monero_wallet, rng, swap_id, - config, + settings, ) .await } diff --git a/swap/src/settings.rs b/swap/src/settings.rs new file mode 100644 index 00000000..75f68522 --- /dev/null +++ b/swap/src/settings.rs @@ -0,0 +1,108 @@ +use crate::bitcoin::Timelock; +use conquer_once::Lazy; +use std::time::Duration; + +#[derive(Debug, Copy, Clone)] +pub struct Protocol { + pub bob_time_to_act: Duration, + pub bitcoin_finality_confirmations: u32, + pub bitcoin_avg_block_time: Duration, + pub monero_finality_confirmations: u32, + pub bitcoin_cancel_timelock: Timelock, + pub bitcoin_punish_timelock: Timelock, + pub bitcoin_network: bitcoin::Network, + pub monero_network: monero::Network, +} + +impl Protocol { + pub fn mainnet() -> Self { + Self { + bob_time_to_act: *mainnet::BOB_TIME_TO_ACT, + bitcoin_finality_confirmations: mainnet::BITCOIN_FINALITY_CONFIRMATIONS, + bitcoin_avg_block_time: *mainnet::BITCOIN_AVG_BLOCK_TIME, + monero_finality_confirmations: mainnet::MONERO_FINALITY_CONFIRMATIONS, + bitcoin_cancel_timelock: mainnet::BITCOIN_CANCEL_TIMELOCK, + bitcoin_punish_timelock: mainnet::BITCOIN_PUNISH_TIMELOCK, + bitcoin_network: bitcoin::Network::Bitcoin, + monero_network: monero::Network::Mainnet, + } + } + + pub fn testnet() -> Self { + Self { + bob_time_to_act: *testnet::BOB_TIME_TO_ACT, + bitcoin_finality_confirmations: testnet::BITCOIN_FINALITY_CONFIRMATIONS, + bitcoin_avg_block_time: *testnet::BITCOIN_AVG_BLOCK_TIME, + monero_finality_confirmations: testnet::MONERO_FINALITY_CONFIRMATIONS, + bitcoin_cancel_timelock: testnet::BITCOIN_CANCEL_TIMELOCK, + bitcoin_punish_timelock: testnet::BITCOIN_PUNISH_TIMELOCK, + bitcoin_network: bitcoin::Network::Testnet, + monero_network: monero::Network::Stagenet, + } + } + + pub fn regtest() -> Self { + Self { + bob_time_to_act: *regtest::BOB_TIME_TO_ACT, + bitcoin_finality_confirmations: regtest::BITCOIN_FINALITY_CONFIRMATIONS, + bitcoin_avg_block_time: *regtest::BITCOIN_AVG_BLOCK_TIME, + monero_finality_confirmations: regtest::MONERO_FINALITY_CONFIRMATIONS, + bitcoin_cancel_timelock: regtest::BITCOIN_CANCEL_TIMELOCK, + bitcoin_punish_timelock: regtest::BITCOIN_PUNISH_TIMELOCK, + bitcoin_network: bitcoin::Network::Regtest, + monero_network: monero::Network::default(), + } + } +} + +mod mainnet { + use super::*; + + // For each step, we are giving Bob 10 minutes to act. + pub static BOB_TIME_TO_ACT: Lazy = Lazy::new(|| Duration::from_secs(10 * 60)); + + pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 3; + + pub static BITCOIN_AVG_BLOCK_TIME: Lazy = Lazy::new(|| Duration::from_secs(10 * 60)); + + pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 15; + + // Set to 12 hours, arbitrary value to be reviewed properly + pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(72); + pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(72); +} + +mod testnet { + use super::*; + + pub static BOB_TIME_TO_ACT: Lazy = Lazy::new(|| Duration::from_secs(60 * 60)); + + // This does not reflect recommended values for mainnet! + pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 1; + + pub static BITCOIN_AVG_BLOCK_TIME: Lazy = Lazy::new(|| Duration::from_secs(5 * 60)); + + // This does not reflect recommended values for mainnet! + pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 5; + + // This does not reflect recommended values for mainnet! + pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(12); + pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(6); +} + +mod regtest { + use super::*; + + // In test, we set a shorter time to fail fast + pub static BOB_TIME_TO_ACT: Lazy = Lazy::new(|| Duration::from_secs(30)); + + pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 1; + + pub static BITCOIN_AVG_BLOCK_TIME: Lazy = Lazy::new(|| Duration::from_secs(5)); + + pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 1; + + pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(50); + + pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(50); +} diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index e21aa1a4..dcd5fe16 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -6,11 +6,10 @@ use libp2p::{core::Multiaddr, PeerId}; use monero_harness::{image, Monero}; use std::{path::PathBuf, sync::Arc}; use swap::{ - bitcoin, - config::Config, - monero, + bitcoin, monero, protocol::{alice, alice::AliceState, bob, bob::BobState, SwapAmounts}, seed::Seed, + settings, }; use tempfile::tempdir; use testcontainers::{clients::Cli, Container}; @@ -26,7 +25,7 @@ pub struct StartingBalances { struct AliceParams { seed: Seed, - config: Config, + settings: settings::Protocol, swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, @@ -38,7 +37,7 @@ impl AliceParams { pub async fn builder(&self) -> alice::Builder { alice::Builder::new( self.seed, - self.config, + self.settings, self.swap_id, self.bitcoin_wallet.clone(), self.monero_wallet.clone(), @@ -61,7 +60,7 @@ struct BobParams { monero_wallet: Arc, alice_address: Multiaddr, alice_peer_id: PeerId, - config: Config, + settings: settings::Protocol, } impl BobParams { @@ -74,7 +73,7 @@ impl BobParams { self.monero_wallet.clone(), self.alice_address.clone(), self.alice_peer_id.clone(), - self.config, + self.settings, ) } } @@ -304,7 +303,7 @@ where xmr: monero::Amount::from_piconero(1_000_000_000_000), }; - let config = Config::regtest(); + let settings = settings::Protocol::regtest(); let alice_starting_balances = StartingBalances { xmr: swap_amounts.xmr * 10, @@ -322,13 +321,13 @@ where &containers.bitcoind, &monero, alice_starting_balances.clone(), - config, + settings, ) .await; let alice_params = AliceParams { seed: Seed::random().unwrap(), - config, + settings, swap_id: Uuid::new_v4(), bitcoin_wallet: alice_bitcoin_wallet.clone(), monero_wallet: alice_monero_wallet.clone(), @@ -346,7 +345,7 @@ where &containers.bitcoind, &monero, bob_starting_balances.clone(), - config, + settings, ) .await; @@ -358,7 +357,7 @@ where monero_wallet: bob_monero_wallet.clone(), alice_address: alice_params.listen_address.clone(), alice_peer_id: alice_params.peer_id().await, - config, + settings, }; let test = TestContext { @@ -391,7 +390,7 @@ async fn init_wallets( bitcoind: &Bitcoind<'_>, monero: &Monero, starting_balances: StartingBalances, - config: Config, + settings: settings::Protocol, ) -> (Arc, Arc) { monero .init(vec![(name, starting_balances.xmr.as_piconero())]) @@ -400,11 +399,11 @@ async fn init_wallets( let xmr_wallet = Arc::new(swap::monero::Wallet { inner: monero.wallet(name).unwrap().client(), - network: config.monero_network, + network: settings.monero_network, }); let btc_wallet = Arc::new( - swap::bitcoin::Wallet::new(name, bitcoind.node_url.clone(), config.bitcoin_network) + swap::bitcoin::Wallet::new(name, bitcoind.node_url.clone(), settings.bitcoin_network) .await .unwrap(), );