mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 11:51:12 +00:00
Add a substrate-peerset crate (#2042)
* Add a substrate-peerset crate * Some adjustements * More adjustements * Use a temporary libp2p branch * Add back-off mechanism * Fix RPC tests * Some adjustements * Another libp2p bugfix * Do a round-robin in the peerset * Use a real dependency instead of a patch for libp2p * Initialize reserved nodes correctly * Better diagnostic for no address * Don't allocate slots if in reserved only * Ban node on dial failure * Fix indentation
This commit is contained in:
committed by
Robert Habermeier
parent
f6f15b618e
commit
90c6f85db5
Generated
+115
-97
@@ -1287,30 +1287,30 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-dns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-floodsub 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-identify 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-kad 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-mdns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-mplex 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-noise 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-ping 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-plaintext 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-ratelimit 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-secio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-tcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-uds 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-websocket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-yamux 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-websocket 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1322,7 +1322,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-core"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1333,15 +1333,15 @@ dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"multistream-select 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1357,7 +1357,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-core-derive"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1366,12 +1366,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-dns"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1379,14 +1379,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-floodsub"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1398,14 +1398,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-identify"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1419,7 +1419,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-kad"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1427,12 +1427,12 @@ dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-identify 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-ping 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1447,15 +1447,15 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-mdns"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1468,12 +1468,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-mplex"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1484,12 +1484,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-noise"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1502,14 +1502,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-ping"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1521,21 +1521,21 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-plaintext"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-ratelimit"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1544,7 +1544,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-secio"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1553,12 +1553,12 @@ dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1570,12 +1570,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-tcp"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1584,25 +1584,25 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-uds"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-websocket"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"stdweb 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"websocket 0.22.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1611,10 +1611,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libp2p-yamux"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1807,7 +1807,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "multistream-select"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2179,13 +2179,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-multiaddr"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2193,7 +2193,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-multihash"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2728,7 +2728,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rw-stream-sink"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20#afd9623fccaac5ce1c41db1d82ad4def2652390f"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3943,6 +3943,7 @@ dependencies = [
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-network-libp2p 0.1.0",
|
||||
"substrate-peerset 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-test-client 0.1.0",
|
||||
"tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3958,7 +3959,7 @@ dependencies = [
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3966,6 +3967,7 @@ dependencies = [
|
||||
"serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-peerset 0.1.0",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3982,6 +3984,22 @@ dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-peerset"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-primitives"
|
||||
version = "0.1.0"
|
||||
@@ -5165,24 +5183,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||
"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
|
||||
"checksum libp2p 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96bec5a2470cf03c5f0a74c55fc7b26fe969a1530d09d40e02ed76b287e3f9d9"
|
||||
"checksum libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d53c885b93897902e5fdfd02340459bd940e970b73dd2cf506d4009e527489bf"
|
||||
"checksum libp2p-core-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ab475ca93c07ce539691003b682a0ff025f7dfb51e4ab29f5474457ded59b"
|
||||
"checksum libp2p-dns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "983bc7e80b6b5c89f5c6b674880bc058d37f481812692431914732ee2aeaf87a"
|
||||
"checksum libp2p-floodsub 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aca5042008a7f7ddc53f5d40e6411ffebd66af22989a364303f2996fc5f39c79"
|
||||
"checksum libp2p-identify 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9036ddde527bba0ae8a9037af7637c6c7a10ccdcdff6d2b00e7fe01f7620d400"
|
||||
"checksum libp2p-kad 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f42265a4ad1c3a153465babcf64ea32d33b3872f4e2a27fb1dc3d1ed9301fd"
|
||||
"checksum libp2p-mdns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "260cb7644da51ee2680c6413d350cee35441e78699b38e63600397867e32e3ab"
|
||||
"checksum libp2p-mplex 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938678badaa29182f826308d86a89db53b99dd401121c551a979fd1b0a87af48"
|
||||
"checksum libp2p-noise 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8820b79d0967de619e5dc991f84ffd5b888d06969bc62cf041412b2e9fc1e5c"
|
||||
"checksum libp2p-ping 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad1b0983dbc2bf126583555c7a855ceaa28abfe764b9ede087d308b80ff7b2a"
|
||||
"checksum libp2p-plaintext 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7cb42f7def0cb74781f6793f0fecbcfa0db79baee80adf18215abc30b1b6912c"
|
||||
"checksum libp2p-ratelimit 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6971c2fc1cd938cd702b2320d3b5e3b5a353b1a3310de974769c3fa670d26e"
|
||||
"checksum libp2p-secio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48a881b9c1b6ff0d35d985437d9f59d2d3ee2c529375aa188a978a1bd1d6f261"
|
||||
"checksum libp2p-tcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79583caf603d93dc43ee314409c57e070e9a70c760631eea91822a25e898d1af"
|
||||
"checksum libp2p-uds 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d72965117a6b0ead9b78af8682b0ab6d8c3d71dbb9aadbcb947ef2ef78c2c8a"
|
||||
"checksum libp2p-websocket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b69b73fcef9d58ae90c6742389a1d29e14dcf3a4ab30bba2f0ca7e984fa59f9f"
|
||||
"checksum libp2p-yamux 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "563222e2c303516fa097686573f003ee74761eb8d6b6df4204ae1aa07f5dc16c"
|
||||
"checksum libp2p 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-core 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-core-derive 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-dns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-floodsub 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-identify 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-kad 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-mdns 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-mplex 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-noise 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-ping 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-plaintext 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-ratelimit 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-secio 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-tcp 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-uds 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-websocket 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum libp2p-yamux 0.5.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum librocksdb-sys 5.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9024327233e7fac7982440f73301c00046d438c5b1011e8f4e394226ce19007"
|
||||
"checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a"
|
||||
"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
|
||||
@@ -5204,7 +5222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum multistream-select 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ed84364f0e921a32204896952ee80c7befc14a7a39f2c56cd955d71e8dae6"
|
||||
"checksum multistream-select 0.3.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum names 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef320dab323286b50fb5cdda23f61c796a72a89998ab565ca32525c5c556f2da"
|
||||
"checksum native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8e08de0070bbf4c31f452ea2a70db092f36f6f2e4d897adf5674477d488fb2"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
@@ -5227,8 +5245,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21c9c3a1623c71ed83964ff28cac6126e178920f7646d32c337eacb9152b2907"
|
||||
"checksum parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "864e9f66b58c0b38f0d6b511b6576afa2b678ae801b64220553bced57ac12df9"
|
||||
"checksum parity-crypto 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b9db194dfbcfe3b398d63d765437a5c7232d59906e203055f0e993f6458ff1"
|
||||
"checksum parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61ae6944d4435d41f4d0f12108c5cbb9207cbb14bc8f2b4984c6e930dc9c8e41"
|
||||
"checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076"
|
||||
"checksum parity-multiaddr 0.2.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum parity-multihash 0.1.0 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc"
|
||||
"checksum parity-ws 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fec5048fba72a2e01baeb0d08089db79aead4b57e2443df172fb1840075a233"
|
||||
"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac"
|
||||
@@ -5288,7 +5306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8"
|
||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d548a40fe17c3a77d54b82457b79fcc9b8a288d509ca20fbf5aa1dac386d22d6"
|
||||
"checksum rw-stream-sink 0.1.1 (git+https://github.com/tomaka/libp2p-rs?branch=substrate-tmp-2019-03-20)" = "<none>"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
|
||||
@@ -100,3 +100,4 @@ is-it-maintained-open-issues = { repository = "paritytech/substrate" }
|
||||
[profile.release]
|
||||
# Substrate runtime requires unwinding.
|
||||
panic = "unwind"
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ bytes = "0.4"
|
||||
error-chain = { version = "0.12", default-features = false }
|
||||
fnv = "1.0"
|
||||
futures = "0.1"
|
||||
libp2p = { version = "0.5.0", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] }
|
||||
libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "substrate-tmp-2019-03-20", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] }
|
||||
parking_lot = "0.7.1"
|
||||
lazy_static = "1.2"
|
||||
log = "0.4"
|
||||
@@ -22,6 +22,7 @@ serde = "1.0.70"
|
||||
serde_derive = "1.0.70"
|
||||
serde_json = "1.0.24"
|
||||
smallvec = "0.6"
|
||||
substrate-peerset = { path = "../peerset" }
|
||||
tokio = "0.1"
|
||||
tokio-io = "0.1"
|
||||
tokio-timer = "0.2"
|
||||
|
||||
@@ -15,14 +15,13 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::custom_proto::{CustomProto, CustomProtoOut, RegisteredProtocol};
|
||||
use crate::NetworkConfiguration;
|
||||
use futures::prelude::*;
|
||||
use libp2p::NetworkBehaviour;
|
||||
use libp2p::core::{Multiaddr, PeerId, ProtocolsHandler, PublicKey};
|
||||
use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction};
|
||||
use libp2p::core::swarm::{NetworkBehaviourEventProcess, PollParameters};
|
||||
use libp2p::identify::{Identify, IdentifyEvent, protocol::IdentifyInfo};
|
||||
use libp2p::kad::{Kademlia, KademliaOut, KadConnectionType};
|
||||
use libp2p::kad::{Kademlia, KademliaOut};
|
||||
use libp2p::ping::{Ping, PingEvent};
|
||||
use log::{debug, trace, warn};
|
||||
use std::{cmp, io, fmt, time::Duration, time::Instant};
|
||||
@@ -50,21 +49,35 @@ pub struct Behaviour<TMessage, TSubstream> {
|
||||
|
||||
impl<TMessage, TSubstream> Behaviour<TMessage, TSubstream> {
|
||||
/// Builds a new `Behaviour`.
|
||||
// TODO: redundancy between config and local_public_key (https://github.com/libp2p/rust-libp2p/issues/745)
|
||||
pub fn new(config: &NetworkConfiguration, local_public_key: PublicKey, protocols: RegisteredProtocol<TMessage>) -> Self {
|
||||
pub fn new(
|
||||
user_agent: String,
|
||||
local_public_key: PublicKey,
|
||||
protocol: RegisteredProtocol<TMessage>,
|
||||
known_addresses: Vec<(PeerId, Multiaddr)>,
|
||||
peerset: substrate_peerset::PeersetMut,
|
||||
) -> Self {
|
||||
let identify = {
|
||||
let proto_version = "/substrate/1.0".to_string();
|
||||
let user_agent = format!("{} ({})", config.client_version, config.node_name);
|
||||
Identify::new(proto_version, user_agent, local_public_key.clone())
|
||||
};
|
||||
|
||||
let local_peer_id = local_public_key.into_peer_id();
|
||||
let custom_protocols = CustomProto::new(config, &local_peer_id, protocols);
|
||||
let custom_protocols = CustomProto::new(protocol, peerset);
|
||||
|
||||
let mut kademlia = Kademlia::without_init(local_public_key.into_peer_id());
|
||||
for (peer_id, addr) in &known_addresses {
|
||||
kademlia.add_connected_address(peer_id, addr.clone());
|
||||
}
|
||||
kademlia.initialize();
|
||||
|
||||
Behaviour {
|
||||
ping: Ping::new(),
|
||||
custom_protocols,
|
||||
discovery: DiscoveryBehaviour::new(local_peer_id),
|
||||
discovery: DiscoveryBehaviour {
|
||||
user_defined: known_addresses,
|
||||
kademlia,
|
||||
next_kad_random_query: Delay::new(Instant::now()),
|
||||
duration_to_next_kad: Duration::from_secs(60),
|
||||
},
|
||||
identify,
|
||||
events: Vec::new(),
|
||||
}
|
||||
@@ -81,67 +94,9 @@ impl<TMessage, TSubstream> Behaviour<TMessage, TSubstream> {
|
||||
self.custom_protocols.send_packet(target, data)
|
||||
}
|
||||
|
||||
/// Returns the number of peers in the topology.
|
||||
pub fn num_topology_peers(&self) -> usize {
|
||||
self.custom_protocols.num_topology_peers()
|
||||
}
|
||||
|
||||
/// Flushes the topology to the disk.
|
||||
pub fn flush_topology(&mut self) -> Result<(), io::Error> {
|
||||
self.custom_protocols.flush_topology()
|
||||
}
|
||||
|
||||
/// Perform a cleanup pass, removing all obsolete addresses and peers.
|
||||
///
|
||||
/// This should be done from time to time.
|
||||
pub fn cleanup(&mut self) {
|
||||
self.custom_protocols.cleanup();
|
||||
}
|
||||
|
||||
/// Returns the list of reserved nodes.
|
||||
pub fn reserved_peers(&self) -> impl Iterator<Item = &PeerId> {
|
||||
self.custom_protocols.reserved_peers()
|
||||
}
|
||||
|
||||
/// Try to add a reserved peer.
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
self.custom_protocols.add_reserved_peer(peer_id, addr)
|
||||
}
|
||||
|
||||
/// Try to remove a reserved peer.
|
||||
///
|
||||
/// If we are in reserved mode and we were connected to a node with this peer ID, then this
|
||||
/// method will disconnect it and return its index.
|
||||
pub fn remove_reserved_peer(&mut self, peer_id: PeerId) {
|
||||
self.custom_protocols.remove_reserved_peer(peer_id)
|
||||
}
|
||||
|
||||
/// Returns true if we only accept reserved nodes.
|
||||
pub fn is_reserved_only(&self) -> bool {
|
||||
self.custom_protocols.is_reserved_only()
|
||||
}
|
||||
|
||||
/// Start accepting all peers again if we weren't.
|
||||
pub fn accept_unreserved_peers(&mut self) {
|
||||
self.custom_protocols.accept_unreserved_peers()
|
||||
}
|
||||
|
||||
/// Start refusing non-reserved nodes. Returns the list of nodes that have been disconnected.
|
||||
pub fn deny_unreserved_peers(&mut self) {
|
||||
self.custom_protocols.deny_unreserved_peers()
|
||||
}
|
||||
|
||||
/// Disconnects a peer and bans it for a little while.
|
||||
///
|
||||
/// Same as `drop_node`, except that the same peer will not be able to reconnect later.
|
||||
#[inline]
|
||||
pub fn ban_node(&mut self, peer_id: PeerId) {
|
||||
self.custom_protocols.ban_peer(peer_id)
|
||||
}
|
||||
|
||||
/// Returns a list of all the peers that are banned, and until when.
|
||||
pub fn banned_nodes(&self) -> impl Iterator<Item = (&PeerId, Instant)> {
|
||||
self.custom_protocols.banned_peers()
|
||||
/// Returns the list of nodes that we know exist in the network.
|
||||
pub fn known_peers(&self) -> impl Iterator<Item = &PeerId> {
|
||||
self.discovery.kademlia.kbuckets_entries()
|
||||
}
|
||||
|
||||
/// Returns true if we try to open protocols with the given peer.
|
||||
@@ -154,6 +109,13 @@ impl<TMessage, TSubstream> Behaviour<TMessage, TSubstream> {
|
||||
self.custom_protocols.is_open(peer_id)
|
||||
}
|
||||
|
||||
/// Adds a hard-coded address for the given peer, that never expires.
|
||||
pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
if self.discovery.user_defined.iter().all(|(p, a)| *p != peer_id && *a != addr) {
|
||||
self.discovery.user_defined.push((peer_id, addr));
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnects the custom protocols from a peer.
|
||||
///
|
||||
/// The peer will still be able to use Kademlia or other protocols, but will get disconnected
|
||||
@@ -167,16 +129,6 @@ impl<TMessage, TSubstream> Behaviour<TMessage, TSubstream> {
|
||||
pub fn drop_node(&mut self, peer_id: &PeerId) {
|
||||
self.custom_protocols.disconnect_peer(peer_id)
|
||||
}
|
||||
|
||||
/// Returns the list of peers in the topology.
|
||||
pub fn known_peers(&self) -> impl Iterator<Item = &PeerId> {
|
||||
self.custom_protocols.known_peers()
|
||||
}
|
||||
|
||||
/// Returns a list of addresses known for this peer, and their reputation score.
|
||||
pub fn known_addresses(&mut self, peer_id: &PeerId) -> impl Iterator<Item = (&Multiaddr, u32)> {
|
||||
self.custom_protocols.known_addresses(peer_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Event that can be emitted by the behaviour.
|
||||
@@ -283,10 +235,7 @@ impl<TMessage, TSubstream> NetworkBehaviourEventProcess<IdentifyEvent> for Behav
|
||||
for addr in &info.listen_addrs {
|
||||
self.discovery.kademlia.add_connected_address(&peer_id, addr.clone());
|
||||
}
|
||||
self.custom_protocols.add_discovered_addrs(
|
||||
&peer_id,
|
||||
info.listen_addrs.iter().map(|addr| (addr.clone(), true))
|
||||
);
|
||||
self.custom_protocols.add_discovered_node(&peer_id);
|
||||
self.events.push(BehaviourOut::Identified { peer_id, info });
|
||||
}
|
||||
IdentifyEvent::Error { .. } => {}
|
||||
@@ -301,17 +250,16 @@ impl<TMessage, TSubstream> NetworkBehaviourEventProcess<IdentifyEvent> for Behav
|
||||
impl<TMessage, TSubstream> NetworkBehaviourEventProcess<KademliaOut> for Behaviour<TMessage, TSubstream> {
|
||||
fn inject_event(&mut self, out: KademliaOut) {
|
||||
match out {
|
||||
KademliaOut::Discovered { peer_id, addresses, ty } => {
|
||||
self.custom_protocols.add_discovered_addrs(
|
||||
&peer_id,
|
||||
addresses.into_iter().map(|addr| (addr, ty == KadConnectionType::Connected))
|
||||
);
|
||||
KademliaOut::Discovered { .. } => {}
|
||||
KademliaOut::KBucketAdded { peer_id, .. } => {
|
||||
self.custom_protocols.add_discovered_node(&peer_id);
|
||||
}
|
||||
KademliaOut::FindNodeResult { key, closer_peers } => {
|
||||
trace!(target: "sub-libp2p", "Kademlia query for {:?} yielded {:?} results",
|
||||
trace!(target: "sub-libp2p", "Libp2p => Query for {:?} yielded {:?} results",
|
||||
key, closer_peers.len());
|
||||
if closer_peers.is_empty() {
|
||||
warn!(target: "sub-libp2p", "Kademlia random query has yielded empty results");
|
||||
warn!(target: "sub-libp2p", "Libp2p => Random Kademlia query has yielded empty \
|
||||
results");
|
||||
}
|
||||
}
|
||||
// We never start any GET_PROVIDERS query.
|
||||
@@ -343,6 +291,9 @@ impl<TMessage, TSubstream> Behaviour<TMessage, TSubstream> {
|
||||
|
||||
/// Implementation of `NetworkBehaviour` that discovers the nodes on the network.
|
||||
pub struct DiscoveryBehaviour<TSubstream> {
|
||||
/// User-defined list of nodes and their addresses. Typically includes bootstrap nodes and
|
||||
/// reserved nodes.
|
||||
user_defined: Vec<(PeerId, Multiaddr)>,
|
||||
/// Kademlia requests and answers.
|
||||
kademlia: Kademlia<TSubstream>,
|
||||
/// Stream that fires when we need to perform the next random Kademlia query.
|
||||
@@ -351,16 +302,6 @@ pub struct DiscoveryBehaviour<TSubstream> {
|
||||
duration_to_next_kad: Duration,
|
||||
}
|
||||
|
||||
impl<TSubstream> DiscoveryBehaviour<TSubstream> {
|
||||
fn new(local_peer_id: PeerId) -> Self {
|
||||
DiscoveryBehaviour {
|
||||
kademlia: Kademlia::without_init(local_peer_id),
|
||||
next_kad_random_query: Delay::new(Instant::now()),
|
||||
duration_to_next_kad: Duration::from_secs(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSubstream> NetworkBehaviour for DiscoveryBehaviour<TSubstream>
|
||||
where
|
||||
TSubstream: AsyncRead + AsyncWrite,
|
||||
@@ -373,7 +314,21 @@ where
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
self.kademlia.addresses_of_peer(peer_id)
|
||||
let mut list = self.user_defined.iter()
|
||||
.filter_map(|(p, a)| if p == peer_id { Some(a.clone()) } else { None })
|
||||
.collect::<Vec<_>>();
|
||||
list.extend(self.kademlia.addresses_of_peer(peer_id));
|
||||
trace!(target: "sub-libp2p", "Addresses of {:?} are {:?}", peer_id, list);
|
||||
if list.is_empty() {
|
||||
if self.kademlia.kbuckets_entries().any(|p| p == peer_id) {
|
||||
debug!(target: "sub-libp2p", "Requested dialing to {:?} (peer in k-buckets), \
|
||||
and no address was found", peer_id);
|
||||
} else {
|
||||
debug!(target: "sub-libp2p", "Requested dialing to {:?} (peer not in k-buckets), \
|
||||
and no address was found", peer_id);
|
||||
}
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) {
|
||||
@@ -417,8 +372,8 @@ where
|
||||
Ok(Async::NotReady) => break,
|
||||
Ok(Async::Ready(_)) => {
|
||||
let random_peer_id = PeerId::random();
|
||||
debug!(target: "sub-libp2p", "Starting random Kademlia request for {:?}",
|
||||
random_peer_id);
|
||||
debug!(target: "sub-libp2p", "Libp2p <= Starting random Kademlia request for \
|
||||
{:?}", random_peer_id);
|
||||
self.kademlia.find_node(random_peer_id);
|
||||
|
||||
// Reset the `Delay` to the next random.
|
||||
@@ -427,7 +382,7 @@ where
|
||||
Duration::from_secs(60));
|
||||
},
|
||||
Err(err) => {
|
||||
warn!(target: "sub-libp2p", "Kad query timer errored: {:?}", err);
|
||||
warn!(target: "sub-libp2p", "Kademlia query timer errored: {:?}", err);
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -799,10 +799,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage {
|
||||
is_severe,
|
||||
error: Box::new(err),
|
||||
}));
|
||||
|
||||
// If we failed to open a substream, there is little chance that we manage to open any
|
||||
// other substream ever again on this connection, and thus we disable the handler.
|
||||
self.disable();
|
||||
}
|
||||
|
||||
fn connection_keep_alive(&self) -> KeepAlive {
|
||||
|
||||
@@ -19,5 +19,4 @@ pub use self::upgrade::{CustomMessage, CustomMessageId, RegisteredProtocol};
|
||||
|
||||
mod behaviour;
|
||||
mod handler;
|
||||
mod topology;
|
||||
mod upgrade;
|
||||
|
||||
@@ -1,725 +0,0 @@
|
||||
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.?
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use libp2p::{core::swarm::ConnectedPoint, Multiaddr, PeerId};
|
||||
use log::{debug, info, trace, warn};
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use std::{cmp, fs};
|
||||
use std::io::{Read, Cursor, Error as IoError, ErrorKind as IoErrorKind, Write, BufReader, BufWriter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, Instant, SystemTime};
|
||||
|
||||
/// For each address we're connected to, a period of this duration increases the score by 1.
|
||||
const CONNEC_DURATION_PER_SCORE: Duration = Duration::from_secs(10);
|
||||
/// Maximum number of addresses for a given peer. If there are more than this number of addresses,
|
||||
/// the ones with a lower score will be removed.
|
||||
const MAX_ADDRESSES_PER_PEER: usize = 10;
|
||||
/// Maximum value for the score.
|
||||
const MAX_SCORE: u32 = 100;
|
||||
/// When we successfully connect to a node, raises its score to the given minimum value.
|
||||
const CONNECTED_MINIMUM_SCORE: u32 = 20;
|
||||
/// Initial score that a node discovered through Kademlia receives, where we have a hint that the
|
||||
/// node is reachable.
|
||||
const DISCOVERY_INITIAL_SCORE_CONNECTABLE: u32 = 15;
|
||||
/// Initial score that a node discovered through Kademlia receives, without any hint.
|
||||
const DISCOVERY_INITIAL_SCORE: u32 = 10;
|
||||
/// Score adjustement when we fail to connect to an address.
|
||||
const SCORE_DIFF_ON_FAILED_TO_CONNECT: i32 = -1;
|
||||
/// Default time-to-live for addresses discovered through Kademlia.
|
||||
/// After this time has elapsed and no connection has succeeded, the address will be removed.
|
||||
const KADEMLIA_DISCOVERY_EXPIRATION: Duration = Duration::from_secs(2 * 3600);
|
||||
/// After a successful connection, the TTL is set to a minimum at this amount.
|
||||
const EXPIRATION_PUSH_BACK_CONNEC: Duration = Duration::from_secs(2 * 3600);
|
||||
/// Initial score that a bootstrap node receives when registered.
|
||||
const BOOTSTRAP_NODE_SCORE: u32 = 100;
|
||||
/// Time to live of a boostrap node. This only applies if you start the node later *without*
|
||||
/// that bootstrap node configured anymore.
|
||||
const BOOTSTRAP_NODE_EXPIRATION: Duration = Duration::from_secs(24 * 3600);
|
||||
/// The first time we fail to connect to an address, wait this duration before trying again.
|
||||
const FIRST_CONNECT_FAIL_BACKOFF: Duration = Duration::from_secs(2);
|
||||
/// Every time we fail to connect to an address, multiply the backoff by this constant.
|
||||
const FAIL_BACKOFF_MULTIPLIER: u32 = 2;
|
||||
/// We need a maximum value for the backoff, overwise we risk an overflow.
|
||||
const MAX_BACKOFF: Duration = Duration::from_secs(30 * 60);
|
||||
|
||||
/// Stores information about the topology of the network.
|
||||
#[derive(Debug)]
|
||||
pub struct NetTopology {
|
||||
/// The actual storage. Never contains a key for `local_peer_id`.
|
||||
store: FnvHashMap<PeerId, PeerInfo>,
|
||||
/// Optional path to the file that caches the serialized version of `store`.
|
||||
cache_path: Option<PathBuf>,
|
||||
/// PeerId of the local node.
|
||||
local_peer_id: PeerId,
|
||||
}
|
||||
|
||||
impl NetTopology {
|
||||
/// Initializes a new `NetTopology` that isn't tied to any file.
|
||||
///
|
||||
/// `flush_to_disk()` will be a no-op.
|
||||
#[inline]
|
||||
pub fn memory(local_peer_id: PeerId) -> NetTopology {
|
||||
NetTopology {
|
||||
store: Default::default(),
|
||||
cache_path: None,
|
||||
local_peer_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `NetTopology` that will use `path` as a cache.
|
||||
///
|
||||
/// This function tries to load a known topology from the file. If the file doesn't exist
|
||||
/// or contains garbage data, the execution still continues.
|
||||
///
|
||||
/// Calling `flush_to_disk()` in the future writes to the given path.
|
||||
pub fn from_file<P: AsRef<Path>>(local_peer_id: PeerId, path: P) -> NetTopology {
|
||||
let path = path.as_ref();
|
||||
debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path);
|
||||
let store = try_load(path, &local_peer_id);
|
||||
NetTopology {
|
||||
store,
|
||||
cache_path: Some(path.to_owned()),
|
||||
local_peer_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the topology into the path passed to `from_file`.
|
||||
///
|
||||
/// No-op if the object was created with `memory()`.
|
||||
pub fn flush_to_disk(&mut self) -> Result<(), IoError> {
|
||||
let path = match self.cache_path {
|
||||
Some(ref p) => p,
|
||||
None => return Ok(())
|
||||
};
|
||||
|
||||
let file = fs::File::create(path)?;
|
||||
// TODO: the capacity of the BufWriter is kind of arbitrary ; decide better
|
||||
serialize(BufWriter::with_capacity(1024 * 1024, file), &mut self.store)
|
||||
}
|
||||
|
||||
/// Returns the number of peers in the topology, excluding the local peer.
|
||||
#[inline]
|
||||
pub fn num_peers(&self) -> usize {
|
||||
self.store.len()
|
||||
}
|
||||
|
||||
/// Perform a cleanup pass, removing all obsolete addresses and peers.
|
||||
///
|
||||
/// This should be done from time to time.
|
||||
pub fn cleanup(&mut self) {
|
||||
let now_systime = SystemTime::now();
|
||||
self.store.retain(|_, peer| {
|
||||
let new_addrs = peer.addrs
|
||||
.drain(..)
|
||||
.filter(|a| a.expires > now_systime || a.is_connected())
|
||||
.collect();
|
||||
peer.addrs = new_addrs;
|
||||
!peer.addrs.is_empty()
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a list of all the known addresses of peers, ordered by the
|
||||
/// order in which we should attempt to connect to them.
|
||||
///
|
||||
/// Because of expiration and back-off mechanisms, this list can grow
|
||||
/// by itself over time. The `Instant` that is returned corresponds to
|
||||
/// the earlier known time when a new entry will be added automatically to
|
||||
/// the list.
|
||||
pub fn addrs_to_attempt(&mut self) -> (impl Iterator<Item = (&PeerId, &Multiaddr)>, Instant) {
|
||||
// TODO: optimize
|
||||
let now = Instant::now();
|
||||
let now_systime = SystemTime::now();
|
||||
let mut instant = now + Duration::from_secs(3600);
|
||||
let mut addrs_out = Vec::new();
|
||||
|
||||
let mut peer_addrs = Vec::new();
|
||||
|
||||
'peer_loop: for (peer, info) in &mut self.store {
|
||||
peer_addrs.clear();
|
||||
|
||||
for addr in &mut info.addrs {
|
||||
let (score, is_connected) = addr.score_and_is_connected();
|
||||
if is_connected {
|
||||
continue 'peer_loop
|
||||
}
|
||||
if score == 0 || addr.expires < now_systime {
|
||||
continue
|
||||
}
|
||||
if addr.back_off_until > now {
|
||||
instant = cmp::min(instant, addr.back_off_until);
|
||||
continue
|
||||
}
|
||||
|
||||
peer_addrs.push(((peer, &addr.addr), score));
|
||||
}
|
||||
|
||||
for val in peer_addrs.drain(..) {
|
||||
addrs_out.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
addrs_out.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
(addrs_out.into_iter().map(|a| a.0), instant)
|
||||
}
|
||||
|
||||
/// Adds an address corresponding to a boostrap node.
|
||||
///
|
||||
/// We assume that the address is valid, so its score starts very high.
|
||||
pub fn add_bootstrap_addr(&mut self, peer: &PeerId, addr: Multiaddr) {
|
||||
if *peer == self.local_peer_id {
|
||||
return
|
||||
}
|
||||
|
||||
let now_systime = SystemTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
let peer = peer_access(&mut self.store, peer);
|
||||
|
||||
let mut found = false;
|
||||
let new_addrs = peer.addrs
|
||||
.drain(..)
|
||||
.filter_map(|a| {
|
||||
if a.expires < now_systime && !a.is_connected() {
|
||||
return None
|
||||
}
|
||||
if a.addr == addr {
|
||||
found = true;
|
||||
}
|
||||
Some(a)
|
||||
})
|
||||
.collect();
|
||||
peer.addrs = new_addrs;
|
||||
|
||||
if !found {
|
||||
peer.addrs.push(Addr {
|
||||
addr,
|
||||
expires: now_systime + BOOTSTRAP_NODE_EXPIRATION,
|
||||
back_off_until: now,
|
||||
next_back_off: FIRST_CONNECT_FAIL_BACKOFF,
|
||||
score: AddrScore {
|
||||
connected_since: None,
|
||||
score: BOOTSTRAP_NODE_SCORE,
|
||||
latest_score_update: now,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates the topology that we have discovered new addresses for a given node.
|
||||
///
|
||||
/// Returns `true` if the topology has changed in some way. Returns `false` if calling this
|
||||
/// method was a no-op.
|
||||
pub fn add_discovered_addrs<I>(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
addrs: I,
|
||||
) -> bool
|
||||
where I: Iterator<Item = (Multiaddr, bool)> {
|
||||
if *peer_id == self.local_peer_id {
|
||||
return false
|
||||
}
|
||||
|
||||
let mut addrs: Vec<_> = addrs.collect();
|
||||
|
||||
if addrs.len() > 40 {
|
||||
warn!(target: "sub-libp2p", "Attempt to add more than 40 addresses for {:?}", peer_id);
|
||||
addrs.truncate(40);
|
||||
}
|
||||
|
||||
let now_systime = SystemTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
let peer = peer_access(&mut self.store, peer_id);
|
||||
|
||||
let new_addrs = peer.addrs
|
||||
.drain(..)
|
||||
.filter(|a| {
|
||||
if a.expires < now_systime && !a.is_connected() {
|
||||
return false
|
||||
}
|
||||
addrs.retain(|(addr, _)| *addr != a.addr);
|
||||
true
|
||||
})
|
||||
.collect();
|
||||
peer.addrs = new_addrs;
|
||||
|
||||
let mut anything_changed = false;
|
||||
|
||||
if !addrs.is_empty() {
|
||||
anything_changed = true;
|
||||
trace!(
|
||||
target: "sub-libp2p",
|
||||
"Peer store: adding addresses {:?} for {:?}",
|
||||
addrs,
|
||||
peer_id,
|
||||
);
|
||||
}
|
||||
|
||||
'addrs_inserter: for (addr, connectable) in addrs {
|
||||
let initial_score = if connectable {
|
||||
DISCOVERY_INITIAL_SCORE_CONNECTABLE
|
||||
} else {
|
||||
DISCOVERY_INITIAL_SCORE
|
||||
};
|
||||
|
||||
// Enforce `MAX_ADDRESSES_PER_PEER` before inserting, or skip this entry.
|
||||
while peer.addrs.len() >= MAX_ADDRESSES_PER_PEER {
|
||||
let pos = peer.addrs.iter_mut().position(|addr| addr.score() <= initial_score);
|
||||
if let Some(pos) = pos {
|
||||
let _ = peer.addrs.remove(pos);
|
||||
} else {
|
||||
continue 'addrs_inserter;
|
||||
}
|
||||
}
|
||||
|
||||
// `addrs` can contain duplicates, therefore we would insert the same address twice.
|
||||
if peer.addrs.iter().any(|a| a.addr == addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
peer.addrs.push(Addr {
|
||||
addr,
|
||||
expires: now_systime + KADEMLIA_DISCOVERY_EXPIRATION,
|
||||
back_off_until: now,
|
||||
next_back_off: FIRST_CONNECT_FAIL_BACKOFF,
|
||||
score: AddrScore {
|
||||
connected_since: None,
|
||||
score: initial_score,
|
||||
latest_score_update: now,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
anything_changed
|
||||
}
|
||||
|
||||
/// Returns the list of peers that are stored in the topology.
|
||||
#[inline]
|
||||
pub fn known_peers(&self) -> impl Iterator<Item = &PeerId> {
|
||||
self.store.keys()
|
||||
}
|
||||
|
||||
/// Returns the addresses stored for a specific peer, and their reputation score.
|
||||
///
|
||||
/// If `include_expired` is true, includes expired addresses that shouldn't be taken into
|
||||
/// account when dialing.
|
||||
#[inline]
|
||||
pub fn addresses_of_peer(&mut self, peer: &PeerId, include_expired: bool)
|
||||
-> impl Iterator<Item = (&Multiaddr, u32)> {
|
||||
let now_st = SystemTime::now();
|
||||
let now_is = Instant::now();
|
||||
|
||||
let mut list = self.store.get_mut(peer).into_iter().flat_map(|p| p.addrs.iter_mut()).filter_map(move |addr| {
|
||||
let (score, connected) = addr.score_and_is_connected();
|
||||
if include_expired || (addr.expires >= now_st && score > 0 && addr.back_off_until < now_is) || connected {
|
||||
Some((score, &addr.addr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
list.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
// TODO: meh, optimize
|
||||
list.into_iter().map(|(score, addr)| (addr, score))
|
||||
}
|
||||
|
||||
/// Marks the given peer as connected through the given endpoint.
|
||||
pub fn set_connected(&mut self, peer: &PeerId, endpoint: &ConnectedPoint) {
|
||||
if *peer == self.local_peer_id {
|
||||
return
|
||||
}
|
||||
|
||||
let addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address } => address,
|
||||
ConnectedPoint::Listener { .. } => return
|
||||
};
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
// Just making sure that we have an entry for this peer in `store`, but don't use it.
|
||||
let _ = peer_access(&mut self.store, peer);
|
||||
|
||||
for (peer_in_store, info_in_store) in self.store.iter_mut() {
|
||||
if peer == peer_in_store {
|
||||
if let Some(addr) = info_in_store.addrs.iter_mut().find(|a| &a.addr == addr) {
|
||||
addr.connected_now(CONNECTED_MINIMUM_SCORE);
|
||||
addr.back_off_until = now;
|
||||
addr.next_back_off = FIRST_CONNECT_FAIL_BACKOFF;
|
||||
continue
|
||||
}
|
||||
|
||||
info_in_store.addrs.push(Addr {
|
||||
addr: addr.clone(),
|
||||
expires: SystemTime::now() + EXPIRATION_PUSH_BACK_CONNEC,
|
||||
back_off_until: now,
|
||||
next_back_off: FIRST_CONNECT_FAIL_BACKOFF,
|
||||
score: AddrScore {
|
||||
connected_since: Some(now),
|
||||
latest_score_update: now,
|
||||
score: CONNECTED_MINIMUM_SCORE,
|
||||
},
|
||||
});
|
||||
|
||||
} else {
|
||||
// Set the score to 0 for any address that matches the one we connected to.
|
||||
for addr_in_store in &mut info_in_store.addrs {
|
||||
if &addr_in_store.addr == addr {
|
||||
addr_in_store.adjust_score(-(MAX_SCORE as i32));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks the given peer as disconnected. The endpoint is the one we were connected to.
|
||||
pub fn set_disconnected(&mut self, _: &PeerId, endpoint: &ConnectedPoint) {
|
||||
let addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address } => address,
|
||||
ConnectedPoint::Listener { .. } => return
|
||||
};
|
||||
|
||||
// Note that we used to have different score values here in the past, but there really
|
||||
// isn't much point in doing so in practice.
|
||||
let score_diff = -3;
|
||||
|
||||
for info in self.store.values_mut() {
|
||||
for a in info.addrs.iter_mut() {
|
||||
if &a.addr == addr {
|
||||
a.disconnected_now(score_diff);
|
||||
a.back_off_until = Instant::now() + a.next_back_off;
|
||||
a.next_back_off = cmp::min(a.next_back_off * FAIL_BACKOFF_MULTIPLIER, MAX_BACKOFF);
|
||||
let expires_push_back = SystemTime::now() + EXPIRATION_PUSH_BACK_CONNEC;
|
||||
if a.expires < expires_push_back {
|
||||
a.expires = expires_push_back;
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates to the topology that we failed to reach a node when dialing the given address.
|
||||
pub fn set_unreachable(&mut self, addr: &Multiaddr) {
|
||||
for info in self.store.values_mut() {
|
||||
for a in info.addrs.iter_mut() {
|
||||
if &a.addr != addr {
|
||||
continue
|
||||
}
|
||||
|
||||
// It is possible that we are connected to this address, and that the dial failure
|
||||
// concerns another peer.
|
||||
if a.is_connected() {
|
||||
continue
|
||||
}
|
||||
|
||||
a.adjust_score(SCORE_DIFF_ON_FAILED_TO_CONNECT);
|
||||
trace!(target: "sub-libp2p", "Back off for {} = {:?}", addr, a.next_back_off);
|
||||
a.back_off_until = Instant::now() + a.next_back_off;
|
||||
a.next_back_off = cmp::min(a.next_back_off * FAIL_BACKOFF_MULTIPLIER, MAX_BACKOFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn peer_access<'a>(store: &'a mut FnvHashMap<PeerId, PeerInfo>, peer: &PeerId) -> &'a mut PeerInfo {
|
||||
// TODO: should be optimizable if HashMap gets a better API
|
||||
store.entry(peer.clone()).or_insert_with(Default::default)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct PeerInfo {
|
||||
/// Addresses of that peer.
|
||||
addrs: Vec<Addr>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Addr {
|
||||
/// The multiaddress.
|
||||
addr: Multiaddr,
|
||||
/// When the address expires.
|
||||
expires: SystemTime,
|
||||
next_back_off: Duration,
|
||||
/// Don't try to connect to this node until `Instant`.
|
||||
back_off_until: Instant,
|
||||
score: AddrScore,
|
||||
}
|
||||
|
||||
impl Clone for Addr {
|
||||
fn clone(&self) -> Addr {
|
||||
Addr {
|
||||
addr: self.addr.clone(),
|
||||
expires: self.expires,
|
||||
next_back_off: self.next_back_off,
|
||||
back_off_until: self.back_off_until,
|
||||
score: self.score.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct AddrScore {
|
||||
/// If connected, contains the moment when we connected. `None` if we're not connected.
|
||||
connected_since: Option<Instant>,
|
||||
/// Score of this address. Potentially needs to be updated based on `latest_score_update`.
|
||||
score: u32,
|
||||
/// When we last updated the score.
|
||||
latest_score_update: Instant,
|
||||
}
|
||||
|
||||
impl Addr {
|
||||
/// Sets the addr to connected. If the score is lower than the given value, raises it to this
|
||||
/// value.
|
||||
fn connected_now(&mut self, raise_to_min: u32) {
|
||||
let now = Instant::now();
|
||||
Addr::flush(&mut self.score, now);
|
||||
self.score.connected_since = Some(now);
|
||||
if self.score.score < raise_to_min {
|
||||
self.score.score = raise_to_min;
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a modification to the score.
|
||||
fn adjust_score(&mut self, score_diff: i32) {
|
||||
Addr::flush(&mut self.score, Instant::now());
|
||||
if score_diff >= 0 {
|
||||
self.score.score = cmp::min(MAX_SCORE, self.score.score + score_diff as u32);
|
||||
} else {
|
||||
self.score.score = self.score.score.saturating_sub(-score_diff as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the addr to disconnected and applies a modification to the score.
|
||||
fn disconnected_now(&mut self, score_diff: i32) {
|
||||
Addr::flush(&mut self.score, Instant::now());
|
||||
self.score.connected_since = None;
|
||||
if score_diff >= 0 {
|
||||
self.score.score = cmp::min(MAX_SCORE, self.score.score + score_diff as u32);
|
||||
} else {
|
||||
self.score.score = self.score.score.saturating_sub(-score_diff as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if we are connected to this addr.
|
||||
fn is_connected(&self) -> bool {
|
||||
self.score.connected_since.is_some()
|
||||
}
|
||||
|
||||
/// Returns the score, and true if we are connected to this addr.
|
||||
fn score_and_is_connected(&mut self) -> (u32, bool) {
|
||||
Addr::flush(&mut self.score, Instant::now());
|
||||
let is_connected = self.score.connected_since.is_some();
|
||||
(self.score.score, is_connected)
|
||||
}
|
||||
|
||||
/// Updates `score` and `latest_score_update`, and returns the score.
|
||||
fn score(&mut self) -> u32 {
|
||||
Addr::flush(&mut self.score, Instant::now());
|
||||
self.score.score
|
||||
}
|
||||
|
||||
fn flush(score: &mut AddrScore, now: Instant) {
|
||||
if let Some(connected_since) = score.connected_since {
|
||||
let potential_score: u32 = div_dur_with_dur(now - connected_since, CONNEC_DURATION_PER_SCORE);
|
||||
// We flush when we connect to an address.
|
||||
debug_assert!(score.latest_score_update >= connected_since);
|
||||
let effective_score: u32 =
|
||||
div_dur_with_dur(score.latest_score_update - connected_since, CONNEC_DURATION_PER_SCORE);
|
||||
let to_add = potential_score.saturating_sub(effective_score);
|
||||
score.score = cmp::min(MAX_SCORE, score.score + to_add);
|
||||
}
|
||||
|
||||
score.latest_score_update = now;
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides a `Duration` with a `Duration`. This exists in the stdlib but isn't stable yet.
|
||||
// TODO: remove this function once stable
|
||||
fn div_dur_with_dur(a: Duration, b: Duration) -> u32 {
|
||||
let a_ms = a.as_secs() * 1_000_000 + u64::from(a.subsec_micros());
|
||||
let b_ms = b.as_secs() * 1_000_000 + u64::from(b.subsec_micros());
|
||||
(a_ms / b_ms) as u32
|
||||
}
|
||||
|
||||
/// Serialized version of a `PeerInfo`. Suitable for storage in the cache file.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct SerializedPeerInfo {
|
||||
addrs: Vec<SerializedAddr>,
|
||||
}
|
||||
|
||||
/// Serialized version of an `Addr`. Suitable for storage in the cache file.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct SerializedAddr {
|
||||
addr: String,
|
||||
expires: SystemTime,
|
||||
score: u32,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut Addr> for SerializedAddr {
|
||||
fn from(addr: &'a mut Addr) -> SerializedAddr {
|
||||
SerializedAddr {
|
||||
addr: addr.addr.to_string(),
|
||||
expires: addr.expires,
|
||||
score: addr.score(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to load storage from a file.
|
||||
/// Ignores any entry equal to `local_peer_id`.
|
||||
/// Deletes the file and returns an empty map if the file doesn't exist, cannot be opened
|
||||
/// or is corrupted.
|
||||
fn try_load(path: impl AsRef<Path>, local_peer_id: &PeerId) -> FnvHashMap<PeerId, PeerInfo> {
|
||||
let path = path.as_ref();
|
||||
if !path.exists() {
|
||||
debug!(target: "sub-libp2p", "Peer storage file {:?} doesn't exist", path);
|
||||
return Default::default()
|
||||
}
|
||||
|
||||
let mut file = match fs::File::open(path) {
|
||||
// TODO: the capacity of the BufReader is kind of arbitrary ; decide better
|
||||
Ok(f) => BufReader::with_capacity(1024 * 1024, f),
|
||||
Err(err) => {
|
||||
warn!(target: "sub-libp2p", "Failed to open peer storage file: {:?}", err);
|
||||
info!(target: "sub-libp2p", "Deleting peer storage file {:?}", path);
|
||||
let _ = fs::remove_file(path);
|
||||
return Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
// We want to support empty files (and treat them as an empty recordset). Unfortunately
|
||||
// `serde_json` will always produce an error if we do this ("unexpected EOF at line 0
|
||||
// column 0"). Therefore we start by reading one byte from the file in order to check
|
||||
// for EOF.
|
||||
|
||||
let mut first_byte = [0];
|
||||
let num_read = match file.read(&mut first_byte) {
|
||||
Ok(f) => f,
|
||||
Err(err) => {
|
||||
// TODO: DRY
|
||||
warn!(target: "sub-libp2p", "Failed to read peer storage file: {:?}", err);
|
||||
info!(target: "sub-libp2p", "Deleting peer storage file {:?}", path);
|
||||
let _ = fs::remove_file(path);
|
||||
return Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
if num_read == 0 {
|
||||
// File is empty.
|
||||
debug!(target: "sub-libp2p", "Peer storage file {:?} is empty", path);
|
||||
Default::default()
|
||||
|
||||
} else {
|
||||
let data = Cursor::new(first_byte).chain(file);
|
||||
match serde_json::from_reader::<_, serde_json::Value>(data) {
|
||||
Ok(serde_json::Value::Null) => Default::default(),
|
||||
Ok(serde_json::Value::Object(map)) =>
|
||||
deserialize_tolerant(map.into_iter(), local_peer_id),
|
||||
Ok(_) | Err(_) => {
|
||||
// The `Ok(_)` case means that the file doesn't contain a map.
|
||||
let _ = fs::remove_file(path);
|
||||
Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to turn a deserialized version of the storage into the final version.
|
||||
///
|
||||
/// Skips entries that are invalid or equal to `local_peer_id`.
|
||||
fn deserialize_tolerant(
|
||||
iter: impl Iterator<Item = (String, serde_json::Value)>,
|
||||
local_peer_id: &PeerId
|
||||
) -> FnvHashMap<PeerId, PeerInfo> {
|
||||
let now = Instant::now();
|
||||
let now_systime = SystemTime::now();
|
||||
|
||||
let mut out = FnvHashMap::default();
|
||||
for (peer, info) in iter {
|
||||
let peer: PeerId = match peer.parse() {
|
||||
Ok(p) => p,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if &peer == local_peer_id {
|
||||
continue
|
||||
}
|
||||
|
||||
let info: SerializedPeerInfo = match serde_json::from_value(info) {
|
||||
Ok(i) => i,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut addrs = Vec::with_capacity(info.addrs.len());
|
||||
for addr in info.addrs {
|
||||
let multiaddr = match addr.addr.parse() {
|
||||
Ok(a) => a,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if addr.expires < now_systime {
|
||||
continue
|
||||
}
|
||||
|
||||
addrs.push(Addr {
|
||||
addr: multiaddr,
|
||||
expires: addr.expires,
|
||||
next_back_off: FIRST_CONNECT_FAIL_BACKOFF,
|
||||
back_off_until: now,
|
||||
score: AddrScore {
|
||||
connected_since: None,
|
||||
score: addr.score,
|
||||
latest_score_update: now,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if addrs.is_empty() {
|
||||
continue
|
||||
}
|
||||
|
||||
out.insert(peer, PeerInfo { addrs });
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Attempts to turn a deserialized version of the storage into the final version.
|
||||
///
|
||||
/// Skips entries that are invalid or expired.
|
||||
fn serialize<W: Write>(out: W, map: &mut FnvHashMap<PeerId, PeerInfo>) -> Result<(), IoError> {
|
||||
let now = SystemTime::now();
|
||||
let array: FnvHashMap<_, _> = map.iter_mut().filter_map(|(peer, info)| {
|
||||
if info.addrs.is_empty() {
|
||||
return None
|
||||
}
|
||||
|
||||
let peer = peer.to_base58();
|
||||
let info = SerializedPeerInfo {
|
||||
addrs: info.addrs.iter_mut()
|
||||
.filter_map(|a| if a.expires > now || a.is_connected() {
|
||||
Some(a.into())
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
Some((peer, info))
|
||||
}).collect();
|
||||
|
||||
serde_json::to_writer_pretty(out, &array)
|
||||
.map_err(|err| IoError::new(IoErrorKind::Other, err))
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::ProtocolId;
|
||||
use bytes::Bytes;
|
||||
use libp2p::core::{Endpoint, UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName};
|
||||
use libp2p::core::{Negotiated, Endpoint, UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName};
|
||||
use libp2p::tokio_codec::Framed;
|
||||
use log::warn;
|
||||
use std::{collections::VecDeque, io, iter, marker::PhantomData, vec::IntoIter as VecIntoIter};
|
||||
@@ -92,7 +92,7 @@ pub struct RegisteredProtocolSubstream<TMessage, TSubstream> {
|
||||
/// If true, we should call `poll_complete` on the inner sink.
|
||||
requires_poll_complete: bool,
|
||||
/// The underlying substream.
|
||||
inner: stream::Fuse<Framed<TSubstream, UviBytes<Vec<u8>>>>,
|
||||
inner: stream::Fuse<Framed<Negotiated<TSubstream>, UviBytes<Vec<u8>>>>,
|
||||
/// Id of the protocol.
|
||||
protocol_id: ProtocolId,
|
||||
/// Version of the protocol that was negotiated.
|
||||
@@ -385,7 +385,7 @@ where TSubstream: AsyncRead + AsyncWrite,
|
||||
|
||||
fn upgrade_inbound(
|
||||
self,
|
||||
socket: TSubstream,
|
||||
socket: Negotiated<TSubstream>,
|
||||
info: Self::Info,
|
||||
) -> Self::Future {
|
||||
let framed = {
|
||||
@@ -418,7 +418,7 @@ where TSubstream: AsyncRead + AsyncWrite,
|
||||
|
||||
fn upgrade_outbound(
|
||||
self,
|
||||
socket: TSubstream,
|
||||
socket: Negotiated<TSubstream>,
|
||||
info: Self::Info,
|
||||
) -> Self::Future {
|
||||
let framed = Framed::new(socket, UviBytes::default());
|
||||
|
||||
@@ -106,12 +106,6 @@ pub struct NetworkState {
|
||||
/// List of addresses the node is currently listening on.
|
||||
pub listened_addresses: HashSet<Multiaddr>,
|
||||
// TODO (https://github.com/libp2p/rust-libp2p/issues/978): external_addresses: Vec<Multiaddr>,
|
||||
/// If true, we only accept reserved peers.
|
||||
pub is_reserved_only: bool,
|
||||
/// PeerIds of the nodes that are marked as reserved.
|
||||
pub reserved_peers: HashSet<String>,
|
||||
/// PeerIds of the nodes that are banned, and how long in the seconds the ban remains.
|
||||
pub banned_peers: HashMap<String, u64>,
|
||||
/// List of node we're connected to.
|
||||
pub connected_peers: HashMap<String, NetworkStatePeer>,
|
||||
/// List of node that we know of but that we're not connected to.
|
||||
@@ -137,15 +131,15 @@ pub struct NetworkStatePeer {
|
||||
/// If true, the peer is "open", which means that we have a Substrate-related protocol
|
||||
/// with this peer.
|
||||
pub open: bool,
|
||||
/// List of addresses known for this node, with its reputation score.
|
||||
pub known_addresses: HashMap<Multiaddr, u32>,
|
||||
/// List of addresses known for this node.
|
||||
pub known_addresses: HashSet<Multiaddr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NetworkStateNotConnectedPeer {
|
||||
/// List of addresses known for this node, with its reputation score.
|
||||
pub known_addresses: HashMap<Multiaddr, u32>,
|
||||
/// List of addresses known for this node.
|
||||
pub known_addresses: HashSet<Multiaddr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
|
||||
@@ -19,20 +19,19 @@ use crate::{
|
||||
transport, NetworkState, NetworkStatePeer, NetworkStateNotConnectedPeer
|
||||
};
|
||||
use crate::custom_proto::{CustomMessage, RegisteredProtocol};
|
||||
use crate::{NetworkConfiguration, NodeIndex, parse_str_addr};
|
||||
use crate::{NetworkConfiguration, NonReservedPeerMode, NodeIndex, parse_str_addr};
|
||||
use fnv::FnvHashMap;
|
||||
use futures::{prelude::*, Stream};
|
||||
use libp2p::{multiaddr::Protocol, Multiaddr, PeerId};
|
||||
use libp2p::{multiaddr::Protocol, Multiaddr, core::swarm::NetworkBehaviour, PeerId};
|
||||
use libp2p::core::{Swarm, nodes::Substream, transport::boxed::Boxed, muxing::StreamMuxerBox};
|
||||
use libp2p::core::nodes::ConnectedPoint;
|
||||
use log::{debug, error, info, warn};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fs;
|
||||
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||
use std::io::Error as IoError;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio_timer::Interval;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Starts the substrate libp2p service.
|
||||
///
|
||||
@@ -40,13 +39,48 @@ use tokio_timer::Interval;
|
||||
pub fn start_service<TMessage>(
|
||||
config: NetworkConfiguration,
|
||||
registered_custom: RegisteredProtocol<TMessage>,
|
||||
) -> Result<Service<TMessage>, IoError>
|
||||
) -> Result<(Service<TMessage>, Arc<substrate_peerset::Peerset>), IoError>
|
||||
where TMessage: CustomMessage + Send + 'static {
|
||||
|
||||
if let Some(ref path) = config.net_config_path {
|
||||
fs::create_dir_all(Path::new(path))?;
|
||||
}
|
||||
|
||||
// List of multiaddresses that we know in the network.
|
||||
let mut known_addresses = Vec::new();
|
||||
let mut bootnodes = Vec::new();
|
||||
let mut reserved_nodes = Vec::new();
|
||||
|
||||
// Process the bootnodes.
|
||||
for bootnode in config.boot_nodes.iter() {
|
||||
match parse_str_addr(bootnode) {
|
||||
Ok((peer_id, addr)) => {
|
||||
bootnodes.push(peer_id.clone());
|
||||
known_addresses.push((peer_id, addr));
|
||||
},
|
||||
Err(_) => warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode),
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the reserved peers.
|
||||
for reserved in config.reserved_nodes.iter() {
|
||||
if let Ok((peer_id, addr)) = parse_str_addr(reserved) {
|
||||
reserved_nodes.push(peer_id.clone());
|
||||
known_addresses.push((peer_id, addr));
|
||||
} else {
|
||||
warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the peerset.
|
||||
let (peerset, peerset_receiver) = substrate_peerset::Peerset::from_config(substrate_peerset::PeersetConfig {
|
||||
in_peers: 25,
|
||||
out_peers: 25,
|
||||
bootnodes,
|
||||
reserved_only: config.non_reserved_mode == NonReservedPeerMode::Deny,
|
||||
reserved_nodes,
|
||||
});
|
||||
|
||||
// Private and public keys configuration.
|
||||
let local_identity = config.node_key.clone().into_keypair()?;
|
||||
let local_public = local_identity.public();
|
||||
@@ -54,7 +88,8 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
|
||||
// Build the swarm.
|
||||
let (mut swarm, bandwidth) = {
|
||||
let behaviour = Behaviour::new(&config, local_public, registered_custom);
|
||||
let user_agent = format!("{} ({})", config.client_version, config.node_name);
|
||||
let behaviour = Behaviour::new(user_agent, local_public, registered_custom, known_addresses, peerset_receiver);
|
||||
let (transport, bandwidth) = transport::build_transport(local_identity);
|
||||
(Swarm::new(transport, behaviour, local_peer_id.clone()), bandwidth)
|
||||
};
|
||||
@@ -75,36 +110,16 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
Swarm::add_external_address(&mut swarm, addr.clone());
|
||||
}
|
||||
|
||||
// Connect to the bootnodes.
|
||||
for bootnode in config.boot_nodes.iter() {
|
||||
match parse_str_addr(bootnode) {
|
||||
Ok((peer_id, _)) => Swarm::dial(&mut swarm, peer_id),
|
||||
Err(_) => warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode),
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the reserved peers.
|
||||
for reserved in config.reserved_nodes.iter() {
|
||||
if let Ok((peer_id, addr)) = parse_str_addr(reserved) {
|
||||
swarm.add_reserved_peer(peer_id.clone(), addr);
|
||||
Swarm::dial(&mut swarm, peer_id);
|
||||
} else {
|
||||
warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved);
|
||||
}
|
||||
}
|
||||
|
||||
debug!(target: "sub-libp2p", "Topology started with {} entries",
|
||||
swarm.num_topology_peers());
|
||||
|
||||
Ok(Service {
|
||||
let service = Service {
|
||||
swarm,
|
||||
bandwidth,
|
||||
nodes_info: Default::default(),
|
||||
index_by_id: Default::default(),
|
||||
next_node_id: 1,
|
||||
cleanup: Interval::new_interval(Duration::from_secs(60)),
|
||||
injected_events: Vec::new(),
|
||||
})
|
||||
};
|
||||
|
||||
Ok((service, peerset))
|
||||
}
|
||||
|
||||
/// Event produced by the service.
|
||||
@@ -164,10 +179,6 @@ pub struct Service<TMessage> where TMessage: CustomMessage {
|
||||
/// Next index to assign to a node.
|
||||
next_node_id: NodeIndex,
|
||||
|
||||
/// Stream that fires when we need to cleanup and flush the topology, and cleanup the disabled
|
||||
/// peers.
|
||||
cleanup: Interval,
|
||||
|
||||
/// Events to produce on the Stream.
|
||||
injected_events: Vec<ServiceEvent<TMessage>>,
|
||||
}
|
||||
@@ -189,13 +200,11 @@ impl<TMessage> Service<TMessage>
|
||||
where TMessage: CustomMessage + Send + 'static {
|
||||
/// Returns a struct containing tons of useful information about the network.
|
||||
pub fn state(&mut self) -> NetworkState {
|
||||
let now = Instant::now();
|
||||
|
||||
let connected_peers = {
|
||||
let swarm = &mut self.swarm;
|
||||
self.nodes_info.values().map(move |info| {
|
||||
let known_addresses = swarm.known_addresses(&info.peer_id)
|
||||
.map(|(a, s)| (a.clone(), s)).collect();
|
||||
let known_addresses = NetworkBehaviour::addresses_of_peer(&mut **swarm, &info.peer_id)
|
||||
.into_iter().collect();
|
||||
|
||||
(info.peer_id.to_base58(), NetworkStatePeer {
|
||||
endpoint: info.endpoint.clone().into(),
|
||||
@@ -214,10 +223,9 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
let list = swarm.known_peers().filter(|p| !index_by_id.contains_key(p))
|
||||
.cloned().collect::<Vec<_>>();
|
||||
list.into_iter().map(move |peer_id| {
|
||||
let known_addresses = swarm.known_addresses(&peer_id)
|
||||
.map(|(a, s)| (a.clone(), s)).collect();
|
||||
(peer_id.to_base58(), NetworkStateNotConnectedPeer {
|
||||
known_addresses,
|
||||
known_addresses: NetworkBehaviour::addresses_of_peer(&mut **swarm, &peer_id)
|
||||
.into_iter().collect(),
|
||||
})
|
||||
}).collect()
|
||||
};
|
||||
@@ -225,12 +233,6 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
NetworkState {
|
||||
peer_id: Swarm::local_peer_id(&self.swarm).to_base58(),
|
||||
listened_addresses: Swarm::listeners(&self.swarm).cloned().collect(),
|
||||
reserved_peers: self.swarm.reserved_peers().map(|p| p.to_base58()).collect(),
|
||||
banned_peers: self.swarm.banned_nodes().map(|(p, until)| {
|
||||
let dur = if until > now { until - now } else { Duration::new(0, 0) };
|
||||
(p.to_base58(), dur.as_secs())
|
||||
}).collect(),
|
||||
is_reserved_only: self.swarm.is_reserved_only(),
|
||||
average_download_per_sec: self.bandwidth.average_download_per_sec(),
|
||||
average_upload_per_sec: self.bandwidth.average_upload_per_sec(),
|
||||
connected_peers,
|
||||
@@ -268,31 +270,6 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
self.nodes_info.keys().cloned()
|
||||
}
|
||||
|
||||
/// Try to add a reserved peer.
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
self.swarm.add_reserved_peer(peer_id, addr);
|
||||
}
|
||||
|
||||
/// Try to remove a reserved peer.
|
||||
///
|
||||
/// If we are in reserved mode and we were connected to a node with this peer ID, then this
|
||||
/// method will disconnect it.
|
||||
pub fn remove_reserved_peer(&mut self, peer_id: PeerId) {
|
||||
self.swarm.remove_reserved_peer(peer_id);
|
||||
}
|
||||
|
||||
/// Start accepting all peers again if we weren't.
|
||||
#[inline]
|
||||
pub fn accept_unreserved_peers(&mut self) {
|
||||
self.swarm.accept_unreserved_peers();
|
||||
}
|
||||
|
||||
/// Start refusing non-reserved nodes. Disconnects the nodes that we are connected to that
|
||||
/// aren't reserved.
|
||||
pub fn deny_unreserved_peers(&mut self) {
|
||||
self.swarm.deny_unreserved_peers();
|
||||
}
|
||||
|
||||
/// Returns the `PeerId` of a node.
|
||||
#[inline]
|
||||
pub fn peer_id_of_node(&self, node_index: NodeIndex) -> Option<&PeerId> {
|
||||
@@ -327,23 +304,10 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnects a peer and bans it for a little while.
|
||||
///
|
||||
/// Same as `drop_node`, except that the same peer will not be able to reconnect later.
|
||||
#[inline]
|
||||
pub fn ban_node(&mut self, node_index: NodeIndex) {
|
||||
if let Some(info) = self.nodes_info.get(&node_index) {
|
||||
info!(target: "sub-libp2p", "Banned {:?} (#{:?}, {:?}, {:?})", info.peer_id,
|
||||
node_index, info.endpoint, info.client_version);
|
||||
self.swarm.ban_node(info.peer_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnects a peer.
|
||||
///
|
||||
/// This is asynchronous and will not immediately close the peer.
|
||||
/// Corresponding closing events will be generated once the closing actually happens.
|
||||
#[inline]
|
||||
pub fn drop_node(&mut self, node_index: NodeIndex) {
|
||||
if let Some(info) = self.nodes_info.get(&node_index) {
|
||||
debug!(target: "sub-libp2p", "Dropping {:?} on purpose (#{:?}, {:?}, {:?})",
|
||||
@@ -352,6 +316,11 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a hard-coded address for the given peer, that never expires.
|
||||
pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
self.swarm.add_known_address(peer_id, addr)
|
||||
}
|
||||
|
||||
/// Get debug info for a given peer.
|
||||
pub fn peer_debug_info(&self, who: NodeIndex) -> String {
|
||||
if let Some(info) = self.nodes_info.get(&who) {
|
||||
@@ -394,7 +363,6 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
loop {
|
||||
match self.swarm.poll() {
|
||||
Ok(Async::Ready(Some(BehaviourOut::CustomProtocolOpen { peer_id, version, endpoint }))) => {
|
||||
debug!(target: "sub-libp2p", "Opened custom protocol with {:?}", peer_id);
|
||||
let node_index = self.index_of_peer_or_assign(peer_id.clone(), endpoint);
|
||||
break Ok(Async::Ready(Some(ServiceEvent::OpenedCustomProtocol {
|
||||
peer_id,
|
||||
@@ -403,8 +371,7 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
debug_info: self.peer_debug_info(node_index),
|
||||
})))
|
||||
}
|
||||
Ok(Async::Ready(Some(BehaviourOut::CustomProtocolClosed { peer_id, result }))) => {
|
||||
debug!(target: "sub-libp2p", "Custom protocol with {:?} closed: {:?}", peer_id, result);
|
||||
Ok(Async::Ready(Some(BehaviourOut::CustomProtocolClosed { peer_id, .. }))) => {
|
||||
let node_index = *self.index_by_id.get(&peer_id).expect("index_by_id is always kept in sync with the state of the behaviour");
|
||||
break Ok(Async::Ready(Some(ServiceEvent::ClosedCustomProtocol {
|
||||
node_index,
|
||||
@@ -457,40 +424,6 @@ where TMessage: CustomMessage + Send + 'static {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Polls the stream that fires when we need to cleanup and flush the topology.
|
||||
fn poll_cleanup(&mut self) -> Poll<Option<ServiceEvent<TMessage>>, IoError> {
|
||||
loop {
|
||||
match self.cleanup.poll() {
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Ok(Async::Ready(Some(_))) => {
|
||||
debug!(target: "sub-libp2p", "Cleaning and flushing topology");
|
||||
self.swarm.cleanup();
|
||||
if let Err(err) = self.swarm.flush_topology() {
|
||||
warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err);
|
||||
}
|
||||
debug!(target: "sub-libp2p", "Topology now contains {} nodes",
|
||||
self.swarm.num_topology_peers());
|
||||
}
|
||||
Ok(Async::Ready(None)) => {
|
||||
warn!(target: "sub-libp2p", "Topology flush stream ended unexpectedly");
|
||||
return Ok(Async::Ready(None))
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(target: "sub-libp2p", "Topology flush stream errored: {:?}", err);
|
||||
return Err(IoError::new(IoErrorKind::Other, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TMessage> Drop for Service<TMessage> where TMessage: CustomMessage {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = self.swarm.flush_topology() {
|
||||
warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TMessage> Stream for Service<TMessage> where TMessage: CustomMessage + Send + 'static {
|
||||
@@ -507,11 +440,6 @@ impl<TMessage> Stream for Service<TMessage> where TMessage: CustomMessage + Send
|
||||
Async::NotReady => (),
|
||||
}
|
||||
|
||||
match self.poll_cleanup()? {
|
||||
Async::Ready(value) => return Ok(Async::Ready(value)),
|
||||
Async::NotReady => (),
|
||||
}
|
||||
|
||||
// The only way we reach this is if we went through all the `NotReady` paths above,
|
||||
// ensuring the current task is registered everywhere.
|
||||
Ok(Async::NotReady)
|
||||
|
||||
@@ -41,7 +41,7 @@ fn build_nodes<TMsg>(num: usize) -> Vec<substrate_network_libp2p::Service<TMsg>>
|
||||
};
|
||||
|
||||
let proto = substrate_network_libp2p::RegisteredProtocol::new(*b"tst", &[1]);
|
||||
result.push(substrate_network_libp2p::start_service(config, proto).unwrap());
|
||||
result.push(substrate_network_libp2p::start_service(config, proto).unwrap().0);
|
||||
}
|
||||
|
||||
result
|
||||
|
||||
@@ -27,6 +27,7 @@ client = { package = "substrate-client", path = "../../core/client" }
|
||||
runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives" }
|
||||
parity-codec = { version = "3.2", features = ["derive"] }
|
||||
network_libp2p = { package = "substrate-network-libp2p", path = "../../core/network-libp2p" }
|
||||
peerset = { package = "substrate-peerset", path = "../../core/peerset" }
|
||||
tokio = "0.1.11"
|
||||
keyring = { package = "substrate-keyring", path = "../../core/keyring", optional = true }
|
||||
test_client = { package = "substrate-test-client", path = "../../core/test-client", optional = true }
|
||||
|
||||
@@ -24,6 +24,7 @@ use parking_lot::{Mutex, RwLock};
|
||||
use network_libp2p::{ProtocolId, NetworkConfiguration, NodeIndex, Severity};
|
||||
use network_libp2p::{start_service, parse_str_addr, Service as NetworkService, ServiceEvent as NetworkServiceEvent};
|
||||
use network_libp2p::{multiaddr, RegisteredProtocol, NetworkState};
|
||||
use peerset::Peerset;
|
||||
use consensus::import_queue::{ImportQueue, Link};
|
||||
use crate::consensus_gossip::ConsensusGossip;
|
||||
use crate::message::{Message, ConsensusEngineId};
|
||||
@@ -138,6 +139,9 @@ pub struct Service<B: BlockT + 'static, S: NetworkSpecialization<B>> {
|
||||
peers: Arc<RwLock<HashMap<NodeIndex, ConnectedPeer<B>>>>,
|
||||
/// Network service
|
||||
network: Arc<Mutex<NetworkService<Message<B>>>>,
|
||||
/// Peerset manager (PSM); manages the reputation of nodes and indicates the network which
|
||||
/// nodes it should be connected to or not.
|
||||
peerset: Arc<Peerset>,
|
||||
/// Protocol sender
|
||||
protocol_sender: Sender<ProtocolMsg<B, S>>,
|
||||
/// Sender for messages to the background service task, and handle for the background thread.
|
||||
@@ -174,7 +178,7 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>> Service<B, S> {
|
||||
)?;
|
||||
let versions = [(protocol::CURRENT_VERSION as u8)];
|
||||
let registered = RegisteredProtocol::new(protocol_id, &versions[..]);
|
||||
let (thread, network) = start_thread(
|
||||
let (thread, network, peerset) = start_thread(
|
||||
network_to_protocol_sender,
|
||||
network_port,
|
||||
params.network_config,
|
||||
@@ -186,6 +190,7 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>> Service<B, S> {
|
||||
is_offline,
|
||||
is_major_syncing,
|
||||
peers,
|
||||
peerset,
|
||||
network,
|
||||
protocol_sender: protocol_sender.clone(),
|
||||
bg_thread: Some(thread),
|
||||
@@ -343,20 +348,21 @@ pub trait ManageNetwork {
|
||||
|
||||
impl<B: BlockT + 'static, S: NetworkSpecialization<B>> ManageNetwork for Service<B, S> {
|
||||
fn accept_unreserved_peers(&self) {
|
||||
self.network.lock().accept_unreserved_peers();
|
||||
self.peerset.set_reserved_only(false);
|
||||
}
|
||||
|
||||
fn deny_unreserved_peers(&self) {
|
||||
self.network.lock().deny_unreserved_peers();
|
||||
self.peerset.set_reserved_only(true);
|
||||
}
|
||||
|
||||
fn remove_reserved_peer(&self, peer: PeerId) {
|
||||
self.network.lock().remove_reserved_peer(peer);
|
||||
self.peerset.remove_reserved_peer(&peer);
|
||||
}
|
||||
|
||||
fn add_reserved_peer(&self, peer: String) -> Result<(), String> {
|
||||
let (addr, peer_id) = parse_str_addr(&peer).map_err(|e| format!("{:?}", e))?;
|
||||
self.network.lock().add_reserved_peer(addr, peer_id);
|
||||
let (peer_id, addr) = parse_str_addr(&peer).map_err(|e| format!("{:?}", e))?;
|
||||
self.peerset.add_reserved_peer(peer_id.clone());
|
||||
self.network.lock().add_known_address(peer_id, addr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -466,10 +472,10 @@ fn start_thread<B: BlockT + 'static>(
|
||||
network_port: NetworkPort<B>,
|
||||
config: NetworkConfiguration,
|
||||
registered: RegisteredProtocol<Message<B>>,
|
||||
) -> Result<((oneshot::Sender<()>, thread::JoinHandle<()>), Arc<Mutex<NetworkService<Message<B>>>>), Error> {
|
||||
) -> Result<((oneshot::Sender<()>, thread::JoinHandle<()>), Arc<Mutex<NetworkService<Message<B>>>>, Arc<Peerset>), Error> {
|
||||
// Start the main service.
|
||||
let service = match start_service(config, registered) {
|
||||
Ok(service) => Arc::new(Mutex::new(service)),
|
||||
let (service, peerset) = match start_service(config, registered) {
|
||||
Ok((service, peerset)) => (Arc::new(Mutex::new(service)), peerset),
|
||||
Err(err) => {
|
||||
warn!("Error starting network: {}", err);
|
||||
return Err(err.into())
|
||||
@@ -493,7 +499,7 @@ fn start_thread<B: BlockT + 'static>(
|
||||
};
|
||||
})?;
|
||||
|
||||
Ok(((close_tx, thread), service))
|
||||
Ok(((close_tx, thread), service, peerset))
|
||||
}
|
||||
|
||||
/// Runs the background thread that handles the networking.
|
||||
@@ -530,7 +536,9 @@ fn run_thread<B: BlockT + 'static>(
|
||||
match severity {
|
||||
Severity::Bad(message) => {
|
||||
info!(target: "sync", "Banning {:?} because {:?}", who, message);
|
||||
network_service_2.lock().ban_node(who)
|
||||
warn!(target: "sync", "Banning a node is a deprecated mechanism that \
|
||||
should be removed");
|
||||
network_service_2.lock().drop_node(who)
|
||||
},
|
||||
Severity::Useless(message) => {
|
||||
info!(target: "sync", "Dropping {:?} because {:?}", who, message);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
description = "Connectivity manager based on reputation"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "substrate-peerset"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
fnv = "1.0"
|
||||
futures = "0.1"
|
||||
libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "substrate-tmp-2019-03-20", default-features = false }
|
||||
log = "0.4"
|
||||
parking_lot = "0.7"
|
||||
rand = "0.6"
|
||||
serde = "1.0.70"
|
||||
serde_derive = "1.0.70"
|
||||
serde_json = "1.0.24"
|
||||
tokio-io = "0.1"
|
||||
@@ -0,0 +1,297 @@
|
||||
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Peer Set Manager (PSM). Contains the strategy for choosing which nodes the network should be
|
||||
//! connected to.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use futures::{prelude::*, sync::mpsc};
|
||||
use libp2p::PeerId;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Shared part of the peer set manager (PSM). Distributed around the code.
|
||||
pub struct Peerset {
|
||||
tx: mpsc::UnboundedSender<Message>,
|
||||
inner: Mutex<Inner>,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
/// List of nodes that we know exist but we are not connected to.
|
||||
discovered: Vec<PeerId>,
|
||||
/// List of reserved nodes.
|
||||
reserved: HashSet<PeerId>,
|
||||
/// If true, we only accept reserved nodes.
|
||||
reserved_only: bool,
|
||||
/// Node slots. Each slot contains either `None` if the node is free, or `Some` if it is
|
||||
/// assigned to a peer.
|
||||
slots: Vec<Option<PeerId>>,
|
||||
}
|
||||
|
||||
/// Message that can be sent by the peer set manager (PSM).
|
||||
#[derive(Debug)]
|
||||
pub enum Message {
|
||||
/// Request to open a connection to the given peer. From the point of view of the PSM, we are
|
||||
/// immediately connected.
|
||||
Connect(PeerId),
|
||||
|
||||
/// Drop the connection to the given peer, or cancel the connection attempt after a `Connect`.
|
||||
Drop(PeerId),
|
||||
|
||||
/// Equivalent to `Connect` for the peer corresponding to this incoming index.
|
||||
Accept(IncomingIndex),
|
||||
|
||||
/// Equivalent to `Drop` for the peer corresponding to this incoming index.
|
||||
Reject(IncomingIndex),
|
||||
}
|
||||
|
||||
/// Opaque identifier for an incoming connection. Allocated by the network.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct IncomingIndex(pub u64);
|
||||
|
||||
impl From<u64> for IncomingIndex {
|
||||
fn from(val: u64) -> IncomingIndex {
|
||||
IncomingIndex(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration to pass when creating the peer set manager.
|
||||
#[derive(Debug)]
|
||||
pub struct PeersetConfig {
|
||||
/// Maximum number of ingoing links to peers.
|
||||
pub in_peers: u32,
|
||||
|
||||
/// Maximum number of outgoing links to peers.
|
||||
pub out_peers: u32,
|
||||
|
||||
/// List of bootstrap nodes to initialize the peer with.
|
||||
///
|
||||
/// > **Note**: Keep in mind that the networking has to know an address for these nodes,
|
||||
/// > otherwise it will not be able to connect to them.
|
||||
pub bootnodes: Vec<PeerId>,
|
||||
|
||||
/// If true, we only accept reserved nodes.
|
||||
pub reserved_only: bool,
|
||||
|
||||
/// List of nodes that we should always be connected to.
|
||||
///
|
||||
/// > **Note**: Keep in mind that the networking has to know an address for these nodes,
|
||||
/// > otherwise it will not be able to connect to them.
|
||||
pub reserved_nodes: Vec<PeerId>,
|
||||
}
|
||||
|
||||
/// Side of the peer set manager owned by the network. In other words, the "receiving" side.
|
||||
///
|
||||
/// Implements the `Stream` trait and can be polled for messages. The `Stream` never ends and never
|
||||
/// errors.
|
||||
pub struct PeersetMut {
|
||||
parent: Arc<Peerset>,
|
||||
rx: mpsc::UnboundedReceiver<Message>,
|
||||
}
|
||||
|
||||
impl Peerset {
|
||||
/// Builds a new peerset from the given configuration.
|
||||
pub fn from_config(config: PeersetConfig) -> (Arc<Peerset>, PeersetMut) {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
|
||||
let mut inner = Inner {
|
||||
discovered: config.bootnodes.into_iter().collect(),
|
||||
reserved: Default::default(),
|
||||
reserved_only: config.reserved_only,
|
||||
slots: (0 .. (config.in_peers + config.out_peers)).map(|_| None).collect(),
|
||||
};
|
||||
|
||||
alloc_slots(&mut inner, &tx);
|
||||
|
||||
let peerset = Arc::new(Peerset {
|
||||
tx,
|
||||
inner: Mutex::new(inner),
|
||||
});
|
||||
|
||||
let rx = PeersetMut {
|
||||
parent: peerset.clone(),
|
||||
rx,
|
||||
};
|
||||
|
||||
for reserved in config.reserved_nodes {
|
||||
peerset.add_reserved_peer(reserved);
|
||||
}
|
||||
|
||||
(peerset, rx)
|
||||
}
|
||||
|
||||
/// Adds a new reserved peer. The peerset will make an effort to always remain connected to
|
||||
/// this peer.
|
||||
///
|
||||
/// Has no effect if the node was already a reserved peer.
|
||||
///
|
||||
/// > **Note**: Keep in mind that the networking has to know an address for this node,
|
||||
/// > otherwise it will not be able to connect to it.
|
||||
pub fn add_reserved_peer(&self, peer_id: PeerId) {
|
||||
let mut inner = self.inner.lock();
|
||||
if !inner.reserved.insert(peer_id.clone()) {
|
||||
// Immediately return if this peer was already in the list.
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign a slot for this reserved peer.
|
||||
if let Some(pos) = inner.slots.iter().position(|s| s.as_ref().map(|n| !inner.reserved.contains(n)).unwrap_or(true)) {
|
||||
let _ = self.tx.unbounded_send(Message::Connect(peer_id.clone()));
|
||||
inner.slots[pos] = Some(peer_id);
|
||||
|
||||
} else {
|
||||
// All slots are filled with reserved peers.
|
||||
if inner.discovered.iter().all(|p| *p != peer_id) {
|
||||
inner.discovered.push(peer_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a previously-added reserved peer.
|
||||
///
|
||||
/// Has no effect if the node was not a reserved peer.
|
||||
pub fn remove_reserved_peer(&self, peer_id: &PeerId) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.reserved.remove(peer_id);
|
||||
}
|
||||
|
||||
/// Sets whether or not the peerset only has connections .
|
||||
pub fn set_reserved_only(&self, reserved_only: bool) {
|
||||
let mut inner = self.inner.lock();
|
||||
let inner = &mut *inner; // Fixes a borrowing issue.
|
||||
inner.reserved_only = reserved_only;
|
||||
|
||||
// Disconnect non-reserved nodes.
|
||||
if reserved_only {
|
||||
for slot in &mut inner.slots {
|
||||
if let Some(peer) = slot.as_ref() {
|
||||
if inner.reserved.contains(peer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let _ = self.tx.unbounded_send(Message::Drop(peer.clone()));
|
||||
}
|
||||
|
||||
*slot = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports an adjustement to the reputation of the given peer.
|
||||
pub fn report_peer(&self, _peer_id: &PeerId, _score_diff: i32) {
|
||||
// This is not implemented in this dummy implementation.
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_slots(inner: &mut Inner, tx: &mpsc::UnboundedSender<Message>) {
|
||||
if inner.reserved_only {
|
||||
return;
|
||||
}
|
||||
|
||||
for slot in inner.slots.iter_mut() {
|
||||
if slot.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !inner.discovered.is_empty() {
|
||||
let elem = inner.discovered.remove(0);
|
||||
*slot = Some(elem.clone());
|
||||
let _ = tx.unbounded_send(Message::Connect(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PeersetMut {
|
||||
/// Indicate that we received an incoming connection. Must be answered either with
|
||||
/// a corresponding `Accept` or `Reject`, except if we were already connected to this peer.
|
||||
///
|
||||
/// Note that this mechanism is orthogonal to `Connect`/`Drop`. Accepting an incoming
|
||||
/// connection implicitely means `Accept`, but incoming connections aren't cancelled by
|
||||
/// `dropped`.
|
||||
///
|
||||
/// Because of concurrency issues, it is acceptable to call `incoming` with a `PeerId` the
|
||||
/// peerset is already connected to, in which case it must not answer.
|
||||
pub fn incoming(&self, peer_id: PeerId, index: IncomingIndex) {
|
||||
let mut inner = self.parent.inner.lock();
|
||||
if inner.slots.iter().any(|s| s.as_ref() == Some(&peer_id)) {
|
||||
return
|
||||
}
|
||||
|
||||
if let Some(pos) = inner.slots.iter().position(|s| s.is_none()) {
|
||||
inner.slots[pos] = Some(peer_id);
|
||||
let _ = self.parent.tx.unbounded_send(Message::Accept(index));
|
||||
} else {
|
||||
if inner.discovered.iter().all(|p| *p != peer_id) {
|
||||
inner.discovered.push(peer_id);
|
||||
}
|
||||
let _ = self.parent.tx.unbounded_send(Message::Reject(index));
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicate that we dropped an active connection with a peer, or that we failed to connect.
|
||||
///
|
||||
/// Must only be called after the PSM has either generated a `Connect` message with this
|
||||
/// `PeerId`, or accepted an incoming connection with this `PeerId`.
|
||||
pub fn dropped(&self, peer_id: &PeerId) {
|
||||
let mut inner = self.parent.inner.lock();
|
||||
|
||||
// Automatically connect back if reserved.
|
||||
if inner.reserved.contains(peer_id) {
|
||||
let _ = self.parent.tx.unbounded_send(Message::Connect(peer_id.clone()));
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, free the slot.
|
||||
for slot in inner.slots.iter_mut() {
|
||||
if slot.as_ref() == Some(peer_id) {
|
||||
*slot = None;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: in this dummy implementation we consider that peers never expire. As soon as we
|
||||
// are disconnected from a peer, we try again.
|
||||
if inner.discovered.iter().all(|p| p != peer_id) {
|
||||
inner.discovered.push(peer_id.clone());
|
||||
}
|
||||
alloc_slots(&mut inner, &self.parent.tx);
|
||||
}
|
||||
|
||||
/// Adds a discovered peer id to the PSM.
|
||||
///
|
||||
/// > **Note**: There is no equivalent "expired" message, meaning that it is the responsibility
|
||||
/// > of the PSM to remove `PeerId`s that fail to dial too often.
|
||||
pub fn discovered(&self, peer_id: PeerId) {
|
||||
let mut inner = self.parent.inner.lock();
|
||||
|
||||
if inner.slots.iter().any(|p| p.as_ref() == Some(&peer_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if inner.discovered.iter().all(|p| *p != peer_id) {
|
||||
inner.discovered.push(peer_id);
|
||||
}
|
||||
alloc_slots(&mut inner, &self.parent.tx);
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for PeersetMut {
|
||||
type Item = Message;
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
self.rx.poll()
|
||||
}
|
||||
}
|
||||
@@ -50,9 +50,6 @@ impl network::SyncProvider<Block> for Status {
|
||||
network::NetworkState {
|
||||
peer_id: String::new(),
|
||||
listened_addresses: Default::default(),
|
||||
is_reserved_only: false,
|
||||
reserved_peers: Default::default(),
|
||||
banned_peers: Default::default(),
|
||||
connected_peers: Default::default(),
|
||||
not_connected_peers: Default::default(),
|
||||
average_download_per_sec: 0,
|
||||
@@ -207,9 +204,6 @@ fn system_network_state() {
|
||||
network::NetworkState {
|
||||
peer_id: String::new(),
|
||||
listened_addresses: Default::default(),
|
||||
is_reserved_only: false,
|
||||
reserved_peers: Default::default(),
|
||||
banned_peers: Default::default(),
|
||||
connected_peers: Default::default(),
|
||||
not_connected_peers: Default::default(),
|
||||
average_download_per_sec: 0,
|
||||
|
||||
Reference in New Issue
Block a user