Merge pull request #113 from comit-network/clippy

This commit is contained in:
Franck Royer 2021-01-04 10:10:19 +11:00 committed by GitHub
commit dd10e68db4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 423 additions and 366 deletions

View File

@ -53,15 +53,15 @@ pub fn new_swarm(
Ok(swarm)
}
#[allow(clippy::large_enum_variant)]
#[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(amounts::OutEvent), // Not-uniform with Bob on purpose, ready for adding Xmr event.
Request(Box<amounts::OutEvent>), /* Not-uniform with Bob on purpose, ready for adding Xmr
* event. */
Message0 {
msg: bob::Message0,
msg: Box<bob::Message0>,
channel: ResponseChannel<AliceToBob>,
},
Message1 {
@ -87,14 +87,17 @@ impl From<peer_tracker::OutEvent> for OutEvent {
impl From<amounts::OutEvent> for OutEvent {
fn from(event: amounts::OutEvent) -> Self {
OutEvent::Request(event)
OutEvent::Request(Box::new(event))
}
}
impl From<message0::OutEvent> for OutEvent {
fn from(event: message0::OutEvent) -> Self {
match event {
message0::OutEvent::Msg { channel, msg } => OutEvent::Message0 { msg, channel },
message0::OutEvent::Msg { channel, msg } => OutEvent::Message0 {
msg: Box::new(msg),
channel,
},
}
}
}

View File

@ -11,6 +11,7 @@ use libp2p::{
use tokio::sync::mpsc::{Receiver, Sender};
use xmr_btc::{alice, bob};
#[allow(missing_debug_implementations)]
pub struct Channels<T> {
sender: Sender<T>,
receiver: Receiver<T>,
@ -29,6 +30,7 @@ impl<T> Default for Channels<T> {
}
}
#[derive(Debug)]
pub struct EventLoopHandle {
msg0: Receiver<(bob::Message0, ResponseChannel<AliceToBob>)>,
msg1: Receiver<(bob::Message1, ResponseChannel<AliceToBob>)>,
@ -122,6 +124,7 @@ impl EventLoopHandle {
}
}
#[allow(missing_debug_implementations)]
pub struct EventLoop {
swarm: libp2p::Swarm<Behaviour>,
msg0: Sender<(bob::Message0, ResponseChannel<AliceToBob>)>,
@ -203,7 +206,7 @@ impl EventLoop {
let _ = self.conn_established.send(alice).await;
}
OutEvent::Message0 { msg, channel } => {
let _ = self.msg0.send((msg, channel)).await;
let _ = self.msg0.send((*msg, channel)).await;
}
OutEvent::Message1 { msg, channel } => {
let _ = self.msg1.send((msg, channel)).await;
@ -215,7 +218,7 @@ impl EventLoop {
let _ = self.msg3.send(msg).await;
}
OutEvent::Request(event) => {
let _ = self.request.send(event).await;
let _ = self.request.send(*event).await;
}
}
},

View File

@ -37,7 +37,7 @@ pub struct Message0 {
impl Message0 {
pub fn send(&mut self, channel: ResponseChannel<AliceToBob>, msg: xmr_btc::alice::Message0) {
let msg = AliceToBob::Message0(msg);
let msg = AliceToBob::Message0(Box::new(msg));
self.rr.send_response(channel, msg);
}
fn poll(
@ -82,7 +82,7 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>>
} => {
if let BobToAlice::Message0(msg) = request {
debug!("Received Message0");
self.events.push_back(OutEvent::Msg { msg, channel });
self.events.push_back(OutEvent::Msg { msg: *msg, channel });
}
}
RequestResponseEvent::Message {

View File

@ -38,7 +38,7 @@ pub struct Message1 {
impl Message1 {
pub fn send(&mut self, channel: ResponseChannel<AliceToBob>, msg: xmr_btc::alice::Message1) {
let msg = AliceToBob::Message1(msg);
let msg = AliceToBob::Message1(Box::new(msg));
self.rr.send_response(channel, msg);
}

View File

@ -10,12 +10,9 @@ use crate::{
wait_for_bitcoin_encrypted_signature, wait_for_bitcoin_refund, wait_for_locked_bitcoin,
},
},
bitcoin,
bitcoin::EncryptedSignature,
database::{Database, Swap},
network::request_response::AliceToBob,
state,
state::{Alice, AliceEndState, Swap},
storage::Database,
SwapAmounts,
};
use anyhow::Result;
@ -41,7 +38,7 @@ trait Rng: RngCore + CryptoRng + Send {}
impl<T> Rng for T where T: RngCore + CryptoRng + Send {}
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum AliceState {
Started {
amounts: SwapAmounts,
@ -50,36 +47,36 @@ pub enum AliceState {
Negotiated {
channel: Option<ResponseChannel<AliceToBob>>,
amounts: SwapAmounts,
state3: State3,
state3: Box<State3>,
},
BtcLocked {
channel: Option<ResponseChannel<AliceToBob>>,
amounts: SwapAmounts,
state3: State3,
state3: Box<State3>,
},
XmrLocked {
state3: State3,
state3: Box<State3>,
},
EncSigLearned {
state3: State3,
encrypted_signature: EncryptedSignature,
state3: Box<State3>,
},
BtcRedeemed,
BtcCancelled {
state3: State3,
tx_cancel: TxCancel,
state3: Box<State3>,
},
BtcRefunded {
spend_key: monero::PrivateKey,
state3: State3,
state3: Box<State3>,
},
BtcPunishable {
tx_refund: TxRefund,
state3: State3,
state3: Box<State3>,
},
XmrRefunded,
CancelTimelockExpired {
state3: State3,
state3: Box<State3>,
},
BtcPunished,
SafelyAborted,
@ -105,114 +102,6 @@ impl fmt::Display for AliceState {
}
}
impl From<&AliceState> for state::Alice {
fn from(alice_state: &AliceState) -> Self {
match alice_state {
AliceState::Negotiated { state3, .. } => Alice::Negotiated(state3.clone()),
AliceState::BtcLocked { state3, .. } => Alice::BtcLocked(state3.clone()),
AliceState::XmrLocked { state3 } => Alice::XmrLocked(state3.clone()),
AliceState::EncSigLearned {
state3,
encrypted_signature,
} => Alice::EncSigLearned {
state: state3.clone(),
encrypted_signature: encrypted_signature.clone(),
},
AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed),
AliceState::BtcCancelled { state3, .. } => Alice::BtcCancelled(state3.clone()),
AliceState::BtcRefunded { spend_key, state3 } => Alice::BtcRefunded {
spend_key: *spend_key,
state3: state3.clone(),
},
AliceState::BtcPunishable { state3, .. } => Alice::BtcPunishable(state3.clone()),
AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded),
AliceState::CancelTimelockExpired { state3 } => {
Alice::CancelTimelockExpired(state3.clone())
}
AliceState::BtcPunished => Alice::Done(AliceEndState::BtcPunished),
AliceState::SafelyAborted => Alice::Done(AliceEndState::SafelyAborted),
AliceState::Started { amounts, state0 } => Alice::Started {
amounts: *amounts,
state0: state0.clone(),
},
}
}
}
impl From<state::Alice> for AliceState {
fn from(db_state: state::Alice) -> Self {
use AliceState::*;
match db_state {
Alice::Started { amounts, state0 } => Started { amounts, state0 },
Alice::Negotiated(state3) => Negotiated {
channel: None,
amounts: SwapAmounts {
btc: state3.btc,
xmr: state3.xmr,
},
state3,
},
Alice::BtcLocked(state3) => BtcLocked {
channel: None,
amounts: SwapAmounts {
btc: state3.btc,
xmr: state3.xmr,
},
state3,
},
Alice::XmrLocked(state3) => XmrLocked { state3 },
Alice::EncSigLearned {
state,
encrypted_signature,
} => EncSigLearned {
state3: state,
encrypted_signature,
},
Alice::CancelTimelockExpired(state3) => AliceState::CancelTimelockExpired { state3 },
Alice::BtcCancelled(state) => {
let tx_cancel = bitcoin::TxCancel::new(
&state.tx_lock,
state.cancel_timelock,
state.a.public(),
state.B,
);
BtcCancelled {
state3: state,
tx_cancel,
}
}
Alice::BtcPunishable(state) => {
let tx_cancel = bitcoin::TxCancel::new(
&state.tx_lock,
state.cancel_timelock,
state.a.public(),
state.B,
);
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &state.refund_address);
BtcPunishable {
tx_refund,
state3: state,
}
}
Alice::BtcRefunded {
state3: state,
spend_key,
..
} => BtcRefunded {
spend_key,
state3: state,
},
Alice::Done(end_state) => match end_state {
AliceEndState::SafelyAborted => SafelyAborted,
AliceEndState::BtcRedeemed => BtcRedeemed,
AliceEndState::XmrRefunded => XmrRefunded,
AliceEndState::BtcPunished => BtcPunished,
},
}
}
}
pub async fn swap(
state: AliceState,
event_loop_handle: EventLoopHandle,
@ -285,7 +174,7 @@ pub async fn run_until(
let state = AliceState::Negotiated {
channel: Some(channel),
amounts,
state3,
state3: Box::new(state3),
};
let db_state = (&state).into();
@ -356,7 +245,7 @@ pub async fn run_until(
lock_xmr(
channel,
amounts,
state3.clone(),
*state3.clone(),
&mut event_loop_handle,
monero_wallet.clone(),
)

View File

@ -45,13 +45,12 @@ pub fn new_swarm(transport: SwapTransport, behaviour: Behaviour) -> Result<Swarm
Ok(swarm)
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
pub enum OutEvent {
ConnectionEstablished(PeerId),
Amounts(SwapAmounts),
Message0(alice::Message0),
Message1(alice::Message1),
Message0(Box<alice::Message0>),
Message1(Box<alice::Message1>),
Message2(alice::Message2),
Message3,
}
@ -77,7 +76,7 @@ impl From<amounts::OutEvent> for OutEvent {
impl From<message0::OutEvent> for OutEvent {
fn from(event: message0::OutEvent) -> Self {
match event {
message0::OutEvent::Msg(msg) => OutEvent::Message0(msg),
message0::OutEvent::Msg(msg) => OutEvent::Message0(Box::new(msg)),
}
}
}
@ -85,7 +84,7 @@ impl From<message0::OutEvent> for OutEvent {
impl From<message1::OutEvent> for OutEvent {
fn from(event: message1::OutEvent) -> Self {
match event {
message1::OutEvent::Msg(msg) => OutEvent::Message1(msg),
message1::OutEvent::Msg(msg) => OutEvent::Message1(Box::new(msg)),
}
}
}

View File

@ -19,7 +19,7 @@ use crate::{
SwapAmounts,
};
#[derive(Debug)]
#[derive(Copy, Clone, Debug)]
pub enum OutEvent {
Amounts(SwapAmounts),
}

View File

@ -12,6 +12,7 @@ use tokio::{
use tracing::{debug, error, info};
use xmr_btc::{alice, bitcoin::EncryptedSignature, bob};
#[derive(Debug)]
pub struct Channels<T> {
sender: Sender<T>,
receiver: Receiver<T>,
@ -30,6 +31,7 @@ impl<T> Default for Channels<T> {
}
}
#[derive(Debug)]
pub struct EventLoopHandle {
msg0: Receiver<alice::Message0>,
msg1: Receiver<alice::Message1>,
@ -105,6 +107,7 @@ impl EventLoopHandle {
}
}
#[allow(missing_debug_implementations)]
pub struct EventLoop {
swarm: libp2p::Swarm<Behaviour>,
alice_peer_id: PeerId,
@ -189,10 +192,10 @@ impl EventLoop {
}
OutEvent::Amounts(_amounts) => info!("Amounts received from Alice"),
OutEvent::Message0(msg) => {
let _ = self.msg0.send(msg).await;
let _ = self.msg0.send(*msg).await;
}
OutEvent::Message1(msg) => {
let _ = self.msg1.send(msg).await;
let _ = self.msg1.send(*msg).await;
}
OutEvent::Message2(msg) => {
let _ = self.msg2.send(msg).await;

View File

@ -33,7 +33,7 @@ pub struct Message0 {
impl Message0 {
pub fn send(&mut self, alice: PeerId, msg: bob::Message0) {
let msg = BobToAlice::Message0(msg);
let msg = BobToAlice::Message0(Box::new(msg));
let _id = self.rr.send_request(&alice, msg);
}
@ -80,7 +80,7 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>>
} => {
if let AliceToBob::Message0(msg) = response {
debug!("Received Message0");
self.events.push_back(OutEvent::Msg(msg));
self.events.push_back(OutEvent::Msg(*msg));
}
}
RequestResponseEvent::InboundFailure { error, .. } => {

View File

@ -80,7 +80,7 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>>
} => {
if let AliceToBob::Message1(msg) = response {
debug!("Received Message1");
self.events.push_back(OutEvent::Msg(msg));
self.events.push_back(OutEvent::Msg(*msg));
}
}
RequestResponseEvent::InboundFailure { error, .. } => {

View File

@ -16,7 +16,7 @@ use tracing::error;
use crate::network::request_response::{AliceToBob, BobToAlice, Codec, Message3Protocol, TIMEOUT};
use xmr_btc::bob;
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
pub enum OutEvent {
Msg,
}

View File

@ -1,10 +1,4 @@
use crate::{
bob::event_loop::EventLoopHandle,
state,
state::{Bob, BobEndState},
storage::Database,
SwapAmounts,
};
use crate::{bob::event_loop::EventLoopHandle, database, database::Database, SwapAmounts};
use anyhow::{bail, Result};
use async_recursion::async_recursion;
use rand::{CryptoRng, RngCore};
@ -55,46 +49,6 @@ impl fmt::Display for BobState {
}
}
impl From<BobState> for state::Bob {
fn from(bob_state: BobState) -> Self {
match bob_state {
BobState::Started { state0, amounts } => Bob::Started { state0, amounts },
BobState::Negotiated(state2) => Bob::Negotiated { state2 },
BobState::BtcLocked(state3) => Bob::BtcLocked { state3 },
BobState::XmrLocked(state4) => Bob::XmrLocked { state4 },
BobState::EncSigSent(state4) => Bob::EncSigSent { state4 },
BobState::BtcRedeemed(state5) => Bob::BtcRedeemed(state5),
BobState::CancelTimelockExpired(state4) => Bob::CancelTimelockExpired(state4),
BobState::BtcCancelled(state4) => Bob::BtcCancelled(state4),
BobState::BtcRefunded(state4) => Bob::Done(BobEndState::BtcRefunded(Box::new(state4))),
BobState::XmrRedeemed => Bob::Done(BobEndState::XmrRedeemed),
BobState::BtcPunished => Bob::Done(BobEndState::BtcPunished),
BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted),
}
}
}
impl From<state::Bob> for BobState {
fn from(db_state: state::Bob) -> Self {
match db_state {
Bob::Started { state0, amounts } => BobState::Started { state0, amounts },
Bob::Negotiated { state2 } => BobState::Negotiated(state2),
Bob::BtcLocked { state3 } => BobState::BtcLocked(state3),
Bob::XmrLocked { state4 } => BobState::XmrLocked(state4),
Bob::EncSigSent { state4 } => BobState::EncSigSent(state4),
Bob::BtcRedeemed(state5) => BobState::BtcRedeemed(state5),
Bob::CancelTimelockExpired(state4) => BobState::CancelTimelockExpired(state4),
Bob::BtcCancelled(state4) => BobState::BtcCancelled(state4),
Bob::Done(end_state) => match end_state {
BobEndState::SafelyAborted => BobState::SafelyAborted,
BobEndState::XmrRedeemed => BobState::XmrRedeemed,
BobEndState::BtcRefunded(state4) => BobState::BtcRefunded(*state4),
BobEndState::BtcPunished => BobState::BtcPunished,
},
}
}
}
// TODO(Franck): Make this a method on a struct
#[allow(clippy::too_many_arguments)]
pub async fn swap<R>(
@ -179,7 +133,7 @@ where
let state = BobState::Negotiated(state2);
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,
@ -201,7 +155,7 @@ where
let state = BobState::BtcLocked(state3);
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,
@ -255,7 +209,7 @@ where
BobState::CancelTimelockExpired(state4)
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,
@ -297,7 +251,7 @@ where
BobState::CancelTimelockExpired(state)
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,
@ -333,7 +287,7 @@ where
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,
@ -353,7 +307,7 @@ where
let state = BobState::XmrRedeemed;
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,
@ -377,7 +331,7 @@ where
}
let state = BobState::BtcCancelled(state4);
db.insert_latest_state(swap_id, state::Swap::Bob(state.clone().into()))
db.insert_latest_state(swap_id, database::Swap::Bob(state.clone().into()))
.await?;
run_until(
@ -406,7 +360,7 @@ where
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, state::Swap::Bob(db_state))
db.insert_latest_state(swap_id, database::Swap::Bob(db_state))
.await?;
run_until(
state,

View File

@ -1,9 +1,15 @@
use crate::state::Swap;
use anyhow::{anyhow, bail, Context, Result};
use serde::{de::DeserializeOwned, Serialize};
use std::path::Path;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{fmt::Display, path::Path};
use uuid::Uuid;
mod alice;
mod bob;
pub use alice::*;
pub use bob::*;
#[derive(Debug)]
pub struct Database(sled::Db);
impl Database {
@ -79,11 +85,37 @@ where
Ok(serde_cbor::from_slice(&v)?)
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Swap {
Alice(Alice),
Bob(Bob),
}
impl From<Alice> for Swap {
fn from(from: Alice) -> Self {
Swap::Alice(from)
}
}
impl From<Bob> for Swap {
fn from(from: Bob) -> Self {
Swap::Bob(from)
}
}
impl Display for Swap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Swap::Alice(alice) => Display::fmt(alice, f),
Swap::Bob(bob) => Display::fmt(bob, f),
}
}
}
#[cfg(test)]
mod tests {
use crate::state::{Alice, AliceEndState, Bob, BobEndState};
use super::*;
use crate::database::{Alice, AliceEndState, Bob, BobEndState};
#[tokio::test]
async fn can_write_and_read_to_multiple_keys() {

172
swap/src/database/alice.rs Normal file
View File

@ -0,0 +1,172 @@
use crate::{alice::swap::AliceState, SwapAmounts};
use bitcoin::hashes::core::fmt::Display;
use serde::{Deserialize, Serialize};
use xmr_btc::{
alice,
bitcoin::{EncryptedSignature, TxCancel, TxRefund},
monero,
serde::monero_private_key,
};
// Large enum variant is fine because this is only used for storage
// and is dropped once written in DB.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Alice {
Started {
amounts: SwapAmounts,
state0: alice::State0,
},
Negotiated(alice::State3),
BtcLocked(alice::State3),
XmrLocked(alice::State3),
EncSigLearned {
encrypted_signature: EncryptedSignature,
state3: alice::State3,
},
CancelTimelockExpired(alice::State3),
BtcCancelled(alice::State3),
BtcPunishable(alice::State3),
BtcRefunded {
state3: alice::State3,
#[serde(with = "monero_private_key")]
spend_key: monero::PrivateKey,
},
Done(AliceEndState),
}
#[derive(Copy, Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum AliceEndState {
SafelyAborted,
BtcRedeemed,
XmrRefunded,
BtcPunished,
}
impl From<&AliceState> for Alice {
fn from(alice_state: &AliceState) -> Self {
match alice_state {
AliceState::Negotiated { state3, .. } => Alice::Negotiated(state3.as_ref().clone()),
AliceState::BtcLocked { state3, .. } => Alice::BtcLocked(state3.as_ref().clone()),
AliceState::XmrLocked { state3 } => Alice::XmrLocked(state3.as_ref().clone()),
AliceState::EncSigLearned {
state3,
encrypted_signature,
} => Alice::EncSigLearned {
state3: state3.as_ref().clone(),
encrypted_signature: encrypted_signature.clone(),
},
AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed),
AliceState::BtcCancelled { state3, .. } => Alice::BtcCancelled(state3.as_ref().clone()),
AliceState::BtcRefunded { spend_key, state3 } => Alice::BtcRefunded {
spend_key: *spend_key,
state3: state3.as_ref().clone(),
},
AliceState::BtcPunishable { state3, .. } => {
Alice::BtcPunishable(state3.as_ref().clone())
}
AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded),
AliceState::CancelTimelockExpired { state3 } => {
Alice::CancelTimelockExpired(state3.as_ref().clone())
}
AliceState::BtcPunished => Alice::Done(AliceEndState::BtcPunished),
AliceState::SafelyAborted => Alice::Done(AliceEndState::SafelyAborted),
AliceState::Started { amounts, state0 } => Alice::Started {
amounts: *amounts,
state0: state0.clone(),
},
}
}
}
impl From<Alice> for AliceState {
fn from(db_state: Alice) -> Self {
match db_state {
Alice::Started { amounts, state0 } => AliceState::Started { amounts, state0 },
Alice::Negotiated(state3) => AliceState::Negotiated {
channel: None,
amounts: SwapAmounts {
btc: state3.btc,
xmr: state3.xmr,
},
state3: Box::new(state3),
},
Alice::BtcLocked(state3) => AliceState::BtcLocked {
channel: None,
amounts: SwapAmounts {
btc: state3.btc,
xmr: state3.xmr,
},
state3: Box::new(state3),
},
Alice::XmrLocked(state3) => AliceState::XmrLocked {
state3: Box::new(state3),
},
Alice::EncSigLearned {
state3: state,
encrypted_signature,
} => AliceState::EncSigLearned {
state3: Box::new(state),
encrypted_signature,
},
Alice::CancelTimelockExpired(state3) => AliceState::CancelTimelockExpired {
state3: Box::new(state3),
},
Alice::BtcCancelled(state) => {
let tx_cancel = TxCancel::new(
&state.tx_lock,
state.cancel_timelock,
state.a.public(),
state.B,
);
AliceState::BtcCancelled {
state3: Box::new(state),
tx_cancel,
}
}
Alice::BtcPunishable(state3) => {
let tx_cancel = TxCancel::new(
&state3.tx_lock,
state3.cancel_timelock,
state3.a.public(),
state3.B,
);
let tx_refund = TxRefund::new(&tx_cancel, &state3.refund_address);
AliceState::BtcPunishable {
tx_refund,
state3: Box::new(state3),
}
}
Alice::BtcRefunded {
state3, spend_key, ..
} => AliceState::BtcRefunded {
spend_key,
state3: Box::new(state3),
},
Alice::Done(end_state) => match end_state {
AliceEndState::SafelyAborted => AliceState::SafelyAborted,
AliceEndState::BtcRedeemed => AliceState::BtcRedeemed,
AliceEndState::XmrRefunded => AliceState::XmrRefunded,
AliceEndState::BtcPunished => AliceState::BtcPunished,
},
}
}
}
impl Display for Alice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Alice::Started { .. } => write!(f, "Started"),
Alice::Negotiated(_) => f.write_str("Negotiated"),
Alice::BtcLocked(_) => f.write_str("Bitcoin locked"),
Alice::XmrLocked(_) => f.write_str("Monero locked"),
Alice::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
Alice::BtcCancelled(_) => f.write_str("Bitcoin cancel transaction published"),
Alice::BtcPunishable(_) => f.write_str("Bitcoin punishable"),
Alice::BtcRefunded { .. } => f.write_str("Monero refundable"),
Alice::Done(end_state) => write!(f, "Done: {}", end_state),
Alice::EncSigLearned { .. } => f.write_str("Encrypted signature learned"),
}
}
}

92
swap/src/database/bob.rs Normal file
View File

@ -0,0 +1,92 @@
use crate::{bob::swap::BobState, SwapAmounts};
use bitcoin::hashes::core::fmt::Display;
use serde::{Deserialize, Serialize};
use xmr_btc::bob;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Bob {
Started {
state0: bob::State0,
amounts: SwapAmounts,
},
Negotiated {
state2: bob::State2,
},
BtcLocked {
state3: bob::State3,
},
XmrLocked {
state4: bob::State4,
},
EncSigSent {
state4: bob::State4,
},
BtcRedeemed(bob::State5),
CancelTimelockExpired(bob::State4),
BtcCancelled(bob::State4),
Done(BobEndState),
}
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum BobEndState {
SafelyAborted,
XmrRedeemed,
BtcRefunded(Box<bob::State4>),
BtcPunished,
}
impl From<BobState> for Bob {
fn from(bob_state: BobState) -> Self {
match bob_state {
BobState::Started { state0, amounts } => Bob::Started { state0, amounts },
BobState::Negotiated(state2) => Bob::Negotiated { state2 },
BobState::BtcLocked(state3) => Bob::BtcLocked { state3 },
BobState::XmrLocked(state4) => Bob::XmrLocked { state4 },
BobState::EncSigSent(state4) => Bob::EncSigSent { state4 },
BobState::BtcRedeemed(state5) => Bob::BtcRedeemed(state5),
BobState::CancelTimelockExpired(state4) => Bob::CancelTimelockExpired(state4),
BobState::BtcCancelled(state4) => Bob::BtcCancelled(state4),
BobState::BtcRefunded(state4) => Bob::Done(BobEndState::BtcRefunded(Box::new(state4))),
BobState::XmrRedeemed => Bob::Done(BobEndState::XmrRedeemed),
BobState::BtcPunished => Bob::Done(BobEndState::BtcPunished),
BobState::SafelyAborted => Bob::Done(BobEndState::SafelyAborted),
}
}
}
impl From<Bob> for BobState {
fn from(db_state: Bob) -> Self {
match db_state {
Bob::Started { state0, amounts } => BobState::Started { state0, amounts },
Bob::Negotiated { state2 } => BobState::Negotiated(state2),
Bob::BtcLocked { state3 } => BobState::BtcLocked(state3),
Bob::XmrLocked { state4 } => BobState::XmrLocked(state4),
Bob::EncSigSent { state4 } => BobState::EncSigSent(state4),
Bob::BtcRedeemed(state5) => BobState::BtcRedeemed(state5),
Bob::CancelTimelockExpired(state4) => BobState::CancelTimelockExpired(state4),
Bob::BtcCancelled(state4) => BobState::BtcCancelled(state4),
Bob::Done(end_state) => match end_state {
BobEndState::SafelyAborted => BobState::SafelyAborted,
BobEndState::XmrRedeemed => BobState::XmrRedeemed,
BobEndState::BtcRefunded(state4) => BobState::BtcRefunded(*state4),
BobEndState::BtcPunished => BobState::BtcPunished,
},
}
}
}
impl Display for Bob {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Bob::Started { .. } => write!(f, "Started"),
Bob::Negotiated { .. } => f.write_str("Negotiated"),
Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Bob::XmrLocked { .. } => f.write_str("Monero locked"),
Bob::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"),
Bob::BtcRedeemed(_) => f.write_str("Monero redeemable"),
Bob::Done(end_state) => write!(f, "Done: {}", end_state),
Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"),
}
}
}

View File

@ -1,3 +1,16 @@
#![warn(
unused_extern_crates,
missing_debug_implementations,
missing_copy_implementations,
rust_2018_idioms,
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::fallible_impl_from,
clippy::cast_precision_loss,
clippy::cast_possible_wrap,
clippy::dbg_macro
)]
#![forbid(unsafe_code)]
#![allow(non_snake_case)]
use ::serde::{Deserialize, Serialize};
@ -7,10 +20,9 @@ pub mod alice;
pub mod bitcoin;
pub mod bob;
pub mod cli;
pub mod database;
pub mod monero;
pub mod network;
pub mod state;
pub mod storage;
pub mod trace;
pub type Never = std::convert::Infallible;
@ -42,7 +54,7 @@ pub struct SwapAmounts {
// TODO: Display in XMR and BTC (not picos and sats).
impl Display for SwapAmounts {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} sats for {} piconeros",

View File

@ -11,6 +11,7 @@
clippy::dbg_macro
)]
#![forbid(unsafe_code)]
#![allow(non_snake_case)]
use anyhow::{bail, Context, Result};
use libp2p::{core::Multiaddr, PeerId};
@ -24,10 +25,9 @@ use swap::{
bitcoin, bob,
bob::swap::BobState,
cli::{Command, Options, Resume},
database::{Database, Swap},
monero,
network::transport::build,
state::Swap,
storage::Database,
trace::init_tracing,
SwapAmounts,
};

View File

@ -7,6 +7,7 @@ use url::Url;
pub use xmr_btc::monero::*;
#[derive(Debug)]
pub struct Wallet(pub wallet::Client);
impl Wallet {

View File

@ -7,6 +7,7 @@ pub mod peer_tracker;
pub mod request_response;
pub mod transport;
#[allow(missing_debug_implementations)]
pub struct TokioExecutor {
pub handle: Handle,
}

View File

@ -22,12 +22,11 @@ const BUF_SIZE: usize = 1024 * 1024;
/// Messages Bob sends to Alice.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum BobToAlice {
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
AmountsFromBtc(::bitcoin::Amount),
AmountsFromXmr(monero::Amount),
Message0(bob::Message0),
Message0(Box<bob::Message0>),
Message1(bob::Message1),
Message2(bob::Message2),
Message3(bob::Message3),
@ -35,11 +34,10 @@ pub enum BobToAlice {
/// Messages Alice sends to Bob.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum AliceToBob {
Amounts(SwapAmounts),
Message0(alice::Message0),
Message1(alice::Message1),
Message0(Box<alice::Message0>),
Message1(Box<alice::Message1>),
Message2(alice::Message2),
Message3, // empty response
}

View File

@ -1,130 +0,0 @@
use crate::SwapAmounts;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use xmr_btc::{alice, bitcoin::EncryptedSignature, bob, monero, serde::monero_private_key};
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Swap {
Alice(Alice),
Bob(Bob),
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Alice {
Started {
amounts: SwapAmounts,
state0: alice::State0,
},
Negotiated(alice::State3),
BtcLocked(alice::State3),
XmrLocked(alice::State3),
EncSigLearned {
state: alice::State3,
encrypted_signature: EncryptedSignature,
},
CancelTimelockExpired(alice::State3),
BtcCancelled(alice::State3),
BtcPunishable(alice::State3),
BtcRefunded {
state3: alice::State3,
#[serde(with = "monero_private_key")]
spend_key: monero::PrivateKey,
},
Done(AliceEndState),
}
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum AliceEndState {
SafelyAborted,
BtcRedeemed,
XmrRefunded,
BtcPunished,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Bob {
Started {
state0: bob::State0,
amounts: SwapAmounts,
},
Negotiated {
state2: bob::State2,
},
BtcLocked {
state3: bob::State3,
},
XmrLocked {
state4: bob::State4,
},
EncSigSent {
state4: bob::State4,
},
BtcRedeemed(bob::State5),
CancelTimelockExpired(bob::State4),
BtcCancelled(bob::State4),
Done(BobEndState),
}
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum BobEndState {
SafelyAborted,
XmrRedeemed,
BtcRefunded(Box<bob::State4>),
BtcPunished,
}
impl From<Alice> for Swap {
fn from(from: Alice) -> Self {
Swap::Alice(from)
}
}
impl From<Bob> for Swap {
fn from(from: Bob) -> Self {
Swap::Bob(from)
}
}
impl Display for Swap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Swap::Alice(alice) => Display::fmt(alice, f),
Swap::Bob(bob) => Display::fmt(bob, f),
}
}
}
impl Display for Alice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Alice::Started { .. } => write!(f, "Started"),
Alice::Negotiated(_) => f.write_str("Negotiated"),
Alice::BtcLocked(_) => f.write_str("Bitcoin locked"),
Alice::XmrLocked(_) => f.write_str("Monero locked"),
Alice::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
Alice::BtcCancelled(_) => f.write_str("Bitcoin cancel transaction published"),
Alice::BtcPunishable(_) => f.write_str("Bitcoin punishable"),
Alice::BtcRefunded { .. } => f.write_str("Monero refundable"),
Alice::Done(end_state) => write!(f, "Done: {}", end_state),
Alice::EncSigLearned { .. } => f.write_str("Encrypted signature learned"),
}
}
}
impl Display for Bob {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Bob::Started { .. } => write!(f, "Started"),
Bob::Negotiated { .. } => f.write_str("Negotiated"),
Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Bob::XmrLocked { .. } => f.write_str("Monero locked"),
Bob::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"),
Bob::BtcRedeemed(_) => f.write_str("Monero redeemable"),
Bob::Done(end_state) => write!(f, "Done: {}", end_state),
Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"),
}
}
}

