mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-07-01 09:01:39 +00:00
Allow Bob to exit execution at a specified state
This commit is contained in:
parent
150e5f2aba
commit
584cc22024
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3369,6 +3369,7 @@ dependencies = [
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"bitcoin-harness",
|
"bitcoin-harness",
|
||||||
"conquer-once",
|
"conquer-once",
|
||||||
|
"conquer-once",
|
||||||
"derivative",
|
"derivative",
|
||||||
"ecdsa_fun",
|
"ecdsa_fun",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
|
@ -33,10 +33,31 @@ pub enum BobState {
|
||||||
SafelyAborted,
|
SafelyAborted,
|
||||||
}
|
}
|
||||||
|
|
||||||
// State machine driver for swap execution
|
|
||||||
#[async_recursion]
|
|
||||||
pub async fn swap<R>(
|
pub async fn swap<R>(
|
||||||
state: BobState,
|
state: BobState,
|
||||||
|
swarm: Swarm,
|
||||||
|
db: Database,
|
||||||
|
bitcoin_wallet: Arc<crate::bitcoin::Wallet>,
|
||||||
|
monero_wallet: Arc<crate::monero::Wallet>,
|
||||||
|
rng: R,
|
||||||
|
swap_id: Uuid,
|
||||||
|
) -> Result<BobState>
|
||||||
|
where
|
||||||
|
R: RngCore + CryptoRng + Send,
|
||||||
|
{
|
||||||
|
run_until(state, is_complete, swarm, db, bitcoin_wallet, monero_wallet, rng, swap_id).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use macro or generics
|
||||||
|
pub fn is_complete(state: &BobState) -> bool {
|
||||||
|
matches!(state, BobState::BtcRefunded| BobState::XmrRedeemed | BobState::Punished | BobState::SafelyAborted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// State machine driver for swap execution
|
||||||
|
#[async_recursion]
|
||||||
|
pub async fn run_until<R>(
|
||||||
|
state: BobState,
|
||||||
|
is_state: fn(&BobState) -> bool,
|
||||||
mut swarm: Swarm,
|
mut swarm: Swarm,
|
||||||
db: Database,
|
db: Database,
|
||||||
bitcoin_wallet: Arc<crate::bitcoin::Wallet>,
|
bitcoin_wallet: Arc<crate::bitcoin::Wallet>,
|
||||||
|
@ -47,112 +68,120 @@ pub async fn swap<R>(
|
||||||
where
|
where
|
||||||
R: RngCore + CryptoRng + Send,
|
R: RngCore + CryptoRng + Send,
|
||||||
{
|
{
|
||||||
match state {
|
if is_state(&state) {
|
||||||
BobState::Started {
|
Ok(state)
|
||||||
state0,
|
} else {
|
||||||
amounts,
|
match state {
|
||||||
peer_id,
|
BobState::Started {
|
||||||
addr,
|
|
||||||
} => {
|
|
||||||
let state2 = negotiate(
|
|
||||||
state0,
|
state0,
|
||||||
amounts,
|
amounts,
|
||||||
&mut swarm,
|
peer_id,
|
||||||
addr,
|
addr,
|
||||||
&mut rng,
|
} => {
|
||||||
bitcoin_wallet.clone(),
|
let state2 = negotiate(
|
||||||
)
|
state0,
|
||||||
.await?;
|
amounts,
|
||||||
swap(
|
&mut swarm,
|
||||||
BobState::Negotiated(state2, peer_id),
|
addr,
|
||||||
swarm,
|
&mut rng,
|
||||||
db,
|
bitcoin_wallet.clone(),
|
||||||
bitcoin_wallet,
|
)
|
||||||
monero_wallet,
|
.await?;
|
||||||
rng,
|
run_until(
|
||||||
swap_id,
|
BobState::Negotiated(state2, peer_id),
|
||||||
)
|
is_state,
|
||||||
.await
|
swarm,
|
||||||
}
|
db,
|
||||||
BobState::Negotiated(state2, alice_peer_id) => {
|
bitcoin_wallet,
|
||||||
// Alice and Bob have exchanged info
|
monero_wallet,
|
||||||
let state3 = state2.lock_btc(bitcoin_wallet.as_ref()).await?;
|
rng,
|
||||||
// db.insert_latest_state(state);
|
swap_id,
|
||||||
swap(
|
)
|
||||||
BobState::BtcLocked(state3, alice_peer_id),
|
.await
|
||||||
swarm,
|
}
|
||||||
db,
|
BobState::Negotiated(state2, alice_peer_id) => {
|
||||||
bitcoin_wallet,
|
// Alice and Bob have exchanged info
|
||||||
monero_wallet,
|
let state3 = state2.lock_btc(bitcoin_wallet.as_ref()).await?;
|
||||||
rng,
|
// db.insert_latest_state(state);
|
||||||
swap_id,
|
run_until(
|
||||||
)
|
BobState::BtcLocked(state3, alice_peer_id),
|
||||||
.await
|
is_state,
|
||||||
}
|
swarm,
|
||||||
// Bob has locked Btc
|
db,
|
||||||
// Watch for Alice to Lock Xmr or for t1 to elapse
|
bitcoin_wallet,
|
||||||
BobState::BtcLocked(state3, alice_peer_id) => {
|
monero_wallet,
|
||||||
// todo: watch until t1, not indefinetely
|
rng,
|
||||||
let state4 = match swarm.next().await {
|
swap_id,
|
||||||
OutEvent::Message2(msg) => {
|
)
|
||||||
state3
|
.await
|
||||||
.watch_for_lock_xmr(monero_wallet.as_ref(), msg)
|
}
|
||||||
.await?
|
// Bob has locked Btc
|
||||||
}
|
// Watch for Alice to Lock Xmr or for t1 to elapse
|
||||||
other => panic!("unexpected event: {:?}", other),
|
BobState::BtcLocked(state3, alice_peer_id) => {
|
||||||
};
|
// todo: watch until t1, not indefinetely
|
||||||
swap(
|
let state4 = match swarm.next().await {
|
||||||
BobState::XmrLocked(state4, alice_peer_id),
|
OutEvent::Message2(msg) => {
|
||||||
swarm,
|
state3
|
||||||
db,
|
.watch_for_lock_xmr(monero_wallet.as_ref(), msg)
|
||||||
bitcoin_wallet,
|
.await?
|
||||||
monero_wallet,
|
}
|
||||||
rng,
|
other => panic!("unexpected event: {:?}", other),
|
||||||
swap_id,
|
};
|
||||||
)
|
run_until(
|
||||||
.await
|
BobState::XmrLocked(state4, alice_peer_id),
|
||||||
}
|
is_state,
|
||||||
BobState::XmrLocked(state, alice_peer_id) => {
|
swarm,
|
||||||
// Alice has locked Xmr
|
db,
|
||||||
// Bob sends Alice his key
|
bitcoin_wallet,
|
||||||
let tx_redeem_encsig = state.tx_redeem_encsig();
|
monero_wallet,
|
||||||
// Do we have to wait for a response?
|
rng,
|
||||||
// What if Alice fails to receive this? Should we always resend?
|
swap_id,
|
||||||
// todo: If we cannot dial Alice we should go to EncSigSent. Maybe dialing
|
)
|
||||||
// should happen in this arm?
|
.await
|
||||||
swarm.send_message3(alice_peer_id.clone(), tx_redeem_encsig);
|
}
|
||||||
|
BobState::XmrLocked(state, alice_peer_id) => {
|
||||||
|
// Alice has locked Xmr
|
||||||
|
// Bob sends Alice his key
|
||||||
|
let tx_redeem_encsig = state.tx_redeem_encsig();
|
||||||
|
// Do we have to wait for a response?
|
||||||
|
// What if Alice fails to receive this? Should we always resend?
|
||||||
|
// todo: If we cannot dial Alice we should go to EncSigSent. Maybe dialing
|
||||||
|
// should happen in this arm?
|
||||||
|
swarm.send_message3(alice_peer_id.clone(), tx_redeem_encsig);
|
||||||
|
|
||||||
// Sadly we have to poll the swarm to get make sure the message is sent?
|
// Sadly we have to poll the swarm to get make sure the message is sent?
|
||||||
// FIXME: Having to wait for Alice's response here is a big problem, because
|
// FIXME: Having to wait for Alice's response here is a big problem, because
|
||||||
// we're stuck if she doesn't send her response back. I believe this is
|
// we're stuck if she doesn't send her response back. I believe this is
|
||||||
// currently necessary, so we may have to rework this and/or how we use libp2p
|
// currently necessary, so we may have to rework this and/or how we use libp2p
|
||||||
match swarm.next().await {
|
match swarm.next().await {
|
||||||
OutEvent::Message3 => {
|
OutEvent::Message3 => {
|
||||||
debug!("Got Message3 empty response");
|
debug!("Got Message3 empty response");
|
||||||
}
|
}
|
||||||
other => panic!("unexpected event: {:?}", other),
|
other => panic!("unexpected event: {:?}", other),
|
||||||
};
|
};
|
||||||
|
|
||||||
swap(
|
run_until(
|
||||||
BobState::EncSigSent(state, alice_peer_id),
|
BobState::EncSigSent(state, alice_peer_id),
|
||||||
swarm,
|
is_state,
|
||||||
db,
|
swarm,
|
||||||
bitcoin_wallet,
|
db,
|
||||||
monero_wallet,
|
bitcoin_wallet,
|
||||||
rng,
|
monero_wallet,
|
||||||
swap_id,
|
rng,
|
||||||
)
|
swap_id,
|
||||||
.await
|
)
|
||||||
}
|
.await
|
||||||
BobState::EncSigSent(state, ..) => {
|
}
|
||||||
// Watch for redeem
|
BobState::EncSigSent(state, ..) => {
|
||||||
let redeem_watcher = state.watch_for_redeem_btc(bitcoin_wallet.as_ref());
|
// Watch for redeem
|
||||||
let t1_timeout = state.wait_for_t1(bitcoin_wallet.as_ref());
|
let redeem_watcher = state.watch_for_redeem_btc(bitcoin_wallet.as_ref());
|
||||||
|
let t1_timeout = state.wait_for_t1(bitcoin_wallet.as_ref());
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
val = redeem_watcher => {
|
val = redeem_watcher => {
|
||||||
swap(
|
run_until(
|
||||||
BobState::BtcRedeemed(val?),
|
BobState::BtcRedeemed(val?),
|
||||||
|
is_state,
|
||||||
swarm,
|
swarm,
|
||||||
db,
|
db,
|
||||||
bitcoin_wallet,
|
bitcoin_wallet,
|
||||||
|
@ -169,8 +198,9 @@ where
|
||||||
state.submit_tx_cancel(bitcoin_wallet.as_ref()).await?;
|
state.submit_tx_cancel(bitcoin_wallet.as_ref()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
swap(
|
run_until(
|
||||||
BobState::Cancelled(state),
|
BobState::Cancelled(state),
|
||||||
|
is_state,
|
||||||
swarm,
|
swarm,
|
||||||
db,
|
db,
|
||||||
bitcoin_wallet,
|
bitcoin_wallet,
|
||||||
|
@ -182,29 +212,35 @@ where
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
BobState::BtcRedeemed(state) => {
|
||||||
|
// Bob redeems XMR using revealed s_a
|
||||||
|
state.claim_xmr(monero_wallet.as_ref()).await?;
|
||||||
|
run_until(
|
||||||
|
BobState::XmrRedeemed,
|
||||||
|
is_state,
|
||||||
|
swarm,
|
||||||
|
db,
|
||||||
|
bitcoin_wallet,
|
||||||
|
monero_wallet,
|
||||||
|
rng,
|
||||||
|
swap_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
BobState::Cancelled(_state) => Ok(BobState::BtcRefunded),
|
||||||
|
BobState::BtcRefunded => Ok(BobState::BtcRefunded),
|
||||||
|
BobState::Punished => Ok(BobState::Punished),
|
||||||
|
BobState::SafelyAborted => Ok(BobState::SafelyAborted),
|
||||||
|
BobState::XmrRedeemed => Ok(BobState::XmrRedeemed),
|
||||||
}
|
}
|
||||||
BobState::BtcRedeemed(state) => {
|
|
||||||
// Bob redeems XMR using revealed s_a
|
|
||||||
state.claim_xmr(monero_wallet.as_ref()).await?;
|
|
||||||
swap(
|
|
||||||
BobState::XmrRedeemed,
|
|
||||||
swarm,
|
|
||||||
db,
|
|
||||||
bitcoin_wallet,
|
|
||||||
monero_wallet,
|
|
||||||
rng,
|
|
||||||
swap_id,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
BobState::Cancelled(_state) => Ok(BobState::BtcRefunded),
|
|
||||||
BobState::BtcRefunded => Ok(BobState::BtcRefunded),
|
|
||||||
BobState::Punished => Ok(BobState::Punished),
|
|
||||||
BobState::SafelyAborted => Ok(BobState::SafelyAborted),
|
|
||||||
BobState::XmrRedeemed => Ok(BobState::XmrRedeemed),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // State machine driver for recovery execution
|
// // State machine driver for recovery execution
|
||||||
// #[async_recursion]
|
// #[async_recursion]
|
||||||
// pub async fn abort(state: BobState, io: Io) -> Result<BobState> {
|
// pub async fn abort(state: BobState, io: Io) -> Result<BobState> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user