Global Network Behaviour Refactor (#2442)

* Network upgrades (#2345)

* Discovery patch (#2382)

* Upgrade libp2p and unstable gossip

* Network protocol upgrades

* Correct dependencies, reduce incoming bucket limit

* Clean up dirty DHT entries before repopulating

* Update cargo lock

* Update lockfile

* Update ENR dep

* Update deps to specific versions

* Update test dependencies

* Update docker rust, and remote signer tests

* More remote signer test fixes

* Temp commit

* Update discovery

* Remove cached enrs after dialing

* Increase the session capacity, for improved efficiency

* Bleeding edge discovery (#2435)

* Update discovery banning logic and tokio

* Update to latest discovery

* Shift to latest discovery

* Fmt

* Initial re-factor of the behaviour

* More progress

* Missed changes

* First draft

* Discovery as a behaviour

* Adding back event waker (not convinced its neccessary, but have made this many changes already)

* Corrections

* Speed up discovery

* Remove double log

* Fmt

* After disconnect inform swarm about ban

* More fmt

* Appease clippy

* Improve ban handling

* Update tests

* Update cargo.lock

* Correct tests

* Downgrade log
This commit is contained in:
Age Manning 2021-07-13 10:48:33 +10:00
parent 64226321b3
commit 3c0d3227ab
No known key found for this signature in database
GPG Key ID: 05EED64B79E06A93
18 changed files with 1190 additions and 1680 deletions

465
Cargo.lock generated
View File

@ -87,7 +87,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e3e798aa0c8239776f54415bc06f3d74b1850f3f830b45c35cfc80556973f70"
dependencies = [
"generic-array 0.14.4",
"generic-array",
]
[[package]]
@ -100,7 +100,7 @@ dependencies = [
"cipher 0.3.0",
"cpufeatures",
"ctr",
"opaque-debug 0.3.0",
"opaque-debug",
]
[[package]]
@ -114,7 +114,7 @@ dependencies = [
"cipher 0.3.0",
"ctr",
"ghash",
"subtle 2.4.1",
"subtle",
]
[[package]]
@ -638,20 +638,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4"
dependencies = [
"crypto-mac 0.8.0",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding 0.1.5",
"byte-tools",
"byteorder",
"generic-array 0.12.4",
"digest",
"opaque-debug",
]
[[package]]
@ -660,17 +648,8 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"block-padding 0.2.1",
"generic-array 0.14.4",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
"block-padding",
"generic-array",
]
[[package]]
@ -793,12 +772,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.3"
@ -930,7 +903,7 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
dependencies = [
"generic-array 0.14.4",
"generic-array",
]
[[package]]
@ -939,7 +912,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array 0.14.4",
"generic-array",
]
[[package]]
@ -1205,24 +1178,14 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
dependencies = [
"generic-array 0.12.4",
"subtle 1.0.0",
]
[[package]]
name = "crypto-mac"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
dependencies = [
"generic-array 0.14.4",
"subtle 2.4.1",
"generic-array",
"subtle",
]
[[package]]
@ -1231,8 +1194,8 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6"
dependencies = [
"generic-array 0.14.4",
"subtle 2.4.1",
"generic-array",
"subtle",
]
[[package]]
@ -1241,8 +1204,8 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e"
dependencies = [
"generic-array 0.14.4",
"subtle 2.4.1",
"generic-array",
"subtle",
]
[[package]]
@ -1334,9 +1297,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3"
dependencies = [
"byteorder",
"digest 0.9.0",
"digest",
"rand_core 0.5.1",
"subtle 2.4.1",
"subtle",
"zeroize",
]
@ -1416,7 +1379,7 @@ dependencies = [
"hex",
"reqwest",
"serde_json",
"sha2 0.9.5",
"sha2",
"tree_hash",
"types",
]
@ -1478,22 +1441,13 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.4",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.4",
"generic-array",
]
[[package]]
@ -1562,20 +1516,20 @@ dependencies = [
"aes",
"aes-gcm",
"arrayvec 0.7.1",
"digest 0.9.0",
"digest",
"enr",
"fnv",
"futures",
"hex",
"hkdf",
"lazy_static",
"libp2p-core 0.29.0",
"libp2p-core 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lru",
"lru_time_cache",
"parking_lot",
"rand 0.8.4",
"rlp 0.5.0",
"sha2 0.9.5",
"sha2",
"smallvec",
"tokio 1.8.1",
"tokio-stream",
@ -1623,7 +1577,7 @@ dependencies = [
"ed25519",
"rand 0.7.3",
"serde",
"sha2 0.9.5",
"sha2",
"zeroize",
]
@ -1669,11 +1623,11 @@ checksum = "c13e9b0c3c4170dcc2a12783746c4205d98e18957f57854251eea3f9750fe005"
dependencies = [
"bitvec 0.20.4",
"ff",
"generic-array 0.14.4",
"generic-array",
"group",
"pkcs8",
"rand_core 0.6.3",
"subtle 2.4.1",
"subtle",
"zeroize",
]
@ -1841,7 +1795,7 @@ dependencies = [
"futures",
"futures-util",
"hex",
"libsecp256k1 0.5.0",
"libsecp256k1",
"procinfo",
"proto_array",
"psutil",
@ -1872,7 +1826,7 @@ dependencies = [
"lazy_static",
"ring",
"rustc-hex",
"sha2 0.9.5",
"sha2",
"wasm-bindgen-test",
]
@ -1899,7 +1853,7 @@ dependencies = [
"hex",
"num-bigint-dig",
"ring",
"sha2 0.9.5",
"sha2",
"zeroize",
]
@ -1919,7 +1873,7 @@ dependencies = [
"serde",
"serde_json",
"serde_repr",
"sha2 0.9.5",
"sha2",
"tempfile",
"unicode-normalization",
"uuid",
@ -1954,7 +1908,7 @@ dependencies = [
"regex",
"serde",
"serde_derive",
"sha2 0.9.5",
"sha2",
"slog",
"slog-async",
"slog-term",
@ -2143,12 +2097,6 @@ dependencies = [
"futures",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fallback"
version = "0.1.0"
@ -2185,7 +2133,7 @@ checksum = "72a4d941a5b7c2a75222e2d44fcdf634a67133d9db31e177ae5ff6ecda852bfe"
dependencies = [
"bitvec 0.20.4",
"rand_core 0.6.3",
"subtle 2.4.1",
"subtle",
]
[[package]]
@ -2440,15 +2388,6 @@ dependencies = [
"slab",
]
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
@ -2513,7 +2452,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bbd60caa311237d508927dbba7594b483db3ef05faa55172fcf89b1bcda7853"
dependencies = [
"opaque-debug 0.3.0",
"opaque-debug",
"polyval",
]
@ -2572,7 +2511,7 @@ checksum = "61b3c1e8b4f1ca07e6605ea1be903a5f6956aec5c8a67fd44d56076631675ed8"
dependencies = [
"ff",
"rand_core 0.6.3",
"subtle 2.4.1",
"subtle",
]
[[package]]
@ -2694,20 +2633,10 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
dependencies = [
"digest 0.9.0",
"digest",
"hmac 0.11.0",
]
[[package]]
name = "hmac"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
dependencies = [
"crypto-mac 0.7.0",
"digest 0.8.1",
]
[[package]]
name = "hmac"
version = "0.8.1"
@ -2715,7 +2644,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
dependencies = [
"crypto-mac 0.8.0",
"digest 0.9.0",
"digest",
]
[[package]]
@ -2725,7 +2654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
dependencies = [
"crypto-mac 0.10.0",
"digest 0.9.0",
"digest",
]
[[package]]
@ -2735,18 +2664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac 0.11.0",
"digest 0.9.0",
]
[[package]]
name = "hmac-drbg"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b"
dependencies = [
"digest 0.8.1",
"generic-array 0.12.4",
"hmac 0.7.1",
"digest",
]
[[package]]
@ -2755,8 +2673,8 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1"
dependencies = [
"digest 0.9.0",
"generic-array 0.14.4",
"digest",
"generic-array",
"hmac 0.8.1",
]
@ -3187,7 +3105,7 @@ dependencies = [
"cfg-if 1.0.0",
"ecdsa",
"elliptic-curve",
"sha2 0.9.5",
"sha2",
]
[[package]]
@ -3355,15 +3273,14 @@ dependencies = [
[[package]]
name = "libp2p"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebbb17eece4aec5bb970880c73825c16ca59ca05a4e41803751e68c7e5f0c618"
version = "0.39.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"atomic",
"bytes 1.0.1",
"futures",
"lazy_static",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"libp2p-dns",
"libp2p-gossipsub",
"libp2p-identify",
@ -3374,47 +3291,13 @@ dependencies = [
"libp2p-tcp",
"libp2p-websocket",
"libp2p-yamux",
"parity-multiaddr",
"multiaddr 0.12.0",
"parking_lot",
"pin-project 1.0.7",
"smallvec",
"wasm-timer",
]
[[package]]
name = "libp2p-core"
version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "554d3e7e9e65f939d66b75fd6a4c67f258fe250da61b91f46c545fc4a89b51d9"
dependencies = [
"asn1_der",
"bs58",
"ed25519-dalek",
"either",
"fnv",
"futures",
"futures-timer",
"lazy_static",
"libsecp256k1 0.3.5",
"log",
"multihash 0.13.2",
"multistream-select",
"parity-multiaddr",
"parking_lot",
"pin-project 1.0.7",
"prost 0.7.0",
"prost-build 0.7.0",
"rand 0.7.3",
"ring",
"rw-stream-sink",
"sha2 0.9.5",
"smallvec",
"thiserror",
"unsigned-varint 0.7.0",
"void",
"zeroize",
]
[[package]]
name = "libp2p-core"
version = "0.29.0"
@ -3429,11 +3312,11 @@ dependencies = [
"futures",
"futures-timer",
"lazy_static",
"libsecp256k1 0.5.0",
"libsecp256k1",
"log",
"multiaddr",
"multiaddr 0.13.0",
"multihash 0.14.0",
"multistream-select",
"multistream-select 0.10.2",
"parking_lot",
"pin-project 1.0.7",
"prost 0.8.0",
@ -3441,7 +3324,40 @@ dependencies = [
"rand 0.7.3",
"ring",
"rw-stream-sink",
"sha2 0.9.5",
"sha2",
"smallvec",
"thiserror",
"unsigned-varint 0.7.0",
"void",
"zeroize",
]
[[package]]
name = "libp2p-core"
version = "0.29.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"asn1_der",
"bs58",
"ed25519-dalek",
"either",
"fnv",
"futures",
"futures-timer",
"lazy_static",
"libsecp256k1",
"log",
"multiaddr 0.12.0",
"multihash 0.13.2",
"multistream-select 0.10.3",
"parking_lot",
"pin-project 1.0.7",
"prost 0.7.0",
"prost-build 0.7.0",
"rand 0.7.3",
"ring",
"rw-stream-sink",
"sha2",
"smallvec",
"thiserror",
"unsigned-varint 0.7.0",
@ -3451,12 +3367,11 @@ dependencies = [
[[package]]
name = "libp2p-dns"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62e63dab8b5ff35e0c101a3e51e843ba782c07bbb1682f5fd827622e0d02b98b"
version = "0.29.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"futures",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"log",
"smallvec",
"trust-dns-resolver",
@ -3464,9 +3379,8 @@ dependencies = [
[[package]]
name = "libp2p-gossipsub"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e562308761818b0c52f2a81a0544b9c22d0cf56d7b2d928a0ff61382404498ce"
version = "0.32.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"asynchronous-codec",
"base64 0.13.0",
@ -3475,14 +3389,14 @@ dependencies = [
"fnv",
"futures",
"hex_fmt",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"libp2p-swarm",
"log",
"prost 0.7.0",
"prost-build 0.7.0",
"rand 0.7.3",
"regex",
"sha2 0.9.5",
"sha2",
"smallvec",
"unsigned-varint 0.7.0",
"wasm-timer",
@ -3490,12 +3404,11 @@ dependencies = [
[[package]]
name = "libp2p-identify"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f668f00efd9883e8b7bcc582eaf0164615792608f886f6577da18bcbeea0a46"
version = "0.30.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"futures",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"libp2p-swarm",
"log",
"prost 0.7.0",
@ -3506,14 +3419,13 @@ dependencies = [
[[package]]
name = "libp2p-mplex"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e9b544335d1ed30af71daa96edbefadef6f19c7a55f078b9fc92c87163105d"
version = "0.29.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"asynchronous-codec",
"bytes 1.0.1",
"futures",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"log",
"nohash-hasher",
"parking_lot",
@ -3524,20 +3436,19 @@ dependencies = [
[[package]]
name = "libp2p-noise"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a2aa6fc4e6855eaf9ea1941a14f7ec4df35636fb6b85951e17481df8dcecf6"
version = "0.32.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"bytes 1.0.1",
"curve25519-dalek",
"futures",
"lazy_static",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"log",
"prost 0.7.0",
"prost-build 0.7.0",
"rand 0.8.4",
"sha2 0.9.5",
"sha2",
"snow",
"static_assertions",
"x25519-dalek",
@ -3546,13 +3457,12 @@ dependencies = [
[[package]]
name = "libp2p-swarm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e04d8e1eef675029ec728ba14e8d0da7975d84b6679b699b4ae91a1de9c3a92"
version = "0.30.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"either",
"futures",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"log",
"rand 0.7.3",
"smallvec",
@ -3563,8 +3473,7 @@ dependencies = [
[[package]]
name = "libp2p-swarm-derive"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365b0a699fea5168676840567582a012ea297b1ca02eee467e58301b9c9c5eed"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"quote",
"syn",
@ -3572,16 +3481,15 @@ dependencies = [
[[package]]
name = "libp2p-tcp"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b1a27d21c477951799e99d5c105d78868258502ce092988040a808d5a19bbd9"
version = "0.29.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"futures",
"futures-timer",
"if-addrs",
"ipnet",
"libc",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"log",
"socket2 0.4.0",
"tokio 1.8.1",
@ -3589,14 +3497,13 @@ dependencies = [
[[package]]
name = "libp2p-websocket"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cace60995ef6f637e4752cccbb2590f6bc358e8741a0d066307636c69a4b3a74"
version = "0.30.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"either",
"futures",
"futures-rustls",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"log",
"quicksink",
"rw-stream-sink",
@ -3607,33 +3514,16 @@ dependencies = [
[[package]]
name = "libp2p-yamux"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f35da42cfc6d5cb0dcf3ad6881bc68d146cdf38f98655e09e33fbba4d13eabc4"
version = "0.33.0"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"futures",
"libp2p-core 0.28.3",
"libp2p-core 0.29.0 (git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93)",
"parking_lot",
"thiserror",
"yamux",
]
[[package]]
name = "libsecp256k1"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962"
dependencies = [
"arrayref",
"crunchy",
"digest 0.8.1",
"hmac-drbg 0.2.0",
"rand 0.7.3",
"sha2 0.8.2",
"subtle 2.4.1",
"typenum",
]
[[package]]
name = "libsecp256k1"
version = "0.5.0"
@ -3642,14 +3532,14 @@ checksum = "bd1137239ab33b41aa9637a88a28249e5e70c40a42ccc92db7f12cc356c1fcd7"
dependencies = [
"arrayref",
"base64 0.12.3",
"digest 0.9.0",
"hmac-drbg 0.3.0",
"digest",
"hmac-drbg",
"libsecp256k1-core",
"libsecp256k1-gen-ecmult",
"libsecp256k1-gen-genmult",
"rand 0.7.3",
"serde",
"sha2 0.9.5",
"sha2",
"typenum",
]
@ -3660,8 +3550,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee11012b293ea30093c129173cac4335513064094619f4639a25b310fd33c11"
dependencies = [
"crunchy",
"digest 0.9.0",
"subtle 2.4.1",
"digest",
"subtle",
]
[[package]]
@ -4011,6 +3901,24 @@ dependencies = [
"tokio 1.8.1",
]
[[package]]
name = "multiaddr"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7139982f583d7e53879d9f611fe48ced18e77d684309484f2252c76bcd39f549"
dependencies = [
"arrayref",
"bs58",
"byteorder",
"data-encoding",
"multihash 0.13.2",
"percent-encoding",
"serde",
"static_assertions",
"unsigned-varint 0.7.0",
"url",
]
[[package]]
name = "multiaddr"
version = "0.13.0"
@ -4035,10 +3943,10 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab"
dependencies = [
"digest 0.9.0",
"generic-array 0.14.4",
"digest",
"generic-array",
"multihash-derive",
"sha2 0.9.5",
"sha2",
"unsigned-varint 0.5.1",
]
@ -4048,10 +3956,10 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "752a61cd890ff691b4411423d23816d5866dd5621e4d1c5687a53b94b5a979d8"
dependencies = [
"digest 0.9.0",
"generic-array 0.14.4",
"digest",
"generic-array",
"multihash-derive",
"sha2 0.9.5",
"sha2",
"unsigned-varint 0.7.0",
]
@ -4107,6 +4015,19 @@ dependencies = [
"unsigned-varint 0.7.0",
]
[[package]]
name = "multistream-select"
version = "0.10.3"
source = "git+https://github.com/libp2p/rust-libp2p?rev=c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93#c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
dependencies = [
"bytes 1.0.1",
"futures",
"log",
"pin-project 1.0.7",
"smallvec",
"unsigned-varint 0.7.0",
]
[[package]]
name = "native-tls"
version = "0.2.7"
@ -4337,12 +4258,6 @@ version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
@ -4415,24 +4330,6 @@ dependencies = [
"types",
]
[[package]]
name = "parity-multiaddr"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58341485071825827b7f03cf7efd1cb21e6a709bea778fb50227fd45d2f361b4"
dependencies = [
"arrayref",
"bs58",
"byteorder",
"data-encoding",
"multihash 0.13.2",
"percent-encoding",
"serde",
"static_assertions",
"unsigned-varint 0.7.0",
"url",
]
[[package]]
name = "parity-scale-codec"
version = "1.3.7"
@ -4688,7 +4585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fe800695325da85083cd23b56826fccb2e2dc29b218e7811a6f33bc93f414be"
dependencies = [
"cpufeatures",
"opaque-debug 0.3.0",
"opaque-debug",
"universal-hash",
]
@ -4700,7 +4597,7 @@ checksum = "e597450cbf209787f0e6de80bf3795c6b2356a380ee87837b545aded8dbc1823"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"opaque-debug 0.3.0",
"opaque-debug",
"universal-hash",
]
@ -5572,7 +5469,7 @@ dependencies = [
"hmac 0.10.1",
"pbkdf2 0.6.0",
"salsa20",
"sha2 0.9.5",
"sha2",
]
[[package]]
@ -5775,11 +5672,11 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
dependencies = [
"block-buffer 0.9.0",
"block-buffer",
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
"digest",
"opaque-debug",
]
[[package]]
@ -5788,29 +5685,17 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]]
name = "sha2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
]
[[package]]
name = "sha2"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
dependencies = [
"block-buffer 0.9.0",
"block-buffer",
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
"digest",
"opaque-debug",
]
[[package]]
@ -5819,10 +5704,10 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
dependencies = [
"block-buffer 0.9.0",
"digest 0.9.0",
"block-buffer",
"digest",
"keccak",
"opaque-debug 0.3.0",
"opaque-debug",
]
[[package]]
@ -5859,7 +5744,7 @@ version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
dependencies = [
"digest 0.9.0",
"digest",
"rand_core 0.6.3",
]
@ -6134,8 +6019,8 @@ dependencies = [
"rand_core 0.6.3",
"ring",
"rustc_version 0.3.3",
"sha2 0.9.5",
"subtle 2.4.1",
"sha2",
"subtle",
"x25519-dalek",
]
@ -6364,12 +6249,6 @@ dependencies = [
"syn",
]
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]]
name = "subtle"
version = "2.4.1"
@ -6621,7 +6500,7 @@ dependencies = [
"pbkdf2 0.4.0",
"rand 0.7.3",
"rustc-hash",
"sha2 0.9.5",
"sha2",
"thiserror",
"unicode-normalization",
"zeroize",
@ -7148,8 +7027,8 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402"
dependencies = [
"generic-array 0.14.4",
"subtle 2.4.1",
"generic-array",
"subtle",
]
[[package]]
@ -7239,7 +7118,7 @@ dependencies = [
"hyper",
"lazy_static",
"libc",
"libsecp256k1 0.5.0",
"libsecp256k1",
"lighthouse_metrics",
"lighthouse_version",
"lockfile",

View File

@ -42,7 +42,10 @@ regex = "1.3.9"
strum = { version = "0.20", features = ["derive"] }
[dependencies.libp2p]
version = "0.38.0"
#version = "0.38.0"
# Bleeding edge, while we wait for 0.39.0
git = "https://github.com/libp2p/rust-libp2p"
rev = "c1ef4bffd225a78cefe8fa43dc8ee18e03ff4f93"
default-features = false
features = ["websocket", "identify", "mplex", "yamux", "noise", "gossipsub", "dns-tokio", "tcp-tokio"]

View File

@ -1,368 +0,0 @@
use crate::behaviour::Gossipsub;
use crate::rpc::*;
use libp2p::{
core::either::{EitherError, EitherOutput},
core::upgrade::{EitherUpgrade, InboundUpgrade, OutboundUpgrade, SelectUpgrade, UpgradeError},
identify::Identify,
swarm::{
protocols_handler::{
KeepAlive, ProtocolsHandlerEvent, ProtocolsHandlerUpgrErr, SubstreamProtocol,
},
NegotiatedSubstream, NetworkBehaviour, ProtocolsHandler,
},
};
use std::task::{Context, Poll};
use types::EthSpec;
/* Auxiliary types for simplicity */
type GossipHandler = <Gossipsub as NetworkBehaviour>::ProtocolsHandler;
type RPCHandler<TSpec> = <RPC<TSpec> as NetworkBehaviour>::ProtocolsHandler;
type IdentifyHandler = <Identify as NetworkBehaviour>::ProtocolsHandler;
/// Handler that combines Lighthouse's Behaviours' handlers in a delegating manner.
pub(super) struct DelegatingHandler<TSpec: EthSpec> {
/// Handler for the Gossipsub protocol.
gossip_handler: GossipHandler,
/// Handler for the RPC protocol.
rpc_handler: RPCHandler<TSpec>,
/// Handler for the Identify protocol.
identify_handler: IdentifyHandler,
}
impl<TSpec: EthSpec> DelegatingHandler<TSpec> {
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(),
}
}
/// Gives mutable access to the rpc handler.
pub fn rpc_mut(&mut self) -> &mut RPCHandler<TSpec> {
&mut self.rpc_handler
}
/// Gives access to the rpc handler.
pub fn rpc(&self) -> &RPCHandler<TSpec> {
&self.rpc_handler
}
/// Gives access to identify's handler.
pub fn _identify(&self) -> &IdentifyHandler {
&self.identify_handler
}
}
/// Wrapper around the `ProtocolsHandler::InEvent` types of the handlers.
/// Simply delegated to the corresponding behaviour's handler.
#[derive(Debug)]
pub enum DelegateIn<TSpec: EthSpec> {
Gossipsub(<GossipHandler as ProtocolsHandler>::InEvent),
RPC(<RPCHandler<TSpec> as ProtocolsHandler>::InEvent),
Identify(<IdentifyHandler as ProtocolsHandler>::InEvent),
}
/// Wrapper around the `ProtocolsHandler::OutEvent` types of the handlers.
/// Simply delegated to the corresponding behaviour's handler.
pub enum DelegateOut<TSpec: EthSpec> {
Gossipsub(<GossipHandler as ProtocolsHandler>::OutEvent),
RPC(<RPCHandler<TSpec> as ProtocolsHandler>::OutEvent),
Identify(Box<<IdentifyHandler as ProtocolsHandler>::OutEvent>),
}
/// Wrapper around the `ProtocolsHandler::Error` types of the handlers.
/// Simply delegated to the corresponding behaviour's handler.
#[derive(Debug)]
pub enum DelegateError<TSpec: EthSpec> {
Gossipsub(<GossipHandler as ProtocolsHandler>::Error),
RPC(<RPCHandler<TSpec> as ProtocolsHandler>::Error),
Identify(<IdentifyHandler as ProtocolsHandler>::Error),
Disconnected,
}
impl<TSpec: EthSpec> std::error::Error for DelegateError<TSpec> {}
impl<TSpec: EthSpec> std::fmt::Display for DelegateError<TSpec> {
fn fmt(
&self,
formater: &mut std::fmt::Formatter<'_>,
) -> std::result::Result<(), std::fmt::Error> {
match self {
DelegateError::Gossipsub(err) => err.fmt(formater),
DelegateError::RPC(err) => err.fmt(formater),
DelegateError::Identify(err) => err.fmt(formater),
DelegateError::Disconnected => write!(formater, "Disconnected"),
}
}
}
pub type DelegateInProto<TSpec> = SelectUpgrade<
<GossipHandler as ProtocolsHandler>::InboundProtocol,
SelectUpgrade<
<RPCHandler<TSpec> as ProtocolsHandler>::InboundProtocol,
<IdentifyHandler as ProtocolsHandler>::InboundProtocol,
>,
>;
pub type DelegateOutProto<TSpec> = EitherUpgrade<
<GossipHandler as ProtocolsHandler>::OutboundProtocol,
EitherUpgrade<
<RPCHandler<TSpec> as ProtocolsHandler>::OutboundProtocol,
<IdentifyHandler as ProtocolsHandler>::OutboundProtocol,
>,
>;
pub type DelegateOutInfo<TSpec> = EitherOutput<
<GossipHandler as ProtocolsHandler>::OutboundOpenInfo,
EitherOutput<
<RPCHandler<TSpec> as ProtocolsHandler>::OutboundOpenInfo,
<IdentifyHandler as ProtocolsHandler>::OutboundOpenInfo,
>,
>;
impl<TSpec: EthSpec> ProtocolsHandler for DelegatingHandler<TSpec> {
type InEvent = DelegateIn<TSpec>;
type OutEvent = DelegateOut<TSpec>;
type Error = DelegateError<TSpec>;
type InboundProtocol = DelegateInProto<TSpec>;
type OutboundProtocol = DelegateOutProto<TSpec>;
type OutboundOpenInfo = DelegateOutInfo<TSpec>;
type InboundOpenInfo = ();
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, ()> {
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 timeout = *gossip_proto
.timeout()
.max(rpc_proto.timeout())
.max(identify_proto.timeout());
let select = SelectUpgrade::new(
gossip_proto.into_upgrade().0,
SelectUpgrade::new(rpc_proto.into_upgrade().0, identify_proto.into_upgrade().0),
);
SubstreamProtocol::new(select, ()).with_timeout(timeout)
}
fn inject_fully_negotiated_inbound(
&mut self,
out: <Self::InboundProtocol as InboundUpgrade<NegotiatedSubstream>>::Output,
_info: Self::InboundOpenInfo,
) {
match out {
// Gossipsub
EitherOutput::First(out) => {
self.gossip_handler.inject_fully_negotiated_inbound(out, ())
}
// RPC
EitherOutput::Second(EitherOutput::First(out)) => {
self.rpc_handler.inject_fully_negotiated_inbound(out, ())
}
// Identify
EitherOutput::Second(EitherOutput::Second(out)) => self
.identify_handler
.inject_fully_negotiated_inbound(out, ()),
}
}
fn inject_fully_negotiated_outbound(
&mut self,
protocol: <Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Output,
info: Self::OutboundOpenInfo,
) {
match (protocol, info) {
// Gossipsub
(EitherOutput::First(protocol), EitherOutput::First(info)) => self
.gossip_handler
.inject_fully_negotiated_outbound(protocol, info),
// RPC
(
EitherOutput::Second(EitherOutput::First(protocol)),
EitherOutput::Second(EitherOutput::First(info)),
) => self
.rpc_handler
.inject_fully_negotiated_outbound(protocol, info),
// Identify
(
EitherOutput::Second(EitherOutput::Second(protocol)),
EitherOutput::Second(EitherOutput::Second(())),
) => self
.identify_handler
.inject_fully_negotiated_outbound(protocol, ()),
// Reaching here means we got a protocol and info for different behaviours
_ => unreachable!("output and protocol don't match"),
}
}
fn inject_event(&mut self, event: Self::InEvent) {
match event {
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),
}
}
fn inject_dial_upgrade_error(
&mut self,
info: Self::OutboundOpenInfo,
error: ProtocolsHandlerUpgrErr<
<Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Error,
>,
) {
match info {
// Gossipsub
EitherOutput::First(info) => match error {
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)) => {
self.gossip_handler.inject_dial_upgrade_error(
info,
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)),
)
}
ProtocolsHandlerUpgrErr::Timer => self
.gossip_handler
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timer),
ProtocolsHandlerUpgrErr::Timeout => self
.gossip_handler
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timeout),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(EitherError::A(err))) => {
self.gossip_handler.inject_dial_upgrade_error(
info,
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(err)),
)
}
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(_)) => {
unreachable!("info and error don't match")
}
},
// RPC
EitherOutput::Second(EitherOutput::First(info)) => match error {
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)) => {
self.rpc_handler.inject_dial_upgrade_error(
info,
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)),
)
}
ProtocolsHandlerUpgrErr::Timer => self
.rpc_handler
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timer),
ProtocolsHandlerUpgrErr::Timeout => self
.rpc_handler
.inject_dial_upgrade_error(info, ProtocolsHandlerUpgrErr::Timeout),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(EitherError::B(
EitherError::A(err),
))) => self.rpc_handler.inject_dial_upgrade_error(
info,
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(err)),
),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(_)) => {
unreachable!("info and error don't match")
}
},
// Identify
EitherOutput::Second(EitherOutput::Second(())) => match error {
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)) => {
self.identify_handler.inject_dial_upgrade_error(
(),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(err)),
)
}
ProtocolsHandlerUpgrErr::Timer => self
.identify_handler
.inject_dial_upgrade_error((), ProtocolsHandlerUpgrErr::Timer),
ProtocolsHandlerUpgrErr::Timeout => self
.identify_handler
.inject_dial_upgrade_error((), ProtocolsHandlerUpgrErr::Timeout),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(EitherError::B(
EitherError::B(err),
))) => self.identify_handler.inject_dial_upgrade_error(
(),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(err)),
),
ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Apply(_)) => {
unreachable!("info and error don't match")
}
},
}
}
fn connection_keep_alive(&self) -> KeepAlive {
self.gossip_handler
.connection_keep_alive()
.max(self.rpc_handler.connection_keep_alive())
.max(self.identify_handler.connection_keep_alive())
}
#[allow(clippy::type_complexity)]
fn poll(
&mut self,
cx: &mut Context,
) -> Poll<
ProtocolsHandlerEvent<
Self::OutboundProtocol,
Self::OutboundOpenInfo,
Self::OutEvent,
Self::Error,
>,
> {
match self.gossip_handler.poll(cx) {
Poll::Ready(ProtocolsHandlerEvent::Custom(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Custom(DelegateOut::Gossipsub(event)));
}
Poll::Ready(ProtocolsHandlerEvent::Close(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Close(DelegateError::Gossipsub(
event,
)));
}
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol }) => {
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
protocol: protocol
.map_upgrade(EitherUpgrade::A)
.map_info(EitherOutput::First),
});
}
Poll::Pending => (),
};
match self.rpc_handler.poll(cx) {
Poll::Ready(ProtocolsHandlerEvent::Custom(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Custom(DelegateOut::RPC(event)));
}
Poll::Ready(ProtocolsHandlerEvent::Close(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Close(DelegateError::RPC(event)));
}
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol }) => {
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
protocol: protocol
.map_upgrade(|u| EitherUpgrade::B(EitherUpgrade::A(u)))
.map_info(|info| EitherOutput::Second(EitherOutput::First(info))),
});
}
Poll::Pending => (),
};
match self.identify_handler.poll(cx) {
Poll::Ready(ProtocolsHandlerEvent::Custom(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Custom(DelegateOut::Identify(
Box::new(event),
)));
}
Poll::Ready(ProtocolsHandlerEvent::Close(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Close(DelegateError::Identify(event)));
}
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol }) => {
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
protocol: protocol
.map_upgrade(|u| EitherUpgrade::B(EitherUpgrade::B(u)))
.map_info(|_| EitherOutput::Second(EitherOutput::Second(()))),
});
}
Poll::Pending => (),
};
Poll::Pending
}
}

