Fix multiple things

This commit is contained in:
patrini32 2024-06-05 12:24:35 +03:00 committed by patrini32
parent 039db6babe
commit bc9c3ff402
3 changed files with 78 additions and 45 deletions

View File

@ -1,5 +1,5 @@
use crate::bitcoin::{parse_rpc_error_code, RpcErrorCode, Wallet};
use crate::protocol::bob::BobState;
use crate::protocol::bob::{BobState, BtcCancelledByAlice, BtcPunishedWhileRefundError};
use crate::protocol::Database;
use anyhow::{bail, Result};
use bitcoin::Txid;
@ -16,12 +16,11 @@ pub async fn cancel_and_refund(
};
let state = match refund(swap_id, bitcoin_wallet, db).await {
Ok(s) => {
tracing::info!("Refund transaction submitted");
s
}
Ok(s) => s,
Err(e) => bail!(e),
};
tracing::info!("Refund transaction submitted");
Ok(state)
}
@ -65,24 +64,21 @@ pub async fn cancel(
Err(err) => {
if let Ok(error_code) = parse_rpc_error_code(&err) {
if error_code == i64::from(RpcErrorCode::RpcVerifyError) {
if err
.to_string()
.contains("Failed to broadcast Bitcoin refund transaction")
{
let txid = state6
.construct_tx_cancel()
.expect("Error when constructing tx_cancel")
.txid();
let state = BobState::BtcCancelled(state6);
db.insert_latest_state(swap_id, state.clone().into())
.await?;
tracing::info!("Cancel transaction has already been confirmed on chain. The swap has therefore already been cancelled by Alice.");
return Ok((txid, state));
} else {
tracing::debug!(%error_code, "parse rpc error");
tracing::info!("General error trying to submit cancel transaction");
}
tracing::debug!(%error_code, "parse rpc error");
tracing::info!("General error trying to submit cancel transaction");
} else if error_code == i64::from(RpcErrorCode::RpcVerifyAlreadyInChain) {
tracing::info!("Cancel transaction has already been confirmed on chain");
}
} else if let Some(error) = err.downcast_ref::<BtcCancelledByAlice>() {
let txid = state6
.construct_tx_cancel()
.expect("Error when constructing tx_cancel")
.txid();
let state = BobState::BtcCancelled(state6);
db.insert_latest_state(swap_id, state.clone().into())
.await?;
tracing::info!(%error);
return Ok((txid, state));
}
bail!(err);
}
@ -116,29 +112,24 @@ pub async fn refund(
};
tracing::info!(%swap_id, "Manually refunding swap");
match state6.publish_refund_btc(bitcoin_wallet.as_ref()).await {
Ok(_) => (),
Err(refund_error) => {
if refund_error
.to_string()
.contains("Failed to broadcast Bitcoin refund transaction")
{
Ok(()) => {
let state = BobState::BtcRefunded(state6);
db.insert_latest_state(swap_id, state.clone().into())
.await?;
Ok(state)
}
Err(error) => {
if let Some(error) = error.downcast_ref::<BtcPunishedWhileRefundError>() {
tracing::info!(%error);
let state = BobState::BtcPunished {
tx_lock_id: state6.tx_lock_id(),
};
db.insert_latest_state(swap_id, state.clone().into())
.await?;
tracing::info!("Cannot refund because BTC is punished by Alice.");
return Ok(state);
}
bail!(refund_error);
bail!(error);
}
}
let state = BobState::BtcRefunded(state6);
db.insert_latest_state(swap_id, state.clone().into())
.await?;
Ok(state)
}

View File

@ -20,6 +20,20 @@ use sha2::Sha256;
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
use std::fmt;
use uuid::Uuid;
#[derive(Debug)]
pub struct BtcCancelledByAlice;
impl std::fmt::Display for BtcCancelledByAlice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Cancel transaction has already been confirmed on chain. The swap has therefore already been cancelled by Alice.")
}
}
#[derive(Debug)]
pub struct BtcPunishedWhileRefundError;
impl std::fmt::Display for BtcPunishedWhileRefundError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Cannot refund because BTC is punished.")
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum BobState {
@ -663,6 +677,7 @@ impl State6 {
Ok(tx)
}
pub fn construct_tx_cancel(&self) -> Result<Transaction> {
bitcoin::TxCancel::new(
&self.tx_lock,
@ -674,24 +689,51 @@ impl State6 {
.complete_as_bob(self.A, self.b.clone(), self.tx_cancel_sig_a.clone())
.context("Failed to complete Bitcoin cancel transaction")
}
pub fn print_type_of<T>(&self, _: &T) {
tracing::debug!("{}", std::any::type_name::<T>())
}
pub async fn submit_tx_cancel(
&self,
bitcoin_wallet: &bitcoin::Wallet,
) -> Result<(Txid, Subscription)> {
let transaction = self.construct_tx_cancel()?;
let (tx_id, subscription) = bitcoin_wallet.broadcast(transaction, "cancel").await?;
Ok((tx_id, subscription))
match bitcoin_wallet.broadcast(transaction, "cancel").await {
Ok((txid, subscription)) => Ok((txid, subscription)),
Err(error) => {
match error.downcast_ref::<bdk::Error>() {
Some(bdk::Error::Electrum(bdk::electrum_client::Error::Protocol(serde_json::Value::String(ref protocol_error))))
// UTXO is already spent, swap timeout.
if protocol_error.contains("bad-txns-inputs-missingorspent") =>
{
return Err(anyhow!(BtcCancelledByAlice));
}
_ => {
Err(error)
}
}
}
}
}
pub async fn publish_refund_btc(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result<()> {
let signed_tx_refund = self.signed_refund_transaction()?;
bitcoin_wallet.broadcast(signed_tx_refund, "refund").await?;
Ok(())
match bitcoin_wallet.broadcast(signed_tx_refund, "refund").await {
Ok((_, _)) => Ok(()),
Err(error) => {
match error.downcast_ref::<bdk::Error>() {
Some(bdk::Error::Electrum(bdk::electrum_client::Error::Protocol(serde_json::Value::String(ref protocol_error))))
if protocol_error.contains("bad-txns-inputs-missingorspent") =>
{
return Err(anyhow!(BtcPunishedWhileRefundError));
}
_ => {
Err(error)
}
}
}
}
}
pub fn signed_refund_transaction(&self) -> Result<Transaction> {
let tx_cancel = bitcoin::TxCancel::new(
&self.tx_lock,

View File

@ -76,7 +76,7 @@ async fn alice_manually_punishes_after_bob_dead_and_bob_cancels() {
let state =
cli::cancel_and_refund(bob_swap_id, bob_swap.bitcoin_wallet, bob_swap.db).await?;
assert!(matches!(state, BobState::BtcPunished { .. }));
assert!(matches!(state, BobState::BtcPunished { .. }));
Ok(())
})
.await;