diff --git a/Cargo.lock b/Cargo.lock index 5affebc76fdeb..e9a07ab2f21fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9597,6 +9597,7 @@ dependencies = [ "futures-timer", "ip_network", "libp2p", + "libp2p-quic", "linked_hash_set", "log", "lru", diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index a974b86026116..5b09814f4cfda 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -67,6 +67,10 @@ pub struct NetworkParams { #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])] pub port: Option, + /// Enable experimental QUIC transport. + #[clap(long)] + pub experimental_quic: bool, + /// Always forbid connecting to private IPv4/IPv6 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)), unless the address was passed with /// `--reserved-nodes` or `--bootnodes`. Enabled by default for chains marked as "live" in @@ -236,6 +240,7 @@ impl NetworkParams { yamux_window_size: None, ipfs_server: self.ipfs_server, sync_mode: self.sync.into(), + experimental_quic: self.experimental_quic, } } } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index be8112327eb80..62c3c8dc9b6e6 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -26,6 +26,7 @@ futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" libp2p = { version = "0.51.3", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux", "websocket", "request-response"] } +libp2p-quic = { version = "0.7.0-alpha.3", features = ["tokio"] } linked_hash_set = "0.1.3" log = "0.4.17" lru = "0.10.0" diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 17ca8335653de..c08f20d39b13c 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -628,6 +628,9 @@ pub struct NetworkConfiguration { /// a modification of the way the implementation works. Different nodes with different /// configured values remain compatible with each other. pub yamux_window_size: Option, + /// If true, enables a possibility to accept QUIC connections. Incoming connections + /// won't be accepted unless a QUIC `Multiaddr` is passed as part of `listen_addresses`. + pub experimental_quic: bool, } impl NetworkConfiguration { @@ -658,6 +661,7 @@ impl NetworkConfiguration { kademlia_disjoint_query_paths: false, yamux_window_size: None, ipfs_server: false, + experimental_quic: false, } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 62ff5ae42466b..f2082b6509e0f 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -259,6 +259,7 @@ where config_mem, network_config.yamux_window_size, yamux_maximum_buffer_size, + network_config.experimental_quic, ) }; diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 4136b34fc0e8e..8f15ae0b2e48a 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -19,6 +19,7 @@ //! Transport that serves as a common ground for all connections. use either::Either; +use futures::future::Either as FutureEither; use libp2p::{ core::{ muxing::StreamMuxerBox, @@ -27,10 +28,19 @@ use libp2p::{ }, dns, identity, noise, tcp, websocket, PeerId, Transport, TransportExt, }; +use libp2p_quic::{self as quic, Config as QuicConfig, GenTransport as QuicTransport}; use std::{sync::Arc, time::Duration}; pub use libp2p::bandwidth::BandwidthSinks; +/// Builds the QUIC transport +fn build_quic_transport(keypair: &identity::Keypair) -> Boxed<(PeerId, quic::Connection)> { + let config = QuicConfig::new(&keypair); + let transport = QuicTransport::::new(config).boxed(); + + transport +} + /// Builds the transport that serves as a common ground for all connections. /// /// If `memory_only` is true, then only communication within the same process are allowed. Only @@ -51,6 +61,7 @@ pub fn build_transport( memory_only: bool, yamux_window_size: Option, yamux_maximum_buffer_size: usize, + enable_quic: bool, ) -> (Boxed<(PeerId, StreamMuxerBox)>, Arc) { // Build the base layer of the transport. let transport = if !memory_only { @@ -95,11 +106,25 @@ pub fn build_transport( yamux_config }; - let transport = transport + let tcp_transport = transport .upgrade(upgrade::Version::V1Lazy) .authenticate(authentication_config) .multiplex(multiplexing_config) - .timeout(Duration::from_secs(20)) + .timeout(Duration::from_secs(20)); + + let quic_transport = if enable_quic { + OptionalTransport::some(build_quic_transport(&keypair)) + } else { + OptionalTransport::none() + }; + + let transport = tcp_transport.or_transport(quic_transport); + + let transport = transport + .map(|either_output, _| match either_output { + FutureEither::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)), + FutureEither::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)), + }) .boxed(); transport.with_bandwidth_logging()