wip: Process swap request in event loop

This commit is contained in:
Franck Royer 2021-02-04 17:40:52 +11:00
parent 815ef90c9f
commit 6b1443b570
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
6 changed files with 86 additions and 23 deletions

5
Cargo.lock generated
View File

@ -2917,10 +2917,11 @@ dependencies = [
[[package]]
name = "rust_decimal"
version = "1.8.1"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e81662973c7a8d9663e64a0de4cd642b89a21d64966e3d99606efdc5fb0cc6"
checksum = "04d1fde955d206c00af1eb529d8ebfca3b505921820a0436566dbcc6c4d4ffb3"
dependencies = [
"arrayvec",
"num-traits",
"serde",
]

View File

@ -40,7 +40,7 @@ pem = "0.8"
prettytable-rs = "0.8"
rand = "0.7"
reqwest = { version = "0.11", default-features = false }
rust_decimal = "1.8"
rust_decimal = "1.10"
serde = { version = "1", features = ["derive"] }
serde_cbor = "0.11"
serde_derive = "1.0"

View File

@ -15,6 +15,7 @@ use rust_decimal::{
};
use serde::{Deserialize, Serialize};
use std::{
convert::TryFrom,
fmt::Display,
ops::{Add, Mul, Sub},
str::FromStr,
@ -88,13 +89,22 @@ impl Amount {
self.0
}
pub fn from_monero(amount: f64) -> Result<Self> {
let decimal = Decimal::try_from(amount)?;
Self::from_decimal(decimal)
}
pub fn parse_monero(amount: &str) -> Result<Self> {
let decimal = Decimal::from_str(amount)?;
Self::from_decimal(decimal)
}
fn from_decimal(amount: Decimal) -> Result<Self> {
let piconeros_dec =
decimal.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64"));
amount.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64"));
let piconeros = piconeros_dec
.to_u64()
.ok_or_else(|| OverflowError(amount.to_owned()))?;
.ok_or_else(|| OverflowError(amount.to_string()))?;
Ok(Amount(piconeros))
}
}

View File

@ -196,6 +196,9 @@ impl Builder {
alice_behaviour,
self.listen_address(),
self.peer_id,
self.execution_params.bitcoin_cancel_timelock,
self.execution_params.bitcoin_punish_timelock,
self.bitcoin_wallet.clone(),
)
}
}

View File

