Improve Lighthouse Connectivity Via ENR TCP Update (#4057)

Currently Lighthouse will remain uncontactable if users port forward a port that is not the same as the one they are listening on. 

For example, if Lighthouse runs with port 9000 TCP/UDP locally but a router is configured to pass 9010 externally to the lighthouse node on 9000, other nodes on the network will not be able to reach the lighthouse node. 

This occurs because Lighthouse does not update its ENR TCP port on external socket discovery. The intention was always that users should use `--enr-tcp-port` to customise this, but this is non-intuitive. 

The difficulty arises because we have no discovery mechanism to find our external TCP port. If we discovery a new external UDP port, we must guess what our external TCP port might be. This PR assumes the external TCP port is the same as the external UDP port (which may not be the case) and thus updates the TCP port along with the UDP port if the `--enr-tcp-port` flag is not set. 

Along with this PR, will be added documentation to the Lighthouse book so users can correctly understand and configure their ENR to maximize Lighthouse's connectivity. 

This relies on https://github.com/sigp/discv5/pull/166 and we should wait for a new release in discv5 before adding this PR.
This commit is contained in:
Age Manning 2023-03-21 05:14:57 +00:00
parent 17d56b06f6
commit 76a2007b64
9 changed files with 67 additions and 26 deletions

45
Cargo.lock generated
View File

@ -1605,16 +1605,6 @@ version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b72465f46d518f6015d9cf07f7f3013a95dd6b9c2747c3d65ae0cce43929d14f" checksum = "b72465f46d518f6015d9cf07f7f3013a95dd6b9c2747c3d65ae0cce43929d14f"
[[package]]
name = "delay_map"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c4d75d3abfe4830dcbf9bcb1b926954e121669f74dd1ca7aa0183b1755d83f6"
dependencies = [
"futures",
"tokio-util 0.6.10",
]
[[package]] [[package]]
name = "delay_map" name = "delay_map"
version = "0.3.0" version = "0.3.0"
@ -1816,15 +1806,15 @@ dependencies = [
[[package]] [[package]]
name = "discv5" name = "discv5"
version = "0.1.0" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767c0e59b3e8d65222d95df723cc2ea1da92bb0f27c563607e6f0bde064f255" checksum = "b009a99b85b58900df46435307fc5c4c845af7e182582b1fbf869572fa9fce69"
dependencies = [ dependencies = [
"aes 0.7.5", "aes 0.7.5",
"aes-gcm 0.9.4", "aes-gcm 0.9.4",
"arrayvec", "arrayvec",
"delay_map 0.1.2", "delay_map",
"enr", "enr 0.7.0",
"fnv", "fnv",
"futures", "futures",
"hashlink 0.7.0", "hashlink 0.7.0",
@ -1973,6 +1963,25 @@ name = "enr"
version = "0.6.2" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fa0a0be8915790626d5759eb51fe47435a8eac92c2f212bd2da9aa7f30ea56" checksum = "26fa0a0be8915790626d5759eb51fe47435a8eac92c2f212bd2da9aa7f30ea56"
dependencies = [
"base64 0.13.1",
"bs58",
"bytes",
"hex",
"k256",
"log",
"rand 0.8.5",
"rlp",
"serde",
"sha3 0.10.6",
"zeroize",
]
[[package]]
name = "enr"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "492a7e5fc2504d5fdce8e124d3e263b244a68b283cac67a69eda0cd43e0aebad"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"bs58", "bs58",
@ -2221,7 +2230,7 @@ dependencies = [
name = "eth2_network_config" name = "eth2_network_config"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"enr", "discv5",
"eth2_config", "eth2_config",
"eth2_ssz", "eth2_ssz",
"serde_yaml", "serde_yaml",
@ -2372,7 +2381,7 @@ dependencies = [
"async-stream", "async-stream",
"blst", "blst",
"bs58", "bs58",
"enr", "enr 0.6.2",
"hex", "hex",
"integer-sqrt", "integer-sqrt",
"multiaddr 0.14.0", "multiaddr 0.14.0",
@ -4415,7 +4424,7 @@ dependencies = [
name = "lighthouse_network" name = "lighthouse_network"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"delay_map 0.3.0", "delay_map",
"directory", "directory",
"dirs", "dirs",
"discv5", "discv5",
@ -5032,7 +5041,7 @@ name = "network"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"beacon_chain", "beacon_chain",
"delay_map 0.3.0", "delay_map",
"derivative", "derivative",
"environment", "environment",
"error-chain", "error-chain",

View File

@ -5,7 +5,7 @@ authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
discv5 = { version = "0.1.0", features = ["libp2p"] } discv5 = { version = "0.2.2", features = ["libp2p"] }
unsigned-varint = { version = "0.6.0", features = ["codec"] } unsigned-varint = { version = "0.6.0", features = ["codec"] }
types = { path = "../../consensus/types" } types = { path = "../../consensus/types" }
eth2_ssz_types = "0.2.2" eth2_ssz_types = "0.2.2"

View File

@ -177,6 +177,13 @@ pub struct Discovery<TSpec: EthSpec> {
/// always false. /// always false.
pub started: bool, pub started: bool,
/// This keeps track of whether an external UDP port change should also indicate an internal
/// TCP port change. As we cannot detect our external TCP port, we assume that the external UDP
/// port is also our external TCP port. This assumption only holds if the user has not
/// explicitly set their ENR TCP port via the CLI config. The first indicates tcp4 and the
/// second indicates tcp6.
update_tcp_port: (bool, bool),
/// Logger for the discovery behaviour. /// Logger for the discovery behaviour.
log: slog::Logger, log: slog::Logger,
} }
@ -300,6 +307,11 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
} }
} }
let update_tcp_port = (
config.enr_tcp4_port.is_none(),
config.enr_tcp6_port.is_none(),
);
Ok(Self { Ok(Self {
cached_enrs: LruCache::new(50), cached_enrs: LruCache::new(50),
network_globals, network_globals,
@ -309,6 +321,7 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
discv5, discv5,
event_stream, event_stream,
started: !config.disable_discovery, started: !config.disable_discovery,
update_tcp_port,
log, log,
enr_dir, enr_dir,
}) })
@ -1019,6 +1032,13 @@ impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
metrics::check_nat(); metrics::check_nat();
// Discv5 will have updated our local ENR. We save the updated version // Discv5 will have updated our local ENR. We save the updated version
// to disk. // to disk.
if (self.update_tcp_port.0 && socket_addr.is_ipv4())
|| (self.update_tcp_port.1 && socket_addr.is_ipv6())
{
// Update the TCP port in the ENR
self.discv5.update_local_enr_socket(socket_addr, true);
}
let enr = self.discv5.local_enr(); let enr = self.discv5.local_enr();
enr::save_enr_to_disk(Path::new(&self.enr_dir), &enr, &self.log); enr::save_enr_to_disk(Path::new(&self.enr_dir), &enr, &self.log);
// update network globals // update network globals

View File

@ -167,7 +167,8 @@ pub fn check_nat() {
} }
pub fn scrape_discovery_metrics() { pub fn scrape_discovery_metrics() {
let metrics = discv5::metrics::Metrics::from(discv5::Discv5::raw_metrics()); let metrics =
discv5::metrics::Metrics::from(discv5::Discv5::<discv5::DefaultProtocolId>::raw_metrics());
set_float_gauge(&DISCOVERY_REQS, metrics.unsolicited_requests_per_second); set_float_gauge(&DISCOVERY_REQS, metrics.unsolicited_requests_per_second);
set_gauge(&DISCOVERY_SESSIONS, metrics.active_sessions as i64); set_gauge(&DISCOVERY_SESSIONS, metrics.active_sessions as i64);
set_gauge(&DISCOVERY_SENT_BYTES, metrics.bytes_sent as i64); set_gauge(&DISCOVERY_SENT_BYTES, metrics.bytes_sent as i64);

View File

@ -41,7 +41,7 @@ drastically and use the (recommended) default.
### NAT Traversal (Port Forwarding) ### NAT Traversal (Port Forwarding)
Lighthouse, by default, used port 9000 for both TCP and UDP. Lighthouse will Lighthouse, by default, uses port 9000 for both TCP and UDP. Lighthouse will
still function if it is behind a NAT without any port mappings. Although still function if it is behind a NAT without any port mappings. Although
Lighthouse still functions, we recommend that some mechanism is used to ensure Lighthouse still functions, we recommend that some mechanism is used to ensure
that your Lighthouse node is publicly accessible. This will typically improve that your Lighthouse node is publicly accessible. This will typically improve
@ -54,6 +54,16 @@ node will inform you of established routes in this case). If UPnP is not
enabled, we recommend you manually set up port mappings to both of Lighthouse's enabled, we recommend you manually set up port mappings to both of Lighthouse's
TCP and UDP ports (9000 by default). TCP and UDP ports (9000 by default).
> Note: Lighthouse needs to advertise its publicly accessible ports in
> order to inform its peers that it is contactable and how to connect to it.
> Lighthouse has an automated way of doing this for the UDP port. This means
> Lighthouse can detect its external UDP port. There is no such mechanism for the
> TCP port. As such, we assume that the external UDP and external TCP port is the
> same (i.e external 5050 UDP/TCP mapping to internal 9000 is fine). If you are setting up differing external UDP and TCP ports, you should
> explicitly specify them using the `--enr-tcp-port` and `--enr-udp-port` as
> explained in the following section.
### ENR Configuration ### ENR Configuration
Lighthouse has a number of CLI parameters for constructing and modifying the Lighthouse has a number of CLI parameters for constructing and modifying the

View File

@ -128,8 +128,9 @@ same `datadir` as a previous network. I.e if you have been running the
`datadir` (the `datadir` is also printed out in the beacon node's logs on `datadir` (the `datadir` is also printed out in the beacon node's logs on
boot-up). boot-up).
If you find yourself with a low peer count and is not reaching the target you If you find yourself with a low peer count and it's not reaching the target you
expect. Try setting up the correct port forwards as described [here](./advanced_networking.md#nat-traversal-port-forwarding). expect. Try setting up the correct port forwards as described
[here](./advanced_networking.md#nat-traversal-port-forwarding).
### What should I do if I lose my slashing protection database? ### What should I do if I lose my slashing protection database?

View File

@ -44,7 +44,7 @@ pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
info!(log, "Contact information"; "multiaddrs" => ?local_enr.multiaddr_p2p()); info!(log, "Contact information"; "multiaddrs" => ?local_enr.multiaddr_p2p());
// construct the discv5 server // construct the discv5 server
let mut discv5 = Discv5::new(local_enr.clone(), local_key, discv5_config).unwrap(); let mut discv5: Discv5 = Discv5::new(local_enr.clone(), local_key, discv5_config).unwrap();
// If there are any bootnodes add them to the routing table // If there are any bootnodes add them to the routing table
for enr in boot_nodes { for enr in boot_nodes {

View File

@ -18,4 +18,4 @@ serde_yaml = "0.8.13"
types = { path = "../../consensus/types"} types = { path = "../../consensus/types"}
eth2_ssz = "0.4.1" eth2_ssz = "0.4.1"
eth2_config = { path = "../eth2_config"} eth2_config = { path = "../eth2_config"}
enr = { version = "0.6.2", features = ["ed25519", "k256"] } discv5 = "0.2.2"

View File

@ -11,7 +11,7 @@
//! To add a new built-in testnet, add it to the `define_hardcoded_nets` invocation in the `eth2_config` //! To add a new built-in testnet, add it to the `define_hardcoded_nets` invocation in the `eth2_config`
//! crate. //! crate.
use enr::{CombinedKey, Enr}; use discv5::enr::{CombinedKey, Enr};
use eth2_config::{instantiate_hardcoded_nets, HardcodedNet}; use eth2_config::{instantiate_hardcoded_nets, HardcodedNet};
use std::fs::{create_dir_all, File}; use std::fs::{create_dir_all, File};
use std::io::{Read, Write}; use std::io::{Read, Write};