From 311ba74cd673fef893514eea7a4de4e7fcf4fff8 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 4 Feb 2021 16:33:13 +1100 Subject: [PATCH 01/20] Remove sell-xmr from CLI --- swap/src/cli.rs | 23 ------------------- swap/src/main.rs | 60 +----------------------------------------------- 2 files changed, 1 insertion(+), 82 deletions(-) diff --git a/swap/src/cli.rs b/swap/src/cli.rs index 16f80f2b..9a1d91a5 100644 --- a/swap/src/cli.rs +++ b/swap/src/cli.rs @@ -19,19 +19,6 @@ pub struct Options { #[derive(structopt::StructOpt, Debug)] #[structopt(name = "xmr_btc-swap", about = "XMR BTC atomic swap")] pub enum Command { - SellXmr { - #[structopt(long = "p2p-address", default_value = "/ip4/0.0.0.0/tcp/9876")] - listen_addr: Multiaddr, - - #[structopt(long = "send-xmr", help = "Monero amount as floating point nr without denomination (e.g. 125.1)", parse(try_from_str = parse_xmr))] - send_monero: monero::Amount, - - #[structopt(long = "receive-btc", help = "Bitcoin amount as floating point nr without denomination (e.g. 1.25)", parse(try_from_str = parse_btc))] - receive_bitcoin: bitcoin::Amount, - - #[structopt(flatten)] - config: Config, - }, BuyXmr { #[structopt(long = "connect-peer-id")] alice_peer_id: PeerId, @@ -56,16 +43,6 @@ pub enum Command { #[derive(structopt::StructOpt, Debug)] pub enum Resume { - SellXmr { - #[structopt(long = "swap-id")] - swap_id: Uuid, - - #[structopt(long = "listen-address", default_value = "/ip4/127.0.0.1/tcp/9876")] - listen_addr: Multiaddr, - - #[structopt(flatten)] - config: Config, - }, BuyXmr { #[structopt(long = "swap-id")] swap_id: Uuid, diff --git a/swap/src/main.rs b/swap/src/main.rs index bd7ec818..da6fd9fa 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -26,7 +26,7 @@ use database::Database; use fs::{default_config_path, default_data_dir}; use log::LevelFilter; use prettytable::{row, Table}; -use protocol::{alice, bob, bob::Builder, SwapAmounts}; +use protocol::{bob, bob::Builder, SwapAmounts}; use std::{path::PathBuf, sync::Arc}; use structopt::StructOpt; use trace::init_tracing; @@ -80,42 +80,6 @@ async fn main() -> Result<()> { let execution_params = execution_params::Testnet::get_execution_params(); match opt.cmd { - Command::SellXmr { - listen_addr, - send_monero, - receive_bitcoin, - config, - } => { - let swap_amounts = SwapAmounts { - xmr: send_monero, - btc: receive_bitcoin, - }; - - let (bitcoin_wallet, monero_wallet) = - init_wallets(config.path, bitcoin_network, monero_network).await?; - - let swap_id = Uuid::new_v4(); - - info!( - "Swap sending {} and receiving {} started with ID {}", - send_monero, receive_bitcoin, swap_id - ); - - let alice_factory = alice::Builder::new( - seed, - execution_params, - swap_id, - Arc::new(bitcoin_wallet), - Arc::new(monero_wallet), - db_path, - listen_addr, - ); - 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?; - } Command::BuyXmr { alice_peer_id, alice_addr, @@ -167,28 +131,6 @@ async fn main() -> Result<()> { // Print the table to stdout table.printstd(); } - Command::Resume(Resume::SellXmr { - swap_id, - listen_addr, - config, - }) => { - let (bitcoin_wallet, monero_wallet) = - init_wallets(config.path, bitcoin_network, monero_network).await?; - - let alice_factory = alice::Builder::new( - seed, - execution_params, - swap_id, - Arc::new(bitcoin_wallet), - Arc::new(monero_wallet), - db_path, - listen_addr, - ); - let (swap, mut event_loop) = alice_factory.build().await?; - - tokio::spawn(async move { event_loop.run().await }); - alice::run(swap).await?; - } Command::Resume(Resume::BuyXmr { swap_id, alice_peer_id, From 788445964a51cc7bcfbfd1c8faa4880d56030ad2 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 4 Feb 2021 16:42:14 +1100 Subject: [PATCH 02/20] Move main.rs to cli.rs to prepare for nectar binary --- swap/Cargo.toml | 6 +++++ swap/src/{main.rs => bin/cli.rs} | 45 ++++++++++++++------------------ swap/src/config.rs | 2 ++ swap/src/lib.rs | 3 +++ 4 files changed, 30 insertions(+), 26 deletions(-) rename swap/src/{main.rs => bin/cli.rs} (95%) diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 85609dcc..5cb515da 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -5,6 +5,12 @@ authors = ["CoBloX developers "] edition = "2018" description = "XMR/BTC trustless atomic swaps." +[[bin]] +name = "cli" + +[lib] +name = "swap" + [dependencies] anyhow = "1" async-recursion = "0.3.1" diff --git a/swap/src/main.rs b/swap/src/bin/cli.rs similarity index 95% rename from swap/src/main.rs rename to swap/src/bin/cli.rs index da6fd9fa..03176ae3 100644 --- a/swap/src/main.rs +++ b/swap/src/bin/cli.rs @@ -12,41 +12,34 @@ #![forbid(unsafe_code)] #![allow(non_snake_case)] -use crate::{ +use anyhow::{Context, Result}; +use log::LevelFilter; +use prettytable::{row, Table}; +use std::{path::PathBuf, sync::Arc}; +use structopt::StructOpt; +use swap::{ + bitcoin, cli::{Cancel, Command, Options, Refund, Resume}, + config, config::{ initial_setup, query_user_for_initial_testnet_config, read_config, ConfigNotInitialized, }, + database::Database, + execution_params, execution_params::GetExecutionParams, + fs::{default_config_path, default_data_dir}, + monero, monero::{CreateWallet, OpenWallet}, - protocol::bob::cancel::CancelError, + protocol::{ + bob, + bob::{cancel::CancelError, Builder}, + SwapAmounts, + }, + trace::init_tracing, }; -use anyhow::{Context, Result}; -use database::Database; -use fs::{default_config_path, default_data_dir}; -use log::LevelFilter; -use prettytable::{row, Table}; -use protocol::{bob, bob::Builder, SwapAmounts}; -use std::{path::PathBuf, sync::Arc}; -use structopt::StructOpt; -use trace::init_tracing; use tracing::{error, info, warn}; use uuid::Uuid; -pub mod bitcoin; -pub mod config; -pub mod database; -pub mod execution_params; -pub mod monero; -pub mod network; -pub mod protocol; -pub mod seed; -pub mod trace; - -mod cli; -mod fs; -mod serde_peer_id; - #[macro_use] extern crate prettytable; @@ -70,7 +63,7 @@ async fn main() -> Result<()> { ); let db_path = data_dir.join("database"); - let seed = config::seed::Seed::from_file_or_generate(&data_dir) + let seed = config::Seed::from_file_or_generate(&data_dir) .expect("Could not retrieve/initialize seed") .into(); diff --git a/swap/src/config.rs b/swap/src/config.rs index 11049581..f9f56431 100644 --- a/swap/src/config.rs +++ b/swap/src/config.rs @@ -13,6 +13,8 @@ use url::Url; pub mod seed; +pub use seed::Seed; + const DEFAULT_BITCOIND_TESTNET_URL: &str = "http://127.0.0.1:18332"; const DEFAULT_MONERO_WALLET_RPC_TESTNET_URL: &str = "http://127.0.0.1:38083/json_rpc"; diff --git a/swap/src/lib.rs b/swap/src/lib.rs index 72c81012..f042cddc 100644 --- a/swap/src/lib.rs +++ b/swap/src/lib.rs @@ -17,8 +17,11 @@ )] pub mod bitcoin; +pub mod cli; +pub mod config; pub mod database; pub mod execution_params; +pub mod fs; pub mod monero; pub mod network; pub mod protocol; From fd084b764da54bcf52b2f9891def898b921d5a29 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 4 Feb 2021 17:01:08 +1100 Subject: [PATCH 03/20] Move generation of keys inside `State0::new` The event loop will now use this function so I want to simplify its usage to avoid having to instantiate too many items to use it. --- swap/src/protocol/alice.rs | 18 ++++-------------- swap/src/protocol/alice/state.rs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index 9f741412..2bd30db8 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -175,30 +175,20 @@ impl Builder { 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 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.execution_params.bitcoin_cancel_timelock, self.execution_params.bitcoin_punish_timelock, - redeem_address, - punish_address, - rng, - ); + self.bitcoin_wallet.as_ref(), + &mut OsRng, + ) + .await?; Ok(AliceState::Started { amounts, state0 }) } diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index a6bbf21f..2e8b4dd5 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -101,25 +101,25 @@ pub struct State0 { } impl State0 { - #[allow(clippy::too_many_arguments)] - pub fn new( - a: bitcoin::SecretKey, - s_a: cross_curve_dleq::Scalar, - v_a: monero::PrivateViewKey, + pub async fn new( btc: bitcoin::Amount, xmr: monero::Amount, cancel_timelock: Timelock, punish_timelock: Timelock, - redeem_address: bitcoin::Address, - punish_address: bitcoin::Address, + bitcoin_wallet: &bitcoin::Wallet, rng: &mut R, - ) -> Self + ) -> Result where R: RngCore + CryptoRng, { + 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 = bitcoin_wallet.new_address().await?; + let punish_address = redeem_address.clone(); let dleq_proof_s_a = cross_curve_dleq::Proof::new(rng, &s_a); - Self { + Ok(Self { a, s_a, v_a, @@ -130,7 +130,7 @@ impl State0 { xmr, cancel_timelock, punish_timelock, - } + }) } pub fn receive(self, msg: Message0) -> Result { From 69363e43a3f8e9719ad784feda37b6eca2199d61 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 4 Feb 2021 17:10:18 +1100 Subject: [PATCH 04/20] Preemptively box encrypted signature to avoid size difference in enum --- swap/src/database/alice.rs | 4 ++-- swap/src/protocol/alice/state.rs | 2 +- swap/src/protocol/alice/swap.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/swap/src/database/alice.rs b/swap/src/database/alice.rs index 07e76501..42c7a2b3 100644 --- a/swap/src/database/alice.rs +++ b/swap/src/database/alice.rs @@ -76,7 +76,7 @@ impl From<&AliceState> for Alice { encrypted_signature, } => Alice::EncSigLearned { state3: state3.as_ref().clone(), - encrypted_signature: encrypted_signature.clone(), + encrypted_signature: *encrypted_signature.clone(), }, AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed), AliceState::BtcCancelled { state3, .. } => Alice::BtcCancelled(state3.as_ref().clone()), @@ -135,7 +135,7 @@ impl From for AliceState { encrypted_signature, } => AliceState::EncSigLearned { state3: Box::new(state), - encrypted_signature, + encrypted_signature: Box::new(encrypted_signature), }, Alice::CancelTimelockExpired(state3) => AliceState::CancelTimelockExpired { state3: Box::new(state3), diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index 2e8b4dd5..b1bc2f65 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -41,7 +41,7 @@ pub enum AliceState { state3: Box, }, EncSigLearned { - encrypted_signature: bitcoin::EncryptedSignature, + encrypted_signature: Box, state3: Box, }, BtcRedeemed, diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 97a542de..7edc91ea 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -202,7 +202,7 @@ async fn run_until_internal( Either::Left(_) => AliceState::CancelTimelockExpired { state3 }, Either::Right((enc_sig, _)) => AliceState::EncSigLearned { state3, - encrypted_signature: enc_sig?, + encrypted_signature: Box::new(enc_sig?), }, } } @@ -231,7 +231,7 @@ async fn run_until_internal( let state = match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? { ExpiredTimelocks::None => { match build_bitcoin_redeem_transaction( - encrypted_signature, + *encrypted_signature, &state3.tx_lock, state3.a.clone(), state3.s_a, From 39a46baa2c0b7d036d6d35b1f6aea565367bb16e Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 14:18:33 +1100 Subject: [PATCH 05/20] Preemptively box cancel tx to avoid size difference in enum --- swap/src/database/alice.rs | 2 +- swap/src/protocol/alice/state.rs | 2 +- swap/src/protocol/alice/swap.rs | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/swap/src/database/alice.rs b/swap/src/database/alice.rs index 42c7a2b3..9a9c4383 100644 --- a/swap/src/database/alice.rs +++ b/swap/src/database/alice.rs @@ -150,7 +150,7 @@ impl From for AliceState { AliceState::BtcCancelled { state3: Box::new(state), - tx_cancel, + tx_cancel: Box::new(tx_cancel), } } Alice::BtcPunishable(state3) => { diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index b1bc2f65..0ec03f05 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -46,7 +46,7 @@ pub enum AliceState { }, BtcRedeemed, BtcCancelled { - tx_cancel: TxCancel, + tx_cancel: Box, state3: Box, }, BtcRefunded { diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 7edc91ea..26e7c707 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -305,7 +305,10 @@ async fn run_until_internal( ) .await?; - let state = AliceState::BtcCancelled { state3, tx_cancel }; + let state = AliceState::BtcCancelled { + state3, + tx_cancel: Box::new(tx_cancel), + }; let db_state = (&state).into(); db.insert_latest_state(swap_id, database::Swap::Alice(db_state)) .await?; From f35ed436ce8eb7a6d638767f384330108a52dd45 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 14:21:54 +1100 Subject: [PATCH 06/20] Allow `EventLoop` to hold a database ready to pass to `alice::Buider` The `EventLoop` will use the `Builder` interface to instantiate a `Swap` upon receiving a `SwapRequest` and successfully doing an execution setup. Before this change, the `EventLoop` would have to hold the path to the db and re-open the db everytime it wants to construct a swap. With this change, we can open the DB once and then hold a `Arc` in the `EventLoop` and pass it to new `Swap`s structs. --- swap/src/protocol/alice.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index 2bd30db8..b35f167e 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -18,7 +18,7 @@ use libp2p::{ core::Multiaddr, identity::Keypair, request_response::ResponseChannel, NetworkBehaviour, PeerId, }; use rand::rngs::OsRng; -use std::{path::PathBuf, sync::Arc}; +use std::sync::Arc; use tracing::{debug, info}; use uuid::Uuid; @@ -56,7 +56,7 @@ pub struct Builder { swap_id: Uuid, identity: Keypair, peer_id: PeerId, - db_path: PathBuf, + db: Database, execution_params: ExecutionParams, listen_address: Multiaddr, @@ -79,7 +79,7 @@ impl Builder { swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, - db_path: PathBuf, + db: Database, listen_address: Multiaddr, ) -> Self { let network_seed = NetworkSeed::new(seed); @@ -90,7 +90,7 @@ impl Builder { swap_id, identity, peer_id, - db_path, + db, execution_params, listen_address, bitcoin_wallet, @@ -115,15 +115,13 @@ impl Builder { let (event_loop, event_loop_handle) = self.init_event_loop()?; - let db = Database::open(self.db_path.as_path())?; - Ok(( Swap { event_loop_handle, bitcoin_wallet: self.bitcoin_wallet, monero_wallet: self.monero_wallet, execution_params: self.execution_params, - db, + db: self.db, state: initial_state, swap_id: self.swap_id, }, @@ -131,11 +129,8 @@ impl Builder { )) } 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)? { + if let database::Swap::Alice(state) = self.db.get_state(self.swap_id)? { state.into() } else { bail!( @@ -154,7 +149,7 @@ impl Builder { monero_wallet: self.monero_wallet, execution_params: self.execution_params, swap_id: self.swap_id, - db, + db: self.db, }, event_loop, )) From 530b9b2ea86a3c05e65c198d29023eaf8966f945 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 14:39:27 +1100 Subject: [PATCH 07/20] Remove possible mix up of timelocks when using `State0::new` --- swap/src/protocol/alice.rs | 3 +-- swap/src/protocol/alice/state.rs | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index b35f167e..cf9b883b 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -178,8 +178,7 @@ impl Builder { let state0 = State0::new( amounts.btc, amounts.xmr, - self.execution_params.bitcoin_cancel_timelock, - self.execution_params.bitcoin_punish_timelock, + self.execution_params, self.bitcoin_wallet.as_ref(), &mut OsRng, ) diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index 0ec03f05..7127ba36 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -6,6 +6,7 @@ use crate::{ wait_for_cancel_timelock_to_expire, GetBlockHeight, TransactionBlockHeight, TxCancel, TxRefund, WatchForRawTransaction, }, + execution_params::ExecutionParams, monero, protocol::{ alice::{Message1, Message3, TransferProof}, @@ -104,8 +105,7 @@ impl State0 { pub async fn new( btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + execution_params: ExecutionParams, bitcoin_wallet: &bitcoin::Wallet, rng: &mut R, ) -> Result @@ -128,8 +128,8 @@ impl State0 { punish_address, btc, xmr, - cancel_timelock, - punish_timelock, + cancel_timelock: execution_params.bitcoin_cancel_timelock, + punish_timelock: execution_params.bitcoin_punish_timelock, }) } From 87be9aeb2a71aa625f1420524aff8d5c3039b164 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 14:49:36 +1100 Subject: [PATCH 08/20] Prepare separation of event loop initialisation to swap initialisation As for Alice, the event loop will be started with the program and will be the one starting swaps (`run_until`) based on libp2p events (swap request). --- swap/src/protocol/alice.rs | 18 ++++-------------- swap/src/protocol/alice/event_loop.rs | 8 +++++--- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index cf9b883b..c228b136 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -7,7 +7,6 @@ use crate::{ monero, network::{ peer_tracker::{self, PeerTracker}, - transport::build, Seed as NetworkSeed, }, protocol::{bob::EncryptedSignature, SwapAmounts}, @@ -113,7 +112,8 @@ impl Builder { .make_initial_state(swap_amounts.btc, swap_amounts.xmr) .await?; - let (event_loop, event_loop_handle) = self.init_event_loop()?; + let (event_loop, event_loop_handle) = + EventLoop::new(self.identity.clone(), self.listen_address(), self.peer_id)?; Ok(( Swap { @@ -139,7 +139,8 @@ impl Builder { ) }; - let (event_loop, event_loop_handle) = self.init_event_loop()?; + let (event_loop, event_loop_handle) = + EventLoop::new(self.identity.clone(), self.listen_address(), self.peer_id)?; Ok(( Swap { @@ -186,17 +187,6 @@ impl Builder { Ok(AliceState::Started { amounts, state0 }) } - - 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(), - self.peer_id, - ) - } } #[derive(Debug)] diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index b2b3873c..2cc0af2a 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -1,6 +1,6 @@ use crate::{ execution_params::ExecutionParams, - network::{transport::SwapTransport, TokioExecutor}, + network::{transport, TokioExecutor}, protocol::{ alice::{Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof}, bob::{EncryptedSignature, SwapRequest}, @@ -135,11 +135,13 @@ pub struct EventLoop { impl EventLoop { pub fn new( - transport: SwapTransport, - behaviour: Behaviour, + identity: libp2p::identity::Keypair, listen: Multiaddr, peer_id: PeerId, ) -> Result<(Self, EventLoopHandle)> { + let behaviour = Behaviour::default(); + let transport = transport::build(identity)?; + let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, peer_id) .executor(Box::new(TokioExecutor { handle: tokio::runtime::Handle::current(), From b5b990257add9b7f3e42515566414e60640a2f3d Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 15:14:22 +1100 Subject: [PATCH 09/20] Move `Behaviour` in dedicated module --- swap/src/protocol/alice.rs | 127 +------------------------- swap/src/protocol/alice/behaviour.rs | 124 +++++++++++++++++++++++++ swap/src/protocol/alice/event_loop.rs | 7 +- 3 files changed, 134 insertions(+), 124 deletions(-) create mode 100644 swap/src/protocol/alice/behaviour.rs diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index c228b136..e83329ff 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -1,24 +1,13 @@ //! Run an XMR/BTC swap in the role of Alice. //! Alice holds XMR and wishes receive BTC. use crate::{ - bitcoin, database, - database::Database, - execution_params::ExecutionParams, - monero, - network::{ - peer_tracker::{self, PeerTracker}, - Seed as NetworkSeed, - }, - protocol::{bob::EncryptedSignature, SwapAmounts}, - seed::Seed, -}; -use anyhow::{bail, Error, Result}; -use libp2p::{ - core::Multiaddr, identity::Keypair, request_response::ResponseChannel, NetworkBehaviour, PeerId, + bitcoin, database, database::Database, execution_params::ExecutionParams, monero, + network::Seed as NetworkSeed, protocol::SwapAmounts, seed::Seed, }; +use anyhow::{bail, Result}; +use libp2p::{core::Multiaddr, identity::Keypair, PeerId}; use rand::rngs::OsRng; use std::sync::Arc; -use tracing::{debug, info}; use uuid::Uuid; pub use self::{ @@ -29,9 +18,9 @@ pub use self::{ swap_response::*, transfer_proof::TransferProof, }; -use crate::protocol::bob::SwapRequest; pub use execution_setup::Message3; +mod behaviour; mod encrypted_signature; pub mod event_loop; mod execution_setup; @@ -188,109 +177,3 @@ impl Builder { Ok(AliceState::Started { amounts, state0 }) } } - -#[derive(Debug)] -pub enum OutEvent { - ConnectionEstablished(PeerId), - SwapRequest { - msg: SwapRequest, - channel: ResponseChannel, - }, - ExecutionSetupDone(Result>), - TransferProofAcknowledged, - EncryptedSignature { - msg: Box, - channel: ResponseChannel<()>, - }, - ResponseSent, // Same variant is used for all messages as no processing is done - Failure(Error), -} - -impl From for OutEvent { - fn from(event: peer_tracker::OutEvent) -> Self { - match event { - peer_tracker::OutEvent::ConnectionEstablished(id) => { - OutEvent::ConnectionEstablished(id) - } - } - } -} - -impl From for OutEvent { - fn from(event: swap_response::OutEvent) -> Self { - use swap_response::OutEvent::*; - match event { - MsgReceived { msg, channel } => OutEvent::SwapRequest { msg, channel }, - ResponseSent => OutEvent::ResponseSent, - Failure(err) => OutEvent::Failure(err.context("Swap Request/Response failure")), - } - } -} - -impl From for OutEvent { - fn from(event: execution_setup::OutEvent) -> Self { - match event { - execution_setup::OutEvent::Done(res) => OutEvent::ExecutionSetupDone(res.map(Box::new)), - } - } -} - -impl From for OutEvent { - fn from(event: transfer_proof::OutEvent) -> Self { - use transfer_proof::OutEvent::*; - match event { - Acknowledged => OutEvent::TransferProofAcknowledged, - Failure(err) => OutEvent::Failure(err.context("Failure with Transfer Proof")), - } - } -} - -impl From for OutEvent { - fn from(event: encrypted_signature::OutEvent) -> Self { - use encrypted_signature::OutEvent::*; - match event { - MsgReceived { msg, channel } => OutEvent::EncryptedSignature { - msg: Box::new(msg), - channel, - }, - AckSent => OutEvent::ResponseSent, - Failure(err) => OutEvent::Failure(err.context("Failure with Encrypted Signature")), - } - } -} - -/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Alice. -#[derive(NetworkBehaviour, Default)] -#[behaviour(out_event = "OutEvent", event_process = false)] -#[allow(missing_debug_implementations)] -pub struct Behaviour { - pt: PeerTracker, - amounts: swap_response::Behaviour, - execution_setup: execution_setup::Behaviour, - transfer_proof: transfer_proof::Behaviour, - encrypted_signature: encrypted_signature::Behaviour, -} - -impl Behaviour { - /// Alice always sends her messages as a response to a request from Bob. - pub fn send_swap_response( - &mut self, - channel: ResponseChannel, - swap_response: SwapResponse, - ) -> Result<()> { - self.amounts.send(channel, swap_response)?; - info!("Sent swap response"); - Ok(()) - } - - pub fn start_execution_setup(&mut self, bob_peer_id: PeerId, state0: State0) { - self.execution_setup.run(bob_peer_id, state0); - info!("Start execution setup with {}", bob_peer_id); - } - - /// Send Transfer Proof to Bob. - pub fn send_transfer_proof(&mut self, bob: PeerId, msg: TransferProof) { - self.transfer_proof.send(bob, msg); - debug!("Sent Transfer Proof"); - } -} diff --git a/swap/src/protocol/alice/behaviour.rs b/swap/src/protocol/alice/behaviour.rs new file mode 100644 index 00000000..891ad108 --- /dev/null +++ b/swap/src/protocol/alice/behaviour.rs @@ -0,0 +1,124 @@ +use crate::{ + network::{peer_tracker, peer_tracker::PeerTracker}, + protocol::{ + alice, + alice::{ + encrypted_signature, execution_setup, swap_response, transfer_proof, State0, State3, + SwapResponse, TransferProof, + }, + bob::{EncryptedSignature, SwapRequest}, + }, +}; +use anyhow::{Error, Result}; +use libp2p::{request_response::ResponseChannel, NetworkBehaviour, PeerId}; +use tracing::{debug, info}; + +#[derive(Debug)] +pub enum OutEvent { + ConnectionEstablished(PeerId), + SwapRequest { + msg: SwapRequest, + channel: ResponseChannel, + }, + ExecutionSetupDone(anyhow::Result>), + TransferProofAcknowledged, + EncryptedSignature { + msg: Box, + channel: ResponseChannel<()>, + }, + ResponseSent, // Same variant is used for all messages as no processing is done + Failure(Error), +} + +impl From for OutEvent { + fn from(event: peer_tracker::OutEvent) -> Self { + match event { + peer_tracker::OutEvent::ConnectionEstablished(id) => { + OutEvent::ConnectionEstablished(id) + } + } + } +} + +impl From for OutEvent { + fn from(event: alice::OutEvent) -> Self { + use crate::protocol::alice::OutEvent::*; + match event { + MsgReceived { msg, channel } => OutEvent::SwapRequest { msg, channel }, + ResponseSent => OutEvent::ResponseSent, + Failure(err) => OutEvent::Failure(err.context("Swap Request/Response failure")), + } + } +} + +impl From for OutEvent { + fn from(event: execution_setup::OutEvent) -> Self { + match event { + execution_setup::OutEvent::Done(res) => OutEvent::ExecutionSetupDone(res.map(Box::new)), + } + } +} + +impl From for OutEvent { + fn from(event: transfer_proof::OutEvent) -> Self { + use crate::protocol::alice::transfer_proof::OutEvent::*; + match event { + Acknowledged => OutEvent::TransferProofAcknowledged, + Failure(err) => OutEvent::Failure(err.context("Failure with Transfer Proof")), + } + } +} + +impl From for OutEvent { + fn from(event: encrypted_signature::OutEvent) -> Self { + use crate::protocol::alice::encrypted_signature::OutEvent::*; + match event { + MsgReceived { msg, channel } => OutEvent::EncryptedSignature { + msg: Box::new(msg), + channel, + }, + AckSent => OutEvent::ResponseSent, + Failure(err) => OutEvent::Failure(err.context("Failure with Encrypted Signature")), + } + } +} + +/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Alice. +#[derive(NetworkBehaviour, Default)] +#[behaviour(out_event = "OutEvent", event_process = false)] +#[allow(missing_debug_implementations)] +pub struct Behaviour { + pt: PeerTracker, + swap_response: swap_response::Behaviour, + execution_setup: execution_setup::Behaviour, + transfer_proof: transfer_proof::Behaviour, + encrypted_signature: encrypted_signature::Behaviour, +} + +impl Behaviour { + /// Alice always sends her messages as a response to a request from Bob. + pub fn send_swap_response( + &mut self, + channel: ResponseChannel, + swap_response: SwapResponse, + ) -> anyhow::Result<()> { + self.swap_response.send(channel, swap_response)?; + info!("Sent swap response"); + Ok(()) + } + + pub fn start_execution_setup(&mut self, bob_peer_id: PeerId, state0: State0) { + self.execution_setup.run(bob_peer_id, state0); + info!("Start execution setup with {}", bob_peer_id); + } + + /// Send Transfer Proof to Bob. + pub fn send_transfer_proof(&mut self, bob: PeerId, msg: TransferProof) { + self.transfer_proof.send(bob, msg); + debug!("Sent Transfer Proof"); + } + + pub fn send_encrypted_signature_ack(&mut self, channel: ResponseChannel<()>) -> Result<()> { + self.encrypted_signature.send_ack(channel) + } +} diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index 2cc0af2a..f1306cc1 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -2,7 +2,10 @@ use crate::{ execution_params::ExecutionParams, network::{transport, TokioExecutor}, protocol::{ - alice::{Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof}, + alice::{ + behaviour::{Behaviour, OutEvent}, + State0, State3, SwapResponse, TransferProof, + }, bob::{EncryptedSignature, SwapRequest}, }, }; @@ -207,7 +210,7 @@ impl EventLoop { OutEvent::EncryptedSignature{ msg, channel } => { let _ = self.recv_encrypted_signature.send(*msg).await; // Send back empty response so that the request/response protocol completes. - if let Err(error) = self.swarm.encrypted_signature.send_ack(channel) { + if let Err(error) = self.swarm.send_encrypted_signature_ack(channel) { error!("Failed to send Encrypted Signature ack: {:?}", error); } } From 60e0b9382c1ef7795fc3a146af335d265c8e88b2 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 15:24:32 +1100 Subject: [PATCH 10/20] Introduced from float API for Monero quantities --- Cargo.lock | 5 +++-- swap/Cargo.toml | 2 +- swap/src/monero.rs | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a3e61d6..8e218318 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2885,10 +2885,11 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.9.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5c739ba050709eae138f053356d27ff818d71fe54ce5a8d9f4c7a660bfb6684" +checksum = "e3e5a94e2006dd60c603d8481c65b665b4b6694f78d23e15869ad10eb883e36e" dependencies = [ + "arrayvec", "num-traits", "serde", ] diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 5cb515da..34bf5ecb 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -40,7 +40,7 @@ pem = "0.8" prettytable-rs = "0.8" rand = "0.7" reqwest = { version = "0.11", default-features = false } -rust_decimal = "1.8" +rust_decimal = "1.10" serde = { version = "1", features = ["derive"] } serde_cbor = "0.11" serde_derive = "1.0" diff --git a/swap/src/monero.rs b/swap/src/monero.rs index 9d7bdec9..bc40b4a0 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -15,6 +15,7 @@ use rust_decimal::{ }; use serde::{Deserialize, Serialize}; use std::{ + convert::TryFrom, fmt::Display, ops::{Add, Mul, Sub}, str::FromStr, @@ -88,13 +89,22 @@ impl Amount { self.0 } + pub fn from_monero(amount: f64) -> Result { + let decimal = Decimal::try_from(amount)?; + Self::from_decimal(decimal) + } + pub fn parse_monero(amount: &str) -> Result { let decimal = Decimal::from_str(amount)?; + Self::from_decimal(decimal) + } + + fn from_decimal(amount: Decimal) -> Result { let piconeros_dec = - decimal.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64")); + amount.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64")); let piconeros = piconeros_dec .to_u64() - .ok_or_else(|| OverflowError(amount.to_owned()))?; + .ok_or_else(|| OverflowError(amount.to_string()))?; Ok(Amount(piconeros)) } } From 4ade5df0e55d27e1e522815bd4774a6e89f32215 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 16:18:31 +1100 Subject: [PATCH 11/20] Remove unnecessary impl block --- swap/src/protocol/alice/event_loop.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index f1306cc1..bc435a24 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -25,16 +25,10 @@ pub struct Channels { receiver: Receiver, } -impl Channels { - pub fn new() -> Channels { - let (sender, receiver) = tokio::sync::mpsc::channel(100); - Channels { sender, receiver } - } -} - impl Default for Channels { fn default() -> Self { - Self::new() + let (sender, receiver) = tokio::sync::mpsc::channel(100); + Channels { sender, receiver } } } @@ -154,14 +148,14 @@ impl EventLoop { Swarm::listen_on(&mut swarm, listen.clone()) .with_context(|| format!("Address is not supported: {:#}", listen))?; - let start_execution_setup = Channels::new(); - let done_execution_setup = Channels::new(); - let recv_encrypted_signature = Channels::new(); - let request = Channels::new(); - let conn_established = Channels::new(); - let send_swap_response = Channels::new(); - let send_transfer_proof = Channels::new(); - let recv_transfer_proof_ack = Channels::new(); + let start_execution_setup = Channels::default(); + let done_execution_setup = Channels::default(); + let recv_encrypted_signature = Channels::default(); + let request = Channels::default(); + let conn_established = Channels::default(); + let send_swap_response = Channels::default(); + let send_transfer_proof = Channels::default(); + let recv_transfer_proof_ack = Channels::default(); let driver = EventLoop { swarm, From f5ca5faabf4933a552ddbbbbdf0c9cd6a0a1c324 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 16:38:23 +1100 Subject: [PATCH 12/20] Process execution setup failure similarly to other failures By merging it in the failure event of the root behaviour. --- swap/src/protocol/alice/behaviour.rs | 6 ++++-- swap/src/protocol/alice/event_loop.rs | 10 +++++----- swap/src/protocol/alice/execution_setup.rs | 11 ++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/swap/src/protocol/alice/behaviour.rs b/swap/src/protocol/alice/behaviour.rs index 891ad108..14e46000 100644 --- a/swap/src/protocol/alice/behaviour.rs +++ b/swap/src/protocol/alice/behaviour.rs @@ -20,7 +20,7 @@ pub enum OutEvent { msg: SwapRequest, channel: ResponseChannel, }, - ExecutionSetupDone(anyhow::Result>), + ExecutionSetupDone(Box), TransferProofAcknowledged, EncryptedSignature { msg: Box, @@ -53,8 +53,10 @@ impl From for OutEvent { impl From for OutEvent { fn from(event: execution_setup::OutEvent) -> Self { + use crate::protocol::alice::execution_setup::OutEvent::*; match event { - execution_setup::OutEvent::Done(res) => OutEvent::ExecutionSetupDone(res.map(Box::new)), + Done(state3) => OutEvent::ExecutionSetupDone(Box::new(state3)), + Failure(err) => OutEvent::Failure(err), } } } diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index bc435a24..32d4da44 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -34,7 +34,7 @@ impl Default for Channels { #[derive(Debug)] pub struct EventLoopHandle { - done_execution_setup: Receiver>, + done_execution_setup: Receiver, recv_encrypted_signature: Receiver, recv_swap_request: Receiver<(SwapRequest, ResponseChannel)>, conn_established: Receiver, @@ -61,7 +61,7 @@ impl EventLoopHandle { self.done_execution_setup .recv() .await - .ok_or_else(|| anyhow!("Failed to setup execution with Bob"))? + .ok_or_else(|| anyhow!("Failed to setup execution with Bob")) } pub async fn recv_encrypted_signature(&mut self) -> Result { @@ -121,7 +121,7 @@ impl EventLoopHandle { pub struct EventLoop { swarm: libp2p::Swarm, start_execution_setup: Receiver<(PeerId, State0)>, - done_execution_setup: Sender>, + done_execution_setup: Sender, recv_encrypted_signature: Sender, recv_swap_request: Sender<(SwapRequest, ResponseChannel)>, conn_established: Sender, @@ -194,8 +194,8 @@ impl EventLoop { OutEvent::SwapRequest { msg, channel } => { let _ = self.recv_swap_request.send((msg, channel)).await; } - OutEvent::ExecutionSetupDone(res) => { - let _ = self.done_execution_setup.send(res.map(|state|*state)).await; + OutEvent::ExecutionSetupDone(state3) => { + let _ = self.done_execution_setup.send(*state3).await; } OutEvent::TransferProofAcknowledged => { trace!("Bob acknowledged transfer proof"); diff --git a/swap/src/protocol/alice/execution_setup.rs b/swap/src/protocol/alice/execution_setup.rs index 967ba26f..e05964a2 100644 --- a/swap/src/protocol/alice/execution_setup.rs +++ b/swap/src/protocol/alice/execution_setup.rs @@ -8,7 +8,7 @@ use crate::{ bob::{Message0, Message2, Message4}, }, }; -use anyhow::{Context, Error, Result}; +use anyhow::{Context, Error}; use libp2p::PeerId; use libp2p_async_await::BehaviourOutEvent; use serde::{Deserialize, Serialize}; @@ -32,14 +32,15 @@ pub struct Message3 { #[derive(Debug)] pub enum OutEvent { - Done(Result), + Done(State3), + Failure(Error), } -impl From> for OutEvent { +impl From> for OutEvent { fn from(event: BehaviourOutEvent) -> Self { match event { - BehaviourOutEvent::Inbound(_, Ok(State3)) => OutEvent::Done(Ok(State3)), - BehaviourOutEvent::Inbound(_, Err(e)) => OutEvent::Done(Err(e)), + BehaviourOutEvent::Inbound(_, Ok(State3)) => OutEvent::Done(State3), + BehaviourOutEvent::Inbound(_, Err(e)) => OutEvent::Failure(e), BehaviourOutEvent::Outbound(..) => unreachable!("Alice only supports inbound"), } } From 1b2be804ed2dff09ea508dcf1a1384b8eb5e0edd Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 16:53:05 +1100 Subject: [PATCH 13/20] Remove unnecessary channels `alice::swap::run_until` will be called once the execution setup is done. The steps before are directly handled by the event loop, hence no channels are needed for said steps: connection established, swap request/response & execution setup. --- swap/src/protocol/alice/event_loop.rs | 99 ++++----------------------- swap/src/protocol/alice/steps.rs | 40 +---------- swap/src/protocol/alice/swap.rs | 20 ++---- 3 files changed, 22 insertions(+), 137 deletions(-) diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index 32d4da44..b9bc6998 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -4,7 +4,7 @@ use crate::{ protocol::{ alice::{ behaviour::{Behaviour, OutEvent}, - State0, State3, SwapResponse, TransferProof, + State3, SwapResponse, TransferProof, }, bob::{EncryptedSignature, SwapRequest}, }, @@ -17,7 +17,7 @@ use tokio::{ sync::mpsc::{Receiver, Sender}, time::timeout, }; -use tracing::{error, trace}; +use tracing::{debug, error, trace}; #[allow(missing_debug_implementations)] pub struct Channels { @@ -34,36 +34,12 @@ impl Default for Channels { #[derive(Debug)] pub struct EventLoopHandle { - done_execution_setup: Receiver, recv_encrypted_signature: Receiver, - recv_swap_request: Receiver<(SwapRequest, ResponseChannel)>, - conn_established: Receiver, - send_swap_response: Sender<(ResponseChannel, SwapResponse)>, - start_execution_setup: Sender<(PeerId, State0)>, send_transfer_proof: Sender<(PeerId, TransferProof)>, recv_transfer_proof_ack: Receiver<()>, } impl EventLoopHandle { - pub async fn recv_conn_established(&mut self) -> Result { - self.conn_established - .recv() - .await - .ok_or_else(|| anyhow!("Failed to receive connection established from Bob")) - } - - pub async fn execution_setup(&mut self, bob_peer_id: PeerId, state0: State0) -> Result { - let _ = self - .start_execution_setup - .send((bob_peer_id, state0)) - .await?; - - self.done_execution_setup - .recv() - .await - .ok_or_else(|| anyhow!("Failed to setup execution with Bob")) - } - pub async fn recv_encrypted_signature(&mut self) -> Result { self.recv_encrypted_signature .recv() @@ -71,27 +47,6 @@ impl EventLoopHandle { .ok_or_else(|| anyhow!("Failed to receive Bitcoin encrypted signature from Bob")) } - pub async fn recv_swap_request( - &mut self, - ) -> Result<(SwapRequest, ResponseChannel)> { - self.recv_swap_request - .recv() - .await - .ok_or_else(|| anyhow!("Failed to receive amounts request from Bob")) - } - - pub async fn send_swap_response( - &mut self, - channel: ResponseChannel, - swap_response: SwapResponse, - ) -> Result<()> { - let _ = self - .send_swap_response - .send((channel, swap_response)) - .await?; - Ok(()) - } - pub async fn send_transfer_proof( &mut self, bob: PeerId, @@ -120,12 +75,7 @@ impl EventLoopHandle { #[allow(missing_debug_implementations)] pub struct EventLoop { swarm: libp2p::Swarm, - start_execution_setup: Receiver<(PeerId, State0)>, - done_execution_setup: Sender, recv_encrypted_signature: Sender, - recv_swap_request: Sender<(SwapRequest, ResponseChannel)>, - conn_established: Sender, - send_swap_response: Receiver<(ResponseChannel, SwapResponse)>, send_transfer_proof: Receiver<(PeerId, TransferProof)>, recv_transfer_proof_ack: Sender<()>, } @@ -148,34 +98,19 @@ impl EventLoop { Swarm::listen_on(&mut swarm, listen.clone()) .with_context(|| format!("Address is not supported: {:#}", listen))?; - let start_execution_setup = Channels::default(); - let done_execution_setup = Channels::default(); let recv_encrypted_signature = Channels::default(); - let request = Channels::default(); - let conn_established = Channels::default(); - let send_swap_response = Channels::default(); let send_transfer_proof = Channels::default(); let recv_transfer_proof_ack = Channels::default(); let driver = EventLoop { swarm, - start_execution_setup: start_execution_setup.receiver, - done_execution_setup: done_execution_setup.sender, recv_encrypted_signature: recv_encrypted_signature.sender, - recv_swap_request: request.sender, - conn_established: conn_established.sender, - send_swap_response: send_swap_response.receiver, send_transfer_proof: send_transfer_proof.receiver, recv_transfer_proof_ack: recv_transfer_proof_ack.sender, }; let handle = EventLoopHandle { - start_execution_setup: start_execution_setup.sender, - done_execution_setup: done_execution_setup.receiver, recv_encrypted_signature: recv_encrypted_signature.receiver, - recv_swap_request: request.receiver, - conn_established: conn_established.receiver, - send_swap_response: send_swap_response.sender, send_transfer_proof: send_transfer_proof.sender, recv_transfer_proof_ack: recv_transfer_proof_ack.receiver, }; @@ -189,13 +124,13 @@ impl EventLoop { swarm_event = self.swarm.next().fuse() => { match swarm_event { OutEvent::ConnectionEstablished(alice) => { - let _ = self.conn_established.send(alice).await; + debug!("Connection Established with {}", alice); } OutEvent::SwapRequest { msg, channel } => { - let _ = self.recv_swap_request.send((msg, channel)).await; + let _ = self.handle_swap_request(msg, channel).await; } OutEvent::ExecutionSetupDone(state3) => { - let _ = self.done_execution_setup.send(*state3).await; + let _ = self.handle_execution_setup_done(*state3).await; } OutEvent::TransferProofAcknowledged => { trace!("Bob acknowledged transfer proof"); @@ -214,21 +149,6 @@ impl EventLoop { } } }, - swap_response = self.send_swap_response.recv().fuse() => { - if let Some((channel, swap_response)) = swap_response { - let _ = self - .swarm - .send_swap_response(channel, swap_response) - .map_err(|err|error!("Failed to send swap response: {:#}", err)); - } - }, - option = self.start_execution_setup.recv().fuse() => { - if let Some((bob_peer_id, state0)) = option { - let _ = self - .swarm - .start_execution_setup(bob_peer_id, state0); - } - }, transfer_proof = self.send_transfer_proof.recv().fuse() => { if let Some((bob_peer_id, msg)) = transfer_proof { self.swarm.send_transfer_proof(bob_peer_id, msg); @@ -237,4 +157,13 @@ impl EventLoop { } } } + + async fn handle_swap_request( + &self, + _msg: SwapRequest, + _channel: ResponseChannel, + ) { + } + + async fn handle_execution_setup_done(&self, _state3: State3) {} } diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index 8cff4b5e..f33b8acb 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -12,7 +12,7 @@ use crate::{ monero::Transfer, protocol::{ alice, - alice::{event_loop::EventLoopHandle, SwapResponse, TransferProof}, + alice::{event_loop::EventLoopHandle, TransferProof}, SwapAmounts, }, }; @@ -26,43 +26,7 @@ use libp2p::PeerId; use sha2::Sha256; use std::sync::Arc; use tokio::time::timeout; -use tracing::{info, trace}; - -pub async fn negotiate( - state0: alice::State0, - xmr_amount: monero::Amount, - event_loop_handle: &mut EventLoopHandle, - execution_params: ExecutionParams, -) -> Result<(PeerId, alice::State3)> { - trace!("Starting negotiate"); - - // todo: we can move this out, we dont need to timeout here - let bob_peer_id = timeout( - execution_params.bob_time_to_act, - event_loop_handle.recv_conn_established(), - ) - .await - .context("Failed to receive dial connection from Bob")??; - - let event = timeout( - execution_params.bob_time_to_act, - event_loop_handle.recv_swap_request(), - ) - .await - .context("Failed to receive swap request from Bob")??; - - event_loop_handle - .send_swap_response(event.1, SwapResponse { xmr_amount }) - .await?; - - let state3 = timeout( - execution_params.bob_time_to_act, - event_loop_handle.execution_setup(bob_peer_id, state0), - ) - .await??; - - Ok((bob_peer_id, state3)) -} +use tracing::info; // TODO(Franck): Use helper functions from xmr-btc instead of re-writing them // here diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 26e7c707..7bc2fdac 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -17,10 +17,10 @@ use crate::{ event_loop::EventLoopHandle, steps::{ build_bitcoin_punish_transaction, build_bitcoin_redeem_transaction, - extract_monero_private_key, lock_xmr, negotiate, - publish_bitcoin_punish_transaction, publish_bitcoin_redeem_transaction, - publish_cancel_transaction, wait_for_bitcoin_encrypted_signature, - wait_for_bitcoin_refund, wait_for_locked_bitcoin, + extract_monero_private_key, lock_xmr, publish_bitcoin_punish_transaction, + publish_bitcoin_redeem_transaction, publish_cancel_transaction, + wait_for_bitcoin_encrypted_signature, wait_for_bitcoin_refund, + wait_for_locked_bitcoin, }, AliceState, }, @@ -92,18 +92,10 @@ async fn run_until_internal( } else { match state { AliceState::Started { amounts, state0 } => { - let (bob_peer_id, state3) = negotiate( - state0, - amounts.xmr, - &mut event_loop_handle, - execution_params, - ) - .await?; - let state = AliceState::Negotiated { - bob_peer_id, + bob_peer_id: todo!(), amounts, - state3: Box::new(state3), + state3: todo!(), }; let db_state = (&state).into(); From cc8b8551177499cf8c34812c0a39258c9d00687c Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 17:03:16 +1100 Subject: [PATCH 14/20] Make it possible to clone a handle This will be used for new swaps. --- swap/src/protocol/alice/event_loop.rs | 78 +++++++++++++++++++-------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index b9bc6998..42d717d2 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -9,34 +9,53 @@ use crate::{ bob::{EncryptedSignature, SwapRequest}, }, }; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result}; use libp2p::{ core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm, }; use tokio::{ - sync::mpsc::{Receiver, Sender}, + sync::{broadcast, mpsc}, time::timeout, }; use tracing::{debug, error, trace}; #[allow(missing_debug_implementations)] -pub struct Channels { - sender: Sender, - receiver: Receiver, +pub struct MpscChannels { + sender: mpsc::Sender, + receiver: mpsc::Receiver, } -impl Default for Channels { +impl Default for MpscChannels { fn default() -> Self { - let (sender, receiver) = tokio::sync::mpsc::channel(100); - Channels { sender, receiver } + let (sender, receiver) = mpsc::channel(100); + MpscChannels { sender, receiver } + } +} + +#[allow(missing_debug_implementations)] +pub struct BroadcastChannels +where + T: Clone, +{ + sender: broadcast::Sender, + receiver: broadcast::Receiver, +} + +impl Default for BroadcastChannels +where + T: Clone, +{ + fn default() -> Self { + let (sender, receiver) = broadcast::channel(100); + BroadcastChannels { sender, receiver } } } #[derive(Debug)] pub struct EventLoopHandle { - recv_encrypted_signature: Receiver, - send_transfer_proof: Sender<(PeerId, TransferProof)>, - recv_transfer_proof_ack: Receiver<()>, + recv_encrypted_signature: broadcast::Receiver, + send_transfer_proof: mpsc::Sender<(PeerId, TransferProof)>, + recv_transfer_proof_ack: broadcast::Receiver<()>, } impl EventLoopHandle { @@ -44,9 +63,8 @@ impl EventLoopHandle { self.recv_encrypted_signature .recv() .await - .ok_or_else(|| anyhow!("Failed to receive Bitcoin encrypted signature from Bob")) + .context("Failed to receive Bitcoin encrypted signature from Bob") } - pub async fn send_transfer_proof( &mut self, bob: PeerId, @@ -75,9 +93,12 @@ impl EventLoopHandle { #[allow(missing_debug_implementations)] pub struct EventLoop { swarm: libp2p::Swarm, - recv_encrypted_signature: Sender, - send_transfer_proof: Receiver<(PeerId, TransferProof)>, - recv_transfer_proof_ack: Sender<()>, + recv_encrypted_signature: broadcast::Sender, + send_transfer_proof: mpsc::Receiver<(PeerId, TransferProof)>, + recv_transfer_proof_ack: broadcast::Sender<()>, + + // Only used to clone further handles + handle: EventLoopHandle, } impl EventLoop { @@ -98,15 +119,22 @@ impl EventLoop { Swarm::listen_on(&mut swarm, listen.clone()) .with_context(|| format!("Address is not supported: {:#}", listen))?; - let recv_encrypted_signature = Channels::default(); - let send_transfer_proof = Channels::default(); - let recv_transfer_proof_ack = Channels::default(); + let recv_encrypted_signature = BroadcastChannels::default(); + let send_transfer_proof = MpscChannels::default(); + let recv_transfer_proof_ack = BroadcastChannels::default(); + + let handle_clone = EventLoopHandle { + recv_encrypted_signature: recv_encrypted_signature.sender.subscribe(), + send_transfer_proof: send_transfer_proof.sender.clone(), + recv_transfer_proof_ack: recv_transfer_proof_ack.sender.subscribe(), + }; let driver = EventLoop { swarm, recv_encrypted_signature: recv_encrypted_signature.sender, send_transfer_proof: send_transfer_proof.receiver, recv_transfer_proof_ack: recv_transfer_proof_ack.sender, + handle: handle_clone, }; let handle = EventLoopHandle { @@ -118,6 +146,14 @@ impl EventLoop { Ok((driver, handle)) } + pub fn clone_handle(&self) -> EventLoopHandle { + EventLoopHandle { + recv_encrypted_signature: self.recv_encrypted_signature.subscribe(), + send_transfer_proof: self.handle.send_transfer_proof.clone(), + recv_transfer_proof_ack: self.recv_transfer_proof_ack.subscribe(), + } + } + pub async fn run(&mut self) { loop { tokio::select! { @@ -134,10 +170,10 @@ impl EventLoop { } OutEvent::TransferProofAcknowledged => { trace!("Bob acknowledged transfer proof"); - let _ = self.recv_transfer_proof_ack.send(()).await; + let _ = self.recv_transfer_proof_ack.send(()); } OutEvent::EncryptedSignature{ msg, channel } => { - let _ = self.recv_encrypted_signature.send(*msg).await; + let _ = self.recv_encrypted_signature.send(*msg); // Send back empty response so that the request/response protocol completes. if let Err(error) = self.swarm.send_encrypted_signature_ack(channel) { error!("Failed to send Encrypted Signature ack: {:?}", error); From bfc19d56280ff56d4d98e7f55b3014c00aea73e2 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Mon, 8 Feb 2021 17:35:12 +1100 Subject: [PATCH 15/20] Remove acknowledgements processing We are aware of issues of timeouts when waiting for acknowledgements. Also, to properly supports acks in a multiple swap context, we need to revert to doing event processing on the behaviour so that we can link leverage the `RequestResponse` libp2p behaviour and link the messages requests ids to swap ids when receiving an ack or response. Acks are usefully for specific scenarios where we queue a message on the behaviour to be sent, save as sent in the DB but crash before the message is actually sent. With acks we are able to resume the swap, without ack, the swap will abort (refund). --- swap/src/protocol/alice/event_loop.rs | 34 ++------------------------- swap/src/protocol/alice/steps.rs | 11 +++------ swap/src/protocol/alice/swap.rs | 1 - swap/src/protocol/bob/event_loop.rs | 10 -------- 4 files changed, 5 insertions(+), 51 deletions(-) diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index 42d717d2..bcc4dc32 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -1,5 +1,4 @@ use crate::{ - execution_params::ExecutionParams, network::{transport, TokioExecutor}, protocol::{ alice::{ @@ -13,10 +12,7 @@ use anyhow::{Context, Result}; use libp2p::{ core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm, }; -use tokio::{ - sync::{broadcast, mpsc}, - time::timeout, -}; +use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error, trace}; #[allow(missing_debug_implementations)] @@ -55,7 +51,6 @@ where pub struct EventLoopHandle { recv_encrypted_signature: broadcast::Receiver, send_transfer_proof: mpsc::Sender<(PeerId, TransferProof)>, - recv_transfer_proof_ack: broadcast::Receiver<()>, } impl EventLoopHandle { @@ -65,27 +60,9 @@ impl EventLoopHandle { .await .context("Failed to receive Bitcoin encrypted signature from Bob") } - pub async fn send_transfer_proof( - &mut self, - bob: PeerId, - msg: TransferProof, - execution_params: ExecutionParams, - ) -> Result<()> { + pub async fn send_transfer_proof(&mut self, bob: PeerId, msg: TransferProof) -> Result<()> { let _ = self.send_transfer_proof.send((bob, msg)).await?; - // TODO: Re-evaluate if these acknowledges are necessary at all. - // If we don't use a timeout here and Alice fails to dial Bob she will wait - // indefinitely for this acknowledge. - if timeout( - execution_params.bob_time_to_act, - self.recv_transfer_proof_ack.recv(), - ) - .await - .is_err() - { - error!("Failed to receive transfer proof ack from Bob") - } - Ok(()) } } @@ -95,7 +72,6 @@ pub struct EventLoop { swarm: libp2p::Swarm, recv_encrypted_signature: broadcast::Sender, send_transfer_proof: mpsc::Receiver<(PeerId, TransferProof)>, - recv_transfer_proof_ack: broadcast::Sender<()>, // Only used to clone further handles handle: EventLoopHandle, @@ -121,26 +97,22 @@ impl EventLoop { let recv_encrypted_signature = BroadcastChannels::default(); let send_transfer_proof = MpscChannels::default(); - let recv_transfer_proof_ack = BroadcastChannels::default(); let handle_clone = EventLoopHandle { recv_encrypted_signature: recv_encrypted_signature.sender.subscribe(), send_transfer_proof: send_transfer_proof.sender.clone(), - recv_transfer_proof_ack: recv_transfer_proof_ack.sender.subscribe(), }; let driver = EventLoop { swarm, recv_encrypted_signature: recv_encrypted_signature.sender, send_transfer_proof: send_transfer_proof.receiver, - recv_transfer_proof_ack: recv_transfer_proof_ack.sender, handle: handle_clone, }; let handle = EventLoopHandle { recv_encrypted_signature: recv_encrypted_signature.receiver, send_transfer_proof: send_transfer_proof.sender, - recv_transfer_proof_ack: recv_transfer_proof_ack.receiver, }; Ok((driver, handle)) @@ -150,7 +122,6 @@ impl EventLoop { EventLoopHandle { recv_encrypted_signature: self.recv_encrypted_signature.subscribe(), send_transfer_proof: self.handle.send_transfer_proof.clone(), - recv_transfer_proof_ack: self.recv_transfer_proof_ack.subscribe(), } } @@ -170,7 +141,6 @@ impl EventLoop { } OutEvent::TransferProofAcknowledged => { trace!("Bob acknowledged transfer proof"); - let _ = self.recv_transfer_proof_ack.send(()); } OutEvent::EncryptedSignature{ msg, channel } => { let _ = self.recv_encrypted_signature.send(*msg); diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index f33b8acb..2e437339 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -60,7 +60,6 @@ pub async fn lock_xmr( state3: alice::State3, event_loop_handle: &mut EventLoopHandle, monero_wallet: Arc, - execution_params: ExecutionParams, ) -> Result<()> where W: Transfer, @@ -82,13 +81,9 @@ where // Otherwise Alice might publish the lock tx twice! event_loop_handle - .send_transfer_proof( - bob_peer_id, - TransferProof { - tx_lock_proof: transfer_proof, - }, - execution_params, - ) + .send_transfer_proof(bob_peer_id, TransferProof { + tx_lock_proof: transfer_proof, + }) .await?; Ok(()) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 7bc2fdac..d01df0c4 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -157,7 +157,6 @@ async fn run_until_internal( *state3.clone(), &mut event_loop_handle, monero_wallet.clone(), - execution_params, ) .await?; diff --git a/swap/src/protocol/bob/event_loop.rs b/swap/src/protocol/bob/event_loop.rs index 4d8229d6..821d1f67 100644 --- a/swap/src/protocol/bob/event_loop.rs +++ b/swap/src/protocol/bob/event_loop.rs @@ -43,7 +43,6 @@ pub struct EventLoopHandle { dial_alice: Sender<()>, send_swap_request: Sender, send_encrypted_signature: Sender, - recv_encrypted_signature_ack: Receiver<()>, } impl EventLoopHandle { @@ -95,10 +94,6 @@ impl EventLoopHandle { ) -> Result<()> { self.send_encrypted_signature.send(tx_redeem_encsig).await?; - self.recv_encrypted_signature_ack - .recv() - .await - .ok_or_else(|| anyhow!("Failed to receive encrypted signature ack from Alice"))?; Ok(()) } } @@ -116,7 +111,6 @@ pub struct EventLoop { conn_established: Sender, send_swap_request: Receiver, send_encrypted_signature: Receiver, - recv_encrypted_signature_ack: Sender<()>, } impl EventLoop { @@ -144,7 +138,6 @@ impl EventLoop { let conn_established = Channels::new(); let send_swap_request = Channels::new(); let send_encrypted_signature = Channels::new(); - let recv_encrypted_signature_ack = Channels::new(); let event_loop = EventLoop { swarm, @@ -158,7 +151,6 @@ impl EventLoop { dial_alice: dial_alice.receiver, send_swap_request: send_swap_request.receiver, send_encrypted_signature: send_encrypted_signature.receiver, - recv_encrypted_signature_ack: recv_encrypted_signature_ack.sender, }; let handle = EventLoopHandle { @@ -170,7 +162,6 @@ impl EventLoop { dial_alice: dial_alice.sender, send_swap_request: send_swap_request.sender, send_encrypted_signature: send_encrypted_signature.sender, - recv_encrypted_signature_ack: recv_encrypted_signature_ack.receiver, }; Ok((event_loop, handle)) @@ -199,7 +190,6 @@ impl EventLoop { } OutEvent::EncryptedSignatureAcknowledged => { debug!("Alice acknowledged encrypted signature"); - let _ = self.recv_encrypted_signature_ack.send(()).await; } OutEvent::ResponseSent => {} OutEvent::Failure(err) => { From fd9f633a7736ae0adee816b209a3d4c47636b6e8 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Wed, 10 Feb 2021 09:40:16 +1100 Subject: [PATCH 16/20] Remove Alice restarts tests Current focus is on CLI UX. Fair amount of change needs to happen to cater for Alice (nectar) restart scenarios. --- .github/workflows/ci.yml | 3 -- bors.toml | 3 -- swap/tests/happy_path_restart_alice.rs | 31 ------------- swap/tests/refund_restart_alice.rs | 33 -------------- swap/tests/refund_restart_alice_cancelled.rs | 47 -------------------- 5 files changed, 117 deletions(-) delete mode 100644 swap/tests/happy_path_restart_alice.rs delete mode 100644 swap/tests/refund_restart_alice.rs delete mode 100644 swap/tests/refund_restart_alice_cancelled.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a46ef1f9..1c4aecb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,13 +127,10 @@ jobs: matrix: test_name: [ happy_path, - happy_path_restart_alice, happy_path_restart_bob_after_comm, happy_path_restart_bob_after_lock_proof_received, happy_path_restart_bob_before_comm, punish, - refund_restart_alice_cancelled, - refund_restart_alice, bob_refunds_using_cancel_and_refund_command, bob_refunds_using_cancel_and_refund_command_timelock_not_exired, bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force, diff --git a/bors.toml b/bors.toml index 8b82cb8c..929e07ea 100644 --- a/bors.toml +++ b/bors.toml @@ -3,11 +3,8 @@ status = [ "build_test (x86_64-unknown-linux-gnu)", "build_test (x86_64-apple-darwin)", "docker_tests (happy_path)", - "docker_tests (happy_path_restart_alice)", "docker_tests (happy_path_restart_bob_after_comm)", "docker_tests (happy_path_restart_bob_after_lock_proof_received)", "docker_tests (happy_path_restart_bob_before_comm)", "docker_tests (punish)", - "docker_tests (refund_restart_alice_cancelled)", - "docker_tests (refund_restart_alice)", ] diff --git a/swap/tests/happy_path_restart_alice.rs b/swap/tests/happy_path_restart_alice.rs deleted file mode 100644 index fbf2515c..00000000 --- a/swap/tests/happy_path_restart_alice.rs +++ /dev/null @@ -1,31 +0,0 @@ -pub mod testutils; - -use swap::protocol::{alice, alice::AliceState, bob}; -use testutils::{alice_run_until::is_encsig_learned, SlowCancelConfig}; - -#[tokio::test] -async fn given_alice_restarts_after_encsig_is_learned_resume_swap() { - testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, alice_join_handle) = ctx.new_swap_as_alice().await; - let (bob_swap, _) = ctx.new_swap_as_bob().await; - - let bob = bob::run(bob_swap); - let bob_handle = tokio::spawn(bob); - - let alice_state = alice::run_until(alice_swap, is_encsig_learned) - .await - .unwrap(); - assert!(matches!(alice_state, AliceState::EncSigLearned { .. })); - - let alice_swap = ctx.stop_and_resume_alice_from_db(alice_join_handle).await; - assert!(matches!(alice_swap.state, AliceState::EncSigLearned { .. })); - - let alice_state = alice::run(alice_swap).await.unwrap(); - - ctx.assert_alice_redeemed(alice_state).await; - - let bob_state = bob_handle.await.unwrap(); - ctx.assert_bob_redeemed(bob_state.unwrap()).await - }) - .await; -} diff --git a/swap/tests/refund_restart_alice.rs b/swap/tests/refund_restart_alice.rs deleted file mode 100644 index 5af2c7a0..00000000 --- a/swap/tests/refund_restart_alice.rs +++ /dev/null @@ -1,33 +0,0 @@ -pub mod testutils; - -use swap::protocol::{alice, alice::AliceState, bob}; -use testutils::{alice_run_until::is_xmr_locked, FastCancelConfig}; - -/// Bob locks btc and Alice locks xmr. Alice fails to act so Bob refunds. Alice -/// then also refunds. -#[tokio::test] -async fn given_alice_restarts_after_xmr_is_locked_refund_swap() { - testutils::setup_test(FastCancelConfig, |mut ctx| async move { - let (alice_swap, alice_join_handle) = ctx.new_swap_as_alice().await; - let (bob_swap, _) = ctx.new_swap_as_bob().await; - - let bob = bob::run(bob_swap); - let bob_handle = tokio::spawn(bob); - - let alice_state = alice::run_until(alice_swap, is_xmr_locked).await.unwrap(); - assert!(matches!(alice_state, AliceState::XmrLocked { .. })); - - // Alice does not act, Bob refunds - let bob_state = bob_handle.await.unwrap(); - ctx.assert_bob_refunded(bob_state.unwrap()).await; - - // Once bob has finished Alice is restarted and refunds as well - let alice_swap = ctx.stop_and_resume_alice_from_db(alice_join_handle).await; - assert!(matches!(alice_swap.state, AliceState::XmrLocked { .. })); - - let alice_state = alice::run(alice_swap).await.unwrap(); - - ctx.assert_alice_refunded(alice_state).await; - }) - .await; -} diff --git a/swap/tests/refund_restart_alice_cancelled.rs b/swap/tests/refund_restart_alice_cancelled.rs deleted file mode 100644 index 129887a1..00000000 --- a/swap/tests/refund_restart_alice_cancelled.rs +++ /dev/null @@ -1,47 +0,0 @@ -pub mod testutils; - -use swap::{ - execution_params, - protocol::{alice, alice::AliceState, bob}, -}; -use testutils::alice_run_until::is_encsig_learned; - -/// Bob locks btc and Alice locks xmr. Alice fails to act so Bob refunds. Alice -/// is forced to refund even though she learned the secret and would be able to -/// redeem had the timelock not expired. -#[tokio::test] -async fn given_alice_restarts_after_enc_sig_learned_and_bob_already_cancelled_refund_swap() { - testutils::setup_test(execution_params::Regtest, |mut ctx| async move { - let (alice_swap, alice_join_handle) = ctx.new_swap_as_alice().await; - let (bob_swap, _) = ctx.new_swap_as_bob().await; - - let bob = bob::run(bob_swap); - let bob_handle = tokio::spawn(bob); - - let alice_state = alice::run_until(alice_swap, is_encsig_learned) - .await - .unwrap(); - assert!( - matches!(alice_state, AliceState::EncSigLearned { .. }), - "Alice state is not EncSigLearned: {:?}", - alice_state - ); - - // Wait for Bob to refund, because Alice does not act - let bob_state = bob_handle.await.unwrap(); - ctx.assert_bob_refunded(bob_state.unwrap()).await; - - // Once bob has finished Alice is restarted and refunds as well - let alice_swap = ctx.stop_and_resume_alice_from_db(alice_join_handle).await; - assert!( - matches!(alice_swap.state, AliceState::EncSigLearned { .. }), - "Alice state is not EncSigLearned: {:?}", - alice_state - ); - - let alice_state = alice::run(alice_swap).await.unwrap(); - - ctx.assert_alice_refunded(alice_state).await; - }) - .await; -} From 3bc8b58b6a2e08e5f5ab65ed92e9dfa25a46203b Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Wed, 10 Feb 2021 10:30:23 +1100 Subject: [PATCH 17/20] Remove Bob restart tests after communication The test do not work without acks as we stop the event loop as soon as a message is considered as "sent" when actually the event loop and swarm may not have yet sent the message. The ack allow to avoid this issue as the message was considered "sent" only once the other party sent a response. However, the ack brings other issue so a review needs to be done to select the appropriate solution. --- .github/workflows/ci.yml | 2 -- bors.toml | 2 -- .../happy_path_restart_bob_after_comm.rs | 30 ---------------- ...h_restart_bob_after_lock_proof_received.rs | 35 ------------------- 4 files changed, 69 deletions(-) delete mode 100644 swap/tests/happy_path_restart_bob_after_comm.rs delete mode 100644 swap/tests/happy_path_restart_bob_after_lock_proof_received.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c4aecb4..36a6d411 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,8 +127,6 @@ jobs: matrix: test_name: [ happy_path, - happy_path_restart_bob_after_comm, - happy_path_restart_bob_after_lock_proof_received, happy_path_restart_bob_before_comm, punish, bob_refunds_using_cancel_and_refund_command, diff --git a/bors.toml b/bors.toml index 929e07ea..b36ba899 100644 --- a/bors.toml +++ b/bors.toml @@ -3,8 +3,6 @@ status = [ "build_test (x86_64-unknown-linux-gnu)", "build_test (x86_64-apple-darwin)", "docker_tests (happy_path)", - "docker_tests (happy_path_restart_bob_after_comm)", - "docker_tests (happy_path_restart_bob_after_lock_proof_received)", "docker_tests (happy_path_restart_bob_before_comm)", "docker_tests (punish)", ] diff --git a/swap/tests/happy_path_restart_bob_after_comm.rs b/swap/tests/happy_path_restart_bob_after_comm.rs deleted file mode 100644 index 6cd08c64..00000000 --- a/swap/tests/happy_path_restart_bob_after_comm.rs +++ /dev/null @@ -1,30 +0,0 @@ -pub mod testutils; - -use swap::protocol::{alice, bob, bob::BobState}; -use testutils::{bob_run_until::is_encsig_sent, SlowCancelConfig}; - -#[tokio::test] -async fn given_bob_restarts_after_encsig_is_sent_resume_swap() { - testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; - let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - - let alice = alice::run(alice_swap); - let alice_handle = tokio::spawn(alice); - - let bob_state = bob::run_until(bob_swap, is_encsig_sent).await.unwrap(); - - assert!(matches!(bob_state, BobState::EncSigSent { .. })); - - let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; - assert!(matches!(bob_swap.state, BobState::EncSigSent { .. })); - - let bob_state = bob::run(bob_swap).await.unwrap(); - - ctx.assert_bob_redeemed(bob_state).await; - - let alice_state = alice_handle.await.unwrap(); - ctx.assert_alice_redeemed(alice_state.unwrap()).await; - }) - .await; -} diff --git a/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs b/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs deleted file mode 100644 index d335acc9..00000000 --- a/swap/tests/happy_path_restart_bob_after_lock_proof_received.rs +++ /dev/null @@ -1,35 +0,0 @@ -pub mod testutils; - -use swap::protocol::{alice, bob, bob::BobState}; -use testutils::{bob_run_until::is_lock_proof_received, SlowCancelConfig}; - -#[tokio::test] -async fn given_bob_restarts_after_lock_proof_received_resume_swap() { - testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; - let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - - let alice_handle = alice::run(alice_swap); - let alice_swap_handle = tokio::spawn(alice_handle); - - let bob_state = bob::run_until(bob_swap, is_lock_proof_received) - .await - .unwrap(); - - assert!(matches!(bob_state, BobState::XmrLockProofReceived { .. })); - - let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; - assert!(matches!( - bob_swap.state, - BobState::XmrLockProofReceived { .. } - )); - - let bob_state = bob::run(bob_swap).await.unwrap(); - - ctx.assert_bob_redeemed(bob_state).await; - - let alice_state = alice_swap_handle.await.unwrap().unwrap(); - ctx.assert_alice_redeemed(alice_state).await; - }) - .await; -} From 15eb9a2fe411c8efa838d9e4b97c0772f324821a Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Wed, 10 Feb 2021 10:43:57 +1100 Subject: [PATCH 18/20] Remove punish test The punish test needs re-work due to the fact that Alice runs continuously Currently focusing on the CLI (Bob), so we can re-introduce this test once we want to ensure that nectar (Alice) punishes. --- .github/workflows/ci.yml | 1 - bors.toml | 1 - swap/tests/punish.rs | 34 ---------------------------------- 3 files changed, 36 deletions(-) delete mode 100644 swap/tests/punish.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36a6d411..630199c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,7 +128,6 @@ jobs: test_name: [ happy_path, happy_path_restart_bob_before_comm, - punish, bob_refunds_using_cancel_and_refund_command, bob_refunds_using_cancel_and_refund_command_timelock_not_exired, bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force, diff --git a/bors.toml b/bors.toml index b36ba899..27bf2b72 100644 --- a/bors.toml +++ b/bors.toml @@ -4,5 +4,4 @@ status = [ "build_test (x86_64-apple-darwin)", "docker_tests (happy_path)", "docker_tests (happy_path_restart_bob_before_comm)", - "docker_tests (punish)", ] diff --git a/swap/tests/punish.rs b/swap/tests/punish.rs deleted file mode 100644 index ea29a95a..00000000 --- a/swap/tests/punish.rs +++ /dev/null @@ -1,34 +0,0 @@ -pub mod testutils; - -use swap::protocol::{alice, bob, bob::BobState}; -use testutils::{bob_run_until::is_btc_locked, FastPunishConfig}; - -/// Bob locks Btc and Alice locks Xmr. Bob does not act; he fails to send Alice -/// 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(FastPunishConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; - let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - - let alice = alice::run(alice_swap); - let alice_handle = tokio::spawn(alice); - - let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); - - assert!(matches!(bob_state, BobState::BtcLocked { .. })); - - let alice_state = alice_handle.await.unwrap(); - ctx.assert_alice_punished(alice_state.unwrap()).await; - - // Restart Bob after Alice punished to ensure Bob transitions to - // punished and does not run indefinitely - let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; - assert!(matches!(bob_swap.state, BobState::BtcLocked { .. })); - - let bob_state = bob::run(bob_swap).await.unwrap(); - - ctx.assert_bob_punished(bob_state).await; - }) - .await; -} From 6e6dc320b438a760b420f4896a1a00348b98ded0 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Tue, 9 Feb 2021 11:15:55 +1100 Subject: [PATCH 19/20] Alice event loop now handles the creation of new swaps --- bors.toml | 3 + swap/src/database/alice.rs | 18 +- swap/src/network/transport.rs | 4 +- swap/src/protocol/alice.rs | 132 ++++++------- swap/src/protocol/alice/behaviour.rs | 31 +++- swap/src/protocol/alice/event_loop.rs | 175 +++++++++++++----- swap/src/protocol/alice/execution_setup.rs | 15 +- swap/src/protocol/alice/state.rs | 5 - swap/src/protocol/alice/swap.rs | 26 +-- swap/src/protocol/alice/swap_response.rs | 4 +- swap/src/protocol/bob.rs | 2 +- ...refunds_using_cancel_and_refund_command.rs | 13 +- ..._and_refund_command_timelock_not_exired.rs | 6 +- ...efund_command_timelock_not_exired_force.rs | 6 +- swap/tests/happy_path.rs | 11 +- .../happy_path_restart_bob_before_comm.rs | 9 +- swap/tests/testutils/mod.rs | 117 ++++++------ 17 files changed, 306 insertions(+), 271 deletions(-) diff --git a/bors.toml b/bors.toml index 27bf2b72..8d33e57c 100644 --- a/bors.toml +++ b/bors.toml @@ -4,4 +4,7 @@ status = [ "build_test (x86_64-apple-darwin)", "docker_tests (happy_path)", "docker_tests (happy_path_restart_bob_before_comm)", + "docker_tests (bob_refunds_using_cancel_and_refund_command.rs)", + "docker_tests (bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs)", + "docker_tests (bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs)" ] diff --git a/swap/src/database/alice.rs b/swap/src/database/alice.rs index 9a9c4383..3eadc70d 100644 --- a/swap/src/database/alice.rs +++ b/swap/src/database/alice.rs @@ -14,10 +14,6 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] pub enum Alice { Started { - amounts: SwapAmounts, - state0: alice::State0, - }, - Negotiated { state3: alice::State3, #[serde(with = "crate::serde_peer_id")] bob_peer_id: PeerId, @@ -54,11 +50,11 @@ pub enum AliceEndState { impl From<&AliceState> for Alice { fn from(alice_state: &AliceState) -> Self { match alice_state { - AliceState::Negotiated { + AliceState::Started { state3, bob_peer_id, .. - } => Alice::Negotiated { + } => Alice::Started { state3: state3.as_ref().clone(), bob_peer_id: *bob_peer_id, }, @@ -93,10 +89,6 @@ impl From<&AliceState> for Alice { } AliceState::BtcPunished => Alice::Done(AliceEndState::BtcPunished), AliceState::SafelyAborted => Alice::Done(AliceEndState::SafelyAborted), - AliceState::Started { amounts, state0 } => Alice::Started { - amounts: *amounts, - state0: state0.clone(), - }, } } } @@ -104,11 +96,10 @@ impl From<&AliceState> for Alice { impl From for AliceState { fn from(db_state: Alice) -> Self { match db_state { - Alice::Started { amounts, state0 } => AliceState::Started { amounts, state0 }, - Alice::Negotiated { + Alice::Started { state3, bob_peer_id, - } => AliceState::Negotiated { + } => AliceState::Started { bob_peer_id, amounts: SwapAmounts { btc: state3.btc, @@ -186,7 +177,6 @@ impl Display for Alice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Alice::Started { .. } => write!(f, "Started"), - Alice::Negotiated { .. } => f.write_str("Negotiated"), Alice::BtcLocked { .. } => f.write_str("Bitcoin locked"), Alice::XmrLocked(_) => f.write_str("Monero locked"), Alice::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"), diff --git a/swap/src/network/transport.rs b/swap/src/network/transport.rs index a8ba1be3..09bd8e9b 100644 --- a/swap/src/network/transport.rs +++ b/swap/src/network/transport.rs @@ -18,10 +18,10 @@ use libp2p::{ /// - DNS name resolution /// - authentication via noise /// - multiplexing via yamux or mplex -pub fn build(id_keys: identity::Keypair) -> Result { +pub fn build(id_keys: &identity::Keypair) -> Result { use libp2p::tcp::TokioTcpConfig; - let dh_keys = noise::Keypair::::new().into_authentic(&id_keys)?; + let dh_keys = noise::Keypair::::new().into_authentic(id_keys)?; let noise = NoiseConfig::xx(dh_keys).into_authenticated(); let tcp = TokioTcpConfig::new().nodelay(true); diff --git a/swap/src/protocol/alice.rs b/swap/src/protocol/alice.rs index e83329ff..2c9d86f3 100644 --- a/swap/src/protocol/alice.rs +++ b/swap/src/protocol/alice.rs @@ -2,15 +2,15 @@ //! Alice holds XMR and wishes receive BTC. use crate::{ bitcoin, database, database::Database, execution_params::ExecutionParams, monero, - network::Seed as NetworkSeed, protocol::SwapAmounts, seed::Seed, + protocol::SwapAmounts, }; use anyhow::{bail, Result}; -use libp2p::{core::Multiaddr, identity::Keypair, PeerId}; -use rand::rngs::OsRng; +use libp2p::{core::Multiaddr, PeerId}; use std::sync::Arc; use uuid::Uuid; pub use self::{ + behaviour::{Behaviour, OutEvent}, event_loop::{EventLoop, EventLoopHandle}, execution_setup::Message1, state::*, @@ -37,16 +37,15 @@ pub struct Swap { pub monero_wallet: Arc, pub execution_params: ExecutionParams, pub swap_id: Uuid, - pub db: Database, + pub db: Arc, } pub struct Builder { swap_id: Uuid, - identity: Keypair, peer_id: PeerId, - db: Database, + db: Arc, execution_params: ExecutionParams, - + event_loop_handle: EventLoopHandle, listen_address: Multiaddr, bitcoin_wallet: Arc, @@ -57,29 +56,31 @@ pub struct Builder { enum InitParams { None, - New { swap_amounts: SwapAmounts }, + New { + swap_amounts: SwapAmounts, + bob_peer_id: PeerId, + state3: Box, + }, } impl Builder { + #[allow(clippy::too_many_arguments)] pub fn new( - seed: Seed, + self_peer_id: PeerId, execution_params: ExecutionParams, swap_id: Uuid, bitcoin_wallet: Arc, monero_wallet: Arc, - db: Database, + db: Arc, listen_address: Multiaddr, + event_loop_handle: EventLoopHandle, ) -> Self { - let network_seed = NetworkSeed::new(seed); - let identity = network_seed.derive_libp2p_identity(); - let peer_id = PeerId::from(identity.public()); - Self { swap_id, - identity, - peer_id, + peer_id: self_peer_id, db, execution_params, + event_loop_handle, listen_address, bitcoin_wallet, monero_wallet, @@ -87,35 +88,44 @@ impl Builder { } } - pub fn with_init_params(self, swap_amounts: SwapAmounts) -> Self { + pub fn with_init_params( + self, + swap_amounts: SwapAmounts, + bob_peer_id: PeerId, + state3: State3, + ) -> Self { Self { - init_params: InitParams::New { swap_amounts }, + init_params: InitParams::New { + swap_amounts, + bob_peer_id, + state3: Box::new(state3), + }, ..self } } - pub async fn build(self) -> Result<(Swap, EventLoop)> { + pub async fn build(self) -> Result { match self.init_params { - InitParams::New { swap_amounts } => { - let initial_state = self - .make_initial_state(swap_amounts.btc, swap_amounts.xmr) - .await?; + InitParams::New { + swap_amounts, + bob_peer_id, + ref state3, + } => { + let initial_state = AliceState::Started { + amounts: swap_amounts, + state3: state3.clone(), + bob_peer_id, + }; - let (event_loop, event_loop_handle) = - EventLoop::new(self.identity.clone(), self.listen_address(), self.peer_id)?; - - Ok(( - Swap { - event_loop_handle, - bitcoin_wallet: self.bitcoin_wallet, - monero_wallet: self.monero_wallet, - execution_params: self.execution_params, - db: self.db, - state: initial_state, - swap_id: self.swap_id, - }, - event_loop, - )) + Ok(Swap { + event_loop_handle: self.event_loop_handle, + bitcoin_wallet: self.bitcoin_wallet, + monero_wallet: self.monero_wallet, + execution_params: self.execution_params, + db: self.db, + state: initial_state, + swap_id: self.swap_id, + }) } InitParams::None => { let resume_state = @@ -128,21 +138,15 @@ impl Builder { ) }; - let (event_loop, event_loop_handle) = - EventLoop::new(self.identity.clone(), self.listen_address(), self.peer_id)?; - - Ok(( - Swap { - state: resume_state, - event_loop_handle, - bitcoin_wallet: self.bitcoin_wallet, - monero_wallet: self.monero_wallet, - execution_params: self.execution_params, - swap_id: self.swap_id, - db: self.db, - }, - event_loop, - )) + Ok(Swap { + state: resume_state, + event_loop_handle: self.event_loop_handle, + bitcoin_wallet: self.bitcoin_wallet, + monero_wallet: self.monero_wallet, + execution_params: self.execution_params, + swap_id: self.swap_id, + db: self.db, + }) } } } @@ -154,26 +158,4 @@ impl Builder { pub fn listen_address(&self) -> Multiaddr { self.listen_address.clone() } - - async fn make_initial_state( - &self, - btc_to_swap: bitcoin::Amount, - xmr_to_swap: monero::Amount, - ) -> Result { - let amounts = SwapAmounts { - btc: btc_to_swap, - xmr: xmr_to_swap, - }; - - let state0 = State0::new( - amounts.btc, - amounts.xmr, - self.execution_params, - self.bitcoin_wallet.as_ref(), - &mut OsRng, - ) - .await?; - - Ok(AliceState::Started { amounts, state0 }) - } } diff --git a/swap/src/protocol/alice/behaviour.rs b/swap/src/protocol/alice/behaviour.rs index 14e46000..4e978f35 100644 --- a/swap/src/protocol/alice/behaviour.rs +++ b/swap/src/protocol/alice/behaviour.rs @@ -1,7 +1,6 @@ use crate::{ network::{peer_tracker, peer_tracker::PeerTracker}, protocol::{ - alice, alice::{ encrypted_signature, execution_setup, swap_response, transfer_proof, State0, State3, SwapResponse, TransferProof, @@ -19,8 +18,12 @@ pub enum OutEvent { SwapRequest { msg: SwapRequest, channel: ResponseChannel, + bob_peer_id: PeerId, + }, + ExecutionSetupDone { + bob_peer_id: PeerId, + state3: Box, }, - ExecutionSetupDone(Box), TransferProofAcknowledged, EncryptedSignature { msg: Box, @@ -40,11 +43,19 @@ impl From for OutEvent { } } -impl From for OutEvent { - fn from(event: alice::OutEvent) -> Self { - use crate::protocol::alice::OutEvent::*; +impl From for OutEvent { + fn from(event: swap_response::OutEvent) -> Self { + use crate::protocol::alice::swap_response::OutEvent::*; match event { - MsgReceived { msg, channel } => OutEvent::SwapRequest { msg, channel }, + MsgReceived { + msg, + channel, + bob_peer_id, + } => OutEvent::SwapRequest { + msg, + channel, + bob_peer_id, + }, ResponseSent => OutEvent::ResponseSent, Failure(err) => OutEvent::Failure(err.context("Swap Request/Response failure")), } @@ -55,7 +66,13 @@ impl From for OutEvent { fn from(event: execution_setup::OutEvent) -> Self { use crate::protocol::alice::execution_setup::OutEvent::*; match event { - Done(state3) => OutEvent::ExecutionSetupDone(Box::new(state3)), + Done { + bob_peer_id, + state3, + } => OutEvent::ExecutionSetupDone { + bob_peer_id, + state3: Box::new(state3), + }, Failure(err) => OutEvent::Failure(err), } } diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index bcc4dc32..02bd17b3 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -1,19 +1,29 @@ use crate::{ + bitcoin, + database::Database, + execution_params::ExecutionParams, + monero, network, network::{transport, TokioExecutor}, protocol::{ - alice::{ - behaviour::{Behaviour, OutEvent}, - State3, SwapResponse, TransferProof, - }, + alice, + alice::{Behaviour, Builder, OutEvent, State0, State3, SwapResponse, TransferProof}, bob::{EncryptedSignature, SwapRequest}, + SwapAmounts, }, + seed::Seed, }; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use libp2p::{ core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm, }; +use rand::rngs::OsRng; +use std::{collections::HashMap, sync::Arc}; use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error, trace}; +use uuid::Uuid; + +// TODO: Use dynamic +const RATE: u32 = 100; #[allow(missing_debug_implementations)] pub struct MpscChannels { @@ -34,7 +44,6 @@ where T: Clone, { sender: broadcast::Sender, - receiver: broadcast::Receiver, } impl Default for BroadcastChannels @@ -42,8 +51,8 @@ where T: Clone, { fn default() -> Self { - let (sender, receiver) = broadcast::channel(100); - BroadcastChannels { sender, receiver } + let (sender, _receiver) = broadcast::channel(100); + BroadcastChannels { sender } } } @@ -70,21 +79,37 @@ impl EventLoopHandle { #[allow(missing_debug_implementations)] pub struct EventLoop { swarm: libp2p::Swarm, + peer_id: PeerId, + execution_params: ExecutionParams, + bitcoin_wallet: Arc, + monero_wallet: Arc, + db: Arc, + listen_address: Multiaddr, + + // Amounts agreed upon for swaps currently in the execution setup phase + // Note: We can do one execution setup per peer at a given time. + swap_amounts: HashMap, + recv_encrypted_signature: broadcast::Sender, send_transfer_proof: mpsc::Receiver<(PeerId, TransferProof)>, - // Only used to clone further handles - handle: EventLoopHandle, + // Only used to produce new handles + send_transfer_proof_sender: mpsc::Sender<(PeerId, TransferProof)>, } impl EventLoop { pub fn new( - identity: libp2p::identity::Keypair, - listen: Multiaddr, - peer_id: PeerId, - ) -> Result<(Self, EventLoopHandle)> { + listen_address: Multiaddr, + seed: Seed, + execution_params: ExecutionParams, + bitcoin_wallet: Arc, + monero_wallet: Arc, + db: Arc, + ) -> Result { + let identity = network::Seed::new(seed).derive_libp2p_identity(); let behaviour = Behaviour::default(); - let transport = transport::build(identity)?; + let transport = transport::build(&identity)?; + let peer_id = PeerId::from(identity.public()); let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, peer_id) .executor(Box::new(TokioExecutor { @@ -92,39 +117,38 @@ impl EventLoop { })) .build(); - Swarm::listen_on(&mut swarm, listen.clone()) - .with_context(|| format!("Address is not supported: {:#}", listen))?; + Swarm::listen_on(&mut swarm, listen_address.clone()) + .with_context(|| format!("Address is not supported: {:#}", listen_address))?; let recv_encrypted_signature = BroadcastChannels::default(); let send_transfer_proof = MpscChannels::default(); - let handle_clone = EventLoopHandle { - recv_encrypted_signature: recv_encrypted_signature.sender.subscribe(), - send_transfer_proof: send_transfer_proof.sender.clone(), - }; - - let driver = EventLoop { + Ok(EventLoop { swarm, + peer_id, + execution_params, + bitcoin_wallet, + monero_wallet, + db, + listen_address, + swap_amounts: Default::default(), recv_encrypted_signature: recv_encrypted_signature.sender, send_transfer_proof: send_transfer_proof.receiver, - handle: handle_clone, - }; - - let handle = EventLoopHandle { - recv_encrypted_signature: recv_encrypted_signature.receiver, - send_transfer_proof: send_transfer_proof.sender, - }; - - Ok((driver, handle)) + send_transfer_proof_sender: send_transfer_proof.sender, + }) } - pub fn clone_handle(&self) -> EventLoopHandle { + pub fn new_handle(&self) -> EventLoopHandle { EventLoopHandle { recv_encrypted_signature: self.recv_encrypted_signature.subscribe(), - send_transfer_proof: self.handle.send_transfer_proof.clone(), + send_transfer_proof: self.send_transfer_proof_sender.clone(), } } + pub fn peer_id(&self) -> PeerId { + self.peer_id + } + pub async fn run(&mut self) { loop { tokio::select! { @@ -133,11 +157,11 @@ impl EventLoop { OutEvent::ConnectionEstablished(alice) => { debug!("Connection Established with {}", alice); } - OutEvent::SwapRequest { msg, channel } => { - let _ = self.handle_swap_request(msg, channel).await; + OutEvent::SwapRequest { msg, channel, bob_peer_id } => { + let _ = self.handle_swap_request(msg, channel, bob_peer_id).await; } - OutEvent::ExecutionSetupDone(state3) => { - let _ = self.handle_execution_setup_done(*state3).await; + OutEvent::ExecutionSetupDone{bob_peer_id, state3} => { + let _ = self.handle_execution_setup_done(bob_peer_id, *state3).await; } OutEvent::TransferProofAcknowledged => { trace!("Bob acknowledged transfer proof"); @@ -165,11 +189,76 @@ impl EventLoop { } async fn handle_swap_request( - &self, - _msg: SwapRequest, - _channel: ResponseChannel, - ) { + &mut self, + swap_request: SwapRequest, + channel: ResponseChannel, + bob_peer_id: PeerId, + ) -> Result<()> { + // 1. Check if acceptable request + // 2. Send response + + let btc_amount = swap_request.btc_amount; + let xmr_amount = btc_amount.as_btc() * RATE as f64; + let xmr_amount = monero::Amount::from_monero(xmr_amount)?; + let swap_response = SwapResponse { xmr_amount }; + + self.swarm + .send_swap_response(channel, swap_response) + .context("Failed to send swap response")?; + + // 3. Start setup execution + + let state0 = State0::new( + btc_amount, + xmr_amount, + self.execution_params, + self.bitcoin_wallet.as_ref(), + &mut OsRng, + ) + .await?; + + // if a node restart during execution setup, the swap is aborted (safely). + self.swap_amounts.insert(bob_peer_id, SwapAmounts { + btc: btc_amount, + xmr: xmr_amount, + }); + + self.swarm.start_execution_setup(bob_peer_id, state0); + // Continues once the execution setup protocol is done + Ok(()) } - async fn handle_execution_setup_done(&self, _state3: State3) {} + async fn handle_execution_setup_done( + &mut self, + bob_peer_id: PeerId, + state3: State3, + ) -> Result<()> { + let swap_id = Uuid::new_v4(); + let handle = self.new_handle(); + + let swap_amounts = self.swap_amounts.remove(&bob_peer_id).ok_or_else(|| { + anyhow!( + "execution setup done for an unknown peer id: {}, node restarted in between?", + bob_peer_id + ) + })?; + + let swap = Builder::new( + self.peer_id, + self.execution_params, + swap_id, + self.bitcoin_wallet.clone(), + self.monero_wallet.clone(), + self.db.clone(), + self.listen_address.clone(), + handle, + ) + .with_init_params(swap_amounts, bob_peer_id, state3) + .build() + .await?; + + tokio::spawn(async move { alice::run(swap).await }); + + Ok(()) + } } diff --git a/swap/src/protocol/alice/execution_setup.rs b/swap/src/protocol/alice/execution_setup.rs index e05964a2..af1e2350 100644 --- a/swap/src/protocol/alice/execution_setup.rs +++ b/swap/src/protocol/alice/execution_setup.rs @@ -32,14 +32,17 @@ pub struct Message3 { #[derive(Debug)] pub enum OutEvent { - Done(State3), + Done { bob_peer_id: PeerId, state3: State3 }, Failure(Error), } -impl From> for OutEvent { - fn from(event: BehaviourOutEvent) -> Self { +impl From> for OutEvent { + fn from(event: BehaviourOutEvent<(PeerId, State3), (), Error>) -> Self { match event { - BehaviourOutEvent::Inbound(_, Ok(State3)) => OutEvent::Done(State3), + BehaviourOutEvent::Inbound(_, Ok((bob_peer_id, state3))) => OutEvent::Done { + bob_peer_id, + state3, + }, BehaviourOutEvent::Inbound(_, Err(e)) => OutEvent::Failure(e), BehaviourOutEvent::Outbound(..) => unreachable!("Alice only supports inbound"), } @@ -49,7 +52,7 @@ impl From> for OutEvent { #[derive(libp2p::NetworkBehaviour)] #[behaviour(out_event = "OutEvent", event_process = false)] pub struct Behaviour { - inner: libp2p_async_await::Behaviour, + inner: libp2p_async_await::Behaviour<(PeerId, State3), (), anyhow::Error>, } impl Default for Behaviour { @@ -93,7 +96,7 @@ impl Behaviour { .context("failed to deserialize message4")?; let state3 = state2.receive(message4)?; - Ok(state3) + Ok((bob, state3)) }) } } diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index 7127ba36..9905a069 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -25,10 +25,6 @@ use std::fmt; #[derive(Debug)] pub enum AliceState { Started { - amounts: SwapAmounts, - state0: State0, - }, - Negotiated { bob_peer_id: PeerId, amounts: SwapAmounts, state3: Box, @@ -70,7 +66,6 @@ impl fmt::Display for AliceState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AliceState::Started { .. } => write!(f, "started"), - AliceState::Negotiated { .. } => write!(f, "negotiated"), AliceState::BtcLocked { .. } => write!(f, "btc is locked"), AliceState::XmrLocked { .. } => write!(f, "xmr is locked"), AliceState::EncSigLearned { .. } => write!(f, "encrypted signature is learned"), diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index d01df0c4..4bd6ef6a 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -84,36 +84,14 @@ async fn run_until_internal( monero_wallet: Arc, execution_params: ExecutionParams, swap_id: Uuid, - db: Database, + db: Arc, ) -> Result { info!("Current state:{}", state); if is_target_state(&state) { Ok(state) } else { match state { - AliceState::Started { amounts, state0 } => { - let state = AliceState::Negotiated { - bob_peer_id: todo!(), - amounts, - state3: todo!(), - }; - - let db_state = (&state).into(); - db.insert_latest_state(swap_id, database::Swap::Alice(db_state)) - .await?; - run_until_internal( - state, - is_target_state, - event_loop_handle, - bitcoin_wallet, - monero_wallet, - execution_params, - swap_id, - db, - ) - .await - } - AliceState::Negotiated { + AliceState::Started { state3, bob_peer_id, amounts, diff --git a/swap/src/protocol/alice/swap_response.rs b/swap/src/protocol/alice/swap_response.rs index 69138642..551d3b11 100644 --- a/swap/src/protocol/alice/swap_response.rs +++ b/swap/src/protocol/alice/swap_response.rs @@ -9,7 +9,7 @@ use libp2p::{ ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, }, - NetworkBehaviour, + NetworkBehaviour, PeerId, }; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -20,6 +20,7 @@ pub enum OutEvent { MsgReceived { msg: SwapRequest, channel: ResponseChannel, + bob_peer_id: PeerId, }, ResponseSent, Failure(Error), @@ -45,6 +46,7 @@ impl From> for OutEvent { OutEvent::MsgReceived { msg: request, channel, + bob_peer_id: peer, } } RequestResponseEvent::Message { diff --git a/swap/src/protocol/bob.rs b/swap/src/protocol/bob.rs index 4807d16e..d3010801 100644 --- a/swap/src/protocol/bob.rs +++ b/swap/src/protocol/bob.rs @@ -168,7 +168,7 @@ impl Builder { &self, ) -> Result<(bob::event_loop::EventLoop, bob::event_loop::EventLoopHandle)> { let bob_behaviour = bob::Behaviour::default(); - let bob_transport = build(self.identity.clone())?; + let bob_transport = build(&self.identity)?; bob::event_loop::EventLoop::new( bob_transport, diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs index 9b64d826..43007177 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command.rs @@ -1,17 +1,13 @@ pub mod testutils; -use swap::protocol::{alice, bob, bob::BobState}; +use swap::protocol::{bob, bob::BobState}; use testutils::{bob_run_until::is_btc_locked, FastCancelConfig}; #[tokio::test] async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { testutils::setup_test(FastCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - let alice_handle = alice::run(alice_swap); - let alice_swap_handle = tokio::spawn(alice_handle); - let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); assert!(matches!(bob_state, BobState::BtcLocked { .. })); @@ -29,6 +25,7 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { } // Bob manually cancels + bob_join_handle.abort(); let (_, state) = bob::cancel( bob_swap.swap_id, bob_swap.state, @@ -41,10 +38,11 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { .unwrap(); assert!(matches!(state, BobState::BtcCancelled { .. })); - let (bob_swap, _) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; + let (bob_swap, bob_join_handle) = ctx.stop_and_resume_bob_from_db(bob_join_handle).await; assert!(matches!(bob_swap.state, BobState::BtcCancelled { .. })); // Bob manually refunds + bob_join_handle.abort(); let bob_state = bob::refund( bob_swap.swap_id, bob_swap.state, @@ -58,9 +56,6 @@ async fn given_bob_manually_refunds_after_btc_locked_bob_refunds() { .unwrap(); ctx.assert_bob_refunded(bob_state).await; - - let alice_state = alice_swap_handle.await.unwrap().unwrap(); - ctx.assert_alice_refunded(alice_state).await; }) .await; } diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs index 07b69590..9e8a79aa 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs @@ -1,18 +1,14 @@ pub mod testutils; use bob::cancel::CancelError; -use swap::protocol::{alice, bob, bob::BobState}; +use swap::protocol::{bob, bob::BobState}; use testutils::{bob_run_until::is_btc_locked, SlowCancelConfig}; #[tokio::test] async fn given_bob_manually_cancels_when_timelock_not_expired_errors() { testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - let alice_handle = alice::run(alice_swap); - tokio::spawn(alice_handle); - let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); assert!(matches!(bob_state, BobState::BtcLocked { .. })); diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs index 098f8752..fd3465d7 100644 --- a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs +++ b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs @@ -1,17 +1,13 @@ pub mod testutils; -use swap::protocol::{alice, bob, bob::BobState}; +use swap::protocol::{bob, bob::BobState}; use testutils::{bob_run_until::is_btc_locked, SlowCancelConfig}; #[tokio::test] async fn given_bob_manually_forces_cancel_when_timelock_not_expired_errors() { testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - let alice_handle = alice::run(alice_swap); - tokio::spawn(alice_handle); - let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap(); assert!(matches!(bob_state, BobState::BtcLocked { .. })); diff --git a/swap/tests/happy_path.rs b/swap/tests/happy_path.rs index 548aee86..8ba5e903 100644 --- a/swap/tests/happy_path.rs +++ b/swap/tests/happy_path.rs @@ -1,23 +1,18 @@ pub mod testutils; -use swap::protocol::{alice, bob}; +use swap::protocol::bob; use testutils::SlowCancelConfig; -use tokio::join; /// Run the following tests with RUST_MIN_STACK=10000000 #[tokio::test] async fn happy_path() { testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; let (bob_swap, _) = ctx.new_swap_as_bob().await; - let alice = alice::run(alice_swap); - let bob = bob::run(bob_swap); + let bob_state = bob::run(bob_swap).await; - let (alice_state, bob_state) = join!(alice, bob); - - ctx.assert_alice_redeemed(alice_state.unwrap()).await; + ctx.assert_alice_redeemed().await; ctx.assert_bob_redeemed(bob_state.unwrap()).await; }) .await; diff --git a/swap/tests/happy_path_restart_bob_before_comm.rs b/swap/tests/happy_path_restart_bob_before_comm.rs index 7c72adf9..6235b0ec 100644 --- a/swap/tests/happy_path_restart_bob_before_comm.rs +++ b/swap/tests/happy_path_restart_bob_before_comm.rs @@ -1,17 +1,13 @@ pub mod testutils; -use swap::protocol::{alice, bob, bob::BobState}; +use swap::protocol::{bob, bob::BobState}; use testutils::{bob_run_until::is_xmr_locked, SlowCancelConfig}; #[tokio::test] async fn given_bob_restarts_after_xmr_is_locked_resume_swap() { testutils::setup_test(SlowCancelConfig, |mut ctx| async move { - let (alice_swap, _) = ctx.new_swap_as_alice().await; let (bob_swap, bob_join_handle) = ctx.new_swap_as_bob().await; - let alice_handle = alice::run(alice_swap); - let alice_swap_handle = tokio::spawn(alice_handle); - let bob_state = bob::run_until(bob_swap, is_xmr_locked).await.unwrap(); assert!(matches!(bob_state, BobState::XmrLocked { .. })); @@ -23,8 +19,7 @@ async fn given_bob_restarts_after_xmr_is_locked_resume_swap() { ctx.assert_bob_redeemed(bob_state).await; - let alice_state = alice_swap_handle.await.unwrap(); - ctx.assert_alice_redeemed(alice_state.unwrap()).await; + ctx.assert_alice_redeemed().await; }) .await; } diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index 91a7949f..bec889af 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -8,6 +8,7 @@ use std::{path::PathBuf, sync::Arc}; use swap::{ bitcoin, bitcoin::Timelock, + database::{Database, Swap}, execution_params, execution_params::{ExecutionParams, GetExecutionParams}, monero, @@ -30,31 +31,10 @@ pub struct StartingBalances { struct AliceParams { seed: Seed, execution_params: ExecutionParams, - swap_id: Uuid, - bitcoin_wallet: Arc, - monero_wallet: Arc, - db_path: PathBuf, + db: Arc, listen_address: Multiaddr, } -impl AliceParams { - pub fn builder(&self) -> alice::Builder { - alice::Builder::new( - self.seed, - self.execution_params, - self.swap_id, - self.bitcoin_wallet.clone(), - self.monero_wallet.clone(), - self.db_path.clone(), - self.listen_address.clone(), - ) - } - - fn peer_id(&self) -> PeerId { - self.builder().peer_id() - } -} - #[derive(Debug, Clone)] struct BobParams { seed: Seed, @@ -84,6 +64,12 @@ impl BobParams { pub struct BobEventLoopJoinHandle(JoinHandle<()>); +impl BobEventLoopJoinHandle { + pub fn abort(&self) { + self.0.abort() + } +} + pub struct AliceEventLoopJoinHandle(JoinHandle<()>); pub struct TestContext { @@ -101,20 +87,6 @@ pub struct TestContext { } impl TestContext { - pub async fn new_swap_as_alice(&mut self) -> (alice::Swap, AliceEventLoopJoinHandle) { - let (swap, mut event_loop) = self - .alice_params - .builder() - .with_init_params(self.swap_amounts) - .build() - .await - .unwrap(); - - let join_handle = tokio::spawn(async move { event_loop.run().await }); - - (swap, AliceEventLoopJoinHandle(join_handle)) - } - pub async fn new_swap_as_bob(&mut self) -> (bob::Swap, BobEventLoopJoinHandle) { let (swap, event_loop) = self .bob_params @@ -129,24 +101,11 @@ impl TestContext { (swap, BobEventLoopJoinHandle(join_handle)) } - pub async fn stop_and_resume_alice_from_db( - &mut self, - join_handle: AliceEventLoopJoinHandle, - ) -> alice::Swap { - join_handle.0.abort(); - - let (swap, mut event_loop) = self.alice_params.builder().build().await.unwrap(); - - tokio::spawn(async move { event_loop.run().await }); - - swap - } - pub async fn stop_and_resume_bob_from_db( &mut self, join_handle: BobEventLoopJoinHandle, ) -> (bob::Swap, BobEventLoopJoinHandle) { - join_handle.0.abort(); + join_handle.abort(); let (swap, event_loop) = self.bob_params.builder().build().await.unwrap(); @@ -155,7 +114,17 @@ impl TestContext { (swap, BobEventLoopJoinHandle(join_handle)) } - pub async fn assert_alice_redeemed(&self, state: AliceState) { + pub async fn assert_alice_redeemed(&self) { + let mut states = self.alice_params.db.all().unwrap(); + + assert_eq!(states.len(), 1, "Expected only one swap in Alice's db"); + + let (_swap_id, state) = states.pop().unwrap(); + let state = match state { + Swap::Alice(state) => state.into(), + Swap::Bob(_) => panic!("Bob state in Alice db is unexpected"), + }; + assert!(matches!(state, AliceState::BtcRedeemed)); let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap(); @@ -174,8 +143,22 @@ impl TestContext { 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)); + pub async fn assert_alice_refunded(&self) { + let mut states = self.alice_params.db.all().unwrap(); + + assert_eq!(states.len(), 1, "Expected only one swap in Alice's db"); + + let (_swap_id, state) = states.pop().unwrap(); + let state = match state { + Swap::Alice(state) => state.into(), + Swap::Bob(_) => panic!("Bob state in Alice db is unexpected"), + }; + + assert!( + matches!(state, AliceState::XmrRefunded), + "Alice state is not XmrRefunded: {}", + state + ); 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); @@ -342,13 +325,13 @@ where ) .await; + let db_path = tempdir().unwrap(); + let alice_db = Arc::new(Database::open(db_path.path()).unwrap()); + let alice_params = AliceParams { seed: Seed::random().unwrap(), execution_params, - 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(), + db: alice_db.clone(), listen_address, }; @@ -365,6 +348,22 @@ where ) .await; + let mut alice_event_loop = alice::EventLoop::new( + alice_params.listen_address.clone(), + alice_params.seed, + alice_params.execution_params, + alice_bitcoin_wallet.clone(), + alice_monero_wallet.clone(), + alice_db, + ) + .unwrap(); + + let alice_peer_id = alice_event_loop.peer_id(); + + tokio::spawn(async move { + alice_event_loop.run().await; + }); + let bob_params = BobParams { seed: Seed::random().unwrap(), db_path: tempdir().unwrap().path().to_path_buf(), @@ -372,7 +371,7 @@ where 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(), + alice_peer_id, execution_params, }; @@ -388,7 +387,7 @@ where bob_monero_wallet, }; - testfn(test).await + testfn(test).await; } async fn init_containers(cli: &Cli) -> (Monero, Containers<'_>) { From eb39add5ff812089ca9ff2f276163ba4fd05009b Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Wed, 10 Feb 2021 12:06:41 +1100 Subject: [PATCH 20/20] Fix typo --- .github/workflows/ci.yml | 4 ++-- bors.toml | 6 +++--- ...using_cancel_and_refund_command_timelock_not_expired.rs} | 0 ...cancel_and_refund_command_timelock_not_expired_force.rs} | 0 4 files changed, 5 insertions(+), 5 deletions(-) rename swap/tests/{bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs => bob_refunds_using_cancel_and_refund_command_timelock_not_expired.rs} (100%) rename swap/tests/{bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs => bob_refunds_using_cancel_and_refund_command_timelock_not_expired_force.rs} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 630199c0..7a2f10f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,8 +129,8 @@ jobs: happy_path, happy_path_restart_bob_before_comm, bob_refunds_using_cancel_and_refund_command, - bob_refunds_using_cancel_and_refund_command_timelock_not_exired, - bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force, + bob_refunds_using_cancel_and_refund_command_timelock_not_expired, + bob_refunds_using_cancel_and_refund_command_timelock_not_expired_force, ] runs-on: ubuntu-latest steps: diff --git a/bors.toml b/bors.toml index 8d33e57c..fcb4f9eb 100644 --- a/bors.toml +++ b/bors.toml @@ -4,7 +4,7 @@ status = [ "build_test (x86_64-apple-darwin)", "docker_tests (happy_path)", "docker_tests (happy_path_restart_bob_before_comm)", - "docker_tests (bob_refunds_using_cancel_and_refund_command.rs)", - "docker_tests (bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs)", - "docker_tests (bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs)" + "docker_tests (bob_refunds_using_cancel_and_refund_command)", + "docker_tests (bob_refunds_using_cancel_and_refund_command_timelock_not_expired_force)", + "docker_tests (bob_refunds_using_cancel_and_refund_command_timelock_not_expired)" ] diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_expired.rs similarity index 100% rename from swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired.rs rename to swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_expired.rs diff --git a/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs b/swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_expired_force.rs similarity index 100% rename from swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_exired_force.rs rename to swap/tests/bob_refunds_using_cancel_and_refund_command_timelock_not_expired_force.rs