Make lock-tx id available in redeem/punish state to be able to assert exact fees

This commit is contained in:
Daniel Karzel 2021-01-18 14:45:47 +11:00
parent 317b251302
commit 8615aaed6e
6 changed files with 63 additions and 30 deletions

View file

@ -130,7 +130,7 @@ mod tests {
.await .await
.expect("Failed to save second state"); .expect("Failed to save second state");
let state_2 = Swap::Bob(Bob::Done(BobEndState::XmrRedeemed)); let state_2 = Swap::Bob(Bob::Done(BobEndState::SafelyAborted));
let swap_id_2 = Uuid::new_v4(); let swap_id_2 = Uuid::new_v4();
db.insert_latest_state(swap_id_2, state_2.clone()) db.insert_latest_state(swap_id_2, state_2.clone())
.await .await
@ -186,7 +186,7 @@ mod tests {
.await .await
.expect("Failed to save second state"); .expect("Failed to save second state");
let state_2 = Swap::Bob(Bob::Done(BobEndState::BtcPunished)); let state_2 = Swap::Bob(Bob::Done(BobEndState::SafelyAborted));
let swap_id_2 = Uuid::new_v4(); let swap_id_2 = Uuid::new_v4();
db.insert_latest_state(swap_id_2, state_2.clone()) db.insert_latest_state(swap_id_2, state_2.clone())
.await .await

View file

@ -33,9 +33,9 @@ pub enum Bob {
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)] #[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum BobEndState { pub enum BobEndState {
SafelyAborted, SafelyAborted,
XmrRedeemed, XmrRedeemed(Box<bob::State6>),
BtcRefunded(Box<bob::State4>), BtcRefunded(Box<bob::State4>),
BtcPunished, BtcPunished(Box<bob::State6>),
} }
impl From<BobState> for Bob { impl From<BobState> for Bob {
@ -50,8 +50,8 @@ impl From<BobState> for Bob {
BobState::CancelTimelockExpired(state4) => Bob::CancelTimelockExpired(state4), BobState::CancelTimelockExpired(state4) => Bob::CancelTimelockExpired(state4),
BobState::BtcCancelled(state4) => Bob::BtcCancelled(state4), BobState::BtcCancelled(state4) => Bob::BtcCancelled(state4),
BobState::BtcRefunded(state4) => Bob::Done(BobEndState::BtcRefunded(Box::new(state4))), BobState::BtcRefunded(state4) => Bob::Done(BobEndState::BtcRefunded(Box::new(state4))),
BobState::XmrRedeemed => Bob::Done(BobEndState::XmrRedeemed), BobState::XmrRedeemed(state6) => Bob::Done(BobEndState::XmrRedeemed(Box::new(state6))),
BobState::BtcPunished => Bob::Done(BobEndState::BtcPunished), BobState::BtcPunished(state6) => Bob::Done(BobEndState::BtcPunished(Box::new(state6))),
BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted), BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted),
} }
} }
@ -70,9 +70,9 @@ impl From<Bob> for BobState {
Bob::BtcCancelled(state4) => BobState::BtcCancelled(state4), Bob::BtcCancelled(state4) => BobState::BtcCancelled(state4),
Bob::Done(end_state) => match end_state { Bob::Done(end_state) => match end_state {
BobEndState::SafelyAborted => BobState::SafelyAborted, BobEndState::SafelyAborted => BobState::SafelyAborted,
BobEndState::XmrRedeemed => BobState::XmrRedeemed, BobEndState::XmrRedeemed(state6) => BobState::XmrRedeemed(*state6),
BobEndState::BtcRefunded(state4) => BobState::BtcRefunded(*state4), BobEndState::BtcRefunded(state4) => BobState::BtcRefunded(*state4),
BobEndState::BtcPunished => BobState::BtcPunished, BobEndState::BtcPunished(state6) => BobState::BtcPunished(*state6),
}, },
} }
} }

View file

