mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-12 00:10:49 -04:00
Merge #405
405: Concurrent swaps with same peer r=da-kami a=da-kami Fixes #367 - [x] Concurrent swaps with same peer Not sure how much more time I should invest into this. We could just merge the current state and then do improvements on top...? Improvements: - [x] Think `// TODO: Remove unnecessary swap-id check` through and remove it - [x] Add concurrent swap test, multiple swaps with same Bob - [ ] Save swap messages without matching swap in execution in the database - [ ] Assert the balances in the new concurrent swap tests - [ ] ~~Add concurrent swap test, multiple swaps with different Bobs~~ - [ ] ~~Send swap-id in separate message, not on top of `Message0`~~ Co-authored-by: Daniel Karzel <daniel@comit.network>
This commit is contained in:
commit
19766b9759
31 changed files with 456 additions and 127 deletions
|
@ -79,8 +79,9 @@ async fn main() -> Result<()> {
|
|||
let mut swarm = swarm::new::<Behaviour>(&seed)?;
|
||||
swarm.add_address(alice_peer_id, alice_multiaddr);
|
||||
|
||||
let swap_id = Uuid::new_v4();
|
||||
let (event_loop, mut event_loop_handle) =
|
||||
EventLoop::new(swarm, alice_peer_id, bitcoin_wallet.clone())?;
|
||||
EventLoop::new(swap_id, swarm, alice_peer_id, bitcoin_wallet.clone())?;
|
||||
let event_loop = tokio::spawn(event_loop.run());
|
||||
|
||||
let send_bitcoin = determine_btc_to_swap(
|
||||
|
@ -174,7 +175,7 @@ async fn main() -> Result<()> {
|
|||
swarm.add_address(alice_peer_id, alice_multiaddr);
|
||||
|
||||
let (event_loop, event_loop_handle) =
|
||||
EventLoop::new(swarm, alice_peer_id, bitcoin_wallet.clone())?;
|
||||
EventLoop::new(swap_id, swarm, alice_peer_id, bitcoin_wallet.clone())?;
|
||||
let handle = tokio::spawn(event_loop.run());
|
||||
|
||||
let swap = Builder::new(
|
||||
|
|
|
@ -5,6 +5,7 @@ use libp2p::request_response::{
|
|||
RequestResponseMessage,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub type OutEvent = RequestResponseEvent<Request, ()>;
|
||||
|
||||
|
@ -19,6 +20,7 @@ impl ProtocolName for EncryptedSignatureProtocol {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Request {
|
||||
pub swap_id: Uuid,
|
||||
pub tx_redeem_encsig: crate::bitcoin::EncryptedSignature,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use libp2p::request_response::{
|
|||
RequestResponseMessage,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub type OutEvent = RequestResponseEvent<Request, ()>;
|
||||
|
||||
|
@ -20,6 +21,7 @@ impl ProtocolName for TransferProofProtocol {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Request {
|
||||
pub swap_id: Uuid,
|
||||
pub tx_lock_proof: monero::TransferProof,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||
use sha2::Sha256;
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::{CrossCurveDLEQ, CrossCurveDLEQProof};
|
||||
use sigma_fun::HashTranscript;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub mod alice;
|
||||
pub mod bob;
|
||||
|
@ -18,14 +19,9 @@ pub static CROSS_CURVE_PROOF_SYSTEM: Lazy<
|
|||
)
|
||||
});
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct StartingBalances {
|
||||
pub xmr: monero::Amount,
|
||||
pub btc: bitcoin::Amount,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message0 {
|
||||
swap_id: Uuid,
|
||||
B: bitcoin::PublicKey,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
|
|
|
@ -6,6 +6,7 @@ use libp2p::request_response::{
|
|||
RequestId, RequestResponseEvent, RequestResponseMessage, ResponseChannel,
|
||||
};
|
||||
use libp2p::{NetworkBehaviour, PeerId};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
|
@ -20,6 +21,7 @@ pub enum OutEvent {
|
|||
},
|
||||
ExecutionSetupDone {
|
||||
bob_peer_id: PeerId,
|
||||
swap_id: Uuid,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
TransferProofAcknowledged {
|
||||
|
@ -157,9 +159,11 @@ impl From<execution_setup::OutEvent> for OutEvent {
|
|||
match event {
|
||||
Done {
|
||||
bob_peer_id,
|
||||
swap_id,
|
||||
state3,
|
||||
} => OutEvent::ExecutionSetupDone {
|
||||
bob_peer_id,
|
||||
swap_id,
|
||||
state3: Box::new(state3),
|
||||
},
|
||||
Failure { peer, error } => OutEvent::Failure { peer, error },
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::database::Database;
|
|||
use crate::env::Config;
|
||||
use crate::monero::BalanceTooLow;
|
||||
use crate::network::quote::BidQuote;
|
||||
use crate::network::{encrypted_signature, spot_price, transfer_proof};
|
||||
use crate::network::{spot_price, transfer_proof};
|
||||
use crate::protocol::alice::{AliceState, Behaviour, OutEvent, State0, State3, Swap};
|
||||
use crate::{bitcoin, kraken, monero};
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
@ -43,16 +43,15 @@ pub struct EventLoop<RS> {
|
|||
|
||||
swap_sender: mpsc::Sender<Swap>,
|
||||
|
||||
/// Stores a sender per peer for incoming [`EncryptedSignature`]s.
|
||||
recv_encrypted_signature:
|
||||
HashMap<PeerId, bmrng::RequestSender<encrypted_signature::Request, ()>>,
|
||||
/// Stores incoming [`EncryptedSignature`]s per swap.
|
||||
recv_encrypted_signature: HashMap<Uuid, bmrng::RequestSender<bitcoin::EncryptedSignature, ()>>,
|
||||
inflight_encrypted_signatures: FuturesUnordered<BoxFuture<'static, ResponseChannel<()>>>,
|
||||
|
||||
send_transfer_proof: FuturesUnordered<OutgoingTransferProof>,
|
||||
|
||||
/// Tracks [`transfer_proof::Request`]s which could not yet be sent because
|
||||
/// we are currently disconnected from the peer.
|
||||
buffered_transfer_proofs: HashMap<PeerId, (transfer_proof::Request, bmrng::Responder<()>)>,
|
||||
buffered_transfer_proofs: HashMap<PeerId, Vec<(transfer_proof::Request, bmrng::Responder<()>)>>,
|
||||
|
||||
/// Tracks [`transfer_proof::Request`]s which are currently inflight and
|
||||
/// awaiting an acknowledgement.
|
||||
|
@ -120,7 +119,7 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let handle = self.new_handle(peer_id);
|
||||
let handle = self.new_handle(peer_id, swap_id);
|
||||
|
||||
let swap = Swap {
|
||||
event_loop_handle: handle,
|
||||
|
@ -186,25 +185,26 @@ where
|
|||
tracing::debug!(%peer, "Failed to respond with quote");
|
||||
}
|
||||
}
|
||||
SwarmEvent::Behaviour(OutEvent::ExecutionSetupDone{bob_peer_id, state3}) => {
|
||||
let _ = self.handle_execution_setup_done(bob_peer_id, *state3).await;
|
||||
SwarmEvent::Behaviour(OutEvent::ExecutionSetupDone{bob_peer_id, swap_id, state3}) => {
|
||||
let _ = self.handle_execution_setup_done(bob_peer_id, swap_id, *state3).await;
|
||||
}
|
||||
SwarmEvent::Behaviour(OutEvent::TransferProofAcknowledged { peer, id }) => {
|
||||
tracing::trace!(%peer, "Bob acknowledged transfer proof");
|
||||
tracing::debug!(%peer, "Bob acknowledged transfer proof");
|
||||
if let Some(responder) = self.inflight_transfer_proofs.remove(&id) {
|
||||
let _ = responder.respond(());
|
||||
}
|
||||
}
|
||||
SwarmEvent::Behaviour(OutEvent::EncryptedSignatureReceived{ msg, channel, peer }) => {
|
||||
let sender = match self.recv_encrypted_signature.remove(&peer) {
|
||||
let sender = match self.recv_encrypted_signature.remove(&msg.swap_id) {
|
||||
Some(sender) => sender,
|
||||
None => {
|
||||
// TODO: Don't just drop encsig if we currently don't have a running swap for it, save in db
|
||||
tracing::warn!(%peer, "No sender for encrypted signature, maybe already handled?");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut responder = match sender.send(*msg).await {
|
||||
let mut responder = match sender.send(msg.tx_redeem_encsig).await {
|
||||
Ok(responder) => responder,
|
||||
Err(_) => {
|
||||
tracing::warn!(%peer, "Failed to relay encrypted signature to swap");
|
||||
|
@ -225,11 +225,13 @@ where
|
|||
SwarmEvent::ConnectionEstablished { peer_id: peer, endpoint, .. } => {
|
||||
tracing::debug!(%peer, address = %endpoint.get_remote_address(), "New connection established");
|
||||
|
||||
if let Some((transfer_proof, responder)) = self.buffered_transfer_proofs.remove(&peer) {
|
||||
tracing::debug!(%peer, "Found buffered transfer proof for peer");
|
||||
if let Some(transfer_proofs) = self.buffered_transfer_proofs.remove(&peer) {
|
||||
for (transfer_proof, responder) in transfer_proofs {
|
||||
tracing::debug!(%peer, "Found buffered transfer proof for peer");
|
||||
|
||||
let id = self.swarm.transfer_proof.send_request(&peer, transfer_proof);
|
||||
self.inflight_transfer_proofs.insert(id, responder);
|
||||
let id = self.swarm.transfer_proof.send_request(&peer, transfer_proof);
|
||||
self.inflight_transfer_proofs.insert(id, responder);
|
||||
}
|
||||
}
|
||||
}
|
||||
SwarmEvent::IncomingConnectionError { send_back_addr: address, error, .. } => {
|
||||
|
@ -253,15 +255,15 @@ where
|
|||
Some(Ok((peer, transfer_proof, responder))) => {
|
||||
if !self.swarm.transfer_proof.is_connected(&peer) {
|
||||
tracing::warn!(%peer, "No active connection to peer, buffering transfer proof");
|
||||
self.buffered_transfer_proofs.insert(peer, (transfer_proof, responder));
|
||||
self.buffered_transfer_proofs.entry(peer).or_insert_with(Vec::new).push((transfer_proof, responder));
|
||||
continue;
|
||||
}
|
||||
|
||||
let id = self.swarm.transfer_proof.send_request(&peer, transfer_proof);
|
||||
self.inflight_transfer_proofs.insert(id, responder);
|
||||
},
|
||||
Some(Err(_)) => {
|
||||
tracing::debug!("A swap stopped without sending a transfer proof");
|
||||
Some(Err(e)) => {
|
||||
tracing::debug!("A swap stopped without sending a transfer proof: {:#}", e);
|
||||
}
|
||||
None => {
|
||||
unreachable!("stream of transfer proof receivers must never terminate")
|
||||
|
@ -317,9 +319,13 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
async fn handle_execution_setup_done(&mut self, bob_peer_id: PeerId, state3: State3) {
|
||||
let swap_id = Uuid::new_v4();
|
||||
let handle = self.new_handle(bob_peer_id);
|
||||
async fn handle_execution_setup_done(
|
||||
&mut self,
|
||||
bob_peer_id: PeerId,
|
||||
swap_id: Uuid,
|
||||
state3: State3,
|
||||
) {
|
||||
let handle = self.new_handle(bob_peer_id, swap_id);
|
||||
|
||||
let initial_state = AliceState::Started {
|
||||
state3: Box::new(state3),
|
||||
|
@ -335,7 +341,7 @@ where
|
|||
swap_id,
|
||||
};
|
||||
|
||||
// TODO: Consider adding separate components for start/rsume of swaps
|
||||
// TODO: Consider adding separate components for start/resume of swaps
|
||||
|
||||
// swaps save peer id so we can resume
|
||||
match self.db.insert_peer_id(swap_id, bob_peer_id).await {
|
||||
|
@ -352,17 +358,24 @@ where
|
|||
|
||||
/// Create a new [`EventLoopHandle`] that is scoped for communication with
|
||||
/// the given peer.
|
||||
fn new_handle(&mut self, peer: PeerId) -> EventLoopHandle {
|
||||
fn new_handle(&mut self, peer: PeerId, swap_id: Uuid) -> EventLoopHandle {
|
||||
// we deliberately don't put timeouts on these channels because the swap always
|
||||
// races these futures against a timelock
|
||||
|
||||
let (transfer_proof_sender, mut transfer_proof_receiver) = bmrng::channel(1);
|
||||
let encrypted_signature = bmrng::channel(1);
|
||||
|
||||
self.recv_encrypted_signature
|
||||
.insert(peer, encrypted_signature.0);
|
||||
.insert(swap_id, encrypted_signature.0);
|
||||
|
||||
self.send_transfer_proof.push(
|
||||
async move {
|
||||
let (request, responder) = transfer_proof_receiver.recv().await?;
|
||||
let (transfer_proof, responder) = transfer_proof_receiver.recv().await?;
|
||||
|
||||
let request = transfer_proof::Request {
|
||||
swap_id,
|
||||
tx_lock_proof: transfer_proof,
|
||||
};
|
||||
|
||||
Ok((peer, request, responder))
|
||||
}
|
||||
|
@ -440,13 +453,13 @@ impl LatestRate for KrakenRate {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct EventLoopHandle {
|
||||
recv_encrypted_signature: Option<bmrng::RequestReceiver<encrypted_signature::Request, ()>>,
|
||||
send_transfer_proof: Option<bmrng::RequestSender<transfer_proof::Request, ()>>,
|
||||
recv_encrypted_signature: Option<bmrng::RequestReceiver<bitcoin::EncryptedSignature, ()>>,
|
||||
send_transfer_proof: Option<bmrng::RequestSender<monero::TransferProof, ()>>,
|
||||
}
|
||||
|
||||
impl EventLoopHandle {
|
||||
pub async fn recv_encrypted_signature(&mut self) -> Result<bitcoin::EncryptedSignature> {
|
||||
let (request, responder) = self
|
||||
let (tx_redeem_encsig, responder) = self
|
||||
.recv_encrypted_signature
|
||||
.take()
|
||||
.context("Encrypted signature was already received")?
|
||||
|
@ -457,14 +470,14 @@ impl EventLoopHandle {
|
|||
.respond(())
|
||||
.context("Failed to acknowledge receipt of encrypted signature")?;
|
||||
|
||||
Ok(request.tx_redeem_encsig)
|
||||
Ok(tx_redeem_encsig)
|
||||
}
|
||||
|
||||
pub async fn send_transfer_proof(&mut self, msg: monero::TransferProof) -> Result<()> {
|
||||
self.send_transfer_proof
|
||||
.take()
|
||||
.context("Transfer proof was already sent")?
|
||||
.send_receive(transfer_proof::Request { tx_lock_proof: msg })
|
||||
.send_receive(msg)
|
||||
.await
|
||||
.context("Failed to send transfer proof")?;
|
||||
|
||||
|
|
|
@ -4,18 +4,27 @@ use crate::protocol::{Message0, Message2, Message4};
|
|||
use anyhow::{Context, Error};
|
||||
use libp2p::PeerId;
|
||||
use libp2p_async_await::BehaviourOutEvent;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Done { bob_peer_id: PeerId, state3: State3 },
|
||||
Failure { peer: PeerId, error: Error },
|
||||
Done {
|
||||
bob_peer_id: PeerId,
|
||||
swap_id: Uuid,
|
||||
state3: State3,
|
||||
},
|
||||
Failure {
|
||||
peer: PeerId,
|
||||
error: Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<BehaviourOutEvent<(PeerId, State3), (), Error>> for OutEvent {
|
||||
fn from(event: BehaviourOutEvent<(PeerId, State3), (), Error>) -> Self {
|
||||
impl From<BehaviourOutEvent<(PeerId, (Uuid, State3)), (), Error>> for OutEvent {
|
||||
fn from(event: BehaviourOutEvent<(PeerId, (Uuid, State3)), (), Error>) -> Self {
|
||||
match event {
|
||||
BehaviourOutEvent::Inbound(_, Ok((bob_peer_id, state3))) => OutEvent::Done {
|
||||
BehaviourOutEvent::Inbound(_, Ok((bob_peer_id, (swap_id, state3)))) => OutEvent::Done {
|
||||
bob_peer_id,
|
||||
swap_id,
|
||||
state3,
|
||||
},
|
||||
BehaviourOutEvent::Inbound(peer, Err(e)) => OutEvent::Failure { peer, error: e },
|
||||
|
@ -27,7 +36,7 @@ impl From<BehaviourOutEvent<(PeerId, State3), (), Error>> for OutEvent {
|
|||
#[derive(libp2p::NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
pub struct Behaviour {
|
||||
inner: libp2p_async_await::Behaviour<(PeerId, State3), (), anyhow::Error>,
|
||||
inner: libp2p_async_await::Behaviour<(PeerId, (Uuid, State3)), (), anyhow::Error>,
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
|
@ -45,7 +54,7 @@ impl Behaviour {
|
|||
let message0 =
|
||||
serde_cbor::from_slice::<Message0>(&substream.read_message(BUF_SIZE).await?)
|
||||
.context("Failed to deserialize message0")?;
|
||||
let state1 = state0.receive(message0)?;
|
||||
let (swap_id, state1) = state0.receive(message0)?;
|
||||
|
||||
substream
|
||||
.write_message(
|
||||
|
@ -73,7 +82,7 @@ impl Behaviour {
|
|||
.context("Failed to deserialize message4")?;
|
||||
let state3 = state2.receive(message4)?;
|
||||
|
||||
Ok((bob, state3))
|
||||
Ok((bob, (swap_id, state3)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use rand::{CryptoRng, RngCore};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
use std::fmt;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AliceState {
|
||||
|
@ -146,7 +147,7 @@ impl State0 {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: Message0) -> Result<State1> {
|
||||
pub fn receive(self, msg: Message0) -> Result<(Uuid, State1)> {
|
||||
let valid = CROSS_CURVE_PROOF_SYSTEM.verify(
|
||||
&msg.dleq_proof_s_b,
|
||||
(
|
||||
|
@ -164,7 +165,7 @@ impl State0 {
|
|||
|
||||
let v = self.v_a + msg.v_b;
|
||||
|
||||
Ok(State1 {
|
||||
Ok((msg.swap_id, State1 {
|
||||
a: self.a,
|
||||
B: msg.B,
|
||||
s_a: self.s_a,
|
||||
|
@ -182,7 +183,7 @@ impl State0 {
|
|||
refund_address: msg.refund_address,
|
||||
redeem_address: self.redeem_address,
|
||||
punish_address: self.punish_address,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::env::Config;
|
|||
use crate::protocol::alice;
|
||||
use crate::protocol::alice::event_loop::EventLoopHandle;
|
||||
use crate::protocol::alice::AliceState;
|
||||
use crate::protocol::alice::AliceState::XmrLockTransferProofSent;
|
||||
use crate::{bitcoin, database, monero};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use tokio::select;
|
||||
|
@ -17,7 +16,7 @@ pub async fn run(swap: alice::Swap) -> Result<AliceState> {
|
|||
run_until(swap, |_| false).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "swap", skip(swap,exit_early), fields(id = %swap.swap_id))]
|
||||
#[tracing::instrument(name = "swap", skip(swap,exit_early), fields(id = %swap.swap_id), err)]
|
||||
pub async fn run_until(
|
||||
mut swap: alice::Swap,
|
||||
exit_early: fn(&AliceState) -> bool,
|
||||
|
@ -130,7 +129,7 @@ async fn next_state(
|
|||
result = event_loop_handle.send_transfer_proof(transfer_proof.clone()) => {
|
||||
result?;
|
||||
|
||||
XmrLockTransferProofSent {
|
||||
AliceState::XmrLockTransferProofSent {
|
||||
monero_wallet_restore_blockheight,
|
||||
transfer_proof,
|
||||
state3,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::bitcoin::EncryptedSignature;
|
||||
use crate::network::quote::BidQuote;
|
||||
use crate::network::{encrypted_signature, spot_price, transfer_proof};
|
||||
use crate::network::{encrypted_signature, spot_price};
|
||||
use crate::protocol::bob::{Behaviour, OutEvent, State0, State2};
|
||||
use crate::{bitcoin, monero};
|
||||
use anyhow::{Context, Result};
|
||||
|
@ -12,9 +12,11 @@ use libp2p::{PeerId, Swarm};
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct EventLoop {
|
||||
swap_id: Uuid,
|
||||
swarm: libp2p::Swarm<Behaviour>,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
alice_peer_id: PeerId,
|
||||
|
@ -22,7 +24,7 @@ pub struct EventLoop {
|
|||
// these streams represents outgoing requests that we have to make
|
||||
quote_requests: bmrng::RequestReceiverStream<(), BidQuote>,
|
||||
spot_price_requests: bmrng::RequestReceiverStream<spot_price::Request, spot_price::Response>,
|
||||
encrypted_signature_requests: bmrng::RequestReceiverStream<encrypted_signature::Request, ()>,
|
||||
encrypted_signatures: bmrng::RequestReceiverStream<EncryptedSignature, ()>,
|
||||
execution_setup_requests: bmrng::RequestReceiverStream<State0, Result<State2>>,
|
||||
|
||||
// these represents requests that are currently in-flight.
|
||||
|
@ -34,7 +36,7 @@ pub struct EventLoop {
|
|||
inflight_execution_setup: Option<bmrng::Responder<Result<State2>>>,
|
||||
|
||||
/// The sender we will use to relay incoming transfer proofs.
|
||||
transfer_proof: bmrng::RequestSender<transfer_proof::Request, ()>,
|
||||
transfer_proof: bmrng::RequestSender<monero::TransferProof, ()>,
|
||||
/// The future representing the successful handling of an incoming transfer
|
||||
/// proof.
|
||||
///
|
||||
|
@ -47,6 +49,7 @@ pub struct EventLoop {
|
|||
|
||||
impl EventLoop {
|
||||
pub fn new(
|
||||
swap_id: Uuid,
|
||||
swarm: Swarm<Behaviour>,
|
||||
alice_peer_id: PeerId,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
|
@ -58,12 +61,13 @@ impl EventLoop {
|
|||
let quote = bmrng::channel_with_timeout(1, Duration::from_secs(30));
|
||||
|
||||
let event_loop = EventLoop {
|
||||
swap_id,
|
||||
swarm,
|
||||
alice_peer_id,
|
||||
bitcoin_wallet,
|
||||
execution_setup_requests: execution_setup.1.into(),
|
||||
transfer_proof: transfer_proof.0,
|
||||
encrypted_signature_requests: encrypted_signature.1.into(),
|
||||
encrypted_signatures: encrypted_signature.1.into(),
|
||||
spot_price_requests: spot_price.1.into(),
|
||||
quote_requests: quote.1.into(),
|
||||
inflight_spot_price_requests: HashMap::default(),
|
||||
|
@ -108,10 +112,20 @@ impl EventLoop {
|
|||
}
|
||||
}
|
||||
SwarmEvent::Behaviour(OutEvent::TransferProofReceived { msg, channel }) => {
|
||||
let mut responder = match self.transfer_proof.send(*msg).await {
|
||||
if msg.swap_id != self.swap_id {
|
||||
|
||||
// TODO: Save unexpected transfer proofs in the database and check for messages in the database when handling swaps
|
||||
tracing::warn!("Received unexpected transfer proof for swap {} while running swap {}. This transfer proof will be ignored.", msg.swap_id, self.swap_id);
|
||||
|
||||
// When receiving a transfer proof that is unexpected we still have to acknowledge that it was received
|
||||
let _ = self.swarm.transfer_proof.send_response(channel, ());
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut responder = match self.transfer_proof.send(msg.tx_lock_proof).await {
|
||||
Ok(responder) => responder,
|
||||
Err(_) => {
|
||||
tracing::warn!("Failed to pass on transfer proof");
|
||||
Err(e) => {
|
||||
tracing::warn!("Failed to pass on transfer proof: {:#}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
@ -180,7 +194,12 @@ impl EventLoop {
|
|||
self.swarm.execution_setup.run(self.alice_peer_id, request, self.bitcoin_wallet.clone());
|
||||
self.inflight_execution_setup = Some(responder);
|
||||
},
|
||||
Some((request, responder)) = self.encrypted_signature_requests.next().fuse(), if self.is_connected_to_alice() => {
|
||||
Some((tx_redeem_encsig, responder)) = self.encrypted_signatures.next().fuse(), if self.is_connected_to_alice() => {
|
||||
let request = encrypted_signature::Request {
|
||||
swap_id: self.swap_id,
|
||||
tx_redeem_encsig
|
||||
};
|
||||
|
||||
let id = self.swarm.encrypted_signature.send_request(&self.alice_peer_id, request);
|
||||
self.inflight_encrypted_signature_requests.insert(id, responder);
|
||||
},
|
||||
|
@ -202,8 +221,8 @@ impl EventLoop {
|
|||
#[derive(Debug)]
|
||||
pub struct EventLoopHandle {
|
||||
execution_setup: bmrng::RequestSender<State0, Result<State2>>,
|
||||
transfer_proof: bmrng::RequestReceiver<transfer_proof::Request, ()>,
|
||||
encrypted_signature: bmrng::RequestSender<encrypted_signature::Request, ()>,
|
||||
transfer_proof: bmrng::RequestReceiver<monero::TransferProof, ()>,
|
||||
encrypted_signature: bmrng::RequestSender<EncryptedSignature, ()>,
|
||||
spot_price: bmrng::RequestSender<spot_price::Request, spot_price::Response>,
|
||||
quote: bmrng::RequestSender<(), BidQuote>,
|
||||
}
|
||||
|
@ -213,8 +232,8 @@ impl EventLoopHandle {
|
|||
self.execution_setup.send_receive(state0).await?
|
||||
}
|
||||
|
||||
pub async fn recv_transfer_proof(&mut self) -> Result<transfer_proof::Request> {
|
||||
let (request, responder) = self
|
||||
pub async fn recv_transfer_proof(&mut self) -> Result<monero::TransferProof> {
|
||||
let (transfer_proof, responder) = self
|
||||
.transfer_proof
|
||||
.recv()
|
||||
.await
|
||||
|
@ -223,7 +242,7 @@ impl EventLoopHandle {
|
|||
.respond(())
|
||||
.context("Failed to acknowledge receipt of transfer proof")?;
|
||||
|
||||
Ok(request)
|
||||
Ok(transfer_proof)
|
||||
}
|
||||
|
||||
pub async fn request_spot_price(&mut self, btc: bitcoin::Amount) -> Result<monero::Amount> {
|
||||
|
@ -244,7 +263,7 @@ impl EventLoopHandle {
|
|||
) -> Result<()> {
|
||||
Ok(self
|
||||
.encrypted_signature
|
||||
.send_receive(encrypted_signature::Request { tx_redeem_encsig })
|
||||
.send_receive(tx_redeem_encsig)
|
||||
.await?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize};
|
|||
use sha2::Sha256;
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
use std::fmt;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BobState {
|
||||
|
@ -69,6 +70,7 @@ impl fmt::Display for BobState {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct State0 {
|
||||
swap_id: Uuid,
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
|
@ -84,7 +86,9 @@ pub struct State0 {
|
|||
}
|
||||
|
||||
impl State0 {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new<R: RngCore + CryptoRng>(
|
||||
swap_id: Uuid,
|
||||
rng: &mut R,
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
|
@ -101,6 +105,7 @@ impl State0 {
|
|||
let (dleq_proof_s_b, (S_b_bitcoin, S_b_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, rng);
|
||||
|
||||
Self {
|
||||
swap_id,
|
||||
b,
|
||||
s_b,
|
||||
v_b,
|
||||
|
@ -120,6 +125,7 @@ impl State0 {
|
|||
|
||||
pub fn next_message(&self) -> Message0 {
|
||||
Message0 {
|
||||
swap_id: self.swap_id,
|
||||
B: self.b.public(),
|
||||
S_b_monero: self.S_b_monero,
|
||||
S_b_bitcoin: self.S_b_bitcoin,
|
||||
|
|
|
@ -68,6 +68,7 @@ async fn next_state(
|
|||
let bitcoin_refund_address = bitcoin_wallet.new_address().await?;
|
||||
|
||||
let state2 = request_price_and_setup(
|
||||
swap_id,
|
||||
btc_amount,
|
||||
event_loop_handle,
|
||||
env_config,
|
||||
|
@ -106,7 +107,7 @@ async fn next_state(
|
|||
|
||||
select! {
|
||||
transfer_proof = transfer_proof_watcher => {
|
||||
let transfer_proof = transfer_proof?.tx_lock_proof;
|
||||
let transfer_proof = transfer_proof?;
|
||||
|
||||
tracing::info!(txid = %transfer_proof.tx_hash(), "Alice locked Monero");
|
||||
|
||||
|
@ -259,6 +260,7 @@ async fn next_state(
|
|||
}
|
||||
|
||||
pub async fn request_price_and_setup(
|
||||
swap_id: Uuid,
|
||||
btc: bitcoin::Amount,
|
||||
event_loop_handle: &mut EventLoopHandle,
|
||||
env_config: &Config,
|
||||
|
@ -269,6 +271,7 @@ pub async fn request_price_and_setup(
|
|||
tracing::info!("Spot price for {} is {}", btc, xmr);
|
||||
|
||||
let state0 = State0::new(
|
||||
swap_id,
|
||||
&mut OsRng,
|
||||
btc,
|
||||
xmr,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue