diff --git a/Cargo.lock b/Cargo.lock index 1d427337b57..3da097362ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,9 +275,9 @@ checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" @@ -532,6 +532,7 @@ dependencies = [ name = "boot_node" version = "0.2.6" dependencies = [ + "beacon_node", "clap", "discv5", "eth2_libp2p", @@ -958,7 +959,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "cfg-if", "crossbeam-utils", "lazy_static", @@ -984,7 +985,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "cfg-if", "lazy_static", ] @@ -1069,6 +1070,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.2.3", + "zeroize", +] + [[package]] name = "darwin-libproc" version = "0.1.2" @@ -1247,15 +1261,15 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "1.0.0-pre.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a8a37f4e8b35af971e6db5e3897e7a6344caa3f92f6544f88125a1f5f0035a" +checksum = "53d2e93f837d749c16d118e7ddf7a4dfd0ac8f452cf51e46e9348824e5ef6851" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.0.0", "ed25519", "rand 0.7.3", "serde", - "sha2 0.8.2", + "sha2 0.9.1", "zeroize", ] @@ -2097,7 +2111,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", ] [[package]] @@ -2398,7 +2412,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "hashbrown 0.8.2", ] @@ -2576,9 +2590,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.74" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" [[package]] name = "libflate" @@ -2777,7 +2791,7 @@ version = "0.23.0" source = "git+https://github.com/sigp/rust-libp2p?rev=bbf0cfbaff2f733b3ae7bfed3caba8b7ee542803#bbf0cfbaff2f733b3ae7bfed3caba8b7ee542803" dependencies = [ "bytes 0.5.6", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "futures 0.3.5", "lazy_static", "libp2p-core 0.21.0", @@ -3044,7 +3058,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", ] [[package]] @@ -3340,7 +3354,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "num-integer", "num-traits", ] @@ -3370,7 +3384,7 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "num-traits", ] @@ -3380,7 +3394,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "num-integer", "num-traits", ] @@ -3391,7 +3405,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", ] [[package]] @@ -3472,7 +3486,7 @@ version = "0.9.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "cc", "libc", "openssl-src", @@ -3780,9 +3794,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "primitive-types" @@ -4111,7 +4125,7 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" dependencies = [ - "autocfg 1.0.0", + "autocfg 1.0.1", "crossbeam-deque", "either", "rayon-core", @@ -6450,7 +6464,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 2.1.0", "rand_core 0.5.1", "zeroize", ] diff --git a/beacon_node/eth2_libp2p/src/discovery/enr.rs b/beacon_node/eth2_libp2p/src/discovery/enr.rs index dc44cb3ab8a..6af9f21fb7e 100644 --- a/beacon_node/eth2_libp2p/src/discovery/enr.rs +++ b/beacon_node/eth2_libp2p/src/discovery/enr.rs @@ -6,6 +6,7 @@ use super::enr_ext::CombinedKeyExt; use super::ENR_FILENAME; use crate::types::{Enr, EnrBitfield}; use crate::NetworkConfig; +use discv5::enr::EnrKey; use libp2p::core::identity::Keypair; use slog::{debug, warn}; use ssz::{Decode, Encode}; @@ -48,23 +49,16 @@ impl Eth2Enr for Enr { } } -/// Loads an ENR from file if it exists and matches the current NodeId and sequence number. If none -/// exists, generates a new one. -/// +/// Either use the given ENR or load an ENR from file if it exists and matches the current NodeId +/// and sequence number. /// If an ENR exists, with the same NodeId, this function checks to see if the loaded ENR from -/// disk is suitable to use, otherwise we increment our newly generated ENR's sequence number. -pub fn build_or_load_enr( - local_key: Keypair, +/// disk is suitable to use, otherwise we increment the given ENR's sequence number. +pub fn use_or_load_enr( + enr_key: &CombinedKey, + local_enr: &mut Enr, config: &NetworkConfig, - enr_fork_id: EnrForkId, log: &slog::Logger, -) -> Result { - // Build the local ENR. - // Note: Discovery should update the ENR record's IP to the external IP as seen by the - // majority of our peers, if the CLI doesn't expressly forbid it. - let enr_key = CombinedKey::from_libp2p(&local_key)?; - let mut local_enr = build_enr::(&enr_key, config, enr_fork_id)?; - +) -> Result<(), String> { let enr_f = config.network_dir.join(ENR_FILENAME); if let Ok(mut enr_file) = File::open(enr_f.clone()) { let mut enr_string = String::new(); @@ -78,14 +72,15 @@ pub fn build_or_load_enr( if compare_enr(&local_enr, &disk_enr) { debug!(log, "ENR loaded from disk"; "file" => format!("{:?}", enr_f)); // the stored ENR has the same configuration, use it - return Ok(disk_enr); + *local_enr = disk_enr; + return Ok(()); } // same node id, different configuration - update the sequence number // Note: local_enr is generated with default(0) attnets value, // so a non default value in persisted enr will also update sequence number. let new_seq_no = disk_enr.seq().checked_add(1).ok_or_else(|| "ENR sequence number on file is too large. Remove it to generate a new NodeId")?; - local_enr.set_seq(new_seq_no, &enr_key).map_err(|e| { + local_enr.set_seq(new_seq_no, enr_key).map_err(|e| { format!("Could not update ENR sequence number: {:?}", e) })?; debug!(log, "ENR sequence number increased"; "seq" => new_seq_no); @@ -101,15 +96,31 @@ pub fn build_or_load_enr( save_enr_to_disk(&config.network_dir, &local_enr, log); - Ok(local_enr) + Ok(()) } -/// Builds a lighthouse ENR given a `NetworkConfig`. -pub fn build_enr( - enr_key: &CombinedKey, +/// Loads an ENR from file if it exists and matches the current NodeId and sequence number. If none +/// exists, generates a new one. +/// +/// If an ENR exists, with the same NodeId, this function checks to see if the loaded ENR from +/// disk is suitable to use, otherwise we increment our newly generated ENR's sequence number. +pub fn build_or_load_enr( + local_key: Keypair, config: &NetworkConfig, enr_fork_id: EnrForkId, + log: &slog::Logger, ) -> Result { + // Build the local ENR. + // Note: Discovery should update the ENR record's IP to the external IP as seen by the + // majority of our peers, if the CLI doesn't expressly forbid it. + let enr_key = CombinedKey::from_libp2p(&local_key)?; + let mut local_enr = build_enr::(&enr_key, config, enr_fork_id)?; + + use_or_load_enr(&enr_key, &mut local_enr, config, log)?; + Ok(local_enr) +} + +pub fn create_enr_builder_from_config(config: &NetworkConfig) -> EnrBuilder { let mut builder = EnrBuilder::new("v4"); if let Some(enr_address) = config.enr_address { builder.ip(enr_address); @@ -120,7 +131,17 @@ pub fn build_enr( // we always give it our listening tcp port // TODO: Add uPnP support to map udp and tcp ports let tcp_port = config.enr_tcp_port.unwrap_or_else(|| config.libp2p_port); - builder.tcp(tcp_port); + builder.tcp(tcp_port).tcp(config.libp2p_port); + builder +} + +/// Builds a lighthouse ENR given a `NetworkConfig`. +pub fn build_enr( + enr_key: &CombinedKey, + config: &NetworkConfig, + enr_fork_id: EnrForkId, +) -> Result { + let mut builder = create_enr_builder_from_config(config); // set the `eth2` field on our ENR builder.add_value(ETH2_ENR_KEY.into(), enr_fork_id.as_ssz_bytes()); @@ -131,7 +152,6 @@ pub fn build_enr( builder.add_value(BITFIELD_ENR_KEY.into(), bitfield.as_ssz_bytes()); builder - .tcp(config.libp2p_port) .build(enr_key) .map_err(|e| format!("Could not build Local ENR: {:?}", e)) } diff --git a/beacon_node/eth2_libp2p/src/discovery/mod.rs b/beacon_node/eth2_libp2p/src/discovery/mod.rs index 1b2163410bc..8ca6e7fe5fc 100644 --- a/beacon_node/eth2_libp2p/src/discovery/mod.rs +++ b/beacon_node/eth2_libp2p/src/discovery/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod enr; pub mod enr_ext; // Allow external use of the lighthouse ENR builder -pub use enr::{build_enr, CombinedKey, Eth2Enr}; +pub use enr::{build_enr, create_enr_builder_from_config, use_or_load_enr, CombinedKey, Eth2Enr}; pub use enr_ext::{CombinedKeyExt, EnrExt}; pub use libp2p::core::identity::Keypair; diff --git a/beacon_node/eth2_libp2p/src/lib.rs b/beacon_node/eth2_libp2p/src/lib.rs index ee422c43d4f..f3f368bb4d6 100644 --- a/beacon_node/eth2_libp2p/src/lib.rs +++ b/beacon_node/eth2_libp2p/src/lib.rs @@ -26,4 +26,4 @@ pub use metrics::scrape_discovery_metrics; pub use peer_manager::{ client::Client, score::PeerAction, PeerDB, PeerInfo, PeerSyncStatus, SyncInfo, }; -pub use service::{Libp2pEvent, Service, NETWORK_KEY_FILENAME}; +pub use service::{load_private_key, Libp2pEvent, Service, NETWORK_KEY_FILENAME}; diff --git a/beacon_node/eth2_libp2p/src/service.rs b/beacon_node/eth2_libp2p/src/service.rs index 34ae88a9ea4..67421cc9681 100644 --- a/beacon_node/eth2_libp2p/src/service.rs +++ b/beacon_node/eth2_libp2p/src/service.rs @@ -357,7 +357,7 @@ fn keypair_from_bytes(mut bytes: Vec) -> error::Result { /// generated and is then saved to disk. /// /// Currently only secp256k1 keys are allowed, as these are the only keys supported by discv5. -fn load_private_key(config: &NetworkConfig, log: &slog::Logger) -> Keypair { +pub fn load_private_key(config: &NetworkConfig, log: &slog::Logger) -> Keypair { // check for key from disk let network_key_f = config.network_dir.join(NETWORK_KEY_FILENAME); if let Ok(mut network_key_file) = File::open(network_key_f.clone()) { diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index b2da523ec09..f9abfca6aeb 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -2,7 +2,7 @@ use beacon_chain::builder::PUBKEY_CACHE_FILENAME; use clap::ArgMatches; use clap_utils::BAD_TESTNET_DIR_MESSAGE; use client::{config::DEFAULT_DATADIR, ClientConfig, ClientGenesis}; -use eth2_libp2p::{multiaddr::Protocol, Enr, Multiaddr}; +use eth2_libp2p::{multiaddr::Protocol, Enr, Multiaddr, NetworkConfig}; use eth2_testnet_config::Eth2TestnetConfig; use slog::{crit, info, Logger}; use ssz::Encode; @@ -75,148 +75,13 @@ pub fn get_config( /* * Networking */ - // If a network dir has been specified, override the `datadir` definition. - if let Some(dir) = cli_args.value_of("network-dir") { - client_config.network.network_dir = PathBuf::from(dir); - } else { - client_config.network.network_dir = client_config.data_dir.join(NETWORK_DIR); - }; - - if let Some(listen_address_str) = cli_args.value_of("listen-address") { - let listen_address = listen_address_str - .parse() - .map_err(|_| format!("Invalid listen address: {:?}", listen_address_str))?; - client_config.network.listen_address = listen_address; - } - - if let Some(target_peers_str) = cli_args.value_of("target-peers") { - client_config.network.target_peers = target_peers_str - .parse::() - .map_err(|_| format!("Invalid number of target peers: {}", target_peers_str))?; - } - - if let Some(port_str) = cli_args.value_of("port") { - let port = port_str - .parse::() - .map_err(|_| format!("Invalid port: {}", port_str))?; - client_config.network.libp2p_port = port; - client_config.network.discovery_port = port; - } - - if let Some(port_str) = cli_args.value_of("discovery-port") { - let port = port_str - .parse::() - .map_err(|_| format!("Invalid port: {}", port_str))?; - client_config.network.discovery_port = port; - } - - if let Some(boot_enr_str) = cli_args.value_of("boot-nodes") { - let mut enrs: Vec = vec![]; - let mut multiaddrs: Vec = vec![]; - for addr in boot_enr_str.split(',') { - match addr.parse() { - Ok(enr) => enrs.push(enr), - Err(_) => { - // parsing as ENR failed, try as Multiaddr - let multi: Multiaddr = addr - .parse() - .map_err(|_| format!("Not valid as ENR nor Multiaddr: {}", addr))?; - if !multi.iter().any(|proto| matches!(proto, Protocol::Udp(_))) { - slog::error!(log, "Missing UDP in Multiaddr {}", multi.to_string()); - } - if !multi.iter().any(|proto| matches!(proto, Protocol::P2p(_))) { - slog::error!(log, "Missing P2P in Multiaddr {}", multi.to_string()); - } - multiaddrs.push(multi); - } - } - } - client_config.network.boot_nodes_enr = enrs; - client_config.network.boot_nodes_multiaddr = multiaddrs; - } - - if let Some(libp2p_addresses_str) = cli_args.value_of("libp2p-addresses") { - client_config.network.libp2p_nodes = libp2p_addresses_str - .split(',') - .map(|multiaddr| { - multiaddr - .parse() - .map_err(|_| format!("Invalid Multiaddr: {}", multiaddr)) - }) - .collect::, _>>()?; - } - - if let Some(enr_udp_port_str) = cli_args.value_of("enr-udp-port") { - client_config.network.enr_udp_port = Some( - enr_udp_port_str - .parse::() - .map_err(|_| format!("Invalid discovery port: {}", enr_udp_port_str))?, - ); - } - - if let Some(enr_tcp_port_str) = cli_args.value_of("enr-tcp-port") { - client_config.network.enr_tcp_port = Some( - enr_tcp_port_str - .parse::() - .map_err(|_| format!("Invalid ENR TCP port: {}", enr_tcp_port_str))?, - ); - } - - if cli_args.is_present("enr-match") { - // set the enr address to localhost if the address is 0.0.0.0 - if client_config.network.listen_address - == "0.0.0.0".parse::().expect("valid ip addr") - { - client_config.network.enr_address = - Some("127.0.0.1".parse::().expect("valid ip addr")); - } else { - client_config.network.enr_address = Some(client_config.network.listen_address); - } - client_config.network.enr_udp_port = Some(client_config.network.discovery_port); - } - - if let Some(enr_address) = cli_args.value_of("enr-address") { - let resolved_addr = match enr_address.parse::() { - Ok(addr) => addr, // // Input is an IpAddr - Err(_) => { - let mut addr = enr_address.to_string(); - // Appending enr-port to the dns hostname to appease `to_socket_addrs()` parsing. - // Since enr-update is disabled with a dns address, not setting the enr-udp-port - // will make the node undiscoverable. - if let Some(enr_udp_port) = client_config.network.enr_udp_port { - addr.push_str(&format!(":{}", enr_udp_port.to_string())); - } else { - return Err( - "enr-udp-port must be set for node to be discoverable with dns address" - .into(), - ); - } - // `to_socket_addr()` does the dns resolution - // Note: `to_socket_addrs()` is a blocking call - let resolved_addr = if let Ok(mut resolved_addrs) = addr.to_socket_addrs() { - // Pick the first ip from the list of resolved addresses - resolved_addrs - .next() - .map(|a| a.ip()) - .ok_or_else(|| "Resolved dns addr contains no entries".to_string())? - } else { - return Err(format!("Failed to parse enr-address: {}", enr_address)); - }; - client_config.network.discv5_config.enr_update = false; - resolved_addr - } - }; - client_config.network.enr_address = Some(resolved_addr); - } - - if cli_args.is_present("disable_enr_auto_update") { - client_config.network.discv5_config.enr_update = false; - } - - if cli_args.is_present("disable-discovery") { - client_config.network.disable_discovery = true; - slog::warn!(log, "Discovery is disabled. New peers will not be found"); - } + set_network_config( + &mut client_config.network, + cli_args, + &client_config.data_dir, + &log, + false, + )?; /* * Http server @@ -399,6 +264,163 @@ pub fn get_config( Ok(client_config) } +/// Sets the network config from the command line arguments +pub fn set_network_config( + config: &mut NetworkConfig, + cli_args: &ArgMatches, + data_dir: &PathBuf, + log: &Logger, + use_listening_port_as_enr_port_by_default: bool, +) -> Result<(), String> { + // If a network dir has been specified, override the `datadir` definition. + if let Some(dir) = cli_args.value_of("network-dir") { + config.network_dir = PathBuf::from(dir); + } else { + config.network_dir = data_dir.join(NETWORK_DIR); + }; + + if let Some(listen_address_str) = cli_args.value_of("listen-address") { + let listen_address = listen_address_str + .parse() + .map_err(|_| format!("Invalid listen address: {:?}", listen_address_str))?; + config.listen_address = listen_address; + } + + if let Some(target_peers_str) = cli_args.value_of("target-peers") { + config.target_peers = target_peers_str + .parse::() + .map_err(|_| format!("Invalid number of target peers: {}", target_peers_str))?; + } + + if let Some(port_str) = cli_args.value_of("port") { + let port = port_str + .parse::() + .map_err(|_| format!("Invalid port: {}", port_str))?; + config.libp2p_port = port; + config.discovery_port = port; + } + + if let Some(port_str) = cli_args.value_of("discovery-port") { + let port = port_str + .parse::() + .map_err(|_| format!("Invalid port: {}", port_str))?; + config.discovery_port = port; + } + + if let Some(boot_enr_str) = cli_args.value_of("boot-nodes") { + let mut enrs: Vec = vec![]; + let mut multiaddrs: Vec = vec![]; + for addr in boot_enr_str.split(',') { + match addr.parse() { + Ok(enr) => enrs.push(enr), + Err(_) => { + // parsing as ENR failed, try as Multiaddr + let multi: Multiaddr = addr + .parse() + .map_err(|_| format!("Not valid as ENR nor Multiaddr: {}", addr))?; + if !multi.iter().any(|proto| matches!(proto, Protocol::Udp(_))) { + slog::error!(log, "Missing UDP in Multiaddr {}", multi.to_string()); + } + if !multi.iter().any(|proto| matches!(proto, Protocol::P2p(_))) { + slog::error!(log, "Missing P2P in Multiaddr {}", multi.to_string()); + } + multiaddrs.push(multi); + } + } + } + config.boot_nodes_enr = enrs; + config.boot_nodes_multiaddr = multiaddrs; + } + + if let Some(libp2p_addresses_str) = cli_args.value_of("libp2p-addresses") { + config.libp2p_nodes = libp2p_addresses_str + .split(',') + .map(|multiaddr| { + multiaddr + .parse() + .map_err(|_| format!("Invalid Multiaddr: {}", multiaddr)) + }) + .collect::, _>>()?; + } + + if let Some(enr_udp_port_str) = cli_args.value_of("enr-udp-port") { + config.enr_udp_port = Some( + enr_udp_port_str + .parse::() + .map_err(|_| format!("Invalid discovery port: {}", enr_udp_port_str))?, + ); + } + + if let Some(enr_tcp_port_str) = cli_args.value_of("enr-tcp-port") { + config.enr_tcp_port = Some( + enr_tcp_port_str + .parse::() + .map_err(|_| format!("Invalid ENR TCP port: {}", enr_tcp_port_str))?, + ); + } + + if cli_args.is_present("enr-match") { + // set the enr address to localhost if the address is 0.0.0.0 + if config.listen_address == "0.0.0.0".parse::().expect("valid ip addr") { + config.enr_address = Some("127.0.0.1".parse::().expect("valid ip addr")); + } else { + config.enr_address = Some(config.listen_address); + } + config.enr_udp_port = Some(config.discovery_port); + } + + if let Some(enr_address) = cli_args.value_of("enr-address") { + let resolved_addr = match enr_address.parse::() { + Ok(addr) => addr, // // Input is an IpAddr + Err(_) => { + let mut addr = enr_address.to_string(); + // Appending enr-port to the dns hostname to appease `to_socket_addrs()` parsing. + // Since enr-update is disabled with a dns address, not setting the enr-udp-port + // will make the node undiscoverable. + if let Some(enr_udp_port) = config.enr_udp_port.or_else(|| { + if use_listening_port_as_enr_port_by_default { + Some(config.discovery_port) + } else { + None + } + }) { + addr.push_str(&format!(":{}", enr_udp_port.to_string())); + } else { + return Err( + "enr-udp-port must be set for node to be discoverable with dns address" + .into(), + ); + } + // `to_socket_addr()` does the dns resolution + // Note: `to_socket_addrs()` is a blocking call + let resolved_addr = if let Ok(mut resolved_addrs) = addr.to_socket_addrs() { + // Pick the first ip from the list of resolved addresses + resolved_addrs + .next() + .map(|a| a.ip()) + .ok_or_else(|| "Resolved dns addr contains no entries".to_string())? + } else { + return Err(format!("Failed to parse enr-address: {}", enr_address)); + }; + config.discv5_config.enr_update = false; + resolved_addr + } + }; + config.enr_address = Some(resolved_addr); + } + + if cli_args.is_present("disable_enr_auto_update") { + config.discv5_config.enr_update = false; + } + + if cli_args.is_present("disable-discovery") { + config.disable_discovery = true; + slog::warn!(log, "Discovery is disabled. New peers will not be found"); + } + + Ok(()) +} + /// Gets the datadir which should be used. pub fn get_data_dir(cli_args: &ArgMatches) -> PathBuf { // Read the `--datadir` flag. diff --git a/beacon_node/src/lib.rs b/beacon_node/src/lib.rs index c3bce447ad9..cc143c44241 100644 --- a/beacon_node/src/lib.rs +++ b/beacon_node/src/lib.rs @@ -7,7 +7,7 @@ mod config; pub use beacon_chain; pub use cli::cli_app; pub use client::{Client, ClientBuilder, ClientConfig, ClientGenesis}; -pub use config::{get_data_dir, get_eth2_testnet_config}; +pub use config::{get_data_dir, get_eth2_testnet_config, set_network_config}; pub use eth2_config::Eth2Config; use beacon_chain::events::TeeEventHandler; diff --git a/boot_node/Cargo.toml b/boot_node/Cargo.toml index c7c8908990e..b1e1a81d7b3 100644 --- a/boot_node/Cargo.toml +++ b/boot_node/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Sigma Prime "] edition = "2018" [dependencies] +beacon_node = { path = "../beacon_node" } clap = "2.33.0" eth2_libp2p = { path = "../beacon_node/eth2_libp2p" } slog = "2.5.2" diff --git a/boot_node/src/cli.rs b/boot_node/src/cli.rs index db47bcf26eb..31d541c3083 100644 --- a/boot_node/src/cli.rs +++ b/boot_node/src/cli.rs @@ -12,7 +12,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { surface compared to a full beacon node.") .settings(&[clap::AppSettings::ColoredHelp]) .arg( - Arg::with_name("boot-node-enr-address") + Arg::with_name("enr-address") .value_name("IP-ADDRESS") .help("The external IP address/ DNS address to broadcast to other peers on how to reach this node. \ If a DNS address is provided, the enr-address is set to the IP address it resolves to and \ @@ -44,7 +44,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .takes_value(true), ) .arg( - Arg::with_name("enr-port") + Arg::with_name("enr-udp-port") .long("enr-port") .value_name("PORT") .help("The UDP port of the boot node's ENR. This is the port that external peers will dial to reach this boot node. Set this only if the external port differs from the listening port.") diff --git a/boot_node/src/config.rs b/boot_node/src/config.rs index 3d6570973a4..a08aed00cbb 100644 --- a/boot_node/src/config.rs +++ b/boot_node/src/config.rs @@ -1,7 +1,12 @@ +use beacon_node::{get_data_dir, set_network_config}; use clap::ArgMatches; use discv5::{enr::CombinedKey, Enr}; +use eth2_libp2p::{ + discovery::{create_enr_builder_from_config, use_or_load_enr}, + load_private_key, CombinedKeyExt, NetworkConfig, +}; use std::convert::TryFrom; -use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; +use std::net::SocketAddr; /// A set of configuration parameters for the bootnode, established from CLI arguments. pub struct BootNodeConfig { @@ -17,17 +22,22 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { type Error = String; fn try_from(matches: &ArgMatches<'_>) -> Result { - let listen_address = matches - .value_of("listen-address") - .expect("required parameter") - .parse::() - .map_err(|_| "Invalid listening address".to_string())?; + let data_dir = get_data_dir(matches); - let listen_port = matches - .value_of("port") - .expect("required parameter") - .parse::() - .map_err(|_| "Invalid listening port".to_string())?; + let mut network_config = NetworkConfig::default(); + + let logger = slog_scope::logger(); + + set_network_config(&mut network_config, matches, &data_dir, &logger, true)?; + + let private_key = load_private_key(&network_config, &logger); + let local_key = CombinedKey::from_libp2p(&private_key)?; + + let mut local_enr = create_enr_builder_from_config(&network_config) + .build(&local_key) + .map_err(|e| format!("Failed to build ENR: {:?}", e))?; + + use_or_load_enr(&local_key, &mut local_enr, &network_config, &logger)?; let boot_nodes = { if let Some(boot_nodes) = matches.value_of("boot-nodes") { @@ -40,34 +50,11 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { } }; - let enr_port = { - if let Some(port) = matches.value_of("boot-node-enr-port") { - port.parse::() - .map_err(|_| "Invalid ENR port".to_string())? - } else { - listen_port - } - }; - - let enr_address = { - let address_string = matches - .value_of("boot-node-enr-address") - .expect("required parameter"); - resolve_address(address_string.into(), enr_port)? - }; - let auto_update = matches.is_present("enable-enr_auto_update"); // the address to listen on - let listen_socket = SocketAddr::new(listen_address, enr_port); - - // Generate a new key and build a new ENR - let local_key = CombinedKey::generate_secp256k1(); - let local_enr = discv5::enr::EnrBuilder::new("v4") - .ip(enr_address) - .udp(enr_port) - .build(&local_key) - .map_err(|e| format!("Failed to build ENR: {:?}", e))?; + let listen_socket = + SocketAddr::new(network_config.listen_address, network_config.discovery_port); Ok(BootNodeConfig { listen_socket, @@ -78,25 +65,3 @@ impl TryFrom<&ArgMatches<'_>> for BootNodeConfig { }) } } - -/// Resolves an IP/DNS string to an IpAddr. -fn resolve_address(address_string: String, port: u16) -> Result { - match address_string.parse::() { - Ok(addr) => Ok(addr), // valid IpAddr - Err(_) => { - let mut addr = address_string.clone(); - // Appending enr-port to the dns hostname to appease `to_socket_addrs()` parsing. - addr.push_str(&format!(":{}", port.to_string())); - // `to_socket_addr()` does the dns resolution - // Note: `to_socket_addrs()` is a blocking call - addr.to_socket_addrs() - .map(|mut resolved_addrs| - // Pick the first ip from the list of resolved addresses - resolved_addrs - .next() - .map(|a| a.ip()) - .ok_or_else(|| "Resolved dns addr contains no entries".to_string())) - .map_err(|_| format!("Failed to parse enr-address: {}", address_string))? - } - } -}