Init Alice behaviour with state0

Previously state0 had to be set after creating Alice's behaviour.
With the event loop we no longer has access to the swarm so
set_state0() has to be called indirectly through a channel. This
means it is difficult to guarantee state0 is being set due to the
asynchronous nature of channels. This was solved by initialising
Alice with state0.
pull/65/head
rishflab 4 years ago
parent 3d8866f1a0
commit 27d1334726

@ -145,9 +145,6 @@ pub async fn swap(
punish_address, punish_address,
); );
info!("Commencing handshake");
swarm.set_state0(state.clone());
state0 = Some(state) state0 = Some(state)
} }
OutEvent::Message0(msg) => { OutEvent::Message0(msg) => {
@ -387,6 +384,20 @@ pub struct Behaviour {
} }
impl Behaviour { impl Behaviour {
pub fn new(state: State0) -> Self {
let identity = Keypair::generate_ed25519();
Self {
pt: PeerTracker::default(),
amounts: Amounts::default(),
message0: Message0::new(state),
message1: Message1::default(),
message2: Message2::default(),
message3: Message3::default(),
identity,
}
}
pub fn identity(&self) -> Keypair { pub fn identity(&self) -> Keypair {
self.identity.clone() self.identity.clone()
} }
@ -402,13 +413,6 @@ impl Behaviour {
info!("Sent amounts response"); info!("Sent amounts response");
} }
// TODO(Franck) remove
/// Message0 gets sent within the network layer using this state0.
pub fn set_state0(&mut self, state: State0) {
debug!("Set state 0");
let _ = self.message0.set_state(state);
}
/// Send Message1 to Bob in response to receiving his Message1. /// Send Message1 to Bob in response to receiving his Message1.
pub fn send_message1( pub fn send_message1(
&mut self, &mut self,
@ -430,22 +434,6 @@ impl Behaviour {
} }
} }
impl Default for Behaviour {
fn default() -> Self {
let identity = Keypair::generate_ed25519();
Self {
pt: PeerTracker::default(),
amounts: Amounts::default(),
message0: Message0::default(),
message1: Message1::default(),
message2: Message2::default(),
message3: Message3::default(),
identity,
}
}
}
fn calculate_amounts(btc: ::bitcoin::Amount) -> SwapAmounts { fn calculate_amounts(btc: ::bitcoin::Amount) -> SwapAmounts {
// TODO (Franck): This should instead verify that the received amounts matches // TODO (Franck): This should instead verify that the received amounts matches
// the command line arguments This value corresponds to 100 XMR per BTC // the command line arguments This value corresponds to 100 XMR per BTC

@ -1,6 +1,6 @@
use crate::{ use crate::{
alice::swarm_driver::SwarmDriverHandle, bitcoin, monero, network::request_response::AliceToBob, alice::swarm_driver::SwarmDriverHandle, bitcoin, monero, network::request_response::AliceToBob,
SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK, SwapAmounts,
}; };
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic}; use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic};
@ -9,13 +9,14 @@ use futures::{
pin_mut, pin_mut,
}; };
use libp2p::request_response::ResponseChannel; use libp2p::request_response::ResponseChannel;
use sha2::Sha256; use sha2::Sha256;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use tokio::time::timeout; use tokio::time::timeout;
use tracing::trace; use tracing::trace;
use xmr_btc::{ use xmr_btc::{
alice, alice,
alice::{State0, State3}, alice::State3,
bitcoin::{ bitcoin::{
poll_until_block_height_is_gte, BlockHeight, BroadcastSignedTransaction, poll_until_block_height_is_gte, BlockHeight, BroadcastSignedTransaction,
EncryptedSignature, GetRawTransaction, TransactionBlockHeight, TxCancel, TxLock, TxRefund, EncryptedSignature, GetRawTransaction, TransactionBlockHeight, TxCancel, TxLock, TxRefund,
@ -27,20 +28,23 @@ use xmr_btc::{
}; };
pub async fn negotiate( pub async fn negotiate(
state0: xmr_btc::alice::State0,
amounts: SwapAmounts, amounts: SwapAmounts,
a: bitcoin::SecretKey, // a: bitcoin::SecretKey,
s_a: cross_curve_dleq::Scalar, // s_a: cross_curve_dleq::Scalar,
v_a: monero::PrivateViewKey, // v_a: monero::PrivateViewKey,
swarm: &mut SwarmDriverHandle, swarm_handle: &mut SwarmDriverHandle,
bitcoin_wallet: Arc<bitcoin::Wallet>, // bitcoin_wallet: Arc<bitcoin::Wallet>,
config: Config, config: Config,
) -> Result<(ResponseChannel<AliceToBob>, State3)> { ) -> Result<(ResponseChannel<AliceToBob>, State3)> {
trace!("Starting negotiate"); trace!("Starting negotiate");
let _peer_id = timeout(config.bob_time_to_act, swarm.recv_conn_established())
// todo: we can move this out, we dont need to timeout here
let _peer_id = timeout(config.bob_time_to_act, swarm_handle.recv_conn_established())
.await .await
.context("Failed to receive dial connection from Bob")??; .context("Failed to receive dial connection from Bob")??;
let event = timeout(config.bob_time_to_act, swarm.recv_request()) let event = timeout(config.bob_time_to_act, swarm_handle.recv_request())
.await .await
.context("Failed to receive amounts from Bob")??; .context("Failed to receive amounts from Bob")??;
@ -52,37 +56,23 @@ pub async fn negotiate(
); );
} }
swarm.send_amounts(event.channel, amounts).await?; swarm_handle.send_amounts(event.channel, amounts).await?;
let redeem_address = bitcoin_wallet.as_ref().new_address().await?;
let punish_address = redeem_address.clone();
let state0 = State0::new(
a,
s_a,
v_a,
amounts.btc,
amounts.xmr,
REFUND_TIMELOCK,
PUNISH_TIMELOCK,
redeem_address,
punish_address,
);
// TODO(Franck): Understand why this is needed.
// swarm.swarm.set_state0(state0.clone());
let bob_message0 = timeout(config.bob_time_to_act, swarm.recv_message0()).await??; let bob_message0 = timeout(config.bob_time_to_act, swarm_handle.recv_message0()).await??;
let state1 = state0.receive(bob_message0)?; let state1 = state0.receive(bob_message0)?;
let (bob_message1, channel) = timeout(config.bob_time_to_act, swarm.recv_message1()).await??; let (bob_message1, channel) =
timeout(config.bob_time_to_act, swarm_handle.recv_message1()).await??;
let state2 = state1.receive(bob_message1); let state2 = state1.receive(bob_message1);
swarm.send_message1(channel, state2.next_message()).await?; swarm_handle
.send_message1(channel, state2.next_message())
.await?;
let (bob_message2, channel) = timeout(config.bob_time_to_act, swarm.recv_message2()).await??; let (bob_message2, channel) =
timeout(config.bob_time_to_act, swarm_handle.recv_message2()).await??;
let state3 = state2.receive(bob_message2)?; let state3 = state2.receive(bob_message2)?;

@ -1,4 +1,3 @@
use anyhow::{bail, Result};
use libp2p::{ use libp2p::{
request_response::{ request_response::{
handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig, handler::RequestProtocol, ProtocolSupport, RequestResponse, RequestResponseConfig,
@ -32,17 +31,24 @@ pub struct Message0 {
#[behaviour(ignore)] #[behaviour(ignore)]
events: VecDeque<OutEvent>, events: VecDeque<OutEvent>,
#[behaviour(ignore)] #[behaviour(ignore)]
state: Option<State0>, state: State0,
} }
impl Message0 { impl Message0 {
pub fn set_state(&mut self, state: State0) -> Result<()> { pub fn new(state: State0) -> Self {
if self.state.is_some() { let timeout = Duration::from_secs(TIMEOUT);
bail!("Trying to set state a second time"); let mut config = RequestResponseConfig::default();
} config.set_request_timeout(timeout);
self.state = Some(state);
Ok(()) Self {
rr: RequestResponse::new(
Codec::default(),
vec![(Message0Protocol, ProtocolSupport::Full)],
config,
),
events: Default::default(),
state,
}
} }
fn poll( fn poll(
@ -58,24 +64,6 @@ impl Message0 {
} }
} }
impl Default for Message0 {
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(),
state: None,
}
}
}
impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Message0 { impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>> for Message0 {
fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) { fn inject_event(&mut self, event: RequestResponseEvent<BobToAlice, AliceToBob>) {
match event { match event {
@ -88,13 +76,9 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<BobToAlice, AliceToBob>>
} => { } => {
if let BobToAlice::Message0(msg) = request { if let BobToAlice::Message0(msg) = request {
debug!("Received Message0"); debug!("Received Message0");
let response = match &self.state {
None => panic!("No state, did you forget to set it?"), let response = AliceToBob::Message0(self.state.next_message(&mut OsRng));
Some(state) => {
// TODO: Get OsRng from somewhere?
AliceToBob::Message0(state.next_message(&mut OsRng))
}
};
self.rr.send_response(channel, response); self.rr.send_response(channel, response);
debug!("Sent Message0"); debug!("Sent Message0");

@ -10,9 +10,7 @@ use crate::{
}, },
swarm_driver::SwarmDriverHandle, swarm_driver::SwarmDriverHandle,
}, },
bitcoin,
bitcoin::EncryptedSignature, bitcoin::EncryptedSignature,
monero,
network::request_response::AliceToBob, network::request_response::AliceToBob,
SwapAmounts, SwapAmounts,
}; };
@ -27,10 +25,9 @@ use rand::{CryptoRng, RngCore};
use std::{fmt, sync::Arc}; use std::{fmt, sync::Arc};
use tracing::info; use tracing::info;
use xmr_btc::{ use xmr_btc::{
alice::State3, alice::{State0, State3},
bitcoin::{TransactionBlockHeight, TxCancel, TxRefund, WatchForRawTransaction}, bitcoin::{TransactionBlockHeight, TxCancel, TxRefund, WatchForRawTransaction},
config::Config, config::Config,
cross_curve_dleq,
monero::CreateWalletForOutput, monero::CreateWalletForOutput,
}; };
@ -44,9 +41,7 @@ impl<T> Rng for T where T: RngCore + CryptoRng + Send {}
pub enum AliceState { pub enum AliceState {
Started { Started {
amounts: SwapAmounts, amounts: SwapAmounts,
a: bitcoin::SecretKey, state0: State0,
s_a: cross_curve_dleq::Scalar,
v_a: monero::PrivateViewKey,
}, },
Negotiated { Negotiated {
channel: ResponseChannel<AliceToBob>, channel: ResponseChannel<AliceToBob>,
@ -157,22 +152,8 @@ pub async fn run_until(
Ok((state, swarm)) Ok((state, swarm))
} else { } else {
match state { match state {
AliceState::Started { AliceState::Started { amounts, state0 } => {
amounts, let (channel, state3) = negotiate(state0, amounts, &mut swarm, config).await?;
a,
s_a,
v_a,
} => {
let (channel, state3) = negotiate(
amounts,
a,
s_a,
v_a,
&mut swarm,
bitcoin_wallet.clone(),
config,
)
.await?;
run_until( run_until(
AliceState::Negotiated { AliceState::Negotiated {

@ -16,6 +16,7 @@ use anyhow::Result;
use futures::{channel::mpsc, StreamExt}; use futures::{channel::mpsc, StreamExt};
use libp2p::Multiaddr; use libp2p::Multiaddr;
use prettytable::{row, Table}; use prettytable::{row, Table};
use rand::rngs::OsRng;
use std::{io, io::Write, process, sync::Arc}; use std::{io, io::Write, process, sync::Arc};
use structopt::StructOpt; use structopt::StructOpt;
use swap::{ use swap::{
@ -25,9 +26,10 @@ use swap::{
network::transport::{build, build_tor, SwapTransport}, network::transport::{build, build_tor, SwapTransport},
recover::recover, recover::recover,
storage::Database, storage::Database,
Cmd, Rsp, SwapAmounts, Cmd, Rsp, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
}; };
use tracing::info; use tracing::info;
use xmr_btc::{alice::State0, cross_curve_dleq};
#[macro_use] #[macro_use]
extern crate prettytable; extern crate prettytable;
@ -50,7 +52,34 @@ async fn main() -> Result<()> {
} => { } => {
info!("running swap node as Alice ..."); info!("running swap node as Alice ...");
let behaviour = alice::Behaviour::default(); let bitcoin_wallet = bitcoin::Wallet::new("alice", bitcoind_url)
.await
.expect("failed to create bitcoin wallet");
let bitcoin_wallet = Arc::new(bitcoin_wallet);
let monero_wallet = Arc::new(monero::Wallet::new(monerod_url));
let rng = &mut OsRng;
let a = bitcoin::SecretKey::new_random(rng);
let s_a = cross_curve_dleq::Scalar::random(rng);
let v_a = xmr_btc::monero::PrivateViewKey::new_random(rng);
let redeem_address = bitcoin_wallet.as_ref().new_address().await?;
let punish_address = redeem_address.clone();
let state0 = State0::new(
a,
s_a,
v_a,
// todo: get from CLI args
bitcoin::Amount::from_sat(100),
// todo: get from CLI args
monero::Amount::from_piconero(1000000),
REFUND_TIMELOCK,
PUNISH_TIMELOCK,
redeem_address,
punish_address,
);
let behaviour = alice::Behaviour::new(state0);
let local_key_pair = behaviour.identity(); let local_key_pair = behaviour.identity();
let (listen_addr, _ac, transport) = match tor_port { let (listen_addr, _ac, transport) = match tor_port {
@ -72,13 +101,6 @@ async fn main() -> Result<()> {
} }
}; };
let bitcoin_wallet = bitcoin::Wallet::new("alice", bitcoind_url)
.await
.expect("failed to create bitcoin wallet");
let bitcoin_wallet = Arc::new(bitcoin_wallet);
let monero_wallet = Arc::new(monero::Wallet::new(monerod_url));
swap_as_alice( swap_as_alice(
bitcoin_wallet, bitcoin_wallet,
monero_wallet, monero_wallet,

@ -12,7 +12,7 @@ use tempfile::tempdir;
use testcontainers::clients::Cli; use testcontainers::clients::Cli;
use tracing_subscriber::util::SubscriberInitExt as _; use tracing_subscriber::util::SubscriberInitExt as _;
use uuid::Uuid; use uuid::Uuid;
use xmr_btc::{bitcoin, config::Config, cross_curve_dleq}; use xmr_btc::{alice::State0, bitcoin, config::Config, cross_curve_dleq};
/// Run the following tests with RUST_MIN_STACK=10000000 /// Run the following tests with RUST_MIN_STACK=10000000
@ -20,7 +20,7 @@ use xmr_btc::{bitcoin, config::Config, cross_curve_dleq};
async fn happy_path() { async fn happy_path() {
use tracing_subscriber::util::SubscriberInitExt as _; use tracing_subscriber::util::SubscriberInitExt as _;
let _guard = tracing_subscriber::fmt() let _guard = tracing_subscriber::fmt()
.with_env_filter("swap=trace,xmr_btc=trace") .with_env_filter("swap=trace,xmr_btc=trace,monero_harness=info")
.with_ansi(false) .with_ansi(false)
.set_default(); .set_default();
@ -249,22 +249,38 @@ async fn init_alice(
xmr: xmr_to_swap, xmr: xmr_to_swap,
}; };
let alice_behaviour = alice::Behaviour::default(); let (alice_state, alice_behaviour) = {
let alice_peer_id = alice_behaviour.peer_id();
let alice_transport = build(alice_behaviour.identity()).unwrap();
let rng = &mut OsRng; let rng = &mut OsRng;
let alice_state = {
let a = bitcoin::SecretKey::new_random(rng); let a = bitcoin::SecretKey::new_random(rng);
let s_a = cross_curve_dleq::Scalar::random(rng); let s_a = cross_curve_dleq::Scalar::random(rng);
let v_a = xmr_btc::monero::PrivateViewKey::new_random(rng); let v_a = xmr_btc::monero::PrivateViewKey::new_random(rng);
AliceState::Started { let redeem_address = alice_btc_wallet.as_ref().new_address().await.unwrap();
amounts, let punish_address = redeem_address.clone();
let state0 = State0::new(
a, a,
s_a, s_a,
v_a, v_a,
} amounts.btc,
amounts.xmr,
REFUND_TIMELOCK,
PUNISH_TIMELOCK,
redeem_address,
punish_address,
);
// let msg0 = AliceToBob::Message0(self.state.next_message(&mut OsRng));
(
AliceState::Started {
amounts,
state0: state0.clone(),
},
alice::Behaviour::new(state0),
)
}; };
let alice_peer_id = alice_behaviour.peer_id();
let alice_transport = build(alice_behaviour.identity()).unwrap();
let (swarm_driver, handle) = let (swarm_driver, handle) =
alice::swarm_driver::SwarmDriver::new(alice_transport, alice_behaviour, listen).unwrap(); alice::swarm_driver::SwarmDriver::new(alice_transport, alice_behaviour, listen).unwrap();

Loading…
Cancel
Save