Make --force the default behaviour for manual recovery

Remove the force flag. There is a resume command that tries to
gracefully restarts the protocol and tries to execute the happy path.
Remove e2e tests which test the --force flag.
This commit is contained in:
rishflab 2021-09-02 09:16:25 +10:00
parent 54061f941b
commit f511ff093c
18 changed files with 148 additions and 482 deletions

View file

@ -1,22 +1,15 @@
use crate::bitcoin::{ExpiredTimelocks, Txid, Wallet};
use crate::bitcoin::{Txid, Wallet};
use crate::database::{Database, Swap};
use crate::protocol::bob::BobState;
use anyhow::{bail, Result};
use std::sync::Arc;
use uuid::Uuid;
#[derive(Debug, thiserror::Error, Clone, Copy)]
pub enum Error {
#[error("The cancel timelock has not expired yet.")]
CancelTimelockNotExpiredYet,
}
pub async fn cancel(
swap_id: Uuid,
bitcoin_wallet: Arc<Wallet>,
db: Database,
force: bool,
) -> Result<Result<(Txid, BobState), Error>> {
) -> Result<(Txid, BobState)> {
let state = db.get_state(swap_id)?.try_into_bob()?.into();
let state6 = match state {
@ -25,11 +18,12 @@ pub async fn cancel(
BobState::XmrLocked(state4) => state4.cancel(),
BobState::EncSigSent(state4) => state4.cancel(),
BobState::CancelTimelockExpired(state6) => state6,
BobState::BtcRefunded(state6) => state6,
BobState::BtcCancelled(state6) => state6,
BobState::Started { .. }
| BobState::SwapSetupCompleted(_)
| BobState::BtcRedeemed(_)
| BobState::BtcCancelled(_)
| BobState::BtcRefunded(_)
| BobState::XmrRedeemed { .. }
| BobState::BtcPunished { .. }
| BobState::SafelyAborted => bail!(
@ -41,25 +35,19 @@ pub async fn cancel(
tracing::info!(%swap_id, "Manually cancelling swap");
if !force {
tracing::debug!(%swap_id, "Checking if cancel timelock is expired");
if let ExpiredTimelocks::None = state6.expired_timelock(bitcoin_wallet.as_ref()).await? {
return Ok(Err(Error::CancelTimelockNotExpiredYet));
let txid = match state6.submit_tx_cancel(bitcoin_wallet.as_ref()).await {
Ok(txid) => txid,
Err(err) => {
if let Some(bdk::Error::TransactionConfirmed) = err.downcast_ref::<bdk::Error>() {
tracing::info!("Cancel transaction has already been published and confirmed")
};
bail!(err);
}
}
let txid = if let Ok(tx) = state6.check_for_tx_cancel(bitcoin_wallet.as_ref()).await {
tracing::debug!(%swap_id, "Cancel transaction has already been published");
tx.txid()
} else {
state6.submit_tx_cancel(bitcoin_wallet.as_ref()).await?
};
let state = BobState::BtcCancelled(state6);
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
Ok(Ok((txid, state)))
Ok((txid, state))
}

View file

@ -171,7 +171,6 @@ where
}
RawCommand::Cancel {
swap_id: SwapId { swap_id },
force,
bitcoin,
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
@ -184,7 +183,6 @@ where
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Cancel {
swap_id,
force,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
},
@ -192,7 +190,6 @@ where
}
RawCommand::Refund {
swap_id: SwapId { swap_id },
force,
bitcoin,
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
@ -205,7 +202,6 @@ where
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Refund {
swap_id,
force,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
},
@ -261,13 +257,11 @@ pub enum Command {
},
Cancel {
swap_id: Uuid,
force: bool,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
},
Refund {
swap_id: Uuid,
force: bool,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
},
@ -376,25 +370,21 @@ enum RawCommand {
#[structopt(flatten)]
tor: Tor,
},
/// Try to cancel an ongoing swap (expert users only)
/// Force submission of the cancel transaction overriding the protocol state
/// machine and blockheight checks (expert users only)
Cancel {
#[structopt(flatten)]
swap_id: SwapId,
#[structopt(short, long)]
force: bool,
#[structopt(flatten)]
bitcoin: Bitcoin,
},
/// Try to cancel a swap and refund the BTC (expert users only)
/// Force submission of the refund transaction overriding the protocol state
/// machine and blockheight checks (expert users only)
Refund {
#[structopt(flatten)]
swap_id: SwapId,
#[structopt(short, long)]
force: bool,
#[structopt(flatten)]
bitcoin: Bitcoin,
},
@ -1190,7 +1180,6 @@ mod tests {
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::Cancel {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
force: false,
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
@ -1206,7 +1195,6 @@ mod tests {
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::Cancel {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
force: false,
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
},
@ -1221,7 +1209,6 @@ mod tests {
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::Refund {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
force: false,
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
@ -1237,7 +1224,6 @@ mod tests {
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::Refund {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
force: false,
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
},

View file

@ -5,45 +5,27 @@ use anyhow::{bail, Result};
use std::sync::Arc;
use uuid::Uuid;
#[derive(thiserror::Error, Debug, Clone, Copy)]
#[error("Cannot refund because swap {0} was not cancelled yet. Make sure to cancel the swap before trying to refund.")]
pub struct SwapNotCancelledYet(pub Uuid);
pub async fn refund(
swap_id: Uuid,
bitcoin_wallet: Arc<Wallet>,
db: Database,
force: bool,
) -> Result<Result<BobState, SwapNotCancelledYet>> {
pub async fn refund(swap_id: Uuid, bitcoin_wallet: Arc<Wallet>, db: Database) -> Result<BobState> {
let state = db.get_state(swap_id)?.try_into_bob()?.into();
let state6 = if force {
match state {
BobState::BtcLocked(state3) => state3.cancel(),
BobState::XmrLockProofReceived { state, .. } => state.cancel(),
BobState::XmrLocked(state4) => state4.cancel(),
BobState::EncSigSent(state4) => state4.cancel(),
BobState::CancelTimelockExpired(state6) => state6,
BobState::BtcCancelled(state6) => state6,
BobState::Started { .. }
| BobState::SwapSetupCompleted(_)
| BobState::BtcRedeemed(_)
| BobState::BtcRefunded(_)
| BobState::XmrRedeemed { .. }
| BobState::BtcPunished { .. }
| BobState::SafelyAborted => bail!(
"Cannot refund swap {} because it is in state {} which is not refundable.",
swap_id,
state
),
}
} else {
match state {
BobState::BtcCancelled(state6) => state6,
_ => {
return Ok(Err(SwapNotCancelledYet(swap_id)));
}
}
let state6 = match state {
BobState::BtcLocked(state3) => state3.cancel(),
BobState::XmrLockProofReceived { state, .. } => state.cancel(),
BobState::XmrLocked(state4) => state4.cancel(),
BobState::EncSigSent(state4) => state4.cancel(),
BobState::CancelTimelockExpired(state6) => state6,
BobState::BtcCancelled(state6) => state6,
BobState::Started { .. }
| BobState::SwapSetupCompleted(_)
| BobState::BtcRedeemed(_)
| BobState::BtcRefunded(_)
| BobState::XmrRedeemed { .. }
| BobState::BtcPunished { .. }
| BobState::SafelyAborted => bail!(
"Cannot refund swap {} because it is in state {} which is not refundable.",
swap_id,
state
),
};
state6.publish_refund_btc(bitcoin_wallet.as_ref()).await?;
@ -53,5 +35,5 @@ pub async fn refund(
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
Ok(Ok(state))
Ok(state)
}