mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-12-23 14:39:37 -05:00
Bob saves lock proof after received so he can resume swap
This commit is contained in:
parent
c5cfc2ce20
commit
3593f5323a
@ -382,7 +382,7 @@ pub struct Transfer {
|
||||
pub unsigned_txset: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
|
||||
pub struct BlockHeight {
|
||||
pub height: u32,
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::{
|
||||
monero::TransferProof,
|
||||
protocol::{bob, bob::BobState},
|
||||
SwapAmounts,
|
||||
};
|
||||
use ::bitcoin::hashes::core::fmt::Display;
|
||||
use monero_harness::rpc::wallet::BlockHeight;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||
@ -17,6 +19,11 @@ pub enum Bob {
|
||||
BtcLocked {
|
||||
state3: bob::State3,
|
||||
},
|
||||
XmrLockProofReceived {
|
||||
state: bob::State3,
|
||||
lock_transfer_proof: TransferProof,
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
},
|
||||
XmrLocked {
|
||||
state4: bob::State4,
|
||||
},
|
||||
@ -43,6 +50,15 @@ impl From<BobState> for Bob {
|
||||
BobState::Started { state0, amounts } => Bob::Started { state0, amounts },
|
||||
BobState::Negotiated(state2) => Bob::Negotiated { state2 },
|
||||
BobState::BtcLocked(state3) => Bob::BtcLocked { state3 },
|
||||
BobState::XmrLockProofReceived {
|
||||
state,
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => Bob::XmrLockProofReceived {
|
||||
state,
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight,
|
||||
},
|
||||
BobState::XmrLocked(state4) => Bob::XmrLocked { state4 },
|
||||
BobState::EncSigSent(state4) => Bob::EncSigSent { state4 },
|
||||
BobState::BtcRedeemed(state5) => Bob::BtcRedeemed(state5),
|
||||
@ -66,6 +82,15 @@ impl From<Bob> for BobState {
|
||||
Bob::Started { state0, amounts } => BobState::Started { state0, amounts },
|
||||
Bob::Negotiated { state2 } => BobState::Negotiated(state2),
|
||||
Bob::BtcLocked { state3 } => BobState::BtcLocked(state3),
|
||||
Bob::XmrLockProofReceived {
|
||||
state,
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => BobState::XmrLockProofReceived {
|
||||
state,
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight,
|
||||
},
|
||||
Bob::XmrLocked { state4 } => BobState::XmrLocked(state4),
|
||||
Bob::EncSigSent { state4 } => BobState::EncSigSent(state4),
|
||||
Bob::BtcRedeemed(state5) => BobState::BtcRedeemed(state5),
|
||||
@ -87,6 +112,9 @@ impl Display for Bob {
|
||||
Bob::Started { .. } => write!(f, "Started"),
|
||||
Bob::Negotiated { .. } => f.write_str("Negotiated"),
|
||||
Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"),
|
||||
Bob::XmrLockProofReceived { .. } => {
|
||||
f.write_str("XMR lock transaction transfer proof received")
|
||||
}
|
||||
Bob::XmrLocked { .. } => f.write_str("Monero locked"),
|
||||
Bob::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
|
||||
Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"),
|
||||
|
@ -139,7 +139,7 @@ impl Display for Amount {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TransferProof {
|
||||
tx_hash: TxHash,
|
||||
#[serde(with = "monero_private_key")]
|
||||
@ -159,7 +159,7 @@ impl TransferProof {
|
||||
}
|
||||
|
||||
// TODO: add constructor/ change String to fixed length byte array
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TxHash(pub String);
|
||||
|
||||
impl From<TxHash> for String {
|
||||
|
@ -150,6 +150,9 @@ pub async fn wait_for_bitcoin_encrypted_signature(
|
||||
.recv_message3()
|
||||
.await
|
||||
.context("Failed to receive Bitcoin encrypted signature from Bob")?;
|
||||
|
||||
tracing::debug!("Message 3 received, returning it");
|
||||
|
||||
Ok(msg3.tx_redeem_encsig)
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
},
|
||||
config::Config,
|
||||
monero,
|
||||
monero::monero_private_key,
|
||||
monero::{monero_private_key, TransferProof},
|
||||
protocol::{alice, bob},
|
||||
ExpiredTimelocks, SwapAmounts,
|
||||
};
|
||||
@ -16,6 +16,7 @@ use ecdsa_fun::{
|
||||
nonce::Deterministic,
|
||||
Signature,
|
||||
};
|
||||
use monero_harness::rpc::wallet::BlockHeight;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha256;
|
||||
@ -29,6 +30,11 @@ pub enum BobState {
|
||||
},
|
||||
Negotiated(State2),
|
||||
BtcLocked(State3),
|
||||
XmrLockProofReceived {
|
||||
state: State3,
|
||||
lock_transfer_proof: TransferProof,
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
},
|
||||
XmrLocked(State4),
|
||||
EncSigSent(State4),
|
||||
BtcRedeemed(State5),
|
||||
@ -50,6 +56,9 @@ impl fmt::Display for BobState {
|
||||
BobState::Started { .. } => write!(f, "started"),
|
||||
BobState::Negotiated(..) => write!(f, "negotiated"),
|
||||
BobState::BtcLocked(..) => write!(f, "btc is locked"),
|
||||
BobState::XmrLockProofReceived { .. } => {
|
||||
write!(f, "XMR lock transaction transfer proof received")
|
||||
}
|
||||
BobState::XmrLocked(..) => write!(f, "xmr is locked"),
|
||||
BobState::EncSigSent(..) => write!(f, "encrypted signature is sent"),
|
||||
BobState::BtcRedeemed(..) => write!(f, "btc is redeemed"),
|
||||
@ -311,7 +320,7 @@ impl State3 {
|
||||
pub async fn watch_for_lock_xmr<W>(
|
||||
self,
|
||||
xmr_wallet: &W,
|
||||
msg: alice::Message2,
|
||||
transfer_proof: TransferProof,
|
||||
monero_wallet_restore_blockheight: u32,
|
||||
) -> Result<State4>
|
||||
where
|
||||
@ -326,7 +335,7 @@ impl State3 {
|
||||
.watch_for_transfer(
|
||||
S,
|
||||
self.v.public(),
|
||||
msg.tx_lock_proof,
|
||||
transfer_proof,
|
||||
self.xmr,
|
||||
self.min_monero_confirmations,
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ use async_recursion::async_recursion;
|
||||
use rand::{rngs::OsRng, CryptoRng, RngCore};
|
||||
use std::sync::Arc;
|
||||
use tokio::select;
|
||||
use tracing::{debug, info};
|
||||
use tracing::info;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn is_complete(state: &BobState) -> bool {
|
||||
@ -28,6 +28,10 @@ pub fn is_btc_locked(state: &BobState) -> bool {
|
||||
matches!(state, BobState::BtcLocked(..))
|
||||
}
|
||||
|
||||
pub fn is_lock_proof_received(state: &BobState) -> bool {
|
||||
matches!(state, BobState::XmrLockProofReceived { .. })
|
||||
}
|
||||
|
||||
pub fn is_xmr_locked(state: &BobState) -> bool {
|
||||
matches!(state, BobState::XmrLocked(..))
|
||||
}
|
||||
@ -155,23 +159,12 @@ where
|
||||
msg2 = msg2_watcher => {
|
||||
|
||||
let msg2 = msg2?;
|
||||
info!("Received XMR lock transaction transfer proof from Alice, watching for transfer confirmations");
|
||||
debug!("Transfer proof: {:?}", msg2.tx_lock_proof);
|
||||
|
||||
let xmr_lock_watcher = state3.clone()
|
||||
.watch_for_lock_xmr(monero_wallet.as_ref(), msg2, monero_wallet_restore_blockheight.height);
|
||||
let cancel_timelock_expires = state3.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref());
|
||||
|
||||
select! {
|
||||
state4 = xmr_lock_watcher => {
|
||||
BobState::XmrLocked(state4?)
|
||||
},
|
||||
_ = cancel_timelock_expires => {
|
||||
let state4 = state3.state4();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
}
|
||||
BobState::XmrLockProofReceived {
|
||||
state: state3,
|
||||
lock_transfer_proof: msg2.tx_lock_proof,
|
||||
monero_wallet_restore_blockheight
|
||||
}
|
||||
|
||||
},
|
||||
_ = cancel_timelock_expires => {
|
||||
let state4 = state3.state4();
|
||||
@ -197,6 +190,53 @@ where
|
||||
)
|
||||
.await
|
||||
}
|
||||
BobState::XmrLockProofReceived {
|
||||
state,
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let state = if let ExpiredTimelocks::None =
|
||||
state.current_epoch(bitcoin_wallet.as_ref()).await?
|
||||
{
|
||||
event_loop_handle.dial().await?;
|
||||
|
||||
let xmr_lock_watcher = state.clone().watch_for_lock_xmr(
|
||||
monero_wallet.as_ref(),
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight.height,
|
||||
);
|
||||
let cancel_timelock_expires =
|
||||
state.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref());
|
||||
|
||||
select! {
|
||||
state4 = xmr_lock_watcher => {
|
||||
BobState::XmrLocked(state4?)
|
||||
},
|
||||
_ = cancel_timelock_expires => {
|
||||
let state4 = state.state4();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let state4 = state.state4();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
};
|
||||
|
||||
let db_state = state.clone().into();
|
||||
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
|
||||
run_until_internal(
|
||||
state,
|
||||
is_target_state,
|
||||
event_loop_handle,
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
BobState::XmrLocked(state) => {
|
||||
let state = if let ExpiredTimelocks::None =
|
||||
state.expired_timelock(bitcoin_wallet.as_ref()).await?
|
||||
|
@ -0,0 +1,34 @@
|
||||
use swap::protocol::{
|
||||
alice, bob,
|
||||
bob::{swap::is_lock_proof_received, BobState},
|
||||
};
|
||||
|
||||
pub mod testutils;
|
||||
|
||||
#[tokio::test]
|
||||
async fn given_bob_restarts_after_lock_proof_received_resume_swap() {
|
||||
testutils::setup_test(|mut ctx| async move {
|
||||
let alice_swap = ctx.new_swap_as_alice().await;
|
||||
let bob_swap = ctx.new_swap_as_bob().await;
|
||||
|
||||
let alice_handle = alice::run(alice_swap);
|
||||
let alice_swap_handle = tokio::spawn(alice_handle);
|
||||
|
||||
let bob_state = bob::run_until(bob_swap, is_lock_proof_received)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(bob_state, BobState::XmrLockProofReceived {..}));
|
||||
|
||||
let bob_swap = ctx.recover_bob_from_db().await;
|
||||
assert!(matches!(bob_swap.state, BobState::XmrLockProofReceived {..}));
|
||||
|
||||
let bob_state = bob::run(bob_swap).await.unwrap();
|
||||
|
||||
ctx.assert_bob_redeemed(bob_state).await;
|
||||
|
||||
let alice_state = alice_swap_handle.await.unwrap().unwrap();
|
||||
ctx.assert_alice_redeemed(alice_state).await;
|
||||
})
|
||||
.await;
|
||||
}
|
Loading…
Reference in New Issue
Block a user