mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Merge #173
173: Use libp2p-async-await to improve API of execution setup phase r=D4nte a=D4nte Co-authored-by: Franck Royer <franck@coblox.tech>
This commit is contained in:
commit
ec661178f4
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -1637,6 +1637,15 @@ dependencies = [
|
||||
"wasm-timer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-async-await"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/comit-network/rust-libp2p-async-await?rev=1429cd780204624b4d244e7d8179fe6ff77988c3#1429cd780204624b4d244e7d8179fe6ff77988c3"
|
||||
dependencies = [
|
||||
"libp2p",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-core"
|
||||
version = "0.27.0"
|
||||
@ -3415,6 +3424,7 @@ dependencies = [
|
||||
"get-port",
|
||||
"hyper",
|
||||
"libp2p",
|
||||
"libp2p-async-await",
|
||||
"log",
|
||||
"miniscript",
|
||||
"monero",
|
||||
|
@ -20,22 +20,22 @@ end
|
||||
|
||||
group Execution Setup
|
||||
group Phase A [Messages can be exchanged in any order]
|
||||
Bob -> Alice: bob::Message0
|
||||
Bob -> Alice: Message0
|
||||
note left: Pubkeys\ndleq proof s_b\nxmr viewkey v_b\nbtc refund addr
|
||||
|
||||
Alice -> Bob: alice::Message0
|
||||
Alice -> Bob: Message1
|
||||
note right: Pubkeys\ndleq proof s_a\nxmr view key v_a\nbtc redeem addr\nbtc punish addr
|
||||
end
|
||||
|
||||
group Phase B [Messages must be exchanged in the given order]
|
||||
|
||||
Bob -> Alice: Message1
|
||||
Bob -> Alice: Message2
|
||||
note left: unsigned btc lock tx
|
||||
|
||||
Alice -> Bob: Message2
|
||||
Alice -> Bob: Message3
|
||||
note right: btc cancel tx sig\nbtc refund tx enc sig S_b
|
||||
|
||||
Bob -> Alice: Message3
|
||||
Bob -> Alice: Message4
|
||||
note left: btc punish tx sig\nbtc cancel tx sig
|
||||
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
edition = "2018"
|
||||
condense_wildcard_suffixes = true
|
||||
format_macro_matchers = true
|
||||
merge_imports = true
|
||||
imports_granularity = "Crate"
|
||||
use_field_init_shorthand = true
|
||||
format_code_in_doc_comments = true
|
||||
normalize_comments = true
|
||||
|
@ -303,14 +303,11 @@ impl IntoIterator for Args {
|
||||
type IntoIter = ::std::vec::IntoIter<String>;
|
||||
|
||||
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
|
||||
let mut args = Vec::new();
|
||||
|
||||
args.push("/bin/bash".into());
|
||||
args.push("-c".into());
|
||||
|
||||
let cmd = format!("{} ", self.image_args.args());
|
||||
args.push(cmd);
|
||||
|
||||
args.into_iter()
|
||||
vec![
|
||||
"/bin/bash".to_string(),
|
||||
"-c".to_string(),
|
||||
format!("{} ", self.image_args.args()),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
nightly-2020-08-13
|
||||
nightly-2021-01-31
|
||||
|
@ -1,7 +1,7 @@
|
||||
edition = "2018"
|
||||
condense_wildcard_suffixes = true
|
||||
format_macro_matchers = true
|
||||
merge_imports = true
|
||||
imports_granularity = "Crate"
|
||||
use_field_init_shorthand = true
|
||||
format_code_in_doc_comments = true
|
||||
normalize_comments = true
|
||||
|
@ -25,6 +25,7 @@ ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", rev = "cdfbc766045
|
||||
ed25519-dalek = { version = "1.0.0-pre.4", features = ["serde"] }# Cannot be 1 because they depend on curve25519-dalek version 3
|
||||
futures = { version = "0.3", default-features = false }
|
||||
libp2p = { version = "0.34", default-features = false, features = ["tcp-tokio", "yamux", "mplex", "dns", "noise", "request-response"] }
|
||||
libp2p-async-await = { git = "https://github.com/comit-network/rust-libp2p-async-await", rev = "1429cd780204624b4d244e7d8179fe6ff77988c3" }
|
||||
log = { version = "0.4", features = ["serde"] }
|
||||
miniscript = { version = "4", features = ["serde"] }
|
||||
monero = { version = "0.9", features = ["serde_support"] }
|
||||
|
@ -157,8 +157,7 @@ impl TransactionBlockHeight for Wallet {
|
||||
.await
|
||||
.map_err(|_| backoff::Error::Transient(Error::Io))?;
|
||||
|
||||
let block_height =
|
||||
block_height.ok_or_else(|| backoff::Error::Transient(Error::NotYetMined))?;
|
||||
let block_height = block_height.ok_or(backoff::Error::Transient(Error::NotYetMined))?;
|
||||
|
||||
Result::<_, backoff::Error<Error>>::Ok(block_height)
|
||||
})
|
||||
|
@ -17,7 +17,7 @@ impl Seed {
|
||||
Ok(Seed(seed::Seed::random()?))
|
||||
}
|
||||
|
||||
pub fn from_file_or_generate(data_dir: &PathBuf) -> Result<Self, Error> {
|
||||
pub fn from_file_or_generate(data_dir: &Path) -> Result<Self, Error> {
|
||||
let file_path_buf = data_dir.join("seed.pem");
|
||||
let file_path = Path::new(&file_path_buf);
|
||||
|
||||
|
@ -1,67 +1,21 @@
|
||||
use crate::protocol::{alice, alice::TransferProof, bob, bob::EncryptedSignature};
|
||||
use async_trait::async_trait;
|
||||
use futures::prelude::*;
|
||||
use libp2p::{
|
||||
core::{upgrade, upgrade::ReadOneError},
|
||||
request_response::{ProtocolName, RequestResponseCodec},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{fmt::Debug, io, marker::PhantomData};
|
||||
|
||||
/// Time to wait for a response back once we send a request.
|
||||
pub const TIMEOUT: u64 = 3600; // One hour.
|
||||
|
||||
/// Message receive buffer.
|
||||
const BUF_SIZE: usize = 1024 * 1024;
|
||||
|
||||
// TODO: Think about whether there is a better way to do this, e.g., separate
|
||||
// Codec for each Message and a macro that implements them.
|
||||
|
||||
/// Messages Bob sends to Alice.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum BobToAlice {
|
||||
SwapRequest(Box<bob::SwapRequest>),
|
||||
Message0(Box<bob::Message0>),
|
||||
Message1(Box<bob::Message1>),
|
||||
Message2(Box<bob::Message2>),
|
||||
}
|
||||
|
||||
/// Messages Alice sends to Bob.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum AliceToBob {
|
||||
SwapResponse(Box<alice::SwapResponse>),
|
||||
Message0(Box<alice::Message0>),
|
||||
Message1(Box<alice::Message1>),
|
||||
Message2,
|
||||
}
|
||||
|
||||
/// Messages sent from one party to the other.
|
||||
/// All responses are empty
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Request {
|
||||
TransferProof(Box<TransferProof>),
|
||||
EncryptedSignature(Box<EncryptedSignature>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
/// Response are only used for acknowledgement purposes.
|
||||
pub enum Response {
|
||||
TransferProof,
|
||||
EncryptedSignature,
|
||||
}
|
||||
pub const BUF_SIZE: usize = 1024 * 1024;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Swap;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Message0Protocol;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Message1Protocol;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Message2Protocol;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct TransferProofProtocol;
|
||||
|
||||
@ -70,139 +24,45 @@ pub struct EncryptedSignatureProtocol;
|
||||
|
||||
impl ProtocolName for Swap {
|
||||
fn protocol_name(&self) -> &[u8] {
|
||||
b"/xmr/btc/swap/1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolName for Message0Protocol {
|
||||
fn protocol_name(&self) -> &[u8] {
|
||||
b"/xmr/btc/message0/1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolName for Message1Protocol {
|
||||
fn protocol_name(&self) -> &[u8] {
|
||||
b"/xmr/btc/message1/1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolName for Message2Protocol {
|
||||
fn protocol_name(&self) -> &[u8] {
|
||||
b"/xmr/btc/message2/1.0.0"
|
||||
b"/comit/xmr/btc/swap/1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolName for TransferProofProtocol {
|
||||
fn protocol_name(&self) -> &[u8] {
|
||||
b"/xmr/btc/transfer_proof/1.0.0"
|
||||
b"/comit/xmr/btc/transfer_proof/1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolName for EncryptedSignatureProtocol {
|
||||
fn protocol_name(&self) -> &[u8] {
|
||||
b"/xmr/btc/encrypted_signature/1.0.0"
|
||||
b"/comit/xmr/btc/encrypted_signature/1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Codec<P> {
|
||||
phantom: PhantomData<P>,
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CborCodec<P, Req, Res> {
|
||||
phantom: PhantomData<(P, Req, Res)>,
|
||||
}
|
||||
|
||||
impl<P, Req, Res> Default for CborCodec<P, Req, Res> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
phantom: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<P> RequestResponseCodec for Codec<P>
|
||||
impl<P, Req, Res> RequestResponseCodec for CborCodec<P, Req, Res>
|
||||
where
|
||||
P: Send + Sync + Clone + ProtocolName,
|
||||
P: ProtocolName + Send + Sync + Clone,
|
||||
Req: DeserializeOwned + Serialize + Send,
|
||||
Res: DeserializeOwned + Serialize + Send,
|
||||
{
|
||||
type Protocol = P;
|
||||
type Request = BobToAlice;
|
||||
type Response = AliceToBob;
|
||||
|
||||
async fn read_request<T>(&mut self, _: &Self::Protocol, io: &mut T) -> io::Result<Self::Request>
|
||||
where
|
||||
T: AsyncRead + Unpin + Send,
|
||||
{
|
||||
let message = upgrade::read_one(io, BUF_SIZE)
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let mut de = serde_cbor::Deserializer::from_slice(&message);
|
||||
let msg = BobToAlice::deserialize(&mut de).map_err(|e| {
|
||||
tracing::debug!("serde read_request error: {:?}", e);
|
||||
io::Error::new(io::ErrorKind::Other, e)
|
||||
})?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
async fn read_response<T>(
|
||||
&mut self,
|
||||
_: &Self::Protocol,
|
||||
io: &mut T,
|
||||
) -> io::Result<Self::Response>
|
||||
where
|
||||
T: AsyncRead + Unpin + Send,
|
||||
{
|
||||
let message = upgrade::read_one(io, BUF_SIZE)
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let mut de = serde_cbor::Deserializer::from_slice(&message);
|
||||
let msg = AliceToBob::deserialize(&mut de).map_err(|e| {
|
||||
tracing::debug!("serde read_response error: {:?}", e);
|
||||
io::Error::new(io::ErrorKind::InvalidData, e)
|
||||
})?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
async fn write_request<T>(
|
||||
&mut self,
|
||||
_: &Self::Protocol,
|
||||
io: &mut T,
|
||||
req: Self::Request,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
T: AsyncWrite + Unpin + Send,
|
||||
{
|
||||
let bytes =
|
||||
serde_cbor::to_vec(&req).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
upgrade::write_one(io, &bytes).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn write_response<T>(
|
||||
&mut self,
|
||||
_: &Self::Protocol,
|
||||
io: &mut T,
|
||||
res: Self::Response,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
T: AsyncWrite + Unpin + Send,
|
||||
{
|
||||
let bytes = serde_cbor::to_vec(&res).map_err(|e| {
|
||||
tracing::debug!("serde write_reponse error: {:?}", e);
|
||||
io::Error::new(io::ErrorKind::InvalidData, e)
|
||||
})?;
|
||||
upgrade::write_one(io, &bytes).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct OneShotCodec<P> {
|
||||
phantom: PhantomData<P>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<P> RequestResponseCodec for OneShotCodec<P>
|
||||
where
|
||||
P: Send + Sync + Clone + ProtocolName,
|
||||
{
|
||||
type Protocol = P;
|
||||
type Request = Request;
|
||||
type Response = Response;
|
||||
type Request = Req;
|
||||
type Response = Res;
|
||||
|
||||
async fn read_request<T>(&mut self, _: &Self::Protocol, io: &mut T) -> io::Result<Self::Request>
|
||||
where
|
||||
@ -213,7 +73,7 @@ where
|
||||
e => io::Error::new(io::ErrorKind::Other, e),
|
||||
})?;
|
||||
let mut de = serde_cbor::Deserializer::from_slice(&message);
|
||||
let msg = Request::deserialize(&mut de).map_err(|e| {
|
||||
let msg = Req::deserialize(&mut de).map_err(|e| {
|
||||
tracing::debug!("serde read_request error: {:?}", e);
|
||||
io::Error::new(io::ErrorKind::Other, e)
|
||||
})?;
|
||||
@ -233,7 +93,7 @@ where
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let mut de = serde_cbor::Deserializer::from_slice(&message);
|
||||
let msg = Response::deserialize(&mut de).map_err(|e| {
|
||||
let msg = Res::deserialize(&mut de).map_err(|e| {
|
||||
tracing::debug!("serde read_response error: {:?}", e);
|
||||
io::Error::new(io::ErrorKind::InvalidData, e)
|
||||
})?;
|
||||
@ -268,7 +128,7 @@ where
|
||||
T: AsyncWrite + Unpin + Send,
|
||||
{
|
||||
let bytes = serde_cbor::to_vec(&res).map_err(|e| {
|
||||
tracing::debug!("serde write_reponse error: {:?}", e);
|
||||
tracing::debug!("serde write_response error: {:?}", e);
|
||||
io::Error::new(io::ErrorKind::InvalidData, e)
|
||||
})?;
|
||||
upgrade::write_one(io, &bytes).await?;
|
||||
|
@ -1,14 +1,5 @@
|
||||
//! Run an XMR/BTC swap in the role of Alice.
|
||||
//! Alice holds XMR and wishes receive BTC.
|
||||
pub use self::{
|
||||
event_loop::{EventLoop, EventLoopHandle},
|
||||
message0::Message0,
|
||||
message1::Message1,
|
||||
state::*,
|
||||
swap::{run, run_until},
|
||||
swap_response::*,
|
||||
transfer_proof::TransferProof,
|
||||
};
|
||||
use crate::{
|
||||
bitcoin, database,
|
||||
database::Database,
|
||||
@ -16,14 +7,13 @@ use crate::{
|
||||
monero,
|
||||
network::{
|
||||
peer_tracker::{self, PeerTracker},
|
||||
request_response::AliceToBob,
|
||||
transport::build,
|
||||
Seed as NetworkSeed,
|
||||
},
|
||||
protocol::{bob, bob::EncryptedSignature, SwapAmounts},
|
||||
protocol::{bob::EncryptedSignature, SwapAmounts},
|
||||
seed::Seed,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{bail, Error, Result};
|
||||
use libp2p::{
|
||||
core::Multiaddr, identity::Keypair, request_response::ResponseChannel, NetworkBehaviour, PeerId,
|
||||
};
|
||||
@ -32,11 +22,20 @@ use std::{path::PathBuf, sync::Arc};
|
||||
use tracing::{debug, info};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub use self::{
|
||||
event_loop::{EventLoop, EventLoopHandle},
|
||||
execution_setup::Message1,
|
||||
state::*,
|
||||
swap::{run, run_until},
|
||||
swap_response::*,
|
||||
transfer_proof::TransferProof,
|
||||
};
|
||||
use crate::protocol::bob::SwapRequest;
|
||||
pub use execution_setup::Message3;
|
||||
|
||||
mod encrypted_signature;
|
||||
pub mod event_loop;
|
||||
mod message0;
|
||||
mod message1;
|
||||
mod message2;
|
||||
mod execution_setup;
|
||||
pub mod state;
|
||||
mod steps;
|
||||
pub mod swap;
|
||||
@ -198,6 +197,7 @@ impl Builder {
|
||||
self.execution_params.bitcoin_punish_timelock,
|
||||
redeem_address,
|
||||
punish_address,
|
||||
rng,
|
||||
);
|
||||
|
||||
Ok(AliceState::Started { amounts, state0 })
|
||||
@ -218,25 +218,18 @@ impl Builder {
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
ConnectionEstablished(PeerId),
|
||||
// TODO (Franck): Change this to get both amounts so parties can verify the amounts are
|
||||
// expected early on.
|
||||
Request(Box<swap_response::OutEvent>), /* Not-uniform with Bob on purpose, ready for adding
|
||||
* Xmr
|
||||
* event. */
|
||||
Message0 {
|
||||
msg: Box<bob::Message0>,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
},
|
||||
Message1 {
|
||||
msg: bob::Message1,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
},
|
||||
Message2 {
|
||||
msg: Box<bob::Message2>,
|
||||
bob_peer_id: PeerId,
|
||||
SwapRequest {
|
||||
msg: SwapRequest,
|
||||
channel: ResponseChannel<SwapResponse>,
|
||||
},
|
||||
ExecutionSetupDone(Result<Box<State3>>),
|
||||
TransferProofAcknowledged,
|
||||
EncryptedSignature(EncryptedSignature),
|
||||
EncryptedSignature {
|
||||
msg: Box<EncryptedSignature>,
|
||||
channel: ResponseChannel<()>,
|
||||
},
|
||||
ResponseSent, // Same variant is used for all messages as no processing is done
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
impl From<peer_tracker::OutEvent> for OutEvent {
|
||||
@ -251,52 +244,43 @@ impl From<peer_tracker::OutEvent> for OutEvent {
|
||||
|
||||
impl From<swap_response::OutEvent> for OutEvent {
|
||||
fn from(event: swap_response::OutEvent) -> Self {
|
||||
OutEvent::Request(Box::new(event))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<message0::OutEvent> for OutEvent {
|
||||
fn from(event: message0::OutEvent) -> Self {
|
||||
use swap_response::OutEvent::*;
|
||||
match event {
|
||||
message0::OutEvent::Msg { channel, msg } => OutEvent::Message0 {
|
||||
msg: Box::new(msg),
|
||||
channel,
|
||||
},
|
||||
MsgReceived { msg, channel } => OutEvent::SwapRequest { msg, channel },
|
||||
ResponseSent => OutEvent::ResponseSent,
|
||||
Failure(err) => OutEvent::Failure(err.context("Swap Request/Response failure")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<message1::OutEvent> for OutEvent {
|
||||
fn from(event: message1::OutEvent) -> Self {
|
||||
impl From<execution_setup::OutEvent> for OutEvent {
|
||||
fn from(event: execution_setup::OutEvent) -> Self {
|
||||
match event {
|
||||
message1::OutEvent::Msg { msg, channel } => OutEvent::Message1 { msg, channel },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<message2::OutEvent> for OutEvent {
|
||||
fn from(event: message2::OutEvent) -> Self {
|
||||
match event {
|
||||
message2::OutEvent::Msg { msg, bob_peer_id } => OutEvent::Message2 {
|
||||
msg: Box::new(msg),
|
||||
bob_peer_id,
|
||||
},
|
||||
execution_setup::OutEvent::Done(res) => OutEvent::ExecutionSetupDone(res.map(Box::new)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<transfer_proof::OutEvent> for OutEvent {
|
||||
fn from(event: transfer_proof::OutEvent) -> Self {
|
||||
use transfer_proof::OutEvent::*;
|
||||
match event {
|
||||
transfer_proof::OutEvent::Acknowledged => OutEvent::TransferProofAcknowledged,
|
||||
Acknowledged => OutEvent::TransferProofAcknowledged,
|
||||
Failure(err) => OutEvent::Failure(err.context("Failure with Transfer Proof")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<encrypted_signature::OutEvent> for OutEvent {
|
||||
fn from(event: encrypted_signature::OutEvent) -> Self {
|
||||
use encrypted_signature::OutEvent::*;
|
||||
match event {
|
||||
encrypted_signature::OutEvent::Msg(msg) => OutEvent::EncryptedSignature(msg),
|
||||
MsgReceived { msg, channel } => OutEvent::EncryptedSignature {
|
||||
msg: Box::new(msg),
|
||||
channel,
|
||||
},
|
||||
AckSent => OutEvent::ResponseSent,
|
||||
Failure(err) => OutEvent::Failure(err.context("Failure with Encrypted Signature")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -308,9 +292,7 @@ impl From<encrypted_signature::OutEvent> for OutEvent {
|
||||
pub struct Behaviour {
|
||||
pt: PeerTracker,
|
||||
amounts: swap_response::Behaviour,
|
||||
message0: message0::Behaviour,
|
||||
message1: message1::Behaviour,
|
||||
message2: message2::Behaviour,
|
||||
execution_setup: execution_setup::Behaviour,
|
||||
transfer_proof: transfer_proof::Behaviour,
|
||||
encrypted_signature: encrypted_signature::Behaviour,
|
||||
}
|
||||
@ -319,7 +301,7 @@ impl Behaviour {
|
||||
/// Alice always sends her messages as a response to a request from Bob.
|
||||
pub fn send_swap_response(
|
||||
&mut self,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
channel: ResponseChannel<SwapResponse>,
|
||||
swap_response: SwapResponse,
|
||||
) -> Result<()> {
|
||||
self.amounts.send(channel, swap_response)?;
|
||||
@ -327,26 +309,9 @@ impl Behaviour {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send Message0 to Bob in response to receiving his Message0.
|
||||
pub fn send_message0(
|
||||
&mut self,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
msg: Message0,
|
||||
) -> Result<()> {
|
||||
self.message0.send(channel, msg)?;
|
||||
debug!("Sent Message0");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send Message1 to Bob in response to receiving his Message1.
|
||||
pub fn send_message1(
|
||||
&mut self,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
msg: Message1,
|
||||
) -> Result<()> {
|
||||
self.message1.send(channel, msg)?;
|
||||
debug!("Sent Message1");
|
||||
Ok(())
|
||||
pub fn start_execution_setup(&mut self, bob_peer_id: PeerId, state0: State0) {
|
||||
self.execution_setup.run(bob_peer_id, state0);
|
||||
info!("Start execution setup with {}", bob_peer_id);
|
||||
}
|
||||
|
||||
/// Send Transfer Proof to Bob.
|
||||
|
@ -1,53 +1,42 @@
|
||||
use crate::{
|
||||
network::request_response::{
|
||||
EncryptedSignatureProtocol, OneShotCodec, Request, Response, TIMEOUT,
|
||||
},
|
||||
network::request_response::{CborCodec, EncryptedSignatureProtocol, TIMEOUT},
|
||||
protocol::bob::EncryptedSignature,
|
||||
};
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||
RequestResponseMessage, ResponseChannel,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour,
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
use std::time::Duration;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg(EncryptedSignature),
|
||||
MsgReceived {
|
||||
msg: EncryptedSignature,
|
||||
channel: ResponseChannel<()>,
|
||||
},
|
||||
AckSent,
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents receiving the Bitcoin encrypted
|
||||
/// signature from Bob.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<OneShotCodec<EncryptedSignatureProtocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
rr: RequestResponse<CborCodec<EncryptedSignatureProtocol, EncryptedSignature, ()>>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<
|
||||
NetworkBehaviourAction<RequestProtocol<OneShotCodec<EncryptedSignatureProtocol>>, OutEvent>,
|
||||
> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
pub fn send_ack(&mut self, channel: ResponseChannel<()>) -> Result<()> {
|
||||
self.rr
|
||||
.send_response(channel, ())
|
||||
.map_err(|err| anyhow!("Failed to ack encrypted signature: {:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,48 +48,42 @@ impl Default for Behaviour {
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
OneShotCodec::default(),
|
||||
CborCodec::default(),
|
||||
vec![(EncryptedSignatureProtocol, ProtocolSupport::Inbound)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
|
||||
impl From<RequestResponseEvent<EncryptedSignature, ()>> for OutEvent {
|
||||
fn from(event: RequestResponseEvent<EncryptedSignature, ()>) -> Self {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
peer,
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
if let Request::EncryptedSignature(msg) = request {
|
||||
debug!("Received encrypted signature");
|
||||
self.events.push_back(OutEvent::Msg(*msg));
|
||||
// Send back empty response so that the request/response protocol completes.
|
||||
if let Err(error) = self.rr.send_response(channel, Response::EncryptedSignature)
|
||||
{
|
||||
error!("Failed to send Encrypted Signature ack: {:?}", error);
|
||||
}
|
||||
debug!("Received encrypted signature from {}", peer);
|
||||
OutEvent::MsgReceived {
|
||||
msg: request,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => panic!("Alice should not get a Response"),
|
||||
} => OutEvent::Failure(anyhow!("Alice should not get a Response")),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
debug!("Alice has sent an Message3 response to Bob");
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => OutEvent::AckSent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
use crate::{
|
||||
network::{request_response::AliceToBob, transport::SwapTransport, TokioExecutor},
|
||||
network::{transport::SwapTransport, TokioExecutor},
|
||||
protocol::{
|
||||
alice,
|
||||
alice::{Behaviour, OutEvent, SwapResponse, TransferProof},
|
||||
bob,
|
||||
bob::EncryptedSignature,
|
||||
alice::{Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof},
|
||||
bob::{EncryptedSignature, SwapRequest},
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
@ -35,15 +33,12 @@ impl<T> Default for Channels<T> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventLoopHandle {
|
||||
recv_message0: Receiver<(bob::Message0, ResponseChannel<AliceToBob>)>,
|
||||
recv_message1: Receiver<(bob::Message1, ResponseChannel<AliceToBob>)>,
|
||||
recv_message2: Receiver<bob::Message2>,
|
||||
done_execution_setup: Receiver<Result<State3>>,
|
||||
recv_encrypted_signature: Receiver<EncryptedSignature>,
|
||||
request: Receiver<crate::protocol::alice::swap_response::OutEvent>,
|
||||
recv_swap_request: Receiver<(SwapRequest, ResponseChannel<SwapResponse>)>,
|
||||
conn_established: Receiver<PeerId>,
|
||||
send_swap_response: Sender<(ResponseChannel<AliceToBob>, SwapResponse)>,
|
||||
send_message0: Sender<(ResponseChannel<AliceToBob>, alice::Message0)>,
|
||||
send_message1: Sender<(ResponseChannel<AliceToBob>, alice::Message1)>,
|
||||
send_swap_response: Sender<(ResponseChannel<SwapResponse>, SwapResponse)>,
|
||||
start_execution_setup: Sender<(PeerId, State0)>,
|
||||
send_transfer_proof: Sender<(PeerId, TransferProof)>,
|
||||
recv_transfer_proof_ack: Receiver<()>,
|
||||
}
|
||||
@ -56,25 +51,16 @@ impl EventLoopHandle {
|
||||
.ok_or_else(|| anyhow!("Failed to receive connection established from Bob"))
|
||||
}
|
||||
|
||||
pub async fn recv_message0(&mut self) -> Result<(bob::Message0, ResponseChannel<AliceToBob>)> {
|
||||
self.recv_message0
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("Failed to receive message 0 from Bob"))
|
||||
}
|
||||
pub async fn execution_setup(&mut self, bob_peer_id: PeerId, state0: State0) -> Result<State3> {
|
||||
let _ = self
|
||||
.start_execution_setup
|
||||
.send((bob_peer_id, state0))
|
||||
.await?;
|
||||
|
||||
pub async fn recv_message1(&mut self) -> Result<(bob::Message1, ResponseChannel<AliceToBob>)> {
|
||||
self.recv_message1
|
||||
self.done_execution_setup
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("Failed to receive message 1 from Bob"))
|
||||
}
|
||||
|
||||
pub async fn recv_message2(&mut self) -> Result<bob::Message2> {
|
||||
self.recv_message2
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("Failed to receive message 2 from Bob"))
|
||||
.ok_or_else(|| anyhow!("Failed to setup execution with Bob"))?
|
||||
}
|
||||
|
||||
pub async fn recv_encrypted_signature(&mut self) -> Result<EncryptedSignature> {
|
||||
@ -84,10 +70,10 @@ impl EventLoopHandle {
|
||||
.ok_or_else(|| anyhow!("Failed to receive Bitcoin encrypted signature from Bob"))
|
||||
}
|
||||
|
||||
pub async fn recv_request(
|
||||
pub async fn recv_swap_request(
|
||||
&mut self,
|
||||
) -> Result<crate::protocol::alice::swap_response::OutEvent> {
|
||||
self.request
|
||||
) -> Result<(SwapRequest, ResponseChannel<SwapResponse>)> {
|
||||
self.recv_swap_request
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("Failed to receive amounts request from Bob"))
|
||||
@ -95,7 +81,7 @@ impl EventLoopHandle {
|
||||
|
||||
pub async fn send_swap_response(
|
||||
&mut self,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
channel: ResponseChannel<SwapResponse>,
|
||||
swap_response: SwapResponse,
|
||||
) -> Result<()> {
|
||||
let _ = self
|
||||
@ -105,24 +91,6 @@ impl EventLoopHandle {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_message0(
|
||||
&mut self,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
msg: alice::Message0,
|
||||
) -> Result<()> {
|
||||
let _ = self.send_message0.send((channel, msg)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_message1(
|
||||
&mut self,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
msg: alice::Message1,
|
||||
) -> Result<()> {
|
||||
let _ = self.send_message1.send((channel, msg)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_transfer_proof(&mut self, bob: PeerId, msg: TransferProof) -> Result<()> {
|
||||
let _ = self.send_transfer_proof.send((bob, msg)).await?;
|
||||
|
||||
@ -137,15 +105,12 @@ impl EventLoopHandle {
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct EventLoop {
|
||||
swarm: libp2p::Swarm<Behaviour>,
|
||||
recv_message0: Sender<(bob::Message0, ResponseChannel<AliceToBob>)>,
|
||||
recv_message1: Sender<(bob::Message1, ResponseChannel<AliceToBob>)>,
|
||||
recv_message2: Sender<bob::Message2>,
|
||||
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>,
|
||||
recv_swap_request: Sender<(SwapRequest, ResponseChannel<SwapResponse>)>,
|
||||
conn_established: Sender<PeerId>,
|
||||
send_swap_response: Receiver<(ResponseChannel<AliceToBob>, SwapResponse)>,
|
||||
send_message0: Receiver<(ResponseChannel<AliceToBob>, alice::Message0)>,
|
||||
send_message1: Receiver<(ResponseChannel<AliceToBob>, alice::Message1)>,
|
||||
send_swap_response: Receiver<(ResponseChannel<SwapResponse>, SwapResponse)>,
|
||||
send_transfer_proof: Receiver<(PeerId, TransferProof)>,
|
||||
recv_transfer_proof_ack: Sender<()>,
|
||||
}
|
||||
@ -166,43 +131,34 @@ impl EventLoop {
|
||||
Swarm::listen_on(&mut swarm, listen.clone())
|
||||
.with_context(|| format!("Address is not supported: {:#}", listen))?;
|
||||
|
||||
let recv_message0 = Channels::new();
|
||||
let recv_message1 = Channels::new();
|
||||
let recv_message2 = Channels::new();
|
||||
let start_execution_setup = Channels::new();
|
||||
let done_execution_setup = Channels::new();
|
||||
let recv_encrypted_signature = Channels::new();
|
||||
let request = Channels::new();
|
||||
let conn_established = Channels::new();
|
||||
let send_swap_response = Channels::new();
|
||||
let send_message0 = Channels::new();
|
||||
let send_message1 = Channels::new();
|
||||
let send_transfer_proof = Channels::new();
|
||||
let recv_transfer_proof_ack = Channels::new();
|
||||
|
||||
let driver = EventLoop {
|
||||
swarm,
|
||||
recv_message0: recv_message0.sender,
|
||||
recv_message1: recv_message1.sender,
|
||||
recv_message2: recv_message2.sender,
|
||||
start_execution_setup: start_execution_setup.receiver,
|
||||
done_execution_setup: done_execution_setup.sender,
|
||||
recv_encrypted_signature: recv_encrypted_signature.sender,
|
||||
request: request.sender,
|
||||
recv_swap_request: request.sender,
|
||||
conn_established: conn_established.sender,
|
||||
send_swap_response: send_swap_response.receiver,
|
||||
send_message0: send_message0.receiver,
|
||||
send_message1: send_message1.receiver,
|
||||
send_transfer_proof: send_transfer_proof.receiver,
|
||||
recv_transfer_proof_ack: recv_transfer_proof_ack.sender,
|
||||
};
|
||||
|
||||
let handle = EventLoopHandle {
|
||||
recv_message0: recv_message0.receiver,
|
||||
recv_message1: recv_message1.receiver,
|
||||
recv_message2: recv_message2.receiver,
|
||||
start_execution_setup: start_execution_setup.sender,
|
||||
done_execution_setup: done_execution_setup.receiver,
|
||||
recv_encrypted_signature: recv_encrypted_signature.receiver,
|
||||
request: request.receiver,
|
||||
recv_swap_request: request.receiver,
|
||||
conn_established: conn_established.receiver,
|
||||
send_swap_response: send_swap_response.sender,
|
||||
send_message0: send_message0.sender,
|
||||
send_message1: send_message1.sender,
|
||||
send_transfer_proof: send_transfer_proof.sender,
|
||||
recv_transfer_proof_ack: recv_transfer_proof_ack.receiver,
|
||||
};
|
||||
@ -218,24 +174,26 @@ impl EventLoop {
|
||||
OutEvent::ConnectionEstablished(alice) => {
|
||||
let _ = self.conn_established.send(alice).await;
|
||||
}
|
||||
OutEvent::Message0 { msg, channel } => {
|
||||
let _ = self.recv_message0.send((*msg, channel)).await;
|
||||
OutEvent::SwapRequest { msg, channel } => {
|
||||
let _ = self.recv_swap_request.send((msg, channel)).await;
|
||||
}
|
||||
OutEvent::Message1 { msg, channel } => {
|
||||
let _ = self.recv_message1.send((msg, channel)).await;
|
||||
}
|
||||
OutEvent::Message2 { msg, bob_peer_id : _} => {
|
||||
let _ = self.recv_message2.send(*msg).await;
|
||||
OutEvent::ExecutionSetupDone(res) => {
|
||||
let _ = self.done_execution_setup.send(res.map(|state|*state)).await;
|
||||
}
|
||||
OutEvent::TransferProofAcknowledged => {
|
||||
trace!("Bob acknowledged transfer proof");
|
||||
let _ = self.recv_transfer_proof_ack.send(()).await;
|
||||
}
|
||||
OutEvent::EncryptedSignature(msg) => {
|
||||
let _ = self.recv_encrypted_signature.send(msg).await;
|
||||
OutEvent::EncryptedSignature{ msg, channel } => {
|
||||
let _ = self.recv_encrypted_signature.send(*msg).await;
|
||||
// Send back empty response so that the request/response protocol completes.
|
||||
if let Err(error) = self.swarm.encrypted_signature.send_ack(channel) {
|
||||
error!("Failed to send Encrypted Signature ack: {:?}", error);
|
||||
}
|
||||
OutEvent::Request(event) => {
|
||||
let _ = self.request.send(*event).await;
|
||||
}
|
||||
OutEvent::ResponseSent => {}
|
||||
OutEvent::Failure(err) => {
|
||||
error!("Communication error: {:#}", err);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -247,20 +205,11 @@ impl EventLoop {
|
||||
.map_err(|err|error!("Failed to send swap response: {:#}", err));
|
||||
}
|
||||
},
|
||||
msg0 = self.send_message0.recv().fuse() => {
|
||||
if let Some((channel, msg)) = msg0 {
|
||||
option = self.start_execution_setup.recv().fuse() => {
|
||||
if let Some((bob_peer_id, state0)) = option {
|
||||
let _ = self
|
||||
.swarm
|
||||
.send_message0(channel, msg)
|
||||
.map_err(|err|error!("Failed to send message0: {:#}", err));
|
||||
}
|
||||
},
|
||||
msg1 = self.send_message1.recv().fuse() => {
|
||||
if let Some((channel, msg)) = msg1 {
|
||||
let _ = self
|
||||
.swarm
|
||||
.send_message1(channel, msg)
|
||||
.map_err(|err|error!("Failed to send message1: {:#}", err));
|
||||
.start_execution_setup(bob_peer_id, state0);
|
||||
}
|
||||
},
|
||||
transfer_proof = self.send_transfer_proof.recv().fuse() => {
|
||||
|
98
swap/src/protocol/alice/execution_setup.rs
Normal file
98
swap/src/protocol/alice/execution_setup.rs
Normal file
@ -0,0 +1,98 @@
|
||||
use crate::{
|
||||
bitcoin,
|
||||
bitcoin::{EncryptedSignature, Signature},
|
||||
monero,
|
||||
network::request_response::BUF_SIZE,
|
||||
protocol::{
|
||||
alice::{State0, State3},
|
||||
bob::{Message0, Message2, Message4},
|
||||
},
|
||||
};
|
||||
use anyhow::{Context, Error, Result};
|
||||
use libp2p::PeerId;
|
||||
use libp2p_async_await::BehaviourOutEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message1 {
|
||||
pub(crate) A: bitcoin::PublicKey,
|
||||
pub(crate) S_a_monero: monero::PublicKey,
|
||||
pub(crate) S_a_bitcoin: bitcoin::PublicKey,
|
||||
pub(crate) dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
pub(crate) v_a: monero::PrivateViewKey,
|
||||
pub(crate) redeem_address: bitcoin::Address,
|
||||
pub(crate) punish_address: bitcoin::Address,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message3 {
|
||||
pub(crate) tx_cancel_sig: Signature,
|
||||
pub(crate) tx_refund_encsig: EncryptedSignature,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Done(Result<State3>),
|
||||
}
|
||||
|
||||
impl From<BehaviourOutEvent<State3, (), anyhow::Error>> for OutEvent {
|
||||
fn from(event: BehaviourOutEvent<State3, (), Error>) -> Self {
|
||||
match event {
|
||||
BehaviourOutEvent::Inbound(_, Ok(State3)) => OutEvent::Done(Ok(State3)),
|
||||
BehaviourOutEvent::Inbound(_, Err(e)) => OutEvent::Done(Err(e)),
|
||||
BehaviourOutEvent::Outbound(..) => unreachable!("Alice only supports inbound"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(libp2p::NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
pub struct Behaviour {
|
||||
inner: libp2p_async_await::Behaviour<State3, (), anyhow::Error>,
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: libp2p_async_await::Behaviour::new(b"/comit/xmr/btc/execution_setup/1.0.0"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn run(&mut self, bob: PeerId, state0: State0) {
|
||||
self.inner
|
||||
.do_protocol_listener(bob, move |mut substream| async move {
|
||||
let message0 =
|
||||
serde_cbor::from_slice::<Message0>(&substream.read_message(BUF_SIZE).await?)
|
||||
.context("failed to deserialize message0")?;
|
||||
let state1 = state0.receive(message0)?;
|
||||
|
||||
substream
|
||||
.write_message(
|
||||
&serde_cbor::to_vec(&state1.next_message())
|
||||
.context("failed to serialize message1")?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let message2 =
|
||||
serde_cbor::from_slice::<Message2>(&substream.read_message(BUF_SIZE).await?)
|
||||
.context("failed to deserialize message2")?;
|
||||
let state2 = state1.receive(message2);
|
||||
|
||||
substream
|
||||
.write_message(
|
||||
&serde_cbor::to_vec(&state2.next_message())
|
||||
.context("failed to serialize message3")?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let message4 =
|
||||
serde_cbor::from_slice::<Message4>(&substream.read_message(BUF_SIZE).await?)
|
||||
.context("failed to deserialize message4")?;
|
||||
let state3 = state2.receive(message4)?;
|
||||
|
||||
Ok(state3)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
use crate::{
|
||||
bitcoin, monero,
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Message0Protocol, TIMEOUT},
|
||||
protocol::bob,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage, ResponseChannel,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg {
|
||||
msg: bob::Message0,
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message0 {
|
||||
pub(crate) A: bitcoin::PublicKey,
|
||||
pub(crate) S_a_monero: monero::PublicKey,
|
||||
pub(crate) S_a_bitcoin: bitcoin::PublicKey,
|
||||
pub(crate) dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
pub(crate) v_a: monero::PrivateViewKey,
|
||||
pub(crate) redeem_address: bitcoin::Address,
|
||||
pub(crate) punish_address: bitcoin::Address,
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents send/recv of message 0.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Message0Protocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, channel: ResponseChannel<AliceToBob>, msg: Message0) -> Result<()> {
|
||||
let msg = AliceToBob::Message0(Box::new(msg));
|
||||
self.rr
|
||||
.send_response(channel, msg)
|
||||
.map_err(|alice_to_bob| anyhow!("Could not send response {:?}", alice_to_bob))
|
||||
}
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Message0Protocol>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
let timeout = Duration::from_secs(TIMEOUT);
|
||||
let mut config = RequestResponseConfig::default();
|
||||
config.set_request_timeout(timeout);
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Message0Protocol, ProtocolSupport::Full)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
if let BobToAlice::Message0(msg) = request {
|
||||
debug!("Received Message0");
|
||||
self.events.push_back(OutEvent::Msg { msg: *msg, channel });
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => panic!("Alice should not get a Response"),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
debug!("Alice has sent Message0 as response to Bob");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
use crate::{
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Message1Protocol, TIMEOUT},
|
||||
protocol::bob,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use ecdsa_fun::{adaptor::EncryptedSignature, Signature};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage, ResponseChannel,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg {
|
||||
/// Received message from Bob.
|
||||
msg: bob::Message1,
|
||||
/// Channel to send back Alice's message 1.
|
||||
channel: ResponseChannel<AliceToBob>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message1 {
|
||||
pub(crate) tx_cancel_sig: Signature,
|
||||
pub(crate) tx_refund_encsig: EncryptedSignature,
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents send/recv of message 1.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Message1Protocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, channel: ResponseChannel<AliceToBob>, msg: Message1) -> Result<()> {
|
||||
let msg = AliceToBob::Message1(Box::new(msg));
|
||||
self.rr
|
||||
.send_response(channel, msg)
|
||||
.map_err(|alice_to_bob| anyhow!("Could not send response {:?}", alice_to_bob))
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Message1Protocol>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
let timeout = Duration::from_secs(TIMEOUT);
|
||||
let mut config = RequestResponseConfig::default();
|
||||
config.set_request_timeout(timeout);
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Message1Protocol, ProtocolSupport::Full)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
if let BobToAlice::Message1(msg) = request {
|
||||
debug!("Received Message1");
|
||||
self.events.push_back(OutEvent::Msg { msg: *msg, channel });
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => panic!("Alice should not get a Response"),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
debug!("Alice has sent an Message1 response to Bob");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
use crate::{
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Message2Protocol, TIMEOUT},
|
||||
protocol::bob,
|
||||
};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg {
|
||||
msg: bob::Message2,
|
||||
bob_peer_id: PeerId,
|
||||
},
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents receiving of message 2 from Bob.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Message2Protocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Message2Protocol>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
let timeout = Duration::from_secs(TIMEOUT);
|
||||
let mut config = RequestResponseConfig::default();
|
||||
config.set_request_timeout(timeout);
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Message2Protocol, ProtocolSupport::Full)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
peer,
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
} => {
|
||||
if let BobToAlice::Message2(msg) = request {
|
||||
debug!("Received Message 2");
|
||||
self.events.push_back(OutEvent::Msg {
|
||||
msg: *msg,
|
||||
bob_peer_id: peer,
|
||||
});
|
||||
// Send back empty response so that the request/response protocol completes.
|
||||
let _ = self.rr.send_response(channel, AliceToBob::Message2);
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => panic!("Alice should not get a Response"),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
debug!("Alice has sent a Message2 response to Bob");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,11 @@ use crate::{
|
||||
TxRefund, WatchForRawTransaction,
|
||||
},
|
||||
monero,
|
||||
protocol::{alice, alice::TransferProof, bob, bob::EncryptedSignature, SwapAmounts},
|
||||
protocol::{
|
||||
alice::{Message1, Message3, TransferProof},
|
||||
bob::{EncryptedSignature, Message0, Message2, Message4},
|
||||
SwapAmounts,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic};
|
||||
@ -16,7 +20,6 @@ use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha256;
|
||||
use std::fmt;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AliceState {
|
||||
@ -87,6 +90,7 @@ pub struct State0 {
|
||||
pub a: bitcoin::SecretKey,
|
||||
pub s_a: cross_curve_dleq::Scalar,
|
||||
pub v_a: monero::PrivateViewKey,
|
||||
pub dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||
pub btc: bitcoin::Amount,
|
||||
pub xmr: monero::Amount,
|
||||
@ -98,7 +102,7 @@ pub struct State0 {
|
||||
|
||||
impl State0 {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
pub fn new<R>(
|
||||
a: bitcoin::SecretKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
v_a: monero::PrivateViewKey,
|
||||
@ -108,11 +112,18 @@ impl State0 {
|
||||
punish_timelock: Timelock,
|
||||
redeem_address: bitcoin::Address,
|
||||
punish_address: bitcoin::Address,
|
||||
) -> Self {
|
||||
rng: &mut R,
|
||||
) -> Self
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let dleq_proof_s_a = cross_curve_dleq::Proof::new(rng, &s_a);
|
||||
|
||||
Self {
|
||||
a,
|
||||
s_a,
|
||||
v_a,
|
||||
dleq_proof_s_a,
|
||||
redeem_address,
|
||||
punish_address,
|
||||
btc,
|
||||
@ -122,24 +133,7 @@ impl State0 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_message<R: RngCore + CryptoRng>(&self, rng: &mut R) -> alice::Message0 {
|
||||
info!("Producing first message");
|
||||
let dleq_proof_s_a = cross_curve_dleq::Proof::new(rng, &self.s_a);
|
||||
|
||||
alice::Message0 {
|
||||
A: self.a.public(),
|
||||
S_a_monero: monero::PublicKey::from_private_key(&monero::PrivateKey {
|
||||
scalar: self.s_a.into_ed25519(),
|
||||
}),
|
||||
S_a_bitcoin: self.s_a.into_secp256k1().into(),
|
||||
dleq_proof_s_a,
|
||||
v_a: self.v_a,
|
||||
redeem_address: self.redeem_address.clone(),
|
||||
punish_address: self.punish_address.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: bob::Message0) -> Result<State1> {
|
||||
pub fn receive(self, msg: Message0) -> Result<State1> {
|
||||
msg.dleq_proof_s_b.verify(
|
||||
msg.S_b_bitcoin.clone().into(),
|
||||
msg.S_b_monero
|
||||
@ -157,6 +151,8 @@ impl State0 {
|
||||
S_b_monero: msg.S_b_monero,
|
||||
S_b_bitcoin: msg.S_b_bitcoin,
|
||||
v,
|
||||
v_a: self.v_a,
|
||||
dleq_proof_s_a: self.dleq_proof_s_a,
|
||||
btc: self.btc,
|
||||
xmr: self.xmr,
|
||||
cancel_timelock: self.cancel_timelock,
|
||||
@ -176,6 +172,8 @@ pub struct State1 {
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
v_a: monero::PrivateViewKey,
|
||||
dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
@ -187,7 +185,21 @@ pub struct State1 {
|
||||
}
|
||||
|
||||
impl State1 {
|
||||
pub fn receive(self, msg: bob::Message1) -> State2 {
|
||||
pub fn next_message(&self) -> Message1 {
|
||||
Message1 {
|
||||
A: self.a.public(),
|
||||
S_a_monero: monero::PublicKey::from_private_key(&monero::PrivateKey {
|
||||
scalar: self.s_a.into_ed25519(),
|
||||
}),
|
||||
S_a_bitcoin: self.s_a.into_secp256k1().into(),
|
||||
dleq_proof_s_a: self.dleq_proof_s_a.clone(),
|
||||
v_a: self.v_a,
|
||||
redeem_address: self.redeem_address.clone(),
|
||||
punish_address: self.punish_address.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: Message2) -> State2 {
|
||||
State2 {
|
||||
a: self.a,
|
||||
B: self.B,
|
||||
@ -227,7 +239,7 @@ pub struct State2 {
|
||||
}
|
||||
|
||||
impl State2 {
|
||||
pub fn next_message(&self) -> alice::Message1 {
|
||||
pub fn next_message(&self) -> Message3 {
|
||||
let tx_cancel =
|
||||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
||||
|
||||
@ -240,13 +252,13 @@ impl State2 {
|
||||
let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_refund.digest());
|
||||
|
||||
let tx_cancel_sig = self.a.sign(tx_cancel.digest());
|
||||
alice::Message1 {
|
||||
Message3 {
|
||||
tx_refund_encsig,
|
||||
tx_cancel_sig,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: bob::Message2) -> Result<State3> {
|
||||
pub fn receive(self, msg: Message4) -> Result<State3> {
|
||||
let tx_cancel =
|
||||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
||||
bitcoin::verify_sig(&self.B, &tx_cancel.digest(), &msg.tx_cancel_sig)
|
||||
|
@ -23,7 +23,6 @@ use futures::{
|
||||
pin_mut,
|
||||
};
|
||||
use libp2p::PeerId;
|
||||
use rand::rngs::OsRng;
|
||||
use sha2::Sha256;
|
||||
use std::sync::Arc;
|
||||
use tokio::time::timeout;
|
||||
@ -47,48 +46,21 @@ pub async fn negotiate(
|
||||
|
||||
let event = timeout(
|
||||
execution_params.bob_time_to_act,
|
||||
event_loop_handle.recv_request(),
|
||||
event_loop_handle.recv_swap_request(),
|
||||
)
|
||||
.await
|
||||
.context("Failed to receive swap request from Bob")??;
|
||||
|
||||
event_loop_handle
|
||||
.send_swap_response(event.channel, SwapResponse { xmr_amount })
|
||||
.send_swap_response(event.1, SwapResponse { xmr_amount })
|
||||
.await?;
|
||||
|
||||
let (bob_message0, channel) = timeout(
|
||||
let state3 = timeout(
|
||||
execution_params.bob_time_to_act,
|
||||
event_loop_handle.recv_message0(),
|
||||
event_loop_handle.execution_setup(bob_peer_id, state0),
|
||||
)
|
||||
.await??;
|
||||
|
||||
let alice_message0 = state0.next_message(&mut OsRng);
|
||||
event_loop_handle
|
||||
.send_message0(channel, alice_message0)
|
||||
.await?;
|
||||
|
||||
let state1 = state0.receive(bob_message0)?;
|
||||
|
||||
let (bob_message1, channel) = timeout(
|
||||
execution_params.bob_time_to_act,
|
||||
event_loop_handle.recv_message1(),
|
||||
)
|
||||
.await??;
|
||||
|
||||
let state2 = state1.receive(bob_message1);
|
||||
|
||||
event_loop_handle
|
||||
.send_message1(channel, state2.next_message())
|
||||
.await?;
|
||||
|
||||
let bob_message2 = timeout(
|
||||
execution_params.bob_time_to_act,
|
||||
event_loop_handle.recv_message2(),
|
||||
)
|
||||
.await??;
|
||||
|
||||
let state3 = state2.receive(bob_message2)?;
|
||||
|
||||
Ok((bob_peer_id, state3))
|
||||
}
|
||||
|
||||
|
@ -247,9 +247,7 @@ async fn run_until_internal(
|
||||
.await;
|
||||
|
||||
match publishded_redeem_tx {
|
||||
Ok(_) => {
|
||||
AliceState::BtcRedeemed
|
||||
}
|
||||
Ok(_) => AliceState::BtcRedeemed,
|
||||
Err(e) => {
|
||||
bail!("Waiting for Bitcoin transaction finality failed with {}! The redeem transaction was published, but it is not ensured that the transaction was included! You're screwed.", e)
|
||||
}
|
||||
|
@ -1,29 +1,28 @@
|
||||
use crate::{
|
||||
monero,
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Swap, TIMEOUT},
|
||||
protocol::bob,
|
||||
network::request_response::{CborCodec, Swap, TIMEOUT},
|
||||
protocol::bob::SwapRequest,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage, ResponseChannel,
|
||||
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||
RequestResponseMessage, ResponseChannel,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
use std::time::Duration;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OutEvent {
|
||||
pub msg: bob::SwapRequest,
|
||||
pub channel: ResponseChannel<AliceToBob>,
|
||||
pub enum OutEvent {
|
||||
MsgReceived {
|
||||
msg: SwapRequest,
|
||||
channel: ResponseChannel<SwapResponse>,
|
||||
},
|
||||
ResponseSent,
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
@ -31,37 +30,58 @@ pub struct SwapResponse {
|
||||
pub xmr_amount: monero::Amount,
|
||||
}
|
||||
|
||||
impl From<RequestResponseEvent<SwapRequest, SwapResponse>> for OutEvent {
|
||||
fn from(event: RequestResponseEvent<SwapRequest, SwapResponse>) -> Self {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
peer,
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
debug!("Received swap request from {}", peer);
|
||||
OutEvent::MsgReceived {
|
||||
msg: request,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => OutEvent::Failure(anyhow!("Alice should not get a Response")),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => OutEvent::ResponseSent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents negotiate a swap using Swap
|
||||
/// request/response.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Swap>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
rr: RequestResponse<CborCodec<Swap, SwapRequest, SwapResponse>>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
/// Alice always sends her messages as a response to a request from Bob.
|
||||
pub fn send(&mut self, channel: ResponseChannel<AliceToBob>, msg: SwapResponse) -> Result<()> {
|
||||
let msg = AliceToBob::SwapResponse(Box::new(msg));
|
||||
pub fn send(
|
||||
&mut self,
|
||||
channel: ResponseChannel<SwapResponse>,
|
||||
msg: SwapResponse,
|
||||
) -> Result<()> {
|
||||
self.rr
|
||||
.send_response(channel, msg)
|
||||
.map_err(|_| anyhow!("Sending swap response failed"))
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Swap>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
@ -73,43 +93,10 @@ impl Default for Behaviour {
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Swap, ProtocolSupport::Full)],
|
||||
CborCodec::default(),
|
||||
vec![(Swap, ProtocolSupport::Inbound)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
if let BobToAlice::SwapRequest(msg) = request {
|
||||
debug!("Received swap request");
|
||||
self.events.push_back(OutEvent { msg: *msg, channel })
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => panic!("Alice should not get a Response"),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
debug!("Alice has sent a swap response to Bob");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +1,42 @@
|
||||
use crate::{
|
||||
monero,
|
||||
network::request_response::{OneShotCodec, Request, Response, TransferProofProtocol, TIMEOUT},
|
||||
network::request_response::{CborCodec, TransferProofProtocol, TIMEOUT},
|
||||
};
|
||||
use anyhow::{anyhow, Error};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||
RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::error;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct TransferProof {
|
||||
pub tx_lock_proof: monero::TransferProof,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Acknowledged,
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents sending the Monero transfer proof to
|
||||
/// Bob.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<OneShotCodec<TransferProofProtocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
rr: RequestResponse<CborCodec<TransferProofProtocol, TransferProof, ()>>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, bob: PeerId, msg: TransferProof) {
|
||||
let msg = Request::TransferProof(Box::new(msg));
|
||||
let _id = self.rr.send_request(&bob, msg);
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<OneShotCodec<TransferProofProtocol>>, OutEvent>>
|
||||
{
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
@ -67,37 +47,36 @@ impl Default for Behaviour {
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
OneShotCodec::default(),
|
||||
CborCodec::default(),
|
||||
vec![(TransferProofProtocol, ProtocolSupport::Outbound)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
|
||||
impl From<RequestResponseEvent<TransferProof, ()>> for OutEvent {
|
||||
fn from(event: RequestResponseEvent<TransferProof, ()>) -> Self {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Request { .. },
|
||||
..
|
||||
} => panic!("Alice should never get a transfer proof request from Bob"),
|
||||
} => OutEvent::Failure(anyhow!(
|
||||
"Alice should never get a transfer proof request from Bob"
|
||||
)),
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => {
|
||||
if let Response::TransferProof = response {
|
||||
self.events.push_back(OutEvent::Acknowledged);
|
||||
}
|
||||
}
|
||||
} => OutEvent::Acknowledged,
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
OutEvent::Failure(anyhow!("Alice should not send a response"))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,16 @@
|
||||
use crate::{
|
||||
bitcoin, database,
|
||||
database::Database,
|
||||
execution_params::ExecutionParams,
|
||||
monero, network,
|
||||
network::{
|
||||
peer_tracker::{self, PeerTracker},
|
||||
transport::build,
|
||||
},
|
||||
protocol::{alice, bob, SwapAmounts},
|
||||
protocol::{alice, alice::TransferProof, bob, SwapAmounts},
|
||||
seed::Seed,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{bail, Error, Result};
|
||||
use libp2p::{core::Multiaddr, identity::Keypair, NetworkBehaviour, PeerId};
|
||||
use rand::rngs::OsRng;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
@ -21,20 +22,16 @@ use uuid::Uuid;
|
||||
pub use self::{
|
||||
encrypted_signature::EncryptedSignature,
|
||||
event_loop::{EventLoop, EventLoopHandle},
|
||||
message0::Message0,
|
||||
message1::Message1,
|
||||
message2::Message2,
|
||||
state::*,
|
||||
swap::{run, run_until},
|
||||
swap_request::*,
|
||||
};
|
||||
use crate::{execution_params::ExecutionParams, protocol::alice::TransferProof};
|
||||
pub use execution_setup::{Message0, Message2, Message4};
|
||||
use libp2p::request_response::ResponseChannel;
|
||||
|
||||
mod encrypted_signature;
|
||||
pub mod event_loop;
|
||||
mod message0;
|
||||
mod message1;
|
||||
mod message2;
|
||||
mod execution_setup;
|
||||
pub mod state;
|
||||
pub mod swap;
|
||||
mod swap_request;
|
||||
@ -162,6 +159,7 @@ impl Builder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_event_loop(
|
||||
&self,
|
||||
) -> Result<(bob::event_loop::EventLoop, bob::event_loop::EventLoopHandle)> {
|
||||
@ -174,6 +172,7 @@ impl Builder {
|
||||
self.peer_id,
|
||||
self.alice_peer_id,
|
||||
self.alice_address.clone(),
|
||||
self.bitcoin_wallet.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -203,15 +202,18 @@ impl Builder {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
ConnectionEstablished(PeerId),
|
||||
SwapResponse(alice::SwapResponse),
|
||||
Message0(Box<alice::Message0>),
|
||||
Message1(Box<alice::Message1>),
|
||||
Message2,
|
||||
TransferProof(Box<TransferProof>),
|
||||
ExecutionSetupDone(Result<Box<State2>>),
|
||||
TransferProof {
|
||||
msg: Box<TransferProof>,
|
||||
channel: ResponseChannel<()>,
|
||||
},
|
||||
EncryptedSignatureAcknowledged,
|
||||
ResponseSent, // Same variant is used for all messages as no processing is done
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
impl From<peer_tracker::OutEvent> for OutEvent {
|
||||
@ -226,46 +228,42 @@ impl From<peer_tracker::OutEvent> for OutEvent {
|
||||
|
||||
impl From<swap_request::OutEvent> for OutEvent {
|
||||
fn from(event: swap_request::OutEvent) -> Self {
|
||||
OutEvent::SwapResponse(event.swap_response)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<message0::OutEvent> for OutEvent {
|
||||
fn from(event: message0::OutEvent) -> Self {
|
||||
use swap_request::OutEvent::*;
|
||||
match event {
|
||||
message0::OutEvent::Msg(msg) => OutEvent::Message0(Box::new(msg)),
|
||||
MsgReceived(swap_response) => OutEvent::SwapResponse(swap_response),
|
||||
Failure(err) => OutEvent::Failure(err.context("Failre with Swap Request")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<message1::OutEvent> for OutEvent {
|
||||
fn from(event: message1::OutEvent) -> Self {
|
||||
impl From<execution_setup::OutEvent> for OutEvent {
|
||||
fn from(event: execution_setup::OutEvent) -> Self {
|
||||
match event {
|
||||
message1::OutEvent::Msg(msg) => OutEvent::Message1(Box::new(msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<message2::OutEvent> for OutEvent {
|
||||
fn from(event: message2::OutEvent) -> Self {
|
||||
match event {
|
||||
message2::OutEvent::Msg => OutEvent::Message2,
|
||||
execution_setup::OutEvent::Done(res) => OutEvent::ExecutionSetupDone(res.map(Box::new)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<transfer_proof::OutEvent> for OutEvent {
|
||||
fn from(event: transfer_proof::OutEvent) -> Self {
|
||||
use transfer_proof::OutEvent::*;
|
||||
match event {
|
||||
transfer_proof::OutEvent::Msg(msg) => OutEvent::TransferProof(Box::new(msg)),
|
||||
MsgReceived { msg, channel } => OutEvent::TransferProof {
|
||||
msg: Box::new(msg),
|
||||
channel,
|
||||
},
|
||||
AckSent => OutEvent::ResponseSent,
|
||||
Failure(err) => OutEvent::Failure(err.context("Failure with Transfer Proof")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<encrypted_signature::OutEvent> for OutEvent {
|
||||
fn from(event: encrypted_signature::OutEvent) -> Self {
|
||||
use encrypted_signature::OutEvent::*;
|
||||
match event {
|
||||
encrypted_signature::OutEvent::Acknowledged => OutEvent::EncryptedSignatureAcknowledged,
|
||||
Acknowledged => OutEvent::EncryptedSignatureAcknowledged,
|
||||
Failure(err) => OutEvent::Failure(err.context("Failure with Encrypted Signature")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,9 +275,7 @@ impl From<encrypted_signature::OutEvent> for OutEvent {
|
||||
pub struct Behaviour {
|
||||
pt: PeerTracker,
|
||||
swap_request: swap_request::Behaviour,
|
||||
message0: message0::Behaviour,
|
||||
message1: message1::Behaviour,
|
||||
message2: message2::Behaviour,
|
||||
execution_setup: execution_setup::Behaviour,
|
||||
transfer_proof: transfer_proof::Behaviour,
|
||||
encrypted_signature: encrypted_signature::Behaviour,
|
||||
}
|
||||
@ -291,22 +287,15 @@ impl Behaviour {
|
||||
info!("Requesting swap from: {}", alice);
|
||||
}
|
||||
|
||||
/// Sends Bob's first message to Alice.
|
||||
pub fn send_message0(&mut self, alice: PeerId, msg: bob::Message0) {
|
||||
self.message0.send(alice, msg);
|
||||
debug!("Message0 sent");
|
||||
}
|
||||
|
||||
/// Sends Bob's second message to Alice.
|
||||
pub fn send_message1(&mut self, alice: PeerId, msg: bob::Message1) {
|
||||
self.message1.send(alice, msg);
|
||||
debug!("Message1 sent");
|
||||
}
|
||||
|
||||
/// Sends Bob's third message to Alice.
|
||||
pub fn send_message2(&mut self, alice: PeerId, msg: bob::Message2) {
|
||||
self.message2.send(alice, msg);
|
||||
debug!("Message2 sent");
|
||||
pub fn start_execution_setup(
|
||||
&mut self,
|
||||
alice_peer_id: PeerId,
|
||||
state0: State0,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
) {
|
||||
self.execution_setup
|
||||
.run(alice_peer_id, state0, bitcoin_wallet);
|
||||
info!("Start execution setup with {}", alice_peer_id);
|
||||
}
|
||||
|
||||
/// Sends Bob's fourth message to Alice.
|
||||
|
@ -1,61 +1,38 @@
|
||||
use crate::network::request_response::{
|
||||
EncryptedSignatureProtocol, OneShotCodec, Request, Response, TIMEOUT,
|
||||
};
|
||||
use crate::network::request_response::{CborCodec, EncryptedSignatureProtocol, TIMEOUT};
|
||||
use anyhow::{anyhow, Error};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||
RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::error;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EncryptedSignature {
|
||||
pub tx_redeem_encsig: crate::bitcoin::EncryptedSignature,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Acknowledged,
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents sending encrypted signature to Alice.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<OneShotCodec<EncryptedSignatureProtocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
rr: RequestResponse<CborCodec<EncryptedSignatureProtocol, EncryptedSignature, ()>>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, alice: PeerId, msg: EncryptedSignature) {
|
||||
let msg = Request::EncryptedSignature(Box::new(msg));
|
||||
let _id = self.rr.send_request(&alice, msg);
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<
|
||||
NetworkBehaviourAction<RequestProtocol<OneShotCodec<EncryptedSignatureProtocol>>, OutEvent>,
|
||||
> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
@ -66,39 +43,34 @@ impl Default for Behaviour {
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
OneShotCodec::default(),
|
||||
CborCodec::default(),
|
||||
vec![(EncryptedSignatureProtocol, ProtocolSupport::Outbound)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
|
||||
impl From<RequestResponseEvent<EncryptedSignature, ()>> for OutEvent {
|
||||
fn from(event: RequestResponseEvent<EncryptedSignature, ()>) -> Self {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Request { .. },
|
||||
..
|
||||
} => panic!("Bob should never get a request from Alice"),
|
||||
} => OutEvent::Failure(anyhow!("Bob should never get a request from Alice")),
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => {
|
||||
if let Response::EncryptedSignature = response {
|
||||
self.events.push_back(OutEvent::Acknowledged);
|
||||
}
|
||||
}
|
||||
} => OutEvent::Acknowledged,
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
unreachable!("Bob does not send the encrypted signature response to Alice");
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => OutEvent::Failure(anyhow!(
|
||||
"Bob does not send the encrypted signature response to Alice"
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
use crate::{
|
||||
bitcoin,
|
||||
bitcoin::EncryptedSignature,
|
||||
network::{transport::SwapTransport, TokioExecutor},
|
||||
protocol::{
|
||||
alice,
|
||||
alice::{SwapResponse, TransferProof},
|
||||
bob::{self, Behaviour, OutEvent, SwapRequest},
|
||||
bob::{Behaviour, OutEvent, State0, State2, SwapRequest},
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures::FutureExt;
|
||||
use libp2p::{core::Multiaddr, PeerId};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
@ -35,15 +36,12 @@ impl<T> Default for Channels<T> {
|
||||
#[derive(Debug)]
|
||||
pub struct EventLoopHandle {
|
||||
recv_swap_response: Receiver<SwapResponse>,
|
||||
recv_message0: Receiver<alice::Message0>,
|
||||
recv_message1: Receiver<alice::Message1>,
|
||||
start_execution_setup: Sender<State0>,
|
||||
done_execution_setup: Receiver<Result<State2>>,
|
||||
recv_transfer_proof: Receiver<TransferProof>,
|
||||
conn_established: Receiver<PeerId>,
|
||||
dial_alice: Sender<()>,
|
||||
send_swap_request: Sender<SwapRequest>,
|
||||
send_message0: Sender<bob::Message0>,
|
||||
send_message1: Sender<bob::Message1>,
|
||||
send_message2: Sender<bob::Message2>,
|
||||
send_encrypted_signature: Sender<EncryptedSignature>,
|
||||
recv_encrypted_signature_ack: Receiver<()>,
|
||||
}
|
||||
@ -56,18 +54,13 @@ impl EventLoopHandle {
|
||||
.ok_or_else(|| anyhow!("Failed to receive swap response from Alice"))
|
||||
}
|
||||
|
||||
pub async fn recv_message0(&mut self) -> Result<alice::Message0> {
|
||||
self.recv_message0
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("Failed to receive message 0 from Alice"))
|
||||
}
|
||||
pub async fn execution_setup(&mut self, state0: State0) -> Result<State2> {
|
||||
let _ = self.start_execution_setup.send(state0).await?;
|
||||
|
||||
pub async fn recv_message1(&mut self) -> Result<alice::Message1> {
|
||||
self.recv_message1
|
||||
self.done_execution_setup
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("Failed to receive message 1 from Alice"))
|
||||
.ok_or_else(|| anyhow!("Failed to setup execution with Alice"))?
|
||||
}
|
||||
|
||||
pub async fn recv_transfer_proof(&mut self) -> Result<TransferProof> {
|
||||
@ -96,21 +89,6 @@ impl EventLoopHandle {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_message0(&mut self, msg: bob::Message0) -> Result<()> {
|
||||
let _ = self.send_message0.send(msg).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_message1(&mut self, msg: bob::Message1) -> Result<()> {
|
||||
let _ = self.send_message1.send(msg).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_message2(&mut self, msg: bob::Message2) -> Result<()> {
|
||||
let _ = self.send_message2.send(msg).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_encrypted_signature(
|
||||
&mut self,
|
||||
tx_redeem_encsig: EncryptedSignature,
|
||||
@ -128,17 +106,15 @@ impl EventLoopHandle {
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct EventLoop {
|
||||
swarm: libp2p::Swarm<Behaviour>,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
alice_peer_id: PeerId,
|
||||
recv_swap_response: Sender<SwapResponse>,
|
||||
recv_message0: Sender<alice::Message0>,
|
||||
recv_message1: Sender<alice::Message1>,
|
||||
start_execution_setup: Receiver<State0>,
|
||||
done_execution_setup: Sender<Result<State2>>,
|
||||
recv_transfer_proof: Sender<TransferProof>,
|
||||
dial_alice: Receiver<()>,
|
||||
conn_established: Sender<PeerId>,
|
||||
send_swap_request: Receiver<SwapRequest>,
|
||||
send_message0: Receiver<bob::Message0>,
|
||||
send_message1: Receiver<bob::Message1>,
|
||||
send_message2: Receiver<bob::Message2>,
|
||||
send_encrypted_signature: Receiver<EncryptedSignature>,
|
||||
recv_encrypted_signature_ack: Sender<()>,
|
||||
}
|
||||
@ -150,6 +126,7 @@ impl EventLoop {
|
||||
peer_id: PeerId,
|
||||
alice_peer_id: PeerId,
|
||||
alice_addr: Multiaddr,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
) -> Result<(Self, EventLoopHandle)> {
|
||||
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, peer_id)
|
||||
.executor(Box::new(TokioExecutor {
|
||||
@ -160,46 +137,38 @@ impl EventLoop {
|
||||
swarm.add_address(alice_peer_id, alice_addr);
|
||||
|
||||
let swap_response = Channels::new();
|
||||
let recv_message0 = Channels::new();
|
||||
let recv_message1 = Channels::new();
|
||||
let start_execution_setup = Channels::new();
|
||||
let done_execution_setup = Channels::new();
|
||||
let recv_transfer_proof = Channels::new();
|
||||
let dial_alice = Channels::new();
|
||||
let conn_established = Channels::new();
|
||||
let send_swap_request = Channels::new();
|
||||
let send_message0 = Channels::new();
|
||||
let send_message1 = Channels::new();
|
||||
let send_message2 = Channels::new();
|
||||
let send_encrypted_signature = Channels::new();
|
||||
let recv_encrypted_signature_ack = Channels::new();
|
||||
|
||||
let event_loop = EventLoop {
|
||||
swarm,
|
||||
alice_peer_id,
|
||||
bitcoin_wallet,
|
||||
recv_swap_response: swap_response.sender,
|
||||
recv_message0: recv_message0.sender,
|
||||
recv_message1: recv_message1.sender,
|
||||
start_execution_setup: start_execution_setup.receiver,
|
||||
done_execution_setup: done_execution_setup.sender,
|
||||
recv_transfer_proof: recv_transfer_proof.sender,
|
||||
conn_established: conn_established.sender,
|
||||
dial_alice: dial_alice.receiver,
|
||||
send_swap_request: send_swap_request.receiver,
|
||||
send_message0: send_message0.receiver,
|
||||
send_message1: send_message1.receiver,
|
||||
send_message2: send_message2.receiver,
|
||||
send_encrypted_signature: send_encrypted_signature.receiver,
|
||||
recv_encrypted_signature_ack: recv_encrypted_signature_ack.sender,
|
||||
};
|
||||
|
||||
let handle = EventLoopHandle {
|
||||
recv_swap_response: swap_response.receiver,
|
||||
recv_message0: recv_message0.receiver,
|
||||
recv_message1: recv_message1.receiver,
|
||||
start_execution_setup: start_execution_setup.sender,
|
||||
done_execution_setup: done_execution_setup.receiver,
|
||||
recv_transfer_proof: recv_transfer_proof.receiver,
|
||||
conn_established: conn_established.receiver,
|
||||
dial_alice: dial_alice.sender,
|
||||
send_swap_request: send_swap_request.sender,
|
||||
send_message0: send_message0.sender,
|
||||
send_message1: send_message1.sender,
|
||||
send_message2: send_message2.sender,
|
||||
send_encrypted_signature: send_encrypted_signature.sender,
|
||||
recv_encrypted_signature_ack: recv_encrypted_signature_ack.receiver,
|
||||
};
|
||||
@ -218,20 +187,24 @@ impl EventLoop {
|
||||
OutEvent::SwapResponse(msg) => {
|
||||
let _ = self.recv_swap_response.send(msg).await;
|
||||
},
|
||||
OutEvent::Message0(msg) => {
|
||||
let _ = self.recv_message0.send(*msg).await;
|
||||
OutEvent::ExecutionSetupDone(res) => {
|
||||
let _ = self.done_execution_setup.send(res.map(|state|*state)).await;
|
||||
}
|
||||
OutEvent::Message1(msg) => {
|
||||
let _ = self.recv_message1.send(*msg).await;
|
||||
}
|
||||
OutEvent::Message2 => info!("Alice acknowledged message 2 received"),
|
||||
OutEvent::TransferProof(msg) => {
|
||||
OutEvent::TransferProof{ msg, channel }=> {
|
||||
let _ = self.recv_transfer_proof.send(*msg).await;
|
||||
// Send back empty response so that the request/response protocol completes.
|
||||
if let Err(error) = self.swarm.transfer_proof.send_ack(channel) {
|
||||
error!("Failed to send Transfer Proof ack: {:?}", error);
|
||||
}
|
||||
}
|
||||
OutEvent::EncryptedSignatureAcknowledged => {
|
||||
debug!("Alice acknowledged encrypted signature");
|
||||
let _ = self.recv_encrypted_signature_ack.send(()).await;
|
||||
}
|
||||
OutEvent::ResponseSent => {}
|
||||
OutEvent::Failure(err) => {
|
||||
error!("Communication error: {:#}", err)
|
||||
}
|
||||
}
|
||||
},
|
||||
option = self.dial_alice.recv().fuse() => {
|
||||
@ -255,21 +228,11 @@ impl EventLoop {
|
||||
self.swarm.send_swap_request(self.alice_peer_id, swap_request);
|
||||
}
|
||||
},
|
||||
|
||||
msg0 = self.send_message0.recv().fuse() => {
|
||||
if let Some(msg) = msg0 {
|
||||
self.swarm.send_message0(self.alice_peer_id, msg);
|
||||
}
|
||||
}
|
||||
|
||||
msg1 = self.send_message1.recv().fuse() => {
|
||||
if let Some(msg) = msg1 {
|
||||
self.swarm.send_message1(self.alice_peer_id, msg);
|
||||
}
|
||||
},
|
||||
msg2 = self.send_message2.recv().fuse() => {
|
||||
if let Some(msg) = msg2 {
|
||||
self.swarm.send_message2(self.alice_peer_id, msg);
|
||||
option = self.start_execution_setup.recv().fuse() => {
|
||||
if let Some(state0) = option {
|
||||
let _ = self
|
||||
.swarm
|
||||
.start_execution_setup(self.alice_peer_id, state0, self.bitcoin_wallet.clone());
|
||||
}
|
||||
},
|
||||
encrypted_signature = self.send_encrypted_signature.recv().fuse() => {
|
||||
|
108
swap/src/protocol/bob/execution_setup.rs
Normal file
108
swap/src/protocol/bob/execution_setup.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use crate::{
|
||||
bitcoin::Signature,
|
||||
network::request_response::BUF_SIZE,
|
||||
protocol::{
|
||||
alice::{Message1, Message3},
|
||||
bob::{State0, State2},
|
||||
},
|
||||
};
|
||||
use anyhow::{Context, Error, Result};
|
||||
use libp2p::PeerId;
|
||||
use libp2p_async_await::BehaviourOutEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message0 {
|
||||
pub(crate) B: crate::bitcoin::PublicKey,
|
||||
pub(crate) S_b_monero: monero::PublicKey,
|
||||
pub(crate) S_b_bitcoin: crate::bitcoin::PublicKey,
|
||||
pub(crate) dleq_proof_s_b: cross_curve_dleq::Proof,
|
||||
pub(crate) v_b: crate::monero::PrivateViewKey,
|
||||
pub(crate) refund_address: bitcoin::Address,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message2 {
|
||||
pub(crate) tx_lock: crate::bitcoin::TxLock,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message4 {
|
||||
pub(crate) tx_punish_sig: Signature,
|
||||
pub(crate) tx_cancel_sig: Signature,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Done(Result<State2>),
|
||||
}
|
||||
|
||||
impl From<BehaviourOutEvent<(), State2, anyhow::Error>> for OutEvent {
|
||||
fn from(event: BehaviourOutEvent<(), State2, Error>) -> Self {
|
||||
match event {
|
||||
BehaviourOutEvent::Outbound(_, Ok(State2)) => OutEvent::Done(Ok(State2)),
|
||||
BehaviourOutEvent::Outbound(_, Err(e)) => OutEvent::Done(Err(e)),
|
||||
BehaviourOutEvent::Inbound(..) => unreachable!("Bob only supports outbound"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(libp2p::NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
pub struct Behaviour {
|
||||
inner: libp2p_async_await::Behaviour<(), State2, anyhow::Error>,
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: libp2p_async_await::Behaviour::new(b"/comit/xmr/btc/execution_setup/1.0.0"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn run(
|
||||
&mut self,
|
||||
alice: PeerId,
|
||||
state0: State0,
|
||||
bitcoin_wallet: Arc<crate::bitcoin::Wallet>,
|
||||
) {
|
||||
self.inner
|
||||
.do_protocol_dialer(alice, move |mut substream| async move {
|
||||
substream
|
||||
.write_message(
|
||||
&serde_cbor::to_vec(&state0.next_message())
|
||||
.context("failed to serialize message0")?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let message1 =
|
||||
serde_cbor::from_slice::<Message1>(&substream.read_message(BUF_SIZE).await?)
|
||||
.context("failed to deserialize message1")?;
|
||||
let state1 = state0.receive(bitcoin_wallet.as_ref(), message1).await?;
|
||||
|
||||
substream
|
||||
.write_message(
|
||||
&serde_cbor::to_vec(&state1.next_message())
|
||||
.context("failed to serialize message2")?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let message3 =
|
||||
serde_cbor::from_slice::<Message3>(&substream.read_message(BUF_SIZE).await?)
|
||||
.context("failed to deserialize message3")?;
|
||||
let state2 = state1.receive(message3)?;
|
||||
|
||||
substream
|
||||
.write_message(
|
||||
&serde_cbor::to_vec(&state2.next_message())
|
||||
.context("failed to serialize message4")?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(state2)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
use crate::{
|
||||
bitcoin, monero,
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Message0Protocol, TIMEOUT},
|
||||
protocol::{alice, bob},
|
||||
};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message0 {
|
||||
pub(crate) B: bitcoin::PublicKey,
|
||||
pub(crate) S_b_monero: monero::PublicKey,
|
||||
pub(crate) S_b_bitcoin: bitcoin::PublicKey,
|
||||
pub(crate) dleq_proof_s_b: cross_curve_dleq::Proof,
|
||||
pub(crate) v_b: monero::PrivateViewKey,
|
||||
pub(crate) refund_address: bitcoin::Address,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg(alice::Message0),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents send/recv of message 0.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Message0Protocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, alice: PeerId, msg: bob::Message0) {
|
||||
let msg = BobToAlice::Message0(Box::new(msg));
|
||||
let _id = self.rr.send_request(&alice, msg);
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Message0Protocol>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
let timeout = Duration::from_secs(TIMEOUT);
|
||||
let mut config = RequestResponseConfig::default();
|
||||
config.set_request_timeout(timeout);
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Message0Protocol, ProtocolSupport::Full)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Request { .. },
|
||||
..
|
||||
} => panic!("Bob should never get a request from Alice"),
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
..
|
||||
} => {
|
||||
if let AliceToBob::Message0(msg) = response {
|
||||
debug!("Received Message0");
|
||||
self.events.push_back(OutEvent::Msg(*msg));
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
unreachable!("Bob does not send a message0 response to Alice");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
use crate::{
|
||||
bitcoin,
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Message1Protocol, TIMEOUT},
|
||||
protocol::alice,
|
||||
};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message1 {
|
||||
pub(crate) tx_lock: bitcoin::TxLock,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg(alice::Message1),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents send/recv of message 1.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Message1Protocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, alice: PeerId, msg: Message1) {
|
||||
let msg = BobToAlice::Message1(Box::new(msg));
|
||||
let _id = self.rr.send_request(&alice, msg);
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Message1Protocol>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
let timeout = Duration::from_secs(TIMEOUT);
|
||||
let mut config = RequestResponseConfig::default();
|
||||
config.set_request_timeout(timeout);
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Message1Protocol, ProtocolSupport::Full)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Request { .. },
|
||||
..
|
||||
} => panic!("Bob should never get a request from Alice"),
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
..
|
||||
} => {
|
||||
if let AliceToBob::Message1(msg) = response {
|
||||
debug!("Received Message1");
|
||||
self.events.push_back(OutEvent::Msg(*msg));
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
unreachable!("Bob does not send a message 1 response to Alice");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
use crate::network::request_response::{AliceToBob, BobToAlice, Codec, Message2Protocol, TIMEOUT};
|
||||
use ecdsa_fun::Signature;
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message2 {
|
||||
pub(crate) tx_punish_sig: Signature,
|
||||
pub(crate) tx_cancel_sig: Signature,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg,
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents sending message 2 to Alice.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Message2Protocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, alice: PeerId, msg: Message2) {
|
||||
let msg = BobToAlice::Message2(Box::new(msg));
|
||||
let _id = self.rr.send_request(&alice, msg);
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Message2Protocol>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
fn default() -> Self {
|
||||
let timeout = Duration::from_secs(TIMEOUT);
|
||||
let mut config = RequestResponseConfig::default();
|
||||
config.set_request_timeout(timeout);
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
vec![(Message2Protocol, ProtocolSupport::Full)],
|
||||
config,
|
||||
),
|
||||
events: VecDeque::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Request { .. },
|
||||
..
|
||||
} => panic!("Bob should never get a request from Alice"),
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
..
|
||||
} => {
|
||||
if let AliceToBob::Message2 = response {
|
||||
debug!("Received Message 2 acknowledgement");
|
||||
self.events.push_back(OutEvent::Msg);
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
unreachable!("Bob does not send a Message2 response to Alice");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,11 @@ use crate::{
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
monero::{monero_private_key, TransferProof},
|
||||
protocol::{alice, bob, bob::EncryptedSignature, SwapAmounts},
|
||||
protocol::{
|
||||
alice::{Message1, Message3},
|
||||
bob::{EncryptedSignature, Message0, Message2, Message4},
|
||||
SwapAmounts,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic, Signature};
|
||||
@ -74,6 +78,7 @@ pub struct State0 {
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
v_b: monero::PrivateViewKey,
|
||||
dleq_proof_s_b: cross_curve_dleq::Proof,
|
||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
@ -97,6 +102,7 @@ impl State0 {
|
||||
|
||||
let s_b = cross_curve_dleq::Scalar::random(rng);
|
||||
let v_b = monero::PrivateViewKey::new_random(rng);
|
||||
let dleq_proof_s_b = cross_curve_dleq::Proof::new(rng, &s_b);
|
||||
|
||||
Self {
|
||||
b,
|
||||
@ -104,6 +110,7 @@ impl State0 {
|
||||
v_b,
|
||||
btc,
|
||||
xmr,
|
||||
dleq_proof_s_b,
|
||||
cancel_timelock,
|
||||
punish_timelock,
|
||||
refund_address,
|
||||
@ -111,22 +118,20 @@ impl State0 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_message<R: RngCore + CryptoRng>(&self, rng: &mut R) -> bob::Message0 {
|
||||
let dleq_proof_s_b = cross_curve_dleq::Proof::new(rng, &self.s_b);
|
||||
|
||||
bob::Message0 {
|
||||
pub fn next_message(&self) -> Message0 {
|
||||
Message0 {
|
||||
B: self.b.public(),
|
||||
S_b_monero: monero::PublicKey::from_private_key(&monero::PrivateKey {
|
||||
scalar: self.s_b.into_ed25519(),
|
||||
}),
|
||||
S_b_bitcoin: self.s_b.into_secp256k1().into(),
|
||||
dleq_proof_s_b,
|
||||
dleq_proof_s_b: self.dleq_proof_s_b.clone(),
|
||||
v_b: self.v_b,
|
||||
refund_address: self.refund_address.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn receive<W>(self, wallet: &W, msg: alice::Message0) -> anyhow::Result<State1>
|
||||
pub async fn receive<W>(self, wallet: &W, msg: Message1) -> anyhow::Result<State1>
|
||||
where
|
||||
W: BuildTxLockPsbt + GetNetwork,
|
||||
{
|
||||
@ -182,13 +187,13 @@ pub struct State1 {
|
||||
}
|
||||
|
||||
impl State1 {
|
||||
pub fn next_message(&self) -> bob::Message1 {
|
||||
bob::Message1 {
|
||||
pub fn next_message(&self) -> Message2 {
|
||||
Message2 {
|
||||
tx_lock: self.tx_lock.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: alice::Message1) -> Result<State2> {
|
||||
pub fn receive(self, msg: Message3) -> Result<State2> {
|
||||
let tx_cancel = TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
|
||||
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address);
|
||||
|
||||
@ -245,14 +250,14 @@ pub struct State2 {
|
||||
}
|
||||
|
||||
impl State2 {
|
||||
pub fn next_message(&self) -> bob::Message2 {
|
||||
pub fn next_message(&self) -> Message4 {
|
||||
let tx_cancel = TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
|
||||
let tx_cancel_sig = self.b.sign(tx_cancel.digest());
|
||||
let tx_punish =
|
||||
bitcoin::TxPunish::new(&tx_cancel, &self.punish_address, self.punish_timelock);
|
||||
let tx_punish_sig = self.b.sign(tx_punish.digest());
|
||||
|
||||
bob::Message2 {
|
||||
Message4 {
|
||||
tx_punish_sig,
|
||||
tx_cancel_sig,
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ use crate::{
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use async_recursion::async_recursion;
|
||||
use rand::{rngs::OsRng, CryptoRng, RngCore};
|
||||
use std::sync::Arc;
|
||||
use tokio::select;
|
||||
use tracing::info;
|
||||
@ -44,7 +43,6 @@ pub async fn run_until(
|
||||
swap.db,
|
||||
swap.bitcoin_wallet,
|
||||
swap.monero_wallet,
|
||||
OsRng,
|
||||
swap.swap_id,
|
||||
swap.execution_params,
|
||||
)
|
||||
@ -54,20 +52,16 @@ pub async fn run_until(
|
||||
// State machine driver for swap execution
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[async_recursion]
|
||||
async fn run_until_internal<R>(
|
||||
async fn run_until_internal(
|
||||
state: BobState,
|
||||
is_target_state: fn(&BobState) -> bool,
|
||||
mut event_loop_handle: EventLoopHandle,
|
||||
db: Database,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
monero_wallet: Arc<monero::Wallet>,
|
||||
mut rng: R,
|
||||
swap_id: Uuid,
|
||||
execution_params: ExecutionParams,
|
||||
) -> Result<BobState>
|
||||
where
|
||||
R: RngCore + CryptoRng + Send,
|
||||
{
|
||||
) -> Result<BobState> {
|
||||
info!("Current state: {}", state);
|
||||
if is_target_state(&state) {
|
||||
Ok(state)
|
||||
@ -76,14 +70,7 @@ where
|
||||
BobState::Started { state0, amounts } => {
|
||||
event_loop_handle.dial().await?;
|
||||
|
||||
let state2 = negotiate(
|
||||
state0,
|
||||
amounts,
|
||||
&mut event_loop_handle,
|
||||
&mut rng,
|
||||
bitcoin_wallet.clone(),
|
||||
)
|
||||
.await?;
|
||||
let state2 = negotiate(state0, amounts, &mut event_loop_handle).await?;
|
||||
|
||||
let state = BobState::Negotiated(state2);
|
||||
let db_state = state.clone().into();
|
||||
@ -95,7 +82,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -117,7 +103,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -170,7 +155,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -217,7 +201,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -260,7 +243,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -296,7 +278,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet.clone(),
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -318,7 +299,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -344,7 +324,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -376,7 +355,6 @@ where
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
rng,
|
||||
swap_id,
|
||||
execution_params,
|
||||
)
|
||||
@ -390,18 +368,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn negotiate<R>(
|
||||
pub async fn negotiate(
|
||||
state0: crate::protocol::bob::state::State0,
|
||||
amounts: SwapAmounts,
|
||||
swarm: &mut EventLoopHandle,
|
||||
mut rng: R,
|
||||
bitcoin_wallet: Arc<crate::bitcoin::Wallet>,
|
||||
) -> Result<bob::state::State2>
|
||||
where
|
||||
R: RngCore + CryptoRng + Send,
|
||||
{
|
||||
event_loop_handle: &mut EventLoopHandle,
|
||||
) -> Result<bob::state::State2> {
|
||||
tracing::trace!("Starting negotiate");
|
||||
swarm
|
||||
event_loop_handle
|
||||
.send_swap_request(SwapRequest {
|
||||
btc_amount: amounts.btc,
|
||||
})
|
||||
@ -409,17 +382,9 @@ where
|
||||
|
||||
// TODO: Use this once Bob's CLI is modified to only pass xmr amount in
|
||||
// argument.
|
||||
let _swap_response = swarm.recv_swap_response().await?;
|
||||
let _swap_response = event_loop_handle.recv_swap_response().await?;
|
||||
|
||||
swarm.send_message0(state0.next_message(&mut rng)).await?;
|
||||
let msg0 = swarm.recv_message0().await?;
|
||||
let state1 = state0.receive(bitcoin_wallet.as_ref(), msg0).await?;
|
||||
|
||||
swarm.send_message1(state1.next_message()).await?;
|
||||
let msg1 = swarm.recv_message1().await?;
|
||||
let state2 = state1.receive(msg1)?;
|
||||
|
||||
swarm.send_message2(state2.next_message()).await?;
|
||||
let state2 = event_loop_handle.execution_setup(state0).await?;
|
||||
|
||||
Ok(state2)
|
||||
}
|
||||
|
@ -1,23 +1,18 @@
|
||||
use crate::{
|
||||
network::request_response::{AliceToBob, BobToAlice, Codec, Swap, TIMEOUT},
|
||||
network::request_response::{CborCodec, Swap, TIMEOUT},
|
||||
protocol::alice::SwapResponse,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestId, RequestResponse,
|
||||
RequestResponseConfig, RequestResponseEvent, RequestResponseMessage,
|
||||
ProtocolSupport, RequestId, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||
RequestResponseMessage,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour, PeerId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
use std::time::Duration;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct SwapRequest {
|
||||
@ -25,40 +20,26 @@ pub struct SwapRequest {
|
||||
pub btc_amount: bitcoin::Amount,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct OutEvent {
|
||||
pub swap_response: SwapResponse,
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
MsgReceived(SwapResponse),
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents doing the negotiation of a swap.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<Codec<Swap>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
rr: RequestResponse<CborCodec<Swap, SwapRequest, SwapResponse>>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, alice: PeerId, swap_request: SwapRequest) -> Result<RequestId> {
|
||||
let msg = BobToAlice::SwapRequest(Box::new(swap_request));
|
||||
let id = self.rr.send_request(&alice, msg);
|
||||
let id = self.rr.send_request(&alice, swap_request);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<Swap>>, OutEvent>> {
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Behaviour {
|
||||
@ -70,41 +51,37 @@ impl Default for Behaviour {
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
Codec::default(),
|
||||
CborCodec::default(),
|
||||
vec![(Swap, ProtocolSupport::Outbound)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
|
||||
impl From<RequestResponseEvent<SwapRequest, SwapResponse>> for OutEvent {
|
||||
fn from(event: RequestResponseEvent<SwapRequest, SwapResponse>) -> Self {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Request { .. },
|
||||
..
|
||||
} => panic!("Bob should never get a request from Alice"),
|
||||
} => OutEvent::Failure(anyhow!("Bob should never get a request from Alice")),
|
||||
RequestResponseEvent::Message {
|
||||
peer,
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
..
|
||||
} => {
|
||||
if let AliceToBob::SwapResponse(swap_response) = response {
|
||||
debug!("Received swap response");
|
||||
self.events.push_back(OutEvent {
|
||||
swap_response: *swap_response,
|
||||
});
|
||||
}
|
||||
debug!("Received swap response from {}", peer);
|
||||
OutEvent::MsgReceived(response)
|
||||
}
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => {
|
||||
error!("Bob does not send a swap response to Alice");
|
||||
OutEvent::Failure(anyhow!("Bob does not send a swap response to Alice"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,42 @@
|
||||
use crate::{
|
||||
network::request_response::{OneShotCodec, Request, Response, TransferProofProtocol, TIMEOUT},
|
||||
network::request_response::{CborCodec, TransferProofProtocol, TIMEOUT},
|
||||
protocol::alice::TransferProof,
|
||||
};
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use libp2p::{
|
||||
request_response::{
|
||||
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
|
||||
RequestResponseEvent, RequestResponseMessage,
|
||||
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||
RequestResponseMessage, ResponseChannel,
|
||||
},
|
||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||
NetworkBehaviour,
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
use std::time::Duration;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
Msg(TransferProof),
|
||||
MsgReceived {
|
||||
msg: TransferProof,
|
||||
channel: ResponseChannel<()>,
|
||||
},
|
||||
AckSent,
|
||||
Failure(Error),
|
||||
}
|
||||
|
||||
/// A `NetworkBehaviour` that represents receiving the transfer proof from
|
||||
/// Alice.
|
||||
#[derive(NetworkBehaviour)]
|
||||
#[behaviour(out_event = "OutEvent", poll_method = "poll")]
|
||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour {
|
||||
rr: RequestResponse<OneShotCodec<TransferProofProtocol>>,
|
||||
#[behaviour(ignore)]
|
||||
events: VecDeque<OutEvent>,
|
||||
rr: RequestResponse<CborCodec<TransferProofProtocol, TransferProof, ()>>,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
fn poll(
|
||||
&mut self,
|
||||
_: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<RequestProtocol<OneShotCodec<TransferProofProtocol>>, OutEvent>>
|
||||
{
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
pub fn send_ack(&mut self, channel: ResponseChannel<()>) -> Result<()> {
|
||||
self.rr
|
||||
.send_response(channel, ())
|
||||
.map_err(|err| anyhow!("Failed to ack transfer proof: {:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,46 +48,42 @@ impl Default for Behaviour {
|
||||
|
||||
Self {
|
||||
rr: RequestResponse::new(
|
||||
OneShotCodec::default(),
|
||||
CborCodec::default(),
|
||||
vec![(TransferProofProtocol, ProtocolSupport::Inbound)],
|
||||
config,
|
||||
),
|
||||
events: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for Behaviour {
|
||||
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
|
||||
impl From<RequestResponseEvent<TransferProof, ()>> for OutEvent {
|
||||
fn from(event: RequestResponseEvent<TransferProof, ()>) -> Self {
|
||||
match event {
|
||||
RequestResponseEvent::Message {
|
||||
peer,
|
||||
message:
|
||||
RequestResponseMessage::Request {
|
||||
request, channel, ..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
if let Request::TransferProof(msg) = request {
|
||||
debug!("Received Transfer Proof");
|
||||
self.events.push_back(OutEvent::Msg(*msg));
|
||||
// Send back empty response so that the request/response protocol completes.
|
||||
let _ = self
|
||||
.rr
|
||||
.send_response(channel, Response::TransferProof)
|
||||
.map_err(|err| error!("Failed to send message 3: {:?}", err));
|
||||
debug!("Received Transfer Proof from {}", peer);
|
||||
OutEvent::MsgReceived {
|
||||
msg: request,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
RequestResponseEvent::Message {
|
||||
message: RequestResponseMessage::Response { .. },
|
||||
..
|
||||
} => panic!("Bob should not get a Response"),
|
||||
} => OutEvent::Failure(anyhow!("Bob should not get a Response")),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
error!("Inbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
error!("Outbound failure: {:?}", error);
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => debug!("Bob ack'd transfer proof message"),
|
||||
RequestResponseEvent::ResponseSent { .. } => OutEvent::AckSent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ async fn given_alice_restarts_after_encsig_is_learned_resume_swap() {
|
||||
let alice_state = alice::run_until(alice_swap, is_encsig_learned)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(matches!(alice_state, AliceState::EncSigLearned {..}));
|
||||
assert!(matches!(alice_state, AliceState::EncSigLearned { .. }));
|
||||
|
||||
let alice_swap = ctx.stop_and_resume_alice_from_db(alice_join_handle).await;
|
||||
assert!(matches!(alice_swap.state, AliceState::EncSigLearned {..}));
|
||||
assert!(matches!(alice_swap.state, AliceState::EncSigLearned { .. }));
|
||||
|
||||
let alice_state = alice::run(alice_swap).await.unwrap();
|
||||
|
||||
|
@ -14,10 +14,10 @@ async fn given_bob_restarts_after_encsig_is_sent_resume_swap() {
|
||||
|
||||
let bob_state = bob::run_until(bob_swap, is_encsig_sent).await.unwrap();
|
||||
|
||||
assert!(matches!(bob_state, BobState::EncSigSent {..}));
|
||||
assert!(matches!(bob_state, BobState::EncSigSent { .. }));
|
||||
|
||||
let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await;
|
||||
assert!(matches!(bob_swap.state, BobState::EncSigSent {..}));
|
||||
assert!(matches!(bob_swap.state, BobState::EncSigSent { .. }));
|
||||
|
||||
let bob_state = bob::run(bob_swap).await.unwrap();
|
||||
|
||||
|
@ -16,11 +16,13 @@ async fn given_bob_restarts_after_lock_proof_received_resume_swap() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(bob_state, BobState::XmrLockProofReceived {..}));
|
||||
assert!(matches!(bob_state, BobState::XmrLockProofReceived { .. }));
|
||||
|
||||
let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await;
|
||||
assert!(matches!(bob_swap.state, BobState::XmrLockProofReceived
|
||||
{..}));
|
||||
assert!(matches!(
|
||||
bob_swap.state,
|
||||
BobState::XmrLockProofReceived { .. }
|
||||
));
|
||||
|
||||
let bob_state = bob::run(bob_swap).await.unwrap();
|
||||
|
||||
|
@ -14,10 +14,10 @@ async fn given_bob_restarts_after_xmr_is_locked_resume_swap() {
|
||||
|
||||
let bob_state = bob::run_until(bob_swap, is_xmr_locked).await.unwrap();
|
||||
|
||||
assert!(matches!(bob_state, BobState::XmrLocked {..}));
|
||||
assert!(matches!(bob_state, BobState::XmrLocked { .. }));
|
||||
|
||||
let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await;
|
||||
assert!(matches!(bob_swap.state, BobState::XmrLocked {..}));
|
||||
assert!(matches!(bob_swap.state, BobState::XmrLocked { .. }));
|
||||
|
||||
let bob_state = bob::run(bob_swap).await.unwrap();
|
||||
|
||||
|
@ -16,7 +16,7 @@ async fn alice_punishes_if_bob_never_acts_after_fund() {
|
||||
|
||||
let bob_state = bob::run_until(bob_swap, is_btc_locked).await.unwrap();
|
||||
|
||||
assert!(matches!(bob_state, BobState::BtcLocked {..}));
|
||||
assert!(matches!(bob_state, BobState::BtcLocked { .. }));
|
||||
|
||||
let alice_state = alice_handle.await.unwrap();
|
||||
ctx.assert_alice_punished(alice_state.unwrap()).await;
|
||||
@ -24,7 +24,7 @@ async fn alice_punishes_if_bob_never_acts_after_fund() {
|
||||
// Restart Bob after Alice punished to ensure Bob transitions to
|
||||
// punished and does not run indefinitely
|
||||
let bob_swap = ctx.stop_and_resume_bob_from_db(bob_join_handle).await;
|
||||
assert!(matches!(bob_swap.state, BobState::BtcLocked {..}));
|
||||
assert!(matches!(bob_swap.state, BobState::BtcLocked { .. }));
|
||||
|
||||
let bob_state = bob::run(bob_swap).await.unwrap();
|
||||
|
||||
|
@ -15,8 +15,7 @@ async fn given_alice_restarts_after_xmr_is_locked_refund_swap() {
|
||||
let bob_handle = tokio::spawn(bob);
|
||||
|
||||
let alice_state = alice::run_until(alice_swap, is_xmr_locked).await.unwrap();
|
||||
assert!(matches!(alice_state,
|
||||
AliceState::XmrLocked {..}));
|
||||
assert!(matches!(alice_state, AliceState::XmrLocked { .. }));
|
||||
|
||||
// Alice does not act, Bob refunds
|
||||
let bob_state = bob_handle.await.unwrap();
|
||||
@ -24,7 +23,7 @@ async fn given_alice_restarts_after_xmr_is_locked_refund_swap() {
|
||||
|
||||
// Once bob has finished Alice is restarted and refunds as well
|
||||
let alice_swap = ctx.stop_and_resume_alice_from_db(alice_join_handle).await;
|
||||
assert!(matches!(alice_swap.state, AliceState::XmrLocked {..}));
|
||||
assert!(matches!(alice_swap.state, AliceState::XmrLocked { .. }));
|
||||
|
||||
let alice_state = alice::run(alice_swap).await.unwrap();
|
||||
|
||||
|
@ -22,7 +22,7 @@ async fn given_alice_restarts_after_enc_sig_learned_and_bob_already_cancelled_re
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
matches!(alice_state, AliceState::EncSigLearned {..}),
|
||||
matches!(alice_state, AliceState::EncSigLearned { .. }),
|
||||
"Alice state is not EncSigLearned: {:?}",
|
||||
alice_state
|
||||
);
|
||||
@ -34,8 +34,7 @@ async fn given_alice_restarts_after_enc_sig_learned_and_bob_already_cancelled_re
|
||||
// Once bob has finished Alice is restarted and refunds as well
|
||||
let alice_swap = ctx.stop_and_resume_alice_from_db(alice_join_handle).await;
|
||||
assert!(
|
||||
matches!(alice_swap.state, AliceState::EncSigLearned
|
||||
{..}),
|
||||
matches!(alice_swap.state, AliceState::EncSigLearned { .. }),
|
||||
"Alice state is not EncSigLearned: {:?}",
|
||||
alice_state
|
||||
);
|
||||
|
@ -478,17 +478,11 @@ pub mod alice_run_until {
|
||||
use swap::protocol::alice::AliceState;
|
||||
|
||||
pub fn is_xmr_locked(state: &AliceState) -> bool {
|
||||
matches!(
|
||||
state,
|
||||
AliceState::XmrLocked{..}
|
||||
)
|
||||
matches!(state, AliceState::XmrLocked { .. })
|
||||
}
|
||||
|
||||
pub fn is_encsig_learned(state: &AliceState) -> bool {
|
||||
matches!(
|
||||
state,
|
||||
AliceState::EncSigLearned{..}
|
||||
)
|
||||
matches!(state, AliceState::EncSigLearned { .. })
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user