Refactor transports to construct them specific for each application

Instead of splitting up the transports into capabilities, we compose
them directly for each application. This allows us to remove the
websocket transport for the CLI which is really only needed for the
ASB to allow retrieval of quotes via the browser.
pull/558/head
Thomas Eizinger 3 years ago
parent 90deb6451c
commit 8a30ef725c
No known key found for this signature in database
GPG Key ID: 651AC83A6C6C8B96

@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Printing the deposit address to the terminal as a QR code. - Printing the deposit address to the terminal as a QR code.
To not break automated scripts or integrations with other software, this behaviour is disabled if `--json` is passed to the application. To not break automated scripts or integrations with other software, this behaviour is disabled if `--json` is passed to the application.
### Removed
- The websocket transport from the CLI.
Websockets were only ever intended to be used for the ASB side to allow websites to retrieve quotes.
The CLI can use regular TCP connections and having both - TCP and websockets - causes problems and unnecessary overhead.
## [0.7.0] - 2021-05-28 ## [0.7.0] - 2021-05-28
### Fixed ### Fixed

@ -2,5 +2,6 @@ pub mod command;
pub mod config; pub mod config;
mod rate; mod rate;
pub mod tracing; pub mod tracing;
pub mod transport;
pub use rate::Rate; pub use rate::Rate;

@ -0,0 +1,19 @@
use crate::network::transport::authenticate_and_multiplex;
use anyhow::Result;
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::Boxed;
use libp2p::dns::TokioDnsConfig;
use libp2p::tcp::TokioTcpConfig;
use libp2p::websocket::WsConfig;
use libp2p::{identity, PeerId, Transport};
/// Creates the libp2p transport for the ASB.
pub fn new(identity: &identity::Keypair) -> Result<Boxed<(PeerId, StreamMuxerBox)>> {
let tcp = TokioTcpConfig::new().nodelay(true);
let tcp_with_dns = TokioDnsConfig::system(tcp)?;
let websocket_with_dns = WsConfig::new(tcp_with_dns.clone());
let transport = tcp_with_dns.or_transport(websocket_with_dns).boxed();
authenticate_and_multiplex(transport, identity)
}

@ -1,2 +1,3 @@
pub mod command; pub mod command;
pub mod tracing; pub mod tracing;
pub mod transport;

@ -0,0 +1,32 @@
use crate::network::tor_transport::TorDialOnlyTransport;
use crate::network::transport::authenticate_and_multiplex;
use anyhow::Result;
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::{Boxed, OptionalTransport};
use libp2p::dns::TokioDnsConfig;
use libp2p::tcp::TokioTcpConfig;
use libp2p::{identity, PeerId, Transport};
/// Creates the libp2p transport for the swap CLI.
///
/// The CLI's transport needs the following capabilities:
/// - Establish TCP connections
/// - Resolve DNS entries
/// - Dial onion-addresses through a running Tor daemon by connecting to the
/// socks5 port. If the port is not given, we will fall back to the regular
/// TCP transport.
pub fn new(
identity: &identity::Keypair,
maybe_tor_socks5_port: Option<u16>,
) -> Result<Boxed<(PeerId, StreamMuxerBox)>> {
let tcp = TokioTcpConfig::new().nodelay(true);
let tcp_with_dns = TokioDnsConfig::system(tcp)?;
let maybe_tor_transport = match maybe_tor_socks5_port {
Some(port) => OptionalTransport::some(TorDialOnlyTransport::new(port)),
None => OptionalTransport::none(),
};
let transport = maybe_tor_transport.or_transport(tcp_with_dns).boxed();
authenticate_and_multiplex(transport, identity)
}

