From dfd69c9c800ec699248dbd4af9196cdaf0ac8715 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Thu, 25 Mar 2021 11:16:34 +1100 Subject: [PATCH] Alice aborts if any timelock expired before locking XMR Once we resume unfinished swaps upon startup we have to ensure that it is safe for Alice to act. If Bob has locked BTC it is only make sense for Alice to lock up the XMR as long as no timelock has expired. Hence we abort if the BTC is locked, but any timelock expired already. --- swap/src/protocol/alice/swap.rs | 52 ++++++++++++++++++--------------- swap/tests/harness/mod.rs | 4 +-- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index dc732bf7..e090e8d5 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -88,36 +88,42 @@ async fn next_state( } } } - AliceState::BtcLocked { state3 } => { - // Record the current monero wallet block height so we don't have to scan from - // block 0 for scenarios where we create a refund wallet. - let monero_wallet_restore_blockheight = monero_wallet.block_height().await?; + AliceState::BtcLocked { state3 } => match state3 + .expired_timelocks(bitcoin_wallet) + .await? + { + ExpiredTimelocks::None => { + // Record the current monero wallet block height so we don't have to scan from + // block 0 for scenarios where we create a refund wallet. + let monero_wallet_restore_blockheight = monero_wallet.block_height().await?; - let transfer_proof = monero_wallet - .transfer(state3.lock_xmr_transfer_request()) - .await?; + let transfer_proof = monero_wallet + .transfer(state3.lock_xmr_transfer_request()) + .await?; - monero_wallet - .watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof.clone(), 1)) - .await?; + monero_wallet + .watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof.clone(), 1)) + .await?; - // TODO: Waiting for XMR confirmations should be done in a separate - // state! We have to record that Alice has already sent the transaction. - // Otherwise Alice might publish the lock tx twice! + // TODO: Waiting for XMR confirmations should be done in a separate + // state! We have to record that Alice has already sent the transaction. + // Otherwise Alice might publish the lock tx twice! - event_loop_handle - .send_transfer_proof(transfer_proof.clone()) - .await?; + event_loop_handle + .send_transfer_proof(transfer_proof.clone()) + .await?; - monero_wallet - .watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof, 10)) - .await?; + monero_wallet + .watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof, 10)) + .await?; - AliceState::XmrLocked { - state3, - monero_wallet_restore_blockheight, + AliceState::XmrLocked { + state3, + monero_wallet_restore_blockheight, + } } - } + _ => AliceState::SafelyAborted, + }, AliceState::XmrLocked { state3, monero_wallet_restore_blockheight, diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 8fafe985..e41f4ab1 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -835,7 +835,7 @@ pub struct FastCancelConfig; impl GetConfig for FastCancelConfig { fn get_config() -> Config { Config { - bitcoin_cancel_timelock: CancelTimelock::new(1), + bitcoin_cancel_timelock: CancelTimelock::new(10), ..env::Regtest::get_config() } } @@ -846,7 +846,7 @@ pub struct FastPunishConfig; impl GetConfig for FastPunishConfig { fn get_config() -> Config { Config { - bitcoin_cancel_timelock: CancelTimelock::new(1), + bitcoin_cancel_timelock: CancelTimelock::new(10), bitcoin_punish_timelock: PunishTimelock::new(1), ..env::Regtest::get_config() }