@ -35,8 +35,8 @@ pub enum BobState {
CancelTimelockExpired(State4), CancelTimelockExpired(State4),
BtcCancelled(State4), BtcCancelled(State4),
BtcRefunded(State4), BtcRefunded(State4),
XmrRedeemed, XmrRedeemed(State6),
BtcPunished, BtcPunished(State6),
SafelyAborted, SafelyAborted,
} }
@ -52,8 +52,8 @@ impl fmt::Display for BobState {
BobState::CancelTimelockExpired(..) => write!(f, "cancel timelock is expired"), BobState::CancelTimelockExpired(..) => write!(f, "cancel timelock is expired"),
BobState::BtcCancelled(..) => write!(f, "btc is cancelled"), BobState::BtcCancelled(..) => write!(f, "btc is cancelled"),
BobState::BtcRefunded(..) => write!(f, "btc is refunded"), BobState::BtcRefunded(..) => write!(f, "btc is refunded"),
BobState::XmrRedeemed => write!(f, "xmr is redeemed"), BobState::XmrRedeemed(..) => write!(f, "xmr is redeemed"),
BobState::BtcPunished => write!(f, "btc is punished"), BobState::BtcPunished(..) => write!(f, "btc is punished"),
BobState::SafelyAborted => write!(f, "safely aborted"), BobState::SafelyAborted => write!(f, "safely aborted"),
} }
} }
@ -592,6 +592,12 @@ impl State4 {
pub fn tx_lock_id(&self) -> bitcoin::Txid { pub fn tx_lock_id(&self) -> bitcoin::Txid {
self.tx_lock.txid() self.tx_lock.txid()
} }
pub fn state6(&self) -> State6 {
State6 {
tx_lock_id: self.tx_lock.txid(),
}
}
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
@ -644,4 +650,21 @@ impl State5 {
pub fn tx_lock_id(&self) -> bitcoin::Txid { pub fn tx_lock_id(&self) -> bitcoin::Txid {
self.tx_lock.txid() self.tx_lock.txid()
} }
pub fn state6(&self) -> State6 {
State6 {
tx_lock_id: self.tx_lock.txid(),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct State6 {
pub tx_lock_id: Txid,
}
impl State6 {
pub fn tx_lock_id(&self) -> bitcoin::Txid {
self.tx_lock_id
}
} }

View file

@ -45,8 +45,8 @@ pub fn is_complete(state: &BobState) -> bool {
matches!( matches!(
state, state,
BobState::BtcRefunded(..) BobState::BtcRefunded(..)
| BobState::XmrRedeemed | BobState::XmrRedeemed { .. }
| BobState::BtcPunished | BobState::BtcPunished { .. }
| BobState::SafelyAborted | BobState::SafelyAborted
) )
} }
@ -273,7 +273,7 @@ where
// Bob redeems XMR using revealed s_a // Bob redeems XMR using revealed s_a
state.claim_xmr(monero_wallet.as_ref()).await?; state.claim_xmr(monero_wallet.as_ref()).await?;
let state = BobState::XmrRedeemed; let state = BobState::XmrRedeemed(state.state6());
let db_state = state.clone().into(); let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until( run_until(
@ -323,7 +323,7 @@ where
state.refund_btc(bitcoin_wallet.as_ref()).await?; state.refund_btc(bitcoin_wallet.as_ref()).await?;
BobState::BtcRefunded(state) BobState::BtcRefunded(state)
} }
ExpiredTimelocks::Punish => BobState::BtcPunished, ExpiredTimelocks::Punish => BobState::BtcPunished(state.state6()),
}; };
let db_state = state.clone().into(); let db_state = state.clone().into();
@ -341,9 +341,9 @@ where
.await .await
} }
BobState::BtcRefunded(state4) => Ok(BobState::BtcRefunded(state4)), BobState::BtcRefunded(state4) => Ok(BobState::BtcRefunded(state4)),
BobState::BtcPunished => Ok(BobState::BtcPunished), BobState::BtcPunished(state6) => Ok(BobState::BtcPunished(state6)),
BobState::SafelyAborted => Ok(BobState::SafelyAborted), BobState::SafelyAborted => Ok(BobState::SafelyAborted),
BobState::XmrRedeemed => Ok(BobState::XmrRedeemed), BobState::XmrRedeemed(state6) => Ok(BobState::XmrRedeemed(state6)),
} }
} }
} }

View file

@ -45,13 +45,6 @@ async fn alice_punishes_if_bob_never_acts_after_fund() {
let bob = bob_harness.recover_bob_from_db().await; let bob = bob_harness.recover_bob_from_db().await;
assert!(matches!(bob.state, BobState::BtcLocked {..})); assert!(matches!(bob.state, BobState::BtcLocked {..}));
// TODO: make lock-tx-id available in final states
let lock_tx_id = if let BobState::BtcLocked(state3) = bob_state {
state3.tx_lock_id()
} else {
panic!("Bob in unexpected state");
};
let bob_state = bob::swap( let bob_state = bob::swap(
bob.state, bob.state,
bob.event_loop_handle, bob.event_loop_handle,
@ -64,7 +57,7 @@ async fn alice_punishes_if_bob_never_acts_after_fund() {
.await .await
.unwrap(); .unwrap();
bob_harness.assert_punished(bob_state, lock_tx_id).await; bob_harness.assert_punished(bob_state).await;
}) })
.await; .await;
} }

View file

@ -363,10 +363,23 @@ impl BobHarness {
} }
pub async fn assert_redeemed(&self, state: BobState) { pub async fn assert_redeemed(&self, state: BobState) {
assert!(matches!(state, BobState::XmrRedeemed)); let lock_tx_id = if let BobState::XmrRedeemed(state6) = state {
state6.tx_lock_id()
} else {
panic!("Bob in unexpected state");
};
let lock_tx_bitcoin_fee = self
.bitcoin_wallet
.transaction_fee(lock_tx_id)
.await
.unwrap();
let btc_balance_after_swap = self.bitcoin_wallet.as_ref().balance().await.unwrap(); let btc_balance_after_swap = self.bitcoin_wallet.as_ref().balance().await.unwrap();
assert!(btc_balance_after_swap <= self.starting_balances.btc - self.swap_amounts.btc); assert_eq!(
btc_balance_after_swap,
self.starting_balances.btc - self.swap_amounts.btc - lock_tx_bitcoin_fee
);
// Ensure that Bob's balance is refreshed as we use a newly created wallet // Ensure that Bob's balance is refreshed as we use a newly created wallet
self.monero_wallet.as_ref().inner.refresh().await.unwrap(); self.monero_wallet.as_ref().inner.refresh().await.unwrap();
@ -409,8 +422,12 @@ impl BobHarness {
assert_eq!(xmr_balance_after_swap, self.starting_balances.xmr); assert_eq!(xmr_balance_after_swap, self.starting_balances.xmr);
} }
pub async fn assert_punished(&self, state: BobState, lock_tx_id: ::bitcoin::Txid) { pub async fn assert_punished(&self, state: BobState) {
assert!(matches!(state, BobState::BtcPunished)); let lock_tx_id = if let BobState::BtcPunished(state6) = state {
state6.tx_lock_id()
} else {
panic!("Bob in unexpected state");
};
let lock_tx_bitcoin_fee = self let lock_tx_bitcoin_fee = self
.bitcoin_wallet .bitcoin_wallet