@ -1,10 +1,9 @@
use crate::network::transport;
use crate::protocol::alice::event_loop::LatestRate; use crate::protocol::alice::event_loop::LatestRate;
use crate::protocol::{alice, bob}; use crate::protocol::{alice, bob};
use crate::seed::Seed; use crate::seed::Seed;
use crate::{env, monero, tor}; use crate::{asb, cli, env, monero, tor};
use anyhow::Result; use anyhow::Result;
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder}; use libp2p::swarm::SwarmBuilder;
use libp2p::{PeerId, Swarm}; use libp2p::{PeerId, Swarm};
use std::fmt::Debug; use std::fmt::Debug;
@ -22,41 +21,19 @@ pub fn asb<LR>(
where where
LR: LatestRate + Send + 'static + Debug, LR: LatestRate + Send + 'static + Debug,
{ {
with_clear_net( let behaviour = alice::Behaviour::new(
seed, balance,
alice::Behaviour::new( lock_fee,
balance, min_buy,
lock_fee, max_buy,
min_buy, latest_rate,
max_buy, resume_only,
latest_rate, env_config,
resume_only, );
env_config,
),
)
}
pub async fn cli(
seed: &Seed,
alice: PeerId,
tor_socks5_port: u16,
) -> Result<Swarm<bob::Behaviour>> {
let client = tor::Client::new(tor_socks5_port);
if client.assert_tor_running().await.is_ok() {
return with_tor(seed, bob::Behaviour::new(alice), tor_socks5_port).await;
}
with_clear_net(seed, bob::Behaviour::new(alice))
}
fn with_clear_net<B>(seed: &Seed, behaviour: B) -> Result<Swarm<B>>
where
B: NetworkBehaviour,
{
tracing::info!("All connections will go through clear net");
let identity = seed.derive_libp2p_identity(); let identity = seed.derive_libp2p_identity();
let transport = transport::build_clear_net(&identity)?; let transport = asb::transport::new(&identity)?;
let peer_id = identity.public().into_peer_id(); let peer_id = identity.public().into_peer_id();
tracing::debug!(%peer_id, "Our peer-id");
let swarm = SwarmBuilder::new(transport, behaviour, peer_id) let swarm = SwarmBuilder::new(transport, behaviour, peer_id)
.executor(Box::new(|f| { .executor(Box::new(|f| {
@ -67,15 +44,21 @@ where
Ok(swarm) Ok(swarm)
} }
async fn with_tor<B>(seed: &Seed, behaviour: B, tor_socks5_port: u16) -> Result<Swarm<B>> pub async fn cli(
where seed: &Seed,
B: NetworkBehaviour, alice: PeerId,
{ tor_socks5_port: u16,
tracing::info!("All connections will go through Tor socks5 proxy"); ) -> Result<Swarm<bob::Behaviour>> {
let maybe_tor_socks5_port = match tor::Client::new(tor_socks5_port).assert_tor_running().await {
Ok(()) => Some(tor_socks5_port),
Err(_) => None,
};
let behaviour = bob::Behaviour::new(alice);
let identity = seed.derive_libp2p_identity(); let identity = seed.derive_libp2p_identity();
let transport = transport::build_tor(&identity, tor_socks5_port)?; let transport = cli::transport::new(&identity, maybe_tor_socks5_port)?;
let peer_id = identity.public().into_peer_id(); let peer_id = identity.public().into_peer_id();
tracing::debug!(%peer_id, "Our peer-id");
let swarm = SwarmBuilder::new(transport, behaviour, peer_id) let swarm = SwarmBuilder::new(transport, behaviour, peer_id)
.executor(Box::new(|f| { .executor(Box::new(|f| {

@ -1,74 +1,39 @@
use crate::network::tor_transport::TorDialOnlyTransport;
use anyhow::Result; use anyhow::Result;
use futures::{AsyncRead, AsyncWrite};
use libp2p::core::muxing::StreamMuxerBox; use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::Boxed; use libp2p::core::transport::Boxed;
use libp2p::core::upgrade::{SelectUpgrade, Version}; use libp2p::core::upgrade::{SelectUpgrade, Version};
use libp2p::dns::TokioDnsConfig;
use libp2p::mplex::MplexConfig; use libp2p::mplex::MplexConfig;
use libp2p::noise::{self, NoiseConfig, X25519Spec}; use libp2p::noise::{self, NoiseConfig, X25519Spec};
use libp2p::tcp::TokioTcpConfig;
use libp2p::websocket::WsConfig;
use libp2p::{identity, yamux, PeerId, Transport}; use libp2p::{identity, yamux, PeerId, Transport};
use std::time::Duration; use std::time::Duration;
/// Builds a libp2p transport with the following features: /// "Completes" a transport by applying the authentication and multiplexing
/// - TcpConnection /// upgrades.
/// - WebSocketConnection ///
/// - DNS name resolution /// Even though the actual transport technology in use might be different, for
/// - authentication via noise /// two libp2p applications to be compatible, the authentication and
/// - multiplexing via yamux or mplex /// multiplexing upgrades need to be compatible.
pub fn build_clear_net(id_keys: &identity::Keypair) -> Result<SwapTransport> { pub fn authenticate_and_multiplex<T>(
let dh_keys = noise::Keypair::<X25519Spec>::new().into_authentic(id_keys)?; transport: Boxed<T>,
let noise = NoiseConfig::xx(dh_keys).into_authenticated(); identity: &identity::Keypair,
) -> Result<Boxed<(PeerId, StreamMuxerBox)>>
let tcp = TokioTcpConfig::new().nodelay(true); where
let dns = TokioDnsConfig::system(tcp)?; T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
let websocket = WsConfig::new(dns.clone()); {
let auth_upgrade = {
let transport = websocket let noise_identity = noise::Keypair::<X25519Spec>::new().into_authentic(identity)?;
.or_transport(dns) NoiseConfig::xx(noise_identity).into_authenticated()
};
let multiplex_upgrade = SelectUpgrade::new(yamux::YamuxConfig::default(), MplexConfig::new());
let transport = transport
.upgrade(Version::V1) .upgrade(Version::V1)
.authenticate(noise) .authenticate(auth_upgrade)
.multiplex(SelectUpgrade::new( .multiplex(multiplex_upgrade)
yamux::YamuxConfig::default(),
MplexConfig::new(),
))
.timeout(Duration::from_secs(20)) .timeout(Duration::from_secs(20))
.map(|(peer, muxer), _| (peer, StreamMuxerBox::new(muxer))) .map(|(peer, muxer), _| (peer, StreamMuxerBox::new(muxer)))
.boxed(); .boxed();
Ok(transport) Ok(transport)
} }
/// Builds a libp2p transport with the following features:
/// - TorTcpConnection
/// - WebSocketConnection
/// - DNS name resolution
/// - authentication via noise
/// - multiplexing via yamux or mplex
pub fn build_tor(id_keys: &identity::Keypair, tor_socks5_port: u16) -> Result<SwapTransport> {
let dh_keys = noise::Keypair::<X25519Spec>::new().into_authentic(id_keys)?;
let noise = NoiseConfig::xx(dh_keys).into_authenticated();
let tcp = TokioTcpConfig::new().nodelay(true);
let tcp_with_dns = TokioDnsConfig::system(tcp)?;
let websocket_with_dns = WsConfig::new(tcp_with_dns.clone());
let tor_dial_only = TorDialOnlyTransport::new(tor_socks5_port);
let transport = tor_dial_only
.or_transport(tcp_with_dns)
.or_transport(websocket_with_dns)
.upgrade(Version::V1)
.authenticate(noise)
.multiplex(SelectUpgrade::new(
yamux::YamuxConfig::default(),
MplexConfig::new(),
))
.timeout(Duration::from_secs(20))
.map(|(peer, muxer), _| (peer, StreamMuxerBox::new(muxer)))
.boxed();
Ok(transport)
}
pub type SwapTransport = Boxed<(PeerId, StreamMuxerBox)>;

Loading…
Cancel
Save