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.
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
### Fixed

@ -2,5 +2,6 @@ pub mod command;
pub mod config;
mod rate;
pub mod tracing;
pub mod transport;
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 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, bob};
use crate::seed::Seed;
use crate::{env, monero, tor};
use crate::{asb, cli, env, monero, tor};
use anyhow::Result;
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder};
use libp2p::swarm::SwarmBuilder;
use libp2p::{PeerId, Swarm};
use std::fmt::Debug;
@ -22,41 +21,19 @@ pub fn asb<LR>(
where
LR: LatestRate + Send + 'static + Debug,
{
with_clear_net(
seed,
alice::Behaviour::new(
balance,
lock_fee,
min_buy,
max_buy,
latest_rate,
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))
}
let behaviour = alice::Behaviour::new(
balance,
lock_fee,
min_buy,
max_buy,
latest_rate,
resume_only,
env_config,
);
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 transport = transport::build_clear_net(&identity)?;
let transport = asb::transport::new(&identity)?;
let peer_id = identity.public().into_peer_id();
tracing::debug!(%peer_id, "Our peer-id");
let swarm = SwarmBuilder::new(transport, behaviour, peer_id)
.executor(Box::new(|f| {
@ -67,15 +44,21 @@ where
Ok(swarm)
}
async fn with_tor<B>(seed: &Seed, behaviour: B, tor_socks5_port: u16) -> Result<Swarm<B>>
where
B: NetworkBehaviour,
{
tracing::info!("All connections will go through Tor socks5 proxy");
pub async fn cli(
seed: &Seed,
alice: PeerId,
tor_socks5_port: u16,
) -> 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 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();
tracing::debug!(%peer_id, "Our peer-id");
let swarm = SwarmBuilder::new(transport, behaviour, peer_id)
.executor(Box::new(|f| {

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