View File

@ -2,7 +2,7 @@ use crate::testutils::{init_alice, init_bob};
use get_port::get_port;
use libp2p::Multiaddr;
use rand::rngs::OsRng;
use swap::{alice, alice::swap::AliceState, bitcoin, bob, storage::Database};
use swap::{alice, alice::swap::AliceState, bitcoin, bob, database::Database};
use tempfile::tempdir;
use testcontainers::clients::Cli;
use testutils::init_tracing;
@ -112,8 +112,8 @@ async fn given_alice_restarts_after_encsig_is_learned_resume_swap() {
let alice_db = Database::open(alice_db_datadir.path()).unwrap();
let resume_state =
if let swap::state::Swap::Alice(state) = alice_db.get_state(alice_swap_id).unwrap() {
assert!(matches!(state, swap::state::Alice::EncSigLearned {..}));
if let swap::database::Swap::Alice(state) = alice_db.get_state(alice_swap_id).unwrap() {
assert!(matches!(state, swap::database::Alice::EncSigLearned {..}));
state.into()
} else {
unreachable!()

View File

@ -2,7 +2,7 @@ use crate::testutils::{init_alice, init_bob};
use get_port::get_port;
use libp2p::Multiaddr;
use rand::rngs::OsRng;
use swap::{alice, bitcoin, bob, bob::swap::BobState, storage::Database};
use swap::{alice, bitcoin, bob, bob::swap::BobState, database::Database};
use tempfile::tempdir;
use testcontainers::clients::Cli;
use testutils::init_tracing;
@ -114,13 +114,13 @@ async fn given_bob_restarts_after_encsig_is_sent_resume_swap() {
let bob_db = Database::open(bob_db_datadir.path()).unwrap();
let resume_state = if let swap::state::Swap::Bob(state) = bob_db.get_state(bob_swap_id).unwrap()
{
assert!(matches!(state, swap::state::Bob::EncSigSent {..}));
state.into()
} else {
unreachable!()
};
let resume_state =
if let swap::database::Swap::Bob(state) = bob_db.get_state(bob_swap_id).unwrap() {
assert!(matches!(state, swap::database::Bob::EncSigSent {..}));
state.into()
} else {
unreachable!()
};
let (event_loop_after_restart, event_loop_handle_after_restart) =
testutils::init_bob_event_loop(alice_peer_id, alice_multiaddr);

View File

@ -2,7 +2,7 @@ use crate::testutils::{init_alice, init_bob};
use get_port::get_port;
use libp2p::Multiaddr;
use rand::rngs::OsRng;
use swap::{alice, alice::swap::AliceState, bitcoin, bob, bob::swap::BobState, storage::Database};
use swap::{alice, alice::swap::AliceState, bitcoin, bob, bob::swap::BobState, database::Database};
use tempfile::tempdir;
use testcontainers::clients::Cli;
use testutils::init_tracing;

View File

@ -3,7 +3,7 @@ use futures::future::try_join;
use get_port::get_port;
use libp2p::Multiaddr;
use rand::rngs::OsRng;
use swap::{alice, alice::swap::AliceState, bob, bob::swap::BobState, storage::Database};
use swap::{alice, alice::swap::AliceState, bob, bob::swap::BobState, database::Database};
use tempfile::tempdir;
use testcontainers::clients::Cli;
use testutils::init_tracing;

View File

@ -4,8 +4,8 @@ use monero_harness::{image, Monero};
use rand::rngs::OsRng;
use std::sync::Arc;
use swap::{
alice, alice::swap::AliceState, bitcoin, bob, bob::swap::BobState, monero,
network::transport::build, storage::Database, SwapAmounts,
alice, alice::swap::AliceState, bitcoin, bob, bob::swap::BobState, database::Database, monero,
network::transport::build, SwapAmounts,
};
use tempfile::tempdir;
use testcontainers::{clients::Cli, Container};

View File

@ -376,11 +376,10 @@ pub async fn next_state<
state6.redeem_btc(bitcoin_wallet).await?;
Ok(state6.into())
}
State::State6(state6) => Ok(state6.into()),
State::State6(state6) => Ok((*state6).into()),
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Deserialize, Serialize)]
pub enum State {
State0(State0),
@ -389,7 +388,7 @@ pub enum State {
State3(State3),
State4(State4),
State5(State5),
State6(State6),
State6(Box<State6>),
}
impl_try_from_parent_enum!(State0, State);
@ -398,7 +397,7 @@ impl_try_from_parent_enum!(State2, State);
impl_try_from_parent_enum!(State3, State);
impl_try_from_parent_enum!(State4, State);
impl_try_from_parent_enum!(State5, State);
impl_try_from_parent_enum!(State6, State);
impl_try_from_parent_enum_for_boxed!(State6, State);
impl_from_child_enum!(State0, State);
impl_from_child_enum!(State1, State);
@ -406,7 +405,7 @@ impl_from_child_enum!(State2, State);
impl_from_child_enum!(State3, State);
impl_from_child_enum!(State4, State);
impl_from_child_enum!(State5, State);
impl_from_child_enum!(State6, State);
impl_from_child_enum_for_boxed!(State6, State);
impl State {
pub fn new<R: RngCore + CryptoRng>(

View File

@ -50,6 +50,8 @@ impl TxLock {
}
pub fn as_outpoint(&self) -> OutPoint {
// This is fine because a transaction that has that many outputs is not
// realistic
#[allow(clippy::cast_possible_truncation)]
OutPoint::new(self.inner.txid(), self.lock_output_vout() as u32)
}

View File

@ -43,7 +43,6 @@ use crate::{
use ::bitcoin::{Transaction, Txid};
pub use message::{Message, Message0, Message1, Message2, Message3};
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum Action {
LockBtc(bitcoin::TxLock),

View File

@ -41,6 +41,24 @@ mod utils {
};
}
macro_rules! impl_try_from_parent_enum_for_boxed {
($type:ident, $parent:ident) => {
impl TryFrom<$parent> for $type {
type Error = anyhow::Error;
fn try_from(from: $parent) -> Result<Self> {
if let $parent::$type(inner) = from {
Ok(*inner)
} else {
Err(anyhow::anyhow!(
"Failed to convert parent state to child state"
))
}
}
}
};
}
macro_rules! impl_from_child_enum {
($type:ident, $parent:ident) => {
impl From<$type> for $parent {
@ -50,6 +68,16 @@ mod utils {
}
};
}
macro_rules! impl_from_child_enum_for_boxed {
($type:ident, $parent:ident) => {
impl From<$type> for $parent {
fn from(from: $type) -> Self {
$parent::$type(Box::new(from))
}
}
};
}
}
pub mod alice;