mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Merge pull request #26 from comit-network/more-on-chain-tests
Test that Alice punishes if Bob is inactive after locking bitcoin
This commit is contained in:
commit
4cfc603786
@ -6,8 +6,8 @@ use anyhow::Result;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::mpsc::{channel, Receiver, Sender},
|
channel::mpsc::{channel, Receiver, Sender},
|
||||||
future::try_join,
|
future::{select, try_join},
|
||||||
SinkExt, StreamExt,
|
pin_mut, SinkExt, StreamExt,
|
||||||
};
|
};
|
||||||
use genawaiter::GeneratorState;
|
use genawaiter::GeneratorState;
|
||||||
use harness::{
|
use harness::{
|
||||||
@ -18,6 +18,7 @@ use monero_harness::Monero;
|
|||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use testcontainers::clients::Cli;
|
use testcontainers::clients::Cli;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
use tracing_subscriber::util::SubscriberInitExt;
|
||||||
use xmr_btc::{
|
use xmr_btc::{
|
||||||
alice::{self, ReceiveBitcoinRedeemEncsig},
|
alice::{self, ReceiveBitcoinRedeemEncsig},
|
||||||
bitcoin::{BroadcastSignedTransaction, EncryptedSignature, SignTxLock},
|
bitcoin::{BroadcastSignedTransaction, EncryptedSignature, SignTxLock},
|
||||||
@ -80,12 +81,32 @@ impl Default for AliceBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BobBehaviour {
|
||||||
|
lock_btc: bool,
|
||||||
|
send_btc_redeem_encsig: bool,
|
||||||
|
create_monero_wallet_for_output: bool,
|
||||||
|
cancel_btc: bool,
|
||||||
|
refund_btc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BobBehaviour {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
lock_btc: true,
|
||||||
|
send_btc_redeem_encsig: true,
|
||||||
|
create_monero_wallet_for_output: true,
|
||||||
|
cancel_btc: true,
|
||||||
|
refund_btc: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn swap_as_alice(
|
async fn swap_as_alice(
|
||||||
network: AliceNetwork,
|
network: AliceNetwork,
|
||||||
// FIXME: It would be more intuitive to have a single network/transport struct instead of
|
// FIXME: It would be more intuitive to have a single network/transport struct instead of
|
||||||
// splitting into two, but Rust ownership rules make this tedious
|
// splitting into two, but Rust ownership rules make this tedious
|
||||||
mut sender: Sender<TransferProof>,
|
mut sender: Sender<TransferProof>,
|
||||||
monero_wallet: &harness::wallet::monero::Wallet,
|
monero_wallet: Arc<harness::wallet::monero::Wallet>,
|
||||||
bitcoin_wallet: Arc<harness::wallet::bitcoin::Wallet>,
|
bitcoin_wallet: Arc<harness::wallet::bitcoin::Wallet>,
|
||||||
behaviour: AliceBehaviour,
|
behaviour: AliceBehaviour,
|
||||||
state: alice::State3,
|
state: alice::State3,
|
||||||
@ -151,6 +172,7 @@ async fn swap_as_bob(
|
|||||||
mut sender: Sender<EncryptedSignature>,
|
mut sender: Sender<EncryptedSignature>,
|
||||||
monero_wallet: Arc<harness::wallet::monero::Wallet>,
|
monero_wallet: Arc<harness::wallet::monero::Wallet>,
|
||||||
bitcoin_wallet: Arc<harness::wallet::bitcoin::Wallet>,
|
bitcoin_wallet: Arc<harness::wallet::bitcoin::Wallet>,
|
||||||
|
behaviour: BobBehaviour,
|
||||||
state: bob::State2,
|
state: bob::State2,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut action_generator = bob::action_generator(
|
let mut action_generator = bob::action_generator(
|
||||||
@ -168,31 +190,41 @@ async fn swap_as_bob(
|
|||||||
|
|
||||||
match state {
|
match state {
|
||||||
GeneratorState::Yielded(bob::Action::LockBtc(tx_lock)) => {
|
GeneratorState::Yielded(bob::Action::LockBtc(tx_lock)) => {
|
||||||
let signed_tx_lock = bitcoin_wallet.sign_tx_lock(tx_lock).await?;
|
if behaviour.lock_btc {
|
||||||
let _ = bitcoin_wallet
|
let signed_tx_lock = bitcoin_wallet.sign_tx_lock(tx_lock).await?;
|
||||||
.broadcast_signed_transaction(signed_tx_lock)
|
let _ = bitcoin_wallet
|
||||||
.await?;
|
.broadcast_signed_transaction(signed_tx_lock)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeneratorState::Yielded(bob::Action::SendBtcRedeemEncsig(tx_redeem_encsig)) => {
|
GeneratorState::Yielded(bob::Action::SendBtcRedeemEncsig(tx_redeem_encsig)) => {
|
||||||
sender.send(tx_redeem_encsig).await.unwrap();
|
if behaviour.send_btc_redeem_encsig {
|
||||||
|
sender.send(tx_redeem_encsig).await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeneratorState::Yielded(bob::Action::CreateXmrWalletForOutput {
|
GeneratorState::Yielded(bob::Action::CreateXmrWalletForOutput {
|
||||||
spend_key,
|
spend_key,
|
||||||
view_key,
|
view_key,
|
||||||
}) => {
|
}) => {
|
||||||
monero_wallet
|
if behaviour.create_monero_wallet_for_output {
|
||||||
.create_and_load_wallet_for_output(spend_key, view_key)
|
monero_wallet
|
||||||
.await?;
|
.create_and_load_wallet_for_output(spend_key, view_key)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeneratorState::Yielded(bob::Action::CancelBtc(tx_cancel)) => {
|
GeneratorState::Yielded(bob::Action::CancelBtc(tx_cancel)) => {
|
||||||
let _ = bitcoin_wallet
|
if behaviour.cancel_btc {
|
||||||
.broadcast_signed_transaction(tx_cancel)
|
let _ = bitcoin_wallet
|
||||||
.await?;
|
.broadcast_signed_transaction(tx_cancel)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeneratorState::Yielded(bob::Action::RefundBtc(tx_refund)) => {
|
GeneratorState::Yielded(bob::Action::RefundBtc(tx_refund)) => {
|
||||||
let _ = bitcoin_wallet
|
if behaviour.refund_btc {
|
||||||
.broadcast_signed_transaction(tx_refund)
|
let _ = bitcoin_wallet
|
||||||
.await?;
|
.broadcast_signed_transaction(tx_refund)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeneratorState::Complete(()) => return Ok(()),
|
GeneratorState::Complete(()) => return Ok(()),
|
||||||
}
|
}
|
||||||
@ -246,7 +278,7 @@ async fn on_chain_happy_path() {
|
|||||||
swap_as_alice(
|
swap_as_alice(
|
||||||
alice_network,
|
alice_network,
|
||||||
alice_sender,
|
alice_sender,
|
||||||
&alice_monero_wallet.clone(),
|
alice_monero_wallet.clone(),
|
||||||
alice_bitcoin_wallet.clone(),
|
alice_bitcoin_wallet.clone(),
|
||||||
AliceBehaviour::default(),
|
AliceBehaviour::default(),
|
||||||
alice,
|
alice,
|
||||||
@ -256,6 +288,7 @@ async fn on_chain_happy_path() {
|
|||||||
bob_sender,
|
bob_sender,
|
||||||
bob_monero_wallet.clone(),
|
bob_monero_wallet.clone(),
|
||||||
bob_bitcoin_wallet.clone(),
|
bob_bitcoin_wallet.clone(),
|
||||||
|
BobBehaviour::default(),
|
||||||
bob,
|
bob,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -287,7 +320,7 @@ async fn on_chain_happy_path() {
|
|||||||
|
|
||||||
// Getting the Monero LockTx fee is tricky in a clean way, I think checking this
|
// Getting the Monero LockTx fee is tricky in a clean way, I think checking this
|
||||||
// condition is sufficient
|
// condition is sufficient
|
||||||
assert!(alice_final_xmr_balance <= initial_balances.alice_xmr - swap_amounts.xmr,);
|
assert!(alice_final_xmr_balance <= initial_balances.alice_xmr - swap_amounts.xmr);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bob_final_xmr_balance,
|
bob_final_xmr_balance,
|
||||||
initial_balances.bob_xmr + swap_amounts.xmr
|
initial_balances.bob_xmr + swap_amounts.xmr
|
||||||
@ -336,7 +369,7 @@ async fn on_chain_both_refund_if_alice_never_redeems() {
|
|||||||
swap_as_alice(
|
swap_as_alice(
|
||||||
alice_network,
|
alice_network,
|
||||||
alice_sender,
|
alice_sender,
|
||||||
&alice_monero_wallet.clone(),
|
alice_monero_wallet.clone(),
|
||||||
alice_bitcoin_wallet.clone(),
|
alice_bitcoin_wallet.clone(),
|
||||||
AliceBehaviour {
|
AliceBehaviour {
|
||||||
redeem_btc: false,
|
redeem_btc: false,
|
||||||
@ -349,6 +382,7 @@ async fn on_chain_both_refund_if_alice_never_redeems() {
|
|||||||
bob_sender,
|
bob_sender,
|
||||||
bob_monero_wallet.clone(),
|
bob_monero_wallet.clone(),
|
||||||
bob_bitcoin_wallet.clone(),
|
bob_bitcoin_wallet.clone(),
|
||||||
|
BobBehaviour::default(),
|
||||||
bob,
|
bob,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -382,3 +416,103 @@ async fn on_chain_both_refund_if_alice_never_redeems() {
|
|||||||
assert_eq!(alice_final_xmr_balance, swap_amounts.xmr);
|
assert_eq!(alice_final_xmr_balance, swap_amounts.xmr);
|
||||||
assert_eq!(bob_final_xmr_balance, initial_balances.bob_xmr);
|
assert_eq!(bob_final_xmr_balance, initial_balances.bob_xmr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn on_chain_alice_punishes_if_bob_never_acts_after_fund() {
|
||||||
|
let _guard = tracing_subscriber::fmt()
|
||||||
|
.with_env_filter("info")
|
||||||
|
.with_ansi(false)
|
||||||
|
.set_default();
|
||||||
|
|
||||||
|
let cli = Cli::default();
|
||||||
|
let (monero, _container) = Monero::new(&cli).unwrap();
|
||||||
|
let bitcoind = init_bitcoind(&cli).await;
|
||||||
|
|
||||||
|
let (alice_state0, bob_state0, mut alice_node, mut bob_node, initial_balances, swap_amounts) =
|
||||||
|
init_test(&monero, &bitcoind, Some(10), Some(10)).await;
|
||||||
|
|
||||||
|
// run the handshake as part of the setup
|
||||||
|
let (alice_state, bob_state) = try_join(
|
||||||
|
run_alice_until(
|
||||||
|
&mut alice_node,
|
||||||
|
alice_state0.into(),
|
||||||
|
harness::alice::is_state3,
|
||||||
|
&mut OsRng,
|
||||||
|
),
|
||||||
|
run_bob_until(
|
||||||
|
&mut bob_node,
|
||||||
|
bob_state0.into(),
|
||||||
|
harness::bob::is_state2,
|
||||||
|
&mut OsRng,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let alice: alice::State3 = alice_state.try_into().unwrap();
|
||||||
|
let bob: bob::State2 = bob_state.try_into().unwrap();
|
||||||
|
let tx_lock_txid = bob.tx_lock.txid();
|
||||||
|
|
||||||
|
let alice_bitcoin_wallet = Arc::new(alice_node.bitcoin_wallet);
|
||||||
|
let bob_bitcoin_wallet = Arc::new(bob_node.bitcoin_wallet);
|
||||||
|
let alice_monero_wallet = Arc::new(alice_node.monero_wallet);
|
||||||
|
let bob_monero_wallet = Arc::new(bob_node.monero_wallet);
|
||||||
|
|
||||||
|
let (alice_network, bob_sender) = Network::<EncryptedSignature>::new();
|
||||||
|
let (bob_network, alice_sender) = Network::<TransferProof>::new();
|
||||||
|
|
||||||
|
let alice_swap = swap_as_alice(
|
||||||
|
alice_network,
|
||||||
|
alice_sender,
|
||||||
|
alice_monero_wallet.clone(),
|
||||||
|
alice_bitcoin_wallet.clone(),
|
||||||
|
AliceBehaviour::default(),
|
||||||
|
alice,
|
||||||
|
);
|
||||||
|
let bob_swap = swap_as_bob(
|
||||||
|
bob_network,
|
||||||
|
bob_sender,
|
||||||
|
bob_monero_wallet.clone(),
|
||||||
|
bob_bitcoin_wallet.clone(),
|
||||||
|
BobBehaviour {
|
||||||
|
send_btc_redeem_encsig: false,
|
||||||
|
create_monero_wallet_for_output: false,
|
||||||
|
cancel_btc: false,
|
||||||
|
refund_btc: false,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
bob,
|
||||||
|
);
|
||||||
|
|
||||||
|
pin_mut!(alice_swap);
|
||||||
|
pin_mut!(bob_swap);
|
||||||
|
|
||||||
|
// since we model Bob as inactive after locking bitcoin, his future does not
|
||||||
|
// resolve, so we wait for one of the two (Alice's) to resolve via select
|
||||||
|
select(alice_swap, bob_swap).await;
|
||||||
|
|
||||||
|
let alice_final_btc_balance = alice_bitcoin_wallet.balance().await.unwrap();
|
||||||
|
let bob_final_btc_balance = bob_bitcoin_wallet.balance().await.unwrap();
|
||||||
|
|
||||||
|
let lock_tx_bitcoin_fee = bob_bitcoin_wallet
|
||||||
|
.transaction_fee(tx_lock_txid)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let alice_final_xmr_balance = alice_monero_wallet.get_balance().await.unwrap();
|
||||||
|
let bob_final_xmr_balance = bob_monero_wallet.get_balance().await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
alice_final_btc_balance,
|
||||||
|
initial_balances.alice_btc + swap_amounts.btc
|
||||||
|
- bitcoin::Amount::from_sat(2 * xmr_btc::bitcoin::TX_FEE)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
bob_final_btc_balance,
|
||||||
|
initial_balances.bob_btc - swap_amounts.btc - lock_tx_bitcoin_fee
|
||||||
|
);
|
||||||
|
|
||||||
|
// Getting the Monero LockTx fee is tricky in a clean way, I think checking this
|
||||||
|
// condition is sufficient
|
||||||
|
assert!(alice_final_xmr_balance <= initial_balances.alice_xmr - swap_amounts.xmr,);
|
||||||
|
assert_eq!(bob_final_xmr_balance, initial_balances.bob_xmr);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user