lighthouse-pulse/lighthouse/tests/boot_node.rs

185 lines
5.8 KiB
Rust
Raw Normal View History

use boot_node::config::BootNodeConfigSerialization;
use crate::exec::{CommandLineTestExec, CompletedTest};
use clap::ArgMatches;
use clap_utils::get_eth2_network_config;
use lighthouse_network::discovery::ENR_FILENAME;
use lighthouse_network::Enr;
use std::fs::File;
use std::io::Write;
use std::net::Ipv4Addr;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
use tempfile::TempDir;
Support for Ipv6 (#4046) ## Issue Addressed Add support for ipv6 and dual stack in lighthouse. ## Proposed Changes From an user perspective, now setting an ipv6 address, optionally configuring the ports should feel exactly the same as using an ipv4 address. If listening over both ipv4 and ipv6 then the user needs to: - use the `--listen-address` two times (ipv4 and ipv6 addresses) - `--port6` becomes then required - `--discovery-port6` can now be used to additionally configure the ipv6 udp port ### Rough list of code changes - Discovery: - Table filter and ip mode set to match the listening config. - Ipv6 address, tcp port and udp port set in the ENR builder - Reported addresses now check which tcp port to give to libp2p - LH Network Service: - Can listen over Ipv6, Ipv4, or both. This uses two sockets. Using mapped addresses is disabled from libp2p and it's the most compatible option. - NetworkGlobals: - No longer stores udp port since was not used at all. Instead, stores the Ipv4 and Ipv6 TCP ports. - NetworkConfig: - Update names to make it clear that previous udp and tcp ports in ENR were Ipv4 - Add fields to configure Ipv6 udp and tcp ports in the ENR - Include advertised enr Ipv6 address. - Add type to model Listening address that's either Ipv4, Ipv6 or both. A listening address includes the ip, udp port and tcp port. - UPnP: - Kept only for ipv4 - Cli flags: - `--listen-addresses` now can take up to two values - `--port` will apply to ipv4 or ipv6 if only one listening address is given. If two listening addresses are given it will apply only to Ipv4. - `--port6` New flag required when listening over ipv4 and ipv6 that applies exclusively to Ipv6. - `--discovery-port` will now apply to ipv4 and ipv6 if only one listening address is given. - `--discovery-port6` New flag to configure the individual udp port of ipv6 if listening over both ipv4 and ipv6. - `--enr-udp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour. - `--enr-udp6-port` Added to configure the enr udp6 field. - `--enr-tcp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour. - `--enr-tcp6-port` Added to configure the enr tcp6 field. - `--enr-addresses` now can take two values. - `--enr-match` updated behaviour. - Common: - rename `unused_port` functions to specify that they are over ipv4. - add functions to get unused ports over ipv6. - Testing binaries - Updated code to reflect network config changes and unused_port changes. ## Additional Info TODOs: - use two sockets in discovery. I'll get back to this and it's on https://github.com/sigp/discv5/pull/160 - lcli allow listening over two sockets in generate_bootnodes_enr - add at least one smoke flag for ipv6 (I have tested this and works for me) - update the book
2023-03-14 01:13:34 +00:00
use unused_port::unused_udp4_port;
const IP_ADDRESS: &str = "192.168.2.108";
/// Returns the `lighthouse boot_node` command.
fn base_cmd() -> Command {
let lighthouse_bin = env!("CARGO_BIN_EXE_lighthouse");
let path = lighthouse_bin
.parse::<PathBuf>()
.expect("should parse CARGO_TARGET_DIR");
let mut cmd = Command::new(path);
cmd.arg("boot_node");
cmd
}
struct CommandLineTest {
cmd: Command,
}
impl CommandLineTest {
fn new() -> CommandLineTest {
let base_cmd = base_cmd();
CommandLineTest { cmd: base_cmd }
}
fn run_with_ip(&mut self) -> CompletedTest<BootNodeConfigSerialization> {
self.cmd.arg("--enr-address").arg(IP_ADDRESS);
self.run()
}
}
impl CommandLineTestExec for CommandLineTest {
type Config = BootNodeConfigSerialization;
fn cmd_mut(&mut self) -> &mut Command {
&mut self.cmd
}
}
#[test]
fn enr_address_arg() {
let mut test = CommandLineTest::new();
test.run_with_ip().with_config(|config| {
assert_eq!(config.local_enr.ip4(), Some(IP_ADDRESS.parse().unwrap()));
});
}
#[test]
fn port_flag() {
Support for Ipv6 (#4046) ## Issue Addressed Add support for ipv6 and dual stack in lighthouse. ## Proposed Changes From an user perspective, now setting an ipv6 address, optionally configuring the ports should feel exactly the same as using an ipv4 address. If listening over both ipv4 and ipv6 then the user needs to: - use the `--listen-address` two times (ipv4 and ipv6 addresses) - `--port6` becomes then required - `--discovery-port6` can now be used to additionally configure the ipv6 udp port ### Rough list of code changes - Discovery: - Table filter and ip mode set to match the listening config. - Ipv6 address, tcp port and udp port set in the ENR builder - Reported addresses now check which tcp port to give to libp2p - LH Network Service: - Can listen over Ipv6, Ipv4, or both. This uses two sockets. Using mapped addresses is disabled from libp2p and it's the most compatible option. - NetworkGlobals: - No longer stores udp port since was not used at all. Instead, stores the Ipv4 and Ipv6 TCP ports. - NetworkConfig: - Update names to make it clear that previous udp and tcp ports in ENR were Ipv4 - Add fields to configure Ipv6 udp and tcp ports in the ENR - Include advertised enr Ipv6 address. - Add type to model Listening address that's either Ipv4, Ipv6 or both. A listening address includes the ip, udp port and tcp port. - UPnP: - Kept only for ipv4 - Cli flags: - `--listen-addresses` now can take up to two values - `--port` will apply to ipv4 or ipv6 if only one listening address is given. If two listening addresses are given it will apply only to Ipv4. - `--port6` New flag required when listening over ipv4 and ipv6 that applies exclusively to Ipv6. - `--discovery-port` will now apply to ipv4 and ipv6 if only one listening address is given. - `--discovery-port6` New flag to configure the individual udp port of ipv6 if listening over both ipv4 and ipv6. - `--enr-udp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour. - `--enr-udp6-port` Added to configure the enr udp6 field. - `--enr-tcp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour. - `--enr-tcp6-port` Added to configure the enr tcp6 field. - `--enr-addresses` now can take two values. - `--enr-match` updated behaviour. - Common: - rename `unused_port` functions to specify that they are over ipv4. - add functions to get unused ports over ipv6. - Testing binaries - Updated code to reflect network config changes and unused_port changes. ## Additional Info TODOs: - use two sockets in discovery. I'll get back to this and it's on https://github.com/sigp/discv5/pull/160 - lcli allow listening over two sockets in generate_bootnodes_enr - add at least one smoke flag for ipv6 (I have tested this and works for me) - update the book
2023-03-14 01:13:34 +00:00
let port = unused_udp4_port().unwrap();
CommandLineTest::new()
.flag("port", Some(port.to_string().as_str()))
.run_with_ip()
.with_config(|config| {
assert_eq!(
config
.ipv4_listen_socket
.expect("Bootnode should be listening on IPv4")
.port(),
port
);
})
}
#[test]
fn listen_address_flag() {
let addr = "127.0.0.2".parse::<Ipv4Addr>().unwrap();
CommandLineTest::new()
.flag("listen-address", Some("127.0.0.2"))
.run_with_ip()
.with_config(|config| {
assert_eq!(
config
.ipv4_listen_socket
.expect("Bootnode should be listening on IPv4")
.ip(),
&addr
);
});
}
#[test]
fn boot_nodes_flag() {
// Get hardcoded boot-nodes to verify they end up in the config.
// Pass empty `ArgMatches` to `get_eth2_network_config` as we want to
// receive the default `Eth2NetworkConfig`.
let empty_args = ArgMatches::default();
let default_enr = get_eth2_network_config(&empty_args)
.unwrap()
.boot_enr
.unwrap();
let default_enr: Vec<String> = default_enr.iter().map(|enr| enr.to_base64()).collect();
// Nodes passed via `--boot-nodes` are added to the local routing table.
let extra_nodes = "enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8,enr:-LK4QFOFWca5ABQzxiCRcy37G7wy1K6zD4qMYBSN5ozzanwze_XVvXVhCk9JvF0cHXOBZrHK1E4vU7Gn-a0bHVczoDU6h2F0dG5ldHOIAAAAAAAAAACEZXRoMpA7CIeVAAAgCf__________gmlkgnY0gmlwhNIy-4iJc2VjcDI1NmsxoQJA3AXQJ6M3NpBWtJS3HPtbXG14t7qHjXuIaL6IOz89T4N0Y3CCIyiDdWRwgiMo";
let extra_enr: Vec<&str> = extra_nodes.split(",").collect();
// Construct vector of enr expected in config.
let default_enr_str: Vec<&str> = default_enr.iter().map(|s| s.as_str()).collect();
let mut expect_enr = Vec::new();
expect_enr.extend_from_slice(&default_enr_str);
expect_enr.extend_from_slice(&extra_enr);
CommandLineTest::new()
.flag("boot-nodes", Some(extra_nodes))
.run_with_ip()
.with_config(|config| {
assert_eq!(config.boot_nodes.len(), expect_enr.len());
for (i, enr) in config.boot_nodes.iter().enumerate() {
assert_eq!(
enr.to_base64(),
expect_enr[i],
"ENR missmatch at index [{}]",
i
);
}
})
}
#[test]
fn enr_port_flag() {
Support for Ipv6 (#4046) ## Issue Addressed Add support for ipv6 and dual stack in lighthouse. ## Proposed Changes From an user perspective, now setting an ipv6 address, optionally configuring the ports should feel exactly the same as using an ipv4 address. If listening over both ipv4 and ipv6 then the user needs to: - use the `--listen-address` two times (ipv4 and ipv6 addresses) - `--port6` becomes then required - `--discovery-port6` can now be used to additionally configure the ipv6 udp port ### Rough list of code changes - Discovery: - Table filter and ip mode set to match the listening config. - Ipv6 address, tcp port and udp port set in the ENR builder - Reported addresses now check which tcp port to give to libp2p - LH Network Service: - Can listen over Ipv6, Ipv4, or both. This uses two sockets. Using mapped addresses is disabled from libp2p and it's the most compatible option. - NetworkGlobals: - No longer stores udp port since was not used at all. Instead, stores the Ipv4 and Ipv6 TCP ports. - NetworkConfig: - Update names to make it clear that previous udp and tcp ports in ENR were Ipv4 - Add fields to configure Ipv6 udp and tcp ports in the ENR - Include advertised enr Ipv6 address. - Add type to model Listening address that's either Ipv4, Ipv6 or both. A listening address includes the ip, udp port and tcp port. - UPnP: - Kept only for ipv4 - Cli flags: - `--listen-addresses` now can take up to two values - `--port` will apply to ipv4 or ipv6 if only one listening address is given. If two listening addresses are given it will apply only to Ipv4. - `--port6` New flag required when listening over ipv4 and ipv6 that applies exclusively to Ipv6. - `--discovery-port` will now apply to ipv4 and ipv6 if only one listening address is given. - `--discovery-port6` New flag to configure the individual udp port of ipv6 if listening over both ipv4 and ipv6. - `--enr-udp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour. - `--enr-udp6-port` Added to configure the enr udp6 field. - `--enr-tcp-port` Updated docs to specify that it only applies to ipv4. This is an old behaviour. - `--enr-tcp6-port` Added to configure the enr tcp6 field. - `--enr-addresses` now can take two values. - `--enr-match` updated behaviour. - Common: - rename `unused_port` functions to specify that they are over ipv4. - add functions to get unused ports over ipv6. - Testing binaries - Updated code to reflect network config changes and unused_port changes. ## Additional Info TODOs: - use two sockets in discovery. I'll get back to this and it's on https://github.com/sigp/discv5/pull/160 - lcli allow listening over two sockets in generate_bootnodes_enr - add at least one smoke flag for ipv6 (I have tested this and works for me) - update the book
2023-03-14 01:13:34 +00:00
let port = unused_udp4_port().unwrap();
CommandLineTest::new()
.flag("enr-port", Some(port.to_string().as_str()))
.run_with_ip()
.with_config(|config| {
assert_eq!(config.local_enr.udp4(), Some(port));
})
}
#[test]
fn disable_packet_filter_flag() {
CommandLineTest::new()
.flag("disable-packet-filter", None)
.run_with_ip()
.with_config(|config| {
assert_eq!(config.disable_packet_filter, true);
});
}
#[test]
fn enable_enr_auto_update_flag() {
CommandLineTest::new()
.flag("enable-enr-auto-update", None)
.run_with_ip()
.with_config(|config| {
assert_eq!(config.enable_enr_auto_update, true);
});
}
#[test]
fn network_dir_flag() {
// Save enr to temp dir.
let enr = Enr::from_str("enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8").unwrap();
let tmp_dir = TempDir::new().unwrap();
save_enr_to_disk(tmp_dir.path(), &enr).unwrap();
CommandLineTest::new()
.flag("network-dir", Some(tmp_dir.path().to_str().unwrap()))
.run()
.with_config(|config| assert_eq!(config.local_enr, enr))
}
fn save_enr_to_disk(dir: &Path, enr: &Enr) -> Result<(), String> {
let mut file = File::create(dir.join(Path::new(ENR_FILENAME)))
.map_err(|e| format!("Could not create ENR file: {:?}", e))?;
file.write_all(enr.to_base64().as_bytes())
.map_err(|e| format!("Could not write ENR to file: {:?}", e))
}