Silky smooth discovery (#1274)
* Initial structural re-write * Improving discovery update and correcting attestation service logic * Rework discovery.mod * Handling lifetimes of query futures * Discovery update first draft * format fixes * Stabalise discv5 update * Formatting corrections * Limit FindPeers queries and bug correction * Update to stable release discv5 * Remove unnecessary pin * formatting
This commit is contained in:
parent
06a72614cb
commit
e379ad0f4e
282
Cargo.lock
generated
282
Cargo.lock
generated
@ -41,9 +41,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||
checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d"
|
||||
|
||||
[[package]]
|
||||
name = "aes-ctr"
|
||||
@ -132,9 +132,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62"
|
||||
checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
@ -225,13 +225,14 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.48"
|
||||
version = "0.3.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130"
|
||||
checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
@ -260,9 +261,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42"
|
||||
checksum = "e223af0dc48c96d4f8342ec01a4974f139df863896b316681efd36742f22cc67"
|
||||
|
||||
[[package]]
|
||||
name = "beacon_chain"
|
||||
@ -320,8 +321,8 @@ dependencies = [
|
||||
"ctrlc",
|
||||
"dirs",
|
||||
"environment",
|
||||
"eth2-libp2p",
|
||||
"eth2_config",
|
||||
"eth2_libp2p",
|
||||
"eth2_ssz",
|
||||
"eth2_testnet_config",
|
||||
"exit-future",
|
||||
@ -621,8 +622,8 @@ dependencies = [
|
||||
"environment",
|
||||
"error-chain",
|
||||
"eth1",
|
||||
"eth2-libp2p",
|
||||
"eth2_config",
|
||||
"eth2_libp2p",
|
||||
"eth2_ssz",
|
||||
"futures 0.3.5",
|
||||
"genesis",
|
||||
@ -843,12 +844,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2"
|
||||
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -990,9 +992,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.7"
|
||||
version = "0.99.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2127768764f1556535c01b5326ef94bd60ff08dcfbdc544d53e69ed155610f5d"
|
||||
checksum = "bc655351f820d774679da6cdc23355a93de496867d8203496675162e17b1d671"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1020,11 +1022,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi 0.3.8",
|
||||
@ -1038,8 +1039,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "discv5"
|
||||
version = "0.1.0-alpha.2"
|
||||
source = "git+https://github.com/sigp/discv5?rev=7b3bd40591b62b8c002ffdb85de008aa9f82e2e5#7b3bd40591b62b8c002ffdb85de008aa9f82e2e5"
|
||||
version = "0.1.0-alpha.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66319abef3e2f4dc434bf0c9bcb5dee5907d7fece3327dfd7da82db905d02441"
|
||||
dependencies = [
|
||||
"arrayvec 0.5.1",
|
||||
"digest",
|
||||
@ -1048,10 +1050,15 @@ dependencies = [
|
||||
"futures 0.3.5",
|
||||
"hex 0.4.2",
|
||||
"hkdf",
|
||||
"lazy_static",
|
||||
"libp2p-core",
|
||||
"libsecp256k1",
|
||||
"log 0.4.8",
|
||||
"lru_time_cache",
|
||||
"multihash",
|
||||
"net2",
|
||||
"openssl",
|
||||
"parking_lot 0.10.2",
|
||||
"rand 0.7.3",
|
||||
"rlp",
|
||||
"sha2",
|
||||
@ -1069,9 +1076,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
|
||||
checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
@ -1129,7 +1136,7 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3cd1bccf1bd78eee44d89c0f81b60008b40153db2b99c0fc01abf353781e13"
|
||||
dependencies = [
|
||||
"base64 0.12.1",
|
||||
"base64 0.12.2",
|
||||
"bs58",
|
||||
"ed25519-dalek",
|
||||
"hex 0.4.2",
|
||||
@ -1160,6 +1167,7 @@ name = "environment"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"ctrlc",
|
||||
"discv5",
|
||||
"eth2_config",
|
||||
"eth2_testnet_config",
|
||||
"exit-future",
|
||||
@ -1228,49 +1236,6 @@ dependencies = [
|
||||
"web3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eth2-libp2p"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"base64 0.12.1",
|
||||
"dirs",
|
||||
"discv5",
|
||||
"environment",
|
||||
"error-chain",
|
||||
"eth2_ssz",
|
||||
"eth2_ssz_derive",
|
||||
"eth2_ssz_types",
|
||||
"exit-future",
|
||||
"fnv",
|
||||
"futures 0.3.5",
|
||||
"hashset_delay",
|
||||
"hex 0.4.2",
|
||||
"lazy_static",
|
||||
"libp2p",
|
||||
"libp2p-tcp",
|
||||
"lighthouse_metrics",
|
||||
"lru 0.5.1",
|
||||
"parking_lot 0.10.2",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sha2",
|
||||
"slog",
|
||||
"slog-async",
|
||||
"slog-stdlog",
|
||||
"slog-term",
|
||||
"smallvec 1.4.0",
|
||||
"snap",
|
||||
"tempdir",
|
||||
"tiny-keccak 2.0.2",
|
||||
"tokio 0.2.21",
|
||||
"tokio-io-timeout",
|
||||
"tokio-util",
|
||||
"types",
|
||||
"unsigned-varint 0.3.3 (git+https://github.com/sigp/unsigned-varint?branch=latest-codecs)",
|
||||
"version",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eth2_config"
|
||||
version = "0.2.0"
|
||||
@ -1296,7 +1261,7 @@ dependencies = [
|
||||
name = "eth2_interop_keypairs"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"base64 0.12.1",
|
||||
"base64 0.12.2",
|
||||
"eth2_hashing",
|
||||
"hex 0.4.2",
|
||||
"lazy_static",
|
||||
@ -1335,6 +1300,49 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eth2_libp2p"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"base64 0.12.2",
|
||||
"dirs",
|
||||
"discv5",
|
||||
"environment",
|
||||
"error-chain",
|
||||
"eth2_ssz",
|
||||
"eth2_ssz_derive",
|
||||
"eth2_ssz_types",
|
||||
"exit-future",
|
||||
"fnv",
|
||||
"futures 0.3.5",
|
||||
"hashset_delay",
|
||||
"hex 0.4.2",
|
||||
"lazy_static",
|
||||
"libp2p",
|
||||
"libp2p-tcp",
|
||||
"lighthouse_metrics",
|
||||
"lru 0.5.1",
|
||||
"parking_lot 0.10.2",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sha2",
|
||||
"slog",
|
||||
"slog-async",
|
||||
"slog-stdlog",
|
||||
"slog-term",
|
||||
"smallvec 1.4.0",
|
||||
"snap",
|
||||
"tempdir",
|
||||
"tiny-keccak 2.0.2",
|
||||
"tokio 0.2.21",
|
||||
"tokio-io-timeout",
|
||||
"tokio-util",
|
||||
"types",
|
||||
"unsigned-varint 0.3.3 (git+https://github.com/sigp/unsigned-varint?branch=latest-codecs)",
|
||||
"version",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eth2_ssz"
|
||||
version = "0.1.2"
|
||||
@ -1850,9 +1858,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
|
||||
checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@ -2166,9 +2174,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
@ -2238,8 +2246,8 @@ dependencies = [
|
||||
"deposit_contract",
|
||||
"dirs",
|
||||
"environment",
|
||||
"eth2-libp2p",
|
||||
"eth2_keystore",
|
||||
"eth2_libp2p",
|
||||
"eth2_ssz",
|
||||
"eth2_testnet_config",
|
||||
"futures 0.3.5",
|
||||
@ -2708,6 +2716,12 @@ dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru_time_cache"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb241df5c4caeb888755363fc95f8a896618dc0d435e9e775f7930cb099beab"
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.3.2"
|
||||
@ -2795,9 +2809,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5"
|
||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
@ -2841,7 +2855,7 @@ checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3"
|
||||
dependencies = [
|
||||
"log 0.4.8",
|
||||
"mio",
|
||||
"miow 0.3.4",
|
||||
"miow 0.3.5",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
@ -2870,9 +2884,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22dfdd1d51b2639a5abd17ed07005c3af05fb7a2a3b1a1d0d7af1000a520c1c7"
|
||||
checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
|
||||
dependencies = [
|
||||
"socket2",
|
||||
"winapi 0.3.8",
|
||||
@ -2949,7 +2963,7 @@ dependencies = [
|
||||
"beacon_chain",
|
||||
"environment",
|
||||
"error-chain",
|
||||
"eth2-libp2p",
|
||||
"eth2_libp2p",
|
||||
"eth2_ssz",
|
||||
"exit-future",
|
||||
"fnv",
|
||||
@ -3058,9 +3072,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-traits",
|
||||
@ -3068,9 +3082,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.40"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00"
|
||||
checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-integer",
|
||||
@ -3079,9 +3093,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
]
|
||||
@ -3098,9 +3112,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2"
|
||||
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
@ -3113,9 +3127,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.1"
|
||||
version = "11.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af325bc33c7f60191be4e2c984d48aaa21e2854f473b85398344b60c9b6358"
|
||||
checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
@ -3145,9 +3159,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.57"
|
||||
version = "0.9.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7410fef80af8ac071d4f63755c0ab89ac3df0fd1ea91f1d1f37cf5cec4395990"
|
||||
checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"cc",
|
||||
@ -3292,18 +3306,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.19"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a1acf4a3e70849f8a673497ef984f043f95d2d8252dcdf74d54e6a1e47e8a"
|
||||
checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.19"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194e88048b71a3e02eb4ee36a6995fed9b8236c11a7bb9f7247a9d9835b3f265"
|
||||
checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -3373,9 +3387,9 @@ checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
||||
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
@ -3543,9 +3557,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@ -3680,10 +3694,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
||||
checksum = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
@ -3691,9 +3706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.7.0"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
||||
checksum = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-queue",
|
||||
@ -3775,9 +3790,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
@ -3788,7 +3803,7 @@ version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b82c9238b305f26f53443e3a4bc8528d64b8d0bee408ec949eb7bf5635ec680"
|
||||
dependencies = [
|
||||
"base64 0.12.1",
|
||||
"base64 0.12.2",
|
||||
"bytes 0.5.4",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@ -3826,8 +3841,8 @@ dependencies = [
|
||||
"bls",
|
||||
"bus",
|
||||
"environment",
|
||||
"eth2-libp2p",
|
||||
"eth2_config",
|
||||
"eth2_libp2p",
|
||||
"eth2_ssz",
|
||||
"eth2_ssz_derive",
|
||||
"futures 0.3.5",
|
||||
@ -4142,18 +4157,18 @@ checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.111"
|
||||
version = "1.0.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
|
||||
checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.111"
|
||||
version = "1.0.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
|
||||
checksum = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4170,9 +4185,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.53"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2"
|
||||
checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -4181,9 +4196,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
|
||||
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4204,9 +4219,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.12"
|
||||
version = "0.8.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16c7a592a1ec97c9c1c68d75b6e537dcbf60c7618e038e7841e00af1d9ccf0c4"
|
||||
checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
|
||||
dependencies = [
|
||||
"dtoa",
|
||||
"linked-hash-map",
|
||||
@ -4697,9 +4712,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.30"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2"
|
||||
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4708,9 +4723,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.3"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4792,18 +4807,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.19"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344"
|
||||
checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.19"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479"
|
||||
checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4925,6 +4940,12 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.1.22"
|
||||
@ -5428,11 +5449,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
||||
checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
|
||||
dependencies = [
|
||||
"smallvec 1.4.0",
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5566,9 +5587,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c"
|
||||
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
@ -5760,10 +5781,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "web3"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/tomusdrw/rust-web3#69d5746f124033dee922d7d36acef9321c1df0b0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a681e8d15deced7c510db88c59133d2eafa7b6298b6e91b545e2a3fed93b3fe"
|
||||
dependencies = [
|
||||
"arrayvec 0.5.1",
|
||||
"base64 0.12.1",
|
||||
"base64 0.12.2",
|
||||
"derive_more",
|
||||
"ethabi",
|
||||
"ethereum-types",
|
||||
|
@ -5,7 +5,7 @@ members = [
|
||||
"beacon_node/beacon_chain",
|
||||
"beacon_node/client",
|
||||
"beacon_node/eth1",
|
||||
"beacon_node/eth2-libp2p",
|
||||
"beacon_node/eth2_libp2p",
|
||||
"beacon_node/network",
|
||||
"beacon_node/rest_api",
|
||||
"beacon_node/store",
|
||||
@ -72,4 +72,3 @@ eth2_ssz = { path = "consensus/ssz" }
|
||||
eth2_ssz_derive = { path = "consensus/ssz_derive" }
|
||||
eth2_ssz_types = { path = "consensus/ssz_types" }
|
||||
eth2_hashing = { path = "crypto/eth2_hashing" }
|
||||
web3 = { git = "https://github.com/tomusdrw/rust-web3" }
|
||||
|
@ -35,7 +35,7 @@ futures = "0.3.5"
|
||||
environment = { path = "../lighthouse/environment" }
|
||||
genesis = { path = "genesis" }
|
||||
eth2_testnet_config = { path = "../common/eth2_testnet_config" }
|
||||
eth2-libp2p = { path = "./eth2-libp2p" }
|
||||
eth2_libp2p = { path = "./eth2_libp2p" }
|
||||
eth2_ssz = "0.1.2"
|
||||
toml = "0.5.6"
|
||||
serde = "1.0.110"
|
||||
|
@ -13,7 +13,7 @@ beacon_chain = { path = "../beacon_chain" }
|
||||
store = { path = "../store" }
|
||||
network = { path = "../network" }
|
||||
timer = { path = "../timer" }
|
||||
eth2-libp2p = { path = "../eth2-libp2p" }
|
||||
eth2_libp2p = { path = "../eth2_libp2p" }
|
||||
rest_api = { path = "../rest_api" }
|
||||
parking_lot = "0.10.2"
|
||||
websocket_server = { path = "../websocket_server" }
|
||||
|
@ -1,628 +0,0 @@
|
||||
///! This manages the discovery and management of peers.
|
||||
pub(crate) mod enr;
|
||||
pub mod enr_ext;
|
||||
|
||||
// Allow external use of the lighthouse ENR builder
|
||||
pub use enr::{build_enr, CombinedKey, Keypair};
|
||||
pub use enr_ext::{CombinedKeyExt, EnrExt};
|
||||
|
||||
use crate::metrics;
|
||||
use crate::{error, Enr, NetworkConfig, NetworkGlobals};
|
||||
use discv5::{enr::NodeId, Discv5, Discv5Event, QueryId};
|
||||
use enr::{Eth2Enr, BITFIELD_ENR_KEY, ETH2_ENR_KEY};
|
||||
use futures::prelude::*;
|
||||
use libp2p::core::{connection::ConnectionId, Multiaddr, PeerId};
|
||||
use libp2p::multiaddr::Protocol;
|
||||
use libp2p::swarm::{
|
||||
protocols_handler::DummyProtocolsHandler, DialPeerCondition, NetworkBehaviour,
|
||||
NetworkBehaviourAction, PollParameters, ProtocolsHandler,
|
||||
};
|
||||
use lru::LruCache;
|
||||
use slog::{crit, debug, info, trace, warn};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
net::SocketAddr,
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::time::{delay_until, Delay};
|
||||
use types::{EnrForkId, EthSpec, SubnetId};
|
||||
|
||||
mod subnet_predicate;
|
||||
|
||||
use subnet_predicate::subnet_predicate;
|
||||
|
||||
/// Maximum seconds before searching for extra peers.
|
||||
const MAX_TIME_BETWEEN_PEER_SEARCHES: u64 = 120;
|
||||
/// Initial delay between peer searches.
|
||||
const INITIAL_SEARCH_DELAY: u64 = 5;
|
||||
/// The number of peers we must be connected to before increasing the discovery delay.
|
||||
const MINIMUM_PEERS_BEFORE_DELAY_INCREASE: usize = 5;
|
||||
/// Local ENR storage filename.
|
||||
pub const ENR_FILENAME: &str = "enr.dat";
|
||||
/// Number of peers we'd like to have connected to a given long-lived subnet.
|
||||
const TARGET_SUBNET_PEERS: usize = 3;
|
||||
/// Number of times to attempt a discovery request
|
||||
const MAX_DISCOVERY_RETRY: u64 = 3;
|
||||
|
||||
/// A struct representing the information associated with a single discovery request,
|
||||
/// which can be retried with multiple queries
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Request {
|
||||
pub query_id: Option<QueryId>,
|
||||
pub min_ttl: Option<Instant>,
|
||||
pub retries: u64,
|
||||
}
|
||||
|
||||
/// Lighthouse discovery behaviour. This provides peer management and discovery using the Discv5
|
||||
/// libp2p protocol.
|
||||
pub struct Discovery<TSpec: EthSpec> {
|
||||
/// Events to be processed by the behaviour.
|
||||
events: VecDeque<NetworkBehaviourAction<void::Void, Discv5Event>>,
|
||||
|
||||
/// A collection of seen live ENRs for quick lookup and to map peer-id's to ENRs.
|
||||
cached_enrs: LruCache<PeerId, Enr>,
|
||||
|
||||
/// The currently banned peers.
|
||||
banned_peers: HashSet<PeerId>,
|
||||
|
||||
/// The target number of connected peers on the libp2p interface.
|
||||
max_peers: usize,
|
||||
|
||||
/// The directory where the ENR is stored.
|
||||
enr_dir: String,
|
||||
|
||||
/// The delay between peer discovery searches.
|
||||
peer_discovery_delay: Delay,
|
||||
|
||||
/// Tracks the last discovery delay. The delay is doubled each round until the max
|
||||
/// time is reached.
|
||||
past_discovery_delay: u64,
|
||||
|
||||
/// The TCP port for libp2p. Used to convert an updated IP address to a multiaddr. Note: This
|
||||
/// assumes that the external TCP port is the same as the internal TCP port if behind a NAT.
|
||||
//TODO: Improve NAT handling limit the above restriction
|
||||
tcp_port: u16,
|
||||
|
||||
/// The discovery behaviour used to discover new peers.
|
||||
discovery: Discv5,
|
||||
|
||||
/// A collection of network constants that can be read from other threads.
|
||||
network_globals: Arc<NetworkGlobals<TSpec>>,
|
||||
|
||||
/// A mapping of SubnetId that we are currently searching for to all information associated with each request.
|
||||
subnet_queries: HashMap<SubnetId, Request>,
|
||||
|
||||
/// Logger for the discovery behaviour.
|
||||
log: slog::Logger,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
pub fn new(
|
||||
local_key: &Keypair,
|
||||
config: &NetworkConfig,
|
||||
network_globals: Arc<NetworkGlobals<TSpec>>,
|
||||
log: &slog::Logger,
|
||||
) -> error::Result<Self> {
|
||||
let log = log.clone();
|
||||
|
||||
let enr_dir = match config.network_dir.to_str() {
|
||||
Some(path) => String::from(path),
|
||||
None => String::from(""),
|
||||
};
|
||||
|
||||
let local_enr = network_globals.local_enr.read().clone();
|
||||
|
||||
info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> format!("{}",local_enr.node_id()), "ip" => format!("{:?}", local_enr.ip()), "udp"=> format!("{:?}", local_enr.udp()), "tcp" => format!("{:?}", local_enr.tcp()));
|
||||
|
||||
let listen_socket = SocketAddr::new(config.listen_address, config.discovery_port);
|
||||
|
||||
// convert the keypair into an ENR key
|
||||
let enr_key: CombinedKey = CombinedKey::from_libp2p(&local_key)?;
|
||||
|
||||
let mut discovery = Discv5::new(
|
||||
local_enr,
|
||||
enr_key,
|
||||
config.discv5_config.clone(),
|
||||
listen_socket,
|
||||
)
|
||||
.map_err(|e| format!("Discv5 service failed. Error: {:?}", e))?;
|
||||
|
||||
// Add bootnodes to routing table
|
||||
for bootnode_enr in config.boot_nodes.clone() {
|
||||
debug!(
|
||||
log,
|
||||
"Adding node to routing table";
|
||||
"node_id" => format!("{}", bootnode_enr.node_id()),
|
||||
"peer_id" => format!("{}", bootnode_enr.peer_id()),
|
||||
"ip" => format!("{:?}", bootnode_enr.ip()),
|
||||
"udp" => format!("{:?}", bootnode_enr.udp()),
|
||||
"tcp" => format!("{:?}", bootnode_enr.tcp())
|
||||
);
|
||||
let _ = discovery.add_enr(bootnode_enr).map_err(|e| {
|
||||
warn!(
|
||||
log,
|
||||
"Could not add peer to the local routing table";
|
||||
"error" => format!("{}", e)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
events: VecDeque::with_capacity(16),
|
||||
cached_enrs: LruCache::new(50),
|
||||
banned_peers: HashSet::new(),
|
||||
max_peers: config.max_peers,
|
||||
peer_discovery_delay: delay_until(tokio::time::Instant::now()),
|
||||
past_discovery_delay: INITIAL_SEARCH_DELAY,
|
||||
tcp_port: config.libp2p_port,
|
||||
discovery,
|
||||
network_globals,
|
||||
subnet_queries: HashMap::new(),
|
||||
log,
|
||||
enr_dir,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the nodes local ENR.
|
||||
pub fn local_enr(&self) -> &Enr {
|
||||
self.discovery.local_enr()
|
||||
}
|
||||
|
||||
/// Manually search for peers. This restarts the discovery round, sparking multiple rapid
|
||||
/// queries.
|
||||
pub fn discover_peers(&mut self) {
|
||||
self.past_discovery_delay = INITIAL_SEARCH_DELAY;
|
||||
self.find_peers();
|
||||
}
|
||||
|
||||
/// Add an ENR to the routing table of the discovery mechanism.
|
||||
pub fn add_enr(&mut self, enr: Enr) {
|
||||
// add the enr to seen caches
|
||||
self.cached_enrs.put(enr.peer_id(), enr.clone());
|
||||
|
||||
let _ = self.discovery.add_enr(enr).map_err(|e| {
|
||||
warn!(
|
||||
self.log,
|
||||
"Could not add peer to the local routing table";
|
||||
"error" => format!("{}", e)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
/// The peer has been banned. Add this peer to the banned list to prevent any future
|
||||
/// re-connections.
|
||||
// TODO: Remove the peer from the DHT if present
|
||||
pub fn peer_banned(&mut self, peer_id: PeerId) {
|
||||
self.banned_peers.insert(peer_id);
|
||||
}
|
||||
|
||||
pub fn peer_unbanned(&mut self, peer_id: &PeerId) {
|
||||
self.banned_peers.remove(peer_id);
|
||||
}
|
||||
|
||||
/// Returns an iterator over all enr entries in the DHT.
|
||||
pub fn enr_entries(&mut self) -> impl Iterator<Item = &Enr> {
|
||||
self.discovery.enr_entries()
|
||||
}
|
||||
|
||||
/// Returns the ENR of a known peer if it exists.
|
||||
pub fn enr_of_peer(&mut self, peer_id: &PeerId) -> Option<Enr> {
|
||||
// first search the local cache
|
||||
if let Some(enr) = self.cached_enrs.get(peer_id) {
|
||||
return Some(enr.clone());
|
||||
}
|
||||
// not in the local cache, look in the routing table
|
||||
if let Ok(_node_id) = enr_ext::peer_id_to_node_id(peer_id) {
|
||||
// TODO: Need to update discv5
|
||||
// self.discovery.find_enr(&node_id)
|
||||
return None;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds/Removes a subnet from the ENR Bitfield
|
||||
pub fn update_enr_bitfield(&mut self, subnet_id: SubnetId, value: bool) -> Result<(), String> {
|
||||
let id = *subnet_id as usize;
|
||||
|
||||
let local_enr = self.discovery.local_enr();
|
||||
let mut current_bitfield = local_enr.bitfield::<TSpec>()?;
|
||||
|
||||
if id >= current_bitfield.len() {
|
||||
return Err(format!(
|
||||
"Subnet id: {} is outside the ENR bitfield length: {}",
|
||||
id,
|
||||
current_bitfield.len()
|
||||
));
|
||||
}
|
||||
|
||||
if current_bitfield
|
||||
.get(id)
|
||||
.map_err(|_| String::from("Subnet ID out of bounds"))?
|
||||
== value
|
||||
{
|
||||
return Err(format!(
|
||||
"Subnet id: {} already in the local ENR already has value: {}",
|
||||
id, value
|
||||
));
|
||||
}
|
||||
|
||||
// set the subnet bitfield in the ENR
|
||||
current_bitfield
|
||||
.set(id, value)
|
||||
.map_err(|_| String::from("Subnet ID out of bounds, could not set subnet ID"))?;
|
||||
|
||||
// insert the bitfield into the ENR record
|
||||
let _ = self
|
||||
.discovery
|
||||
.enr_insert(BITFIELD_ENR_KEY, current_bitfield.as_ssz_bytes());
|
||||
|
||||
// replace the global version
|
||||
*self.network_globals.local_enr.write() = self.discovery.local_enr().clone();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Updates the `eth2` field of our local ENR.
|
||||
pub fn update_eth2_enr(&mut self, enr_fork_id: EnrForkId) {
|
||||
// to avoid having a reference to the spec constant, for the logging we assume
|
||||
// FAR_FUTURE_EPOCH is u64::max_value()
|
||||
let next_fork_epoch_log = if enr_fork_id.next_fork_epoch == u64::max_value() {
|
||||
String::from("No other fork")
|
||||
} else {
|
||||
format!("{:?}", enr_fork_id.next_fork_epoch)
|
||||
};
|
||||
|
||||
info!(self.log, "Updating the ENR fork version";
|
||||
"fork_digest" => format!("{:?}", enr_fork_id.fork_digest),
|
||||
"next_fork_version" => format!("{:?}", enr_fork_id.next_fork_version),
|
||||
"next_fork_epoch" => next_fork_epoch_log,
|
||||
);
|
||||
|
||||
let _ = self
|
||||
.discovery
|
||||
.enr_insert(ETH2_ENR_KEY.into(), enr_fork_id.as_ssz_bytes())
|
||||
.map_err(|e| {
|
||||
warn!(
|
||||
self.log,
|
||||
"Could not update eth2 ENR field";
|
||||
"error" => format!("{:?}", e)
|
||||
)
|
||||
});
|
||||
|
||||
// replace the global version with discovery version
|
||||
*self.network_globals.local_enr.write() = self.discovery.local_enr().clone();
|
||||
}
|
||||
|
||||
/// A request to find peers on a given subnet.
|
||||
pub fn discover_subnet_peers(&mut self, subnet_id: SubnetId, min_ttl: Option<Instant>) {
|
||||
// TODO: Extend this to an event once discovery becomes a thread managed by the peer
|
||||
// manager
|
||||
if let Some(min_ttl) = min_ttl {
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.extend_peers_on_subnet(subnet_id, min_ttl);
|
||||
}
|
||||
|
||||
// If there is already a discovery request in process for this subnet, ignore this request,
|
||||
// but update the min_ttl.
|
||||
if let Some(request) = self.subnet_queries.get_mut(&subnet_id) {
|
||||
// update the min_ttl if required
|
||||
if let Some(min_ttl) = min_ttl {
|
||||
if request.min_ttl < Some(min_ttl) {
|
||||
request.min_ttl = Some(min_ttl);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert a request and start a query for the subnet
|
||||
self.subnet_queries.insert(
|
||||
subnet_id.clone(),
|
||||
Request {
|
||||
query_id: None,
|
||||
min_ttl,
|
||||
retries: 0,
|
||||
},
|
||||
);
|
||||
self.run_subnet_query(subnet_id);
|
||||
}
|
||||
|
||||
/// Runs a discovery request for a given subnet_id if one already exists.
|
||||
fn run_subnet_query(&mut self, subnet_id: SubnetId) {
|
||||
let mut request = match self.subnet_queries.remove(&subnet_id) {
|
||||
Some(v) => v,
|
||||
None => return, // request doesn't exist
|
||||
};
|
||||
|
||||
// increment the retry count
|
||||
request.retries += 1;
|
||||
|
||||
let peers_on_subnet = self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.peers_on_subnet(subnet_id)
|
||||
.count();
|
||||
|
||||
if peers_on_subnet > TARGET_SUBNET_PEERS {
|
||||
trace!(self.log, "Discovery ignored";
|
||||
"reason" => "Already connected to desired peers",
|
||||
"connected_peers_on_subnet" => peers_on_subnet,
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the entry and complete the query if greater than the maximum search count
|
||||
if request.retries >= MAX_DISCOVERY_RETRY {
|
||||
debug!(
|
||||
self.log,
|
||||
"Subnet peer discovery did not find sufficient peers. Reached max retry limit"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let target_peers = TARGET_SUBNET_PEERS - peers_on_subnet;
|
||||
debug!(self.log, "Searching for peers for subnet";
|
||||
"subnet_id" => *subnet_id,
|
||||
"connected_peers_on_subnet" => peers_on_subnet,
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS,
|
||||
"peers_to_find" => target_peers,
|
||||
"attempt" => request.retries,
|
||||
);
|
||||
|
||||
// start the query, and update the queries map if necessary
|
||||
let subnet_predicate = subnet_predicate::<TSpec>(subnet_id, &self.log);
|
||||
if let Some(query_id) = self.start_query(subnet_predicate, target_peers) {
|
||||
request.query_id = Some(query_id);
|
||||
} else {
|
||||
// ENR is not present remove the query
|
||||
return;
|
||||
}
|
||||
self.subnet_queries.insert(subnet_id, request);
|
||||
}
|
||||
|
||||
/* Internal Functions */
|
||||
|
||||
/// Run a standard query to search for more peers.
|
||||
///
|
||||
/// This searches for the standard kademlia bucket size (16) peers.
|
||||
fn find_peers(&mut self) {
|
||||
debug!(self.log, "Searching for peers");
|
||||
self.start_query(|_| true, 16);
|
||||
}
|
||||
|
||||
/// Search for a specified number of new peers using the underlying discovery mechanism.
|
||||
///
|
||||
/// This can optionally search for peers for a given predicate. Regardless of the predicate
|
||||
/// given, this will only search for peers on the same enr_fork_id as specified in the local
|
||||
/// ENR.
|
||||
fn start_query<F>(&mut self, enr_predicate: F, num_nodes: usize) -> Option<QueryId>
|
||||
where
|
||||
F: Fn(&Enr) -> bool + Send + 'static + Clone,
|
||||
{
|
||||
// pick a random NodeId
|
||||
let random_node = NodeId::random();
|
||||
|
||||
let enr_fork_id = match self.local_enr().eth2() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
crit!(self.log, "Local ENR has no fork id"; "error" => e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
// predicate for finding nodes with a matching fork
|
||||
let eth2_fork_predicate = move |enr: &Enr| enr.eth2() == Ok(enr_fork_id.clone());
|
||||
let predicate = move |enr: &Enr| eth2_fork_predicate(enr) && enr_predicate(enr);
|
||||
|
||||
// general predicate
|
||||
Some(
|
||||
self.discovery
|
||||
.find_enr_predicate(random_node, predicate, num_nodes),
|
||||
)
|
||||
}
|
||||
|
||||
/// Peers that are found during discovery are optionally dialed.
|
||||
// TODO: Shift to peer manager. As its own service, discovery should spit out discovered nodes
|
||||
// and the peer manager should decide about who to connect to.
|
||||
fn dial_discovered_peers(&mut self, peers: Vec<Enr>, min_ttl: Option<Instant>) {
|
||||
for enr in peers {
|
||||
// cache known peers
|
||||
let peer_id = enr.peer_id();
|
||||
self.cached_enrs.put(enr.peer_id(), enr);
|
||||
|
||||
// if we need more peers, attempt a connection
|
||||
if self.network_globals.connected_or_dialing_peers() < self.max_peers
|
||||
&& !self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.is_connected_or_dialing(&peer_id)
|
||||
&& !self.banned_peers.contains(&peer_id)
|
||||
{
|
||||
debug!(self.log, "Connecting to discovered peer"; "peer_id"=> peer_id.to_string());
|
||||
// TODO: Update output
|
||||
// This should be updated with the peer dialing. In fact created once the peer is
|
||||
// dialed
|
||||
if let Some(min_ttl) = min_ttl {
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.update_min_ttl(&peer_id, min_ttl);
|
||||
}
|
||||
self.events.push_back(NetworkBehaviourAction::DialPeer {
|
||||
peer_id,
|
||||
condition: DialPeerCondition::Disconnected,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build a dummy Network behaviour around the discv5 server
|
||||
impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
|
||||
type ProtocolsHandler = DummyProtocolsHandler;
|
||||
type OutEvent = Discv5Event;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||
DummyProtocolsHandler::default()
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
if let Some(enr) = self.enr_of_peer(peer_id) {
|
||||
// ENR's may have multiple Multiaddrs. The multi-addr associated with the UDP
|
||||
// port is removed, which is assumed to be associated with the discv5 protocol (and
|
||||
// therefore irrelevant for other libp2p components).
|
||||
let mut out_list = enr.multiaddr();
|
||||
out_list.retain(|addr| {
|
||||
addr.iter()
|
||||
.find(|v| match v {
|
||||
Protocol::Udp(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
.is_none()
|
||||
});
|
||||
|
||||
out_list
|
||||
} else {
|
||||
// PeerId is not known
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
// ignore libp2p connections/streams
|
||||
fn inject_connected(&mut self, _: &PeerId) {}
|
||||
|
||||
// ignore libp2p connections/streams
|
||||
fn inject_disconnected(&mut self, _: &PeerId) {}
|
||||
|
||||
// no libp2p discv5 events - event originate from the session_service.
|
||||
fn inject_event(
|
||||
&mut self,
|
||||
_: PeerId,
|
||||
_: ConnectionId,
|
||||
_event: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent,
|
||||
) {
|
||||
void::unreachable(_event)
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<
|
||||
NetworkBehaviourAction<
|
||||
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
|
||||
Self::OutEvent,
|
||||
>,
|
||||
> {
|
||||
// search for peers if it is time
|
||||
loop {
|
||||
match self.peer_discovery_delay.poll_unpin(cx) {
|
||||
Poll::Ready(_) => {
|
||||
if self.network_globals.connected_peers() < self.max_peers {
|
||||
self.find_peers();
|
||||
}
|
||||
// Set to maximum, and update to earlier, once we get our results back.
|
||||
self.peer_discovery_delay.reset(
|
||||
tokio::time::Instant::now()
|
||||
+ Duration::from_secs(MAX_TIME_BETWEEN_PEER_SEARCHES),
|
||||
);
|
||||
}
|
||||
Poll::Pending => break,
|
||||
}
|
||||
}
|
||||
|
||||
// Poll discovery
|
||||
loop {
|
||||
match self.discovery.poll_next_unpin(cx) {
|
||||
Poll::Ready(Some(event)) => {
|
||||
match event {
|
||||
Discv5Event::Discovered(_enr) => {
|
||||
// peers that get discovered during a query but are not contactable or
|
||||
// don't match a predicate can end up here. For debugging purposes we
|
||||
// log these to see if we are unnecessarily dropping discovered peers
|
||||
/*
|
||||
if enr.eth2() == self.local_enr().eth2() {
|
||||
trace!(self.log, "Peer found in process of query"; "peer_id" => format!("{}", enr.peer_id()), "tcp_socket" => enr.tcp_socket());
|
||||
} else {
|
||||
// this is temporary warning for debugging the DHT
|
||||
warn!(self.log, "Found peer during discovery not on correct fork"; "peer_id" => format!("{}", enr.peer_id()), "tcp_socket" => enr.tcp_socket());
|
||||
}
|
||||
*/
|
||||
}
|
||||
Discv5Event::SocketUpdated(socket) => {
|
||||
info!(self.log, "Address updated"; "ip" => format!("{}",socket.ip()), "udp_port" => format!("{}", socket.port()));
|
||||
metrics::inc_counter(&metrics::ADDRESS_UPDATE_COUNT);
|
||||
let mut address = Multiaddr::from(socket.ip());
|
||||
address.push(Protocol::Tcp(self.tcp_port));
|
||||
let enr = self.discovery.local_enr();
|
||||
enr::save_enr_to_disk(Path::new(&self.enr_dir), enr, &self.log);
|
||||
|
||||
return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr {
|
||||
address,
|
||||
});
|
||||
}
|
||||
Discv5Event::FindNodeResult {
|
||||
closer_peers,
|
||||
query_id,
|
||||
..
|
||||
} => {
|
||||
debug!(self.log, "Discovery query completed"; "peers_found" => closer_peers.len());
|
||||
// update the time to the next query
|
||||
if self.past_discovery_delay < MAX_TIME_BETWEEN_PEER_SEARCHES
|
||||
&& self.network_globals.connected_or_dialing_peers()
|
||||
> MINIMUM_PEERS_BEFORE_DELAY_INCREASE
|
||||
{
|
||||
self.past_discovery_delay *= 2;
|
||||
}
|
||||
let delay = std::cmp::max(
|
||||
self.past_discovery_delay,
|
||||
MAX_TIME_BETWEEN_PEER_SEARCHES,
|
||||
);
|
||||
self.peer_discovery_delay
|
||||
.reset(tokio::time::Instant::now() + Duration::from_secs(delay));
|
||||
|
||||
// if this is a subnet query, run it to completion
|
||||
if let Some((subnet_id, min_ttl)) = self
|
||||
.subnet_queries
|
||||
.iter()
|
||||
.find(|(_, request)| request.query_id == Some(query_id))
|
||||
.map(|(subnet_id, request)| {
|
||||
(subnet_id.clone(), request.min_ttl.clone())
|
||||
})
|
||||
{
|
||||
debug!(self.log, "Peer subnet discovery request completed"; "peers_found" => closer_peers.len(), "subnet_id" => *subnet_id);
|
||||
self.dial_discovered_peers(closer_peers, min_ttl);
|
||||
self.run_subnet_query(subnet_id);
|
||||
} else {
|
||||
if closer_peers.is_empty() {
|
||||
debug!(self.log, "Peer Discovery request yielded no results.");
|
||||
} else {
|
||||
self.dial_discovered_peers(closer_peers, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// discv5 does not output any other NetworkBehaviourAction
|
||||
Poll::Ready(_) => {}
|
||||
Poll::Pending => break,
|
||||
}
|
||||
}
|
||||
|
||||
// process any queued events
|
||||
if let Some(event) = self.events.pop_front() {
|
||||
return Poll::Ready(event);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "eth2-libp2p"
|
||||
name = "eth2_libp2p"
|
||||
version = "0.1.2"
|
||||
authors = ["Age Manning <Age@AgeManning.com>"]
|
||||
edition = "2018"
|
||||
@ -32,8 +32,7 @@ snap = "1.0.0"
|
||||
void = "1.0.2"
|
||||
tokio-io-timeout = "0.4.0"
|
||||
tokio-util = { version = "0.3.1", features = ["codec", "compat"] }
|
||||
# Patched for quick updates
|
||||
discv5 = { git = "https://github.com/sigp/discv5", rev = "7b3bd40591b62b8c002ffdb85de008aa9f82e2e5" }
|
||||
discv5 = { version = "0.1.0-alpha.5", features = ["libp2p"] }
|
||||
tiny-keccak = "2.0.2"
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
libp2p-tcp = { version = "0.19.1", default-features = false, features = ["tokio"] }
|
@ -1,4 +1,3 @@
|
||||
use crate::discovery::Discovery;
|
||||
use crate::rpc::*;
|
||||
use libp2p::{
|
||||
core::either::{EitherError, EitherOutput},
|
||||
@ -19,7 +18,6 @@ use types::EthSpec;
|
||||
type GossipHandler = <Gossipsub as NetworkBehaviour>::ProtocolsHandler;
|
||||
type RPCHandler<TSpec> = <RPC<TSpec> as NetworkBehaviour>::ProtocolsHandler;
|
||||
type IdentifyHandler = <Identify as NetworkBehaviour>::ProtocolsHandler;
|
||||
type DiscoveryHandler<TSpec> = <Discovery<TSpec> as NetworkBehaviour>::ProtocolsHandler;
|
||||
|
||||
/// Handler that combines Lighthouse's Behaviours' handlers in a delegating manner.
|
||||
pub(super) struct DelegatingHandler<TSpec: EthSpec> {
|
||||
@ -29,22 +27,14 @@ pub(super) struct DelegatingHandler<TSpec: EthSpec> {
|
||||
rpc_handler: RPCHandler<TSpec>,
|
||||
/// Handler for the Identify protocol.
|
||||
identify_handler: IdentifyHandler,
|
||||
/// Handler for the Discovery protocol.
|
||||
discovery_handler: DiscoveryHandler<TSpec>,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> DelegatingHandler<TSpec> {
|
||||
pub fn new(
|
||||
gossipsub: &mut Gossipsub,
|
||||
rpc: &mut RPC<TSpec>,
|
||||
identify: &mut Identify,
|
||||
discovery: &mut Discovery<TSpec>,
|
||||
) -> Self {
|
||||
pub fn new(gossipsub: &mut Gossipsub, rpc: &mut RPC<TSpec>, identify: &mut Identify) -> Self {
|
||||
DelegatingHandler {
|
||||
gossip_handler: gossipsub.new_handler(),
|
||||
rpc_handler: rpc.new_handler(),
|
||||
identify_handler: identify.new_handler(),
|
||||
discovery_handler: discovery.new_handler(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +63,6 @@ pub enum DelegateIn<TSpec: EthSpec> {
|
||||
Gossipsub(<GossipHandler as ProtocolsHandler>::InEvent),
|
||||
RPC(<RPCHandler<TSpec> as ProtocolsHandler>::InEvent),
|
||||
Identify(<IdentifyHandler as ProtocolsHandler>::InEvent),
|
||||
Discovery(<DiscoveryHandler<TSpec> as ProtocolsHandler>::InEvent),
|
||||
}
|
||||
|
||||
/// Wrapper around the `ProtocolsHandler::OutEvent` types of the handlers.
|
||||
@ -82,7 +71,6 @@ pub enum DelegateOut<TSpec: EthSpec> {
|
||||
Gossipsub(<GossipHandler as ProtocolsHandler>::OutEvent),
|
||||
RPC(<RPCHandler<TSpec> as ProtocolsHandler>::OutEvent),
|
||||
Identify(<IdentifyHandler as ProtocolsHandler>::OutEvent),
|
||||
Discovery(<DiscoveryHandler<TSpec> as ProtocolsHandler>::OutEvent),
|
||||
}
|
||||
|
||||
/// Wrapper around the `ProtocolsHandler::Error` types of the handlers.
|
||||
@ -92,7 +80,6 @@ pub enum DelegateError<TSpec: EthSpec> {
|
||||
Gossipsub(<GossipHandler as ProtocolsHandler>::Error),
|
||||
RPC(<RPCHandler<TSpec> as ProtocolsHandler>::Error),
|
||||
Identify(<IdentifyHandler as ProtocolsHandler>::Error),
|
||||
Discovery(<DiscoveryHandler<TSpec> as ProtocolsHandler>::Error),
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> std::error::Error for DelegateError<TSpec> {}
|
||||
@ -106,7 +93,6 @@ impl<TSpec: EthSpec> std::fmt::Display for DelegateError<TSpec> {
|
||||
DelegateError::Gossipsub(err) => err.fmt(formater),
|
||||
DelegateError::RPC(err) => err.fmt(formater),
|
||||
DelegateError::Identify(err) => err.fmt(formater),
|
||||
DelegateError::Discovery(err) => err.fmt(formater),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,10 +101,7 @@ pub type DelegateInProto<TSpec> = SelectUpgrade<
|
||||
<GossipHandler as ProtocolsHandler>::InboundProtocol,
|
||||
SelectUpgrade<
|
||||
<RPCHandler<TSpec> as ProtocolsHandler>::InboundProtocol,
|
||||
SelectUpgrade<
|
||||
<IdentifyHandler as ProtocolsHandler>::InboundProtocol,
|
||||
<DiscoveryHandler<TSpec> as ProtocolsHandler>::InboundProtocol,
|
||||
>,
|
||||
<IdentifyHandler as ProtocolsHandler>::InboundProtocol,
|
||||
>,
|
||||
>;
|
||||
|
||||
@ -126,10 +109,7 @@ pub type DelegateOutProto<TSpec> = EitherUpgrade<
|
||||
<GossipHandler as ProtocolsHandler>::OutboundProtocol,
|
||||
EitherUpgrade<
|
||||
<RPCHandler<TSpec> as ProtocolsHandler>::OutboundProtocol,
|
||||
EitherUpgrade<
|
||||
<IdentifyHandler as ProtocolsHandler>::OutboundProtocol,
|
||||
<DiscoveryHandler<TSpec> as ProtocolsHandler>::OutboundProtocol,
|
||||
>,
|
||||
<IdentifyHandler as ProtocolsHandler>::OutboundProtocol,
|
||||
>,
|
||||
>;
|
||||
|
||||
@ -138,10 +118,7 @@ pub type DelegateOutInfo<TSpec> = EitherOutput<
|
||||
<GossipHandler as ProtocolsHandler>::OutboundOpenInfo,
|
||||
EitherOutput<
|
||||
<RPCHandler<TSpec> as ProtocolsHandler>::OutboundOpenInfo,
|
||||
EitherOutput<
|
||||
<IdentifyHandler as ProtocolsHandler>::OutboundOpenInfo,
|
||||
<DiscoveryHandler<TSpec> as ProtocolsHandler>::OutboundOpenInfo,
|
||||
>,
|
||||
<IdentifyHandler as ProtocolsHandler>::OutboundOpenInfo,
|
||||
>,
|
||||
>;
|
||||
|
||||
@ -157,24 +134,16 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
let gossip_proto = self.gossip_handler.listen_protocol();
|
||||
let rpc_proto = self.rpc_handler.listen_protocol();
|
||||
let identify_proto = self.identify_handler.listen_protocol();
|
||||
let discovery_proto = self.discovery_handler.listen_protocol();
|
||||
|
||||
let timeout = gossip_proto
|
||||
.timeout()
|
||||
.max(rpc_proto.timeout())
|
||||
.max(identify_proto.timeout())
|
||||
.max(discovery_proto.timeout())
|
||||
.clone();
|
||||
|
||||
let select = SelectUpgrade::new(
|
||||
gossip_proto.into_upgrade().1,
|
||||
SelectUpgrade::new(
|
||||
rpc_proto.into_upgrade().1,
|
||||
SelectUpgrade::new(
|
||||
identify_proto.into_upgrade().1,
|
||||
discovery_proto.into_upgrade().1,
|
||||
),
|
||||
),
|
||||
SelectUpgrade::new(rpc_proto.into_upgrade().1, identify_proto.into_upgrade().1),
|
||||
);
|
||||
|
||||
SubstreamProtocol::new(select).with_timeout(timeout)
|
||||
@ -192,13 +161,9 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
self.rpc_handler.inject_fully_negotiated_inbound(out)
|
||||
}
|
||||
// Identify
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::First(out))) => {
|
||||
EitherOutput::Second(EitherOutput::Second(out)) => {
|
||||
self.identify_handler.inject_fully_negotiated_inbound(out)
|
||||
}
|
||||
// Discovery
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::Second(out))) => {
|
||||
self.discovery_handler.inject_fully_negotiated_inbound(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,18 +186,11 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
.inject_fully_negotiated_outbound(protocol, info),
|
||||
// Identify
|
||||
(
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::First(protocol))),
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::First(info))),
|
||||
EitherOutput::Second(EitherOutput::Second(protocol)),
|
||||
EitherOutput::Second(EitherOutput::Second(info)),
|
||||
) => self
|
||||
.identify_handler
|
||||
.inject_fully_negotiated_outbound(protocol, info),
|
||||
// Discovery
|
||||
(
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::Second(protocol))),
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::Second(info))),
|
||||
) => self
|
||||
.discovery_handler
|
||||
.inject_fully_negotiated_outbound(protocol, info),
|
||||
// Reaching here means we got a protocol and info for different behaviours
|
||||
_ => unreachable!("output and protocol don't match"),
|
||||
}
|
||||
@ -243,7 +201,6 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
DelegateIn::Gossipsub(ev) => self.gossip_handler.inject_event(ev),
|
||||
DelegateIn::RPC(ev) => self.rpc_handler.inject_event(ev),
|
||||
DelegateIn::Identify(ev) => self.identify_handler.inject_event(ev),
|
||||
DelegateIn::Discovery(ev) => self.discovery_handler.inject_event(ev),
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +262,7 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
}
|
||||
},
|
||||
// Identify
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::First(info))) => match error {
|
||||
EitherOutput::Second(EitherOutput::Second(info)) => match error {
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)) => {
|
||||
self.identify_handler.inject_dial_upgrade_error(
|
||||
info,
|
||||
@ -319,7 +276,7 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
.identify_handler
|
||||
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timeout),
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(EitherError::B(
|
||||
EitherError::B(EitherError::A(err)),
|
||||
EitherError::B(err),
|
||||
))) => self.identify_handler.inject_dial_upgrade_error(
|
||||
info,
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(err)),
|
||||
@ -328,30 +285,6 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
unreachable!("info and error don't match")
|
||||
}
|
||||
},
|
||||
// Discovery
|
||||
EitherOutput::Second(EitherOutput::Second(EitherOutput::Second(info))) => match error {
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)) => {
|
||||
self.discovery_handler.inject_dial_upgrade_error(
|
||||
info,
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)),
|
||||
)
|
||||
}
|
||||
ProtocolsHandlerUpgrErr::Timer => self
|
||||
.discovery_handler
|
||||
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timer),
|
||||
ProtocolsHandlerUpgrErr::Timeout => self
|
||||
.discovery_handler
|
||||
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timeout),
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(EitherError::B(
|
||||
EitherError::B(EitherError::B(err)),
|
||||
))) => self.discovery_handler.inject_dial_upgrade_error(
|
||||
info,
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(err)),
|
||||
),
|
||||
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(_)) => {
|
||||
unreachable!("info and error don't match")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,7 +293,6 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
.connection_keep_alive()
|
||||
.max(self.rpc_handler.connection_keep_alive())
|
||||
.max(self.identify_handler.connection_keep_alive())
|
||||
.max(self.discovery_handler.connection_keep_alive())
|
||||
}
|
||||
|
||||
fn poll(
|
||||
@ -417,28 +349,8 @@ impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
|
||||
}
|
||||
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol, info }) => {
|
||||
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
|
||||
protocol: protocol
|
||||
.map_upgrade(|u| EitherUpgrade::B(EitherUpgrade::B(EitherUpgrade::A(u)))),
|
||||
info: EitherOutput::Second(EitherOutput::Second(EitherOutput::First(info))),
|
||||
});
|
||||
}
|
||||
Poll::Pending => (),
|
||||
};
|
||||
|
||||
match self.discovery_handler.poll(cx) {
|
||||
Poll::Ready(ProtocolsHandlerEvent::Custom(event)) => {
|
||||
return Poll::Ready(ProtocolsHandlerEvent::Custom(DelegateOut::Discovery(event)));
|
||||
}
|
||||
Poll::Ready(ProtocolsHandlerEvent::Close(event)) => {
|
||||
return Poll::Ready(ProtocolsHandlerEvent::Close(DelegateError::Discovery(
|
||||
event,
|
||||
)));
|
||||
}
|
||||
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol, info }) => {
|
||||
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
|
||||
protocol: protocol
|
||||
.map_upgrade(|u| EitherUpgrade::B(EitherUpgrade::B(EitherUpgrade::B(u)))),
|
||||
info: EitherOutput::Second(EitherOutput::Second(EitherOutput::Second(info))),
|
||||
protocol: protocol.map_upgrade(|u| EitherUpgrade::B(EitherUpgrade::B(u))),
|
||||
info: EitherOutput::Second(EitherOutput::Second(info)),
|
||||
});
|
||||
}
|
||||
Poll::Pending => (),
|
@ -1,4 +1,3 @@
|
||||
use crate::discovery::Discovery;
|
||||
use crate::rpc::*;
|
||||
use delegate::DelegatingHandler;
|
||||
pub(super) use delegate::{
|
||||
@ -27,14 +26,9 @@ pub struct BehaviourHandler<TSpec: EthSpec> {
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> BehaviourHandler<TSpec> {
|
||||
pub fn new(
|
||||
gossipsub: &mut Gossipsub,
|
||||
rpc: &mut RPC<TSpec>,
|
||||
identify: &mut Identify,
|
||||
discovery: &mut Discovery<TSpec>,
|
||||
) -> Self {
|
||||
pub fn new(gossipsub: &mut Gossipsub, rpc: &mut RPC<TSpec>, identify: &mut Identify) -> Self {
|
||||
BehaviourHandler {
|
||||
delegate: DelegatingHandler::new(gossipsub, rpc, identify, discovery),
|
||||
delegate: DelegatingHandler::new(gossipsub, rpc, identify),
|
||||
shutting_down: false,
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
use crate::discovery::{enr::Eth2Enr, Discovery};
|
||||
use crate::peer_manager::{PeerManager, PeerManagerEvent};
|
||||
use crate::rpc::*;
|
||||
use crate::types::{GossipEncoding, GossipKind, GossipTopic};
|
||||
use crate::Eth2Enr;
|
||||
use crate::{error, Enr, NetworkConfig, NetworkGlobals, PubsubMessage, TopicHash};
|
||||
use discv5::Discv5Event;
|
||||
use futures::prelude::*;
|
||||
use handler::{BehaviourHandler, BehaviourHandlerIn, BehaviourHandlerOut, DelegateIn, DelegateOut};
|
||||
use libp2p::{
|
||||
@ -46,8 +45,6 @@ pub struct Behaviour<TSpec: EthSpec> {
|
||||
// TODO: Using id for initial interop. This will be removed by mainnet.
|
||||
/// Provides IP addresses and peer information.
|
||||
identify: Identify,
|
||||
/// Discovery behaviour.
|
||||
discovery: Discovery<TSpec>,
|
||||
/// The peer manager that keeps track of peer's reputation and status.
|
||||
peer_manager: PeerManager<TSpec>,
|
||||
/// The events generated by this behaviour to be consumed in the swarm poll.
|
||||
@ -76,7 +73,6 @@ macro_rules! delegate_to_behaviours {
|
||||
$self.gossipsub.$fn($($arg),*);
|
||||
$self.eth2_rpc.$fn($($arg),*);
|
||||
$self.identify.$fn($($arg),*);
|
||||
$self.discovery.$fn($($arg),*);
|
||||
};
|
||||
}
|
||||
|
||||
@ -85,21 +81,11 @@ impl<TSpec: EthSpec> NetworkBehaviour for Behaviour<TSpec> {
|
||||
type OutEvent = BehaviourEvent<TSpec>;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||
BehaviourHandler::new(
|
||||
&mut self.gossipsub,
|
||||
&mut self.eth2_rpc,
|
||||
&mut self.identify,
|
||||
&mut self.discovery,
|
||||
)
|
||||
BehaviourHandler::new(&mut self.gossipsub, &mut self.eth2_rpc, &mut self.identify)
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
let mut out = Vec::new();
|
||||
out.extend(self.gossipsub.addresses_of_peer(peer_id));
|
||||
out.extend(self.eth2_rpc.addresses_of_peer(peer_id));
|
||||
out.extend(self.identify.addresses_of_peer(peer_id));
|
||||
out.extend(self.discovery.addresses_of_peer(peer_id));
|
||||
out
|
||||
self.peer_manager.addresses_of_peer(peer_id)
|
||||
}
|
||||
|
||||
fn inject_connected(&mut self, peer_id: &PeerId) {
|
||||
@ -178,7 +164,6 @@ impl<TSpec: EthSpec> NetworkBehaviour for Behaviour<TSpec> {
|
||||
DelegateOut::Gossipsub(ev) => self.gossipsub.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::RPC(ev) => self.eth2_rpc.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::Identify(ev) => self.identify.inject_event(peer_id, conn_id, ev),
|
||||
DelegateOut::Discovery(ev) => self.discovery.inject_event(peer_id, conn_id, ev),
|
||||
},
|
||||
/* Custom events sent BY the handler */
|
||||
BehaviourHandlerOut::Custom => {
|
||||
@ -240,7 +225,6 @@ impl<TSpec: EthSpec> NetworkBehaviour for Behaviour<TSpec> {
|
||||
poll_behaviour!(gossipsub, on_gossip_event, DelegateIn::Gossipsub);
|
||||
poll_behaviour!(eth2_rpc, on_rpc_event, DelegateIn::RPC);
|
||||
poll_behaviour!(identify, on_identify_event, DelegateIn::Identify);
|
||||
poll_behaviour!(discovery, on_discovery_event, DelegateIn::Discovery);
|
||||
|
||||
self.custom_poll(cx)
|
||||
}
|
||||
@ -264,14 +248,12 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
);
|
||||
|
||||
let enr_fork_id = network_globals
|
||||
.local_enr
|
||||
.read()
|
||||
.local_enr()
|
||||
.eth2()
|
||||
.expect("Local ENR must have a fork id");
|
||||
|
||||
let attnets = network_globals
|
||||
.local_enr
|
||||
.read()
|
||||
.local_enr()
|
||||
.bitfield::<TSpec>()
|
||||
.expect("Local ENR must have subnet bitfield");
|
||||
|
||||
@ -283,9 +265,8 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
Ok(Behaviour {
|
||||
eth2_rpc: RPC::new(log.clone()),
|
||||
gossipsub: Gossipsub::new(local_peer_id, net_conf.gs_config.clone()),
|
||||
discovery: Discovery::new(local_key, net_conf, network_globals.clone(), log)?,
|
||||
identify,
|
||||
peer_manager: PeerManager::new(network_globals.clone(), log),
|
||||
peer_manager: PeerManager::new(local_key, net_conf, network_globals.clone(), log)?,
|
||||
events: Vec::new(),
|
||||
peers_to_dc: Vec::new(),
|
||||
seen_gossip_messages: LruCache::new(100_000),
|
||||
@ -296,9 +277,9 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Obtain a reference to the discovery protocol.
|
||||
pub fn discovery(&self) -> &Discovery<TSpec> {
|
||||
&self.discovery
|
||||
/// Returns the local ENR of the node.
|
||||
pub fn local_enr(&self) -> Enr {
|
||||
self.network_globals.local_enr()
|
||||
}
|
||||
|
||||
/// Obtain a reference to the gossipsub protocol.
|
||||
@ -428,33 +409,35 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
)
|
||||
}
|
||||
|
||||
/* Discovery / Peer management functions */
|
||||
/* Peer management functions */
|
||||
|
||||
/// Notify discovery that the peer has been banned.
|
||||
pub fn peer_banned(&mut self, peer_id: PeerId) {
|
||||
self.discovery.peer_banned(peer_id);
|
||||
}
|
||||
// TODO: Remove this and integrate all disconnection/banning logic inside the peer manager.
|
||||
pub fn peer_banned(&mut self, _peer_id: PeerId) {}
|
||||
|
||||
/// Notify discovery that the peer has been unbanned.
|
||||
pub fn peer_unbanned(&mut self, peer_id: &PeerId) {
|
||||
self.discovery.peer_unbanned(peer_id);
|
||||
}
|
||||
// TODO: Remove this and integrate all disconnection/banning logic inside the peer manager.
|
||||
pub fn peer_unbanned(&mut self, _peer_id: &PeerId) {}
|
||||
|
||||
/// Returns an iterator over all enr entries in the DHT.
|
||||
pub fn enr_entries(&mut self) -> impl Iterator<Item = &Enr> {
|
||||
self.discovery.enr_entries()
|
||||
pub fn enr_entries(&mut self) -> Vec<Enr> {
|
||||
self.peer_manager.discovery_mut().table_entries_enr()
|
||||
}
|
||||
|
||||
/// Add an ENR to the routing table of the discovery mechanism.
|
||||
pub fn add_enr(&mut self, enr: Enr) {
|
||||
self.discovery.add_enr(enr);
|
||||
self.peer_manager.discovery_mut().add_enr(enr);
|
||||
}
|
||||
|
||||
/// Updates a subnet value to the ENR bitfield.
|
||||
///
|
||||
/// The `value` is `true` if a subnet is being added and false otherwise.
|
||||
pub fn update_enr_subnet(&mut self, subnet_id: SubnetId, value: bool) {
|
||||
if let Err(e) = self.discovery.update_enr_bitfield(subnet_id, value) {
|
||||
if let Err(e) = self
|
||||
.peer_manager
|
||||
.discovery_mut()
|
||||
.update_enr_bitfield(subnet_id, value)
|
||||
{
|
||||
crit!(self.log, "Could not update ENR bitfield"; "error" => e);
|
||||
}
|
||||
// update the local meta data which informs our peers of the update during PINGS
|
||||
@ -464,12 +447,14 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
/// Attempts to discover new peers for a given subnet. The `min_ttl` gives the time at which we
|
||||
/// would like to retain the peers for.
|
||||
pub fn discover_subnet_peers(&mut self, subnet_id: SubnetId, min_ttl: Option<Instant>) {
|
||||
self.discovery.discover_subnet_peers(subnet_id, min_ttl)
|
||||
self.peer_manager.discover_subnet_peers(subnet_id, min_ttl)
|
||||
}
|
||||
|
||||
/// Updates the local ENR's "eth2" field with the latest EnrForkId.
|
||||
pub fn update_fork_version(&mut self, enr_fork_id: EnrForkId) {
|
||||
self.discovery.update_eth2_enr(enr_fork_id.clone());
|
||||
self.peer_manager
|
||||
.discovery_mut()
|
||||
.update_eth2_enr(enr_fork_id.clone());
|
||||
|
||||
// unsubscribe from all gossip topics and re-subscribe to their new fork counterparts
|
||||
let subscribed_topics = self
|
||||
@ -497,11 +482,12 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
|
||||
/* Private internal functions */
|
||||
|
||||
/// Updates the current meta data of the node.
|
||||
/// Updates the current meta data of the node to match the local ENR.
|
||||
fn update_metadata(&mut self) {
|
||||
self.meta_data.seq_number += 1;
|
||||
self.meta_data.attnets = self
|
||||
.discovery
|
||||
.peer_manager
|
||||
.discovery()
|
||||
.local_enr()
|
||||
.bitfield::<TSpec>()
|
||||
.expect("Local discovery must have bitfield");
|
||||
@ -764,6 +750,15 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
loop {
|
||||
match self.peer_manager.poll_next_unpin(cx) {
|
||||
Poll::Ready(Some(event)) => match event {
|
||||
PeerManagerEvent::Dial(peer_id) => {
|
||||
return Poll::Ready(NBAction::DialPeer {
|
||||
peer_id,
|
||||
condition: libp2p::swarm::DialPeerCondition::Disconnected,
|
||||
});
|
||||
}
|
||||
PeerManagerEvent::SocketUpdated(address) => {
|
||||
return Poll::Ready(NBAction::ReportObservedAddr { address });
|
||||
}
|
||||
PeerManagerEvent::Status(peer_id) => {
|
||||
// it's time to status. We don't keep a beacon chain reference here, so we inform
|
||||
// the network to send a status to this peer
|
||||
@ -835,10 +830,6 @@ impl<TSpec: EthSpec> Behaviour<TSpec> {
|
||||
IdentifyEvent::Error { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_discovery_event(&mut self, _event: Discv5Event) {
|
||||
// discv5 has no events to inject
|
||||
}
|
||||
}
|
||||
|
||||
/* Public API types */
|
@ -109,14 +109,15 @@ impl Default for Config {
|
||||
|
||||
// discv5 configuration
|
||||
let discv5_config = Discv5ConfigBuilder::new()
|
||||
.enable_packet_filter()
|
||||
.session_cache_capacity(100)
|
||||
.request_timeout(Duration::from_secs(4))
|
||||
.request_retries(2)
|
||||
.enr_update(true) // update IP based on PONG responses
|
||||
.enr_peer_update_min(2) // prevents NAT's should be raised for mainnet
|
||||
.query_parallelism(5)
|
||||
.query_timeout(Duration::from_secs(60))
|
||||
.query_peer_timeout(Duration::from_secs(2))
|
||||
.ip_limit(false) // limits /24 IP's in buckets. Enable for mainnet
|
||||
.ip_limit() // limits /24 IP's in buckets.
|
||||
.ping_interval(Duration::from_secs(300))
|
||||
.build();
|
||||
|
@ -7,7 +7,6 @@ extern crate lazy_static;
|
||||
|
||||
pub mod behaviour;
|
||||
mod config;
|
||||
pub mod discovery;
|
||||
mod metrics;
|
||||
mod peer_manager;
|
||||
pub mod rpc;
|
||||
@ -17,9 +16,14 @@ pub mod types;
|
||||
pub use crate::types::{error, Enr, GossipTopic, NetworkGlobals, PubsubMessage};
|
||||
pub use behaviour::{BehaviourEvent, PeerRequestId, Request, Response};
|
||||
pub use config::Config as NetworkConfig;
|
||||
pub use discovery::enr_ext::{CombinedKeyExt, EnrExt};
|
||||
pub use discv5;
|
||||
pub use libp2p::gossipsub::{MessageId, Topic, TopicHash};
|
||||
pub use libp2p::{core::ConnectedPoint, PeerId, Swarm};
|
||||
pub use libp2p::{multiaddr, Multiaddr};
|
||||
pub use peer_manager::{client::Client, PeerDB, PeerInfo, PeerSyncStatus, SyncInfo};
|
||||
pub use peer_manager::discovery;
|
||||
pub use peer_manager::{
|
||||
client::Client,
|
||||
discovery::{CombinedKeyExt, EnrExt, Eth2Enr},
|
||||
PeerDB, PeerInfo, PeerSyncStatus, SyncInfo,
|
||||
};
|
||||
pub use service::{Libp2pEvent, Service, NETWORK_KEY_FILENAME};
|
@ -17,4 +17,12 @@ lazy_static! {
|
||||
"libp2p_peer_disconnect_event_total",
|
||||
"Count of libp2p peer disconnect events"
|
||||
);
|
||||
pub static ref DISCOVERY_QUEUE: Result<IntGauge> = try_create_int_gauge(
|
||||
"discovery_queue_size",
|
||||
"The number of discovery queries awaiting execution"
|
||||
);
|
||||
pub static ref DISCOVERY_REQS: Result<IntGauge> = try_create_int_gauge(
|
||||
"discovery_requests",
|
||||
"The number of unsolicited discovery requests per second"
|
||||
);
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
//! Helper functions and an extension trait for Ethereum 2 ENRs.
|
||||
|
||||
pub use discv5::enr::{self, CombinedKey, EnrBuilder};
|
||||
pub use libp2p::core::identity::Keypair;
|
||||
|
||||
use super::enr_ext::CombinedKeyExt;
|
||||
use super::ENR_FILENAME;
|
||||
use crate::types::{Enr, EnrBitfield};
|
||||
use crate::CombinedKeyExt;
|
||||
use crate::NetworkConfig;
|
||||
use libp2p::core::identity::Keypair;
|
||||
use slog::{debug, warn};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
632
beacon_node/eth2_libp2p/src/peer_manager/discovery/mod.rs
Normal file
632
beacon_node/eth2_libp2p/src/peer_manager/discovery/mod.rs
Normal file
@ -0,0 +1,632 @@
|
||||
///! This manages the discovery and management of peers.
|
||||
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_ext::{CombinedKeyExt, EnrExt};
|
||||
pub use libp2p::core::identity::Keypair;
|
||||
|
||||
use crate::metrics;
|
||||
use crate::{error, Enr, NetworkConfig, NetworkGlobals};
|
||||
use discv5::{enr::NodeId, Discv5, Discv5Event};
|
||||
use enr::{BITFIELD_ENR_KEY, ETH2_ENR_KEY};
|
||||
use futures::prelude::*;
|
||||
use libp2p::core::PeerId;
|
||||
// use libp2p::multiaddr::Protocol;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use lru::LruCache;
|
||||
use slog::{crit, debug, info, trace, warn};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
net::SocketAddr,
|
||||
path::Path,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
time::Instant,
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
use types::{EnrForkId, EthSpec, SubnetId};
|
||||
|
||||
mod subnet_predicate;
|
||||
use subnet_predicate::subnet_predicate;
|
||||
|
||||
/// Local ENR storage filename.
|
||||
pub const ENR_FILENAME: &str = "enr.dat";
|
||||
/// Target number of peers we'd like to have connected to a given long-lived subnet.
|
||||
const TARGET_SUBNET_PEERS: usize = 3;
|
||||
/// Number of times to attempt a discovery request
|
||||
const MAX_DISCOVERY_RETRY: usize = 3;
|
||||
/// The maximum number of concurrent discovery queries.
|
||||
const MAX_CONCURRENT_QUERIES: usize = 1;
|
||||
/// The number of closest peers to search for when doing a regular peer search.
|
||||
///
|
||||
/// We could reduce this constant to speed up queries however at the cost of security. It will
|
||||
/// make it easier to peers to eclipse this node. Kademlia suggests a value of 16.
|
||||
const FIND_NODE_QUERY_CLOSEST_PEERS: usize = 16;
|
||||
|
||||
/// The events emitted by polling discovery.
|
||||
pub enum DiscoveryEvent {
|
||||
/// A query has completed. The first parameter is the `min_ttl` of the peers if it is specified
|
||||
/// and the second parameter are the discovered peers.
|
||||
QueryResult(Option<Instant>, Box<Vec<Enr>>),
|
||||
/// This indicates that our local UDP socketaddr has been updated and we should inform libp2p.
|
||||
SocketUpdated(SocketAddr),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum QueryType {
|
||||
/// We are searching for subnet peers.
|
||||
Subnet {
|
||||
subnet_id: SubnetId,
|
||||
min_ttl: Option<Instant>,
|
||||
retries: usize,
|
||||
},
|
||||
/// We are searching for more peers without ENR or time constraints.
|
||||
FindPeers,
|
||||
}
|
||||
|
||||
impl QueryType {
|
||||
/// Returns true if this query has expired.
|
||||
pub fn expired(&self) -> bool {
|
||||
match self {
|
||||
Self::FindPeers => false,
|
||||
Self::Subnet { min_ttl, .. } => {
|
||||
if let Some(ttl) = min_ttl {
|
||||
ttl > &Instant::now()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the min_ttl of the query if one exists
|
||||
///
|
||||
/// This is required for returning to the peer manager. The peer manager will update newly
|
||||
/// connected peers with this `min_ttl`
|
||||
pub fn min_ttl(&self) -> Option<Instant> {
|
||||
match self {
|
||||
Self::FindPeers => None,
|
||||
Self::Subnet { min_ttl, .. } => min_ttl.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of a query.
|
||||
struct QueryResult(QueryType, Result<Vec<Enr>, discv5::QueryError>);
|
||||
|
||||
// Awaiting the event stream future
|
||||
enum EventStream {
|
||||
/// Awaiting an event stream to be generated. This is required due to the poll nature of
|
||||
/// `Discovery`
|
||||
Awaiting(
|
||||
Pin<
|
||||
Box<
|
||||
dyn Future<Output = Result<mpsc::Receiver<Discv5Event>, discv5::Discv5Error>>
|
||||
+ Send,
|
||||
>,
|
||||
>,
|
||||
),
|
||||
/// The future has completed.
|
||||
Present(mpsc::Receiver<Discv5Event>),
|
||||
// The future has failed, there are no events from discv5.
|
||||
Failed,
|
||||
}
|
||||
|
||||
pub struct Discovery<TSpec: EthSpec> {
|
||||
/// A collection of seen live ENRs for quick lookup and to map peer-id's to ENRs.
|
||||
cached_enrs: LruCache<PeerId, Enr>,
|
||||
|
||||
/// The directory where the ENR is stored.
|
||||
enr_dir: String,
|
||||
|
||||
/// The handle for the underlying discv5 Server.
|
||||
///
|
||||
/// This is behind a Reference counter to allow for futures to be spawned and polled with a
|
||||
/// static lifetime.
|
||||
discv5: Discv5,
|
||||
|
||||
/// A collection of network constants that can be read from other threads.
|
||||
network_globals: Arc<NetworkGlobals<TSpec>>,
|
||||
|
||||
/// Indicates if we are actively searching for peers. We only allow a single FindPeers query at
|
||||
/// a time, regardless of the query concurrency.
|
||||
find_peer_active: bool,
|
||||
|
||||
/// A queue of discovery queries to be processed.
|
||||
queued_queries: VecDeque<QueryType>,
|
||||
|
||||
/// Active discovery queries.
|
||||
active_queries: FuturesUnordered<std::pin::Pin<Box<dyn Future<Output = QueryResult> + Send>>>,
|
||||
|
||||
/// The discv5 event stream.
|
||||
event_stream: EventStream,
|
||||
|
||||
/// Logger for the discovery behaviour.
|
||||
log: slog::Logger,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
/// NOTE: Creating discovery requires running within a tokio execution environment.
|
||||
pub fn new(
|
||||
local_key: &Keypair,
|
||||
config: &NetworkConfig,
|
||||
network_globals: Arc<NetworkGlobals<TSpec>>,
|
||||
log: &slog::Logger,
|
||||
) -> error::Result<Self> {
|
||||
let log = log.clone();
|
||||
|
||||
let enr_dir = match config.network_dir.to_str() {
|
||||
Some(path) => String::from(path),
|
||||
None => String::from(""),
|
||||
};
|
||||
|
||||
let local_enr = network_globals.local_enr.read().clone();
|
||||
|
||||
info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> format!("{}",local_enr.node_id()), "ip" => format!("{:?}", local_enr.ip()), "udp"=> format!("{:?}", local_enr.udp()), "tcp" => format!("{:?}", local_enr.tcp()));
|
||||
|
||||
let listen_socket = SocketAddr::new(config.listen_address, config.discovery_port);
|
||||
|
||||
// convert the keypair into an ENR key
|
||||
let enr_key: CombinedKey = CombinedKey::from_libp2p(&local_key)?;
|
||||
|
||||
let mut discv5 = Discv5::new(local_enr, enr_key, config.discv5_config.clone())
|
||||
.map_err(|e| format!("Discv5 service failed. Error: {:?}", e))?;
|
||||
|
||||
// Add bootnodes to routing table
|
||||
for bootnode_enr in config.boot_nodes.clone() {
|
||||
debug!(
|
||||
log,
|
||||
"Adding node to routing table";
|
||||
"node_id" => format!("{}", bootnode_enr.node_id()),
|
||||
"peer_id" => format!("{}", bootnode_enr.peer_id()),
|
||||
"ip" => format!("{:?}", bootnode_enr.ip()),
|
||||
"udp" => format!("{:?}", bootnode_enr.udp()),
|
||||
"tcp" => format!("{:?}", bootnode_enr.tcp())
|
||||
);
|
||||
let _ = discv5.add_enr(bootnode_enr).map_err(|e| {
|
||||
warn!(
|
||||
log,
|
||||
"Could not add peer to the local routing table";
|
||||
"error" => format!("{}", e)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// start the discv5 service.
|
||||
discv5.start(listen_socket);
|
||||
debug!(log, "Discovery service started");
|
||||
|
||||
// obtain the event stream
|
||||
let event_stream = EventStream::Awaiting(Box::pin(discv5.event_stream()));
|
||||
|
||||
Ok(Self {
|
||||
cached_enrs: LruCache::new(50),
|
||||
network_globals,
|
||||
find_peer_active: false,
|
||||
queued_queries: VecDeque::with_capacity(10),
|
||||
active_queries: FuturesUnordered::new(),
|
||||
discv5,
|
||||
event_stream,
|
||||
log,
|
||||
enr_dir,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the nodes local ENR.
|
||||
pub fn local_enr(&self) -> Enr {
|
||||
self.discv5.local_enr()
|
||||
}
|
||||
|
||||
/// This adds a new `FindPeers` query to the queue if one doesn't already exist.
|
||||
pub fn discover_peers(&mut self) {
|
||||
// If there is not already a find peer's query queued, add one
|
||||
let query = QueryType::FindPeers;
|
||||
if !self.queued_queries.contains(&query) {
|
||||
trace!(self.log, "Queuing a peer discovery request");
|
||||
self.queued_queries.push_back(query);
|
||||
// update the metrics
|
||||
metrics::set_gauge(&metrics::DISCOVERY_QUEUE, self.queued_queries.len() as i64);
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes a request to search for more peers on a subnet.
|
||||
pub fn discover_subnet_peers(&mut self, subnet_id: SubnetId, min_ttl: Option<Instant>) {
|
||||
self.add_subnet_query(subnet_id, min_ttl, 0);
|
||||
}
|
||||
|
||||
/// Adds a subnet query if one doesn't exist. If a subnet query already exists, this
|
||||
/// updates the min_ttl field.
|
||||
fn add_subnet_query(&mut self, subnet_id: SubnetId, min_ttl: Option<Instant>, retries: usize) {
|
||||
// remove the entry and complete the query if greater than the maximum search count
|
||||
if retries >= MAX_DISCOVERY_RETRY {
|
||||
debug!(
|
||||
self.log,
|
||||
"Subnet peer discovery did not find sufficient peers. Reached max retry limit"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Search through any queued requests and update the timeout if a query for this subnet
|
||||
// already exists
|
||||
let mut found = false;
|
||||
for query in self.queued_queries.iter_mut() {
|
||||
if let QueryType::Subnet {
|
||||
subnet_id: ref mut q_subnet_id,
|
||||
min_ttl: ref mut q_min_ttl,
|
||||
retries: ref mut q_retries,
|
||||
} = query
|
||||
{
|
||||
if *q_subnet_id == subnet_id {
|
||||
if *q_min_ttl < min_ttl {
|
||||
*q_min_ttl = min_ttl;
|
||||
}
|
||||
// update the number of retries
|
||||
*q_retries = retries;
|
||||
// mimic an `Iter::Find()` and short-circuit the loop
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
// Set up the query and add it to the queue
|
||||
let query = QueryType::Subnet {
|
||||
subnet_id,
|
||||
min_ttl,
|
||||
retries,
|
||||
};
|
||||
// update the metrics and insert into the queue.
|
||||
metrics::set_gauge(&metrics::DISCOVERY_QUEUE, self.queued_queries.len() as i64);
|
||||
self.queued_queries.push_back(query);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an ENR to the routing table of the discovery mechanism.
|
||||
pub fn add_enr(&mut self, enr: Enr) {
|
||||
// add the enr to seen caches
|
||||
self.cached_enrs.put(enr.peer_id(), enr.clone());
|
||||
|
||||
if let Err(e) = self.discv5.add_enr(enr) {
|
||||
warn!(
|
||||
self.log,
|
||||
"Could not add peer to the local routing table";
|
||||
"error" => format!("{}", e)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all enr entries in the DHT.
|
||||
pub fn table_entries_enr(&mut self) -> Vec<Enr> {
|
||||
self.discv5.table_entries_enr()
|
||||
}
|
||||
|
||||
/// Returns the ENR of a known peer if it exists.
|
||||
pub fn enr_of_peer(&mut self, peer_id: &PeerId) -> Option<Enr> {
|
||||
// first search the local cache
|
||||
if let Some(enr) = self.cached_enrs.get(peer_id) {
|
||||
return Some(enr.clone());
|
||||
}
|
||||
// not in the local cache, look in the routing table
|
||||
if let Ok(node_id) = enr_ext::peer_id_to_node_id(peer_id) {
|
||||
self.discv5.find_enr(&node_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds/Removes a subnet from the ENR Bitfield
|
||||
pub fn update_enr_bitfield(&mut self, subnet_id: SubnetId, value: bool) -> Result<(), String> {
|
||||
let id = *subnet_id as usize;
|
||||
|
||||
let local_enr = self.discv5.local_enr();
|
||||
let mut current_bitfield = local_enr.bitfield::<TSpec>()?;
|
||||
|
||||
if id >= current_bitfield.len() {
|
||||
return Err(format!(
|
||||
"Subnet id: {} is outside the ENR bitfield length: {}",
|
||||
id,
|
||||
current_bitfield.len()
|
||||
));
|
||||
}
|
||||
|
||||
if current_bitfield
|
||||
.get(id)
|
||||
.map_err(|_| String::from("Subnet ID out of bounds"))?
|
||||
== value
|
||||
{
|
||||
return Err(format!(
|
||||
"Subnet id: {} already in the local ENR already has value: {}",
|
||||
id, value
|
||||
));
|
||||
}
|
||||
|
||||
// set the subnet bitfield in the ENR
|
||||
current_bitfield
|
||||
.set(id, value)
|
||||
.map_err(|_| String::from("Subnet ID out of bounds, could not set subnet ID"))?;
|
||||
|
||||
// insert the bitfield into the ENR record
|
||||
let _ = self
|
||||
.discv5
|
||||
.enr_insert(BITFIELD_ENR_KEY, current_bitfield.as_ssz_bytes());
|
||||
|
||||
// replace the global version
|
||||
*self.network_globals.local_enr.write() = self.discv5.local_enr().clone();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Updates the `eth2` field of our local ENR.
|
||||
pub fn update_eth2_enr(&mut self, enr_fork_id: EnrForkId) {
|
||||
// to avoid having a reference to the spec constant, for the logging we assume
|
||||
// FAR_FUTURE_EPOCH is u64::max_value()
|
||||
let next_fork_epoch_log = if enr_fork_id.next_fork_epoch == u64::max_value() {
|
||||
String::from("No other fork")
|
||||
} else {
|
||||
format!("{:?}", enr_fork_id.next_fork_epoch)
|
||||
};
|
||||
|
||||
info!(self.log, "Updating the ENR fork version";
|
||||
"fork_digest" => format!("{:?}", enr_fork_id.fork_digest),
|
||||
"next_fork_version" => format!("{:?}", enr_fork_id.next_fork_version),
|
||||
"next_fork_epoch" => next_fork_epoch_log,
|
||||
);
|
||||
|
||||
let _ = self
|
||||
.discv5
|
||||
.enr_insert(ETH2_ENR_KEY.into(), enr_fork_id.as_ssz_bytes())
|
||||
.map_err(|e| {
|
||||
warn!(
|
||||
self.log,
|
||||
"Could not update eth2 ENR field";
|
||||
"error" => format!("{:?}", e)
|
||||
)
|
||||
});
|
||||
|
||||
// replace the global version with discovery version
|
||||
*self.network_globals.local_enr.write() = self.discv5.local_enr().clone();
|
||||
}
|
||||
|
||||
/* Internal Functions */
|
||||
|
||||
/// Consume the discovery queue and initiate queries when applicable.
|
||||
///
|
||||
/// This also sanitizes the queue removing out-dated queries.
|
||||
fn process_queue(&mut self) {
|
||||
// Sanitize the queue, removing any out-dated subnet queries
|
||||
self.queued_queries.retain(|query| !query.expired());
|
||||
|
||||
// Check that we are within our query concurrency limit
|
||||
while !self.at_capacity() && !self.queued_queries.is_empty() {
|
||||
// consume and process the query queue
|
||||
match self.queued_queries.pop_front() {
|
||||
Some(QueryType::FindPeers) => {
|
||||
// Only permit one FindPeers query at a time
|
||||
if self.find_peer_active {
|
||||
self.queued_queries.push_back(QueryType::FindPeers);
|
||||
continue;
|
||||
}
|
||||
// This is a regular request to find additional peers
|
||||
debug!(self.log, "Searching for new peers");
|
||||
self.find_peer_active = true;
|
||||
self.start_query(QueryType::FindPeers, FIND_NODE_QUERY_CLOSEST_PEERS);
|
||||
}
|
||||
Some(QueryType::Subnet {
|
||||
subnet_id,
|
||||
min_ttl,
|
||||
retries,
|
||||
}) => {
|
||||
// This query is for searching for peers of a particular subnet
|
||||
self.start_subnet_query(subnet_id, min_ttl, retries);
|
||||
}
|
||||
None => {} // Queue is empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a boolean indicating if we are currently processing the maximum number of
|
||||
// concurrent queries or not.
|
||||
fn at_capacity(&self) -> bool {
|
||||
if self.active_queries.len() >= MAX_CONCURRENT_QUERIES {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs a discovery request for a given subnet_id if one already exists.
|
||||
fn start_subnet_query(
|
||||
&mut self,
|
||||
subnet_id: SubnetId,
|
||||
min_ttl: Option<Instant>,
|
||||
retries: usize,
|
||||
) {
|
||||
// Determine if we have sufficient peers, which may make this discovery unnecessary.
|
||||
let peers_on_subnet = self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.peers_on_subnet(subnet_id)
|
||||
.count();
|
||||
|
||||
if peers_on_subnet > TARGET_SUBNET_PEERS {
|
||||
trace!(self.log, "Discovery ignored";
|
||||
"reason" => "Already connected to desired peers",
|
||||
"connected_peers_on_subnet" => peers_on_subnet,
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let target_peers = TARGET_SUBNET_PEERS - peers_on_subnet;
|
||||
debug!(self.log, "Searching for peers for subnet";
|
||||
"subnet_id" => *subnet_id,
|
||||
"connected_peers_on_subnet" => peers_on_subnet,
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS,
|
||||
"peers_to_find" => target_peers,
|
||||
"attempt" => retries,
|
||||
);
|
||||
|
||||
// start the query, and update the queries map if necessary
|
||||
let query = QueryType::Subnet {
|
||||
subnet_id,
|
||||
min_ttl,
|
||||
retries,
|
||||
};
|
||||
self.start_query(query, target_peers);
|
||||
}
|
||||
|
||||
/// Search for a specified number of new peers using the underlying discovery mechanism.
|
||||
///
|
||||
/// This can optionally search for peers for a given predicate. Regardless of the predicate
|
||||
/// given, this will only search for peers on the same enr_fork_id as specified in the local
|
||||
/// ENR.
|
||||
fn start_query(&mut self, query: QueryType, target_peers: usize) {
|
||||
// Generate a random target node id.
|
||||
let random_node = NodeId::random();
|
||||
|
||||
let enr_fork_id = match self.local_enr().eth2() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
crit!(self.log, "Local ENR has no fork id"; "error" => e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
// predicate for finding nodes with a matching fork
|
||||
let eth2_fork_predicate = move |enr: &Enr| enr.eth2() == Ok(enr_fork_id.clone());
|
||||
|
||||
// General predicate
|
||||
let predicate: Box<dyn Fn(&Enr) -> bool + Send> = match &query {
|
||||
QueryType::FindPeers => Box::new(eth2_fork_predicate),
|
||||
QueryType::Subnet { subnet_id, .. } => {
|
||||
// build the subnet predicate as a combination of the eth2_fork_predicate and the
|
||||
// subnet predicate
|
||||
let subnet_predicate = subnet_predicate::<TSpec>(subnet_id.clone(), &self.log);
|
||||
Box::new(move |enr: &Enr| eth2_fork_predicate(enr) && subnet_predicate(enr))
|
||||
}
|
||||
};
|
||||
|
||||
// Build the future
|
||||
let query_future = self
|
||||
.discv5
|
||||
.find_node_predicate(random_node, predicate, target_peers)
|
||||
.map(|v| QueryResult(query, v));
|
||||
|
||||
// Add the future to active queries, to be executed.
|
||||
self.active_queries.push(Box::pin(query_future));
|
||||
}
|
||||
|
||||
/// Drives the queries returning any results from completed queries.
|
||||
fn poll_queries(&mut self, cx: &mut Context) -> Option<(Option<Instant>, Vec<Enr>)> {
|
||||
while let Poll::Ready(Some(query_future)) = self.active_queries.poll_next_unpin(cx) {
|
||||
match query_future.0 {
|
||||
QueryType::FindPeers => {
|
||||
self.find_peer_active = false;
|
||||
match query_future.1 {
|
||||
Ok(r) if r.is_empty() => {
|
||||
debug!(self.log, "Discovery query yielded no results.");
|
||||
}
|
||||
Ok(r) => {
|
||||
debug!(self.log, "Discovery query completed"; "peers_found" => r.len());
|
||||
return Some((None, r));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(self.log, "Discovery query failed"; "error" => e.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
QueryType::Subnet {
|
||||
subnet_id,
|
||||
min_ttl,
|
||||
retries,
|
||||
} => {
|
||||
match query_future.1 {
|
||||
Ok(r) if r.is_empty() => {
|
||||
debug!(self.log, "Subnet discovery query yielded no results."; "subnet_id" => *subnet_id, "retries" => retries);
|
||||
}
|
||||
Ok(r) => {
|
||||
debug!(self.log, "Peer subnet discovery request completed"; "peers_found" => r.len(), "subnet_id" => *subnet_id);
|
||||
// A subnet query has completed. Add back to the queue, incrementing retries.
|
||||
self.add_subnet_query(subnet_id, min_ttl, retries + 1);
|
||||
// Report the results back to the peer manager.
|
||||
return Some((query_future.0.min_ttl(), r));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(self.log,"Subnet Discovery query failed"; "subnet_id" => *subnet_id, "error" => e.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// Main execution loop to be driven by the peer manager.
|
||||
pub fn poll(&mut self, cx: &mut Context) -> Poll<DiscoveryEvent> {
|
||||
// Process the query queue
|
||||
self.process_queue();
|
||||
|
||||
// Drive the queries and return any results from completed queries
|
||||
if let Some((min_ttl, result)) = self.poll_queries(cx) {
|
||||
// cache the found ENR's
|
||||
for enr in result.iter().cloned() {
|
||||
self.cached_enrs.put(enr.peer_id(), enr);
|
||||
}
|
||||
// return the result to the peer manager
|
||||
return Poll::Ready(DiscoveryEvent::QueryResult(min_ttl, Box::new(result)));
|
||||
}
|
||||
|
||||
// Process the server event stream
|
||||
match self.event_stream {
|
||||
EventStream::Awaiting(ref mut fut) => {
|
||||
// Still awaiting the event stream, poll it
|
||||
if let Poll::Ready(event_stream) = fut.poll_unpin(cx) {
|
||||
match event_stream {
|
||||
Ok(stream) => self.event_stream = EventStream::Present(stream),
|
||||
Err(e) => {
|
||||
slog::crit!(self.log, "Discv5 event stream failed"; "error" => e.to_string());
|
||||
self.event_stream = EventStream::Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EventStream::Failed => {} // ignore checking the stream
|
||||
EventStream::Present(ref mut stream) => {
|
||||
while let Ok(event) = stream.try_recv() {
|
||||
match event {
|
||||
// We filter out unwanted discv5 events here and only propagate useful results to
|
||||
// the peer manager.
|
||||
Discv5Event::Discovered(_enr) => {
|
||||
// Peers that get discovered during a query but are not contactable or
|
||||
// don't match a predicate can end up here. For debugging purposes we
|
||||
// log these to see if we are unnecessarily dropping discovered peers
|
||||
/*
|
||||
if enr.eth2() == self.local_enr().eth2() {
|
||||
trace!(self.log, "Peer found in process of query"; "peer_id" => format!("{}", enr.peer_id()), "tcp_socket" => enr.tcp_socket());
|
||||
} else {
|
||||
// this is temporary warning for debugging the DHT
|
||||
warn!(self.log, "Found peer during discovery not on correct fork"; "peer_id" => format!("{}", enr.peer_id()), "tcp_socket" => enr.tcp_socket());
|
||||
}
|
||||
*/
|
||||
}
|
||||
Discv5Event::SocketUpdated(socket) => {
|
||||
info!(self.log, "Address updated"; "ip" => format!("{}",socket.ip()), "udp_port" => format!("{}", socket.port()));
|
||||
metrics::inc_counter(&metrics::ADDRESS_UPDATE_COUNT);
|
||||
// Discv5 will have updated our local ENR. We save the updated version
|
||||
// to disk.
|
||||
let enr = self.discv5.local_enr();
|
||||
enr::save_enr_to_disk(Path::new(&self.enr_dir), &enr, &self.log);
|
||||
return Poll::Ready(DiscoveryEvent::SocketUpdated(socket));
|
||||
}
|
||||
_ => {} // Ignore all other discv5 server events
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ use super::*;
|
||||
pub fn subnet_predicate<TSpec>(
|
||||
subnet_id: SubnetId,
|
||||
log: &slog::Logger,
|
||||
) -> impl Fn(&Enr) -> bool + Send + 'static + Clone
|
||||
) -> impl Fn(&Enr) -> bool + Send
|
||||
where
|
||||
TSpec: EthSpec,
|
||||
{
|
@ -1,27 +1,35 @@
|
||||
//! Implementation of a Lighthouse's peer management system.
|
||||
|
||||
pub use self::peerdb::*;
|
||||
use crate::metrics;
|
||||
use crate::rpc::{MetaData, Protocol, RPCError, RPCResponseErrorCode};
|
||||
use crate::{NetworkGlobals, PeerId};
|
||||
use crate::{error, metrics};
|
||||
use crate::{Enr, EnrExt, NetworkConfig, NetworkGlobals, PeerId};
|
||||
use futures::prelude::*;
|
||||
use futures::Stream;
|
||||
use hashset_delay::HashSetDelay;
|
||||
use libp2p::core::multiaddr::Protocol as MProtocol;
|
||||
use libp2p::identify::IdentifyInfo;
|
||||
use slog::{crit, debug, error, warn};
|
||||
use slog::{crit, debug, error};
|
||||
use smallvec::SmallVec;
|
||||
use std::convert::TryInto;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::{Duration, Instant};
|
||||
use types::EthSpec;
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use types::{EthSpec, SubnetId};
|
||||
|
||||
pub use libp2p::core::{identity::Keypair, Multiaddr};
|
||||
|
||||
pub mod client;
|
||||
pub mod discovery;
|
||||
mod peer_info;
|
||||
mod peer_sync_status;
|
||||
mod peerdb;
|
||||
|
||||
use discovery::{Discovery, DiscoveryEvent};
|
||||
|
||||
pub use peer_info::{PeerConnectionStatus::*, PeerInfo};
|
||||
pub use peer_sync_status::{PeerSyncStatus, SyncInfo};
|
||||
/// The minimum reputation before a peer is disconnected.
|
||||
@ -33,18 +41,26 @@ const STATUS_INTERVAL: u64 = 300;
|
||||
/// this time frame (Seconds)
|
||||
const PING_INTERVAL: u64 = 30;
|
||||
|
||||
/// The heartbeat performs regular updates such as updating reputations and performing discovery
|
||||
/// requests. This defines the interval in seconds.
|
||||
const HEARTBEAT_INTERVAL: u64 = 30;
|
||||
|
||||
/// The main struct that handles peer's reputation and connection status.
|
||||
pub struct PeerManager<TSpec: EthSpec> {
|
||||
/// Storage of network globals to access the `PeerDB`.
|
||||
network_globals: Arc<NetworkGlobals<TSpec>>,
|
||||
/// A queue of events that the `PeerManager` is waiting to produce.
|
||||
events: SmallVec<[PeerManagerEvent; 5]>,
|
||||
events: SmallVec<[PeerManagerEvent; 16]>,
|
||||
/// A collection of peers awaiting to be Ping'd.
|
||||
ping_peers: HashSetDelay<PeerId>,
|
||||
/// A collection of peers awaiting to be Status'd.
|
||||
status_peers: HashSetDelay<PeerId>,
|
||||
/// Last updated moment.
|
||||
_last_updated: Instant,
|
||||
/// The target number of peers we would like to connect to.
|
||||
target_peers: usize,
|
||||
/// The discovery service.
|
||||
discovery: Discovery<TSpec>,
|
||||
/// The heartbeat interval to perform routine maintenance.
|
||||
heartbeat: tokio::time::Interval,
|
||||
/// The logger associated with the `PeerManager`.
|
||||
log: slog::Logger,
|
||||
}
|
||||
@ -89,6 +105,10 @@ impl PeerAction {
|
||||
|
||||
/// The events that the `PeerManager` outputs (requests).
|
||||
pub enum PeerManagerEvent {
|
||||
/// Dial a PeerId.
|
||||
Dial(PeerId),
|
||||
/// Inform libp2p that our external socket addr has been updated.
|
||||
SocketUpdated(Multiaddr),
|
||||
/// Sends a STATUS to a peer.
|
||||
Status(PeerId),
|
||||
/// Sends a PING to a peer.
|
||||
@ -100,99 +120,59 @@ pub enum PeerManagerEvent {
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
pub fn new(network_globals: Arc<NetworkGlobals<TSpec>>, log: &slog::Logger) -> Self {
|
||||
PeerManager {
|
||||
// NOTE: Must be run inside a tokio executor.
|
||||
pub fn new(
|
||||
local_key: &Keypair,
|
||||
config: &NetworkConfig,
|
||||
network_globals: Arc<NetworkGlobals<TSpec>>,
|
||||
log: &slog::Logger,
|
||||
) -> error::Result<Self> {
|
||||
// start the discovery service
|
||||
let mut discovery = Discovery::new(local_key, config, network_globals.clone(), log)?;
|
||||
|
||||
// start searching for peers
|
||||
discovery.discover_peers();
|
||||
|
||||
let heartbeat = tokio::time::interval(tokio::time::Duration::from_secs(HEARTBEAT_INTERVAL));
|
||||
|
||||
Ok(PeerManager {
|
||||
network_globals,
|
||||
events: SmallVec::new(),
|
||||
_last_updated: Instant::now(),
|
||||
ping_peers: HashSetDelay::new(Duration::from_secs(PING_INTERVAL)),
|
||||
status_peers: HashSetDelay::new(Duration::from_secs(STATUS_INTERVAL)),
|
||||
target_peers: config.max_peers, //TODO: Add support for target peers and max peers
|
||||
discovery,
|
||||
heartbeat,
|
||||
log: log.clone(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* Public accessible functions */
|
||||
|
||||
/// A ping request has been received.
|
||||
// NOTE: The behaviour responds with a PONG automatically
|
||||
// TODO: Update last seen
|
||||
pub fn ping_request(&mut self, peer_id: &PeerId, seq: u64) {
|
||||
if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
|
||||
// received a ping
|
||||
// reset the to-ping timer for this peer
|
||||
debug!(self.log, "Received a ping request"; "peer_id" => peer_id.to_string(), "seq_no" => seq);
|
||||
self.ping_peers.insert(peer_id.clone());
|
||||
/* Discovery Requests */
|
||||
|
||||
// if the sequence number is unknown send an update the meta data of the peer.
|
||||
if let Some(meta_data) = &peer_info.meta_data {
|
||||
if meta_data.seq_number < seq {
|
||||
debug!(self.log, "Requesting new metadata from peer";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => meta_data.seq_number, "ping_seq_no" => seq);
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
// if we don't know the meta-data, request it
|
||||
debug!(self.log, "Requesting first metadata from peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
crit!(self.log, "Received a PING from an unknown peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
}
|
||||
/// Provides a reference to the underlying discovery service.
|
||||
pub fn discovery(&self) -> &Discovery<TSpec> {
|
||||
&self.discovery
|
||||
}
|
||||
|
||||
/// A PONG has been returned from a peer.
|
||||
// TODO: Update last seen
|
||||
pub fn pong_response(&mut self, peer_id: &PeerId, seq: u64) {
|
||||
if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
|
||||
// received a pong
|
||||
|
||||
// if the sequence number is unknown send update the meta data of the peer.
|
||||
if let Some(meta_data) = &peer_info.meta_data {
|
||||
if meta_data.seq_number < seq {
|
||||
debug!(self.log, "Requesting new metadata from peer";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => meta_data.seq_number, "pong_seq_no" => seq);
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
// if we don't know the meta-data, request it
|
||||
debug!(self.log, "Requesting first metadata from peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
crit!(self.log, "Received a PONG from an unknown peer"; "peer_id" => peer_id.to_string());
|
||||
}
|
||||
/// Provides a mutable reference to the underlying discovery service.
|
||||
pub fn discovery_mut(&mut self) -> &mut Discovery<TSpec> {
|
||||
&mut self.discovery
|
||||
}
|
||||
|
||||
/// Received a metadata response from a peer.
|
||||
// TODO: Update last seen
|
||||
pub fn meta_data_response(&mut self, peer_id: &PeerId, meta_data: MetaData<TSpec>) {
|
||||
if let Some(peer_info) = self.network_globals.peers.write().peer_info_mut(peer_id) {
|
||||
if let Some(known_meta_data) = &peer_info.meta_data {
|
||||
if known_meta_data.seq_number < meta_data.seq_number {
|
||||
debug!(self.log, "Updating peer's metadata";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
|
||||
peer_info.meta_data = Some(meta_data);
|
||||
} else {
|
||||
debug!(self.log, "Received old metadata";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
|
||||
}
|
||||
} else {
|
||||
// we have no meta-data for this peer, update
|
||||
debug!(self.log, "Obtained peer's metadata";
|
||||
"peer_id" => peer_id.to_string(), "new_seq_no" => meta_data.seq_number);
|
||||
peer_info.meta_data = Some(meta_data);
|
||||
}
|
||||
} else {
|
||||
crit!(self.log, "Received METADATA from an unknown peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
/// A request to find peers on a given subnet.
|
||||
pub fn discover_subnet_peers(&mut self, subnet_id: SubnetId, min_ttl: Option<Instant>) {
|
||||
// Extend the time to maintain peers if required.
|
||||
if let Some(min_ttl) = min_ttl {
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.extend_peers_on_subnet(subnet_id, min_ttl);
|
||||
}
|
||||
|
||||
// request the subnet query from discovery
|
||||
self.discovery.discover_subnet_peers(subnet_id, min_ttl);
|
||||
}
|
||||
|
||||
/// A STATUS message has been received from a peer. This resets the status timer.
|
||||
@ -320,8 +300,158 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
self.report_peer(peer_id, peer_action);
|
||||
}
|
||||
|
||||
/// A ping request has been received.
|
||||
// NOTE: The behaviour responds with a PONG automatically
|
||||
// TODO: Update last seen
|
||||
pub fn ping_request(&mut self, peer_id: &PeerId, seq: u64) {
|
||||
if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
|
||||
// received a ping
|
||||
// reset the to-ping timer for this peer
|
||||
debug!(self.log, "Received a ping request"; "peer_id" => peer_id.to_string(), "seq_no" => seq);
|
||||
self.ping_peers.insert(peer_id.clone());
|
||||
|
||||
// if the sequence number is unknown send an update the meta data of the peer.
|
||||
if let Some(meta_data) = &peer_info.meta_data {
|
||||
if meta_data.seq_number < seq {
|
||||
debug!(self.log, "Requesting new metadata from peer";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => meta_data.seq_number, "ping_seq_no" => seq);
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
// if we don't know the meta-data, request it
|
||||
debug!(self.log, "Requesting first metadata from peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
crit!(self.log, "Received a PING from an unknown peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
/// A PONG has been returned from a peer.
|
||||
// TODO: Update last seen
|
||||
pub fn pong_response(&mut self, peer_id: &PeerId, seq: u64) {
|
||||
if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
|
||||
// received a pong
|
||||
|
||||
// if the sequence number is unknown send update the meta data of the peer.
|
||||
if let Some(meta_data) = &peer_info.meta_data {
|
||||
if meta_data.seq_number < seq {
|
||||
debug!(self.log, "Requesting new metadata from peer";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => meta_data.seq_number, "pong_seq_no" => seq);
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
// if we don't know the meta-data, request it
|
||||
debug!(self.log, "Requesting first metadata from peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
self.events
|
||||
.push(PeerManagerEvent::MetaData(peer_id.clone()));
|
||||
}
|
||||
} else {
|
||||
crit!(self.log, "Received a PONG from an unknown peer"; "peer_id" => peer_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
/// Received a metadata response from a peer.
|
||||
// TODO: Update last seen
|
||||
pub fn meta_data_response(&mut self, peer_id: &PeerId, meta_data: MetaData<TSpec>) {
|
||||
if let Some(peer_info) = self.network_globals.peers.write().peer_info_mut(peer_id) {
|
||||
if let Some(known_meta_data) = &peer_info.meta_data {
|
||||
if known_meta_data.seq_number < meta_data.seq_number {
|
||||
debug!(self.log, "Updating peer's metadata";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
|
||||
peer_info.meta_data = Some(meta_data);
|
||||
} else {
|
||||
debug!(self.log, "Received old metadata";
|
||||
"peer_id" => peer_id.to_string(), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
|
||||
}
|
||||
} else {
|
||||
// we have no meta-data for this peer, update
|
||||
debug!(self.log, "Obtained peer's metadata";
|
||||
"peer_id" => peer_id.to_string(), "new_seq_no" => meta_data.seq_number);
|
||||
peer_info.meta_data = Some(meta_data);
|
||||
}
|
||||
} else {
|
||||
crit!(self.log, "Received METADATA from an unknown peer";
|
||||
"peer_id" => peer_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Handles the libp2p request to obtain multiaddrs for peer_id's in order to dial them.
|
||||
pub fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
if let Some(enr) = self.discovery.enr_of_peer(peer_id) {
|
||||
// ENR's may have multiple Multiaddrs. The multi-addr associated with the UDP
|
||||
// port is removed, which is assumed to be associated with the discv5 protocol (and
|
||||
// therefore irrelevant for other libp2p components).
|
||||
let mut out_list = enr.multiaddr();
|
||||
out_list.retain(|addr| {
|
||||
addr.iter()
|
||||
.find(|v| match v {
|
||||
MProtocol::Udp(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
.is_none()
|
||||
});
|
||||
|
||||
out_list
|
||||
} else {
|
||||
// PeerId is not known
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal functions */
|
||||
|
||||
// The underlying discovery server has updated our external IP address. We send this up to
|
||||
// notify libp2p.
|
||||
fn socket_updated(&mut self, socket: SocketAddr) {
|
||||
// Build a multiaddr to report to libp2p
|
||||
let mut multiaddr = Multiaddr::from(socket.ip());
|
||||
// NOTE: This doesn't actually track the external TCP port. More sophisticated NAT handling
|
||||
// should handle this.
|
||||
multiaddr.push(MProtocol::Tcp(self.network_globals.listen_port_tcp()));
|
||||
self.events.push(PeerManagerEvent::SocketUpdated(multiaddr));
|
||||
}
|
||||
|
||||
/// Peers that have been returned by discovery requests are dialed here if they are suitable.
|
||||
///
|
||||
/// NOTE: By dialing `PeerId`s and not multiaddrs, libp2p requests the multiaddr associated
|
||||
/// with a new `PeerId` which involves a discovery routing table lookup. We could dial the
|
||||
/// multiaddr here, however this could relate to duplicate PeerId's etc. If the lookup
|
||||
/// proves resource constraining, we should switch to multiaddr dialling here.
|
||||
fn peers_discovered(&mut self, peers: Vec<Enr>, min_ttl: Option<Instant>) {
|
||||
for enr in peers {
|
||||
let peer_id = enr.peer_id();
|
||||
|
||||
// if we need more peers, attempt a connection
|
||||
if self.network_globals.connected_or_dialing_peers() < self.target_peers
|
||||
&& !self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.is_connected_or_dialing(&peer_id)
|
||||
&& !self.network_globals.peers.read().peer_banned(&peer_id)
|
||||
{
|
||||
debug!(self.log, "Dialing discovered peer"; "peer_id"=> peer_id.to_string());
|
||||
// TODO: Update output
|
||||
// This should be updated with the peer dialing. In fact created once the peer is
|
||||
// dialed
|
||||
if let Some(min_ttl) = min_ttl {
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.update_min_ttl(&peer_id, min_ttl);
|
||||
}
|
||||
self.events.push(PeerManagerEvent::Dial(peer_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a peer as connected. The `ingoing` parameter determines if the peer is being
|
||||
/// dialed or connecting to us.
|
||||
///
|
||||
@ -376,12 +506,11 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
///
|
||||
/// A banned(disconnected) peer that gets its rep above(below) MIN_REP_BEFORE_BAN is
|
||||
/// now considered a disconnected(banned) peer.
|
||||
// TODO: Implement when reputation is added.
|
||||
fn _update_reputations(&mut self) {
|
||||
/*
|
||||
// avoid locking the peerdb too often
|
||||
// TODO: call this on a timer
|
||||
if self._last_updated.elapsed().as_secs() < 30 {
|
||||
return;
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
@ -457,6 +586,28 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
}
|
||||
|
||||
self._last_updated = Instant::now();
|
||||
*/
|
||||
}
|
||||
|
||||
/// The Peer manager's heartbeat maintains the peer count and maintains peer reputations.
|
||||
///
|
||||
/// It will request discovery queries if the peer count has not reached the desired number of
|
||||
/// peers.
|
||||
///
|
||||
/// NOTE: Discovery will only add a new query if one isn't already queued.
|
||||
fn heartbeat(&mut self) {
|
||||
// TODO: Provide a back-off time for discovery queries. I.e Queue many initially, then only
|
||||
// perform discoveries over a larger fixed interval. Perhaps one every 6 heartbeats
|
||||
let peer_count = self.network_globals.connected_or_dialing_peers();
|
||||
if peer_count < self.target_peers {
|
||||
// If we need more peers, queue a discovery lookup.
|
||||
self.discovery.discover_peers();
|
||||
}
|
||||
|
||||
// TODO: If we have too many peers, remove peers that are not required for subnet
|
||||
// validation.
|
||||
|
||||
// TODO: Perform peer reputation maintenance here
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,6 +615,21 @@ impl<TSpec: EthSpec> Stream for PeerManager<TSpec> {
|
||||
type Item = PeerManagerEvent;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
// perform the heartbeat when necessary
|
||||
while let Poll::Ready(Some(_)) = self.heartbeat.poll_next_unpin(cx) {
|
||||
self.heartbeat();
|
||||
}
|
||||
|
||||
// handle any discovery events
|
||||
while let Poll::Ready(event) = self.discovery.poll(cx) {
|
||||
match event {
|
||||
DiscoveryEvent::SocketUpdated(socket_addr) => self.socket_updated(socket_addr),
|
||||
DiscoveryEvent::QueryResult(min_ttl, peers) => {
|
||||
self.peers_discovered(*peers, min_ttl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// poll the timeouts for pings and status'
|
||||
loop {
|
||||
match self.ping_peers.poll_next_unpin(cx) {
|
@ -106,6 +106,14 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the Peer is banned.
|
||||
pub fn peer_banned(&self, peer_id: &PeerId) -> bool {
|
||||
match self.peers.get(peer_id).map(|info| &info.connection_status) {
|
||||
Some(status) => status.is_banned(),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gives the ids of all known connected peers.
|
||||
pub fn connected_peers(&self) -> impl Iterator<Item = (&PeerId, &PeerInfo<TSpec>)> {
|
||||
self.peers
|
@ -4,7 +4,7 @@ use crate::rpc::methods::MetaData;
|
||||
use crate::types::SyncState;
|
||||
use crate::Client;
|
||||
use crate::EnrExt;
|
||||
use crate::{discovery::enr::Eth2Enr, Enr, GossipTopic, Multiaddr, PeerId};
|
||||
use crate::{Enr, Eth2Enr, GossipTopic, Multiaddr, PeerId};
|
||||
use parking_lot::RwLock;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::atomic::{AtomicU16, Ordering};
|
@ -115,7 +115,7 @@ pub fn build_libp2p_instance(
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_enr(node: &LibP2PService<E>) -> Enr {
|
||||
let enr = node.swarm.discovery().local_enr().clone();
|
||||
let enr = node.swarm.local_enr().clone();
|
||||
enr
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ pub async fn build_node_pair(log: &slog::Logger) -> (Libp2pInstance, Libp2pInsta
|
||||
let mut sender = build_libp2p_instance(vec![], None, sender_log);
|
||||
let mut receiver = build_libp2p_instance(vec![], None, receiver_log);
|
||||
|
||||
let receiver_multiaddr = receiver.swarm.discovery().local_enr().clone().multiaddr()[1].clone();
|
||||
let receiver_multiaddr = receiver.swarm.local_enr().multiaddr()[1].clone();
|
||||
|
||||
// let the two nodes set up listeners
|
||||
let sender_fut = async {
|
@ -15,7 +15,7 @@ exit-future = "0.2.0"
|
||||
[dependencies]
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
store = { path = "../store" }
|
||||
eth2-libp2p = { path = "../eth2-libp2p" }
|
||||
eth2_libp2p = { path = "../eth2_libp2p" }
|
||||
hashset_delay = { path = "../../common/hashset_delay" }
|
||||
rest_types = { path = "../../common/rest_types" }
|
||||
types = { path = "../../consensus/types" }
|
||||
|
@ -71,17 +71,20 @@ impl PartialEq for AttServiceMessage {
|
||||
subnet_id: other_subnet_id,
|
||||
min_ttl: other_min_ttl,
|
||||
},
|
||||
) => match (min_ttl, other_min_ttl) {
|
||||
(Some(min_ttl_instant), Some(other_min_ttl_instant)) => {
|
||||
min_ttl_instant.saturating_duration_since(other_min_ttl_instant)
|
||||
< DURATION_DIFFERENCE
|
||||
&& other_min_ttl_instant.saturating_duration_since(min_ttl_instant)
|
||||
< DURATION_DIFFERENCE
|
||||
&& subnet_id == other_subnet_id
|
||||
}
|
||||
(None, None) => subnet_id == other_subnet_id,
|
||||
_ => false,
|
||||
},
|
||||
) => {
|
||||
subnet_id == other_subnet_id
|
||||
&& match (min_ttl, other_min_ttl) {
|
||||
(Some(min_ttl_instant), Some(other_min_ttl_instant)) => {
|
||||
min_ttl_instant.saturating_duration_since(other_min_ttl_instant)
|
||||
< DURATION_DIFFERENCE
|
||||
&& other_min_ttl_instant.saturating_duration_since(min_ttl_instant)
|
||||
< DURATION_DIFFERENCE
|
||||
}
|
||||
(None, None) => true,
|
||||
(None, Some(_)) => true,
|
||||
(Some(_), None) => true,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -353,12 +356,12 @@ impl<T: BeaconChainTypes> AttestationService<T> {
|
||||
*other_min_ttl = min_ttl;
|
||||
}
|
||||
}
|
||||
(None, Some(_)) => {
|
||||
// Update the min_ttl to None, because the new message is longer-lived.
|
||||
*other_min_ttl = None;
|
||||
(None, Some(_)) => {} // Keep the current one as it has an actual min_ttl
|
||||
(Some(min_ttl), None) => {
|
||||
// Update the request to include a min_ttl.
|
||||
*other_min_ttl = Some(min_ttl);
|
||||
}
|
||||
(Some(_), None) => {} // Don't replace this because the existing message is for a longer-lived peer.
|
||||
(None, None) => {} // Duplicate message, do nothing.
|
||||
(None, None) => {} // Duplicate message, do nothing.
|
||||
}
|
||||
is_duplicate = true;
|
||||
return;
|
||||
|
@ -11,7 +11,7 @@ use eth2_libp2p::{
|
||||
rpc::{RPCResponseErrorCode, RequestId},
|
||||
Libp2pEvent, PeerRequestId, PubsubMessage, Request, Response,
|
||||
};
|
||||
use eth2_libp2p::{BehaviourEvent, Enr, MessageId, NetworkGlobals, PeerId};
|
||||
use eth2_libp2p::{BehaviourEvent, MessageId, NetworkGlobals, PeerId};
|
||||
use futures::prelude::*;
|
||||
use rest_types::ValidatorSubscription;
|
||||
use slog::{debug, error, info, o, trace};
|
||||
@ -136,7 +136,7 @@ fn spawn_service<T: BeaconChainTypes>(
|
||||
// handle network shutdown
|
||||
_ = (&mut exit_rx) => {
|
||||
// network thread is terminating
|
||||
let enrs: Vec<Enr> = service.libp2p.swarm.enr_entries().cloned().collect();
|
||||
let enrs = service.libp2p.swarm.enr_entries();
|
||||
debug!(
|
||||
service.log,
|
||||
"Persisting DHT to store";
|
||||
|
@ -10,7 +10,7 @@ bls = { path = "../../crypto/bls" }
|
||||
rest_types = { path = "../../common/rest_types" }
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
network = { path = "../network" }
|
||||
eth2-libp2p = { path = "../eth2-libp2p" }
|
||||
eth2_libp2p = { path = "../eth2_libp2p" }
|
||||
store = { path = "../store" }
|
||||
version = { path = "../version" }
|
||||
serde = { version = "1.0.110", features = ["derive"] }
|
||||
|
@ -82,6 +82,8 @@ impl<E: EthSpec> ProductionBeaconNode<E> {
|
||||
let db_path = client_config.create_db_path()?;
|
||||
let freezer_db_path_res = client_config.create_freezer_db_path();
|
||||
|
||||
let executor = context.executor.clone();
|
||||
|
||||
let builder = ClientBuilder::new(context.eth_spec_instance.clone())
|
||||
.runtime_context(context)
|
||||
.chain_spec(spec)
|
||||
@ -119,6 +121,9 @@ impl<E: EthSpec> ProductionBeaconNode<E> {
|
||||
.system_time_slot_clock()?
|
||||
.tee_event_handler(client_config.websocket_server.clone())?;
|
||||
|
||||
// Inject the executor into the discv5 network config.
|
||||
client_config.network.discv5_config.executor = Some(Box::new(executor));
|
||||
|
||||
let builder = builder
|
||||
.build_beacon_chain()?
|
||||
.network(&mut client_config.network)?
|
||||
|
@ -28,7 +28,7 @@ deposit_contract = { path = "../common/deposit_contract" }
|
||||
tree_hash = "0.1.0"
|
||||
tokio = { version = "0.2.21", features = ["full"] }
|
||||
clap_utils = { path = "../common/clap_utils" }
|
||||
eth2-libp2p = { path = "../beacon_node/eth2-libp2p" }
|
||||
eth2_libp2p = { path = "../beacon_node/eth2_libp2p" }
|
||||
validator_dir = { path = "../common/validator_dir", features = ["insecure_keys"] }
|
||||
rand = "0.7.2"
|
||||
eth2_keystore = { path = "../crypto/eth2_keystore" }
|
||||
|
@ -21,3 +21,4 @@ slog-json = "2.3.0"
|
||||
exit-future = "0.2.0"
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
discv5 = "0.1.0-alpha.5"
|
||||
|
@ -126,3 +126,9 @@ impl TaskExecutor {
|
||||
&self.log
|
||||
}
|
||||
}
|
||||
|
||||
impl discv5::Executor for TaskExecutor {
|
||||
fn spawn(&self, future: std::pin::Pin<Box<dyn Future<Output = ()> + Send>>) {
|
||||
self.spawn(future, "discv5")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user