View File

@ -1,131 +0,0 @@
use crate::behaviour::Gossipsub;
use crate::rpc::*;
use delegate::DelegatingHandler;
pub(super) use delegate::{
DelegateError, DelegateIn, DelegateInProto, DelegateOut, DelegateOutInfo, DelegateOutProto,
};
use libp2p::{
core::upgrade::{InboundUpgrade, OutboundUpgrade},
identify::Identify,
swarm::protocols_handler::{
KeepAlive, ProtocolsHandlerEvent, ProtocolsHandlerUpgrErr, SubstreamProtocol,
},
swarm::{NegotiatedSubstream, ProtocolsHandler},
};
use std::task::{Context, Poll};
use types::EthSpec;
mod delegate;
/// Handler that combines Lighthouse's Behaviours' handlers in a delegating manner.
pub struct BehaviourHandler<TSpec: EthSpec> {
/// Handler combining all sub behaviour's handlers.
delegate: DelegatingHandler<TSpec>,
/// Flag indicating if the handler is shutting down.
shutting_down: bool,
}
impl<TSpec: EthSpec> BehaviourHandler<TSpec> {
pub fn new(gossipsub: &mut Gossipsub, rpc: &mut RPC<TSpec>, identify: &mut Identify) -> Self {
BehaviourHandler {
delegate: DelegatingHandler::new(gossipsub, rpc, identify),
shutting_down: false,
}
}
}
pub enum BehaviourHandlerIn<TSpec: EthSpec> {
Delegate(DelegateIn<TSpec>),
/// Start the shutdown process.
Shutdown(Option<(RequestId, OutboundRequest<TSpec>)>),
}
impl<TSpec: EthSpec> ProtocolsHandler for BehaviourHandler<TSpec> {
type InEvent = BehaviourHandlerIn<TSpec>;
type OutEvent = DelegateOut<TSpec>;
type Error = DelegateError<TSpec>;
type InboundProtocol = DelegateInProto<TSpec>;
type OutboundProtocol = DelegateOutProto<TSpec>;
type OutboundOpenInfo = DelegateOutInfo<TSpec>;
type InboundOpenInfo = ();
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, ()> {
self.delegate.listen_protocol()
}
fn inject_fully_negotiated_inbound(
&mut self,
out: <Self::InboundProtocol as InboundUpgrade<NegotiatedSubstream>>::Output,
_info: Self::InboundOpenInfo,
) {
self.delegate.inject_fully_negotiated_inbound(out, ())
}
fn inject_fully_negotiated_outbound(
&mut self,
out: <Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Output,
info: Self::OutboundOpenInfo,
) {
self.delegate.inject_fully_negotiated_outbound(out, info)
}
fn inject_event(&mut self, event: Self::InEvent) {
match event {
BehaviourHandlerIn::Delegate(delegated_ev) => self.delegate.inject_event(delegated_ev),
/* Events coming from the behaviour */
BehaviourHandlerIn::Shutdown(last_message) => {
self.shutting_down = true;
self.delegate.rpc_mut().shutdown(last_message);
}
}
}
fn inject_dial_upgrade_error(
&mut self,
info: Self::OutboundOpenInfo,
err: ProtocolsHandlerUpgrErr<
<Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Error,
>,
) {
self.delegate.inject_dial_upgrade_error(info, err)
}
// We don't use the keep alive to disconnect. This is handled in the poll
fn connection_keep_alive(&self) -> KeepAlive {
KeepAlive::Yes
}
#[allow(clippy::type_complexity)]
fn poll(
&mut self,
cx: &mut Context,
) -> Poll<
ProtocolsHandlerEvent<
Self::OutboundProtocol,
Self::OutboundOpenInfo,
Self::OutEvent,
Self::Error,
>,
> {
// Disconnect if the sub-handlers are ready.
// Currently we only respect the RPC handler.
if self.shutting_down && KeepAlive::No == self.delegate.rpc().connection_keep_alive() {
return Poll::Ready(ProtocolsHandlerEvent::Close(DelegateError::Disconnected));
}
match self.delegate.poll(cx) {
Poll::Ready(ProtocolsHandlerEvent::Custom(event)) => {
return Poll::Ready(ProtocolsHandlerEvent::Custom(event))
}
Poll::Ready(ProtocolsHandlerEvent::Close(err)) => {
return Poll::Ready(ProtocolsHandlerEvent::Close(err))
}
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol }) => {
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest { protocol });
}
Poll::Pending => (),
}
Poll::Pending
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,34 @@
///! This manages the discovery and management of peers.
//! The discovery sub-behaviour of Lighthouse.
//!
//! This module creates a libp2p dummy-behaviour built around the discv5 protocol. It handles
//! queries and manages access to the discovery routing table.
pub(crate) mod enr;
pub mod enr_ext;
// Allow external use of the lighthouse ENR builder
use crate::{config, metrics};
use crate::{error, Enr, NetworkConfig, NetworkGlobals, SubnetDiscovery};
use discv5::{enr::NodeId, Discv5, Discv5Event};
pub use enr::{
build_enr, create_enr_builder_from_config, load_enr_from_disk, use_or_load_enr, CombinedKey,
Eth2Enr,
};
pub use enr_ext::{peer_id_to_node_id, CombinedKeyExt, EnrExt};
pub use libp2p::core::identity::{Keypair, PublicKey};
use crate::{config, metrics};
use crate::{error, Enr, NetworkConfig, NetworkGlobals, SubnetDiscovery};
use discv5::{enr::NodeId, Discv5, Discv5Event};
use enr::{BITFIELD_ENR_KEY, ETH2_ENR_KEY};
pub use enr_ext::{peer_id_to_node_id, CombinedKeyExt, EnrExt};
use futures::prelude::*;
use futures::stream::FuturesUnordered;
use libp2p::core::PeerId;
pub use libp2p::{
core::{
connection::ConnectionId,
identity::{Keypair, PublicKey},
ConnectedPoint, Multiaddr, PeerId,
},
swarm::{
protocols_handler::ProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction as NBAction,
NotifyHandler, PollParameters, SubstreamProtocol,
},
};
use lru::LruCache;
use slog::{crit, debug, error, info, warn};
use ssz::{Decode, Encode};
@ -885,9 +897,68 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
}
None
}
}
// Main execution loop to be driven by the peer manager.
pub fn poll(&mut self, cx: &mut Context) -> Poll<DiscoveryEvent> {
/* NetworkBehaviour Implementation */
impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
// Discovery is not a real NetworkBehaviour...
type ProtocolsHandler = libp2p::swarm::protocols_handler::DummyProtocolsHandler;
type OutEvent = DiscoveryEvent;
fn new_handler(&mut self) -> Self::ProtocolsHandler {
libp2p::swarm::protocols_handler::DummyProtocolsHandler::default()
}
// Handles the libp2p request to obtain multiaddrs for peer_id's in order to dial them.
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).
enr.multiaddr_tcp()
} else {
// PeerId is not known
Vec::new()
}
}
fn inject_connected(&mut self, _peer_id: &PeerId) {}
fn inject_disconnected(&mut self, _peer_id: &PeerId) {}
fn inject_connection_established(
&mut self,
_: &PeerId,
_: &ConnectionId,
_connected_point: &ConnectedPoint,
) {
}
fn inject_connection_closed(
&mut self,
_: &PeerId,
_: &ConnectionId,
_connected_point: &ConnectedPoint,
) {
}
fn inject_event(
&mut self,
_: PeerId,
_: ConnectionId,
_: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent,
) {
}
fn inject_dial_failure(&mut self, peer_id: &PeerId) {
// set peer as disconnected in discovery DHT
debug!(self.log, "Marking peer disconnected in DHT"; "peer_id" => %peer_id);
self.disconnect_peer(peer_id);
}
// Main execution loop to drive the behaviour
fn poll(
&mut self,
cx: &mut Context,
_: &mut impl PollParameters,
) -> Poll<NBAction<<Self::ProtocolsHandler as ProtocolsHandler>::InEvent, Self::OutEvent>> {
if !self.started {
return Poll::Pending;
}
@ -898,7 +969,9 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
// Drive the queries and return any results from completed queries
if let Some(results) = self.poll_queries(cx) {
// return the result to the peer manager
return Poll::Ready(DiscoveryEvent::QueryResult(results));
return Poll::Ready(NBAction::GenerateEvent(DiscoveryEvent::QueryResult(
results,
)));
}
// Process the server event stream
@ -946,7 +1019,9 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
enr::save_enr_to_disk(Path::new(&self.enr_dir), &enr, &self.log);
// update network globals
*self.network_globals.local_enr.write() = enr;
return Poll::Ready(DiscoveryEvent::SocketUpdated(socket));
return Poll::Ready(NBAction::GenerateEvent(
DiscoveryEvent::SocketUpdated(socket),
));
}
Discv5Event::EnrAdded { .. }
| Discv5Event::TalkRequest(_)

