From 2639e67e908b45d2b23208ca59f0ebdbbdbaff97 Mon Sep 17 00:00:00 2001 From: Divma <26765164+divagant-martian@users.noreply.github.com> Date: Tue, 13 Jun 2023 01:25:05 +0000 Subject: [PATCH] Update discv5 to expand ipv6 support (#4319) Done in different PRs so that they can reviewed independently, as it's likely this won't be merged before I leave Includes resolution for #4080 - [ ] #4299 - [ ] #4318 - [ ] #4320 Co-authored-by: Diva M Co-authored-by: Age Manning --- Cargo.lock | 294 ++++++++++++++---- beacon_node/lighthouse_network/Cargo.toml | 4 +- beacon_node/lighthouse_network/src/config.rs | 30 +- .../src/discovery/enr_ext.rs | 28 +- .../lighthouse_network/src/discovery/mod.rs | 39 +-- beacon_node/src/cli.rs | 2 - book/src/advanced_networking.md | 78 ++++- boot_node/src/cli.rs | 37 ++- boot_node/src/config.rs | 57 ++-- boot_node/src/server.rs | 6 +- common/eth2_network_config/Cargo.toml | 2 +- lighthouse/tests/boot_node.rs | 18 +- 12 files changed, 425 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f40e53c3..f53171aaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,6 +566,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" @@ -1377,6 +1383,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1472,11 +1490,12 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.1" +version = "4.0.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" dependencies = [ "cfg-if", + "digest 0.10.7", "fiat-crypto", "packed_simd_2", "platforms 3.0.2", @@ -1659,6 +1678,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "der-parser" version = "7.0.0" @@ -1805,6 +1834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] @@ -1861,15 +1891,15 @@ dependencies = [ [[package]] name = "discv5" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b009a99b85b58900df46435307fc5c4c845af7e182582b1fbf869572fa9fce69" +checksum = "77f32d27968ba86689e3f0eccba0383414348a6fc5918b0a639c98dd81e20ed6" dependencies = [ "aes 0.7.5", "aes-gcm 0.9.4", "arrayvec", "delay_map", - "enr 0.7.0", + "enr 0.8.1", "fnv", "futures", "hashlink 0.7.0", @@ -1885,8 +1915,6 @@ dependencies = [ "smallvec", "socket2 0.4.9", "tokio", - "tokio-stream", - "tokio-util 0.6.10", "tracing", "tracing-subscriber", "uint", @@ -1922,10 +1950,24 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +dependencies = [ + "der 0.7.6", + "digest 0.10.7", + "elliptic-curve 0.13.5", + "rfc6979 0.4.0", + "signature 2.1.0", + "spki 0.7.2", ] [[package]] @@ -1934,7 +1976,17 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.1.0", ] [[package]] @@ -1944,13 +1996,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.2.0", - "ed25519", + "ed25519 1.5.3", "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a" +dependencies = [ + "curve25519-dalek 4.0.0-rc.2", + "ed25519 2.2.1", + "rand_core 0.6.4", + "serde", + "sha2 0.10.6", + "zeroize", +] + [[package]] name = "ef_tests" version = "0.2.0" @@ -1994,18 +2060,37 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", - "der", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", "digest 0.10.7", - "ff", + "ff 0.12.1", "generic-array", - "group", + "group 0.12.1", "hkdf", "pem-rfc7468", - "pkcs8", + "pkcs8 0.9.0", "rand_core 0.6.4", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.2", + "digest 0.10.7", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.2", "subtle", "zeroize", ] @@ -2029,7 +2114,7 @@ dependencies = [ "bs58", "bytes", "hex", - "k256", + "k256 0.11.6", "log", "rand 0.8.5", "rlp", @@ -2040,16 +2125,15 @@ dependencies = [ [[package]] name = "enr" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "492a7e5fc2504d5fdce8e124d3e263b244a68b283cac67a69eda0cd43e0aebad" +checksum = "cf56acd72bb22d2824e66ae8e9e5ada4d0de17a69c7fd35569dde2ada8ec9116" dependencies = [ "base64 0.13.1", - "bs58", "bytes", - "ed25519-dalek", + "ed25519-dalek 2.0.0-rc.2", "hex", - "k256", + "k256 0.13.1", "log", "rand 0.8.5", "rlp", @@ -2545,11 +2629,11 @@ dependencies = [ "bytes", "cargo_metadata", "chrono", - "elliptic-curve", + "elliptic-curve 0.12.3", "ethabi 18.0.0", "generic-array", "hex", - "k256", + "k256 0.11.6", "once_cell", "open-fastrlp", "rand 0.8.5", @@ -2731,6 +2815,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ffi-opaque" version = "2.0.1" @@ -3009,6 +3103,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -3118,7 +3213,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] @@ -3855,12 +3961,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if", - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.6", "sha3 0.10.8", ] +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa 0.16.7", + "elliptic-curve 0.13.5", + "once_cell", + "sha2 0.10.6", + "signature 2.1.0", +] + [[package]] name = "keccak" version = "0.1.4" @@ -4059,7 +4179,7 @@ checksum = "b1fff5bd889c82a0aec668f2045edd066f559d4e5c40354e5a4c77ac00caac38" dependencies = [ "asn1_der", "bs58", - "ed25519-dalek", + "ed25519-dalek 1.0.1", "either", "fnv", "futures", @@ -4094,7 +4214,7 @@ checksum = "b6a8fcd392ff67af6cc3f03b1426c41f7f26b6b9aff2dc632c1c56dd649e571f" dependencies = [ "asn1_der", "bs58", - "ed25519-dalek", + "ed25519-dalek 1.0.1", "either", "fnv", "futures", @@ -4113,7 +4233,7 @@ dependencies = [ "prost-build", "rand 0.8.5", "rw-stream-sink", - "sec1", + "sec1 0.3.0", "sha2 0.10.6", "smallvec", "thiserror", @@ -4222,7 +4342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1" dependencies = [ "bs58", - "ed25519-dalek", + "ed25519-dalek 1.0.1", "log", "multiaddr 0.17.1", "multihash 0.17.0", @@ -5654,8 +5774,8 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.6", ] @@ -5665,8 +5785,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.6", ] @@ -5922,8 +6042,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", - "spki", + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.6", + "spki 0.7.2", ] [[package]] @@ -6666,11 +6796,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac 0.12.1", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -7047,10 +7187,24 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", - "der", + "base16ct 0.1.1", + "der 0.6.1", "generic-array", - "pkcs8", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.6", + "generic-array", + "pkcs8 0.10.2", "subtle", "zeroize", ] @@ -7339,6 +7493,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "simple_asn1" version = "0.6.2" @@ -7576,14 +7740,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" +checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-rc.1", + "curve25519-dalek 4.0.0-rc.2", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -7640,7 +7804,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der 0.7.6", ] [[package]] @@ -9358,9 +9532,9 @@ dependencies = [ [[package]] name = "webrtc-dtls" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942be5bd85f072c3128396f6e5a9bfb93ca8c1939ded735d177b7bcba9a13d05" +checksum = "c4a00f4242f2db33307347bd5be53263c52a0331c96c14292118c9a6bb48d267" dependencies = [ "aes 0.6.0", "aes-gcm 0.10.2", @@ -9371,29 +9545,28 @@ dependencies = [ "ccm", "curve25519-dalek 3.2.0", "der-parser 8.2.0", - "elliptic-curve", + "elliptic-curve 0.12.3", "hkdf", "hmac 0.12.1", "log", - "oid-registry 0.6.1", "p256", "p384", "rand 0.8.5", "rand_core 0.6.4", - "rcgen 0.9.3", + "rcgen 0.10.0", "ring", "rustls 0.19.1", - "sec1", + "sec1 0.3.0", "serde", "sha1", "sha2 0.10.6", - "signature", + "signature 1.6.4", "subtle", "thiserror", "tokio", "webpki 0.21.4", "webrtc-util", - "x25519-dalek 2.0.0-pre.1", + "x25519-dalek 2.0.0-rc.2", "x509-parser 0.13.2", ] @@ -9836,12 +10009,13 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0-pre.1" +version = "2.0.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" +checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95" dependencies = [ - "curve25519-dalek 3.2.0", + "curve25519-dalek 4.0.0-rc.2", "rand_core 0.6.4", + "serde", "zeroize", ] diff --git a/beacon_node/lighthouse_network/Cargo.toml b/beacon_node/lighthouse_network/Cargo.toml index c1b4d7217..ca15b5ef2 100644 --- a/beacon_node/lighthouse_network/Cargo.toml +++ b/beacon_node/lighthouse_network/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Sigma Prime "] edition = "2021" [dependencies] -discv5 = { version = "0.2.2", features = ["libp2p"] } +discv5 = { version = "0.3.0", features = ["libp2p"]} unsigned-varint = { version = "0.6.0", features = ["codec"] } types = { path = "../../consensus/types" } ssz_types = "0.5.0" @@ -60,4 +60,4 @@ quickcheck = "0.9.2" quickcheck_macros = "0.9.1" [features] -libp2p-websocket = [] +libp2p-websocket = [] \ No newline at end of file diff --git a/beacon_node/lighthouse_network/src/config.rs b/beacon_node/lighthouse_network/src/config.rs index 01bb8569d..946752645 100644 --- a/beacon_node/lighthouse_network/src/config.rs +++ b/beacon_node/lighthouse_network/src/config.rs @@ -163,7 +163,7 @@ impl Config { udp_port, tcp_port, }); - self.discv5_config.ip_mode = discv5::IpMode::Ip4; + self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port); self.discv5_config.table_filter = |enr| enr.ip4().as_ref().map_or(false, is_global_ipv4) } @@ -176,9 +176,8 @@ impl Config { udp_port, tcp_port, }); - self.discv5_config.ip_mode = discv5::IpMode::Ip6 { - enable_mapped_addresses: false, - }; + + self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port); self.discv5_config.table_filter = |enr| enr.ip6().as_ref().map_or(false, is_global_ipv6) } @@ -206,10 +205,10 @@ impl Config { tcp_port: tcp6_port, }, ); + self.discv5_config.listen_config = discv5::ListenConfig::default() + .with_ipv4(v4_addr, udp4_port) + .with_ipv6(v6_addr, udp6_port); - self.discv5_config.ip_mode = discv5::IpMode::Ip6 { - enable_mapped_addresses: true, - }; self.discv5_config.table_filter = |enr| match (&enr.ip4(), &enr.ip6()) { (None, None) => false, (None, Some(ip6)) => is_global_ipv6(ip6), @@ -279,9 +278,17 @@ impl Default for Config { .build() .expect("The total rate limit has been specified"), ); + let listen_addresses = ListenAddress::V4(ListenAddr { + addr: Ipv4Addr::UNSPECIFIED, + udp_port: 9000, + tcp_port: 9000, + }); + + let discv5_listen_config = + discv5::ListenConfig::from_ip(Ipv4Addr::UNSPECIFIED.into(), 9000); // discv5 configuration - let discv5_config = Discv5ConfigBuilder::new() + let discv5_config = Discv5ConfigBuilder::new(discv5_listen_config) .enable_packet_filter() .session_cache_capacity(5000) .request_timeout(Duration::from_secs(1)) @@ -304,12 +311,9 @@ impl Default for Config { // NOTE: Some of these get overridden by the corresponding CLI default values. Config { network_dir, - listen_addresses: ListenAddress::V4(ListenAddr { - addr: Ipv4Addr::UNSPECIFIED, - udp_port: 9000, - tcp_port: 9000, - }), + listen_addresses, enr_address: (None, None), + enr_udp4_port: None, enr_tcp4_port: None, enr_udp6_port: None, diff --git a/beacon_node/lighthouse_network/src/discovery/enr_ext.rs b/beacon_node/lighthouse_network/src/discovery/enr_ext.rs index e9cca6667..3df7f7c16 100644 --- a/beacon_node/lighthouse_network/src/discovery/enr_ext.rs +++ b/beacon_node/lighthouse_network/src/discovery/enr_ext.rs @@ -198,7 +198,7 @@ impl CombinedKeyPublicExt for CombinedPublicKey { fn as_peer_id(&self) -> PeerId { match self { Self::Secp256k1(pk) => { - let pk_bytes = pk.to_bytes(); + let pk_bytes = pk.to_sec1_bytes(); let libp2p_pk = libp2p::core::PublicKey::Secp256k1( libp2p::core::identity::secp256k1::PublicKey::decode(&pk_bytes) .expect("valid public key"), @@ -222,14 +222,16 @@ impl CombinedKeyExt for CombinedKey { match key { Keypair::Secp256k1(key) => { let secret = - discv5::enr::k256::ecdsa::SigningKey::from_bytes(&key.secret().to_bytes()) + discv5::enr::k256::ecdsa::SigningKey::from_slice(&key.secret().to_bytes()) .expect("libp2p key must be valid"); Ok(CombinedKey::Secp256k1(secret)) } Keypair::Ed25519(key) => { - let ed_keypair = - discv5::enr::ed25519_dalek::SecretKey::from_bytes(&key.encode()[..32]) - .expect("libp2p key must be valid"); + let ed_keypair = discv5::enr::ed25519_dalek::SigningKey::from_bytes( + &(key.encode()[..32]) + .try_into() + .expect("libp2p key must be valid"), + ); Ok(CombinedKey::from(ed_keypair)) } Keypair::Ecdsa(_) => Err("Ecdsa keypairs not supported"), @@ -281,7 +283,7 @@ mod tests { fn test_secp256k1_peer_id_conversion() { let sk_hex = "df94a73d528434ce2309abb19c16aedb535322797dbd59c157b1e04095900f48"; let sk_bytes = hex::decode(sk_hex).unwrap(); - let secret_key = discv5::enr::k256::ecdsa::SigningKey::from_bytes(&sk_bytes).unwrap(); + let secret_key = discv5::enr::k256::ecdsa::SigningKey::from_slice(&sk_bytes).unwrap(); let libp2p_sk = libp2p::identity::secp256k1::SecretKey::from_bytes(sk_bytes).unwrap(); let secp256k1_kp: libp2p::identity::secp256k1::Keypair = libp2p_sk.into(); @@ -300,16 +302,18 @@ mod tests { fn test_ed25519_peer_conversion() { let sk_hex = "4dea8a5072119927e9d243a7d953f2f4bc95b70f110978e2f9bc7a9000e4b261"; let sk_bytes = hex::decode(sk_hex).unwrap(); - let secret = discv5::enr::ed25519_dalek::SecretKey::from_bytes(&sk_bytes).unwrap(); - let public = discv5::enr::ed25519_dalek::PublicKey::from(&secret); - let keypair = discv5::enr::ed25519_dalek::Keypair { secret, public }; + let secret_key = discv5::enr::ed25519_dalek::SigningKey::from_bytes( + &sk_bytes.clone().try_into().unwrap(), + ); let libp2p_sk = libp2p::identity::ed25519::SecretKey::from_bytes(sk_bytes).unwrap(); - let ed25519_kp: libp2p::identity::ed25519::Keypair = libp2p_sk.into(); - let libp2p_kp = Keypair::Ed25519(ed25519_kp); + let secp256k1_kp: libp2p::identity::ed25519::Keypair = libp2p_sk.into(); + let libp2p_kp = Keypair::Ed25519(secp256k1_kp); let peer_id = libp2p_kp.public().to_peer_id(); - let enr = discv5::enr::EnrBuilder::new("v4").build(&keypair).unwrap(); + let enr = discv5::enr::EnrBuilder::new("v4") + .build(&secret_key) + .unwrap(); let node_id = peer_id_to_node_id(&peer_id).unwrap(); assert_eq!(enr.node_id(), node_id); diff --git a/beacon_node/lighthouse_network/src/discovery/mod.rs b/beacon_node/lighthouse_network/src/discovery/mod.rs index 13fdf8ed5..3ee74ebf0 100644 --- a/beacon_node/lighthouse_network/src/discovery/mod.rs +++ b/beacon_node/lighthouse_network/src/discovery/mod.rs @@ -209,13 +209,6 @@ impl Discovery { info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> %local_enr.node_id(), "ip4" => ?local_enr.ip4(), "udp4"=> ?local_enr.udp4(), "tcp4" => ?local_enr.tcp4(), "tcp6" => ?local_enr.tcp6(), "udp6" => ?local_enr.udp6() ); - let listen_socket = match config.listen_addrs() { - crate::listen_addr::ListenAddress::V4(v4_addr) => v4_addr.udp_socket_addr(), - crate::listen_addr::ListenAddress::V6(v6_addr) => v6_addr.udp_socket_addr(), - crate::listen_addr::ListenAddress::DualStack(_v4_addr, v6_addr) => { - v6_addr.udp_socket_addr() - } - }; // convert the keypair into an ENR key let enr_key: CombinedKey = CombinedKey::from_libp2p(local_key)?; @@ -251,10 +244,7 @@ impl Discovery { // Start the discv5 service and obtain an event stream let event_stream = if !config.disable_discovery { - discv5 - .start(listen_socket) - .map_err(|e| e.to_string()) - .await?; + discv5.start().map_err(|e| e.to_string()).await?; debug!(log, "Discovery service started"); EventStream::Awaiting(Box::pin(discv5.event_stream())) } else { @@ -413,7 +403,7 @@ impl Discovery { /// If the external address needs to be modified, use `update_enr_udp_socket. pub fn update_enr_tcp_port(&mut self, port: u16) -> Result<(), String> { self.discv5 - .enr_insert("tcp", &port.to_be_bytes()) + .enr_insert("tcp", &port) .map_err(|e| format!("{:?}", e))?; // replace the global version @@ -428,29 +418,12 @@ impl Discovery { /// This is with caution. Discovery should automatically maintain this. This should only be /// used when automatic discovery is disabled. pub fn update_enr_udp_socket(&mut self, socket_addr: SocketAddr) -> Result<(), String> { - match socket_addr { - SocketAddr::V4(socket) => { - self.discv5 - .enr_insert("ip", &socket.ip().octets()) - .map_err(|e| format!("{:?}", e))?; - self.discv5 - .enr_insert("udp", &socket.port().to_be_bytes()) - .map_err(|e| format!("{:?}", e))?; - } - SocketAddr::V6(socket) => { - self.discv5 - .enr_insert("ip6", &socket.ip().octets()) - .map_err(|e| format!("{:?}", e))?; - self.discv5 - .enr_insert("udp6", &socket.port().to_be_bytes()) - .map_err(|e| format!("{:?}", e))?; - } + const IS_TCP: bool = false; + if self.discv5.update_local_enr_socket(socket_addr, IS_TCP) { + // persist modified enr to disk + enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log); } - - // replace the global version *self.network_globals.local_enr.write() = self.discv5.local_enr(); - // persist modified enr to disk - enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log); Ok(()) } diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 379eb8e33..e763d93f8 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -116,7 +116,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .value_name("PORT") .help("The UDP port that discovery will listen on over IpV6 if listening over \ both Ipv4 and IpV6. Defaults to `port6`") - .hidden(true) // TODO: implement dual stack via two sockets in discv5. .takes_value(true), ) .arg( @@ -198,7 +197,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { discovery. Set this only if you are sure other nodes can connect to your \ local node on this address. This will update the `ip4` or `ip6` ENR fields \ accordingly. To update both, set this flag twice with the different values.") - .requires("enr-udp-port") .multiple(true) .max_values(2) .takes_value(true), diff --git a/book/src/advanced_networking.md b/book/src/advanced_networking.md index 59f3da376..586503cb9 100644 --- a/book/src/advanced_networking.md +++ b/book/src/advanced_networking.md @@ -38,7 +38,6 @@ large peer count will not speed up sync. For these reasons, we recommend users do not modify the `--target-peers` count drastically and use the (recommended) default. - ### NAT Traversal (Port Forwarding) Lighthouse, by default, uses port 9000 for both TCP and UDP. Lighthouse will @@ -55,7 +54,7 @@ enabled, we recommend you to manually set up port mappings to both of Lighthouse 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. +> 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 @@ -107,3 +106,78 @@ Modifying the ENR settings can degrade the discovery of your node, making it harder for peers to find you or potentially making it harder for other peers to find each other. We recommend not touching these settings unless for a more advanced use case. + + +### IPv6 support + +As noted in the previous sections, two fundamental parts to ensure good +connectivity are: The parameters that configure the sockets over which +Lighthouse listens for connections, and the parameters used to tell other peers +how to connect to your node. This distinction is relevant and applies to most +nodes that do not run directly on a public network. + +#### Configuring Lighthouse to listen over IPv4/IPv6/Dual stack + +To listen over only IPv6 use the same parameters as done when listening over +IPv4 only: + +- `--listen-addresses :: --port 9909` will listen over IPv6 using port `9909` for +TCP and UDP. +- `--listen-addresses :: --port 9909 --discovery-port 9999` will listen over + IPv6 using port `9909` for TCP and port `9999` for UDP. + +To listen over both IPv4 and IPv6: +- Set two listening addresses using the `--listen-addresses` flag twice ensuring + the two addresses are one IPv4, and the other IPv6. When doing so, the + `--port` and `--discovery-port` flags will apply exclusively to IPv4. Note + that this behaviour differs from the Ipv6 only case described above. +- If necessary, set the `--port6` flag to configure the port used for TCP and + UDP over IPv6. This flag has no effect when listening over IPv6 only. +- If necessary, set the `--discovery-port6` flag to configure the IPv6 UDP + port. This will default to the value given to `--port6` if not set. This flag + has no effect when listening over IPv6 only. + +##### Configuration Examples + +- `--listen-addresses :: --listen-addresses 0.0.0.0 --port 9909` will listen + over IPv4 using port `9909` for TCP and UDP. It will also listen over IPv6 but + using the default value for `--port6` for UDP and TCP (`9090`). +- `--listen-addresses :: --listen-addresses --port 9909 --discovery-port6 9999` + will have the same configuration as before except for the IPv6 UDP socket, + which will use port `9999`. + +#### Configuring Lighthouse to advertise IPv6 reachable addresses +Lighthouse supports IPv6 to connect to other nodes both over IPv6 exclusively, +and dual stack using one socket for IPv6 and another socket for IPv6. In both +scenarios, the previous sections still apply. In summary: + +> Beacon nodes must advertise their publicly reachable socket address + +In order to do so, lighthouse provides the following CLI options/parameters. + +- `--enr-udp-port` Use this to advertise the port that is publicly reachable + over UDP with a publicly reachable IPv4 address. This might differ from the + IPv4 port used to listen. +- `--enr-udp6-port` Use this to advertise the port that is publicly reachable + over UDP with a publicly reachable IPv6 address. This might differ from the + IPv6 port used to listen. +- `--enr-tcp-port` Use this to advertise the port that is publicly reachable + over TCP with a publicly reachable IPv4 address. This might differ from the + IPv4 port used to listen. +- `--enr-tcp6-port` Use this to advertise the port that is publicly reachable + over TCP with a publicly reachable IPv6 address. This might differ from the + IPv6 port used to listen. +- `--enr-addresses` Use this to advertise publicly reachable addresses. Takes at + most two values, one for IPv4 and one for IPv6. Note that a beacon node that + advertises some address, must be + reachable both over UDP and TCP. + +In the general case, an user will not require to set these explicitly. Update +these options only if you can guarantee your node is reachable with these +values. + +#### Known caveats + +IPv6 link local addresses are likely to have poor connectivity if used in +topologies with more than one interface. Use global addresses for the general +case. diff --git a/boot_node/src/cli.rs b/boot_node/src/cli.rs index c3d7ac48a..b13f47f75 100644 --- a/boot_node/src/cli.rs +++ b/boot_node/src/cli.rs @@ -13,13 +13,19 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .settings(&[clap::AppSettings::ColoredHelp]) .arg( 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 \ - does not auto-update based on PONG responses in discovery.") + .long("enr-address") + .value_name("ADDRESS") + .help("The 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 does not auto-update based on PONG responses in \ + discovery. Set this only if you are sure other nodes can connect to your \ + local node on this address. This will update the `ip4` or `ip6` ENR fields \ + accordingly. To update both, set this flag twice with the different values.") + .multiple(true) + .max_values(2) .required(true) - .takes_value(true) .conflicts_with("network-dir") + .takes_value(true), ) .arg( Arg::with_name("port") @@ -29,11 +35,29 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .default_value("9000") .takes_value(true) ) + .arg( + Arg::with_name("port6") + .long("port6") + .value_name("PORT") + .help("The UDP port to listen on over IpV6 when listening over both Ipv4 and \ + Ipv6. Defaults to 9090 when required.") + .default_value("9090") + .takes_value(true), + ) .arg( Arg::with_name("listen-address") .long("listen-address") .value_name("ADDRESS") - .help("The address the bootnode will listen for UDP connections.") + .help("The address the bootnode will listen for UDP communications. To listen \ + over IpV4 and IpV6 set this flag twice with the different values.\n\ + Examples:\n\ + - --listen-address '0.0.0.0' will listen over Ipv4.\n\ + - --listen-address '::' will listen over Ipv6.\n\ + - --listen-address '0.0.0.0' --listen-address '::' will listen over both \ + Ipv4 and Ipv6. The order of the given addresses is not relevant. However, \ + multiple Ipv4, or multiple Ipv6 addresses will not be accepted.") + .multiple(true) + .max_values(2) .default_value("0.0.0.0") .takes_value(true) ) @@ -59,6 +83,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .value_name("PORT") .help("The UDP6 port of the local ENR. Set this only if you are sure other nodes \ can connect to your local node on this port over IpV6.") + .conflicts_with("network-dir") .takes_value(true), ) .arg( diff --git a/boot_node/src/config.rs b/boot_node/src/config.rs index d3ee58a90..c4e36022a 100644 --- a/boot_node/src/config.rs +++ b/boot_node/src/config.rs @@ -2,7 +2,6 @@ use beacon_node::{get_data_dir, set_network_config}; use clap::ArgMatches; use eth2_network_config::Eth2NetworkConfig; use lighthouse_network::discovery::create_enr_builder_from_config; -use lighthouse_network::discv5::IpMode; use lighthouse_network::discv5::{enr::CombinedKey, Discv5Config, Enr}; use lighthouse_network::{ discovery::{load_enr_from_disk, use_or_load_enr}, @@ -10,13 +9,12 @@ use lighthouse_network::{ }; use serde_derive::{Deserialize, Serialize}; use ssz::Encode; -use std::net::SocketAddr; +use std::net::{SocketAddrV4, SocketAddrV6}; use std::{marker::PhantomData, path::PathBuf}; use types::EthSpec; /// A set of configuration parameters for the bootnode, established from CLI arguments. pub struct BootNodeConfig { - pub listen_socket: SocketAddr, // TODO: Generalise to multiaddr pub boot_nodes: Vec, pub local_enr: Enr, @@ -81,31 +79,6 @@ impl BootNodeConfig { network_config.discv5_config.enr_update = false; } - // the address to listen on - let listen_socket = match network_config.listen_addrs().clone() { - lighthouse_network::ListenAddress::V4(v4_addr) => { - // Set explicitly as ipv4 otherwise - network_config.discv5_config.ip_mode = IpMode::Ip4; - v4_addr.udp_socket_addr() - } - lighthouse_network::ListenAddress::V6(v6_addr) => { - // create ipv6 sockets and enable ipv4 mapped addresses. - network_config.discv5_config.ip_mode = IpMode::Ip6 { - enable_mapped_addresses: false, - }; - - v6_addr.udp_socket_addr() - } - lighthouse_network::ListenAddress::DualStack(_v4_addr, v6_addr) => { - // create ipv6 sockets and enable ipv4 mapped addresses. - network_config.discv5_config.ip_mode = IpMode::Ip6 { - enable_mapped_addresses: true, - }; - - v6_addr.udp_socket_addr() - } - }; - let private_key = load_private_key(&network_config, &logger); let local_key = CombinedKey::from_libp2p(&private_key)?; @@ -143,7 +116,7 @@ impl BootNodeConfig { let mut builder = create_enr_builder_from_config(&network_config, enable_tcp); // If we know of the ENR field, add it to the initial construction if let Some(enr_fork_bytes) = enr_fork { - builder.add_value("eth2", enr_fork_bytes.as_slice()); + builder.add_value("eth2", &enr_fork_bytes); } builder .build(&local_key) @@ -155,7 +128,6 @@ impl BootNodeConfig { }; Ok(BootNodeConfig { - listen_socket, boot_nodes, local_enr, local_key, @@ -170,7 +142,8 @@ impl BootNodeConfig { /// Its fields are a subset of the fields of `BootNodeConfig`, some of them are copied from `Discv5Config`. #[derive(Serialize, Deserialize)] pub struct BootNodeConfigSerialization { - pub listen_socket: SocketAddr, + pub ipv4_listen_socket: Option, + pub ipv6_listen_socket: Option, // TODO: Generalise to multiaddr pub boot_nodes: Vec, pub local_enr: Enr, @@ -183,7 +156,6 @@ impl BootNodeConfigSerialization { /// relevant fields of `config` pub fn from_config_ref(config: &BootNodeConfig) -> Self { let BootNodeConfig { - listen_socket, boot_nodes, local_enr, local_key: _, @@ -191,8 +163,27 @@ impl BootNodeConfigSerialization { phantom: _, } = config; + let (ipv4_listen_socket, ipv6_listen_socket) = match discv5_config.listen_config { + lighthouse_network::discv5::ListenConfig::Ipv4 { ip, port } => { + (Some(SocketAddrV4::new(ip, port)), None) + } + lighthouse_network::discv5::ListenConfig::Ipv6 { ip, port } => { + (None, Some(SocketAddrV6::new(ip, port, 0, 0))) + } + lighthouse_network::discv5::ListenConfig::DualStack { + ipv4, + ipv4_port, + ipv6, + ipv6_port, + } => ( + Some(SocketAddrV4::new(ipv4, ipv4_port)), + Some(SocketAddrV6::new(ipv6, ipv6_port, 0, 0)), + ), + }; + BootNodeConfigSerialization { - listen_socket: *listen_socket, + ipv4_listen_socket, + ipv6_listen_socket, boot_nodes: boot_nodes.clone(), local_enr: local_enr.clone(), disable_packet_filter: !discv5_config.enable_packet_filter, diff --git a/boot_node/src/server.rs b/boot_node/src/server.rs index 3f5419c2c..3823b2872 100644 --- a/boot_node/src/server.rs +++ b/boot_node/src/server.rs @@ -10,7 +10,6 @@ use types::EthSpec; pub async fn run(config: BootNodeConfig, log: slog::Logger) { let BootNodeConfig { - listen_socket, boot_nodes, local_enr, local_key, @@ -31,7 +30,7 @@ pub async fn run(config: BootNodeConfig, log: slog::Logger) { let pretty_v6_socket = enr_v6_socket.as_ref().map(|addr| addr.to_string()); info!( log, "Configuration parameters"; - "listening_address" => %listen_socket, + "listening_address" => ?discv5_config.listen_config, "advertised_v4_address" => ?pretty_v4_socket, "advertised_v6_address" => ?pretty_v6_socket, "eth2" => eth2_field @@ -41,6 +40,7 @@ pub async fn run(config: BootNodeConfig, log: slog::Logger) { // build the contactable multiaddr list, adding the p2p protocol info!(log, "Contact information"; "enr" => local_enr.to_base64()); + info!(log, "Enr details"; "enr" => ?local_enr); info!(log, "Contact information"; "multiaddrs" => ?local_enr.multiaddr_p2p()); // construct the discv5 server @@ -64,7 +64,7 @@ pub async fn run(config: BootNodeConfig, log: slog::Logger) { } // start the server - if let Err(e) = discv5.start(listen_socket).await { + if let Err(e) = discv5.start().await { slog::crit!(log, "Could not start discv5 server"; "error" => %e); return; } diff --git a/common/eth2_network_config/Cargo.toml b/common/eth2_network_config/Cargo.toml index f8382c95d..296d43b1a 100644 --- a/common/eth2_network_config/Cargo.toml +++ b/common/eth2_network_config/Cargo.toml @@ -18,4 +18,4 @@ serde_yaml = "0.8.13" types = { path = "../../consensus/types"} ethereum_ssz = "0.5.0" eth2_config = { path = "../eth2_config"} -discv5 = "0.2.2" +discv5 = "0.3.0" \ No newline at end of file diff --git a/lighthouse/tests/boot_node.rs b/lighthouse/tests/boot_node.rs index 4dd5ad95d..659dea468 100644 --- a/lighthouse/tests/boot_node.rs +++ b/lighthouse/tests/boot_node.rs @@ -39,7 +39,7 @@ impl CommandLineTest { } fn run_with_ip(&mut self) -> CompletedTest { - self.cmd.arg(IP_ADDRESS); + self.cmd.arg("--enr-address").arg(IP_ADDRESS); self.run() } } @@ -67,7 +67,13 @@ fn port_flag() { .flag("port", Some(port.to_string().as_str())) .run_with_ip() .with_config(|config| { - assert_eq!(config.listen_socket.port(), port); + assert_eq!( + config + .ipv4_listen_socket + .expect("Bootnode should be listening on IPv4") + .port(), + port + ); }) } @@ -78,7 +84,13 @@ fn listen_address_flag() { .flag("listen-address", Some("127.0.0.2")) .run_with_ip() .with_config(|config| { - assert_eq!(config.listen_socket.ip(), addr); + assert_eq!( + config + .ipv4_listen_socket + .expect("Bootnode should be listening on IPv4") + .ip(), + &addr + ); }); }