Extract transport creation and remove tor conditional compile

The numerous tor conditional compile flags were removed by
extracting transport creation to the main statement. A tor
transport is created if Alice specifies a tor port using the CLI.
This commit is contained in:
rishflab 2020-10-29 22:18:59 +11:00
parent 0ca511bf8a
commit 796d0b3439
7 changed files with 101 additions and 128 deletions

View File

@ -32,7 +32,8 @@ structopt = "0.3"
tempfile = "3" tempfile = "3"
time = "0.2" time = "0.2"
tokio = { version = "0.2", features = ["rt-threaded", "time", "macros", "sync"] } tokio = { version = "0.2", features = ["rt-threaded", "time", "macros", "sync"] }
torut = { version = "0.1", optional = true } #torut = { version = "0.1", optional = true }
torut = { version = "0.1"}
tracing = { version = "0.1", features = ["attributes"] } tracing = { version = "0.1", features = ["attributes"] }
tracing-core = "0.1" tracing-core = "0.1"
tracing-futures = { version = "0.2", features = ["std-future", "futures-03"] } tracing-futures = { version = "0.2", features = ["std-future", "futures-03"] }
@ -49,6 +50,6 @@ spectral = "0.6"
tempfile = "3" tempfile = "3"
testcontainers = "0.10" testcontainers = "0.10"
[features] #[features]
default = [] #default = []
tor = ["torut"] #tor = ["torut"]

View File

