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,
);
info!("Commencing handshake");
swarm.set_state0(state.clone());
state0 = Some(state)
}
OutEvent::Message0(msg) => {
@ -387,6 +384,20 @@ pub struct 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 {
self.identity.clone()
}
@ -402,13 +413,6 @@ impl Behaviour {
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.
pub fn send_message1(
&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 {
// TODO (Franck): This should instead verify that the received amounts matches
// the command line arguments This value corresponds to 100 XMR per BTC

@ -1,6 +1,6 @@
use crate::{
alice::swarm_driver::SwarmDriverHandle, bitcoin, monero, network::request_response::AliceToBob,
SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
SwapAmounts,
};
use anyhow::{bail, Context, Result};
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic};
@ -9,13 +9,14 @@ use futures::{
pin_mut,
};
use libp2p::request_response::ResponseChannel;
use sha2::Sha256;
use std::{sync::Arc, time::Duration};
use tokio::time::timeout;
use tracing::trace;
use xmr_btc::{
alice,
alice::{State0, State3},
alice::State3,
bitcoin::{
poll_until_block_height_is_gte, BlockHeight, BroadcastSignedTransaction,
EncryptedSignature, GetRawTransaction, TransactionBlockHeight, TxCancel, TxLock, TxRefund,
@ -27,20 +28,23 @@ use xmr_btc::{
};
pub async fn negotiate(
state0: xmr_btc::alice::State0,
amounts: SwapAmounts,
a: bitcoin::SecretKey,
s_a: cross_curve_dleq::Scalar,
v_a: monero::PrivateViewKey,
swarm: &mut SwarmDriverHandle,
bitcoin_wallet: Arc<bitcoin::Wallet>,
// a: bitcoin::SecretKey,
// s_a: cross_curve_dleq::Scalar,
// v_a: monero::PrivateViewKey,
swarm_handle: &mut SwarmDriverHandle,
// bitcoin_wallet: Arc<bitcoin::Wallet>,
config: Config,
) -> Result<(ResponseChannel<AliceToBob>, State3)> {
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
.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
.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 (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);
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)?;

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

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

@ -16,6 +16,7 @@ use anyhow::Result;
use futures::{channel::mpsc, StreamExt};
use libp2p::Multiaddr;
use prettytable::{row, Table};
use rand::rngs::OsRng;
use std::{io, io::Write, process, sync::Arc};
use structopt::StructOpt;
use swap::{
@ -25,9 +26,10 @@ use swap::{
network::transport::{build, build_tor, SwapTransport},
recover::recover,
storage::Database,
Cmd, Rsp, SwapAmounts,
Cmd, Rsp, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
};
use tracing::info;
use xmr_btc::{alice::State0, cross_curve_dleq};
#[macro_use]
extern crate prettytable;
@ -50,7 +52,34 @@ async fn main() -> Result<()> {
} => {
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 (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(
bitcoin_wallet,
monero_wallet,

@ -12,7 +12,7 @@ use tempfile::tempdir;
use testcontainers::clients::Cli;
use tracing_subscriber::util::SubscriberInitExt as _;
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
@ -20,7 +20,7 @@ use xmr_btc::{bitcoin, config::Config, cross_curve_dleq};
async fn happy_path() {
use tracing_subscriber::util::SubscriberInitExt as _;
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)
.set_default();
@ -249,22 +249,38 @@ async fn init_alice(
xmr: xmr_to_swap,
};
let alice_behaviour = alice::Behaviour::default();
let alice_peer_id = alice_behaviour.peer_id();
let alice_transport = build(alice_behaviour.identity()).unwrap();
let rng = &mut OsRng;
let alice_state = {
let (alice_state, alice_behaviour) = {
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);
AliceState::Started {
amounts,
let redeem_address = alice_btc_wallet.as_ref().new_address().await.unwrap();
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,
);
// 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) =
alice::swarm_driver::SwarmDriver::new(alice_transport, alice_behaviour, listen).unwrap();

Loading…
Cancel
Save