Multiple swaps with the same peer

- Swap-id is exchanged during execution setup. CLI (Bob) sends the swap-id to be used in his first message.
- Transfer poof and encryption signature messages include the swap-id so it can be properly associated with the correct swap.
- ASB: Encryption signatures are associated with swaps by swap-id, not peer-id.
- ASB: Transfer proofs are still associated to peer-ids (because they have to be sent to the respective peer), but the ASB can buffer multiple
- CLI: Incoming transfer proofs are checked for matching swap-id. If a transfer proof with a different swap-id than the current executing swap is received it will be ignored. We can change this to saving into the database.

Includes concurrent swap tests with the same Bob.

- One test that pauses and starts an additional swap after the transfer proof was received. Results in both swaps being redeemed after resuming the first swap.
- One test that pauses and starts an additional swap before the transfer proof is sent (just after BTC locked). Results in the second swap redeeming and the first swap being refunded (because the transfer proof on Bob's side is lost). Once we store transfer proofs that we receive during executing a different swap into the database both swaps should redeem.

Note that the monero harness was adapted to allow creating wallets with multiple outputs, which is needed for Alice.
This commit is contained in:
Daniel Karzel 2021-04-08 18:56:26 +10:00
parent 46f144ac67
commit c976358c37
No known key found for this signature in database
GPG key ID: 30C3FC2E438ADB6E
29 changed files with 430 additions and 114 deletions

View file

@ -107,8 +107,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(
@ -128,7 +129,6 @@ async fn main() -> Result<()> {
)
.await?;
let swap_id = Uuid::new_v4();
db.insert_peer_id(swap_id, alice_peer_id).await?;
let swap = Builder::new(
@ -190,7 +190,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(

View file

@ -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,
}

View file

@ -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,
}

View file

@ -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,

View file

@ -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 },

View file

@ -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,9 +43,8 @@ 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>,
@ -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");
@ -262,8 +262,8 @@ where
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")
@ -319,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),
@ -337,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 {
@ -354,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))
}
@ -442,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")?
@ -459,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")?;

View file

@ -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)))
})
}
}

View file

@ -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,
})
}))
}
}

View file

@ -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;
@ -16,7 +15,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,
@ -127,7 +126,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,

View file

@ -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?)
}
}

View file

@ -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,

View file

@ -8,6 +8,7 @@ use crate::{bitcoin, monero};
use anyhow::{bail, Context, Result};
use rand::rngs::OsRng;
use tokio::select;
use uuid::Uuid;
pub fn is_complete(state: &BobState) -> bool {
matches!(
@ -32,6 +33,7 @@ pub async fn run_until(
while !is_target_state(&current_state) {
current_state = next_state(
swap.swap_id,
current_state,
&mut swap.event_loop_handle,
swap.bitcoin_wallet.as_ref(),
@ -51,6 +53,7 @@ pub async fn run_until(
}
async fn next_state(
swap_id: Uuid,
state: BobState,
event_loop_handle: &mut EventLoopHandle,
bitcoin_wallet: &bitcoin::Wallet,
@ -65,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,
@ -103,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");
@ -244,6 +248,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,
@ -254,6 +259,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,