Skip to content

Commit 2941036

Browse files
AgeManningjxs
andcommitted
Add Experimental QUIC support (#4577)
## Issue Addressed #4402 ## Proposed Changes This PR adds QUIC support to Lighthouse. As this is not officially spec'd this will only work between lighthouse <-> lighthouse connections. We attempt a QUIC connection (if the node advertises it) and if it fails we fallback to TCP. This should be a backwards compatible modification. We want to test this functionality on live networks to observe any improvements in bandwidth/latency. NOTE: This also removes the websockets transport as I believe no one is really using it. It should be mentioned in our release however. Co-authored-by: João Oliveira <[email protected]>
1 parent 35f47f4 commit 2941036

File tree

35 files changed

+1157
-752
lines changed

35 files changed

+1157
-752
lines changed

Cargo.lock

Lines changed: 144 additions & 207 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

beacon_node/client/src/lib.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,6 @@ impl<T: BeaconChainTypes> Client<T> {
4646
self.http_metrics_listen_addr
4747
}
4848

49-
/// Returns the ipv4 port of the client's libp2p stack, if it was started.
50-
pub fn libp2p_listen_ipv4_port(&self) -> Option<u16> {
51-
self.network_globals
52-
.as_ref()
53-
.and_then(|n| n.listen_port_tcp4())
54-
}
55-
56-
/// Returns the ipv6 port of the client's libp2p stack, if it was started.
57-
pub fn libp2p_listen_ipv6_port(&self) -> Option<u16> {
58-
self.network_globals
59-
.as_ref()
60-
.and_then(|n| n.listen_port_tcp6())
61-
}
62-
6349
/// Returns the list of libp2p addresses the client is listening to.
6450
pub fn libp2p_listen_addresses(&self) -> Option<Vec<Multiaddr>> {
6551
self.network_globals.as_ref().map(|n| n.listen_multiaddrs())

beacon_node/http_api/src/lib.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,12 +2825,8 @@ pub fn serve<T: BeaconChainTypes>(
28252825
})?;
28262826

28272827
if let Some(peer_info) = network_globals.peers.read().peer_info(&peer_id) {
2828-
let address = if let Some(socket_addr) = peer_info.seen_addresses().next() {
2829-
let mut addr = lighthouse_network::Multiaddr::from(socket_addr.ip());
2830-
addr.push(lighthouse_network::multiaddr::Protocol::Tcp(
2831-
socket_addr.port(),
2832-
));
2833-
addr.to_string()
2828+
let address = if let Some(multiaddr) = peer_info.seen_multiaddrs().next() {
2829+
multiaddr.to_string()
28342830
} else if let Some(addr) = peer_info.listening_addresses().first() {
28352831
addr.to_string()
28362832
} else {
@@ -2878,13 +2874,8 @@ pub fn serve<T: BeaconChainTypes>(
28782874
.peers()
28792875
.for_each(|(peer_id, peer_info)| {
28802876
let address =
2881-
if let Some(socket_addr) = peer_info.seen_addresses().next() {
2882-
let mut addr =
2883-
lighthouse_network::Multiaddr::from(socket_addr.ip());
2884-
addr.push(lighthouse_network::multiaddr::Protocol::Tcp(
2885-
socket_addr.port(),
2886-
));
2887-
addr.to_string()
2877+
if let Some(multiaddr) = peer_info.seen_multiaddrs().next() {
2878+
multiaddr.to_string()
28882879
} else if let Some(addr) = peer_info.listening_addresses().first() {
28892880
addr.to_string()
28902881
} else {

beacon_node/http_api/src/test_utils.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,6 @@ pub async fn create_api_server_on_port<T: BeaconChainTypes>(
152152
let enr = EnrBuilder::new("v4").build(&enr_key).unwrap();
153153
let network_globals = Arc::new(NetworkGlobals::new(
154154
enr.clone(),
155-
Some(TCP_PORT),
156-
None,
157155
meta_data,
158156
vec![],
159157
false,

beacon_node/lighthouse_network/Cargo.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ prometheus-client = "0.21.0"
4444
unused_port = { path = "../../common/unused_port" }
4545
delay_map = "0.3.0"
4646
void = "1"
47+
libp2p-quic= { version = "0.9.2", features=["tokio"]}
4748
libp2p-mplex = "0.40.0"
4849

4950
[dependencies.libp2p]
5051
version = "0.52"
5152
default-features = false
52-
features = ["websocket", "identify", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "plaintext", "secp256k1", "macros", "ecdsa"]
53+
features = ["identify", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "plaintext", "secp256k1", "macros", "ecdsa"]
5354

5455
[dev-dependencies]
5556
slog-term = "2.6.0"
@@ -59,6 +60,3 @@ exit-future = "0.2.0"
5960
void = "1"
6061
quickcheck = "0.9.2"
6162
quickcheck_macros = "0.9.1"
62-
63-
[features]
64-
libp2p-websocket = []

beacon_node/lighthouse_network/src/config.rs

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,24 @@ pub struct Config {
5858
/// that no discovery address has been set in the CLI args.
5959
pub enr_address: (Option<Ipv4Addr>, Option<Ipv6Addr>),
6060

61-
/// The udp4 port to broadcast to peers in order to reach back for discovery.
61+
/// The udp ipv4 port to broadcast to peers in order to reach back for discovery.
6262
pub enr_udp4_port: Option<u16>,
6363

64-
/// The tcp4 port to broadcast to peers in order to reach back for libp2p services.
64+
/// The quic ipv4 port to broadcast to peers in order to reach back for libp2p services.
65+
pub enr_quic4_port: Option<u16>,
66+
67+
/// The tcp ipv4 port to broadcast to peers in order to reach back for libp2p services.
6568
pub enr_tcp4_port: Option<u16>,
6669

67-
/// The udp6 port to broadcast to peers in order to reach back for discovery.
70+
/// The udp ipv6 port to broadcast to peers in order to reach back for discovery.
6871
pub enr_udp6_port: Option<u16>,
6972

70-
/// The tcp6 port to broadcast to peers in order to reach back for libp2p services.
73+
/// The tcp ipv6 port to broadcast to peers in order to reach back for libp2p services.
7174
pub enr_tcp6_port: Option<u16>,
7275

76+
/// The quic ipv6 port to broadcast to peers in order to reach back for libp2p services.
77+
pub enr_quic6_port: Option<u16>,
78+
7379
/// Target number of connected peers.
7480
pub target_peers: usize,
7581

@@ -102,6 +108,9 @@ pub struct Config {
102108
/// Disables the discovery protocol from starting.
103109
pub disable_discovery: bool,
104110

111+
/// Disables quic support.
112+
pub disable_quic_support: bool,
113+
105114
/// Attempt to construct external port mappings with UPnP.
106115
pub upnp_enabled: bool,
107116

@@ -149,57 +158,76 @@ impl Config {
149158
/// Sets the listening address to use an ipv4 address. The discv5 ip_mode and table filter are
150159
/// adjusted accordingly to ensure addresses that are present in the enr are globally
151160
/// reachable.
152-
pub fn set_ipv4_listening_address(&mut self, addr: Ipv4Addr, tcp_port: u16, udp_port: u16) {
161+
pub fn set_ipv4_listening_address(
162+
&mut self,
163+
addr: Ipv4Addr,
164+
tcp_port: u16,
165+
disc_port: u16,
166+
quic_port: u16,
167+
) {
153168
self.listen_addresses = ListenAddress::V4(ListenAddr {
154169
addr,
155-
udp_port,
170+
disc_port,
171+
quic_port,
156172
tcp_port,
157173
});
158-
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port);
174+
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), disc_port);
159175
self.discv5_config.table_filter = |enr| enr.ip4().as_ref().map_or(false, is_global_ipv4)
160176
}
161177

162178
/// Sets the listening address to use an ipv6 address. The discv5 ip_mode and table filter is
163179
/// adjusted accordingly to ensure addresses that are present in the enr are globally
164180
/// reachable.
165-
pub fn set_ipv6_listening_address(&mut self, addr: Ipv6Addr, tcp_port: u16, udp_port: u16) {
181+
pub fn set_ipv6_listening_address(
182+
&mut self,
183+
addr: Ipv6Addr,
184+
tcp_port: u16,
185+
disc_port: u16,
186+
quic_port: u16,
187+
) {
166188
self.listen_addresses = ListenAddress::V6(ListenAddr {
167189
addr,
168-
udp_port,
190+
disc_port,
191+
quic_port,
169192
tcp_port,
170193
});
171194

172-
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port);
195+
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), disc_port);
173196
self.discv5_config.table_filter = |enr| enr.ip6().as_ref().map_or(false, is_global_ipv6)
174197
}
175198

176199
/// Sets the listening address to use both an ipv4 and ipv6 address. The discv5 ip_mode and
177200
/// table filter is adjusted accordingly to ensure addresses that are present in the enr are
178201
/// globally reachable.
202+
#[allow(clippy::too_many_arguments)]
179203
pub fn set_ipv4_ipv6_listening_addresses(
180204
&mut self,
181205
v4_addr: Ipv4Addr,
182206
tcp4_port: u16,
183-
udp4_port: u16,
207+
disc4_port: u16,
208+
quic4_port: u16,
184209
v6_addr: Ipv6Addr,
185210
tcp6_port: u16,
186-
udp6_port: u16,
211+
disc6_port: u16,
212+
quic6_port: u16,
187213
) {
188214
self.listen_addresses = ListenAddress::DualStack(
189215
ListenAddr {
190216
addr: v4_addr,
191-
udp_port: udp4_port,
217+
disc_port: disc4_port,
218+
quic_port: quic4_port,
192219
tcp_port: tcp4_port,
193220
},
194221
ListenAddr {
195222
addr: v6_addr,
196-
udp_port: udp6_port,
223+
disc_port: disc6_port,
224+
quic_port: quic6_port,
197225
tcp_port: tcp6_port,
198226
},
199227
);
200228
self.discv5_config.listen_config = discv5::ListenConfig::default()
201-
.with_ipv4(v4_addr, udp4_port)
202-
.with_ipv6(v6_addr, udp6_port);
229+
.with_ipv4(v4_addr, disc4_port)
230+
.with_ipv6(v6_addr, disc6_port);
203231

204232
self.discv5_config.table_filter = |enr| match (&enr.ip4(), &enr.ip6()) {
205233
(None, None) => false,
@@ -213,27 +241,32 @@ impl Config {
213241
match listen_addr {
214242
ListenAddress::V4(ListenAddr {
215243
addr,
216-
udp_port,
244+
disc_port,
245+
quic_port,
217246
tcp_port,
218-
}) => self.set_ipv4_listening_address(addr, tcp_port, udp_port),
247+
}) => self.set_ipv4_listening_address(addr, tcp_port, disc_port, quic_port),
219248
ListenAddress::V6(ListenAddr {
220249
addr,
221-
udp_port,
250+
disc_port,
251+
quic_port,
222252
tcp_port,
223-
}) => self.set_ipv6_listening_address(addr, tcp_port, udp_port),
253+
}) => self.set_ipv6_listening_address(addr, tcp_port, disc_port, quic_port),
224254
ListenAddress::DualStack(
225255
ListenAddr {
226256
addr: ip4addr,
227-
udp_port: udp4_port,
257+
disc_port: disc4_port,
258+
quic_port: quic4_port,
228259
tcp_port: tcp4_port,
229260
},
230261
ListenAddr {
231262
addr: ip6addr,
232-
udp_port: udp6_port,
263+
disc_port: disc6_port,
264+
quic_port: quic6_port,
233265
tcp_port: tcp6_port,
234266
},
235267
) => self.set_ipv4_ipv6_listening_addresses(
236-
ip4addr, tcp4_port, udp4_port, ip6addr, tcp6_port, udp6_port,
268+
ip4addr, tcp4_port, disc4_port, quic4_port, ip6addr, tcp6_port, disc6_port,
269+
quic6_port,
237270
),
238271
}
239272
}
@@ -272,7 +305,8 @@ impl Default for Config {
272305
);
273306
let listen_addresses = ListenAddress::V4(ListenAddr {
274307
addr: Ipv4Addr::UNSPECIFIED,
275-
udp_port: 9000,
308+
disc_port: 9000,
309+
quic_port: 9001,
276310
tcp_port: 9000,
277311
});
278312

@@ -305,10 +339,11 @@ impl Default for Config {
305339
network_dir,
306340
listen_addresses,
307341
enr_address: (None, None),
308-
309342
enr_udp4_port: None,
343+
enr_quic4_port: None,
310344
enr_tcp4_port: None,
311345
enr_udp6_port: None,
346+
enr_quic6_port: None,
312347
enr_tcp6_port: None,
313348
target_peers: 50,
314349
gs_config,
@@ -320,6 +355,7 @@ impl Default for Config {
320355
disable_peer_scoring: false,
321356
client_version: lighthouse_version::version_with_platform(),
322357
disable_discovery: false,
358+
disable_quic_support: false,
323359
upnp_enabled: true,
324360
network_load: 3,
325361
private: false,

beacon_node/lighthouse_network/src/discovery/enr.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use std::path::Path;
1717
use std::str::FromStr;
1818
use types::{EnrForkId, EthSpec};
1919

20+
use super::enr_ext::{EnrExt, QUIC6_ENR_KEY, QUIC_ENR_KEY};
21+
2022
/// The ENR field specifying the fork id.
2123
pub const ETH2_ENR_KEY: &str = "eth2";
2224
/// The ENR field specifying the attestation subnet bitfield.
@@ -142,7 +144,7 @@ pub fn build_or_load_enr<T: EthSpec>(
142144

143145
pub fn create_enr_builder_from_config<T: EnrKey>(
144146
config: &NetworkConfig,
145-
enable_tcp: bool,
147+
enable_libp2p: bool,
146148
) -> EnrBuilder<T> {
147149
let mut builder = EnrBuilder::new("v4");
148150
let (maybe_ipv4_address, maybe_ipv6_address) = &config.enr_address;
@@ -163,7 +165,28 @@ pub fn create_enr_builder_from_config<T: EnrKey>(
163165
builder.udp6(udp6_port);
164166
}
165167

166-
if enable_tcp {
168+
if enable_libp2p {
169+
// Add QUIC fields to the ENR.
170+
// Since QUIC is used as an alternative transport for the libp2p protocols,
171+
// the related fields should only be added when both QUIC and libp2p are enabled
172+
if !config.disable_quic_support {
173+
// If we are listening on ipv4, add the quic ipv4 port.
174+
if let Some(quic4_port) = config
175+
.enr_quic4_port
176+
.or_else(|| config.listen_addrs().v4().map(|v4_addr| v4_addr.quic_port))
177+
{
178+
builder.add_value(QUIC_ENR_KEY, &quic4_port);
179+
}
180+
181+
// If we are listening on ipv6, add the quic ipv6 port.
182+
if let Some(quic6_port) = config
183+
.enr_quic6_port
184+
.or_else(|| config.listen_addrs().v6().map(|v6_addr| v6_addr.quic_port))
185+
{
186+
builder.add_value(QUIC6_ENR_KEY, &quic6_port);
187+
}
188+
}
189+
167190
// If the ENR port is not set, and we are listening over that ip version, use the listening port instead.
168191
let tcp4_port = config
169192
.enr_tcp4_port
@@ -218,6 +241,9 @@ fn compare_enr(local_enr: &Enr, disk_enr: &Enr) -> bool {
218241
// tcp ports must match
219242
&& local_enr.tcp4() == disk_enr.tcp4()
220243
&& local_enr.tcp6() == disk_enr.tcp6()
244+
// quic ports must match
245+
&& local_enr.quic4() == disk_enr.quic4()
246+
&& local_enr.quic6() == disk_enr.quic6()
221247
// must match on the same fork
222248
&& local_enr.get(ETH2_ENR_KEY) == disk_enr.get(ETH2_ENR_KEY)
223249
// take preference over disk udp port if one is not specified

0 commit comments

Comments
 (0)