@ -1,7 +1,10 @@
use crate::{
bitcoin,
bitcoin::Timelock,
monero,
network::{request_response::Response, transport::SwapTransport, TokioExecutor},
protocol::{
alice::{Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof},
alice::{swap_response, Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof},
bob::EncryptedSignature,
},
};
@ -9,9 +12,14 @@ use anyhow::{anyhow, Context, Result};
use libp2p::{
core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm,
};
use rand::rngs::OsRng;
use std::sync::Arc;
use tokio::sync::mpsc::{Receiver, Sender};
use tracing::{debug, error, trace};
// TODO: Use dynamic
const RATE: u32 = 100;
#[allow(missing_debug_implementations)]
pub struct Channels<T> {
sender: Sender<T>,
@ -35,7 +43,6 @@ impl<T> Default for Channels<T> {
pub struct EventLoopHandle {
done_execution_setup: Receiver<Result<State3>>,
recv_encrypted_signature: Receiver<EncryptedSignature>,
request: Receiver<crate::protocol::alice::swap_response::OutEvent>,
send_swap_response: Sender<(ResponseChannel<Response>, SwapResponse)>,
start_execution_setup: Sender<(PeerId, State0)>,
send_transfer_proof: Sender<(PeerId, TransferProof)>,
@ -62,15 +69,6 @@ impl EventLoopHandle {
.ok_or_else(|| anyhow!("Failed to receive Bitcoin encrypted signature from Bob"))
}
pub async fn recv_request(
&mut self,
) -> Result<crate::protocol::alice::swap_response::OutEvent> {
self.request
.recv()
.await
.ok_or_else(|| anyhow!("Failed to receive amounts request from Bob"))
}
pub async fn send_swap_response(
&mut self,
channel: ResponseChannel<Response>,
@ -100,10 +98,12 @@ pub struct EventLoop {
start_execution_setup: Receiver<(PeerId, State0)>,
done_execution_setup: Sender<Result<State3>>,
recv_encrypted_signature: Sender<EncryptedSignature>,
request: Sender<crate::protocol::alice::swap_response::OutEvent>,
send_swap_response: Receiver<(ResponseChannel<Response>, SwapResponse)>,
send_transfer_proof: Receiver<(PeerId, TransferProof)>,
recv_transfer_proof_ack: Sender<()>,
cancel_timelock: Timelock,
punish_timelock: Timelock,
bitcoin_wallet: Arc<bitcoin::Wallet>,
}
impl EventLoop {
@ -112,6 +112,10 @@ impl EventLoop {
behaviour: Behaviour,
listen: Multiaddr,
peer_id: PeerId,
// TODO(Franck): Have the timelocks in a struct so they don't get swap by mistake
cancel_timelock: Timelock,
punish_timelock: Timelock,
bitcoin_wallet: Arc<bitcoin::Wallet>,
) -> Result<(Self, EventLoopHandle)> {
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, peer_id)
.executor(Box::new(TokioExecutor {
@ -125,7 +129,6 @@ impl EventLoop {
let start_execution_setup = Channels::new();
let done_execution_setup = Channels::new();
let recv_encrypted_signature = Channels::new();
let request = Channels::new();
let send_swap_response = Channels::new();
let send_transfer_proof = Channels::new();
let recv_transfer_proof_ack = Channels::new();
@ -135,17 +138,18 @@ impl EventLoop {
start_execution_setup: start_execution_setup.receiver,
done_execution_setup: done_execution_setup.sender,
recv_encrypted_signature: recv_encrypted_signature.sender,
request: request.sender,
send_swap_response: send_swap_response.receiver,
send_transfer_proof: send_transfer_proof.receiver,
recv_transfer_proof_ack: recv_transfer_proof_ack.sender,
cancel_timelock,
punish_timelock,
bitcoin_wallet,
};
let handle = EventLoopHandle {
start_execution_setup: start_execution_setup.sender,
done_execution_setup: done_execution_setup.receiver,
recv_encrypted_signature: recv_encrypted_signature.receiver,
request: request.receiver,
send_swap_response: send_swap_response.sender,
send_transfer_proof: send_transfer_proof.sender,
recv_transfer_proof_ack: recv_transfer_proof_ack.receiver,
@ -173,7 +177,7 @@ impl EventLoop {
let _ = self.recv_encrypted_signature.send(*msg).await;
}
OutEvent::Request(event) => {
let _ = self.request.send(*event).await;
let _ = self.handle_swap_request(*event).await;
}
}
},
@ -200,4 +204,43 @@ impl EventLoop {
}
}
}
async fn handle_swap_request(&mut self, event: swap_response::OutEvent) -> Result<()> {
let swap_response::OutEvent {
msg,
bob_peer_id,
channel,
} = event;
// 1. Check if acceptable request
// 2. Send response
let btc_amount = msg.btc_amount;
let xmr_amount = btc_amount.as_btc() * RATE as f64;
let xmr_amount = monero::Amount::from_monero(xmr_amount)?;
let swap_response = SwapResponse { xmr_amount };
self.swarm
.send_swap_response(channel, swap_response)
.context("Failed to send swap response")?;
// 3. Start setup execution
let state0 = State0::new(
btc_amount,
xmr_amount,
self.cancel_timelock,
self.punish_timelock,
self.bitcoin_wallet.as_ref(),
&mut OsRng,
)
.await?;
self.swarm.execution_setup.run(bob_peer_id, state0);
// 4. Trigger swap
todo!();
Ok(())
}
}

View File

@ -10,7 +10,7 @@ use libp2p::{
RequestResponseEvent, RequestResponseMessage, ResponseChannel,
},
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
NetworkBehaviour,
NetworkBehaviour, PeerId,
};
use serde::{Deserialize, Serialize};
use std::{
@ -23,6 +23,7 @@ use tracing::{debug, error};
#[derive(Debug)]
pub struct OutEvent {
pub msg: bob::SwapRequest,
pub bob_peer_id: PeerId,
pub channel: ResponseChannel<Response>,
}
@ -86,6 +87,7 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for B
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
match event {
RequestResponseEvent::Message {
peer,
message:
RequestResponseMessage::Request {
request, channel, ..
@ -94,7 +96,11 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for B
} => {
if let Request::SwapRequest(msg) = request {
debug!("Received swap request");
self.events.push_back(OutEvent { msg: *msg, channel })
self.events.push_back(OutEvent {
bob_peer_id: peer,
msg: *msg,
channel,
})
}
}
RequestResponseEvent::Message {