From 7cae6a9e4da8b13eb2648a21cf52c13f5184594e Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Mon, 14 Dec 2020 22:16:39 +1100 Subject: [PATCH] Add Bob restart test --- swap/src/bob/swap.rs | 4 + swap/tests/bob_safe_restart.rs | 395 ------------------------------- swap/tests/happy_path.rs | 7 +- swap/tests/happy_path_restart.rs | 124 +++++++++- swap/tests/punish.rs | 7 +- swap/tests/refund_restart.rs | 1 + swap/tests/testutils/mod.rs | 11 +- 7 files changed, 139 insertions(+), 410 deletions(-) delete mode 100644 swap/tests/bob_safe_restart.rs diff --git a/swap/src/bob/swap.rs b/swap/src/bob/swap.rs index 4d398458..fdb6cf3c 100644 --- a/swap/src/bob/swap.rs +++ b/swap/src/bob/swap.rs @@ -168,6 +168,10 @@ pub fn is_xmr_locked(state: &BobState) -> bool { matches!(state, BobState::XmrLocked(..)) } +pub fn is_encsig_sent(state: &BobState) -> bool { + matches!(state, BobState::EncSigSent(..)) +} + // State machine driver for swap execution #[allow(clippy::too_many_arguments)] #[async_recursion] diff --git a/swap/tests/bob_safe_restart.rs b/swap/tests/bob_safe_restart.rs deleted file mode 100644 index 087f0fba..00000000 --- a/swap/tests/bob_safe_restart.rs +++ /dev/null @@ -1,395 +0,0 @@ -// use bitcoin_harness::Bitcoind; -// use futures::future::try_join; -// use libp2p::Multiaddr; -// use monero_harness::{image, Monero}; -// use rand::rngs::OsRng; -// use std::{convert::TryInto, sync::Arc}; -// use swap::{ -// alice, alice::swap::AliceState, bitcoin, bob, bob::swap::BobState, -// monero, network::transport::build, storage::Database, SwapAmounts -// }; -// use tempfile::{tempdir, TempDir}; -// use testcontainers::{clients::Cli, Container}; -// use uuid::Uuid; -// use xmr_btc::cross_curve_dleq; -// use xmr_btc::config::Config; -// -// fn setup_tracing() { -// use tracing_subscriber::util::SubscriberInitExt as _; -// let _guard = tracing_subscriber::fmt() -// .with_env_filter("swap=trace,xmr_btc=trace") -// .with_ansi(false) -// .set_default(); -// } -// -// // This is just to keep the containers alive -// #[allow(dead_code)] -// struct Containers<'a> { -// bitcoind: Bitcoind<'a>, -// monerods: Vec>, -// } -// -// /// Returns Alice's and Bob's wallets, in this order -// async fn setup_wallets( -// cli: &Cli, -// _init_btc_alice: bitcoin::Amount, -// init_xmr_alice: monero::Amount, -// init_btc_bob: bitcoin::Amount, -// init_xmr_bob: monero::Amount, -// config: Config -// ) -> ( -// bitcoin::Wallet, -// monero::Wallet, -// bitcoin::Wallet, -// monero::Wallet, -// Containers<'_>, -// ) { -// let bitcoind = Bitcoind::new(&cli, "0.19.1").unwrap(); -// let _ = bitcoind.init(5).await; -// -// let alice_btc_wallet = swap::bitcoin::Wallet::new("alice", -// bitcoind.node_url.clone(), config.bitcoin_network) .await -// .unwrap(); -// let bob_btc_wallet = swap::bitcoin::Wallet::new("bob", -// bitcoind.node_url.clone(), config.bitcoin_network) .await -// .unwrap(); -// bitcoind -// .mint(bob_btc_wallet.inner.new_address().await.unwrap(), -// init_btc_bob) .await -// .unwrap(); -// -// let (monero, monerods) = Monero::new(&cli, None, -// vec!["alice".to_string(), "bob".to_string()]) .await -// .unwrap(); -// monero -// .init(vec![ -// ("alice", init_xmr_alice.as_piconero()), -// ("bob", init_xmr_bob.as_piconero()), -// ]) -// .await -// .unwrap(); -// -// let alice_xmr_wallet = -// swap::monero::Wallet(monero.wallet("alice").unwrap().client()); -// let bob_xmr_wallet = -// swap::monero::Wallet(monero.wallet("bob").unwrap().client()); -// -// ( -// alice_btc_wallet, -// alice_xmr_wallet, -// bob_btc_wallet, -// bob_xmr_wallet, -// Containers { bitcoind, monerods }, -// ) -// } -// -// #[tokio::test] -// async fn given_bob_restarts_after_encsig_is_sent_resume_swap() { -// setup_tracing(); -// -// let config = Config::regtest(); -// -// let alice_multiaddr: Multiaddr = "/ip4/127.0.0.1/tcp/9876" -// .parse() -// .expect("failed to parse Alice's address"); -// -// let btc_to_swap = bitcoin::Amount::from_sat(1_000_000); -// let init_btc_alice = bitcoin::Amount::ZERO; -// let init_btc_bob = btc_to_swap * 10; -// -// let xmr_to_swap = monero::Amount::from_piconero(1_000_000_000_000); -// let init_xmr_alice = xmr_to_swap * 10; -// let init_xmr_bob = monero::Amount::ZERO; -// -// let cli = Cli::default(); -// let (alice_btc_wallet, alice_xmr_wallet, bob_btc_wallet, bob_xmr_wallet, -// _containers) = setup_wallets( -// &cli, -// init_btc_alice, -// init_xmr_alice, -// init_btc_bob, -// init_xmr_bob, -// config -// ) -// .await; -// -// let alice_btc_wallet = Arc::new(alice_btc_wallet); -// let alice_xmr_wallet = Arc::new(alice_xmr_wallet); -// let bob_btc_wallet = Arc::new(bob_btc_wallet); -// let bob_xmr_wallet = Arc::new(bob_xmr_wallet); -// -// let amounts = SwapAmounts { -// btc: btc_to_swap, -// xmr: xmr_to_swap, -// }; -// -// let alice_db_dir = TempDir::new().unwrap(); -// let alice_swap = async { -// let rng = &mut OsRng; -// let behaviour = alice::Behaviour::default(); -// let transport = build(behaviour.identity()).unwrap(); -// let start_state = { -// let a = bitcoin::SecretKey::new_random(rng); -// let s_a = cross_curve_dleq::Scalar::random(rng); -// let v_a = xmr_btc::monero::PrivateViewKey::new_random(rng); -// AliceState::Started { -// amounts, -// a, -// s_a, -// v_a, -// } -// }; -// let config = xmr_btc::config::Config::regtest(); -// let swap_id = Uuid::new_v4(); -// -// let swarm = alice::new_swarm(alice_multiaddr.clone(), transport, -// behaviour).unwrap(); let db = -// Database::open(alice_db_dir.path()).unwrap(); -// -// alice::swap::swap( -// start_state, -// swarm, -// alice_btc_wallet.clone(), -// alice_xmr_wallet.clone(), -// config, -// swap_id, -// db, -// ) -// .await -// }; -// -// let bob_swap = { -// let rng = &mut OsRng; -// let bob_db_dir = tempdir().unwrap(); -// let bob_db = Database::open(bob_db_dir.path()).unwrap(); -// let bob_behaviour = bob::Behaviour::default(); -// let bob_transport = build(bob_behaviour.identity()).unwrap(); -// -// let refund_address = bob_btc_wallet.new_address().await.unwrap(); -// let state0 = xmr_btc::bob::State0::new( -// rng, -// btc_to_swap, -// xmr_to_swap, -// config.bitcoin_refund_timelock, -// config.bitcoin_punish_timelock, -// refund_address, -// ); -// let start_state = BobState::Started { -// state0, -// amounts, -// addr: alice_multiaddr.clone(), -// }; -// let bob_swarm = bob::new_swarm(bob_transport, -// bob_behaviour).unwrap(); let swap_id = Uuid::new_v4(); -// // Bob reaches encsig_learned -// bob::swap::run_until( -// start_state, -// |state| matches!(state, BobState::EncSigSent { .. }), -// bob_swarm, -// bob_db, -// bob_btc_wallet.clone(), -// bob_xmr_wallet.clone(), -// OsRng, -// swap_id, -// ) -// .await -// .unwrap(); -// -// let bob_behaviour = bob::Behaviour::default(); -// let bob_transport = build(bob_behaviour.identity()).unwrap(); -// let bob_swarm = bob::new_swarm(bob_transport, -// bob_behaviour).unwrap(); let bob_db = -// Database::open(bob_db_dir.path()).unwrap(); -// -// // Load the latest state from the db -// let latest_state = bob_db.get_state(swap_id).unwrap(); -// let state = if let swap::state::Swap::Bob(state) = latest_state { -// state -// } else { -// panic!("Bob state expected") -// }; -// -// bob::swap::swap( -// state.into(), -// bob_swarm, -// bob_db, -// bob_btc_wallet.clone(), -// bob_xmr_wallet.clone(), -// OsRng, -// swap_id, -// ) -// }; -// -// try_join(alice_swap, bob_swap).await.unwrap(); -// -// let btc_alice_final = alice_btc_wallet.balance().await.unwrap(); -// let xmr_alice_final = alice_xmr_wallet.get_balance().await.unwrap(); -// -// let btc_bob_final = bob_btc_wallet.balance().await.unwrap(); -// bob_xmr_wallet.0.refresh().await.unwrap(); -// let xmr_bob_final = bob_xmr_wallet.get_balance().await.unwrap(); -// -// assert_eq!( -// btc_alice_final, -// init_btc_alice + btc_to_swap - -// bitcoin::Amount::from_sat(bitcoin::TX_FEE) ); -// assert!(btc_bob_final <= init_btc_bob - btc_to_swap); -// -// assert!(xmr_alice_final <= init_xmr_alice - xmr_to_swap); -// assert_eq!(xmr_bob_final, init_xmr_bob + xmr_to_swap); -// } -// -// #[tokio::test] -// async fn given_alice_restarts_after_xmr_is_locked_refund_swap() { -// setup_tracing(); -// -// let config = Config::regtest(); -// -// let alice_multiaddr: Multiaddr = "/ip4/127.0.0.1/tcp/9876" -// .parse() -// .expect("failed to parse Alice's address"); -// -// let btc_to_swap = bitcoin::Amount::from_sat(1_000_000); -// let init_btc_alice = bitcoin::Amount::ZERO; -// let init_btc_bob = btc_to_swap * 10; -// -// let xmr_to_swap = monero::Amount::from_piconero(1_000_000_000_000); -// let init_xmr_alice = xmr_to_swap * 10; -// let init_xmr_bob = monero::Amount::ZERO; -// -// let cli = Cli::default(); -// let (alice_btc_wallet, alice_xmr_wallet, bob_btc_wallet, bob_xmr_wallet, -// _containers) = setup_wallets( -// &cli, -// init_btc_alice, -// init_xmr_alice, -// init_btc_bob, -// init_xmr_bob, -// ) -// .await; -// -// let alice_btc_wallet = Arc::new(alice_btc_wallet); -// let alice_xmr_wallet = Arc::new(alice_xmr_wallet); -// let bob_btc_wallet = Arc::new(bob_btc_wallet); -// let bob_xmr_wallet = Arc::new(bob_xmr_wallet); -// -// let amounts = SwapAmounts { -// btc: btc_to_swap, -// xmr: xmr_to_swap, -// }; -// -// let alice_db_dir = TempDir::new().unwrap(); -// let alice_swap = async { -// let rng = &mut OsRng; -// let behaviour = alice::Behaviour::default(); -// let transport = build(behaviour.identity()).unwrap(); -// let start_state = { -// let a = bitcoin::SecretKey::new_random(rng); -// let s_a = cross_curve_dleq::Scalar::random(rng); -// let v_a = xmr_btc::monero::PrivateViewKey::new_random(rng); -// AliceState::Started { -// amounts, -// a, -// s_a, -// v_a, -// } -// }; -// let config = xmr_btc::config::Config::regtest(); -// let swap_id = Uuid::new_v4(); -// -// let swarm = alice::new_swarm(alice_multiaddr.clone(), transport, -// behaviour).unwrap(); let db = -// Database::open(alice_db_dir.path()).unwrap(); -// -// // Alice reaches encsig_learned -// alice::swap::run_until( -// start_state, -// |state| matches!(state, AliceState::XmrLocked { .. }), -// swarm, -// alice_btc_wallet.clone(), -// alice_xmr_wallet.clone(), -// config, -// swap_id, -// db, -// ) -// .await -// .unwrap(); -// -// let behaviour = alice::Behaviour::default(); -// let transport = build(behaviour.identity()).unwrap(); -// let swarm = alice::new_swarm(alice_multiaddr.clone(), transport, -// behaviour).unwrap(); let db = -// Database::open(alice_db_dir.path()).unwrap(); -// -// // Load the latest state from the db -// let latest_state = db.get_state(swap_id).unwrap(); -// let latest_state = latest_state.try_into().unwrap(); -// -// // Finish the swap -// alice::swap::swap( -// latest_state, -// swarm, -// alice_btc_wallet.clone(), -// alice_xmr_wallet.clone(), -// config, -// swap_id, -// db, -// ) -// .await -// }; -// -// let bob_swap = { -// let rng = &mut OsRng; -// let bob_db_dir = tempdir().unwrap(); -// let bob_db = Database::open(bob_db_dir.path()).unwrap(); -// let bob_behaviour = bob::Behaviour::default(); -// let bob_transport = build(bob_behaviour.identity()).unwrap(); -// -// let refund_address = bob_btc_wallet.new_address().await.unwrap(); -// let state0 = xmr_btc::bob::State0::new( -// rng, -// btc_to_swap, -// xmr_to_swap, -// config.bitcoin_refund_timelock, -// config.bitcoin_punish_timelock, -// refund_address, -// ); -// let bob_state = BobState::Started { -// state0, -// amounts, -// addr: alice_multiaddr.clone(), -// }; -// let bob_swarm = bob::new_swarm(bob_transport, -// bob_behaviour).unwrap(); bob::swap::swap( -// bob_state, -// bob_swarm, -// bob_db, -// bob_btc_wallet.clone(), -// bob_xmr_wallet.clone(), -// OsRng, -// Uuid::new_v4(), -// ) -// }; -// -// try_join(alice_swap, bob_swap).await.unwrap(); -// -// let btc_alice_final = alice_btc_wallet.balance().await.unwrap(); -// let xmr_alice_final = alice_xmr_wallet.get_balance().await.unwrap(); -// -// let btc_bob_final = bob_btc_wallet.balance().await.unwrap(); -// bob_xmr_wallet.0.refresh().await.unwrap(); -// let xmr_bob_final = bob_xmr_wallet.get_balance().await.unwrap(); -// -// // Alice's BTC balance did not change -// assert_eq!(btc_alice_final, init_btc_alice); -// // Bob wasted some BTC fees -// assert_eq!( -// btc_bob_final, -// init_btc_bob - bitcoin::Amount::from_sat(bitcoin::TX_FEE) -// ); -// -// // Alice wasted some XMR fees -// assert_eq!(init_xmr_alice - xmr_alice_final, monero::Amount::ZERO); -// // Bob's ZMR balance did not change -// assert_eq!(xmr_bob_final, init_xmr_bob); -// } diff --git a/swap/tests/happy_path.rs b/swap/tests/happy_path.rs index a8f11b47..5138c0a7 100644 --- a/swap/tests/happy_path.rs +++ b/swap/tests/happy_path.rs @@ -2,8 +2,7 @@ use crate::testutils::{init_alice, init_bob}; use futures::future::try_join; use libp2p::Multiaddr; use rand::rngs::OsRng; -use swap::{alice, bob, storage::Database}; -use tempfile::tempdir; +use swap::{alice, bob}; use testcontainers::clients::Cli; use testutils::init_tracing; use uuid::Uuid; @@ -49,6 +48,7 @@ async fn happy_path() { alice_event_loop_handle, alice_btc_wallet, alice_xmr_wallet, + alice_db, ) = init_alice( &bitcoind, &monero, @@ -72,9 +72,6 @@ async fn happy_path() { ) .await; - let alice_db_datadir = tempdir().unwrap(); - let alice_db = Database::open(alice_db_datadir.path()).unwrap(); - let alice_swap_fut = alice::swap::swap( alice_state, alice_event_loop_handle, diff --git a/swap/tests/happy_path_restart.rs b/swap/tests/happy_path_restart.rs index e57381cc..173eb389 100644 --- a/swap/tests/happy_path_restart.rs +++ b/swap/tests/happy_path_restart.rs @@ -9,6 +9,7 @@ use xmr_btc::config::Config; pub mod testutils; use crate::testutils::{init_alice, init_bob}; +use swap::bob::swap::BobState; use testutils::init_tracing; #[tokio::test] @@ -42,6 +43,7 @@ async fn given_alice_restarts_after_encsig_is_learned_resume_swap() { alice_event_loop_handle, alice_btc_wallet, alice_xmr_wallet, + _, ) = init_alice( &bitcoind, &monero, @@ -93,7 +95,7 @@ async fn given_alice_restarts_after_encsig_is_learned_resume_swap() { alice_event_loop_handle, alice_btc_wallet.clone(), alice_xmr_wallet.clone(), - Config::regtest(), + config, alice_swap_id, alice_db, ) @@ -117,7 +119,7 @@ async fn given_alice_restarts_after_encsig_is_learned_resume_swap() { event_loop_handle_after_restart, alice_btc_wallet, alice_xmr_wallet, - Config::regtest(), + config, alice_swap_id, alice_db, ) @@ -128,3 +130,121 @@ async fn given_alice_restarts_after_encsig_is_learned_resume_swap() { // TODO: Additionally assert balances } + +#[tokio::test] +async fn given_bob_restarts_after_encsig_is_sent_resume_swap() { + let _guard = init_tracing(); + + let cli = Cli::default(); + let ( + monero, + testutils::Containers { + bitcoind, + monerods: _monerods, + }, + ) = testutils::init_containers(&cli).await; + + let btc_to_swap = bitcoin::Amount::from_sat(1_000_000); + let xmr_to_swap = xmr_btc::monero::Amount::from_piconero(1_000_000_000_000); + + let bob_btc_starting_balance = btc_to_swap * 10; + let alice_xmr_starting_balance = xmr_to_swap * 10; + + let alice_multiaddr: Multiaddr = "/ip4/127.0.0.1/tcp/9877" + .parse() + .expect("failed to parse Alice's address"); + + let config = Config::regtest(); + + let ( + alice_state, + mut alice_event_loop, + alice_event_loop_handle, + alice_btc_wallet, + alice_xmr_wallet, + alice_db, + ) = init_alice( + &bitcoind, + &monero, + btc_to_swap, + xmr_to_swap, + alice_xmr_starting_balance, + alice_multiaddr.clone(), + config, + ) + .await; + + let (bob_state, bob_event_loop, bob_event_loop_handle, bob_btc_wallet, bob_xmr_wallet, _) = + init_bob( + alice_multiaddr.clone(), + &bitcoind, + &monero, + btc_to_swap, + bob_btc_starting_balance, + xmr_to_swap, + config, + ) + .await; + + let _ = tokio::spawn(async move { + alice::swap::swap( + alice_state, + alice_event_loop_handle, + alice_btc_wallet, + alice_xmr_wallet.clone(), + config, + Uuid::new_v4(), + alice_db, + ) + .await + }); + + let _alice_swarm_fut = tokio::spawn(async move { alice_event_loop.run().await }); + + let _bob_swarm_fut = tokio::spawn(async move { bob_event_loop.run().await }); + + let bob_swap_id = Uuid::new_v4(); + let bob_db_datadir = tempdir().unwrap(); + let bob_db = Database::open(bob_db_datadir.path()).unwrap(); + + let bob_state = bob::swap::run_until( + bob_state, + bob::swap::is_encsig_sent, + bob_event_loop_handle, + bob_db, + bob_btc_wallet.clone(), + bob_xmr_wallet.clone(), + OsRng, + bob_swap_id, + ) + .await + .unwrap(); + + assert!(matches!(bob_state, BobState::EncSigSent {..})); + + let bob_db = Database::open(bob_db_datadir.path()).unwrap(); + let state_before_restart = bob_db.get_state(bob_swap_id).unwrap(); + + if let swap::state::Swap::Bob(state) = state_before_restart.clone() { + assert!(matches!(state, swap::state::Bob::EncSigSent {..})); + } + + let (event_loop_after_restart, event_loop_handle_after_restart) = + testutils::init_bob_event_loop(); + let _alice_swarm_fut = tokio::spawn(async move { event_loop_after_restart.run().await }); + + let alice_state = bob::swap::recover( + event_loop_handle_after_restart, + bob_db, + bob_btc_wallet, + bob_xmr_wallet, + OsRng, + bob_swap_id, + ) + .await + .unwrap(); + + assert!(matches!(alice_state, BobState::XmrRedeemed {..})); + + // TODO: Additionally assert balances +} diff --git a/swap/tests/punish.rs b/swap/tests/punish.rs index 5262b17f..a7ddb1d8 100644 --- a/swap/tests/punish.rs +++ b/swap/tests/punish.rs @@ -2,8 +2,7 @@ use crate::testutils::{init_alice, init_bob}; use futures::future::try_join; use libp2p::Multiaddr; use rand::rngs::OsRng; -use swap::{alice, alice::swap::AliceState, bob, bob::swap::BobState, storage::Database}; -use tempfile::tempdir; +use swap::{alice, alice::swap::AliceState, bob, bob::swap::BobState}; use testcontainers::clients::Cli; use testutils::init_tracing; use uuid::Uuid; @@ -47,6 +46,7 @@ async fn alice_punishes_if_bob_never_acts_after_fund() { alice_event_loop_handle, alice_btc_wallet, alice_xmr_wallet, + alice_db, ) = init_alice( &bitcoind, &monero, @@ -83,9 +83,6 @@ async fn alice_punishes_if_bob_never_acts_after_fund() { let _bob_swarm_fut = tokio::spawn(async move { bob_event_loop.run().await }); - let alice_db_datadir = tempdir().unwrap(); - let alice_db = Database::open(alice_db_datadir.path()).unwrap(); - let alice_fut = alice::swap::swap( alice_state, alice_event_loop_handle, diff --git a/swap/tests/refund_restart.rs b/swap/tests/refund_restart.rs index d44294ff..956a04b3 100644 --- a/swap/tests/refund_restart.rs +++ b/swap/tests/refund_restart.rs @@ -46,6 +46,7 @@ async fn both_refund() { alice_event_loop_handle, alice_btc_wallet, alice_xmr_wallet, + _, ) = init_alice( &bitcoind, &monero, diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index d008c65c..64a64146 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -124,6 +124,7 @@ pub async fn init_alice( alice::event_loop::EventLoopHandle, Arc, Arc, + Database, ) { let (alice_btc_wallet, alice_xmr_wallet) = init_wallets( "alice", @@ -138,14 +139,18 @@ pub async fn init_alice( let alice_start_state = init_alice_state(btc_to_swap, xmr_to_swap, alice_btc_wallet.clone(), config).await; - let (swarm_driver, handle) = init_alice_event_loop(listen); + let (event_loop, event_loop_handle) = init_alice_event_loop(listen); + + let alice_db_datadir = tempdir().unwrap(); + let alice_db = Database::open(alice_db_datadir.path()).unwrap(); ( alice_start_state, - swarm_driver, - handle, + event_loop, + event_loop_handle, alice_btc_wallet, alice_xmr_wallet, + alice_db, ) }