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.
This commit is contained in:
rishflab 2020-12-10 11:18:45 +11:00
parent 3d8866f1a0
commit 27d1334726
6 changed files with 114 additions and 133 deletions

View File

@ -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

View File

@ -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)?;

View File

@ -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");

View File

@ -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 {

View File

@ -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,

View File

@ -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();