diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 55c305a2..4a767c79 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -290,22 +290,30 @@ async fn run_until_internal( state3.B, )?; - let punish_tx_finalised = async { + let punish = async { let (txid, finality) = bitcoin_wallet.broadcast(signed_tx_punish, "punish").await?; - finality.await?; Result::<_, anyhow::Error>::Ok(txid) - }; + } + .await; - let tx_refund = state3.tx_refund(); - let refund_tx_seen = - bitcoin_wallet.watch_until_status(&tx_refund, |status| status.has_been_seen()); + match punish { + Ok(_) => AliceState::BtcPunished, + Err(e) => { + tracing::warn!( + "Falling back to refund because punish transaction failed with {:#}", + e + ); - select! { - result = refund_tx_seen => { - result.context("Failed to monitor refund transaction")?; + // Upon punish failure we assume that the refund tx was included but we + // missed seeing it. In case we fail to fetch the refund tx we fail + // with no state update because it is unclear what state we should transition + // to. It does not help to race punish and refund inclusion, + // because a punish tx failure is not recoverable (besides re-trying) if the + // refund tx was not included. + let tx_refund = state3.tx_refund(); let published_refund_tx = bitcoin_wallet.get_raw_transaction(tx_refund.txid()).await?; @@ -315,15 +323,13 @@ async fn run_until_internal( state3.a.clone(), state3.S_b_bitcoin, )?; + AliceState::BtcRefunded { spend_key, state3, monero_wallet_restore_blockheight, } } - _ = punish_tx_finalised => { - AliceState::BtcPunished - } } } AliceState::XmrRefunded => AliceState::XmrRefunded,