diff --git a/swap/src/main.rs b/swap/src/main.rs index 0c70d67e..770b95f5 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -23,7 +23,7 @@ use swap::{ config::Config, database::Database, monero, - protocol::{alice, bob, bob::SwapFactory, StartingBalances}, + protocol::{alice, bob, bob::Builder}, trace::init_tracing, SwapAmounts, }; @@ -67,7 +67,7 @@ async fn main() -> Result<()> { btc: receive_bitcoin, }; - let (bitcoin_wallet, monero_wallet, starting_balances) = setup_wallets( + let (bitcoin_wallet, monero_wallet) = setup_wallets( bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, @@ -82,18 +82,18 @@ async fn main() -> Result<()> { send_monero, receive_bitcoin, swap_id ); - let alice_factory = alice::SwapFactory::new( + let alice_factory = alice::Builder::new( seed, config, swap_id, - bitcoin_wallet, - monero_wallet, - starting_balances, + Arc::new(bitcoin_wallet), + Arc::new(monero_wallet), db_path, listen_addr, ) .await; - let (swap, mut event_loop) = alice_factory.new_swap_as_alice(swap_amounts).await?; + let (swap, mut event_loop) = + alice_factory.with_init_params(swap_amounts).build().await?; tokio::spawn(async move { event_loop.run().await }); alice::run(swap).await?; @@ -112,7 +112,7 @@ async fn main() -> Result<()> { xmr: receive_monero, }; - let (bitcoin_wallet, monero_wallet, starting_balances) = setup_wallets( + let (bitcoin_wallet, monero_wallet) = setup_wallets( bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, @@ -127,18 +127,19 @@ async fn main() -> Result<()> { send_bitcoin, receive_monero, swap_id ); - let bob_factory = SwapFactory::new( + let bob_factory = Builder::new( seed, db_path, swap_id, - bitcoin_wallet, - monero_wallet, - config, - starting_balances, + Arc::new(bitcoin_wallet), + Arc::new(monero_wallet), alice_addr, alice_peer_id, ); - let (swap, event_loop) = bob_factory.new_swap_as_bob(swap_amounts).await?; + let (swap, event_loop) = bob_factory + .with_init_params(swap_amounts, config) + .build() + .await?; tokio::spawn(async move { event_loop.run().await }); bob::run(swap).await?; @@ -164,7 +165,7 @@ async fn main() -> Result<()> { monero_wallet_rpc_url, listen_addr, }) => { - let (bitcoin_wallet, monero_wallet, starting_balances) = setup_wallets( + let (bitcoin_wallet, monero_wallet) = setup_wallets( bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, @@ -172,18 +173,17 @@ async fn main() -> Result<()> { ) .await?; - let alice_factory = alice::SwapFactory::new( + let alice_factory = alice::Builder::new( seed, config, swap_id, - bitcoin_wallet, - monero_wallet, - starting_balances, + Arc::new(bitcoin_wallet), + Arc::new(monero_wallet), db_path, listen_addr, ) .await; - let (swap, mut event_loop) = alice_factory.recover_alice_from_db().await?; + let (swap, mut event_loop) = alice_factory.build().await?; tokio::spawn(async move { event_loop.run().await }); alice::run(swap).await?; @@ -196,7 +196,7 @@ async fn main() -> Result<()> { alice_peer_id, alice_addr, }) => { - let (bitcoin_wallet, monero_wallet, starting_balances) = setup_wallets( + let (bitcoin_wallet, monero_wallet) = setup_wallets( bitcoind_url, bitcoin_wallet_name.as_str(), monero_wallet_rpc_url, @@ -204,18 +204,16 @@ async fn main() -> Result<()> { ) .await?; - let bob_factory = SwapFactory::new( + let bob_factory = Builder::new( seed, db_path, swap_id, - bitcoin_wallet, - monero_wallet, - config, - starting_balances, + Arc::new(bitcoin_wallet), + Arc::new(monero_wallet), alice_addr, alice_peer_id, ); - let (swap, event_loop) = bob_factory.recover_bob_from_db().await?; + let (swap, event_loop) = bob_factory.build().await?; tokio::spawn(async move { event_loop.run().await }); bob::run(swap).await?; @@ -230,11 +228,7 @@ async fn setup_wallets( bitcoin_wallet_name: &str, monero_wallet_rpc_url: url::Url, config: Config, -) -> Result<( - Arc, - Arc, - StartingBalances, -)> { +) -> Result<(swap::bitcoin::Wallet, swap::monero::Wallet)> { let bitcoin_wallet = swap::bitcoin::Wallet::new(bitcoin_wallet_name, bitcoind_url, config.bitcoin_network) .await?; @@ -243,7 +237,6 @@ async fn setup_wallets( "Connection to Bitcoin wallet succeeded, balance: {}", bitcoin_balance ); - let bitcoin_wallet = Arc::new(bitcoin_wallet); let monero_wallet = monero::Wallet::new(monero_wallet_rpc_url, config.monero_network); let monero_balance = monero_wallet.get_balance().await?; @@ -251,12 +244,6 @@ async fn setup_wallets( "Connection to Monero wallet succeeded, balance: {}", monero_balance ); - let monero_wallet = Arc::new(monero_wallet); - let starting_balances = StartingBalances { - btc: bitcoin_balance, - xmr: monero_balance, - }; - - Ok((bitcoin_wallet, monero_wallet, starting_balances)) + Ok((bitcoin_wallet, monero_wallet)) } diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index 3b07005b..dba570d8 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -24,10 +24,7 @@ pub use self::{ state::*, swap::{run, run_until}, }; -use crate::{ - config::Config, database::Database, network::transport::build, protocol::StartingBalances, - seed::Seed, -}; +use crate::{config::Config, database::Database, network::transport::build, seed::Seed}; use libp2p::{core::Multiaddr, identity::Keypair}; use rand::rngs::OsRng; use std::{path::PathBuf, sync::Arc}; @@ -53,7 +50,7 @@ pub struct Swap { pub db: Database, } -pub struct SwapFactory { +pub struct Builder { swap_id: Uuid, identity: Keypair, peer_id: PeerId, @@ -62,20 +59,24 @@ pub struct SwapFactory { listen_address: Multiaddr, - pub bitcoin_wallet: Arc, - pub monero_wallet: Arc, - pub starting_balances: StartingBalances, + bitcoin_wallet: Arc, + monero_wallet: Arc, + + init_params: InitParams, } -impl SwapFactory { - #[allow(clippy::too_many_arguments)] +enum InitParams { + None, + New { swap_amounts: SwapAmounts }, +} + +impl Builder { pub async fn new( seed: Seed, config: Config, swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, - starting_balances: StartingBalances, db_path: PathBuf, listen_address: Multiaddr, ) -> Self { @@ -92,72 +93,71 @@ impl SwapFactory { listen_address, bitcoin_wallet, monero_wallet, - starting_balances, + init_params: InitParams::None, } } - pub async fn new_swap_as_alice(&self, swap_amounts: SwapAmounts) -> Result<(Swap, EventLoop)> { - let initial_state = init_alice_state( - swap_amounts.btc, - swap_amounts.xmr, - self.bitcoin_wallet.clone(), - self.config, - ) - .await?; - - let (event_loop, event_loop_handle) = init_alice_event_loop( - self.listen_address.clone(), - self.identity.clone(), - self.peer_id.clone(), - )?; - - let db = Database::open(self.db_path.as_path())?; - - Ok(( - Swap { - event_loop_handle, - bitcoin_wallet: self.bitcoin_wallet.clone(), - monero_wallet: self.monero_wallet.clone(), - config: self.config, - db, - state: initial_state, - swap_id: self.swap_id, - }, - event_loop, - )) + pub fn with_init_params(self, swap_amounts: SwapAmounts) -> Self { + Self { + init_params: InitParams::New { swap_amounts }, + ..self + } } - pub async fn recover_alice_from_db(&self) -> Result<(Swap, EventLoop)> { - // reopen the existing database - let db = Database::open(self.db_path.clone().as_path())?; + pub async fn build(self) -> Result<(Swap, EventLoop)> { + match self.init_params { + InitParams::New { swap_amounts } => { + let initial_state = self + .make_initial_state(swap_amounts.btc, swap_amounts.xmr) + .await?; - let resume_state = if let database::Swap::Alice(state) = db.get_state(self.swap_id)? { - state.into() - } else { - bail!( - "Trying to load swap with id {} for the wrong direction.", - self.swap_id - ) - }; + let (event_loop, event_loop_handle) = self.init_event_loop()?; - let (event_loop, event_loop_handle) = init_alice_event_loop( - self.listen_address.clone(), - self.identity.clone(), - self.peer_id.clone(), - )?; + let db = Database::open(self.db_path.as_path())?; - Ok(( - Swap { - state: resume_state, - event_loop_handle, - bitcoin_wallet: self.bitcoin_wallet.clone(), - monero_wallet: self.monero_wallet.clone(), - config: self.config, - swap_id: self.swap_id, - db, - }, - event_loop, - )) + Ok(( + Swap { + event_loop_handle, + bitcoin_wallet: self.bitcoin_wallet, + monero_wallet: self.monero_wallet, + config: self.config, + db, + state: initial_state, + swap_id: self.swap_id, + }, + event_loop, + )) + } + InitParams::None => { + // reopen the existing database + let db = Database::open(self.db_path.as_path())?; + + let resume_state = + if let database::Swap::Alice(state) = db.get_state(self.swap_id)? { + state.into() + } else { + bail!( + "Trying to load swap with id {} for the wrong direction.", + self.swap_id + ) + }; + + let (event_loop, event_loop_handle) = self.init_event_loop()?; + + Ok(( + Swap { + state: resume_state, + event_loop_handle, + bitcoin_wallet: self.bitcoin_wallet, + monero_wallet: self.monero_wallet, + config: self.config, + swap_id: self.swap_id, + db, + }, + event_loop, + )) + } + } } pub fn peer_id(&self) -> PeerId { @@ -167,49 +167,49 @@ impl SwapFactory { pub fn listen_address(&self) -> Multiaddr { self.listen_address.clone() } -} -async fn init_alice_state( - btc_to_swap: bitcoin::Amount, - xmr_to_swap: monero::Amount, - alice_btc_wallet: Arc, - config: Config, -) -> Result { - let rng = &mut OsRng; + async fn make_initial_state( + &self, + btc_to_swap: bitcoin::Amount, + xmr_to_swap: monero::Amount, + ) -> Result { + let rng = &mut OsRng; - let amounts = SwapAmounts { - btc: btc_to_swap, - xmr: xmr_to_swap, - }; + let amounts = SwapAmounts { + btc: btc_to_swap, + xmr: xmr_to_swap, + }; - let a = bitcoin::SecretKey::new_random(rng); - let s_a = cross_curve_dleq::Scalar::random(rng); - let v_a = monero::PrivateViewKey::new_random(rng); - let redeem_address = alice_btc_wallet.as_ref().new_address().await?; - let punish_address = redeem_address.clone(); - let state0 = State0::new( - a, - s_a, - v_a, - amounts.btc, - amounts.xmr, - config.bitcoin_cancel_timelock, - config.bitcoin_punish_timelock, - redeem_address, - punish_address, - ); + let a = bitcoin::SecretKey::new_random(rng); + let s_a = cross_curve_dleq::Scalar::random(rng); + let v_a = monero::PrivateViewKey::new_random(rng); + let redeem_address = self.bitcoin_wallet.new_address().await?; + let punish_address = redeem_address.clone(); + let state0 = State0::new( + a, + s_a, + v_a, + amounts.btc, + amounts.xmr, + self.config.bitcoin_cancel_timelock, + self.config.bitcoin_punish_timelock, + redeem_address, + punish_address, + ); - Ok(AliceState::Started { amounts, state0 }) -} + Ok(AliceState::Started { amounts, state0 }) + } -fn init_alice_event_loop( - listen: Multiaddr, - identity: Keypair, - peer_id: PeerId, -) -> Result<(EventLoop, EventLoopHandle)> { - let alice_behaviour = Behaviour::default(); - let alice_transport = build(identity)?; - EventLoop::new(alice_transport, alice_behaviour, listen, peer_id) + fn init_event_loop(&self) -> Result<(EventLoop, EventLoopHandle)> { + let alice_behaviour = Behaviour::default(); + let alice_transport = build(self.identity.clone())?; + EventLoop::new( + alice_transport, + alice_behaviour, + self.listen_address.clone(), + self.peer_id.clone(), + ) + } } #[derive(Debug)] diff --git a/swap/src/protocol/bob.rs b/swap/src/protocol/bob.rs index f9ac84a2..d9cfc3fd 100644 --- a/swap/src/protocol/bob.rs +++ b/swap/src/protocol/bob.rs @@ -23,10 +23,7 @@ pub use self::{ state::*, swap::{run, run_until}, }; -use crate::{ - config::Config, database::Database, network::transport::build, protocol::StartingBalances, - seed::Seed, -}; +use crate::{config::Config, database::Database, network::transport::build, seed::Seed}; use libp2p::identity::Keypair; use rand::rngs::OsRng; use std::{path::PathBuf, sync::Arc}; @@ -50,33 +47,38 @@ pub struct Swap { pub swap_id: Uuid, } -pub struct SwapFactory { +pub struct Builder { swap_id: Uuid, identity: Keypair, peer_id: PeerId, db_path: PathBuf, - config: Config, - alice_connect_address: Multiaddr, - alice_connect_peer_id: PeerId, + alice_address: Multiaddr, + alice_peer_id: PeerId, - pub bitcoin_wallet: Arc, - pub monero_wallet: Arc, - pub starting_balances: StartingBalances, + bitcoin_wallet: Arc, + monero_wallet: Arc, + + init_params: InitParams, } -impl SwapFactory { - #[allow(clippy::too_many_arguments)] +enum InitParams { + None, + New { + swap_amounts: SwapAmounts, + config: Config, + }, +} + +impl Builder { pub fn new( seed: Seed, db_path: PathBuf, swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, - config: Config, - starting_balances: StartingBalances, - alice_connect_address: Multiaddr, - alice_connect_peer_id: PeerId, + alice_address: Multiaddr, + alice_peer_id: PeerId, ) -> Self { let identity = network::Seed::new(seed).derive_libp2p_identity(); let peer_id = identity.public().into_peer_id(); @@ -86,126 +88,120 @@ impl SwapFactory { identity, peer_id, db_path, - config, - alice_connect_address, - alice_connect_peer_id, + alice_address, + alice_peer_id, bitcoin_wallet, monero_wallet, - starting_balances, + init_params: InitParams::None, } } - pub async fn new_swap_as_bob( - &self, - swap_amounts: SwapAmounts, - ) -> Result<(bob::Swap, bob::EventLoop)> { - let initial_state = init_bob_state( - swap_amounts.btc, - swap_amounts.xmr, - self.bitcoin_wallet.clone(), - self.config, - ) - .await?; - - let (event_loop, event_loop_handle) = init_bob_event_loop( - self.identity.clone(), - self.peer_id.clone(), - self.alice_connect_peer_id.clone(), - self.alice_connect_address.clone(), - )?; - - let db = Database::open(self.db_path.as_path())?; - - Ok(( - Swap { - state: initial_state, - event_loop_handle, - db, - bitcoin_wallet: self.bitcoin_wallet.clone(), - monero_wallet: self.monero_wallet.clone(), - swap_id: self.swap_id, + pub fn with_init_params(self, swap_amounts: SwapAmounts, config: Config) -> Self { + Self { + init_params: InitParams::New { + swap_amounts, + config, }, - event_loop, - )) + ..self + } } - pub async fn recover_bob_from_db(&self) -> Result<(bob::Swap, bob::EventLoop)> { - // reopen the existing database - let db = Database::open(self.db_path.clone().as_path())?; + pub async fn build(self) -> Result<(bob::Swap, bob::EventLoop)> { + match self.init_params { + InitParams::New { + swap_amounts, + config, + } => { + let initial_state = self + .make_initial_state(swap_amounts.btc, swap_amounts.xmr, config) + .await?; - let resume_state = if let database::Swap::Bob(state) = db.get_state(self.swap_id)? { - state.into() - } else { - bail!( - "Trying to load swap with id {} for the wrong direction.", - self.swap_id - ) + let (event_loop, event_loop_handle) = self.init_event_loop()?; + + let db = Database::open(self.db_path.as_path())?; + + Ok(( + Swap { + state: initial_state, + event_loop_handle, + db, + bitcoin_wallet: self.bitcoin_wallet.clone(), + monero_wallet: self.monero_wallet.clone(), + swap_id: self.swap_id, + }, + event_loop, + )) + } + InitParams::None => { + // reopen the existing database + let db = Database::open(self.db_path.as_path())?; + + let resume_state = if let database::Swap::Bob(state) = db.get_state(self.swap_id)? { + state.into() + } else { + bail!( + "Trying to load swap with id {} for the wrong direction.", + self.swap_id + ) + }; + + let (event_loop, event_loop_handle) = self.init_event_loop()?; + + Ok(( + Swap { + state: resume_state, + event_loop_handle, + db, + bitcoin_wallet: self.bitcoin_wallet.clone(), + monero_wallet: self.monero_wallet.clone(), + swap_id: self.swap_id, + }, + event_loop, + )) + } + } + } + fn init_event_loop( + &self, + ) -> Result<(bob::event_loop::EventLoop, bob::event_loop::EventLoopHandle)> { + let bob_behaviour = bob::Behaviour::default(); + let bob_transport = build(self.identity.clone())?; + + bob::event_loop::EventLoop::new( + bob_transport, + bob_behaviour, + self.peer_id.clone(), + self.alice_peer_id.clone(), + self.alice_address.clone(), + ) + } + + async fn make_initial_state( + &self, + btc_to_swap: bitcoin::Amount, + xmr_to_swap: monero::Amount, + config: Config, + ) -> Result { + let amounts = SwapAmounts { + btc: btc_to_swap, + xmr: xmr_to_swap, }; - let (event_loop, event_loop_handle) = init_bob_event_loop( - self.identity.clone(), - self.peer_id.clone(), - self.alice_connect_peer_id.clone(), - self.alice_connect_address.clone(), - )?; + let refund_address = self.bitcoin_wallet.new_address().await?; + let state0 = bob::State0::new( + &mut OsRng, + btc_to_swap, + xmr_to_swap, + config.bitcoin_cancel_timelock, + config.bitcoin_punish_timelock, + refund_address, + config.monero_finality_confirmations, + ); - Ok(( - Swap { - state: resume_state, - event_loop_handle, - db, - bitcoin_wallet: self.bitcoin_wallet.clone(), - monero_wallet: self.monero_wallet.clone(), - swap_id: self.swap_id, - }, - event_loop, - )) + Ok(BobState::Started { state0, amounts }) } } -async fn init_bob_state( - btc_to_swap: bitcoin::Amount, - xmr_to_swap: monero::Amount, - bob_btc_wallet: Arc, - config: Config, -) -> Result { - let amounts = SwapAmounts { - btc: btc_to_swap, - xmr: xmr_to_swap, - }; - - let refund_address = bob_btc_wallet.new_address().await?; - let state0 = bob::State0::new( - &mut OsRng, - btc_to_swap, - xmr_to_swap, - config.bitcoin_cancel_timelock, - config.bitcoin_punish_timelock, - refund_address, - config.monero_finality_confirmations, - ); - - Ok(BobState::Started { state0, amounts }) -} - -fn init_bob_event_loop( - identity: Keypair, - peer_id: PeerId, - alice_peer_id: PeerId, - alice_addr: Multiaddr, -) -> Result<(bob::event_loop::EventLoop, bob::event_loop::EventLoopHandle)> { - let bob_behaviour = bob::Behaviour::default(); - let bob_transport = build(identity)?; - - bob::event_loop::EventLoop::new( - bob_transport, - bob_behaviour, - peer_id, - alice_peer_id, - alice_addr, - ) -} - #[derive(Debug, Clone)] pub enum OutEvent { ConnectionEstablished(PeerId), diff --git a/swap/tests/happy_path.rs b/swap/tests/happy_path.rs index 700c5d05..57789eed 100644 --- a/swap/tests/happy_path.rs +++ b/swap/tests/happy_path.rs @@ -7,7 +7,7 @@ pub mod testutils; #[tokio::test] async fn happy_path() { - testutils::setup_test(|ctx| async move { + testutils::setup_test(|mut ctx| async move { let alice_swap = ctx.new_swap_as_alice().await; let bob_swap = ctx.new_swap_as_bob().await; diff --git a/swap/tests/happy_path_restart_alice.rs b/swap/tests/happy_path_restart_alice.rs index dcd39f8e..1f298818 100644 --- a/swap/tests/happy_path_restart_alice.rs +++ b/swap/tests/happy_path_restart_alice.rs @@ -4,7 +4,7 @@ pub mod testutils; #[tokio::test] async fn given_alice_restarts_after_encsig_is_learned_resume_swap() { - testutils::setup_test(|ctx| async move { + testutils::setup_test(|mut ctx| async move { let alice_swap = ctx.new_swap_as_alice().await; let bob_swap = ctx.new_swap_as_bob().await; diff --git a/swap/tests/happy_path_restart_bob_after_comm.rs b/swap/tests/happy_path_restart_bob_after_comm.rs index a1c04034..93382734 100644 --- a/swap/tests/happy_path_restart_bob_after_comm.rs +++ b/swap/tests/happy_path_restart_bob_after_comm.rs @@ -4,7 +4,7 @@ pub mod testutils; #[tokio::test] async fn given_bob_restarts_after_encsig_is_sent_resume_swap() { - testutils::setup_test(|ctx| async move { + testutils::setup_test(|mut ctx| async move { let alice_swap = ctx.new_swap_as_alice().await; let bob_swap = ctx.new_swap_as_bob().await; diff --git a/swap/tests/happy_path_restart_bob_before_comm.rs b/swap/tests/happy_path_restart_bob_before_comm.rs index 231ed1e5..bd190b4c 100644 --- a/swap/tests/happy_path_restart_bob_before_comm.rs +++ b/swap/tests/happy_path_restart_bob_before_comm.rs @@ -7,7 +7,7 @@ pub mod testutils; #[tokio::test] async fn given_bob_restarts_after_xmr_is_locked_resume_swap() { - testutils::setup_test(|ctx| async move { + testutils::setup_test(|mut ctx| async move { let alice_swap = ctx.new_swap_as_alice().await; let bob_swap = ctx.new_swap_as_bob().await; diff --git a/swap/tests/punish.rs b/swap/tests/punish.rs index 9aea25bd..cc7289c4 100644 --- a/swap/tests/punish.rs +++ b/swap/tests/punish.rs @@ -9,7 +9,7 @@ pub mod testutils; /// the encsig and fail to refund or redeem. Alice punishes. #[tokio::test] async fn alice_punishes_if_bob_never_acts_after_fund() { - testutils::setup_test(|ctx| async move { + testutils::setup_test(|mut ctx| async move { let alice_swap = ctx.new_swap_as_alice().await; let bob_swap = ctx.new_swap_as_bob().await; diff --git a/swap/tests/refund_restart_alice.rs b/swap/tests/refund_restart_alice.rs index 111d1cfa..55fc2abe 100644 --- a/swap/tests/refund_restart_alice.rs +++ b/swap/tests/refund_restart_alice.rs @@ -6,7 +6,7 @@ pub mod testutils; /// then also refunds. #[tokio::test] async fn given_alice_restarts_after_xmr_is_locked_abort_swap() { - testutils::setup_test(|ctx| async move { + testutils::setup_test(|mut ctx| async move { let alice_swap = ctx.new_swap_as_alice().await; let bob_swap = ctx.new_swap_as_bob().await; diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index 021b8bd9..7a452d4c 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -2,14 +2,14 @@ use crate::testutils; use bitcoin_harness::Bitcoind; use futures::Future; use get_port::get_port; -use libp2p::core::Multiaddr; +use libp2p::{core::Multiaddr, PeerId}; use monero_harness::{image, Monero}; -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use swap::{ bitcoin, config::Config, monero, - protocol::{alice, alice::AliceState, bob, bob::BobState, StartingBalances}, + protocol::{alice, alice::AliceState, bob, bob::BobState}, seed::Seed, SwapAmounts, }; @@ -19,18 +19,87 @@ use tracing_core::dispatcher::DefaultGuard; use tracing_log::LogTracer; use uuid::Uuid; +#[derive(Debug, Clone)] +pub struct StartingBalances { + pub xmr: monero::Amount, + pub btc: bitcoin::Amount, +} + +struct AliceParams { + seed: Seed, + config: Config, + swap_id: Uuid, + bitcoin_wallet: Arc, + monero_wallet: Arc, + db_path: PathBuf, + listen_address: Multiaddr, +} + +impl AliceParams { + pub async fn builder(&self) -> alice::Builder { + alice::Builder::new( + self.seed, + self.config, + self.swap_id, + self.bitcoin_wallet.clone(), + self.monero_wallet.clone(), + self.db_path.clone(), + self.listen_address.clone(), + ) + .await + } + + async fn peer_id(&self) -> PeerId { + self.builder().await.peer_id() + } +} + +struct BobParams { + seed: Seed, + db_path: PathBuf, + swap_id: Uuid, + bitcoin_wallet: Arc, + monero_wallet: Arc, + alice_address: Multiaddr, + alice_peer_id: PeerId, +} + +impl BobParams { + pub fn builder(&self) -> bob::Builder { + bob::Builder::new( + self.seed, + self.db_path.clone(), + self.swap_id, + self.bitcoin_wallet.clone(), + self.monero_wallet.clone(), + self.alice_address.clone(), + self.alice_peer_id.clone(), + ) + } +} + pub struct TestContext { swap_amounts: SwapAmounts, - alice_swap_factory: alice::SwapFactory, - bob_swap_factory: bob::SwapFactory, + alice_params: AliceParams, + alice_starting_balances: StartingBalances, + alice_bitcoin_wallet: Arc, + alice_monero_wallet: Arc, + + bob_params: BobParams, + bob_starting_balances: StartingBalances, + bob_bitcoin_wallet: Arc, + bob_monero_wallet: Arc, } impl TestContext { - pub async fn new_swap_as_alice(&self) -> alice::Swap { + pub async fn new_swap_as_alice(&mut self) -> alice::Swap { let (swap, mut event_loop) = self - .alice_swap_factory - .new_swap_as_alice(self.swap_amounts) + .alice_params + .builder() + .await + .with_init_params(self.swap_amounts) + .build() .await .unwrap(); @@ -39,10 +108,12 @@ impl TestContext { swap } - pub async fn new_swap_as_bob(&self) -> bob::Swap { + pub async fn new_swap_as_bob(&mut self) -> bob::Swap { let (swap, event_loop) = self - .bob_swap_factory - .new_swap_as_bob(self.swap_amounts) + .bob_params + .builder() + .with_init_params(self.swap_amounts, Config::regtest()) + .build() .await .unwrap(); @@ -51,20 +122,16 @@ impl TestContext { swap } - pub async fn recover_alice_from_db(&self) -> alice::Swap { - let (swap, mut event_loop) = self - .alice_swap_factory - .recover_alice_from_db() - .await - .unwrap(); + pub async fn recover_alice_from_db(&mut self) -> alice::Swap { + let (swap, mut event_loop) = self.alice_params.builder().await.build().await.unwrap(); tokio::spawn(async move { event_loop.run().await }); swap } - pub async fn recover_bob_from_db(&self) -> bob::Swap { - let (swap, event_loop) = self.bob_swap_factory.recover_bob_from_db().await.unwrap(); + pub async fn recover_bob_from_db(&mut self) -> bob::Swap { + let (swap, event_loop) = self.bob_params.builder().build().await.unwrap(); tokio::spawn(async move { event_loop.run().await }); @@ -74,58 +141,37 @@ impl TestContext { pub async fn assert_alice_redeemed(&self, state: AliceState) { assert!(matches!(state, AliceState::BtcRedeemed)); - let btc_balance_after_swap = self - .alice_swap_factory - .bitcoin_wallet - .as_ref() - .balance() - .await - .unwrap(); + let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap(); assert_eq!( btc_balance_after_swap, - self.alice_swap_factory.starting_balances.btc + self.swap_amounts.btc + self.alice_starting_balances.btc + self.swap_amounts.btc - bitcoin::Amount::from_sat(bitcoin::TX_FEE) ); let xmr_balance_after_swap = self - .alice_swap_factory - .monero_wallet + .alice_monero_wallet .as_ref() .get_balance() .await .unwrap(); - assert!( - xmr_balance_after_swap - <= self.alice_swap_factory.starting_balances.xmr - self.swap_amounts.xmr - ); + assert!(xmr_balance_after_swap <= self.alice_starting_balances.xmr - self.swap_amounts.xmr); } pub async fn assert_alice_refunded(&self, state: AliceState) { assert!(matches!(state, AliceState::XmrRefunded)); - let btc_balance_after_swap = self - .alice_swap_factory - .bitcoin_wallet - .as_ref() - .balance() - .await - .unwrap(); - assert_eq!( - btc_balance_after_swap, - self.alice_swap_factory.starting_balances.btc - ); + let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap(); + assert_eq!(btc_balance_after_swap, self.alice_starting_balances.btc); // Ensure that Alice's balance is refreshed as we use a newly created wallet - self.alice_swap_factory - .monero_wallet + self.alice_monero_wallet .as_ref() .inner .refresh() .await .unwrap(); let xmr_balance_after_swap = self - .alice_swap_factory - .monero_wallet + .alice_monero_wallet .as_ref() .get_balance() .await @@ -136,30 +182,20 @@ impl TestContext { pub async fn assert_alice_punished(&self, state: AliceState) { assert!(matches!(state, AliceState::BtcPunished)); - let btc_balance_after_swap = self - .alice_swap_factory - .bitcoin_wallet - .as_ref() - .balance() - .await - .unwrap(); + let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap(); assert_eq!( btc_balance_after_swap, - self.alice_swap_factory.starting_balances.btc + self.swap_amounts.btc + self.alice_starting_balances.btc + self.swap_amounts.btc - bitcoin::Amount::from_sat(2 * bitcoin::TX_FEE) ); let xmr_balance_after_swap = self - .alice_swap_factory - .monero_wallet + .alice_monero_wallet .as_ref() .get_balance() .await .unwrap(); - assert!( - xmr_balance_after_swap - <= self.alice_swap_factory.starting_balances.xmr - self.swap_amounts.xmr - ); + assert!(xmr_balance_after_swap <= self.alice_starting_balances.xmr - self.swap_amounts.xmr); } pub async fn assert_bob_redeemed(&self, state: BobState) { @@ -170,44 +206,28 @@ impl TestContext { }; let lock_tx_bitcoin_fee = self - .bob_swap_factory - .bitcoin_wallet + .bob_bitcoin_wallet .transaction_fee(lock_tx_id) .await .unwrap(); - let btc_balance_after_swap = self - .bob_swap_factory - .bitcoin_wallet - .as_ref() - .balance() - .await - .unwrap(); + let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap(); assert_eq!( btc_balance_after_swap, - self.bob_swap_factory.starting_balances.btc - - self.swap_amounts.btc - - lock_tx_bitcoin_fee + self.bob_starting_balances.btc - self.swap_amounts.btc - lock_tx_bitcoin_fee ); // Ensure that Bob's balance is refreshed as we use a newly created wallet - self.bob_swap_factory - .monero_wallet + self.bob_monero_wallet .as_ref() .inner .refresh() .await .unwrap(); - let xmr_balance_after_swap = self - .bob_swap_factory - .monero_wallet - .as_ref() - .get_balance() - .await - .unwrap(); + let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap(); assert_eq!( xmr_balance_after_swap, - self.bob_swap_factory.starting_balances.xmr + self.swap_amounts.xmr + self.bob_starting_balances.xmr + self.swap_amounts.xmr ); } @@ -218,27 +238,20 @@ impl TestContext { panic!("Bob in unexpected state"); }; let lock_tx_bitcoin_fee = self - .bob_swap_factory - .bitcoin_wallet + .bob_bitcoin_wallet .transaction_fee(lock_tx_id) .await .unwrap(); - let btc_balance_after_swap = self - .bob_swap_factory - .bitcoin_wallet - .as_ref() - .balance() - .await - .unwrap(); + let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap(); let alice_submitted_cancel = btc_balance_after_swap - == self.bob_swap_factory.starting_balances.btc + == self.bob_starting_balances.btc - lock_tx_bitcoin_fee - bitcoin::Amount::from_sat(bitcoin::TX_FEE); let bob_submitted_cancel = btc_balance_after_swap - == self.bob_swap_factory.starting_balances.btc + == self.bob_starting_balances.btc - lock_tx_bitcoin_fee - bitcoin::Amount::from_sat(2 * bitcoin::TX_FEE); @@ -246,17 +259,8 @@ impl TestContext { // Since we cannot be sure who submitted it we have to assert accordingly assert!(alice_submitted_cancel || bob_submitted_cancel); - let xmr_balance_after_swap = self - .bob_swap_factory - .monero_wallet - .as_ref() - .get_balance() - .await - .unwrap(); - assert_eq!( - xmr_balance_after_swap, - self.bob_swap_factory.starting_balances.xmr - ); + let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap(); + assert_eq!(xmr_balance_after_swap, self.bob_starting_balances.xmr); } pub async fn assert_bob_punished(&self, state: BobState) { @@ -267,37 +271,19 @@ impl TestContext { }; let lock_tx_bitcoin_fee = self - .bob_swap_factory - .bitcoin_wallet + .bob_bitcoin_wallet .transaction_fee(lock_tx_id) .await .unwrap(); - let btc_balance_after_swap = self - .bob_swap_factory - .bitcoin_wallet - .as_ref() - .balance() - .await - .unwrap(); + let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap(); assert_eq!( btc_balance_after_swap, - self.bob_swap_factory.starting_balances.btc - - self.swap_amounts.btc - - lock_tx_bitcoin_fee + self.bob_starting_balances.btc - self.swap_amounts.btc - lock_tx_bitcoin_fee ); - let xmr_balance_after_swap = self - .bob_swap_factory - .monero_wallet - .as_ref() - .get_balance() - .await - .unwrap(); - assert_eq!( - xmr_balance_after_swap, - self.bob_swap_factory.starting_balances.xmr - ); + let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap(); + assert_eq!(xmr_balance_after_swap, self.bob_starting_balances.xmr); } } @@ -339,17 +325,15 @@ where ) .await; - let alice_swap_factory = alice::SwapFactory::new( - Seed::random().unwrap(), + let alice_params = AliceParams { + seed: Seed::random().unwrap(), config, - Uuid::new_v4(), - alice_bitcoin_wallet, - alice_monero_wallet, - alice_starting_balances, - tempdir().unwrap().path().to_path_buf(), + swap_id: Uuid::new_v4(), + bitcoin_wallet: alice_bitcoin_wallet.clone(), + monero_wallet: alice_monero_wallet.clone(), + db_path: tempdir().unwrap().path().to_path_buf(), listen_address, - ) - .await; + }; let bob_starting_balances = StartingBalances { xmr: monero::Amount::ZERO, @@ -365,22 +349,26 @@ where ) .await; - let bob_swap_factory = bob::SwapFactory::new( - Seed::random().unwrap(), - tempdir().unwrap().path().to_path_buf(), - Uuid::new_v4(), - bob_bitcoin_wallet, - bob_monero_wallet, - config, - bob_starting_balances, - alice_swap_factory.listen_address(), - alice_swap_factory.peer_id(), - ); + let bob_params = BobParams { + seed: Seed::random().unwrap(), + db_path: tempdir().unwrap().path().to_path_buf(), + swap_id: Uuid::new_v4(), + bitcoin_wallet: bob_bitcoin_wallet.clone(), + monero_wallet: bob_monero_wallet.clone(), + alice_address: alice_params.listen_address.clone(), + alice_peer_id: alice_params.peer_id().await, + }; let test = TestContext { swap_amounts, - alice_swap_factory, - bob_swap_factory, + alice_params, + alice_starting_balances, + alice_bitcoin_wallet, + alice_monero_wallet, + bob_params, + bob_starting_balances, + bob_bitcoin_wallet, + bob_monero_wallet, }; testfn(test).await