View File

@ -1,20 +1,19 @@
//! Implementation of a Lighthouse's peer management system.
//! Implementation of Lighthouse's peer management system.
pub use self::peerdb::*;
use crate::discovery::{subnet_predicate, Discovery, DiscoveryEvent, TARGET_SUBNET_PEERS};
use crate::rpc::{GoodbyeReason, MetaData, Protocol, RPCError, RPCResponseErrorCode};
use crate::types::SyncState;
use crate::{error, metrics, Gossipsub};
use crate::{EnrExt, NetworkConfig, NetworkGlobals, PeerId, SubnetDiscovery};
use crate::{NetworkConfig, NetworkGlobals, PeerId};
use discv5::Enr;
use futures::prelude::*;
use futures::Stream;
use hashset_delay::HashSetDelay;
use libp2p::core::multiaddr::Protocol as MProtocol;
use libp2p::core::ConnectedPoint;
use libp2p::identify::IdentifyInfo;
use slog::{crit, debug, error, trace, warn};
use slog::{crit, debug, error, warn};
use smallvec::SmallVec;
use std::{
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
@ -36,6 +35,7 @@ pub use peer_sync_status::{PeerSyncStatus, SyncInfo};
use score::{PeerAction, ReportSource, ScoreState};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::net::IpAddr;
/// The time in seconds between re-status's peers.
const STATUS_INTERVAL: u64 = 300;
@ -79,20 +79,22 @@ pub struct PeerManager<TSpec: EthSpec> {
target_peers: usize,
/// The maximum number of peers we allow (exceptions for subnet peers)
max_peers: usize,
/// The discovery service.
discovery: Discovery<TSpec>,
/// The heartbeat interval to perform routine maintenance.
heartbeat: tokio::time::Interval,
/// Keeps track of whether the discovery service is enabled or not.
discovery_enabled: bool,
/// The logger associated with the `PeerManager`.
log: slog::Logger,
}
/// 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),
/// A peer has dialed us.
PeerConnectedIncoming(PeerId),
/// A peer has been dialed.
PeerConnectedOutgoing(PeerId),
/// A peer has disconnected.
PeerDisconnected(PeerId),
/// Sends a STATUS to a peer.
Status(PeerId),
/// Sends a PING to a peer.
@ -101,22 +103,22 @@ pub enum PeerManagerEvent {
MetaData(PeerId),
/// The peer should be disconnected.
DisconnectPeer(PeerId, GoodbyeReason),
/// Inform the behaviour to ban this peer and associated ip addresses.
Banned(PeerId, Vec<IpAddr>),
/// The peer should be unbanned with the associated ip addresses.
UnBanned(PeerId, Vec<IpAddr>),
/// Request the behaviour to discover more peers.
DiscoverPeers,
}
impl<TSpec: EthSpec> PeerManager<TSpec> {
// NOTE: Must be run inside a tokio executor.
pub async 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).await?;
// start searching for peers
discovery.discover_peers();
// Set up the peer manager heartbeat interval
let heartbeat = tokio::time::interval(tokio::time::Duration::from_secs(HEARTBEAT_INTERVAL));
Ok(PeerManager {
@ -127,22 +129,14 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
status_peers: HashSetDelay::new(Duration::from_secs(STATUS_INTERVAL)),
target_peers: config.target_peers,
max_peers: (config.target_peers as f32 * (1.0 + PEER_EXCESS_FACTOR)).ceil() as usize,
discovery,
heartbeat,
discovery_enabled: !config.disable_discovery,
log: log.clone(),
})
}
/* Public accessible functions */
/// Attempts to connect to a peer.
///
/// Returns true if the peer was accepted into the database.
pub fn dial_peer(&mut self, peer_id: &PeerId) -> bool {
self.events.push(PeerManagerEvent::Dial(*peer_id));
self.connect_peer(peer_id, ConnectingType::Dialing)
}
/// The application layer wants to disconnect from a peer for a particular reason.
///
/// All instant disconnections are fatal and we ban the associated peer.
@ -217,66 +211,52 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
self.ban_and_unban_peers(to_ban_peers, to_unban_peers);
}
/* Discovery Requests */
/// Peers that have been returned by discovery requests that are suitable for dialing are
/// returned here.
///
/// 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.
#[allow(clippy::mutable_key_type)]
pub fn peers_discovered(&mut self, results: HashMap<PeerId, Option<Instant>>) -> Vec<PeerId> {
let mut to_dial_peers = Vec::new();
/// Provides a reference to the underlying discovery service.
pub fn discovery(&self) -> &Discovery<TSpec> {
&self.discovery
}
/// Provides a mutable reference to the underlying discovery service.
pub fn discovery_mut(&mut self) -> &mut Discovery<TSpec> {
&mut self.discovery
}
/// A request to find peers on a given subnet.
pub fn discover_subnet_peers(&mut self, subnets_to_discover: Vec<SubnetDiscovery>) {
// If discovery is not started or disabled, ignore the request
if !self.discovery.started {
return;
}
let filtered: Vec<SubnetDiscovery> = subnets_to_discover
.into_iter()
.filter(|s| {
// Extend min_ttl of connected peers on required subnets
if let Some(min_ttl) = s.min_ttl {
let connected_or_dialing = self.network_globals.connected_or_dialing_peers();
for (peer_id, min_ttl) in results {
// we attempt a connection if this peer is a subnet peer or if the max peer count
// is not yet filled (including dialing peers)
if (min_ttl.is_some() || connected_or_dialing + to_dial_peers.len() < self.max_peers)
&& self.network_globals.peers.read().should_dial(&peer_id)
{
// 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()
.extend_peers_on_subnet(s.subnet_id, min_ttl);
.update_min_ttl(&peer_id, min_ttl);
}
// Already have target number of peers, no need for subnet discovery
let peers_on_subnet = self
.network_globals
.peers
.read()
.good_peers_on_subnet(s.subnet_id)
.count();
if peers_on_subnet >= TARGET_SUBNET_PEERS {
trace!(
self.log,
"Discovery query ignored";
"subnet_id" => ?s.subnet_id,
"reason" => "Already connected to desired peers",
"connected_peers_on_subnet" => peers_on_subnet,
"target_subnet_peers" => TARGET_SUBNET_PEERS,
);
false
// Queue an outgoing connection request to the cached peers that are on `s.subnet_id`.
// If we connect to the cached peers before the discovery query starts, then we potentially
// save a costly discovery query.
} else {
self.dial_cached_enrs_in_subnet(s.subnet_id);
true
}
})
.collect();
// request the subnet query from discovery
if !filtered.is_empty() {
self.discovery.discover_subnet_peers(filtered);
to_dial_peers.push(peer_id);
}
}
// Queue another discovery if we need to
let peer_count = self.network_globals.connected_or_dialing_peers();
let outbound_only_peer_count = self.network_globals.connected_outbound_only_peers();
let min_outbound_only_target =
(self.target_peers as f32 * MIN_OUTBOUND_ONLY_FACTOR).ceil() as usize;
if self.discovery_enabled
&& (peer_count < self.target_peers.saturating_sub(to_dial_peers.len())
|| outbound_only_peer_count < min_outbound_only_target)
{
// We need more peers, re-queue a discovery lookup.
debug!(self.log, "Starting a new peer discovery query"; "connected_peers" => peer_count, "target_peers" => self.target_peers);
self.events.push(PeerManagerEvent::DiscoverPeers);
}
to_dial_peers
}
/// A STATUS message has been received from a peer. This resets the status timer.
@ -307,19 +287,144 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
/* Notifications from the Swarm */
/// Updates the state of the peer as disconnected.
///
/// This is also called when dialing a peer fails.
pub fn notify_disconnect(&mut self, peer_id: &PeerId) {
self.network_globals
.peers
.write()
.notify_disconnect(peer_id);
// A peer is being dialed.
pub fn inject_dialing(&mut self, peer_id: &PeerId, enr: Option<Enr>) {
self.inject_peer_connection(peer_id, ConnectingType::Dialing, enr);
}
// remove the ping and status timer for the peer
self.inbound_ping_peers.remove(peer_id);
self.outbound_ping_peers.remove(peer_id);
self.status_peers.remove(peer_id);
pub fn inject_connection_established(
&mut self,
peer_id: PeerId,
endpoint: ConnectedPoint,
num_established: std::num::NonZeroU32,
enr: Option<Enr>,
) {
// Log the connection
match &endpoint {
ConnectedPoint::Listener { .. } => {
debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => "Incoming", "connections" => %num_established);
}
ConnectedPoint::Dialer { .. } => {
debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => "Outgoing", "connections" => %num_established);
}
}
// Should not be able to connect to a banned peer. Double check here
if self.is_banned(&peer_id) {
warn!(self.log, "Connected to a banned peer"; "peer_id" => %peer_id);
self.events.push(PeerManagerEvent::DisconnectPeer(
peer_id,
GoodbyeReason::Banned,
));
self.network_globals
.peers
.write()
.notify_disconnecting(&peer_id, true);
return;
}
// Check the connection limits
if self.peer_limit_reached()
&& self
.network_globals
.peers
.read()
.peer_info(&peer_id)
.map_or(true, |peer| !peer.has_future_duty())
{
self.events.push(PeerManagerEvent::DisconnectPeer(
peer_id,
GoodbyeReason::TooManyPeers,
));
self.network_globals
.peers
.write()
.notify_disconnecting(&peer_id, false);
return;
}
// Register the newly connected peer (regardless if we are about to disconnect them).
// NOTE: We don't register peers that we are disconnecting immediately. The network service
// does not need to know about these peers.
match endpoint {
ConnectedPoint::Listener { send_back_addr, .. } => {
self.inject_connect_ingoing(&peer_id, send_back_addr, enr);
if num_established == std::num::NonZeroU32::new(1).expect("valid") {
self.events
.push(PeerManagerEvent::PeerConnectedIncoming(peer_id));
}
}
ConnectedPoint::Dialer { address } => {
self.inject_connect_outgoing(&peer_id, address, enr);
if num_established == std::num::NonZeroU32::new(1).expect("valid") {
self.events
.push(PeerManagerEvent::PeerConnectedOutgoing(peer_id));
}
}
}
// increment prometheus metrics
metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
metrics::set_gauge(
&metrics::PEERS_CONNECTED,
self.network_globals.connected_peers() as i64,
);
}
pub fn inject_connection_closed(
&mut self,
peer_id: PeerId,
_endpoint: ConnectedPoint,
num_established: u32,
) {
if num_established == 0 {
// There are no more connections
// Remove all subnet subscriptions from the peer_db
self.remove_all_subscriptions(&peer_id);
if self
.network_globals
.peers
.read()
.is_connected_or_disconnecting(&peer_id)
{
// We are disconnecting the peer or the peer has already been connected.
// Both these cases, the peer has been previously registered by the peer manager and
// potentially the application layer.
// Inform the application.
self.events
.push(PeerManagerEvent::PeerDisconnected(peer_id));
debug!(self.log, "Peer disconnected"; "peer_id" => %peer_id);
// Decrement the PEERS_PER_CLIENT metric
if let Some(kind) = self
.network_globals
.peers
.read()
.peer_info(&peer_id)
.map(|info| info.client.kind.clone())
{
if let Some(v) =
metrics::get_int_gauge(&metrics::PEERS_PER_CLIENT, &[&kind.to_string()])
{
v.dec()
};
}
}
// NOTE: It may be the case that a rejected node, due to too many peers is disconnected
// here and the peer manager has no knowledge of its connection. We insert it here for
// reference so that peer manager can track this peer.
self.inject_disconnect(&peer_id);
// Update the prometheus metrics
metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
metrics::set_gauge(
&metrics::PEERS_CONNECTED,
self.network_globals.connected_peers() as i64,
);
}
}
/// A dial attempt has failed.
@ -327,27 +432,12 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
/// NOTE: It can be the case that we are dialing a peer and during the dialing process the peer
/// connects and the dial attempt later fails. To handle this, we only update the peer_db if
/// the peer is not already connected.
pub fn notify_dial_failure(&mut self, peer_id: &PeerId) {
pub fn inject_dial_failure(&mut self, peer_id: &PeerId) {
if !self.network_globals.peers.read().is_connected(peer_id) {
self.notify_disconnect(peer_id);
// set peer as disconnected in discovery DHT
debug!(self.log, "Marking peer disconnected in DHT"; "peer_id" => %peer_id);
self.discovery.disconnect_peer(peer_id);
self.inject_disconnect(peer_id);
}
}
/// Sets a peer as connected as long as their reputation allows it
/// Informs if the peer was accepted
pub fn connect_ingoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) -> bool {
self.connect_peer(peer_id, ConnectingType::IngoingConnected { multiaddr })
}
/// Sets a peer as connected as long as their reputation allows it
/// Informs if the peer was accepted
pub fn connect_outgoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) -> bool {
self.connect_peer(peer_id, ConnectingType::OutgoingConnected { multiaddr })
}
/// Reports if a peer is banned or not.
///
/// This is used to determine if we should accept incoming connections.
@ -483,6 +573,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
},
},
RPCError::NegotiationTimeout => PeerAction::LowToleranceError,
RPCError::Disconnected => return, // No penalty for a graceful disconnection
};
self.report_peer(peer_id, peer_action, ReportSource::RPC);
@ -574,19 +665,6 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
}
}
// 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).
enr.multiaddr_tcp()
} else {
// PeerId is not known
Vec::new()
}
}
pub(crate) fn update_gossipsub_scores(&mut self, gossipsub: &Gossipsub) {
let mut to_ban_peers = Vec::new();
let mut to_unban_peers = Vec::new();
@ -642,73 +720,49 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
/* 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));
/// Sets a peer as connected as long as their reputation allows it
/// Informs if the peer was accepted
fn inject_connect_ingoing(
&mut self,
peer_id: &PeerId,
multiaddr: Multiaddr,
enr: Option<Enr>,
) -> bool {
self.inject_peer_connection(peer_id, ConnectingType::IngoingConnected { multiaddr }, enr)
}
/// Dial cached enrs in discovery service that are in the given `subnet_id` and aren't
/// in Connected, Dialing or Banned state.
fn dial_cached_enrs_in_subnet(&mut self, subnet_id: SubnetId) {
let predicate = subnet_predicate::<TSpec>(vec![subnet_id], &self.log);
let peers_to_dial: Vec<PeerId> = self
.discovery()
.cached_enrs()
.filter_map(|(peer_id, enr)| {
let peers = self.network_globals.peers.read();
if predicate(enr) && peers.should_dial(peer_id) {
Some(*peer_id)
} else {
None
}
})
.collect();
for peer_id in &peers_to_dial {
debug!(self.log, "Dialing cached ENR peer"; "peer_id" => %peer_id);
// Remove the ENR from the cache to prevent continual re-dialing on disconnects
self.discovery.remove_cached_enr(&peer_id);
self.dial_peer(peer_id);
}
/// Sets a peer as connected as long as their reputation allows it
/// Informs if the peer was accepted
fn inject_connect_outgoing(
&mut self,
peer_id: &PeerId,
multiaddr: Multiaddr,
enr: Option<Enr>,
) -> bool {
self.inject_peer_connection(
peer_id,
ConnectingType::OutgoingConnected { multiaddr },
enr,
)
}
/// Peers that have been returned by discovery requests are dialed here if they are suitable.
/// Updates the state of the peer as disconnected.
///
/// 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.
#[allow(clippy::mutable_key_type)]
fn peers_discovered(&mut self, results: HashMap<PeerId, Option<Instant>>) {
let mut to_dial_peers = Vec::new();
/// This is also called when dialing a peer fails.
fn inject_disconnect(&mut self, peer_id: &PeerId) {
if self
.network_globals
.peers
.write()
.inject_disconnect(peer_id)
{
self.ban_peer(peer_id);
}
let connected_or_dialing = self.network_globals.connected_or_dialing_peers();
for (peer_id, min_ttl) in results {
// we attempt a connection if this peer is a subnet peer or if the max peer count
// is not yet filled (including dialing peers)
if (min_ttl.is_some() || connected_or_dialing + to_dial_peers.len() < self.max_peers)
&& self.network_globals.peers.read().should_dial(&peer_id)
{
// 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);
}
to_dial_peers.push(peer_id);
}
}
for peer_id in to_dial_peers {
debug!(self.log, "Dialing discovered peer"; "peer_id" => %peer_id);
self.dial_peer(&peer_id);
}
// remove the ping and status timer for the peer
self.inbound_ping_peers.remove(peer_id);
self.outbound_ping_peers.remove(peer_id);
self.status_peers.remove(peer_id);
}
/// Registers a peer as connected. The `ingoing` parameter determines if the peer is being
@ -717,7 +771,12 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
/// This is called by `connect_ingoing` and `connect_outgoing`.
///
/// Informs if the peer was accepted in to the db or not.
fn connect_peer(&mut self, peer_id: &PeerId, connection: ConnectingType) -> bool {
fn inject_peer_connection(
&mut self,
peer_id: &PeerId,
connection: ConnectingType,
enr: Option<Enr>,
) -> bool {
{
let mut peerdb = self.network_globals.peers.write();
if peerdb.is_banned(&peer_id) {
@ -725,8 +784,6 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
slog::crit!(self.log, "Connection has been allowed to a banned peer"; "peer_id" => %peer_id);
}
let enr = self.discovery.enr_of_peer(peer_id);
match connection {
ConnectingType::Dialing => {
peerdb.dialing_peer(peer_id, enr);
@ -773,6 +830,8 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
true
}
/// This handles score transitions between states. It transitions peers states from
/// disconnected/banned/connected.
fn handle_score_transitions(
previous_state: ScoreState,
peer_id: &PeerId,
@ -813,6 +872,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
}
}
/// Updates the state of banned peers.
fn ban_and_unban_peers(&mut self, to_ban_peers: Vec<PeerId>, to_unban_peers: Vec<PeerId>) {
// process banning peers
for peer_id in to_ban_peers {
@ -882,7 +942,9 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
})
.unwrap_or_default();
self.discovery.ban_peer(&peer_id, banned_ip_addresses);
// Inform the Swarm to ban the peer
self.events
.push(PeerManagerEvent::Banned(*peer_id, banned_ip_addresses));
}
/// Unbans a peer.
@ -898,7 +960,9 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
.map(|info| info.seen_addresses().collect::<Vec<_>>())
.unwrap_or_default();
self.discovery.unban_peer(&peer_id, seen_ip_addresses);
// Inform the Swarm to unban the peer
self.events
.push(PeerManagerEvent::UnBanned(*peer_id, seen_ip_addresses));
Ok(())
}
@ -914,12 +978,13 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
let min_outbound_only_target =
(self.target_peers as f32 * MIN_OUTBOUND_ONLY_FACTOR).ceil() as usize;
if peer_count < self.target_peers || outbound_only_peer_count < min_outbound_only_target {
if self.discovery_enabled
&& (peer_count < self.target_peers
|| outbound_only_peer_count < min_outbound_only_target)
{
// If we need more peers, queue a discovery lookup.
if self.discovery.started {
debug!(self.log, "Starting a new peer discovery query"; "connected_peers" => peer_count, "target_peers" => self.target_peers);
self.discovery.discover_peers();
}
debug!(self.log, "Starting a new peer discovery query"; "connected_peers" => peer_count, "target_peers" => self.target_peers);
self.events.push(PeerManagerEvent::DiscoverPeers);
}
// Updates peer's scores.
@ -958,7 +1023,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
let mut peer_db = self.network_globals.peers.write();
for peer_id in disconnecting_peers {
peer_db.notify_disconnecting(&peer_id);
peer_db.notify_disconnecting(&peer_id, false);
self.events.push(PeerManagerEvent::DisconnectPeer(
peer_id,
GoodbyeReason::TooManyPeers,
@ -976,14 +1041,6 @@ impl<TSpec: EthSpec> Stream for PeerManager<TSpec> {
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(results) => self.peers_discovered(results),
}
}
// poll the timeouts for pings and status'
loop {
match self.inbound_ping_peers.poll_next_unpin(cx) {
@ -1107,7 +1164,7 @@ mod tests {
vec![],
&log,
);
PeerManager::new(&keypair, &config, Arc::new(globals), &log)
PeerManager::new(&config, Arc::new(globals), &log)
.await
.unwrap()
}
@ -1124,11 +1181,19 @@ mod tests {
let outbound_only_peer1 = PeerId::random();
let outbound_only_peer2 = PeerId::random();
peer_manager.connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_ingoing(&peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_ingoing(&peer2, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_outgoing(&outbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_outgoing(&outbound_only_peer2, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_ingoing(&peer1, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_ingoing(&peer2, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_outgoing(
&outbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager.inject_connect_outgoing(
&outbound_only_peer2,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
// Set the outbound-only peers to have the lowest score.
peer_manager
@ -1180,13 +1245,17 @@ mod tests {
// Connect to 20 ingoing-only peers.
for _i in 0..19 {
let peer = PeerId::random();
peer_manager.connect_ingoing(&peer, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(&peer, "/ip4/0.0.0.0".parse().unwrap(), None);
}
// Connect an outbound-only peer.
// Give it the lowest score so that it is evaluated first in the disconnect list iterator.
let outbound_only_peer = PeerId::random();
peer_manager.connect_ingoing(&outbound_only_peer, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(
&outbound_only_peer,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager
.network_globals
.peers
@ -1212,12 +1281,20 @@ mod tests {
let inbound_only_peer1 = PeerId::random();
let outbound_only_peer1 = PeerId::random();
peer_manager.connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_outgoing(&peer0, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_outgoing(&peer0, "/ip4/0.0.0.0".parse().unwrap(), None);
// Connect to two peers that are on the threshold of being disconnected.
peer_manager.connect_ingoing(&inbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_outgoing(&outbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(
&inbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager.inject_connect_outgoing(
&outbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager
.network_globals
.peers
@ -1267,12 +1344,20 @@ mod tests {
let inbound_only_peer1 = PeerId::random();
let outbound_only_peer1 = PeerId::random();
peer_manager.connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_ingoing(&peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_ingoing(&peer1, "/ip4/0.0.0.0".parse().unwrap(), None);
// Connect to two peers that are on the threshold of being disconnected.
peer_manager.connect_ingoing(&inbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_outgoing(&outbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(
&inbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager.inject_connect_outgoing(
&outbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager
.network_globals
.peers
@ -1319,12 +1404,20 @@ mod tests {
let inbound_only_peer1 = PeerId::random();
let outbound_only_peer1 = PeerId::random();
peer_manager.connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_ingoing(&peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_ingoing(&peer2, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.connect_outgoing(&outbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(&peer0, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_ingoing(&peer1, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_ingoing(&peer2, "/ip4/0.0.0.0".parse().unwrap(), None);
peer_manager.inject_connect_outgoing(
&outbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
// Have one peer be on the verge of disconnection.
peer_manager.connect_ingoing(&inbound_only_peer1, "/ip4/0.0.0.0".parse().unwrap());
peer_manager.inject_connect_ingoing(
&inbound_only_peer1,
"/ip4/0.0.0.0".parse().unwrap(),
None,
);
peer_manager
.network_globals
.peers

View File

@ -198,25 +198,16 @@ impl<T: EthSpec> PeerInfo<T> {
// Setters
/// Modifies the status to Disconnected and sets the last seen instant to now. Returns None if
/// no changes were made. Returns Some(bool) where the bool represents if peer became banned or
/// simply just disconnected.
/// no changes were made. Returns Some(bool) where the bool represents if peer is to now be
/// baned
pub fn notify_disconnect(&mut self) -> Option<bool> {
match self.connection_status {
Banned { .. } | Disconnected { .. } => None,
Disconnecting { to_ban } => {
// If we are disconnecting this peer in the process of banning, we now ban the
// peer.
if to_ban {
self.connection_status = Banned {
since: Instant::now(),
};
Some(true)
} else {
self.connection_status = Disconnected {
since: Instant::now(),
};
Some(false)
}
self.connection_status = Disconnected {
since: Instant::now(),
};
Some(to_ban)
}
Connected { .. } | Dialing { .. } | Unknown => {
self.connection_status = Disconnected {
@ -227,11 +218,8 @@ impl<T: EthSpec> PeerInfo<T> {
}
}
/// Notify the we are currently disconnecting this peer, after which the peer will be
/// considered banned.
// This intermediate state is required to inform the network behaviours that the sub-protocols
// are aware this peer exists and it is in the process of being banned. Compared to nodes that
// try to connect to us and are already banned (sub protocols do not know of these peers).
/// Notify the we are currently disconnecting this peer. Optionally ban the peer after the
/// disconnect.
pub fn disconnecting(&mut self, to_ban: bool) {
self.connection_status = Disconnecting { to_ban }
}

View File

@ -453,28 +453,31 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
self.connect(peer_id, multiaddr, enr, ConnectionDirection::Outgoing)
}
/// Sets the peer as disconnected. A banned peer remains banned
pub fn notify_disconnect(&mut self, peer_id: &PeerId) {
/// Sets the peer as disconnected. A banned peer remains banned. If the node has become banned,
/// this returns true, otherwise this is false.
pub fn inject_disconnect(&mut self, peer_id: &PeerId) -> bool {
// Note that it could be the case we prevent new nodes from joining. In this instance,
// we don't bother tracking the new node.
if let Some(info) = self.peers.get_mut(peer_id) {
if let Some(became_banned) = info.notify_disconnect() {
if became_banned {
self.banned_peers_count
.add_banned_peer(info.seen_addresses());
} else {
self.disconnected_peers += 1;
}
if !matches!(
info.connection_status(),
PeerConnectionStatus::Disconnected { .. } | PeerConnectionStatus::Banned { .. }
) {
self.disconnected_peers += 1;
}
let result = info.notify_disconnect().unwrap_or(false);
self.shrink_to_fit();
result
} else {
false
}
}
/// Notifies the peer manager that the peer is undergoing a normal disconnect (without banning
/// afterwards.
pub fn notify_disconnecting(&mut self, peer_id: &PeerId) {
/// Notifies the peer manager that the peer is undergoing a normal disconnect. Optionally tag
/// the peer to be banned after the disconnect.
pub fn notify_disconnecting(&mut self, peer_id: &PeerId, to_ban_afterwards: bool) {
if let Some(info) = self.peers.get_mut(peer_id) {
info.disconnecting(false);
info.disconnecting(to_ban_afterwards);
}
}
@ -505,15 +508,17 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
PeerConnectionStatus::Disconnected { .. } => {
// It is possible to ban a peer that has a disconnected score, if there are many
// events that score it poorly and are processed after it has disconnected.
debug!(log_ref, "Banning a disconnected peer"; "peer_id" => %peer_id);
self.disconnected_peers = self.disconnected_peers.saturating_sub(1);
info.ban();
self.banned_peers_count
.add_banned_peer(info.seen_addresses());
self.shrink_to_fit();
false
}
PeerConnectionStatus::Disconnecting { .. } => {
warn!(log_ref, "Banning peer that is currently disconnecting"; "peer_id" => %peer_id);
// NOTE: This can occur due a rapid downscore of a peer. It goes through the
// disconnection phase and straight into banning in a short time-frame.
debug!(log_ref, "Banning peer that is currently disconnecting"; "peer_id" => %peer_id);
info.disconnecting(true);
false
}
@ -532,6 +537,7 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
self.banned_peers_count
.add_banned_peer(info.seen_addresses());
info.ban();
self.shrink_to_fit();
false
}
}
@ -726,7 +732,7 @@ mod tests {
assert_eq!(pdb.disconnected_peers, 0);
for p in pdb.connected_peer_ids().cloned().collect::<Vec<_>>() {
pdb.notify_disconnect(&p);
pdb.inject_disconnect(&p);
}
assert_eq!(pdb.disconnected_peers, MAX_DC_PEERS);
@ -744,7 +750,8 @@ mod tests {
for p in pdb.connected_peer_ids().cloned().collect::<Vec<_>>() {
pdb.disconnect_and_ban(&p);
pdb.notify_disconnect(&p);
pdb.inject_disconnect(&p);
pdb.disconnect_and_ban(&p);
}
assert_eq!(pdb.banned_peers_count.banned_peers(), MAX_BANNED_PEERS);
@ -804,23 +811,24 @@ mod tests {
pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap(), None);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.connect_outgoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap(), None);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.disconnect_and_ban(&random_peer);
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
pdb.disconnect_and_ban(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
}
@ -835,6 +843,10 @@ mod tests {
let random_peer1 = PeerId::random();
let random_peer2 = PeerId::random();
let random_peer3 = PeerId::random();
println!("{}", random_peer);
println!("{}", random_peer1);
println!("{}", random_peer2);
println!("{}", random_peer3);
pdb.connect_ingoing(&random_peer, multiaddr.clone(), None);
pdb.connect_ingoing(&random_peer1, multiaddr.clone(), None);
@ -846,10 +858,17 @@ mod tests {
pdb.banned_peers().count()
);
println!("1:{}", pdb.disconnected_peers);
pdb.connect_ingoing(&random_peer, multiaddr.clone(), None);
pdb.notify_disconnect(&random_peer1);
pdb.inject_disconnect(&random_peer1);
println!("2:{}", pdb.disconnected_peers);
pdb.disconnect_and_ban(&random_peer2);
pdb.notify_disconnect(&random_peer2);
println!("3:{}", pdb.disconnected_peers);
pdb.inject_disconnect(&random_peer2);
println!("4:{}", pdb.disconnected_peers);
pdb.disconnect_and_ban(&random_peer2);
println!("5:{}", pdb.disconnected_peers);
pdb.connect_ingoing(&random_peer3, multiaddr.clone(), None);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
assert_eq!(
@ -857,7 +876,16 @@ mod tests {
pdb.banned_peers().count()
);
pdb.disconnect_and_ban(&random_peer1);
pdb.notify_disconnect(&random_peer1);
println!("6:{}", pdb.disconnected_peers);
pdb.inject_disconnect(&random_peer1);
println!("7:{}", pdb.disconnected_peers);
pdb.disconnect_and_ban(&random_peer1);
println!("8:{}", pdb.disconnected_peers);
println!(
"{}, {:?}",
pdb.disconnected_peers,
pdb.disconnected_peers().collect::<Vec<_>>()
);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
assert_eq!(
pdb.banned_peers_count.banned_peers(),
@ -871,7 +899,8 @@ mod tests {
pdb.banned_peers().count()
);
pdb.disconnect_and_ban(&random_peer3);
pdb.notify_disconnect(&random_peer3);
pdb.inject_disconnect(&random_peer3);
pdb.disconnect_and_ban(&random_peer3);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
assert_eq!(
pdb.banned_peers_count.banned_peers(),
@ -879,32 +908,34 @@ mod tests {
);
pdb.disconnect_and_ban(&random_peer3);
pdb.notify_disconnect(&random_peer3);
pdb.connect_ingoing(&random_peer1, multiaddr.clone(), None);
pdb.notify_disconnect(&random_peer2);
pdb.inject_disconnect(&random_peer3);
pdb.disconnect_and_ban(&random_peer3);
pdb.connect_ingoing(&random_peer1, multiaddr.clone(), None);
pdb.inject_disconnect(&random_peer2);
pdb.disconnect_and_ban(&random_peer3);
pdb.inject_disconnect(&random_peer3);
pdb.disconnect_and_ban(&random_peer3);
pdb.notify_disconnect(&random_peer3);
pdb.connect_ingoing(&random_peer, multiaddr, None);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
assert_eq!(
pdb.banned_peers_count.banned_peers(),
pdb.banned_peers().count()
);
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
assert_eq!(
pdb.banned_peers_count.banned_peers(),
pdb.banned_peers().count()
);
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
assert_eq!(
pdb.banned_peers_count.banned_peers(),
pdb.banned_peers().count()
);
pdb.disconnect_and_ban(&random_peer);
pdb.notify_disconnect(&random_peer);
pdb.inject_disconnect(&random_peer);
assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count());
}
@ -950,7 +981,8 @@ mod tests {
for p in &peers[..BANNED_PEERS_PER_IP_THRESHOLD + 1] {
pdb.disconnect_and_ban(p);
pdb.notify_disconnect(p);
pdb.inject_disconnect(p);
pdb.disconnect_and_ban(p);
}
//check that ip1 and ip2 are banned but ip3-5 not
@ -962,7 +994,8 @@ mod tests {
//ban also the last peer in peers
pdb.disconnect_and_ban(&peers[BANNED_PEERS_PER_IP_THRESHOLD + 1]);
pdb.notify_disconnect(&peers[BANNED_PEERS_PER_IP_THRESHOLD + 1]);
pdb.inject_disconnect(&peers[BANNED_PEERS_PER_IP_THRESHOLD + 1]);
pdb.disconnect_and_ban(&peers[BANNED_PEERS_PER_IP_THRESHOLD + 1]);
//check that ip1-ip4 are banned but ip5 not
assert!(pdb.is_banned(&p1));
@ -1012,7 +1045,8 @@ mod tests {
// ban all peers
for p in &peers {
pdb.disconnect_and_ban(p);
pdb.notify_disconnect(p);
pdb.inject_disconnect(p);
pdb.disconnect_and_ban(p);
}
// check ip is banned
@ -1033,7 +1067,8 @@ mod tests {
for p in &peers {
pdb.connect_ingoing(&p, socker_addr.clone(), None);
pdb.disconnect_and_ban(p);
pdb.notify_disconnect(p);
pdb.inject_disconnect(p);
pdb.disconnect_and_ban(p);
}
// both IP's are now banned
@ -1049,7 +1084,8 @@ mod tests {
// reban every peer except one
for p in &peers[1..] {
pdb.disconnect_and_ban(p);
pdb.notify_disconnect(p);
pdb.inject_disconnect(p);
pdb.disconnect_and_ban(p);
}
// nothing is banned
@ -1058,7 +1094,8 @@ mod tests {
//reban last peer
pdb.disconnect_and_ban(&peers[0]);
pdb.notify_disconnect(&peers[0]);
pdb.inject_disconnect(&peers[0]);
pdb.disconnect_and_ban(&peers[0]);
//Ip's are banned again
assert!(pdb.is_banned(&p1));

View File

@ -1,8 +1,10 @@
#![allow(clippy::type_complexity)]
#![allow(clippy::cognitive_complexity)]
use super::methods::{RPCCodedResponse, RPCResponseErrorCode, RequestId, ResponseTermination};
use super::protocol::{Protocol, RPCError, RPCProtocol};
use super::methods::{
GoodbyeReason, RPCCodedResponse, RPCResponseErrorCode, RequestId, ResponseTermination,
};
use super::protocol::{InboundRequest, Protocol, RPCError, RPCProtocol};
use super::{RPCReceived, RPCSend};
use crate::rpc::outbound::{OutboundFramed, OutboundRequest};
use crate::rpc::protocol::InboundFramed;
@ -221,13 +223,14 @@ where
}
}
/// Initiates the handler's shutdown process, sending an optional last message to the peer.
pub fn shutdown(&mut self, final_msg: Option<(RequestId, OutboundRequest<TSpec>)>) {
/// Initiates the handler's shutdown process, sending an optional Goodbye message to the
/// peer.
fn shutdown(&mut self, goodbye_reason: Option<GoodbyeReason>) {
if matches!(self.state, HandlerState::Active) {
if !self.dial_queue.is_empty() {
debug!(self.log, "Starting handler shutdown"; "unsent_queued_requests" => self.dial_queue.len());
}
// we now drive to completion communications already dialed/established
// We now drive to completion communications already dialed/established
while let Some((id, req)) = self.dial_queue.pop() {
self.events_out.push(Err(HandlerErr::Outbound {
error: RPCError::HandlerRejected,
@ -236,9 +239,10 @@ where
}));
}
// Queue our final message, if any
if let Some((id, req)) = final_msg {
self.dial_queue.push((id, req));
// Queue our goodbye message.
if let Some(reason) = goodbye_reason {
self.dial_queue
.push((RequestId::Router, OutboundRequest::Goodbye(reason)));
}
self.state = HandlerState::ShuttingDown(Box::new(sleep_until(
@ -345,6 +349,11 @@ where
);
}
// If we received a goodbye, shutdown the connection.
if let InboundRequest::Goodbye(_) = req {
self.shutdown(None);
}
self.events_out.push(Ok(RPCReceived::Request(
self.current_inbound_substream_id,
req,
@ -412,6 +421,7 @@ where
match rpc_event {
RPCSend::Request(id, req) => self.send_request(id, req),
RPCSend::Response(inbound_id, response) => self.send_response(inbound_id, response),
RPCSend::Shutdown(reason) => self.shutdown(Some(reason)),
}
}
@ -512,6 +522,9 @@ where
if delay.is_elapsed() {
self.state = HandlerState::Deactivated;
debug!(self.log, "Handler deactivated");
return Poll::Ready(ProtocolsHandlerEvent::Close(RPCError::InternalError(
"Shutdown timeout",
)));
}
}
@ -864,6 +877,19 @@ where
protocol: SubstreamProtocol::new(req.clone(), ()).map_info(|()| (id, req)),
});
}
// Check if we have completed sending a goodbye, disconnect.
if let HandlerState::ShuttingDown(_) = self.state {
if self.dial_queue.is_empty()
&& self.outbound_substreams.is_empty()
&& self.inbound_substreams.is_empty()
&& self.events_out.is_empty()
&& self.dial_negotiated == 0
{
return Poll::Ready(ProtocolsHandlerEvent::Close(RPCError::Disconnected));
}
}
Poll::Pending
}
}

View File

@ -149,9 +149,9 @@ impl From<u64> for GoodbyeReason {
}
}
impl Into<u64> for GoodbyeReason {
fn into(self) -> u64 {
self as u64
impl From<GoodbyeReason> for u64 {
fn from(reason: GoodbyeReason) -> u64 {
reason as u64
}
}

View File

@ -52,6 +52,8 @@ pub enum RPCSend<TSpec: EthSpec> {
/// peer. The second parameter is a single chunk of a response. These go over *inbound*
/// connections.
Response(SubstreamId, RPCCodedResponse<TSpec>),
/// Lighthouse has requested to terminate the connection with a goodbye message.
Shutdown(GoodbyeReason),
}
/// RPC events received from outside Lighthouse.
@ -77,6 +79,7 @@ impl<T: EthSpec> std::fmt::Display for RPCSend<T> {
match self {
RPCSend::Request(id, req) => write!(f, "RPC Request(id: {:?}, {})", id, req),
RPCSend::Response(id, res) => write!(f, "RPC Response(id: {:?}, {})", id, res),
RPCSend::Shutdown(reason) => write!(f, "Sending Goodbye: {}", reason),
}
}
}
@ -115,11 +118,7 @@ impl<TSpec: EthSpec> RPC<TSpec> {
methods::MAX_REQUEST_BLOCKS,
Duration::from_secs(10),
)
.n_every(
Protocol::BlocksByRoot,
methods::MAX_REQUEST_BLOCKS,
Duration::from_secs(10),
)
.n_every(Protocol::BlocksByRoot, 128, Duration::from_secs(10))
.build()
.expect("Configuration parameters are valid");
RPC {
@ -160,6 +159,16 @@ impl<TSpec: EthSpec> RPC<TSpec> {
event: RPCSend::Request(request_id, event),
});
}
/// Lighthouse wishes to disconnect from this peer by sending a Goodbye message. This
/// gracefully terminates the RPC behaviour with a goodbye message.
pub fn shutdown(&mut self, peer_id: PeerId, reason: GoodbyeReason) {
self.events.push(NetworkBehaviourAction::NotifyHandler {
peer_id,
handler: NotifyHandler::Any,
event: RPCSend::Shutdown(reason),
});
}
}
impl<TSpec> NetworkBehaviour for RPC<TSpec>

View File

@ -452,6 +452,8 @@ pub enum RPCError {
NegotiationTimeout,
/// Handler rejected this request.
HandlerRejected,
/// We have intentionally disconnected.
Disconnected,
}
impl From<ssz::DecodeError> for RPCError {
@ -490,6 +492,7 @@ impl std::fmt::Display for RPCError {
RPCError::InternalError(ref err) => write!(f, "Internal error: {}", err),
RPCError::NegotiationTimeout => write!(f, "Negotiation timeout"),
RPCError::HandlerRejected => write!(f, "Handler rejected the request"),
RPCError::Disconnected => write!(f, "Gracefully Disconnected"),
}
}
}
@ -508,6 +511,7 @@ impl std::error::Error for RPCError {
RPCError::ErrorResponse(_, _) => None,
RPCError::NegotiationTimeout => None,
RPCError::HandlerRejected => None,
RPCError::Disconnected => None,
}
}
}

View File

@ -266,6 +266,7 @@ impl<TSpec: EthSpec> Service<TSpec> {
pub fn report_peer(&mut self, peer_id: &PeerId, action: PeerAction, source: ReportSource) {
self.swarm
.behaviour_mut()
.peer_manager_mut()
.report_peer(peer_id, action, source);
}
@ -285,19 +286,48 @@ impl<TSpec: EthSpec> Service<TSpec> {
pub async fn next_event(&mut self) -> Libp2pEvent<TSpec> {
loop {
match self.swarm.next_event().await {
SwarmEvent::Behaviour(behaviour) => return Libp2pEvent::Behaviour(behaviour),
SwarmEvent::ConnectionEstablished { .. } => {
// A connection could be established with a banned peer. This is
// handled inside the behaviour.
match self.swarm.select_next_some().await {
SwarmEvent::Behaviour(behaviour) => {
// Handle banning here
match &behaviour {
BehaviourEvent::PeerBanned(peer_id) => {
self.swarm.ban_peer_id(*peer_id);
}
BehaviourEvent::PeerUnbanned(peer_id) => {
self.swarm.unban_peer_id(*peer_id);
}
_ => {}
}
return Libp2pEvent::Behaviour(behaviour);
}
SwarmEvent::ConnectionEstablished {
peer_id,
endpoint,
num_established,
} => {
// Inform the peer manager.
// We require the ENR to inject into the peer db, if it exists.
let enr = self
.swarm
.behaviour_mut()
.discovery_mut()
.enr_of_peer(&peer_id);
self.swarm
.behaviour_mut()
.peer_manager_mut()
.inject_connection_established(peer_id, endpoint, num_established, enr);
}
SwarmEvent::ConnectionClosed {
peer_id,
cause,
endpoint: _,
cause: _,
endpoint,
num_established,
} => {
trace!(self.log, "Connection closed"; "peer_id" => %peer_id, "cause" => ?cause, "connections" => num_established);
// Inform the peer manager.
self.swarm
.behaviour_mut()
.peer_manager_mut()
.inject_connection_closed(peer_id, endpoint, num_established);
}
SwarmEvent::NewListenAddr(multiaddr) => {
return Libp2pEvent::NewListenAddr(multiaddr)
@ -313,10 +343,10 @@ impl<TSpec: EthSpec> Service<TSpec> {
send_back_addr,
error,
} => {
debug!(self.log, "Failed incoming connection"; "our_addr" => %local_addr, "from" => %send_back_addr, "error" => %error)
debug!(self.log, "Failed incoming connection"; "our_addr" => %local_addr, "from" => %send_back_addr, "error" => %error);
}
SwarmEvent::BannedPeer { .. } => {
// We do not ban peers at the swarm layer, so this should never occur.
SwarmEvent::BannedPeer { peer_id, .. } => {
debug!(self.log, "Banned peer connection rejected"; "peer_id" => %peer_id);
}
SwarmEvent::UnreachableAddr {
peer_id,
@ -325,6 +355,10 @@ impl<TSpec: EthSpec> Service<TSpec> {
attempts_remaining,
} => {
debug!(self.log, "Failed to dial address"; "peer_id" => %peer_id, "address" => %address, "error" => %error, "attempts_remaining" => attempts_remaining);
self.swarm
.behaviour_mut()
.peer_manager_mut()
.inject_dial_failure(&peer_id);
}
SwarmEvent::UnknownPeerUnreachableAddr { address, error } => {
debug!(self.log, "Peer not known at dialed address"; "address" => %address, "error" => %error);
@ -346,7 +380,16 @@ impl<TSpec: EthSpec> Service<TSpec> {
}
}
SwarmEvent::Dialing(peer_id) => {
debug!(self.log, "Dialing peer"; "peer_id" => %peer_id);
// We require the ENR to inject into the peer db, if it exists.
let enr = self
.swarm
.behaviour_mut()
.discovery_mut()
.enr_of_peer(&peer_id);
self.swarm
.behaviour_mut()
.peer_manager_mut()
.inject_dialing(&peer_id, enr);
}
}
}

View File

@ -144,19 +144,19 @@ impl GossipTopic {
}
}
impl Into<Topic> for GossipTopic {
fn into(self) -> Topic {
Topic::new(self)
impl From<GossipTopic> for Topic {
fn from(topic: GossipTopic) -> Topic {
Topic::new(topic)
}
}
impl Into<String> for GossipTopic {
fn into(self) -> String {
let encoding = match self.encoding {
impl From<GossipTopic> for String {
fn from(topic: GossipTopic) -> String {
let encoding = match topic.encoding {
GossipEncoding::SSZSnappy => SSZ_SNAPPY_ENCODING_POSTFIX,
};
let kind = match self.kind {
let kind = match topic.kind {
GossipKind::BeaconBlock => BEACON_BLOCK_TOPIC.into(),
GossipKind::BeaconAggregateAndProof => BEACON_AGGREGATE_AND_PROOF_TOPIC.into(),
GossipKind::VoluntaryExit => VOLUNTARY_EXIT_TOPIC.into(),
@ -167,7 +167,7 @@ impl Into<String> for GossipTopic {
format!(
"/{}/{}/{}/{}",
TOPIC_PREFIX,
hex::encode(self.fork_digest),
hex::encode(topic.fork_digest),
kind,
encoding
)

View File

@ -53,7 +53,7 @@ fn test_status_rpc() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a STATUS message
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().send_request(
@ -149,7 +149,7 @@ fn test_blocks_by_range_chunked_rpc() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a STATUS message
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().send_request(
@ -263,7 +263,7 @@ fn test_blocks_by_range_chunked_rpc_terminates_correctly() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a STATUS message
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().send_request(
@ -395,7 +395,7 @@ fn test_blocks_by_range_single_empty_rpc() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a STATUS message
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().send_request(
@ -510,7 +510,7 @@ fn test_blocks_by_root_chunked_rpc() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a STATUS message
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().send_request(
@ -631,7 +631,7 @@ fn test_blocks_by_root_chunked_rpc_terminates_correctly() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a STATUS message
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().send_request(
@ -746,7 +746,7 @@ fn test_goodbye_rpc() {
let sender_future = async {
loop {
match sender.next_event().await {
Libp2pEvent::Behaviour(BehaviourEvent::PeerDialed(peer_id)) => {
Libp2pEvent::Behaviour(BehaviourEvent::PeerConnectedOutgoing(peer_id)) => {
// Send a goodbye and disconnect
debug!(log, "Sending RPC");
sender.swarm.behaviour_mut().goodbye_peer(

View File

@ -1,7 +1,7 @@
use super::work_reprocessing_queue::ReprocessQueueMessage;
use crate::{service::NetworkMessage, sync::SyncMessage};
use beacon_chain::{BeaconChain, BeaconChainTypes};
use slog::{error, Logger};
use slog::{debug, Logger};
use std::sync::Arc;
use tokio::sync::mpsc;
@ -27,7 +27,7 @@ impl<T: BeaconChainTypes> Worker<T> {
/// Creates a log if there is an internal error.
fn send_sync_message(&self, message: SyncMessage<T::EthSpec>) {
self.sync_tx.send(message).unwrap_or_else(|e| {
error!(self.log, "Could not send message to the sync service";
debug!(self.log, "Could not send message to the sync service, likely shutdown";
"error" => %e)
});
}
@ -37,7 +37,7 @@ impl<T: BeaconChainTypes> Worker<T> {
/// Creates a log if there is an internal error.
fn send_network_message(&self, message: NetworkMessage<T::EthSpec>) {
self.network_tx.send(message).unwrap_or_else(|e| {
error!(self.log, "Could not send message to the network service";
debug!(self.log, "Could not send message to the network service, likely shutdown";
"error" => %e)
});
}

View File

@ -313,7 +313,7 @@ fn spawn_service<T: BeaconChainTypes>(
service.upnp_mappings = (tcp_socket.map(|s| s.port()), udp_socket.map(|s| s.port()));
// If there is an external TCP port update, modify our local ENR.
if let Some(tcp_socket) = tcp_socket {
if let Err(e) = service.libp2p.swarm.behaviour_mut().peer_manager().discovery_mut().update_enr_tcp_port(tcp_socket.port()) {
if let Err(e) = service.libp2p.swarm.behaviour_mut().discovery_mut().update_enr_tcp_port(tcp_socket.port()) {
warn!(service.log, "Failed to update ENR"; "error" => e);
}
}
@ -321,7 +321,7 @@ fn spawn_service<T: BeaconChainTypes>(
// UPnP mappings
if !service.discovery_auto_update {
if let Some(udp_socket) = udp_socket {
if let Err(e) = service.libp2p.swarm.behaviour_mut().peer_manager().discovery_mut().update_enr_udp_socket(udp_socket) {
if let Err(e) = service.libp2p.swarm.behaviour_mut().discovery_mut().update_enr_udp_socket(udp_socket) {
warn!(service.log, "Failed to update ENR"; "error" => e);
}
}
@ -427,17 +427,15 @@ fn spawn_service<T: BeaconChainTypes>(
// poll the swarm
match libp2p_event {
Libp2pEvent::Behaviour(event) => match event {
BehaviourEvent::PeerDialed(peer_id) => {
BehaviourEvent::PeerConnectedOutgoing(peer_id) => {
let _ = service
.router_send
.send(RouterMessage::PeerDialed(peer_id))
.map_err(|_| {
debug!(service.log, "Failed to send peer dialed to router"); });
},
BehaviourEvent::PeerConnected(_peer_id) => {
// A peer has connected to us
// We currently do not perform any action here.
BehaviourEvent::PeerConnectedIncoming(_) | BehaviourEvent::PeerBanned(_) | BehaviourEvent::PeerUnbanned(_) => {
// No action required for these events.
},
BehaviourEvent::PeerDisconnected(peer_id) => {
let _ = service