@ -28,7 +28,9 @@ use crate::{
network::{ network::{
peer_tracker::{self, PeerTracker}, peer_tracker::{self, PeerTracker},
request_response::AliceToBob, request_response::AliceToBob,
transport, TokioExecutor, transport,
transport::SwapTransport,
TokioExecutor,
}, },
SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
}; };
@ -43,7 +45,10 @@ pub async fn swap(
bitcoin_wallet: Arc<bitcoin::Wallet>, bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>, monero_wallet: Arc<monero::Wallet>,
listen: Multiaddr, listen: Multiaddr,
local_port: Option<u16>, redeem_address: ::bitcoin::Address,
punish_address: ::bitcoin::Address,
transport: SwapTransport,
behaviour: Alice,
) -> Result<()> { ) -> Result<()> {
struct Network { struct Network {
swarm: Arc<Mutex<Swarm>>, swarm: Arc<Mutex<Swarm>>,
@ -96,7 +101,7 @@ pub async fn swap(
} }
} }
let mut swarm = new_swarm(listen, local_port)?; let mut swarm = new_swarm(listen, transport, behaviour)?;
let message0: bob::Message0; let message0: bob::Message0;
let mut state0: Option<alice::State0> = None; let mut state0: Option<alice::State0> = None;
let mut last_amounts: Option<SwapAmounts> = None; let mut last_amounts: Option<SwapAmounts> = None;
@ -230,30 +235,11 @@ pub async fn swap(
pub type Swarm = libp2p::Swarm<Alice>; pub type Swarm = libp2p::Swarm<Alice>;
fn new_swarm(listen: Multiaddr, port: Option<u16>) -> Result<Swarm> { fn new_swarm(listen: Multiaddr, transport: SwapTransport, behaviour: Alice) -> Result<Swarm> {
use anyhow::Context as _; use anyhow::Context as _;
let behaviour = Alice::default();
let local_key_pair = behaviour.identity();
let local_peer_id = behaviour.peer_id(); let local_peer_id = behaviour.peer_id();
let transport;
#[cfg(feature = "tor")]
{
transport = match port {
Some(port) => transport::build(local_key_pair, Some((listen.clone(), port)))?,
None => anyhow::bail!("Must supply local port"),
};
}
#[cfg(not(feature = "tor"))]
{
transport = match port {
None => transport::build(local_key_pair)?,
Some(_) => anyhow::bail!("local port should not be provided for non-tor usage"),
};
}
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone()) let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
.executor(Box::new(TokioExecutor { .executor(Box::new(TokioExecutor {
handle: tokio::runtime::Handle::current(), handle: tokio::runtime::Handle::current(),

View File

@ -27,7 +27,9 @@ use crate::{
monero, monero,
network::{ network::{
peer_tracker::{self, PeerTracker}, peer_tracker::{self, PeerTracker},
transport, TokioExecutor, transport,
transport::SwapTransport,
TokioExecutor,
}, },
Cmd, Rsp, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK, Cmd, Rsp, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
}; };
@ -45,6 +47,8 @@ pub async fn swap(
addr: Multiaddr, addr: Multiaddr,
mut cmd_tx: Sender<Cmd>, mut cmd_tx: Sender<Cmd>,
mut rsp_rx: Receiver<Rsp>, mut rsp_rx: Receiver<Rsp>,
transport: SwapTransport,
behaviour: Bob,
) -> Result<()> { ) -> Result<()> {
struct Network(Swarm); struct Network(Swarm);
@ -80,7 +84,7 @@ pub async fn swap(
} }
} }
let mut swarm = new_swarm()?; let mut swarm = new_swarm(transport, behaviour)?;
libp2p::Swarm::dial_addr(&mut swarm, addr)?; libp2p::Swarm::dial_addr(&mut swarm, addr)?;
let alice = match swarm.next().await { let alice = match swarm.next().await {
@ -202,23 +206,9 @@ pub async fn swap(
pub type Swarm = libp2p::Swarm<Bob>; pub type Swarm = libp2p::Swarm<Bob>;
fn new_swarm() -> Result<Swarm> { fn new_swarm(transport: SwapTransport, behaviour: Bob) -> Result<Swarm> {
let behaviour = Bob::default();
let local_key_pair = behaviour.identity();
let local_peer_id = behaviour.peer_id(); let local_peer_id = behaviour.peer_id();
let transport = {
#[cfg(feature = "tor")]
{
transport::build(local_key_pair, None)?
}
#[cfg(not(feature = "tor"))]
{
transport::build(local_key_pair)?
}
};
let swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone()) let swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
.executor(Box::new(TokioExecutor { .executor(Box::new(TokioExecutor {
handle: tokio::runtime::Handle::current(), handle: tokio::runtime::Handle::current(),

View File

@ -4,41 +4,32 @@ use url::Url;
#[derive(structopt::StructOpt, Debug)] #[derive(structopt::StructOpt, Debug)]
pub enum Options { pub enum Options {
Alice { Alice {
/// Run the swap as Bob and try to swap this many BTC (in satoshi).
#[structopt(long = "sats")]
satoshis: u64,
// /// Run the swap as Bob and try to swap this many XMR (in piconero). // /// Run the swap as Bob and try to swap this many XMR (in piconero).
// #[structopt(long = "picos", conflicts_with = "sats"))] // #[structopt(long = "picos", conflicts_with = "sats"))]
// pub piconeros: u64, // pub piconeros: u64,
#[structopt(default_value = "http://127.0.0.1:8332", long = "bitcoind")] #[structopt(default_value = "http://127.0.0.1:8332", long = "bitcoind")]
bitcoind_url: Url, bitcoind_url: Url,
#[structopt(default_value = "127.0.0.1", long = "listen_addr")] #[structopt(default_value = "/ip4/127.0.0.1/tcp/9876", long = "listen-addr")]
listen_addr: String, listen_addr: Multiaddr,
#[structopt(default_value = 9876, long = "list_port")] /// Run the swap as Bob and try to swap this many BTC (in satoshi).
listen_port: u16, // #[cfg(feature = "tor")]
#[structopt(long = "tor-port")]
tor_port: Option<u16>,
}, },
Bob { Bob {
/// Alice's multitaddr (only required for Bob, Alice will autogenerate
/// one)
#[structopt(long = "alice_addr")]
alice_addr: Multiaddr,
/// Run the swap as Bob and try to swap this many BTC (in satoshi). /// Run the swap as Bob and try to swap this many BTC (in satoshi).
#[structopt(long = "sats")] #[structopt(long = "sats")]
satoshis: u64, satoshis: u64,
#[structopt(long = "alice-addr")]
alice_addr: Multiaddr,
// /// Run the swap as Bob and try to swap this many XMR (in piconero). // /// Run the swap as Bob and try to swap this many XMR (in piconero).
// #[structopt(long = "picos", conflicts_with = "sats"))] // #[structopt(long = "picos", conflicts_with = "sats"))]
// pub piconeros: u64, // pub piconeros: u64,
#[structopt(default_value = "http://127.0.0.1:8332", long = "bitcoind")] #[structopt(default_value = "http://127.0.0.1:8332", long = "bitcoind")]
bitcoind_url: Url, bitcoind_url: Url,
// #[structopt(default_value = "/ip4/127.0.0.1/tcp/9876", long = "dial")]
// alice_addr: String,
#[cfg(feature = "tor")]
#[structopt(long = "tor")]
tor_port: u16,
}, },
} }

View File

@ -7,7 +7,7 @@ pub mod bob;
pub mod monero; pub mod monero;
pub mod network; pub mod network;
pub mod storage; pub mod storage;
#[cfg(feature = "tor")] //#[cfg(feature = "tor")]
pub mod tor; pub mod tor;
const REFUND_TIMELOCK: u32 = 10; // Relative timelock, this is number of blocks. TODO: What should it be? const REFUND_TIMELOCK: u32 = 10; // Relative timelock, this is number of blocks. TODO: What should it be?

View File

@ -12,14 +12,24 @@
)] )]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use anyhow::{bail, Context, Result}; use anyhow::Result;
use futures::{channel::mpsc, StreamExt}; use futures::{channel::mpsc, StreamExt};
use libp2p::core::Multiaddr; use libp2p::core::Multiaddr;
use log::LevelFilter; use log::LevelFilter;
use std::{io, io::Write, process, sync::Arc}; use std::{io, io::Write, process, sync::Arc};
use structopt::StructOpt; use structopt::StructOpt;
use swap::{
alice,
alice::Alice,
bitcoin::Wallet,
bob,
bob::Bob,
network::transport::{build, build_tor, SwapTransport},
Cmd, Rsp, SwapAmounts,
};
use tracing::info; use tracing::info;
use url::Url; use url::Url;
use xmr_btc::bitcoin::{BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock};
mod cli; mod cli;
mod trace; mod trace;
@ -29,15 +39,6 @@ use swap::{alice, bitcoin, bob, monero, Cmd, Rsp, SwapAmounts};
// TODO: Add root seed file instead of generating new seed each run. // TODO: Add root seed file instead of generating new seed each run.
// // TODO: Add a config file with these in it.
// // Alice's address and port until we have a config file.
// pub const LISTEN_PORT: u16 = 9876; // Arbitrarily chosen.
// pub const LISTEN_ADDR: &str = "127.0.0.1";
// pub const BITCOIND_JSON_RPC_URL: &str = "http://127.0.0.1:8332";
//
// #[cfg(feature = "tor")]
// pub const TOR_PORT: u16 = LISTEN_PORT + 1;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let opt: Options = Options::from_args(); let opt: Options = Options::from_args();
@ -48,29 +49,31 @@ async fn main() -> Result<()> {
Options::Alice { Options::Alice {
bitcoind_url: url, bitcoind_url: url,
listen_addr, listen_addr,
listen_port, tor_port,
.. ..
} => { } => {
info!("running swap node as Alice ..."); info!("running swap node as Alice ...");
#[cfg(feature = "tor")] let behaviour = Alice::default();
let (alice, _ac) = { let local_key_pair = behaviour.identity();
let tor_secret_key = torut::onion::TorSecretKeyV3::generate();
let onion_address = tor_secret_key
.public()
.get_onion_address()
.get_address_without_dot_onion();
let onion_address_string = format!("/onion3/{}:{}", onion_address, TOR_PORT);
let addr: Multiaddr = onion_address_string.parse()?;
(addr, create_tor_service(tor_secret_key).await?) let (listen_addr, ac, transport) = match tor_port {
}; Some(tor_port) => {
let tor_secret_key = torut::onion::TorSecretKeyV3::generate();
#[cfg(not(feature = "tor"))] let onion_address = tor_secret_key
let alice = { .public()
let alice: Multiaddr = listen_addr .get_onion_address()
.parse() .get_address_without_dot_onion();
.expect("failed to parse Alice's address"); let onion_address_string = format!("/onion3/{}:{}", onion_address, tor_port);
let addr: Multiaddr = onion_address_string.parse()?;
let ac = create_tor_service(tor_secret_key, tor_port).await?;
let transport = build_tor(local_key_pair, addr.clone(), tor_port)?;
(addr, Some(ac), transport)
}
None => {
let transport = build(local_key_pair)?;
(listen_addr, None, transport)
}
}; };
let bitcoin_wallet = bitcoin::Wallet::new("alice", &url) let bitcoin_wallet = bitcoin::Wallet::new("alice", &url)
@ -80,31 +83,44 @@ async fn main() -> Result<()> {
let monero_wallet = Arc::new(monero::Wallet::localhost(MONERO_WALLET_RPC_PORT)); let monero_wallet = Arc::new(monero::Wallet::localhost(MONERO_WALLET_RPC_PORT));
swap_as_alice(bitcoin_wallet, monero_wallet, alice.clone()).await?; swap_as_alice(listen_addr, redeem, punish, transport, behaviour).await?;
} }
Options::Bob { Options::Bob {
alice_addr: alice_address, alice_addr,
satoshis, satoshis,
bitcoind_url: url, bitcoind_url: url,
} => { } => {
info!("running swap node as Bob ..."); info!("running swap node as Bob ...");
let behaviour = Bob::default();
let local_key_pair = behaviour.identity();
let transport = build(local_key_pair)?;
let bitcoin_wallet = Wallet::new("bob", &url) let bitcoin_wallet = Wallet::new("bob", &url)
.await .await
.expect("failed to create bitcoin wallet"); .expect("failed to create bitcoin wallet");
let monero_wallet = Arc::new(monero::Wallet::localhost(MONERO_WALLET_RPC_PORT)); let monero_wallet = Arc::new(monero::Wallet::localhost(MONERO_WALLET_RPC_PORT));
swap_as_bob(satoshis, alice_address, refund, bitcoin_wallet).await?; swap_as_bob(
satoshis,
alice_addr,
refund,
bitcoin_wallet,
transport,
behaviour,
)
.await?;
} }
} }
Ok(()) Ok(())
} }
#[cfg(feature = "tor")]
async fn create_tor_service( async fn create_tor_service(
tor_secret_key: torut::onion::TorSecretKeyV3, tor_secret_key: torut::onion::TorSecretKeyV3,
tor_port: u16,
) -> Result<swap::tor::AuthenticatedConnection> { ) -> Result<swap::tor::AuthenticatedConnection> {
// TODO use configurable ports for tor connection // TODO use configurable ports for tor connection
let mut authenticated_connection = swap::tor::UnauthenticatedConnection::default() let mut authenticated_connection = swap::tor::UnauthenticatedConnection::default()
@ -113,7 +129,7 @@ async fn create_tor_service(
tracing::info!("Tor authenticated."); tracing::info!("Tor authenticated.");
authenticated_connection authenticated_connection
.add_service(TOR_PORT, &tor_secret_key) .add_service(tor_port, &tor_secret_key)
.await?; .await?;
tracing::info!("Tor service added."); tracing::info!("Tor service added.");
@ -124,15 +140,12 @@ async fn swap_as_alice(
bitcoin_wallet: Arc<swap::bitcoin::Wallet>, bitcoin_wallet: Arc<swap::bitcoin::Wallet>,
monero_wallet: Arc<swap::monero::Wallet>, monero_wallet: Arc<swap::monero::Wallet>,
addr: Multiaddr, addr: Multiaddr,
redeem: bitcoin::Address,
punish: bitcoin::Address,
transport: SwapTransport,
behaviour: Alice,
) -> Result<()> { ) -> Result<()> {
#[cfg(not(feature = "tor"))] alice::swap(addr, redeem, punish, transport, behaviour).await
{
alice::swap(bitcoin_wallet, monero_wallet, addr, None).await
}
#[cfg(feature = "tor")]
{
alice::swap(bitcoin_wallet, monero_wallet, addr, Some(LISTEN_PORT)).await
}
} }
async fn swap_as_bob( async fn swap_as_bob(
@ -140,16 +153,18 @@ async fn swap_as_bob(
monero_wallet: Arc<swap::monero::Wallet>, monero_wallet: Arc<swap::monero::Wallet>,
sats: u64, sats: u64,
alice: Multiaddr, alice: Multiaddr,
) -> Result<()> { refund: bitcoin::Address,
wallet: W,
transport: SwapTransport,
behaviour: Bob,
) -> Result<()>
where
W: BuildTxLockPsbt + SignTxLock + BroadcastSignedTransaction + Send + Sync + 'static,
{
let (cmd_tx, mut cmd_rx) = mpsc::channel(1); let (cmd_tx, mut cmd_rx) = mpsc::channel(1);
let (mut rsp_tx, rsp_rx) = mpsc::channel(1); let (mut rsp_tx, rsp_rx) = mpsc::channel(1);
tokio::spawn(bob::swap( tokio::spawn(bob::swap(
bitcoin_wallet, sats, alice, cmd_tx, rsp_rx, refund, wallet, transport, behaviour,
monero_wallet,
sats,
alice,
cmd_tx,
rsp_rx,
)); ));
loop { loop {
@ -201,10 +216,3 @@ fn verify(amounts: SwapAmounts) -> Rsp {
fn is_yes(s: &str) -> bool { fn is_yes(s: &str) -> bool {
matches!(s, "y" | "Y" | "yes" | "YES" | "Yes") matches!(s, "y" | "Y" | "yes" | "YES" | "Yes")
} }
fn multiaddr(s: &str) -> Result<Multiaddr> {
let addr = s
.parse()
.with_context(|| format!("failed to parse multiaddr: {}", s))?;
Ok(addr)
}

View File

@ -5,7 +5,7 @@ use libp2p::{
muxing::StreamMuxerBox, muxing::StreamMuxerBox,
transport::Boxed, transport::Boxed,
upgrade::{SelectUpgrade, Version}, upgrade::{SelectUpgrade, Version},
Transport, Multiaddr, Transport,
}, },
dns::DnsConfig, dns::DnsConfig,
mplex::MplexConfig, mplex::MplexConfig,
@ -18,7 +18,7 @@ use libp2p::{
/// - DNS name resolution /// - DNS name resolution
/// - authentication via noise /// - authentication via noise
/// - multiplexing via yamux or mplex /// - multiplexing via yamux or mplex
#[cfg(not(feature = "tor"))] /// #[cfg(not(feature = "tor"))]
pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> { pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
use libp2p::tcp::TokioTcpConfig; use libp2p::tcp::TokioTcpConfig;
@ -40,24 +40,21 @@ pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
Ok(transport) Ok(transport)
} }
/// Builds a libp2p transport with Tor and with the following features: /// Builds a libp2p transport with Tor and with the following features:
/// - TCP connection over the Tor network /// - TCP connection over the Tor network
/// - DNS name resolution /// - DNS name resolution
/// - authentication via noise /// - authentication via noise
/// - multiplexing via yamux or mplex /// - multiplexing via yamux or mplex
#[cfg(feature = "tor")] // #[cfg(feature = "tor")]
pub fn build( pub fn build_tor(
id_keys: identity::Keypair, id_keys: identity::Keypair,
address_port_pair: Option<(libp2p::core::Multiaddr, u16)>, addr: libp2p::core::Multiaddr,
port: u16,
) -> Result<SwapTransport> { ) -> Result<SwapTransport> {
use libp2p_tokio_socks5::Socks5TokioTcpConfig; use libp2p_tokio_socks5::Socks5TokioTcpConfig;
use std::collections::HashMap; use std::collections::HashMap;
let mut map = HashMap::new(); let map: HashMap<Multiaddr, u16> = [(addr, port)].iter().cloned().collect();
if let Some((addr, port)) = address_port_pair {
map.insert(addr, port);
}
let dh_keys = noise::Keypair::<X25519Spec>::new().into_authentic(&id_keys)?; let dh_keys = noise::Keypair::<X25519Spec>::new().into_authentic(&id_keys)?;
let noise = NoiseConfig::xx(dh_keys).into_authenticated(); let noise = NoiseConfig::xx(dh_keys).into_authenticated();