diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 447aeca08f..4ec456004e 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1,11 +1,3 @@ -[[package]] -name = "MacTypes-sys" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "aes-ctr" version = "0.1.0" @@ -48,7 +40,7 @@ dependencies = [ [[package]] name = "aio-limited" version = "0.1.0" -source = "git+https://github.com/paritytech/aio-limited.git#f01b01501c87c93d3005f9120cc35d0e576fa7a3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -155,24 +147,6 @@ name = "base58" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "base64" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bigint" version = "4.4.1" @@ -202,11 +176,6 @@ dependencies = [ "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bitflags" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "1.0.4" @@ -214,12 +183,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -240,6 +210,17 @@ dependencies = [ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-buffer" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "block-cipher-trait" version = "0.5.3" @@ -248,6 +229,14 @@ dependencies = [ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-padding" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bs58" version = "0.2.2" @@ -258,11 +247,21 @@ name = "byte-tools" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byte-tools" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.7" @@ -303,15 +302,6 @@ name = "cfg-if" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "chashmap" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "chrono" version = "0.4.6" @@ -376,23 +366,6 @@ name = "constant_time_eq" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "core-foundation" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "criterion" version = "0.1.2" @@ -533,7 +506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crypto-mac" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -542,11 +515,11 @@ dependencies = [ [[package]] name = "crypto-mac" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -567,6 +540,15 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cuckoofilter" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "curve25519-dalek" version = "0.20.0" @@ -585,19 +567,6 @@ name = "data-encoding" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "datastore" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -dependencies = [ - "base64 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chashmap 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "difference" version = "1.0.0" @@ -616,11 +585,28 @@ dependencies = [ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "digest" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "discard" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "dns-parser" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ed25519-dalek" version = "0.8.1" @@ -693,17 +679,6 @@ dependencies = [ "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "eth-secp256k1" -version = "0.5.7" -source = "git+https://github.com/paritytech/rust-secp256k1#ccc06e7480148b723eb44ac56cf4d20eec380b6f" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "etrace" version = "1.1.1" @@ -847,6 +822,14 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "generic-array" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "getset" version = "0.0.6" @@ -974,24 +957,6 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hyper" -version = "0.10.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hyper" version = "0.12.19" @@ -1226,11 +1191,6 @@ dependencies = [ "rocksdb 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "1.2.0" @@ -1257,30 +1217,29 @@ dependencies = [ [[package]] name = "libp2p" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-dns 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-floodsub 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-identify 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-kad 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-mplex 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-ping 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-ratelimit 0.1.1 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-relay 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-secio 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-tcp-transport 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-transport-timeout 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-uds 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-websocket 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-yamux 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-dns 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-floodsub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-identify 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-kad 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-mdns 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-mplex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ping 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-plaintext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ratelimit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-secio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-tcp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-uds 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-yamux 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (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)", @@ -1288,21 +1247,21 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", "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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multistream-select 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "multistream-select 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "rw-stream-sink 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (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)", @@ -1310,34 +1269,41 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "libp2p-core-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libp2p-dns" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "tokio-dns-unofficial 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", ] [[package]] name = "libp2p-floodsub" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (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.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1346,18 +1312,18 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.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-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1367,77 +1333,81 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", "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)", - "datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", "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.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-identify 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-ping 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-identify 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ping 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.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-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-mdns" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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.2.0 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-mplex" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (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)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "libp2p-peerstore" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -dependencies = [ - "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "libp2p-ping" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "multistream-select 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.1.0 (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.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.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-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1445,55 +1415,47 @@ dependencies = [ ] [[package]] -name = "libp2p-ratelimit" -version = "0.1.1" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +name = "libp2p-plaintext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aio-limited 0.1.0 (git+https://github.com/paritytech/aio-limited.git)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-ratelimit" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", ] -[[package]] -name = "libp2p-relay" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -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)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "protobuf 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "libp2p-secio" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aes-ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "asn1_der 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "ctr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ed25519-dalek 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "rw-stream-sink 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1502,69 +1464,41 @@ dependencies = [ ] [[package]] -name = "libp2p-tcp-transport" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +name = "libp2p-tcp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", ] -[[package]] -name = "libp2p-transport-timeout" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "libp2p-uds" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "libp2p-websocket" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "rw-stream-sink 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "stdweb 0.1.3 (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.21.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "libp2p-yamux" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", - "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (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.6 (git+https://github.com/paritytech/yamux)", + "yamux 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1679,14 +1613,6 @@ name = "memory_units" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mio" version = "0.6.16" @@ -1737,36 +1663,10 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "multiaddr" -version = "0.3.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -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 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "multihash" -version = "0.8.1-pre" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" -dependencies = [ - "blake2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "multistream-select" -version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", @@ -1785,23 +1685,6 @@ dependencies = [ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "native-tls" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "net2" version = "0.2.33" @@ -2010,6 +1893,11 @@ name = "opaque-debug" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "opaque-debug" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "openssl" version = "0.10.16" @@ -2023,11 +1911,6 @@ dependencies = [ "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "openssl-probe" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "openssl-sys" version = "0.9.40" @@ -2039,11 +1922,6 @@ dependencies = [ "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "owning_ref" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "owning_ref" version = "0.3.3" @@ -2095,6 +1973,33 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-multiaddr" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 0.4.2 (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)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-multihash" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-wasm" version = "0.31.3" @@ -2103,16 +2008,6 @@ dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parking_lot" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot" version = "0.4.8" @@ -2572,7 +2467,7 @@ dependencies = [ [[package]] name = "rw-stream-sink" version = "0.1.0" -source = "git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec#997d0163bc8a7e11559524ad8466bc3b1850c8ec" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", @@ -2592,54 +2487,19 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safemem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "schannel" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scoped-tls" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "security-framework" -version = "0.2.1" +name = "secp256k1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "security-framework-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "MacTypes-sys 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2680,11 +2540,6 @@ dependencies = [ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "sha1" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "sha1" version = "0.6.0" @@ -2701,6 +2556,17 @@ dependencies = [ "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "shell32-sys" version = "0.1.2" @@ -3226,11 +3092,6 @@ name = "static_assertions" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "stdweb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "stdweb" version = "0.4.12" @@ -3636,7 +3497,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)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)", + "libp2p 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3644,10 +3505,12 @@ dependencies = [ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3986,19 +3849,6 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tempfile" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term" version = "0.4.6" @@ -4034,16 +3884,6 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread-id" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread-scoped" version = "1.0.2" @@ -4118,24 +3958,6 @@ dependencies = [ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-core" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -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)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.14 (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)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-current-thread" version = "0.1.4" @@ -4147,7 +3969,7 @@ dependencies = [ [[package]] name = "tokio-dns-unofficial" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4241,16 +4063,6 @@ dependencies = [ "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-tls" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.2 (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 = "tokio-udp" version = "0.1.3" @@ -4282,11 +4094,6 @@ dependencies = [ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "trie-bench" version = "0.9.0" @@ -4354,11 +4161,6 @@ dependencies = [ "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "typenum" version = "1.10.0" @@ -4380,14 +4182,6 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicase" version = "2.2.0" @@ -4432,14 +4226,6 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unsigned-varint" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unsigned-varint" version = "0.2.1" @@ -4541,27 +4327,6 @@ dependencies = [ "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "websocket" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (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)", - "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "which" version = "1.0.5" @@ -4673,7 +4438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "yamux" version = "0.1.6" -source = "git+https://github.com/paritytech/yamux#957bccae409e827db4be05abb67d1d6246d5f5c8" +source = "registry+https://github.com/rust-lang/crates.io-index" 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)", @@ -4687,12 +4452,11 @@ dependencies = [ ] [metadata] -"checksum MacTypes-sys 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7dbbe033994ae2198a18517c7132d952a29fb1db44249a1234779da7c50f4698" "checksum aes-ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f65958ff3692041c36fc009261ccd63f24cd8e0dc1164266f068c2387e8b4e4f" "checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" "checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" -"checksum aio-limited 0.1.0 (git+https://github.com/paritytech/aio-limited.git)" = "" +"checksum aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f10b352bc3fc08ae24dc5d2d3ddcac153678533986122dc283d747b12071000" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" @@ -4706,26 +4470,26 @@ dependencies = [ "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base-x 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d55aa264e822dbafa12db4d54767aff17c6ba55ea2d8559b3e17392c7d000e5d" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" -"checksum base64 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5032d51da2741729bfdaeb2664d9b8c6d9fd1e2b90715c660b6def36628499c2" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" "checksum bindgen 0.43.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d52d263eacd15d26cbcf215d254b410bd58212aaa2d3c453a04b2d3b3adcf41" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum blake2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73b77e29dbd0115e43938be2d5128ecf81c0353e00acaa65339a1242586951d9" +"checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" "checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" +"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" "checksum bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de79cfb98e7aa9988188784d8664b4b5dad6eaaa0863b91d9a4ed871d4f7a42" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" +"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "011941fb53da1a8ac3e4132a1becc367c44fe13f630769f3143d8c66c91c6cb6" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc0086be9ca82f7fc89fc873435531cb898b86e850005850de1f820e2db6e9b" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" -"checksum chashmap 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47e651a8c1eb0cbbaa730f705e2531e75276c6f2bbe2eb12662cfd305213dff8" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" @@ -4733,8 +4497,6 @@ dependencies = [ "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" -"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" "checksum criterion 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f58b0200bf321214bdda8c797cf0071bcc638171c40ec198c3f652a4edaacde3" "checksum criterion-plot 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "885431f7865f9d4956b466126674e5ea40a0f193d42157e56630c356c5501957" "checksum criterion-stats 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c71521cb4c7b7eac76b540e75447fb0172c4234d6333729001b886aaa21d6da4" @@ -4748,17 +4510,19 @@ dependencies = [ "checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" -"checksum crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958" "checksum crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7afa06d05a046c7a47c3a849907ec303504608c927f4e85f7bfff22b7180d971" +"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum ctr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4b669fcb8e20124db86dbd9b01e74ec0e9e420e65381311ce5249864fc7ff0c0" "checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e" +"checksum cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" "checksum curve25519-dalek 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eacf6ff1b911e3170a8c400b402e10c86dc3cb166bd69034ebbc2b785fea4c2" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" -"checksum datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" "checksum ed25519-dalek 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd66d8a16ef71c23cf5eeb2140d8d3cd293457c6c7fd6804b593397a933fcf1e" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" @@ -4767,7 +4531,6 @@ dependencies = [ "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" "checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" -"checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" "checksum etrace 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f17311e68ea07046ee809b8513f6c259518bc10173681d98c21f8c3926f56f40" "checksum exit-future 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "87559b08e99a81a92bbb867d237543e43495857749f688e0773390a20d56c61c" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" @@ -4785,6 +4548,7 @@ dependencies = [ "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54c7f36a235738bb25904d6a2b3dbb28f6f5736cd3918c4bf80d6bb236200782" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" @@ -4801,7 +4565,6 @@ dependencies = [ "checksum http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "02096a6d2c55e63f7fcb800690e4f889a25f6ec342e3adb4594e293b625215ab" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c" "checksum hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f1ebec079129e43af5e234ef36ee3d7e6085687d145b7ea653b262d16c6b65f1" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum impl-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c88568d828291c50eed30cd7fb9f8e688ad0013620186fa3e777b9f206c79f2" @@ -4825,28 +4588,26 @@ dependencies = [ "checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum kvdb-rocksdb 0.1.4 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" -"checksum libp2p 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-dns 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-floodsub 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-identify 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-kad 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-mplex 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-ping 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-ratelimit 0.1.1 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-relay 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-secio 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-tcp-transport 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-transport-timeout 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-uds 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-websocket 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum libp2p-yamux 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" +"checksum libp2p 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a92f6f1c0bd32ac7bb23c33af667149df5518e38f9ad2f517df71e52f1f0bbc" +"checksum libp2p-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bdcd726ea75447b332288169581c921e49e893e34ca9925d49fd28dda16afe3" +"checksum libp2p-core-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e52a2262f187aa45d07054bc80e39f0da582eb0288ca5f2dc0074b372e4b7eaa" +"checksum libp2p-dns 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f7ad92f9711efece48bb7ce30e3f1e662cd3524dc5d9f96b8f68b6e4e7cde96" +"checksum libp2p-floodsub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4feda0ff3afcf84dfee9ea088835293829d199a34491d7f0990a4ccfd627816c" +"checksum libp2p-identify 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "548f9180101bd5846f4f60e060a00032ba3671a77fc735c48a85b7d1016d28ef" +"checksum libp2p-kad 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06312d4a1655d2d531b2f9293039a66d6e89854e11ef3eac6d2f9137cae99f0" +"checksum libp2p-mdns 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1bbcb82063545605abf697967d919d418b1725f7d3688973fa26c98f81e8cda8" +"checksum libp2p-mplex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9406ea58ce4fef47820f7d2d6aa62b7e42b4972c30cc87de577d4da40852d4b1" +"checksum libp2p-ping 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1ca7b60c2edb0cae7f9db56fbe6c21ca6960e96ec92cd1ed265ac06db24a1fe" +"checksum libp2p-plaintext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bdbdd4700d5edea10214e4733ab5ac5be87862bac8a9b259c987bc9c15004" +"checksum libp2p-ratelimit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3001ea6afed5ccd1e5934715aa388b60b23e7587117db36b89d697e8ea43ff3" +"checksum libp2p-secio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a066857eeadf4e632d0c2aedab66022bee02daf21bb60b4ce45977082c8196a" +"checksum libp2p-tcp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fcb2bcb9402f5fe42441dd4558306ff83a28624f67c6066bdbaa98928c180e3" +"checksum libp2p-uds 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3e88ac8f419f8d9487aaee9ef8785f592b37d78067c6764fe0adc1874a72c6c" +"checksum libp2p-yamux 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71b4fd69a1c038152d017366d759177e2580fb4fbb56ce65429a642e011a07b1" "checksum librocksdb-sys 5.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9024327233e7fac7982440f73301c00046d438c5b1011e8f4e394226ce19007" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" @@ -4862,16 +4623,12 @@ dependencies = [ "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory-db 0.9.0 (git+https://github.com/paritytech/trie)" = "" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "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 multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" -"checksum multistream-select 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" +"checksum multistream-select 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "886fe7ba983a194afdd9074323171c8e313b2c145561da69464d5443f1a3d121" "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" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" @@ -4885,18 +4642,18 @@ dependencies = [ "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce3535d54560c937c1652ba4a0da66bfc63e0f8e07bed127483afb6e5ee925" "checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" +"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682" "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" -"checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dca389ea5e1632c89b2ce54f7e2b4a8a8c9d278042222a91e0bf95451218cb4c" "checksum parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa42c2cb493b60b12c75b26e8c94cb734af4df4d7f2cc229dc04c1953dac189" "checksum parity-crypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8adf489acb31f1922db0ce43803b6f48a425241a8473611be3cc625a8e4a4c47" +"checksum parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a8e5d637787fe097ec1bfca2aa3eb687396518003df991c6c7216d86682d5ff" +"checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076" "checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" -"checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" @@ -4950,24 +4707,19 @@ dependencies = [ "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.0 (git+https://github.com/tomaka/libp2p-rs?rev=997d0163bc8a7e11559524ad8466bc3b1850c8ec)" = "" +"checksum rw-stream-sink 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "108ad7c3d65ba866ec50a224b7b3b0cb6c682c3d805015cea859d491232346a5" "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.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" -"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" -"checksum security-framework-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "40d95f3d7da09612affe897f320d78264f0d2320f3e8eea27d12bd1bd94445e2" +"checksum secp256k1 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4070f3906e65249228094cf97b04a90799fba04468190bbbcfa812309cf86e32" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" "checksum serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d6115a3ca25c224e409185325afc16a0d5aaaabc15c42b09587d6f1ba39a5b" "checksum serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "bdf540260cfee6da923831f4776ddc495ada940c30117977c70f1313a6130545" -"checksum sha1 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171698ce4ec7cbb93babeb3190021b4d72e96ccb98e33d277ae4ea959d6f2d9e" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum simplelog 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "24b615b1a3cc51ffa565d9a1d0cfcc49fe7d64737ada84eca284cddb0292d125" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" @@ -4978,7 +4730,6 @@ dependencies = [ "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" "checksum stdweb 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b84f9c829ef7d2e6abf1965393b231c0fd495f0293d612f32dbadd637e91fd0d" "checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930" "checksum stdweb-internal-macros 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d60e306bddd5d213f86f7b417b6cdcefbf742917414ac9dda6e9750ef4553dce" @@ -4998,12 +4749,10 @@ dependencies = [ "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" -"checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c" @@ -5011,9 +4760,8 @@ dependencies = [ "checksum tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b" "checksum tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4790d0be6f4ba6ae4f48190efa2ed7780c9e3567796abdb285003cf39840d9c5" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" -"checksum tokio-dns-unofficial 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb9bf62ca2c53bf2f2faec3e48a98b6d8c9577c27011cb0203a4beacdc8ab328" +"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" "checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" "checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" "checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" @@ -5021,10 +4769,8 @@ dependencies = [ "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" "checksum tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17465013014410310f9f61fa10bf4724803c149ea1d51efece131c38efca93aa" "checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" -"checksum tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum trie-bench 0.9.0 (git+https://github.com/paritytech/trie)" = "" "checksum trie-db 0.9.0 (git+https://github.com/paritytech/trie)" = "" "checksum trie-root 0.9.0 (git+https://github.com/paritytech/trie)" = "" @@ -5032,11 +4778,9 @@ dependencies = [ "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum twofish 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1eef327f05b0d0ec1b9d7d119d8f4d9f602ceee37e0540aff8071e8e66c2e22e" "checksum twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "555cd4909480122bbbf21e34faac4cb08a171f324775670447ed116726c474af" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "082df6964410f6aa929a61ddfafc997e4f32c62c22490e439ac351cec827f436" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" @@ -5044,7 +4788,6 @@ dependencies = [ "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum unsigned-varint 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c1441164e5da61f00acd15f5a9e61939693c2c6e8b9fae36a220b82de7e212" "checksum unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8abc4b7d8158bdfbbaaccc35331ed3c30c2673e99000d7ae665a2eb6576f4" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" @@ -5058,7 +4801,6 @@ dependencies = [ "checksum wabt-sys 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "462336bb61096e64761730e0dea1bc8b777bd4e3689c7e813c81f1cfdf4e8a51" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d" -"checksum websocket 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c9faed2bff8af2ea6b9f8b917d3d00b467583f6781fe3def174a9e33c879703" "checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" @@ -5072,4 +4814,4 @@ dependencies = [ "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" -"checksum yamux 0.1.6 (git+https://github.com/paritytech/yamux)" = "" +"checksum yamux 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e25561b512df3c287cf52404cab0b07ea43d095cb96230e9e2cb635db72d75f0" diff --git a/substrate/core/network-libp2p/Cargo.toml b/substrate/core/network-libp2p/Cargo.toml index 7c7271e396..4fee117b4e 100644 --- a/substrate/core/network-libp2p/Cargo.toml +++ b/substrate/core/network-libp2p/Cargo.toml @@ -11,7 +11,7 @@ bytes = "0.4" error-chain = { version = "0.12", default-features = false } fnv = "1.0" futures = "0.1" -libp2p = { git = "https://github.com/tomaka/libp2p-rs", rev = "997d0163bc8a7e11559524ad8466bc3b1850c8ec", default-features = false, features = ["secio-rsa", "secio-secp256k1"] } +libp2p = { version = "0.2", default-features = false, features = ["secio-rsa", "secio-secp256k1"] } parking_lot = "0.7.1" libc = "0.2" log = "0.4" @@ -19,10 +19,12 @@ rand = "0.5.0" serde = "1.0.70" serde_derive = "1.0.70" serde_json = "1.0.24" +smallvec = "0.6" tokio = "0.1" tokio-io = "0.1" tokio-timer = "0.2" unsigned-varint = { version = "0.2.1", features = ["codec"] } +void = "1.0" [dev-dependencies] assert_matches = "1.2" diff --git a/substrate/core/network-libp2p/src/behaviour.rs b/substrate/core/network-libp2p/src/behaviour.rs new file mode 100644 index 0000000000..ccaab248ff --- /dev/null +++ b/substrate/core/network-libp2p/src/behaviour.rs @@ -0,0 +1,262 @@ +// Copyright 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 . + +use crate::custom_proto::{CustomProtos, CustomProtosOut, RegisteredProtocols}; +use crate::{NetworkConfiguration, ProtocolId}; +use bytes::Bytes; +use futures::prelude::*; +use libp2p::core::{PeerId, ProtocolsHandler}; +use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction}; +use libp2p::core::swarm::{NetworkBehaviourEventProcess, PollParameters}; +use libp2p::identify::{Identify, IdentifyEvent}; +use libp2p::kad::{Kademlia, KademliaOut, KademliaTopology}; +use libp2p::ping::{Ping, PingEvent}; +use std::{cmp, time::Duration, time::Instant}; +use tokio_io::{AsyncRead, AsyncWrite}; +use tokio_timer::Delay; +use void; + +/// General behaviour of the network. +#[derive(NetworkBehaviour)] +#[behaviour(out_event = "CustomProtosOut", poll_method = "poll")] +pub struct Behaviour { + /// Periodically ping nodes, and close the connection if it's unresponsive. + ping: Ping, + /// Custom protocols (dot, bbq, sub, etc.). + custom_protocols: CustomProtos, + /// Discovers nodes of the network. Defined below. + discovery: DiscoveryBehaviour, + /// Periodically identifies the remote and responds to incoming requests. + identify: Identify, + + /// Queue of events to produce for the outside. + #[behaviour(ignore)] + events: Vec, +} + +impl Behaviour { + /// Builds a new `Behaviour`. + // TODO: redundancy between config and local_peer_id (https://github.com/libp2p/rust-libp2p/issues/745) + pub fn new(config: &NetworkConfiguration, local_peer_id: PeerId, protocols: RegisteredProtocols) -> Self { + Behaviour { + ping: Ping::new(), + custom_protocols: CustomProtos::new(config, protocols), + discovery: DiscoveryBehaviour::new(local_peer_id), + identify: Identify::new( + // The agent and protocol versions; maybe we should use something better? + concat!("substrate/", env!("CARGO_PKG_VERSION")).to_owned(), + concat!("substrate/", env!("CARGO_PKG_VERSION")).to_owned() + ), + events: Vec::new(), + } + } + + /// Sends a message to a peer using the given custom protocol. + /// + /// Has no effect if the custom protocol is not open with the given peer. + /// + /// Also note that even we have a valid open substream, it may in fact be already closed + /// without us knowing, in which case the packet will not be received. + #[inline] + pub fn send_custom_message(&mut self, target: &PeerId, protocol_id: ProtocolId, data: impl Into) { + self.custom_protocols.send_packet(target, protocol_id, data) + } + + /// Try to add a reserved peer. + pub fn add_reserved_peer(&mut self, peer_id: PeerId) { + self.custom_protocols.add_reserved_peer(peer_id) + } + + /// 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) + } + + /// 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) + } + + /// Disconnects the custom protocols from a peer. + /// + /// The peer will still be able to use Kademlia or other protocols, but will get disconnected + /// after a few seconds of inactivity. + /// + /// This is asynchronous and does not instantly close the custom protocols. + /// Corresponding closing events will be generated once the closing actually happens. + /// + /// Has no effect if we're not connected to the `PeerId`. + #[inline] + pub fn drop_node(&mut self, peer_id: &PeerId) { + self.custom_protocols.disconnect_peer(peer_id) + } +} + +impl NetworkBehaviourEventProcess for Behaviour { + fn inject_event(&mut self, event: void::Void) { + void::unreachable(event) + } +} + +impl NetworkBehaviourEventProcess for Behaviour { + fn inject_event(&mut self, event: CustomProtosOut) { + self.events.push(event); + } +} + +impl NetworkBehaviourEventProcess for Behaviour { + fn inject_event(&mut self, event: IdentifyEvent) { + match event { + IdentifyEvent::Identified { peer_id, info, .. } => { + trace!(target: "sub-libp2p", "Identified {:?} => {:?}", peer_id, info); + } + IdentifyEvent::Error { .. } => {} + } + } +} + +impl NetworkBehaviourEventProcess for Behaviour { + fn inject_event(&mut self, _: KademliaOut) { + // We only ever use Kademlia for discovering nodes, and nodes discovered by Kademlia are + // automatically added to the topology. Therefore we don't need to do anything. + } +} + +impl NetworkBehaviourEventProcess for Behaviour { + fn inject_event(&mut self, event: PingEvent) { + match event { + PingEvent::PingSuccess { peer, time } => { + trace!(target: "sub-libp2p", "Ping time with {:?}: {:?}", peer, time); + } + } + } +} + +impl Behaviour { + fn poll(&mut self) -> Async> { + if !self.events.is_empty() { + return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))) + } + + Async::NotReady + } +} + +/// Implementation of `NetworkBehaviour` that discovers the nodes on the network. +pub struct DiscoveryBehaviour { + /// Kademlia requests and answers. + kademlia: Kademlia, + /// Stream that fires when we need to perform the next random Kademlia query. + next_kad_random_query: Delay, + /// After `next_kad_random_query` triggers, the next one triggers after this duration. + duration_to_next_kad: Duration, +} + +impl DiscoveryBehaviour { + 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 NetworkBehaviour for DiscoveryBehaviour +where + TSubstream: AsyncRead + AsyncWrite, + TTopology: KademliaTopology, +{ + type ProtocolsHandler = as NetworkBehaviour>::ProtocolsHandler; + type OutEvent = as NetworkBehaviour>::OutEvent; + + fn new_handler(&mut self) -> Self::ProtocolsHandler { + NetworkBehaviour::::new_handler(&mut self.kademlia) + } + + fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { + NetworkBehaviour::::inject_connected(&mut self.kademlia, peer_id, endpoint) + } + + fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { + NetworkBehaviour::::inject_disconnected(&mut self.kademlia, peer_id, endpoint) + } + + fn inject_node_event( + &mut self, + peer_id: PeerId, + event: ::OutEvent, + ) { + NetworkBehaviour::::inject_node_event(&mut self.kademlia, peer_id, event) + } + + fn poll( + &mut self, + params: &mut PollParameters, + ) -> Async< + NetworkBehaviourAction< + ::InEvent, + Self::OutEvent, + >, + > { + // Poll Kademlia. + match self.kademlia.poll(params) { + Async::Ready(action) => return Async::Ready(action), + Async::NotReady => (), + } + + // Poll the stream that fires when we need to start a random Kademlia query. + loop { + match self.next_kad_random_query.poll() { + 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); + self.kademlia.find_node(random_peer_id); + + // Reset the `Delay` to the next random. + self.next_kad_random_query.reset(Instant::now() + self.duration_to_next_kad); + self.duration_to_next_kad = cmp::min(self.duration_to_next_kad * 2, + Duration::from_secs(60)); + }, + Err(err) => { + warn!(target: "sub-libp2p", "Kad query timer errored: {:?}", err); + break + } + } + } + + Async::NotReady + } +} + diff --git a/substrate/core/network-libp2p/src/custom_proto/behaviour.rs b/substrate/core/network-libp2p/src/custom_proto/behaviour.rs new file mode 100644 index 0000000000..521c204ff2 --- /dev/null +++ b/substrate/core/network-libp2p/src/custom_proto/behaviour.rs @@ -0,0 +1,471 @@ +// Copyright 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 . + +use crate::custom_proto::handler::{CustomProtosHandler, CustomProtosHandlerOut, CustomProtosHandlerIn}; +use crate::custom_proto::upgrade::RegisteredProtocols; +use crate::{NetworkConfiguration, NonReservedPeerMode, ProtocolId, topology::NetTopology}; +use bytes::Bytes; +use fnv::{FnvHashMap, FnvHashSet}; +use futures::prelude::*; +use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; +use libp2p::core::{protocols_handler::ProtocolsHandler, PeerId}; +use smallvec::SmallVec; +use std::{io, marker::PhantomData, time::Duration, time::Instant}; +use tokio_io::{AsyncRead, AsyncWrite}; +use tokio_timer::Delay; + +// Duration during which a peer is disabled. +const PEER_DISABLE_DURATION: Duration = Duration::from_secs(5 * 60); + +/// Network behaviour that handles opening substreams for custom protocols with other nodes. +pub struct CustomProtos { + /// List of protocols to open with peers. Never modified. + registered_protocols: RegisteredProtocols, + + /// List of custom protocols that we have open with remotes. + open_protocols: Vec<(PeerId, ProtocolId)>, + + /// List of peer handlers that were enabled, and whether we're dialing or listening. + /// + /// Note that it is possible for a peer to be in the shutdown process, in which case it will + /// not be in this list but will be present in `open_protocols`. + /// It is also possible that we have *just* enabled a peer, in which case it will be in this + /// list but not in `open_protocols`. + enabled_peers: FnvHashMap, + + /// Maximum number of incoming non-reserved connections, taken from the config. Never modified. + max_incoming_connections: usize, + + /// Maximum number of outgoing non-reserved connections, taken from the config. Never modified. + max_outgoing_connections: usize, + + /// If true, only reserved peers can connect. + reserved_only: bool, + + /// List of the IDs of the reserved peers. We always try to maintain a connection these peers. + reserved_peers: FnvHashSet, + + /// List of the IDs of peers that are forbidden, and the moment their ban expires. + banned_peers: Vec<(PeerId, Instant)>, + + /// When this delay expires, we need to synchronize our active connectons with the + /// network topology. + next_connect_to_nodes: Delay, + + /// Events to produce from `poll()`. + events: SmallVec<[NetworkBehaviourAction; 4]>, + + /// Marker to pin the generics. + marker: PhantomData, +} + +/// Event that can be emitted by the `CustomProtos`. +#[derive(Debug)] +pub enum CustomProtosOut { + /// Opened a custom protocol with the remote. + CustomProtocolOpen { + /// Identifier of the protocol. + protocol_id: ProtocolId, + /// Version of the protocol that has been opened. + version: u8, + /// Id of the node we have opened a connection with. + peer_id: PeerId, + /// Endpoint used for this custom protocol. + endpoint: ConnectedPoint, + }, + + /// Closed a custom protocol with the remote. + CustomProtocolClosed { + /// Id of the peer we were connected to. + peer_id: PeerId, + /// Identifier of the protocol. + protocol_id: ProtocolId, + /// Reason why the substream closed. If `Ok`, then it's a graceful exit (EOF). + result: io::Result<()>, + }, + + /// Receives a message on a custom protocol substream. + CustomMessage { + /// Id of the peer the message came from. + peer_id: PeerId, + /// Protocol which generated the message. + protocol_id: ProtocolId, + /// Data that has been received. + data: Bytes, + }, +} + +impl CustomProtos { + /// Creates a `CustomProtos`. + pub fn new(config: &NetworkConfiguration, registered_protocols: RegisteredProtocols) -> Self { + let max_incoming_connections = config.in_peers as usize; + let max_outgoing_connections = config.out_peers as usize; + + // Expected maximum number of connections. + let connec_cap = max_incoming_connections + .saturating_add(max_outgoing_connections) + .saturating_add(4); // We add an arbitrary number for reserved peers slots + + // Expected maximum number of substreams. + let open_protos_cap = connec_cap.saturating_mul(registered_protocols.len()); + + CustomProtos { + registered_protocols, + max_incoming_connections, + max_outgoing_connections, + reserved_only: config.non_reserved_mode == NonReservedPeerMode::Deny, + reserved_peers: Default::default(), + banned_peers: Vec::new(), + open_protocols: Vec::with_capacity(open_protos_cap), + enabled_peers: FnvHashMap::with_capacity_and_hasher(connec_cap, Default::default()), + next_connect_to_nodes: Delay::new(Instant::now()), + events: SmallVec::new(), + marker: PhantomData, + } + } + + /// Adds a reserved peer. + pub fn add_reserved_peer(&mut self, peer_id: PeerId) { + self.reserved_peers.insert(peer_id); + + // Trigger a `connect_to_nodes` round. + self.next_connect_to_nodes = Delay::new(Instant::now()); + } + + /// Removes 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.reserved_peers.remove(&peer_id); + } + + /// Start accepting all peers again if we weren't. + pub fn accept_unreserved_peers(&mut self) { + if !self.reserved_only { + return + } + + self.reserved_only = false; + // Trigger a `connect_to_nodes` round. + self.next_connect_to_nodes = Delay::new(Instant::now()); + } + + /// Start refusing non-reserved nodes. + pub fn deny_unreserved_peers(&mut self) { + if self.reserved_only { + return + } + + self.reserved_only = true; + + // Disconnecting nodes that are connected to us and that aren't reserved + let reserved_peers = &mut self.reserved_peers; + let events = &mut self.events; + self.enabled_peers.retain(move |peer_id, _| { + if reserved_peers.contains(peer_id) { + return true + } + events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer_id.clone(), + event: CustomProtosHandlerIn::Disable, + }); + false + }) + } + + /// Disconnects the given peer if we are connected to it. + pub fn disconnect_peer(&mut self, peer: &PeerId) { + if self.enabled_peers.remove(peer).is_some() { + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer.clone(), + event: CustomProtosHandlerIn::Disable, + }); + } + } + + /// Disconnects the given peer if we are connected to it and disables it for a little while. + pub fn ban_peer(&mut self, peer_id: PeerId) { + // Peer is already banned + if self.banned_peers.iter().any(|(p, _)| p == &peer_id) { + return + } + self.banned_peers.push((peer_id.clone(), Instant::now() + PEER_DISABLE_DURATION)); + if self.enabled_peers.remove(&peer_id).is_some() { + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id, + event: CustomProtosHandlerIn::Disable, + }); + } + } + + /// Sends a message to a peer using the given custom protocol. + /// + /// Has no effect if the custom protocol is not open with the given peer. + /// + /// Also note that even we have a valid open substream, it may in fact be already closed + /// without us knowing, in which case the packet will not be received. + pub fn send_packet(&mut self, target: &PeerId, protocol_id: ProtocolId, data: impl Into) { + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: target.clone(), + event: CustomProtosHandlerIn::SendCustomMessage { + protocol: protocol_id, + data: data.into(), + } + }); + } + + /// Updates the attempted connections to nodes. + /// + /// Also updates `next_connect_to_nodes` with the earliest known moment when we need to + /// update connections again. + fn connect_to_nodes(&mut self, params: &mut PollParameters) { + // Make sure we are connected or connecting to all the reserved nodes. + for reserved in self.reserved_peers.iter() { + // TODO: don't generate an event if we're already in a pending connection (https://github.com/libp2p/rust-libp2p/issues/697) + if !self.enabled_peers.contains_key(&reserved) { + self.events.push(NetworkBehaviourAction::DialPeer { peer_id: reserved.clone() }); + } + } + + // We're done with reserved node; return early if there's nothing more to do. + if self.reserved_only { + return + } + + // Counter of number of connections to open, decreased when we open one. + let mut num_to_open = { + let num_outgoing_connections = self.enabled_peers + .iter() + .filter(|(_, endpoint)| endpoint.is_dialer()) + .filter(|(p, _)| !self.reserved_peers.contains(p)) + .count(); + self.max_outgoing_connections - num_outgoing_connections + }; + + trace!(target: "sub-libp2p", "Connect-to-nodes round; attempting to fill {:?} slots", + num_to_open); + + let local_peer_id = params.local_peer_id().clone(); + let (to_try, will_change) = params.topology().addrs_to_attempt(); + for (peer_id, _) in to_try { + if num_to_open == 0 { + break + } + + if peer_id == &local_peer_id { + continue + } + + if let Some((_, ban_end)) = self.banned_peers.iter().find(|(p, _)| p == peer_id) { + if *ban_end > Instant::now() { + continue + } + } + + num_to_open -= 1; + self.events.push(NetworkBehaviourAction::DialPeer { peer_id: peer_id.clone() }); + } + + // Next round is when we expect the topology will change. + self.next_connect_to_nodes.reset(will_change); + } +} + +impl NetworkBehaviour for CustomProtos +where + TSubstream: AsyncRead + AsyncWrite, +{ + type ProtocolsHandler = CustomProtosHandler; + type OutEvent = CustomProtosOut; + + fn new_handler(&mut self) -> Self::ProtocolsHandler { + CustomProtosHandler::new(self.registered_protocols.clone()) + } + + fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { + // When a peer connects, its handler is initially in the disabled state. We make sure that + // the peer is allowed, and if so we put it in the enabled state. + + let is_reserved = self.reserved_peers.contains(&peer_id); + if self.reserved_only && !is_reserved { + debug!(target: "sub-libp2p", "Ignoring {:?} because we're in reserved mode", peer_id); + return + } + + // Check whether peer is banned. + if !is_reserved { + if let Some((_, expire)) = self.banned_peers.iter().find(|(p, _)| p == &peer_id) { + if *expire >= Instant::now() { + debug!(target: "sub-libp2p", "Ignoring banned peer {:?}", peer_id); + return + } + } + } + + // Check the limits on the ingoing and outgoing connections. + match endpoint { + ConnectedPoint::Dialer { .. } => { + let num_outgoing = self.enabled_peers.iter() + .filter(|(_, e)| e.is_dialer()) + .filter(|(p, _)| !self.reserved_peers.contains(p)) + .count(); + + debug_assert!(num_outgoing <= self.max_outgoing_connections); + if num_outgoing == self.max_outgoing_connections { + return + } + } + ConnectedPoint::Listener { .. } => { + let num_ingoing = self.enabled_peers.iter() + .filter(|(_, e)| e.is_listener()) + .filter(|(p, _)| !self.reserved_peers.contains(p)) + .count(); + + debug_assert!(num_ingoing <= self.max_incoming_connections); + if num_ingoing == self.max_incoming_connections { + debug!(target: "sub-libp2p", "Ignoring incoming connection from {:?} because \ + we're full", peer_id); + return + } + } + } + + // If everything is fine, enable the node. + debug_assert!(!self.enabled_peers.contains_key(&peer_id)); + // We ask the handler to actively open substreams only if we are the dialer; otherwise + // the two nodes will race to be the first to open the unique allowed substream. + if endpoint.is_dialer() { + trace!(target: "sub-libp2p", "Enabling custom protocols with {:?} (active)", peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer_id.clone(), + event: CustomProtosHandlerIn::EnableActive, + }); + } else { + trace!(target: "sub-libp2p", "Enabling custom protocols with {:?} (passive)", peer_id); + self.events.push(NetworkBehaviourAction::SendEvent { + peer_id: peer_id.clone(), + event: CustomProtosHandlerIn::EnablePassive, + }); + } + + self.enabled_peers.insert(peer_id, endpoint); + } + + fn inject_disconnected(&mut self, peer_id: &PeerId, _: ConnectedPoint) { + while let Some(pos) = self.open_protocols.iter().position(|(p, _)| p == peer_id) { + let (_, protocol_id) = self.open_protocols.remove(pos); + + let event = CustomProtosOut::CustomProtocolClosed { + protocol_id, + peer_id: peer_id.clone(), + result: Ok(()), + }; + + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + + // Trigger a `connect_to_nodes` round. + self.next_connect_to_nodes = Delay::new(Instant::now()); + } + + self.enabled_peers.remove(peer_id); + } + + fn inject_node_event( + &mut self, + source: PeerId, + event: ::OutEvent, + ) { + match event { + CustomProtosHandlerOut::CustomProtocolClosed { protocol_id, result } => { + let pos = self.open_protocols.iter().position(|(s, p)| + s == &source && p == &protocol_id + ); + + if let Some(pos) = pos { + self.open_protocols.remove(pos); + } else { + debug_assert!(false, "Couldn't find protocol in open_protocols"); + } + + let event = CustomProtosOut::CustomProtocolClosed { + protocol_id, + result, + peer_id: source, + }; + + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + } + CustomProtosHandlerOut::CustomProtocolOpen { protocol_id, version } => { + debug_assert!(!self.open_protocols.iter().any(|(s, p)| + s == &source && p == &protocol_id + )); + self.open_protocols.push((source.clone(), protocol_id)); + + if let Some(address) = self.enabled_peers.get(&source) { + let event = CustomProtosOut::CustomProtocolOpen { + protocol_id, + version, + peer_id: source, + endpoint: address.clone() + }; + + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + } + } + CustomProtosHandlerOut::CustomMessage { protocol_id, data } => { + let event = CustomProtosOut::CustomMessage { + peer_id: source, + protocol_id, + data, + }; + + self.events.push(NetworkBehaviourAction::GenerateEvent(event)); + } + } + } + + fn poll( + &mut self, + params: &mut PollParameters, + ) -> Async< + NetworkBehaviourAction< + ::InEvent, + Self::OutEvent, + >, + > { + loop { + match self.next_connect_to_nodes.poll() { + Ok(Async::Ready(())) => self.connect_to_nodes(params), + Ok(Async::NotReady) => break, + Err(err) => { + warn!(target: "sub-libp2p", "Connect-to-nodes timer errored: {:?}", err); + break + } + } + } + + // Clean up `banned_peers` + self.banned_peers.retain(|(_, end)| *end < Instant::now()); + self.banned_peers.shrink_to_fit(); + + if !self.events.is_empty() { + return Async::Ready(self.events.remove(0)) + } + + Async::NotReady + } +} diff --git a/substrate/core/network-libp2p/src/custom_proto/handler.rs b/substrate/core/network-libp2p/src/custom_proto/handler.rs new file mode 100644 index 0000000000..d03f3f093d --- /dev/null +++ b/substrate/core/network-libp2p/src/custom_proto/handler.rs @@ -0,0 +1,327 @@ +// Copyright 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 . + +use crate::ProtocolId; +use crate::custom_proto::upgrade::{RegisteredProtocol, RegisteredProtocols, RegisteredProtocolSubstream}; +use bytes::Bytes; +use futures::prelude::*; +use libp2p::core::{ + Endpoint, ProtocolsHandler, ProtocolsHandlerEvent, + protocols_handler::ProtocolsHandlerUpgrErr, + upgrade::{InboundUpgrade, OutboundUpgrade} +}; +use smallvec::SmallVec; +use std::{fmt, io}; +use tokio_io::{AsyncRead, AsyncWrite}; +use void::Void; + +/// Protocol handler that tries to maintain one substream per registered custom protocol. +/// +/// The handler initially starts in the "Disable" state. It can then be enabled by sending an +/// `Enable` message. +/// The handler can then be enabled and disabled at any time with the `Enable` and `Disable` +/// messages. +pub struct CustomProtosHandler { + /// List of all the protocols we support. + protocols: RegisteredProtocols, + + /// See the documentation of `State`. + state: State, + + /// The active substreams. There should always ever be only one substream per protocol. + substreams: SmallVec<[RegisteredProtocolSubstream; 6]>, + + /// Queue of events to send to the outside. + events_queue: SmallVec<[ProtocolsHandlerEvent; 16]>, +} + +/// State of the handler. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum State { + /// Normal functionning. + Normal, + + /// We are disabled. We close existing substreams and refuse incoming connections, but don't + /// shut down the entire handler. + Disabled, + + /// We are trying to shut down the existing node and thus should refuse any incoming + /// connection. + ShuttingDown, +} + +/// Event that can be received by a `CustomProtosHandler`. +#[derive(Debug)] +pub enum CustomProtosHandlerIn { + /// The node should start using custom protocols and actively open substreams. + EnableActive, + + /// The node should listen to custom protocols but not open substreams. + EnablePassive, + + /// The node should stop using custom protocols. + Disable, + + /// Sends a message through a custom protocol substream. + SendCustomMessage { + /// The protocol to use. + protocol: ProtocolId, + /// The data to send. + data: Bytes, + }, +} + +/// Event that can be emitted by a `CustomProtosHandler`. +#[derive(Debug)] +pub enum CustomProtosHandlerOut { + /// Opened a custom protocol with the remote. + CustomProtocolOpen { + /// Identifier of the protocol. + protocol_id: ProtocolId, + /// Version of the protocol that has been opened. + version: u8, + }, + + /// Closed a custom protocol with the remote. + CustomProtocolClosed { + /// Identifier of the protocol. + protocol_id: ProtocolId, + /// Reason why the substream closed. If `Ok`, then it's a graceful exit (EOF). + result: io::Result<()>, + }, + + /// Receives a message on a custom protocol substream. + CustomMessage { + /// Protocol which generated the message. + protocol_id: ProtocolId, + /// Data that has been received. + data: Bytes, + }, +} + +impl CustomProtosHandler +where + TSubstream: AsyncRead + AsyncWrite, +{ + /// Builds a new `CustomProtosHandler`. + pub fn new(protocols: RegisteredProtocols) -> Self { + CustomProtosHandler { + protocols, + state: State::Disabled, + substreams: SmallVec::new(), + events_queue: SmallVec::new(), + } + } + + /// Called by `inject_fully_negotiated_inbound` and `inject_fully_negotiated_outbound`. + fn inject_fully_negotiated( + &mut self, + proto: RegisteredProtocolSubstream, + _: Endpoint, + ) { + match self.state { + State::Disabled | State::ShuttingDown => return, + State::Normal => () + } + + if self.substreams.iter().any(|p| p.protocol_id() == proto.protocol_id()) { + // Skipping protocol that's already open. + return + } + + let event = CustomProtosHandlerOut::CustomProtocolOpen { + protocol_id: proto.protocol_id(), + version: proto.protocol_version(), + }; + + self.substreams.push(proto); + self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); + } +} + +impl ProtocolsHandler for CustomProtosHandler +where + TSubstream: AsyncRead + AsyncWrite, +{ + type InEvent = CustomProtosHandlerIn; + type OutEvent = CustomProtosHandlerOut; + type Substream = TSubstream; + type Error = Void; + type InboundProtocol = RegisteredProtocols; + type OutboundProtocol = RegisteredProtocol; + type OutboundOpenInfo = (); + + #[inline] + fn listen_protocol(&self) -> Self::InboundProtocol { + self.protocols.clone() + } + + fn inject_fully_negotiated_inbound( + &mut self, + proto: >::Output + ) { + self.inject_fully_negotiated(proto, Endpoint::Listener); + } + + #[inline] + fn inject_fully_negotiated_outbound( + &mut self, + proto: >::Output, + _: Self::OutboundOpenInfo + ) { + self.inject_fully_negotiated(proto, Endpoint::Dialer); + } + + fn inject_event(&mut self, message: CustomProtosHandlerIn) { + match message { + CustomProtosHandlerIn::Disable => { + match self.state { + State::Normal => self.state = State::Disabled, + State::Disabled | State::ShuttingDown => (), + } + + for substream in self.substreams.iter_mut() { + substream.shutdown(); + } + }, + CustomProtosHandlerIn::EnableActive | CustomProtosHandlerIn::EnablePassive => { + match self.state { + State::Disabled => self.state = State::Normal, + State::Normal | State::ShuttingDown => (), + } + + // Try open one substream for each registered protocol. + if let CustomProtosHandlerIn::EnableActive = message { + for protocol in self.protocols.0.iter() { + if self.substreams.iter().any(|p| p.protocol_id() == protocol.id()) { + // Skipping protocol that's already open. + continue + } + + self.events_queue.push(ProtocolsHandlerEvent::OutboundSubstreamRequest { + upgrade: protocol.clone(), + info: (), + }); + } + } + }, + CustomProtosHandlerIn::SendCustomMessage { protocol, data } => { + debug_assert!(self.protocols.has_protocol(protocol), + "invalid protocol id requested in the API of the libp2p networking"); + let proto = match self.substreams.iter_mut().find(|p| p.protocol_id() == protocol) { + Some(proto) => proto, + None => { + // We are processing a message event before we could report to the outside + // that we disconnected from the protocol. This is not an error. + trace!(target: "sub-libp2p", "Tried to send message through closed \ + protocol"); + return + }, + }; + + proto.send_message(data); + }, + } + } + + #[inline] + fn inject_inbound_closed(&mut self) {} + + #[inline] + fn inject_dial_upgrade_error(&mut self, _: Self::OutboundOpenInfo, err: ProtocolsHandlerUpgrErr) { + warn!(target: "sub-libp2p", "Error while opening custom protocol: {:?}", err); + } + + #[inline] + fn connection_keep_alive(&self) -> bool { + // Right now if the remote doesn't support one of the custom protocols, we shut down the + // entire connection. This is a hack-ish solution to the problem where we connect to nodes + // that support libp2p but not the testnet that we want. + self.substreams.len() == self.protocols.len() + } + + fn shutdown(&mut self) { + match self.state { + State::Normal | State::Disabled => self.state = State::ShuttingDown, + State::ShuttingDown => (), + } + + for substream in self.substreams.iter_mut() { + substream.shutdown(); + } + } + + fn poll( + &mut self, + ) -> Poll< + ProtocolsHandlerEvent, + Self::Error, + > { + if !self.events_queue.is_empty() { + let event = self.events_queue.remove(0); + return Ok(Async::Ready(event)) + } + + if self.state == State::ShuttingDown && self.substreams.is_empty() { + return Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)) + } + + for n in (0..self.substreams.len()).rev() { + let mut substream = self.substreams.swap_remove(n); + match substream.poll() { + Ok(Async::Ready(Some(data))) => { + let event = CustomProtosHandlerOut::CustomMessage { + protocol_id: substream.protocol_id(), + data + }; + self.substreams.push(substream); + return Ok(Async::Ready(ProtocolsHandlerEvent::Custom(event))) + }, + Ok(Async::NotReady) => + self.substreams.push(substream), + Ok(Async::Ready(None)) => { + let event = CustomProtosHandlerOut::CustomProtocolClosed { + protocol_id: substream.protocol_id(), + result: Ok(()) + }; + return Ok(Async::Ready(ProtocolsHandlerEvent::Custom(event))) + }, + Err(err) => { + let event = CustomProtosHandlerOut::CustomProtocolClosed { + protocol_id: substream.protocol_id(), + result: Err(err) + }; + return Ok(Async::Ready(ProtocolsHandlerEvent::Custom(event))) + }, + } + } + + Ok(Async::NotReady) + } +} + +impl fmt::Debug for CustomProtosHandler +where + TSubstream: AsyncRead + AsyncWrite, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.debug_struct("CustomProtosHandler") + .field("protocols", &self.protocols.len()) + .field("state", &self.state) + .field("substreams", &self.substreams.len()) + .finish() + } +} diff --git a/substrate/core/network-libp2p/src/custom_proto/mod.rs b/substrate/core/network-libp2p/src/custom_proto/mod.rs new file mode 100644 index 0000000000..f8b7e8edc5 --- /dev/null +++ b/substrate/core/network-libp2p/src/custom_proto/mod.rs @@ -0,0 +1,22 @@ +// Copyright 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 . + +pub use self::behaviour::{CustomProtos, CustomProtosOut}; +pub use self::upgrade::{RegisteredProtocol, RegisteredProtocols}; + +mod behaviour; +mod handler; +mod upgrade; diff --git a/substrate/core/network-libp2p/src/custom_proto.rs b/substrate/core/network-libp2p/src/custom_proto/upgrade.rs similarity index 64% rename from substrate/core/network-libp2p/src/custom_proto.rs rename to substrate/core/network-libp2p/src/custom_proto/upgrade.rs index fd76581d3e..94bc657902 100644 --- a/substrate/core/network-libp2p/src/custom_proto.rs +++ b/substrate/core/network-libp2p/src/custom_proto/upgrade.rs @@ -15,10 +15,10 @@ // along with Substrate. If not, see . use bytes::Bytes; -use libp2p::core::{ConnectionUpgrade, Endpoint}; +use libp2p::core::{UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName}; use libp2p::tokio_codec::Framed; use std::{collections::VecDeque, io, vec::IntoIter as VecIntoIter}; -use futures::{prelude::*, future, stream, task}; +use futures::{prelude::*, future, stream}; use tokio_io::{AsyncRead, AsyncWrite}; use unsigned_varint::codec::UviBytes; use ProtocolId; @@ -80,8 +80,6 @@ pub struct RegisteredProtocolSubstream { protocol_id: ProtocolId, /// Version of the protocol that was negotiated. protocol_version: u8, - /// Task to notify when something is changed and we need to be polled. - to_notify: Option, } impl RegisteredProtocolSubstream { @@ -105,9 +103,6 @@ impl RegisteredProtocolSubstream { /// After calling this, the stream is guaranteed to finish soon-ish. pub fn shutdown(&mut self) { self.is_closing = true; - if let Some(task) = self.to_notify.take() { - task.notify(); - } } /// Sends a message to the substream. @@ -119,10 +114,6 @@ impl RegisteredProtocolSubstream { warn!(target: "sub-libp2p", "Queue of packets to send over substream is pretty \ large: {}", self.send_queue.len()); } - - if let Some(task) = self.to_notify.take() { - task.notify(); - } } } @@ -135,7 +126,7 @@ where TSubstream: AsyncRead + AsyncWrite, fn poll(&mut self) -> Poll, Self::Error> { // If we are closing, close as soon as the Sink is closed. if self.is_closing { - return Ok(self.inner.close()?.map(|()| None)); + return Ok(self.inner.close()?.map(|()| None)) } // Flushing the local queue. @@ -143,7 +134,7 @@ where TSubstream: AsyncRead + AsyncWrite, match self.inner.start_send(packet)? { AsyncSink::NotReady(packet) => { self.send_queue.push_front(packet); - break; + break }, AsyncSink::Ready => self.requires_poll_complete = true, } @@ -158,51 +149,64 @@ where TSubstream: AsyncRead + AsyncWrite, // Receiving incoming packets. // Note that `inner` is wrapped in a `Fuse`, therefore we can poll it forever. - loop { - match self.inner.poll()? { - Async::Ready(Some(data)) => - return Ok(Async::Ready(Some(data.freeze()))), - Async::Ready(None) => - if !self.requires_poll_complete && self.send_queue.is_empty() { - return Ok(Async::Ready(None)) - } else { - break - }, - Async::NotReady => break, - } + match self.inner.poll()? { + Async::Ready(Some(data)) => Ok(Async::Ready(Some(data.freeze()))), + Async::Ready(None) => + if !self.requires_poll_complete && self.send_queue.is_empty() { + Ok(Async::Ready(None)) + } else { + Ok(Async::NotReady) + }, + Async::NotReady => Ok(Async::NotReady), } - - self.to_notify = Some(task::current()); - Ok(Async::NotReady) } } -impl ConnectionUpgrade for RegisteredProtocol -where TSubstream: AsyncRead + AsyncWrite, -{ - type NamesIter = VecIntoIter<(Bytes, Self::UpgradeIdentifier)>; - type UpgradeIdentifier = u8; // Protocol version +impl UpgradeInfo for RegisteredProtocol { + type Info = RegisteredProtocolName; + type InfoIter = VecIntoIter; #[inline] - fn protocol_names(&self) -> Self::NamesIter { + fn protocol_info(&self) -> Self::InfoIter { // Report each version as an individual protocol. - self.supported_versions.iter().map(|&ver| { - let num = ver.to_string(); + self.supported_versions.iter().map(|&version| { + let num = version.to_string(); let mut name = self.base_name.clone(); name.extend_from_slice(num.as_bytes()); - (name, ver) + RegisteredProtocolName { + name, + version, + } }).collect::>().into_iter() } +} +/// Implementation of `ProtocolName` for a custom protocol. +#[derive(Debug, Clone)] +pub struct RegisteredProtocolName { + /// Protocol name, as advertised on the wire. + name: Bytes, + /// Version number. Stored in string form in `name`, but duplicated here for easier retrieval. + version: u8, +} + +impl ProtocolName for RegisteredProtocolName { + fn protocol_name(&self) -> &[u8] { + &self.name + } +} + +impl InboundUpgrade for RegisteredProtocol +where TSubstream: AsyncRead + AsyncWrite, +{ type Output = RegisteredProtocolSubstream; type Future = future::FutureResult; + type Error = io::Error; - #[allow(deprecated)] - fn upgrade( + fn upgrade_inbound( self, socket: TSubstream, - protocol_version: Self::UpgradeIdentifier, - _: Endpoint + info: Self::Info, ) -> Self::Future { let framed = Framed::new(socket, UviBytes::default()); @@ -212,12 +216,28 @@ where TSubstream: AsyncRead + AsyncWrite, requires_poll_complete: false, inner: framed.fuse(), protocol_id: self.id, - protocol_version, - to_notify: None, + protocol_version: info.version, }) } } +impl OutboundUpgrade for RegisteredProtocol +where TSubstream: AsyncRead + AsyncWrite, +{ + type Output = >::Output; + type Future = >::Future; + type Error = >::Error; + + fn upgrade_outbound( + self, + socket: TSubstream, + info: Self::Info, + ) -> Self::Future { + // Upgrades are symmetrical. + self.upgrade_inbound(socket, info) + } +} + // Connection upgrade for all the protocols contained in it. #[derive(Clone)] pub struct RegisteredProtocols(pub Vec); @@ -229,12 +249,6 @@ impl RegisteredProtocols { self.0.len() } - /// Finds a protocol in the list by its id. - pub fn find_protocol(&self, protocol: ProtocolId) - -> Option<&RegisteredProtocol> { - self.0.iter().find(|p| p.id == protocol) - } - /// Returns true if the given protocol is in the list. pub fn has_protocol(&self, protocol: ProtocolId) -> bool { self.0.iter().any(|p| p.id == protocol) @@ -247,36 +261,75 @@ impl Default for RegisteredProtocols { } } -impl ConnectionUpgrade for RegisteredProtocols -where TSubstream: AsyncRead + AsyncWrite, -{ - type NamesIter = VecIntoIter<(Bytes, Self::UpgradeIdentifier)>; - type UpgradeIdentifier = (usize, - >::UpgradeIdentifier); +impl UpgradeInfo for RegisteredProtocols { + type Info = RegisteredProtocolsName; + type InfoIter = VecIntoIter; - fn protocol_names(&self) -> Self::NamesIter { + #[inline] + fn protocol_info(&self) -> Self::InfoIter { // We concat the lists of `RegisteredProtocol::protocol_names` for // each protocol. self.0.iter().enumerate().flat_map(|(n, proto)| - ConnectionUpgrade::::protocol_names(proto) - .map(move |(name, id)| (name, (n, id))) + UpgradeInfo::protocol_info(proto) + .map(move |inner| { + RegisteredProtocolsName { + inner, + index: n, + } + }) ).collect::>().into_iter() } +} - type Output = >::Output; - type Future = >::Future; +/// Implementation of `ProtocolName` for several custom protocols. +#[derive(Debug, Clone)] +pub struct RegisteredProtocolsName { + /// Inner registered protocol. + inner: RegisteredProtocolName, + /// Index of the protocol in the list of registered custom protocols. + index: usize, +} - #[inline] - fn upgrade( - self, - socket: TSubstream, - upgrade_identifier: Self::UpgradeIdentifier, - endpoint: Endpoint - ) -> Self::Future { - let (protocol_index, inner_proto_id) = upgrade_identifier; - self.0.into_iter() - .nth(protocol_index) - .expect("invalid protocol index ; programmer logic error") - .upgrade(socket, inner_proto_id, endpoint) +impl ProtocolName for RegisteredProtocolsName { + fn protocol_name(&self) -> &[u8] { + self.inner.protocol_name() + } +} + +impl InboundUpgrade for RegisteredProtocols +where TSubstream: AsyncRead + AsyncWrite, +{ + type Output = >::Output; + type Future = >::Future; + type Error = io::Error; + + #[inline] + fn upgrade_inbound( + self, + socket: TSubstream, + info: Self::Info, + ) -> Self::Future { + self.0.into_iter() + .nth(info.index) + .expect("invalid protocol index ; programmer logic error") + .upgrade_inbound(socket, info.inner) + } +} + +impl OutboundUpgrade for RegisteredProtocols +where TSubstream: AsyncRead + AsyncWrite, +{ + type Output = >::Output; + type Future = >::Future; + type Error = >::Error; + + #[inline] + fn upgrade_outbound( + self, + socket: TSubstream, + info: Self::Info, + ) -> Self::Future { + // Upgrades are symmetrical. + self.upgrade_inbound(socket, info) } } diff --git a/substrate/core/network-libp2p/src/lib.rs b/substrate/core/network-libp2p/src/lib.rs index 6890450763..9fb1bb8a13 100644 --- a/substrate/core/network-libp2p/src/lib.rs +++ b/substrate/core/network-libp2p/src/lib.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Substrate libp2p implementation of the ethcore network library +//! Networking layer of Substrate. #![recursion_limit = "128"] @@ -31,6 +31,8 @@ extern crate rand; #[macro_use] extern crate serde_derive; extern crate serde_json; +extern crate smallvec; +extern crate void; extern crate bytes; extern crate unsigned_varint; @@ -41,12 +43,11 @@ extern crate log; #[cfg(test)] #[macro_use] extern crate assert_matches; +mod behaviour; mod custom_proto; mod error; -mod node_handler; mod secret; mod service_task; -mod swarm; mod topology; mod traits; mod transport; diff --git a/substrate/core/network-libp2p/src/node_handler.rs b/substrate/core/network-libp2p/src/node_handler.rs deleted file mode 100644 index ad1f4b7504..0000000000 --- a/substrate/core/network-libp2p/src/node_handler.rs +++ /dev/null @@ -1,863 +0,0 @@ -// Copyright 2018 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 . - -use bytes::Bytes; -use custom_proto::{RegisteredProtocols, RegisteredProtocolSubstream}; -use futures::{prelude::*, task}; -use libp2p::core::{ConnectionUpgrade, Endpoint, PeerId, PublicKey, upgrade}; -use libp2p::core::nodes::handled_node::{NodeHandler, NodeHandlerEndpoint, NodeHandlerEvent}; -use libp2p::kad::{KadConnecConfig, KadFindNodeRespond, KadIncomingRequest, KadConnecController}; -use libp2p::{identify, ping}; -use parking_lot::Mutex; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use std::sync::Arc; -use std::time::{Duration, Instant}; -use tokio_io::{AsyncRead, AsyncWrite}; -use tokio_timer::{Delay, Interval}; -use {Multiaddr, ProtocolId}; - -/// Duration after which we consider that a ping failed. -const PING_TIMEOUT: Duration = Duration::from_secs(30); -/// After a ping succeeded, wait this long before the next ping. -const DELAY_TO_NEXT_PING: Duration = Duration::from_secs(15); -/// Period at which we identify the remote. -const PERIOD_IDENTIFY: Duration = Duration::from_secs(5 * 60); -/// Delay between the moment we connect and the first time we ping. -const DELAY_TO_FIRST_PING: Duration = Duration::from_secs(5); -/// Delay between the moment we connect and the first time we identify. -const DELAY_TO_FIRST_IDENTIFY: Duration = Duration::from_secs(2); - -/// This struct handles the open substreams of a specific node. -/// -/// It doesn't handle opening the substreams, but only what to do with substreams that have been -/// opened. -/// -/// The node will be pinged at a regular interval to determine whether it's still alive. We will -/// also regularly query the remote for identification information, for statistics purposes. -pub struct SubstrateNodeHandler { - /// List of registered custom protocols. - registered_custom: Arc, - /// Substreams open for "custom" protocols (eg. dot). - custom_protocols_substreams: Vec>, - - /// Substream open for Kademlia, if any. - kademlia_substream: Option<(KadConnecController, Box + Send>)>, - /// If true, we need to send back a `KadOpen` event on the stream (if Kademlia is open). - need_report_kad_open: bool, - - /// Substream open for sending pings, if any. - ping_out_substream: Option>, - /// Active pinging attempt with the moment it expires. - active_ping_out: Option, - /// Substreams open for receiving pings. - ping_in_substreams: Vec>, - /// Future that fires when we need to ping the node again. - /// - /// Every time we receive a pong, we reset the timer to the next time. - next_ping: Delay, - - /// Substreams for sending back our identify info to the remote. - /// - /// This is in an `Arc` in order to avoid borrowing issues with the future. - identify_send_back: Arc + Send>>>>, - /// Stream that fires when we need to identify the node again. - next_identify: Interval, - - /// Substreams being upgraded on the listening side. - upgrades_in_progress_listen: Vec, Error = IoError> + Send>>, - /// Substreams being upgraded on the dialing side. Contrary to `upgrades_in_progress_listen`, - /// these have a known purpose. - upgrades_in_progress_dial: Vec<(UpgradePurpose, Box, Error = IoError> + Send>)>, - /// The substreams we want to open. - queued_dial_upgrades: Vec, - /// Number of outbound substreams the outside should open for us. - num_out_user_must_open: usize, - - /// The node has started its shutdown process. - is_shutting_down: bool, - - /// Task to notify if we add an element to one of the lists from the public API. - to_notify: Option, -} - -/// Purpose of an upgrade in progress on the dialing side. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum UpgradePurpose { - Custom(ProtocolId), - Kad, - Identify, - Ping, -} - -/// Event that can happen on the `SubstrateNodeHandler`. -pub enum SubstrateOutEvent { - /// The node has been determined to be unresponsive. - Unresponsive, - - /// The node works but we can't do anything useful with it. - Useless, - - /// Started pinging the remote. This can be used to print a diagnostic message in the logs. - PingStart, - - /// The node has successfully responded to a ping. - PingSuccess(Duration), - - /// Opened a custom protocol with the remote. - CustomProtocolOpen { - /// Identifier of the protocol. - protocol_id: ProtocolId, - /// Version of the protocol that has been opened. - version: u8, - }, - - /// Closed a custom protocol with the remote. - CustomProtocolClosed { - /// Identifier of the protocol. - protocol_id: ProtocolId, - /// Reason why the substream closed. If `Ok`, then it's a graceful exit (EOF). - result: Result<(), IoError>, - }, - - /// Receives a message on a custom protocol substream. - CustomMessage { - /// Protocol which generated the message. - protocol_id: ProtocolId, - /// Data that has been received. - data: Bytes, - }, - - /// We obtained identification information from the remote - Identified { - /// Information of the remote. - info: identify::IdentifyInfo, - /// Address the remote observes us as. - observed_addr: Multiaddr, - }, - - /// The remote wants us to send back identification information. - /// - /// The `IdentificationRequest` object should be used to send the information. - IdentificationRequest(IdentificationRequest), - - /// Opened a Kademlia substream with the node. - KadOpen(KadConnecController), - - /// The remote wants us to answer a Kademlia `FIND_NODE` request. - /// - /// The `responder` should be used to answer that query. - // TODO: this API with the "responder" is bad, but changing it requires modifications in libp2p - KadFindNode { - /// The value being searched. - searched: PeerId, - /// Object to use to respond to the request. - responder: KadFindNodeRespond, - }, - - /// The Kademlia substream has been closed. - /// - /// The parameter contains the reason why it has been closed. `Ok` means that it's been closed - /// gracefully. - KadClosed(Result<(), IoError>), - - /// An error happened while upgrading a substream. - /// - /// This can be used to print a diagnostic message. - SubstreamUpgradeFail(IoError), -} - -/// The remote wants us to send back information. -pub struct IdentificationRequest { - /// Where to store the future that sends back the information. - identify_send_back: Arc + Send>>>>, - /// Object that sends back the information. - sender: identify::IdentifySender, - /// Protocol names that we support, to send back. - protocols: Vec, -} - -impl IdentificationRequest { - /// Responds to the request. - /// - /// - `local_key` must contain our local public key. - /// - `listen_addrs` must contain the list of addresses we're listening on (preferably after - /// NAT traversal). - /// - `remote_addr` must be the address of the remote from our local point of view. - /// - pub fn respond( - self, - local_key: PublicKey, - listen_addrs: Vec, - remote_addr: &Multiaddr - ) where TSubstream: AsyncRead + AsyncWrite + Send + 'static { - // TODO: what to return for `protocol_version` and `agent_version`? - let sender = self.sender.send( - identify::IdentifyInfo { - public_key: local_key, - protocol_version: concat!("substrate/", env!("CARGO_PKG_VERSION")).to_owned(), - agent_version: concat!("substrate/", env!("CARGO_PKG_VERSION")).to_owned(), - listen_addrs, - protocols: self.protocols, - }, - remote_addr - ); - - self.identify_send_back.lock().push(sender); - } -} - -/// Event that can be received by a `SubstrateNodeHandler`. -#[derive(Debug, Clone)] -pub enum SubstrateInEvent { - /// Before anything happens on the node, we wait for an `Accept` event. This is used to deny - /// nodes based on their peer ID. - Accept, - - /// Sends a message through a custom protocol substream. - SendCustomMessage { - protocol: ProtocolId, - data: Vec, - }, - - /// Requests to open a Kademlia substream. - // TODO: document better - OpenKademlia, -} - -/// Ideally we would have a method on `SubstrateNodeHandler` that builds this type, but in practice it's a -/// bit tedious to express, even with the `impl Trait` syntax. -/// Therefore we simply use a macro instead. -macro_rules! listener_upgrade { - ($self:expr) => ( - upgrade::or(upgrade::or(upgrade::or( - upgrade::map((*$self.registered_custom).clone(), move |c| FinalUpgrade::Custom(c)), - upgrade::map(KadConnecConfig::new(), move |(c, s)| FinalUpgrade::Kad(c, s))), - upgrade::map(ping::protocol::Ping::default(), move |p| FinalUpgrade::from(p))), - upgrade::map(identify::IdentifyProtocolConfig, move |i| FinalUpgrade::from(i))) - // TODO: meh for cloning a Vec here - ) -} - -impl SubstrateNodeHandler -where TSubstream: AsyncRead + AsyncWrite + Send + 'static, -{ - /// Creates a new node handler. - #[inline] - pub fn new(registered_custom: Arc) -> Self { - let registered_custom_len = registered_custom.len(); - let queued_dial_upgrades = registered_custom.0 - .iter() - .map(|proto| UpgradePurpose::Custom(proto.id())) - .collect(); - - SubstrateNodeHandler { - custom_protocols_substreams: Vec::with_capacity(registered_custom_len), - kademlia_substream: None, - need_report_kad_open: false, - identify_send_back: Arc::new(Mutex::new(Vec::with_capacity(1))), - ping_in_substreams: Vec::with_capacity(1), - ping_out_substream: None, - active_ping_out: None, - registered_custom, - upgrades_in_progress_listen: Vec::with_capacity(registered_custom_len + 3), - upgrades_in_progress_dial: Vec::with_capacity(registered_custom_len + 3), - next_ping: Delay::new(Instant::now() + DELAY_TO_FIRST_PING), - next_identify: Interval::new(Instant::now() + DELAY_TO_FIRST_IDENTIFY, PERIOD_IDENTIFY), - queued_dial_upgrades, - num_out_user_must_open: registered_custom_len, - is_shutting_down: false, - to_notify: None, - } - } -} - -impl NodeHandler for SubstrateNodeHandler -where TSubstream: AsyncRead + AsyncWrite + Send + 'static, -{ - type InEvent = SubstrateInEvent; - type OutEvent = SubstrateOutEvent; - type OutboundOpenInfo = (); - type Substream = TSubstream; - - fn inject_substream(&mut self, substream: TSubstream, endpoint: NodeHandlerEndpoint) { - // For listeners, propose all the possible upgrades. - if endpoint == NodeHandlerEndpoint::Listener { - let listener_upgrade = listener_upgrade!(self); - let upgrade = upgrade::apply(substream, listener_upgrade, Endpoint::Listener); - self.upgrades_in_progress_listen.push(Box::new(upgrade) as Box<_>); - // Since we pushed to `upgrades_in_progress_listen`, we have to notify the task. - if let Some(task) = self.to_notify.take() { - task.notify(); - } - return; - } - - // If we're the dialer, we have to decide which upgrade we want. - let purpose = if self.queued_dial_upgrades.is_empty() { - // Since we sometimes remove elements from `queued_dial_upgrades` before they succeed - // but after the outbound substream has started opening, it is possible that the queue - // is empty when we receive a substream. This is not an error. - // Example: we want to open a Kademlia substream, we start opening one, but in the - // meanwhile the remote opens a Kademlia substream. When we receive the new substream, - // we don't need it anymore. - return; - } else { - self.queued_dial_upgrades.remove(0) - }; - - match purpose { - UpgradePurpose::Custom(id) => { - let wanted = if let Some(proto) = self.registered_custom.find_protocol(id) { - // TODO: meh for cloning - upgrade::map(proto.clone(), move |c| FinalUpgrade::Custom(c)) - } else { - error!(target: "sub-libp2p", "Logic error: wrong custom protocol id for \ - opened substream"); - return; - }; - - let upgrade = upgrade::apply(substream, wanted, Endpoint::Dialer); - self.upgrades_in_progress_dial.push((purpose, Box::new(upgrade) as Box<_>)); - } - UpgradePurpose::Kad => { - let wanted = upgrade::map(KadConnecConfig::new(), move |(c, s)| FinalUpgrade::Kad(c, s)); - let upgrade = upgrade::apply(substream, wanted, Endpoint::Dialer); - self.upgrades_in_progress_dial.push((purpose, Box::new(upgrade) as Box<_>)); - } - UpgradePurpose::Identify => { - let wanted = upgrade::map(identify::IdentifyProtocolConfig, move |i| FinalUpgrade::from(i)); - let upgrade = upgrade::apply(substream, wanted, Endpoint::Dialer); - self.upgrades_in_progress_dial.push((purpose, Box::new(upgrade) as Box<_>)); - } - UpgradePurpose::Ping => { - let wanted = upgrade::map(ping::protocol::Ping::default(), move |p| FinalUpgrade::from(p)); - let upgrade = upgrade::apply(substream, wanted, Endpoint::Dialer); - self.upgrades_in_progress_dial.push((purpose, Box::new(upgrade) as Box<_>)); - } - }; - - // Since we pushed to `upgrades_in_progress_dial`, we have to notify the task. - if let Some(task) = self.to_notify.take() { - task.notify(); - } - } - - #[inline] - fn inject_inbound_closed(&mut self) { - } - - #[inline] - fn inject_outbound_closed(&mut self, _: Self::OutboundOpenInfo) { - } - - fn inject_event(&mut self, event: Self::InEvent) { - match event { - SubstrateInEvent::SendCustomMessage { protocol, data } => { - self.send_custom_message(protocol, data); - }, - SubstrateInEvent::OpenKademlia => self.open_kademlia(), - SubstrateInEvent::Accept => { - // TODO: implement - }, - } - } - - fn shutdown(&mut self) { - // TODO: close gracefully - self.is_shutting_down = true; - - for custom_proto in &mut self.custom_protocols_substreams { - custom_proto.shutdown(); - } - - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - } - - fn poll(&mut self) -> Poll>, IoError> { - if self.is_shutting_down { - // TODO: finish only when everything is closed - return Ok(Async::Ready(None)); - } - - match self.poll_upgrades_in_progress()? { - Async::Ready(value) => return Ok(Async::Ready(value.map(NodeHandlerEvent::Custom))), - Async::NotReady => (), - }; - - match self.poll_custom_protocols()? { - Async::Ready(value) => return Ok(Async::Ready(value.map(NodeHandlerEvent::Custom))), - Async::NotReady => (), - }; - - match self.poll_kademlia()? { - Async::Ready(value) => return Ok(Async::Ready(value.map(NodeHandlerEvent::Custom))), - Async::NotReady => (), - }; - - match self.poll_ping()? { - Async::Ready(value) => return Ok(Async::Ready(value.map(NodeHandlerEvent::Custom))), - Async::NotReady => (), - }; - - match self.poll_identify()? { - Async::Ready(value) => return Ok(Async::Ready(value.map(NodeHandlerEvent::Custom))), - Async::NotReady => (), - }; - - // Request new outbound substreams from the user if necessary. - if self.num_out_user_must_open >= 1 { - self.num_out_user_must_open -= 1; - return Ok(Async::Ready(Some(NodeHandlerEvent::OutboundSubstreamRequest(())))); - } - - // Nothing happened. Register our task to be notified and return. - self.to_notify = Some(task::current()); - Ok(Async::NotReady) - } -} - -impl SubstrateNodeHandler -where TSubstream: AsyncRead + AsyncWrite + Send + 'static, -{ - /// Sends a message on a custom protocol substream. - fn send_custom_message( - &mut self, - protocol: ProtocolId, - data: Vec, - ) { - debug_assert!(self.registered_custom.has_protocol(protocol), - "invalid protocol id requested in the API of the libp2p networking"); - let proto = match self.custom_protocols_substreams.iter_mut().find(|p| p.protocol_id() == protocol) { - Some(proto) => proto, - None => { - // We are processing a message event before we could report to the outside that - // we disconnected from the protocol. This is not an error. - return - }, - }; - - proto.send_message(data.into()); - } - - /// The node will try to open a Kademlia substream and produce a `KadOpen` event containing the - /// controller. If a Kademlia substream is already open, produces the event immediately. - fn open_kademlia(&mut self) { - if self.kademlia_substream.is_some() { - self.need_report_kad_open = true; - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - } else if self.has_upgrade_purpose(&UpgradePurpose::Kad) { - // We are currently upgrading a substream to Kademlia ; nothing more to do except wait. - } else { - // Opening a new substream for Kademlia. - self.queued_dial_upgrades.push(UpgradePurpose::Kad); - self.num_out_user_must_open += 1; - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - } - } - - /// Returns true if we are currently upgrading to the given protocol. - fn has_upgrade_purpose(&self, purpose: &UpgradePurpose) -> bool { - self.upgrades_in_progress_dial.iter().any(|&(ref p, _)| p == purpose) || - self.queued_dial_upgrades.iter().any(|p| p == purpose) - } - - /// Cancels a dialing upgrade in progress. - /// - /// Useful when the listener opened the protocol we wanted. - fn cancel_dial_upgrade(&mut self, purpose: &UpgradePurpose) { - self.upgrades_in_progress_dial.retain(|&(purp, _)| &purp != purpose); - self.queued_dial_upgrades.retain(|u| u != purpose); - } - - /// Returns the names of the protocols that we supporitt. - fn supported_protocol_names(&self) -> Vec { - let list = listener_upgrade!(self); - ConnectionUpgrade::::protocol_names(&list) - .filter_map(|(n, _)| String::from_utf8(n.to_vec()).ok()) - .collect() - } - - /// Inject a fully negotiated substream into the state. - /// - /// Optionally produces an event to dispatch. - fn inject_fully_negotiated( - &mut self, - upgrade: FinalUpgrade - ) -> Option> { - match upgrade { - FinalUpgrade::IdentifyListener(sender) => - Some(SubstrateOutEvent::IdentificationRequest(IdentificationRequest { - sender, - identify_send_back: self.identify_send_back.clone(), - protocols: self.supported_protocol_names(), - })), - FinalUpgrade::IdentifyDialer(info, observed_addr) => { - self.cancel_dial_upgrade(&UpgradePurpose::Identify); - Some(SubstrateOutEvent::Identified { info, observed_addr }) - }, - FinalUpgrade::PingDialer(ping_dialer) => { - self.cancel_dial_upgrade(&UpgradePurpose::Ping); - // We always open the ping substream for a reason, which is to immediately ping. - self.ping_out_substream = Some(ping_dialer); - self.active_ping_out = None; - if self.ping_remote() { - Some(SubstrateOutEvent::PingStart) - } else { - None - } - }, - FinalUpgrade::PingListener(ping_listener) => { - self.ping_in_substreams.push(ping_listener); - None - }, - FinalUpgrade::Kad(controller, stream) => { - // Remove all upgrades in the progress for Kademlia. - self.cancel_dial_upgrade(&UpgradePurpose::Kad); - // Refuse the substream if we already have Kademlia substream open. - if self.kademlia_substream.is_none() { - self.kademlia_substream = Some((controller.clone(), stream)); - Some(SubstrateOutEvent::KadOpen(controller)) - } else { - None - } - }, - FinalUpgrade::Custom(proto) => { - self.cancel_dial_upgrade(&UpgradePurpose::Custom(proto.protocol_id())); - if self.custom_protocols_substreams.iter().any(|p| p.protocol_id() == proto.protocol_id()) { - // Skipping protocol that's already open. - return None; - } - - let event = SubstrateOutEvent::CustomProtocolOpen { - protocol_id: proto.protocol_id(), - version: proto.protocol_version(), - }; - - self.custom_protocols_substreams.push(proto); - Some(event) - }, - } - } - - /// Start the process of identifying the remote. - fn identify_remote(&mut self) { - if !self.has_upgrade_purpose(&UpgradePurpose::Identify) { - self.queued_dial_upgrades.push(UpgradePurpose::Identify); - self.num_out_user_must_open += 1; - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - } - } - - /// Start the process of pinging the remote. - /// - /// Doesn't do anything if a ping attempt is already in progress. - /// - /// Returns true if this actually starts a ping, false is this just opens a substream or does - /// nothing. - fn ping_remote(&mut self) -> bool { - // Ignore if we are already actively pinging. - if self.active_ping_out.is_some() { - return false; - } - - // If we have a ping open, ping it! - if let Some(ref mut pinger) = self.ping_out_substream { - let now = Instant::now(); - pinger.ping(now); - let future = Delay::new(now + PING_TIMEOUT); - self.active_ping_out = Some(future); - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - return true; - } - - // Otherwise, ensure we have an upgrade for a ping substream in queue. - if !self.has_upgrade_purpose(&UpgradePurpose::Ping) { - self.queued_dial_upgrades.push(UpgradePurpose::Ping); - self.num_out_user_must_open += 1; - // We also start the unresponsiveness counter when opening the substream, as a - // peer may not respond to our opening request. - let future = Delay::new(Instant::now() + PING_TIMEOUT); - self.active_ping_out = Some(future); - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - } - - false - } - - /// Polls the upgrades in progress. - fn poll_upgrades_in_progress(&mut self) -> Poll>, IoError> { - // Continue negotiation of newly-opened substreams on the listening side. - // We remove each element from `upgrades_in_progress_listen` one by one and add them back - // if not ready. - for n in (0 .. self.upgrades_in_progress_listen.len()).rev() { - let mut in_progress = self.upgrades_in_progress_listen.swap_remove(n); - match in_progress.poll() { - Ok(Async::Ready(upgrade)) => { - if let Some(event) = self.inject_fully_negotiated(upgrade) { - return Ok(Async::Ready(Some(event))); - } - }, - Ok(Async::NotReady) => { - self.upgrades_in_progress_listen.push(in_progress); - }, - Err(err) => { - return Ok(Async::Ready(Some(SubstrateOutEvent::SubstreamUpgradeFail(err)))); - }, - } - } - - // Continue negotiation of newly-opened substreams. - // We remove each element from `upgrades_in_progress_dial` one by one and add them back if - // not ready. - for n in (0 .. self.upgrades_in_progress_dial.len()).rev() { - let (purpose, mut in_progress) = self.upgrades_in_progress_dial.swap_remove(n); - match in_progress.poll() { - Ok(Async::Ready(upgrade)) => { - if let Some(event) = self.inject_fully_negotiated(upgrade) { - return Ok(Async::Ready(Some(event))); - } - }, - Ok(Async::NotReady) => - self.upgrades_in_progress_dial.push((purpose, in_progress)), - Err(err) => { - // TODO: dispatch depending on actual error ; right now we assume that - // error == not supported, which is not necessarily true in theory - if let UpgradePurpose::Custom(_) = purpose { - return Ok(Async::Ready(Some(SubstrateOutEvent::Useless))); - } else { - let msg = format!("While upgrading to {:?}: {:?}", purpose, err); - let err = IoError::new(IoErrorKind::Other, msg); - return Ok(Async::Ready(Some(SubstrateOutEvent::SubstreamUpgradeFail(err)))); - } - }, - } - } - - Ok(Async::NotReady) - } - - /// Polls the upgrades in progress. - fn poll_custom_protocols(&mut self) -> Poll>, IoError> { - // Poll for messages on the custom protocol stream. - for n in (0 .. self.custom_protocols_substreams.len()).rev() { - let mut custom_proto = self.custom_protocols_substreams.swap_remove(n); - match custom_proto.poll() { - Ok(Async::NotReady) => self.custom_protocols_substreams.push(custom_proto), - Ok(Async::Ready(Some(data))) => { - let protocol_id = custom_proto.protocol_id(); - self.custom_protocols_substreams.push(custom_proto); - return Ok(Async::Ready(Some(SubstrateOutEvent::CustomMessage { - protocol_id, - data, - }))); - }, - Ok(Async::Ready(None)) => { - // Trying to reopen the protocol. - self.queued_dial_upgrades.push(UpgradePurpose::Custom(custom_proto.protocol_id())); - self.num_out_user_must_open += 1; - return Ok(Async::Ready(Some(SubstrateOutEvent::CustomProtocolClosed { - protocol_id: custom_proto.protocol_id(), - result: Ok(()), - }))) - }, - Err(err) => { - // Trying to reopen the protocol. - self.queued_dial_upgrades.push(UpgradePurpose::Custom(custom_proto.protocol_id())); - self.num_out_user_must_open += 1; - return Ok(Async::Ready(Some(SubstrateOutEvent::CustomProtocolClosed { - protocol_id: custom_proto.protocol_id(), - result: Err(err), - }))) - }, - } - } - - Ok(Async::NotReady) - } - - /// Polls the open Kademlia substream, if any. - fn poll_kademlia(&mut self) -> Poll>, IoError> { - // Produce a `KadOpen` event if necessary. - if self.need_report_kad_open { - self.need_report_kad_open = false; - if let Some((ref kad_ctrl, _)) = self.kademlia_substream { - return Ok(Async::Ready(Some(SubstrateOutEvent::KadOpen(kad_ctrl.clone())))); - } - } - - // Poll for Kademlia events. - if let Some((controller, mut stream)) = self.kademlia_substream.take() { - loop { - match stream.poll() { - Ok(Async::Ready(Some(KadIncomingRequest::FindNode { searched, responder }))) => { - self.kademlia_substream = Some((controller, stream)); - return Ok(Async::Ready(Some(SubstrateOutEvent::KadFindNode { searched, responder }))); - }, - // We don't care about Kademlia pings, they are unused. - Ok(Async::Ready(Some(KadIncomingRequest::PingPong))) => {}, - // Other Kademlia messages are unimplemented. - Ok(Async::Ready(Some(KadIncomingRequest::GetProviders { .. }))) => {}, - Ok(Async::Ready(Some(KadIncomingRequest::AddProvider { .. }))) => {}, - Ok(Async::NotReady) => { - self.kademlia_substream = Some((controller, stream)); - break; - }, - Ok(Async::Ready(None)) => return Ok(Async::Ready(Some(SubstrateOutEvent::KadClosed(Ok(()))))), - Err(err) => return Ok(Async::Ready(Some(SubstrateOutEvent::KadClosed(Err(err))))), - } - } - } - - Ok(Async::NotReady) - } - - /// Polls the ping substreams. - fn poll_ping(&mut self) -> Poll>, IoError> { - // Poll the future that fires when we need to ping the node again. - match self.next_ping.poll() { - Ok(Async::NotReady) => {}, - Ok(Async::Ready(())) => { - // We reset `next_ping` to a very long time in the future so that we can poll - // it again without having an accident. - self.next_ping.reset(Instant::now() + Duration::from_secs(5 * 60)); - if self.ping_remote() { - return Ok(Async::Ready(Some(SubstrateOutEvent::PingStart))); - } - }, - Err(err) => { - warn!(target: "sub-libp2p", "Ping timer errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)); - } - } - - // Poll for answering pings. - for n in (0 .. self.ping_in_substreams.len()).rev() { - let mut ping = self.ping_in_substreams.swap_remove(n); - match ping.poll() { - Ok(Async::Ready(())) => {}, - Ok(Async::NotReady) => self.ping_in_substreams.push(ping), - Err(err) => warn!(target: "sub-libp2p", "Remote ping substream errored: {:?}", err), - } - } - - // Poll the ping substream. - if let Some(mut ping_dialer) = self.ping_out_substream.take() { - match ping_dialer.poll() { - Ok(Async::Ready(Some(started))) => { - self.active_ping_out = None; - self.next_ping.reset(Instant::now() + DELAY_TO_NEXT_PING); - return Ok(Async::Ready(Some(SubstrateOutEvent::PingSuccess(started.elapsed())))); - }, - Ok(Async::Ready(None)) => { - // Try re-open ping if it got closed. - self.queued_dial_upgrades.push(UpgradePurpose::Ping); - self.num_out_user_must_open += 1; - }, - Ok(Async::NotReady) => self.ping_out_substream = Some(ping_dialer), - Err(_) => {}, - } - } - - // Poll the active ping attempt. - if let Some(mut deadline) = self.active_ping_out.take() { - match deadline.poll() { - Ok(Async::Ready(())) => - return Ok(Async::Ready(Some(SubstrateOutEvent::Unresponsive))), - Ok(Async::NotReady) => self.active_ping_out = Some(deadline), - Err(err) => { - warn!(target: "sub-libp2p", "Active ping deadline errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)); - }, - } - } - - Ok(Async::NotReady) - } - - /// Polls the identify substreams. - fn poll_identify(&mut self) -> Poll>, IoError> { - // Poll the future that fires when we need to identify the node again. - loop { - match self.next_identify.poll() { - Ok(Async::NotReady) => break, - Ok(Async::Ready(Some(_))) => self.identify_remote(), - Ok(Async::Ready(None)) => { - warn!(target: "sub-libp2p", "Identify timer closed unexpectedly"); - return Ok(Async::Ready(None)); - } - Err(err) => { - warn!(target: "sub-libp2p", "Identify timer errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)); - } - } - } - - // Poll for sending identify information to the remote. - let mut identify_send_back = self.identify_send_back.lock(); - for n in (0 .. identify_send_back.len()).rev() { - let mut id_send_back = identify_send_back.swap_remove(n); - match id_send_back.poll() { - Ok(Async::Ready(())) => {}, - Ok(Async::NotReady) => identify_send_back.push(id_send_back), - Err(err) => warn!(target: "sub-libp2p", "Sending back identify info errored: {:?}", err), - } - } - - Ok(Async::NotReady) - } -} - -/// Enum of all the possible protocols our service handles. -enum FinalUpgrade { - Kad(KadConnecController, Box + Send>), - IdentifyListener(identify::IdentifySender), - IdentifyDialer(identify::IdentifyInfo, Multiaddr), - PingDialer(ping::protocol::PingDialer), - PingListener(ping::protocol::PingListener), - Custom(RegisteredProtocolSubstream), -} - -impl From> for FinalUpgrade { - fn from(out: ping::protocol::PingOutput) -> Self { - match out { - ping::protocol::PingOutput::Ponger(ponger) => FinalUpgrade::PingListener(ponger), - ping::protocol::PingOutput::Pinger(pinger) => FinalUpgrade::PingDialer(pinger), - } - } -} - -impl From> for FinalUpgrade { - fn from(out: identify::IdentifyOutput) -> Self { - match out { - identify::IdentifyOutput::RemoteInfo { info, observed_addr } => - FinalUpgrade::IdentifyDialer(info, observed_addr), - identify::IdentifyOutput::Sender { sender } => - FinalUpgrade::IdentifyListener(sender), - } - } -} diff --git a/substrate/core/network-libp2p/src/service_task.rs b/substrate/core/network-libp2p/src/service_task.rs index 5fd03caa4b..0a6b094408 100644 --- a/substrate/core/network-libp2p/src/service_task.rs +++ b/substrate/core/network-libp2p/src/service_task.rs @@ -14,36 +14,26 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +use crate::{behaviour::Behaviour, custom_proto::CustomProtosOut, secret::obtain_private_key, transport}; use bytes::Bytes; use custom_proto::{RegisteredProtocol, RegisteredProtocols}; -use fnv::{FnvHashMap, FnvHashSet}; -use futures::{prelude::*, task, Stream}; -use futures::sync::{oneshot, mpsc}; +use fnv::FnvHashMap; +use futures::{prelude::*, Stream}; use libp2p::{Multiaddr, PeerId}; -use libp2p::core::{Endpoint, PublicKey}; +use libp2p::core::{Swarm, nodes::Substream, transport::boxed::Boxed, muxing::StreamMuxerBox}; use libp2p::core::nodes::ConnectedPoint; -use libp2p::kad::{KadSystem, KadSystemConfig, KadConnecController, KadPeer}; -use libp2p::kad::{KadConnectionType, KadQueryEvent}; -use parking_lot::Mutex; -use rand; -use secret::obtain_private_key; +use std::collections::hash_map::Entry; use std::fs; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use std::iter; use std::net::SocketAddr; use std::path::Path; -use std::sync::Arc; -use std::time::{Duration, Instant}; -use swarm::{self, Swarm, SwarmEvent}; -use topology::{DisconnectReason, NetTopology}; -use tokio_timer::{Delay, Interval}; -use {Error, ErrorKind, NetworkConfiguration, NodeIndex, parse_str_addr}; -use {NonReservedPeerMode, ProtocolId}; +use std::time::Duration; +use topology::NetTopology; +use tokio_timer::Interval; +use {Error, NetworkConfiguration, NodeIndex, ProtocolId, parse_str_addr}; // File where the network topology is stored. const NODES_FILE: &str = "nodes.json"; -// Duration during which a peer is disabled. -const PEER_DISABLE_DURATION: Duration = Duration::from_secs(5 * 60); /// Starts the substrate libp2p service. /// @@ -55,7 +45,7 @@ pub fn start_service( where TProtos: IntoIterator { if let Some(ref path) = config.net_config_path { - fs::create_dir_all(Path::new(path))?; + fs::create_dir_all(Path::new(path))?; } // Private and public keys configuration. @@ -63,133 +53,90 @@ where TProtos: IntoIterator { let local_public_key = local_private_key.to_public_key(); let local_peer_id = local_public_key.clone().into_peer_id(); - // Build the swarm. - let registered_custom = RegisteredProtocols(registered_custom.into_iter().collect()); - let mut swarm = swarm::start_swarm(registered_custom, local_private_key)?; - - // Listen on multiaddresses. - for addr in &config.listen_addresses { - match swarm.listen_on(addr.clone()) { - Ok(new_addr) => debug!(target: "sub-libp2p", "Libp2p listening on {}", new_addr), - Err(_) => { - warn!(target: "sub-libp2p", "Can't listen on {}, protocol not supported", addr); - return Err(ErrorKind::BadProtocol.into()) - }, - } - } - - // Register the external addresses provided by the user. - for addr in &config.public_addresses { - swarm.add_external_address(addr.clone()); - } - // Initialize the topology of the network. let mut topology = if let Some(ref path) = config.net_config_path { let path = Path::new(path).join(NODES_FILE); debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path); - NetTopology::from_file(path) + NetTopology::from_file(local_public_key, path) } else { debug!(target: "sub-libp2p", "No peers file configured ; peers won't be saved"); - NetTopology::memory() + NetTopology::memory(local_public_key) }; - // Create the Kademlia system, containing the kbuckets. - let kad_system = KadSystem::without_init(KadSystemConfig { - parallelism: 3, - local_peer_id, - kbuckets_timeout: Duration::from_secs(600), - request_timeout: Duration::from_secs(10), - known_initial_peers: iter::empty(), - }); + // Register the external addresses provided by the user as our own. + topology.add_external_addrs(config.public_addresses.clone().into_iter()); + + // Build the swarm. + let mut swarm = { + let registered_custom = RegisteredProtocols(registered_custom.into_iter().collect()); + let behaviour = Behaviour::new(&config, local_peer_id.clone(), registered_custom); + let transport = transport::build_transport(local_private_key); + Swarm::new(transport, behaviour, topology) + }; + + // Listen on multiaddresses. + for addr in &config.listen_addresses { + match Swarm::listen_on(&mut swarm, addr.clone()) { + Ok(new_addr) => debug!(target: "sub-libp2p", "Libp2p listening on {}", new_addr), + Err(err) => warn!(target: "sub-libp2p", "Can't listen on {} because: {:?}", addr, err) + } + } // Add the bootstrap nodes to the topology and connect to them. for bootnode in config.boot_nodes.iter() { match parse_str_addr(bootnode) { Ok((peer_id, addr)) => { - topology.add_bootstrap_addr(&peer_id, addr.clone()); - kad_system.update_kbuckets(peer_id.clone()); - if let Err(_) = swarm.ensure_connection(peer_id, addr) { - warn!(target: "sub-libp2p", "Failed to dial boot node: {}", bootnode); - } + Swarm::topology_mut(&mut swarm).add_bootstrap_addr(&peer_id, addr.clone()); + Swarm::dial(&mut swarm, peer_id); }, Err(_) => { // If the format of the bootstrap node is not a multiaddr, try to parse it as // a `SocketAddr`. This corresponds to the format `IP:PORT`. - let addr = match bootnode.parse::() { + let addr = match bootnode.parse::() { Ok(SocketAddr::V4(socket)) => multiaddr![Ip4(*socket.ip()), Tcp(socket.port())], Ok(SocketAddr::V6(socket)) => multiaddr![Ip6(*socket.ip()), Tcp(socket.port())], _ => { warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode); - continue; + continue } }; - debug!(target: "sub-libp2p", "Dialing {} with no peer id", addr); - if let Err(addr) = swarm.dial(addr) { - warn!(target: "sub-libp2p", "Bootstrap address not supported: {}", addr); + info!(target: "sub-libp2p", "Dialing {} with no peer id. Keep in mind that doing \ + so is vulnerable to man-in-the-middle attacks.", addr); + if let Err(addr) = Swarm::dial_addr(&mut swarm, addr) { + warn!(target: "sub-libp2p", "Bootstrap address not supported: {}", addr) } }, } } // Initialize the reserved peers. - let mut reserved_peers = FnvHashSet::default(); for reserved in config.reserved_nodes.iter() { - match parse_str_addr(reserved) { - Ok((peer_id, addr)) => { - reserved_peers.insert(peer_id.clone()); - topology.add_bootstrap_addr(&peer_id, addr.clone()); - if let Err(_) = swarm.ensure_connection(peer_id, addr) { - warn!(target: "sub-libp2p", "Failed to dial reserved node: {}", reserved); - } - }, - Err(_) => - // TODO: also handle the `IP:PORT` format ; however we need to somehow add the - // reserved ID to `reserved_peers` at some point - warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved), + if let Ok((peer_id, addr)) = parse_str_addr(reserved) { + Swarm::topology_mut(&mut swarm).add_bootstrap_addr(&peer_id, addr); + swarm.add_reserved_peer(peer_id.clone()); + 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", topology.num_peers()); - - let (kad_new_ctrl_req_tx, kad_new_ctrl_req_rx) = mpsc::unbounded(); + debug!(target: "sub-libp2p", "Topology started with {} entries", + Swarm::topology_mut(&mut swarm).num_peers()); Ok(Service { swarm, - max_incoming_connections: config.in_peers as usize, - max_outgoing_connections: config.out_peers as usize, - topology, nodes_addresses: Default::default(), - disabled_peers: Default::default(), - reserved_peers, - reserved_only: config.non_reserved_mode == NonReservedPeerMode::Deny, - kad_system, - kad_pending_ctrls: Default::default(), - kad_new_ctrl_req_tx, - kad_new_ctrl_req_rx, - kad_queries: Vec::with_capacity(1), - next_connect_to_nodes: Delay::new(Instant::now()), - next_kad_random_query: Interval::new(Instant::now() + Duration::from_secs(5), Duration::from_secs(45)), + index_by_id: Default::default(), + next_node_id: 1, cleanup: Interval::new_interval(Duration::from_secs(60)), injected_events: Vec::new(), - to_notify: None, }) } /// Event produced by the service. #[derive(Debug)] pub enum ServiceEvent { - /// Closed connection to a node. - /// - /// It is guaranteed that this node has been opened with a `NewNode` event beforehand. However - /// not all `ClosedCustomProtocol` events have been dispatched. - NodeClosed { - /// Index of the node. - node_index: NodeIndex, - /// List of custom protocols that were still open. - closed_custom_protocols: Vec, - }, - /// A custom protocol substream has been opened with a node. OpenedCustomProtocol { /// Index of the node. @@ -232,53 +179,16 @@ pub enum ServiceEvent { /// Network service. Must be polled regularly in order for the networking to work. pub struct Service { /// Stream of events of the swarm. - swarm: Swarm, - - /// Maximum number of incoming non-reserved connections, taken from the config. - max_incoming_connections: usize, - - /// Maximum number of outgoing non-reserved connections, taken from the config. - max_outgoing_connections: usize, + swarm: Swarm, Behaviour>, NetTopology>, /// For each node we're connected to, how we're connected to it. - nodes_addresses: FnvHashMap, + nodes_addresses: FnvHashMap, - /// If true, only reserved peers can connect. - reserved_only: bool, + /// Opposite of `nodes_addresses`. + index_by_id: FnvHashMap, - /// List of the IDs of the reserved peers. - reserved_peers: FnvHashSet, - - /// List of the IDs of disabled peers, and when the ban expires. - /// Purged at a regular interval. - disabled_peers: FnvHashMap, - - /// Topology of the network. - topology: NetTopology, - - /// Handles the Kademlia queries. - // TODO: put the kbuckets in the topology instead - kad_system: KadSystem, - - /// List of Kademlia controller we want to open. - /// - /// A clone of tihs `Arc` is stored in each Kademlia query stream. - // TODO: use a better container? - kad_pending_ctrls: Arc>>>>, - - /// Sender whenever we inserted an entry in `kad_pending_ctrls`, so that we can process it. - kad_new_ctrl_req_tx: mpsc::UnboundedSender, - /// Receiver side of `kad_new_ctrl_req_tx`. - kad_new_ctrl_req_rx: mpsc::UnboundedReceiver, - - /// Active Kademlia queries. - kad_queries: Vec>, Error = IoError> + Send>>, - - /// Future that will fire when we need to connect to new nodes. - next_connect_to_nodes: Delay, - - /// Stream that fires when we need to perform the next Kademlia query. - next_kad_random_query: Interval, + /// 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. @@ -286,22 +196,19 @@ pub struct Service { /// Events to produce on the Stream. injected_events: Vec, - - /// Task to notify when elements are added to `injected_events`. - to_notify: Option, } impl Service { - /// Returns an iterator that produces the list of addresses we're listening on. + /// Returns an iterator that produces the list of addresses we're listening on. #[inline] pub fn listeners(&self) -> impl Iterator { - self.swarm.listeners() + Swarm::listeners(&self.swarm) } /// Returns the peer id of the local node. #[inline] pub fn peer_id(&self) -> &PeerId { - self.kad_system.local_peer_id() + Swarm::local_peer_id(&self.swarm) } /// Returns the list of all the peers we are connected to. @@ -312,76 +219,57 @@ impl Service { /// Try to add a reserved peer. pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) { - self.reserved_peers.insert(peer_id.clone()); - self.topology.add_bootstrap_addr(&peer_id, addr.clone()); - let _ = self.swarm.ensure_connection(peer_id, addr); + Swarm::topology_mut(&mut self.swarm).add_bootstrap_addr(&peer_id, addr); + self.swarm.add_reserved_peer(peer_id); } /// 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) -> Option { - self.reserved_peers.remove(&peer_id); - if self.reserved_only { - if let Some(node_index) = self.swarm.latest_node_by_peer_id(&peer_id) { - self.drop_node_inner(node_index, DisconnectReason::NoSlot, None); - return Some(node_index); - } - } - None + /// 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) { - if self.reserved_only { - self.reserved_only = false; - self.connect_to_nodes(); - } + self.swarm.accept_unreserved_peers(); } - /// Start refusing non-reserved nodes. Returns the list of nodes that have been disconnected. - pub fn deny_unreserved_peers(&mut self) -> Vec { - self.reserved_only = true; - - // Disconnect the nodes that are not reserved. - let to_disconnect: Vec = self.swarm - .nodes() - .filter(|&n| { - let peer_id = self.swarm.peer_id_of_node(n) - .expect("swarm.nodes() always returns valid node indices"); - !self.reserved_peers.contains(peer_id) - }) - .collect(); - - for &node_index in &to_disconnect { - self.drop_node_inner(node_index, DisconnectReason::NoSlot, None); - } - - to_disconnect + /// 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> { - self.swarm.peer_id_of_node(node_index) + self.nodes_addresses.get(&node_index).map(|(id, _)| id) } /// Returns the way we are connected to a node. #[inline] pub fn node_endpoint(&self, node_index: NodeIndex) -> Option<&ConnectedPoint> { - self.nodes_addresses.get(&node_index) + self.nodes_addresses.get(&node_index).map(|(_, cp)| cp) } /// Sends a message to a peer using the custom protocol. - // TODO: report invalid node index or protocol? + /// + /// Has no effect if the connection to the node has been closed, or if the node index is + /// invalid. pub fn send_custom_message( &mut self, node_index: NodeIndex, protocol: ProtocolId, data: Vec ) { - self.swarm.send_custom_message(node_index, protocol, data) + if let Some(peer_id) = self.nodes_addresses.get(&node_index).map(|(id, _)| id) { + self.swarm.send_custom_message(peer_id, protocol, data); + } else { + warn!(target: "sub-libp2p", "Tried to send message to unknown node: {:}", node_index); + } } /// Disconnects a peer and bans it for a little while. @@ -389,11 +277,10 @@ impl Service { /// 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(peer_id) = self.swarm.peer_id_of_node(node_index) { - info!(target: "sub-libp2p", "Banned {:?}", peer_id); + if let Some(peer_id) = self.nodes_addresses.get(&node_index).map(|(id, _)| id) { + info!(target: "sub-libp2p", "Banned {:?} (#{:?})", peer_id, node_index); + self.swarm.ban_node(peer_id.clone()); } - - self.drop_node_inner(node_index, DisconnectReason::Banned, Some(PEER_DISABLE_DURATION)); } /// Disconnects a peer. @@ -402,526 +289,62 @@ impl Service { /// Corresponding closing events will be generated once the closing actually happens. #[inline] pub fn drop_node(&mut self, node_index: NodeIndex) { - if let Some(peer_id) = self.swarm.peer_id_of_node(node_index) { - info!(target: "sub-libp2p", "Dropped {:?}", peer_id); - } - - self.drop_node_inner(node_index, DisconnectReason::Useless, None); - } - - /// Common implementation of `drop_node` and `ban_node`. - fn drop_node_inner( - &mut self, - node_index: NodeIndex, - reason: DisconnectReason, - disable_duration: Option - ) { - let peer_id = match self.swarm.peer_id_of_node(node_index) { - Some(pid) => pid.clone(), - None => return, // TODO: report? - }; - - // Kill the node from the swarm, and inject an event about it. - let closed_custom_protocols = self.swarm.drop_node(node_index) - .expect("we checked right above that node is valid"); - self.injected_events.push(ServiceEvent::NodeClosed { - node_index, - closed_custom_protocols, - }); - - if let Some(to_notify) = self.to_notify.take() { - to_notify.notify(); - } - - if let Some(ConnectedPoint::Dialer { address }) = self.nodes_addresses.remove(&node_index) { - self.topology.report_disconnected(&address, reason); - } - - if let Some(disable_duration) = disable_duration { - let timeout = Instant::now() + disable_duration; - self.disabled_peers.insert(peer_id, timeout); - } - - self.connect_to_nodes(); - } - - /// Counts the number of non-reserved ingoing connections. - fn num_ingoing_connections(&self) -> usize { - self.swarm.nodes() - .filter(|&i| self.swarm.node_endpoint(i) == Some(Endpoint::Listener) && - !self.reserved_peers.contains(&self.swarm.peer_id_of_node(i).unwrap())) - .count() - } - - /// Counts the number of non-reserved outgoing connections. - fn num_outgoing_connections(&self) -> usize { - self.swarm.nodes() - .filter(|&i| self.swarm.node_endpoint(i) == Some(Endpoint::Dialer) && - !self.reserved_peers.contains(&self.swarm.peer_id_of_node(i).unwrap())) - .count() - } - - /// Updates the attempted connections to nodes. - /// - /// Also updates `next_connect_to_nodes` with the earliest known moment when we need to - /// update connections again. - fn connect_to_nodes(&mut self) { - // Make sure we are connected or connecting to all the reserved nodes. - for reserved in self.reserved_peers.iter() { - let addrs = self.topology.addrs_of_peer(&reserved); - for (addr, _) in addrs { - let _ = self.swarm.ensure_connection(reserved.clone(), addr.clone()); - } - } - - // Counter of number of connections to open, decreased when we open one. - let mut num_to_open = self.max_outgoing_connections - self.num_outgoing_connections(); - - let (to_try, will_change) = self.topology.addrs_to_attempt(); - for (peer_id, addr) in to_try { - if num_to_open == 0 { - break; - } - - if peer_id == self.kad_system.local_peer_id() { - continue; - } - - if self.disabled_peers.contains_key(&peer_id) { - continue; - } - - // It is possible that we are connected to this peer, but the topology doesn't know - // about that because it is an incoming connection. - match self.swarm.ensure_connection(peer_id.clone(), addr.clone()) { - Ok(true) => (), - Ok(false) => num_to_open -= 1, - Err(_) => () - } - } - - self.next_connect_to_nodes.reset(will_change); - } - - /// Starts a random Kademlia query in order to fill the topology. - /// - /// Query the node IDs that are closest to a random ID. - /// Note that the randomness doesn't have to be secure, as this only influences which nodes we - /// end up being connected to. - fn perform_kad_random_query(&mut self) { - let random_key = PublicKey::Ed25519((0 .. 32) - .map(|_| -> u8 { rand::random() }).collect()); - let random_peer_id = random_key.into_peer_id(); - debug!(target: "sub-libp2p", "Start random Kademlia query for {:?}", random_peer_id); - - let kad_pending_ctrls = self.kad_pending_ctrls.clone(); - let kad_new_ctrl_req_tx = self.kad_new_ctrl_req_tx.clone(); - let stream = self.kad_system - .find_node(random_peer_id, move |who| { - let (tx, rx) = oneshot::channel(); - let mut kad_pending_ctrls = kad_pending_ctrls.lock(); - kad_pending_ctrls.entry(who.clone()).or_insert(Vec::new()).push(tx); - let _ = kad_new_ctrl_req_tx.unbounded_send(who.clone()); - rx.map_err(|_| IoError::new(IoErrorKind::Other, "Couldn't reach peer")) - }); - - self.kad_queries.push(Box::new(stream)); - } - - /// If a remote performs a `FIND_NODE` Kademlia request for `searched`, this function builds - /// the response to send back. - fn build_kademlia_response(&self, searched: &PeerId) -> Vec { - self.kad_system - .known_closest_peers(searched) - .map(|who| { - if who == *self.kad_system.local_peer_id() { - KadPeer { - node_id: who.clone(), - multiaddrs: self.swarm.external_addresses().cloned().collect(), - connection_ty: KadConnectionType::Connected, - } - } else { - let mut addrs = self.topology.addrs_of_peer(&who) - .map(|(a, c)| (a.clone(), c)) - .collect::>(); - let connected = addrs.iter().any(|&(_, conn)| conn); - // The Kademlia protocol of libp2p doesn't allow specifying which address is valid - // and which is outdated, therefore in order to stay honest towards the network - // we only report the addresses we're connected to if we're connected to any. - if connected { - addrs.retain(|&(_, connected)| connected); - } - - KadPeer { - node_id: who.clone(), - multiaddrs: addrs.into_iter().map(|(a, _)| a).collect(), - connection_ty: if connected { - KadConnectionType::Connected - } else { - KadConnectionType::NotConnected - }, - } - } - }) - // TODO: we really want to remove nodes with no multiaddress from - // the results, but a flaw in the Kad protocol of libp2p makes it - // impossible to return empty results ; therefore we must at least - // return ourselves - .filter(|p| p.node_id == *self.kad_system.local_peer_id() || !p.multiaddrs.is_empty()) - .take(20) - .collect::>() - } - - /// Adds a list of peers to the network topology. - fn add_discovered_peers(&mut self, list: impl IntoIterator) { - let mut topology_has_changed = false; - - for peer in list { - let connected = match peer.connection_ty { - KadConnectionType::NotConnected => false, - KadConnectionType::Connected => true, - KadConnectionType::CanConnect => true, - KadConnectionType::CannotConnect => continue, - }; - - let changed = self.topology.add_kademlia_discovered_addrs( - &peer.node_id, - peer.multiaddrs.iter().map(|a| (a.clone(), connected)) - ); - - if changed { - topology_has_changed = true; - } - } - - // Potentially connect to the newly-discovered nodes. - if topology_has_changed { - self.connect_to_nodes(); + if let Some(peer_id) = self.nodes_addresses.get(&node_index).map(|(id, _)| id) { + debug!(target: "sub-libp2p", "Dropping {:?} on purpose (#{:?})", peer_id, node_index); + self.swarm.drop_node(peer_id); } } - /// Handles the swarm opening a connection to the given peer. - /// - /// > **Note**: Must be called from inside `poll()`, otherwise it will panic. - fn handle_connection( - &mut self, - node_index: NodeIndex, - peer_id: PeerId, - endpoint: ConnectedPoint - ) { - // Reject connections to our own node, which can happen if the DHT contains `127.0.0.1` - // for example. - if &peer_id == self.kad_system.local_peer_id() { - debug!(target: "sub-libp2p", "Rejected connection to/from ourself: {:?}", endpoint); - assert_eq!(self.swarm.drop_node(node_index), Ok(Vec::new())); - if let ConnectedPoint::Dialer { ref address } = endpoint { - self.topology.report_failed_to_connect(address); - } - return; - } - - // Reject non-reserved nodes if we're in reserved mode. - let is_reserved = self.reserved_peers.contains(&peer_id); - if self.reserved_only && !is_reserved { - debug!(target: "sub-libp2p", "Rejected non-reserved peer {:?}", peer_id); - assert_eq!(self.swarm.drop_node(node_index), Ok(Vec::new())); - if let ConnectedPoint::Dialer { ref address } = endpoint { - self.topology.report_failed_to_connect(address); - } - return; - } - - // Reject connections from disabled peers. - if let Some(expires) = self.disabled_peers.get(&peer_id) { - if expires > &Instant::now() { - info!(target: "sub-libp2p", "Rejected connection from disabled peer: {:?}", peer_id); - assert_eq!(self.swarm.drop_node(node_index), Ok(Vec::new())); - if let ConnectedPoint::Dialer { ref address } = endpoint { - self.topology.report_failed_to_connect(address); - } - return; - } - } - - match endpoint { - ConnectedPoint::Listener { ref listen_addr, ref send_back_addr } => { - if is_reserved || self.num_ingoing_connections() < self.max_incoming_connections { - debug!(target: "sub-libp2p", "Connected to {:?} through {} on listener {}", - peer_id, send_back_addr, listen_addr); - } else { - info!(target: "sub-libp2p", "Rejected incoming peer {:?} because we are full", peer_id); - assert_eq!(self.swarm.drop_node(node_index), Ok(Vec::new())); - return; - } + /// Returns the `NodeIndex` of a peer, or assigns one if none exists. + fn index_of_peer_or_assign(&mut self, peer: PeerId, endpoint: ConnectedPoint) -> NodeIndex { + match self.index_by_id.entry(peer) { + Entry::Occupied(entry) => { + let id = *entry.get(); + self.nodes_addresses.insert(id, (entry.key().clone(), endpoint)); + id }, - ConnectedPoint::Dialer { ref address } => { - if is_reserved || self.num_outgoing_connections() < self.max_outgoing_connections { - debug!(target: "sub-libp2p", "Connected to {:?} through {}", peer_id, address); - self.topology.report_connected(address, &peer_id); - } else { - debug!(target: "sub-libp2p", "Rejected dialed peer {:?} because we are full", peer_id); - assert_eq!(self.swarm.drop_node(node_index), Ok(Vec::new())); - return; - } - }, - }; - - if let Err(_) = self.swarm.accept_node(node_index) { - error!(target: "sub-libp2p", "accept_node returned an error"); - } - - // We are finally sure that we're connected. - - if let ConnectedPoint::Dialer { ref address } = endpoint { - self.topology.report_connected(address, &peer_id); - } - self.nodes_addresses.insert(node_index, endpoint.clone()); - - // If we're waiting for a Kademlia substream for this peer id, open one. - let kad_pending_ctrls = self.kad_pending_ctrls.lock(); - if kad_pending_ctrls.contains_key(&peer_id) { - let res = self.swarm.open_kademlia(node_index); - debug_assert!(res.is_ok()); - } - } - - /// Processes an event received by the swarm. - /// - /// Optionally returns an event to report back to the outside. - /// - /// > **Note**: Must be called from inside `poll()`, otherwise it will panic. - fn process_network_event( - &mut self, - event: SwarmEvent - ) -> Option { - match event { - SwarmEvent::NodePending { node_index, peer_id, endpoint } => { - self.handle_connection(node_index, peer_id, endpoint); - None - }, - SwarmEvent::Reconnected { node_index, endpoint, closed_custom_protocols } => { - if let Some(ConnectedPoint::Dialer { address }) = self.nodes_addresses.remove(&node_index) { - self.topology.report_disconnected(&address, DisconnectReason::FoundBetterAddr); - } - if let ConnectedPoint::Dialer { ref address } = endpoint { - let peer_id = self.swarm.peer_id_of_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - self.topology.report_connected(address, peer_id); - } - self.nodes_addresses.insert(node_index, endpoint); - Some(ServiceEvent::ClosedCustomProtocols { - node_index, - protocols: closed_custom_protocols, - }) - }, - SwarmEvent::NodeClosed { node_index, peer_id, closed_custom_protocols } => { - debug!(target: "sub-libp2p", "Connection to {:?} closed gracefully", peer_id); - if let Some(ConnectedPoint::Dialer { ref address }) = self.nodes_addresses.get(&node_index) { - self.topology.report_disconnected(address, DisconnectReason::RemoteClosed); - } - self.connect_to_nodes(); - Some(ServiceEvent::NodeClosed { - node_index, - closed_custom_protocols, - }) - }, - SwarmEvent::DialFail { address, error } => { - debug!(target: "sub-libp2p", "Failed to dial address {}: {:?}", address, error); - self.topology.report_failed_to_connect(&address); - self.connect_to_nodes(); - None - }, - SwarmEvent::UnresponsiveNode { node_index } => { - let closed_custom_protocols = self.swarm.drop_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - if let Some(ConnectedPoint::Dialer { address }) = self.nodes_addresses.remove(&node_index) { - self.topology.report_disconnected(&address, DisconnectReason::Useless); - } - Some(ServiceEvent::NodeClosed { - node_index, - closed_custom_protocols, - }) - }, - SwarmEvent::UselessNode { node_index } => { - let peer_id = self.swarm.peer_id_of_node(node_index) - .expect("the swarm always produces events containing valid node indices") - .clone(); - let closed_custom_protocols = self.swarm.drop_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - self.topology.report_useless(&peer_id); - if let Some(ConnectedPoint::Dialer { address }) = self.nodes_addresses.remove(&node_index) { - self.topology.report_disconnected(&address, DisconnectReason::Useless); - } - Some(ServiceEvent::NodeClosed { - node_index, - closed_custom_protocols, - }) - }, - SwarmEvent::NodeInfos { node_index, listen_addrs, .. } => { - let peer_id = self.swarm.peer_id_of_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - self.topology.add_self_reported_listen_addrs( - peer_id, - listen_addrs.into_iter() - ); - None - }, - SwarmEvent::KadFindNode { searched, responder, .. } => { - let response = self.build_kademlia_response(&searched); - responder.respond(response); - None - }, - SwarmEvent::KadOpen { node_index, controller } => { - let peer_id = self.swarm.peer_id_of_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - trace!(target: "sub-libp2p", "Opened Kademlia substream with {:?}", peer_id); - if let Some(list) = self.kad_pending_ctrls.lock().remove(&peer_id) { - for tx in list { - let _ = tx.send(controller.clone()); - } - } - None - }, - SwarmEvent::KadClosed { .. } => { - None - }, - SwarmEvent::OpenedCustomProtocol { node_index, protocol, version } => { - let peer_id = self.swarm.peer_id_of_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - self.kad_system.update_kbuckets(peer_id.clone()); - Some(ServiceEvent::OpenedCustomProtocol { - node_index, - protocol, - version, - }) - }, - SwarmEvent::ClosedCustomProtocol { node_index, protocol } => - Some(ServiceEvent::ClosedCustomProtocol { - node_index, - protocol, - }), - SwarmEvent::CustomMessage { node_index, protocol_id, data } => { - let peer_id = self.swarm.peer_id_of_node(node_index) - .expect("the swarm always produces events containing valid node indices"); - self.kad_system.update_kbuckets(peer_id.clone()); - Some(ServiceEvent::CustomMessage { - node_index, - protocol_id, - data, - }) + Entry::Vacant(entry) => { + let id = self.next_node_id; + self.next_node_id += 1; + self.nodes_addresses.insert(id, (entry.key().clone(), endpoint)); + entry.insert(id); + id }, } } - /// Handles a Kademlia query requesting a Kademlia controller with the given peer. - fn handle_kad_ctrl_request(&mut self, peer_id: PeerId) { - if let Some(node_index) = self.swarm.latest_node_by_peer_id(&peer_id) { - if let Err(_) = self.swarm.open_kademlia(node_index) { - self.kad_pending_ctrls.lock().remove(&peer_id); - } - } else { - let addrs = self.topology.addrs_of_peer(&peer_id); - let mut one_worked = false; - for (addr, _) in addrs { - if let Ok(_) = self.swarm.ensure_connection(peer_id.clone(), addr.clone()) { - one_worked = true; - } - } - if !one_worked { - debug!(target: "sub-libp2p", "Couldn't open Kad substream with {:?} \ - because no address is known", peer_id); - // Closing the senders in order to generate errors on the Kad query. - self.kad_pending_ctrls.lock().remove(&peer_id); - } - } - } - - /// Polls for what happened on the main network side. + /// Polls for what happened on the network. fn poll_swarm(&mut self) -> Poll, IoError> { loop { match self.swarm.poll() { - Ok(Async::Ready(Some(event))) => - if let Some(event) = self.process_network_event(event) { - return Ok(Async::Ready(Some(event))); - } - Ok(Async::NotReady) => return Ok(Async::NotReady), + Ok(Async::Ready(Some(CustomProtosOut::CustomProtocolOpen { protocol_id, 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, endpoint); + break Ok(Async::Ready(Some(ServiceEvent::OpenedCustomProtocol { + node_index, + protocol: protocol_id, + version, + }))) + } + Ok(Async::Ready(Some(CustomProtosOut::CustomProtocolClosed { protocol_id, peer_id, result }))) => { + debug!(target: "sub-libp2p", "Custom protocol with {:?} closed: {:?}", peer_id, result); + 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, + protocol: protocol_id, + }))) + } + Ok(Async::Ready(Some(CustomProtosOut::CustomMessage { protocol_id, peer_id, data }))) => { + 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::CustomMessage { + node_index, + protocol_id, + data, + }))) + } + Ok(Async::NotReady) => break Ok(Async::NotReady), Ok(Async::Ready(None)) => unreachable!("The Swarm stream never ends"), - // TODO: this `Err` contains a `Void` ; remove variant when Rust allows that - Err(_) => unreachable!("The Swarm stream never errors"), - } - } - } - - /// Polls the Kademlia system. - fn poll_kademlia(&mut self) -> Poll, IoError> { - // Polls the active Kademlia queries. - // We remove each element from `kad_queries` one by one and add them back if not ready. - for n in (0 .. self.kad_queries.len()).rev() { - let mut query = self.kad_queries.swap_remove(n); - loop { - match query.poll() { - Ok(Async::Ready(Some(KadQueryEvent::PeersReported(list)))) => - self.add_discovered_peers(list), - // We don't actually care about the results - Ok(Async::Ready(Some(KadQueryEvent::Finished(_out)))) => { - if _out.is_empty() { - warn!(target: "sub-libp2p", "Random Kademlia request has yielded \ - empty results"); - } - break - }, - Ok(Async::Ready(None)) => break, - Ok(Async::NotReady) => { - self.kad_queries.push(query); - break; - }, - Err(err) => { - warn!(target: "sub-libp2p", "Kademlia query failed: {:?}", err); - break; - }, - } - } - } - - // Poll the future that fires when we need to reply to a Kademlia query. - loop { - match self.kad_new_ctrl_req_rx.poll() { - Ok(Async::NotReady) => break, - Ok(Async::Ready(Some(peer_id))) => self.handle_kad_ctrl_request(peer_id), - Ok(Async::Ready(None)) => unreachable!("The tx is in self"), - Err(()) => unreachable!("An UnboundedReceiver never errors"), - } - } - - // Poll the future that fires when we need to perform a random Kademlia query. - loop { - match self.next_kad_random_query.poll() { - Ok(Async::NotReady) => break, - Ok(Async::Ready(Some(_))) => self.perform_kad_random_query(), - Ok(Async::Ready(None)) => { - warn!(target: "sub-libp2p", "Kad query timer closed unexpectedly"); - return Ok(Async::Ready(None)); - } - Err(err) => { - warn!(target: "sub-libp2p", "Kad query timer errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)); - } - } - } - - Ok(Async::NotReady) - } - - // Polls the future that fires when we need to refresh our connections. - fn poll_next_connect_refresh(&mut self) -> Poll, IoError> { - loop { - match self.next_connect_to_nodes.poll() { - Ok(Async::Ready(())) => self.connect_to_nodes(), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(err) => { - warn!(target: "sub-libp2p", "Connect to nodes timer errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)); - } + Err(_) => unreachable!("The Swarm never errors"), } } } @@ -933,22 +356,20 @@ impl Service { Ok(Async::NotReady) => return Ok(Async::NotReady), Ok(Async::Ready(Some(_))) => { debug!(target: "sub-libp2p", "Cleaning and flushing topology"); - self.topology.cleanup(); - if let Err(err) = self.topology.flush_to_disk() { + Swarm::topology_mut(&mut self.swarm).cleanup(); + if let Err(err) = Swarm::topology_mut(&mut self.swarm).flush_to_disk() { warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err); } - let now = Instant::now(); - self.disabled_peers.retain(move |_, v| *v < now); debug!(target: "sub-libp2p", "Topology now contains {} nodes", - self.topology.num_peers()); + Swarm::topology_mut(&mut self.swarm).num_peers()); }, Ok(Async::Ready(None)) => { warn!(target: "sub-libp2p", "Topology flush stream ended unexpectedly"); - return Ok(Async::Ready(None)); + return Ok(Async::Ready(None)) } Err(err) => { warn!(target: "sub-libp2p", "Topology flush stream errored: {:?}", err); - return Err(IoError::new(IoErrorKind::Other, err)); + return Err(IoError::new(IoErrorKind::Other, err)) } } } @@ -957,7 +378,7 @@ impl Service { impl Drop for Service { fn drop(&mut self) { - if let Err(err) = self.topology.flush_to_disk() { + if let Err(err) = Swarm::topology_mut(&mut self.swarm).flush_to_disk() { warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err); } } @@ -977,16 +398,6 @@ impl Stream for Service { Async::NotReady => (), } - match self.poll_kademlia()? { - Async::Ready(value) => return Ok(Async::Ready(value)), - Async::NotReady => (), - } - - match self.poll_next_connect_refresh()? { - Async::Ready(value) => return Ok(Async::Ready(value)), - Async::NotReady => (), - } - match self.poll_cleanup()? { Async::Ready(value) => return Ok(Async::Ready(value)), Async::NotReady => (), @@ -994,7 +405,6 @@ impl Stream for Service { // The only way we reach this is if we went through all the `NotReady` paths above, // ensuring the current task is registered everywhere. - self.to_notify = Some(task::current()); Ok(Async::NotReady) } } diff --git a/substrate/core/network-libp2p/src/swarm.rs b/substrate/core/network-libp2p/src/swarm.rs deleted file mode 100644 index 0a6bfaa994..0000000000 --- a/substrate/core/network-libp2p/src/swarm.rs +++ /dev/null @@ -1,672 +0,0 @@ -// Copyright 2018 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 . - -use bytes::Bytes; -use custom_proto::RegisteredProtocols; -use fnv::FnvHashMap; -use futures::{prelude::*, Stream}; -use libp2p::{Multiaddr, multiaddr::Protocol, PeerId}; -use libp2p::core::{muxing, Endpoint, PublicKey}; -use libp2p::core::nodes::{ConnectedPoint, RawSwarm, RawSwarmEvent, Peer as SwarmPeer, Substream}; -use libp2p::core::transport::boxed::Boxed; -use libp2p::kad::{KadConnecController, KadFindNodeRespond}; -use libp2p::secio; -use node_handler::{SubstrateOutEvent, SubstrateNodeHandler, SubstrateInEvent, IdentificationRequest}; -use std::{io, mem, sync::Arc}; -use transport; -use {Error, NodeIndex, ProtocolId}; - -/// Starts a swarm. -/// -/// Returns a stream that must be polled regularly in order for the networking to function. -pub fn start_swarm( - registered_custom: RegisteredProtocols, - local_private_key: secio::SecioKeyPair, -) -> Result { - // Private and public keys. - let local_public_key = local_private_key.to_public_key(); - let local_peer_id = local_public_key.clone().into_peer_id(); - - // Build the transport layer. This is what allows us to listen or to reach nodes. - let transport = transport::build_transport(local_private_key); - - // Build the underlying libp2p swarm. - let swarm = RawSwarm::new(transport); - - Ok(Swarm { - swarm, - registered_custom: Arc::new(registered_custom), - local_public_key, - local_peer_id, - listening_addrs: Vec::new(), - node_by_peer: Default::default(), - nodes_info: Default::default(), - next_node_index: 0, - }) -} - -/// Event produced by the swarm. -pub enum SwarmEvent { - /// We have successfully connected to a node. - /// - /// The node is in pending node, and should be accepted by calling `accept_node(node_index)` - /// or denied by calling `drop_node(node_index)`. - NodePending { - /// Index of the node. - node_index: NodeIndex, - /// Public key of the node as a peer id. - peer_id: PeerId, - /// Whether we dialed the node or if it came to us. - endpoint: ConnectedPoint, - }, - - /// The connection to a peer has changed. - Reconnected { - /// Index of the node. - node_index: NodeIndex, - /// The new endpoint. - endpoint: ConnectedPoint, - /// List of custom protocols that were closed in the process. - closed_custom_protocols: Vec, - }, - - /// Closed connection to a node, either gracefully or because of an error. - /// - /// It is guaranteed that this node has been opened with a `NewNode` event beforehand. However - /// not all `ClosedCustomProtocol` events have been dispatched. - NodeClosed { - /// Index of the node. - node_index: NodeIndex, - /// Peer id we were connected to. - peer_id: PeerId, - /// List of custom protocols that were still open. - closed_custom_protocols: Vec, - }, - - /// Failed to dial an address. - DialFail { - /// Address that failed. - address: Multiaddr, - /// Reason why we failed. - error: io::Error, - }, - - /// Report information about the node. - NodeInfos { - /// Index of the node. - node_index: NodeIndex, - /// The client version. Note that it can be anything and should not be trusted. - client_version: String, - /// Multiaddresses the node is listening on. - listen_addrs: Vec, - }, - - /// A custom protocol substream has been opened with a node. - OpenedCustomProtocol { - /// Index of the node. - node_index: NodeIndex, - /// Protocol that has been opened. - protocol: ProtocolId, - /// Version of the protocol that was opened. - version: u8, - }, - - /// A custom protocol substream has been closed. - ClosedCustomProtocol { - /// Index of the node. - node_index: NodeIndex, - /// Protocol that has been closed. - protocol: ProtocolId, - }, - - /// Receives a message on a custom protocol stream. - CustomMessage { - /// Index of the node. - node_index: NodeIndex, - /// Protocol which generated the message. - protocol_id: ProtocolId, - /// Data that has been received. - data: Bytes, - }, - - /// The node has been determined to be unresponsive. - UnresponsiveNode { - /// Index of the node. - node_index: NodeIndex, - }, - - /// The node works but we can't do anything useful with it. - UselessNode { - /// Index of the node. - node_index: NodeIndex, - }, - - /// Opened a Kademlia substream with the node. - // TODO: the controller API is bad, but we need to make changes in libp2p to improve that - KadOpen { - /// Index of the node. - node_index: NodeIndex, - /// The Kademlia controller. Allows making queries. - controller: KadConnecController, - }, - - /// The remote wants us to answer a Kademlia `FIND_NODE` request. - /// - /// The `responder` should be used to answer that query. - // TODO: this API with the "responder" is bad, but changing it requires modifications in libp2p - KadFindNode { - /// Index of the node that wants an answer. - node_index: NodeIndex, - /// The value being searched. - searched: PeerId, - /// Object to use to respond to the request. - responder: KadFindNodeRespond, - }, - - /// A Kademlia substream has been closed. - KadClosed { - /// Index of the node. - node_index: NodeIndex, - /// Reason why it has been closed. `Ok` means that it's been closed gracefully. - result: Result<(), io::Error>, - }, -} - -/// Network swarm. Must be polled regularly in order for the networking to work. -pub struct Swarm { - /// Stream of events of the swarm. - swarm: RawSwarm< - Boxed<(PeerId, Muxer)>, - SubstrateInEvent, - SubstrateOutEvent>, - SubstrateNodeHandler> - >, - - /// List of registered protocols. Used when we open or receive a new connection. - registered_custom: Arc, - - /// Public key of the local node. - local_public_key: PublicKey, - - /// Peer id of the local node. - local_peer_id: PeerId, - - /// Addresses we know we're listening on. Only includes NAT traversed addresses. - listening_addrs: Vec, - - /// For each peer id, the corresponding node index. - node_by_peer: FnvHashMap, - - /// All the nodes tasks. Must be maintained consistent with `node_by_peer`. - nodes_info: FnvHashMap, - - /// Next key to use when we insert a new entry in `nodes_info`. - next_node_index: NodeIndex, -} - -/// Local information about a peer. -struct NodeInfo { - /// The peer id. Must be maintained consistent with the rest of the state. - peer_id: PeerId, - - /// Whether we opened the connection or the remote opened it. - endpoint: Endpoint, - - /// List of custom protocol substreams that are open. - open_protocols: Vec, -} - -/// The muxer used by the transport. -type Muxer = muxing::StreamMuxerBox; - -impl Swarm { - /// Start listening on a multiaddr. - #[inline] - pub fn listen_on(&mut self, addr: Multiaddr) -> Result { - match self.swarm.listen_on(addr) { - Ok(mut addr) => { - addr.append(Protocol::P2p(self.local_peer_id.clone().into())); - info!(target: "sub-libp2p", "Local node address is: {}", addr); - Ok(addr) - }, - Err(addr) => Err(addr) - } - } - - /// Returns an iterator that produces the list of addresses we're listening on. - #[inline] - pub fn listeners(&self) -> impl Iterator { - self.swarm.listeners() - } - - /// Adds an external address. Sent to other nodes when they query it. - #[inline] - pub fn add_external_address(&mut self, addr: Multiaddr) { - self.listening_addrs.push(addr); - } - - /// Returns an iterator to our known external addresses. - #[inline] - pub fn external_addresses(&self) -> impl Iterator { - self.listening_addrs.iter() - } - - /// Returns all the nodes that are currently active. - #[inline] - pub fn nodes<'a>(&'a self) -> impl Iterator + 'a { - self.nodes_info.keys().cloned() - } - - /// Returns the latest node connected to this peer ID. - #[inline] - pub fn latest_node_by_peer_id(&self, peer_id: &PeerId) -> Option { - self.node_by_peer.get(peer_id).map(|&i| i) - } - - /// Endpoint of the node. - /// - /// Returns `None` if the index is invalid. - #[inline] - pub fn node_endpoint(&self, node_index: NodeIndex) -> Option { - self.nodes_info.get(&node_index).map(|i| i.endpoint) - } - - /// Sends a message to a peer using the custom protocol. - // TODO: report invalid node index or protocol? - pub fn send_custom_message( - &mut self, - node_index: NodeIndex, - protocol: ProtocolId, - data: Vec - ) { - if let Some(info) = self.nodes_info.get_mut(&node_index) { - if let Some(mut connected) = self.swarm.peer(info.peer_id.clone()).as_connected() { - connected.send_event(SubstrateInEvent::SendCustomMessage { protocol, data }); - } else { - error!(target: "sub-libp2p", "Tried to send message to {:?}, but we're not \ - connected to it", info.peer_id); - } - } else { - error!(target: "sub-libp2p", "Tried to send message to invalid node index {:?}", - node_index); - } - } - - /// Returns the peer id of a node we're connected to. - #[inline] - pub fn peer_id_of_node(&self, node_index: NodeIndex) -> Option<&PeerId> { - self.nodes_info.get(&node_index).map(|i| &i.peer_id) - } - - /// If we're not already dialing the given peer, start dialing it and return false. - /// If we're dialing, adds the address to the queue of addresses to try (if not already) and - /// return false. - /// If we're already connected, do nothing and return true. - /// - /// Returns an error if the address is not supported. - pub fn ensure_connection(&mut self, peer_id: PeerId, addr: Multiaddr) -> Result { - match self.swarm.peer(peer_id.clone()) { - SwarmPeer::Connected(_) => Ok(true), - SwarmPeer::PendingConnect(mut peer) => { - peer.append_multiaddr_attempt(addr); - Ok(false) - }, - SwarmPeer::NotConnected(peer) => { - trace!(target: "sub-libp2p", "Starting to connect to {:?} through {}", - peer_id, addr); - match peer.connect(addr, SubstrateNodeHandler::new(self.registered_custom.clone())) { - Ok(_) => Ok(false), - Err(_) => Err(()), - } - }, - } - } - - /// Start dialing an address, not knowing which peer ID to expect. - #[inline] - pub fn dial(&mut self, addr: Multiaddr) -> Result<(), Multiaddr> { - self.swarm.dial(addr, SubstrateNodeHandler::new(self.registered_custom.clone())) - } - - /// After receiving a `NodePending` event, you should call either `accept_node` or `drop_node` - /// with the specified index. - /// - /// Returns an error if the node index is invalid, or if it was already accepted. - pub fn accept_node(&mut self, node_index: NodeIndex) -> Result<(), ()> { - // TODO: detect if already accepted? - let peer_id = match self.nodes_info.get(&node_index) { - Some(info) => &info.peer_id, - None => return Err(()) - }; - - match self.swarm.peer(peer_id.clone()) { - SwarmPeer::Connected(mut peer) => { - peer.send_event(SubstrateInEvent::Accept); - Ok(()) - }, - SwarmPeer::PendingConnect(_) | SwarmPeer::NotConnected(_) => { - error!(target: "sub-libp2p", "State inconsistency detected in accept_node ; \ - nodes_info is not in sync with the underlying swarm"); - Err(()) - }, - } - } - - /// Disconnects a peer. - /// - /// If the peer is connected, this disconnects it. - /// If the peer hasn't been accepted yet, this immediately drops it. - /// - /// Returns the list of custom protocol substreams that were opened. - #[inline] - pub fn drop_node(&mut self, node_index: NodeIndex) -> Result, ()> { - let info = match self.nodes_info.remove(&node_index) { - Some(i) => i, - None => { - error!(target: "sub-libp2p", "Trying to close non-existing node #{}", node_index); - return Err(()); - }, - }; - - let idx_in_hashmap = self.node_by_peer.remove(&info.peer_id); - debug_assert_eq!(idx_in_hashmap, Some(node_index)); - - if let Some(connected) = self.swarm.peer(info.peer_id.clone()).as_connected() { - connected.close(); - } else { - error!(target: "sub-libp2p", "State inconsistency: node_by_peer and nodes_info are \ - not in sync with the underlying swarm"); - } - - Ok(info.open_protocols) - } - - /// Opens a Kademlia substream with the given node. A `KadOpen` event will later be produced - /// for the given node. - /// - /// If a Kademlia substream is already open, also produces a `KadOpen` event. - /// - /// Returns an error if the node index is invalid. - pub fn open_kademlia(&mut self, node_index: NodeIndex) -> Result<(), ()> { - if let Some(info) = self.nodes_info.get_mut(&node_index) { - if let Some(mut connected) = self.swarm.peer(info.peer_id.clone()).as_connected() { - connected.send_event(SubstrateInEvent::OpenKademlia); - Ok(()) - } else { - error!(target: "sub-libp2p", "Tried to open Kademlia with {:?}, but we're not \ - connected to it", info.peer_id); - Err(()) - } - } else { - error!(target: "sub-libp2p", "Tried to open Kademlia with invalid node index {:?}", - node_index); - Err(()) - } - } - - /// Adds an address the given peer observes us as. - fn add_observed_addr(&mut self, peer_id: &PeerId, observed_addr: &Multiaddr) { - for mut addr in self.swarm.nat_traversal(observed_addr) { - // Ignore addresses we already know about. - if self.listening_addrs.iter().any(|a| a == &addr) { - continue; - } - - debug!(target: "sub-libp2p", - "NAT traversal: {:?} observes us as {}; registering {} as one of our own addresses", - peer_id, - observed_addr, - addr - ); - - self.listening_addrs.push(addr.clone()); - addr.append(Protocol::P2p(self.local_peer_id.clone().into())); - info!(target: "sub-libp2p", "New external node address: {}", addr); - } - } - - /// Responds to an answer to send back identification information. - fn respond_to_identify_request( - &mut self, - requester: &PeerId, - responder: IdentificationRequest> - ) { - let peer = match self.swarm.peer(requester.clone()).as_connected() { - Some(p) => p, - None => { - debug!(target: "sub-libp2p", "Ignoring identify request from {:?} because we are \ - disconnected", requester); - return; - } - }; - - let observed_addr = match peer.endpoint() { - &ConnectedPoint::Dialer { ref address } => address, - &ConnectedPoint::Listener { ref send_back_addr, .. } => send_back_addr, - }; - - trace!(target: "sub-libp2p", "Responding to identify request from {:?}", requester); - responder.respond( - self.local_public_key.clone(), - self.listening_addrs.clone(), - &observed_addr, - ); - } - - /// Processes an event obtained by a node in the swarm. - /// - /// Optionally returns an event that the service must emit. - /// - /// > **Note**: The event **must** have been produced by the swarm, otherwise state - /// > inconsistencies will likely happen. - fn handle_node_event( - &mut self, - peer_id: PeerId, - event: SubstrateOutEvent> - ) -> Option { - // Obtain the peer id and whether the node has been closed earlier. - // If the node has been closed, do not generate any additional event about it. - let node_index = *self.node_by_peer.get(&peer_id) - .expect("node_by_peer is always kept in sync with the underlying swarm"); - - match event { - SubstrateOutEvent::Unresponsive => { - debug!(target: "sub-libp2p", "Node {:?} is unresponsive", peer_id); - Some(SwarmEvent::UnresponsiveNode { node_index }) - }, - SubstrateOutEvent::Useless => { - debug!(target: "sub-libp2p", "Node {:?} is useless", peer_id); - Some(SwarmEvent::UselessNode { node_index }) - }, - SubstrateOutEvent::PingStart => { - trace!(target: "sub-libp2p", "Pinging {:?}", peer_id); - None - }, - SubstrateOutEvent::PingSuccess(ping) => { - trace!(target: "sub-libp2p", "Pong from {:?} in {:?}", peer_id, ping); - None - }, - SubstrateOutEvent::Identified { info, observed_addr } => { - self.add_observed_addr(&peer_id, &observed_addr); - trace!(target: "sub-libp2p", "Client version of {:?}: {:?}", peer_id, info.agent_version); - if !info.agent_version.contains("substrate") { - info!(target: "sub-libp2p", "Connected to non-substrate node {:?}: {}", - peer_id, info.agent_version); - } - - Some(SwarmEvent::NodeInfos { - node_index, - client_version: info.agent_version, - listen_addrs: info.listen_addrs, - }) - }, - SubstrateOutEvent::IdentificationRequest(request) => { - self.respond_to_identify_request(&peer_id, request); - None - }, - SubstrateOutEvent::KadFindNode { searched, responder } => { - Some(SwarmEvent::KadFindNode { node_index, searched, responder }) - }, - SubstrateOutEvent::KadOpen(ctrl) => { - trace!(target: "sub-libp2p", "Opened Kademlia substream with {:?}", peer_id); - Some(SwarmEvent::KadOpen { node_index, controller: ctrl }) - }, - SubstrateOutEvent::KadClosed(result) => { - trace!(target: "sub-libp2p", "Closed Kademlia substream with {:?}: {:?}", peer_id, result); - Some(SwarmEvent::KadClosed { node_index, result }) - }, - SubstrateOutEvent::CustomProtocolOpen { protocol_id, version } => { - trace!(target: "sub-libp2p", "Opened custom protocol with {:?}", peer_id); - self.nodes_info.get_mut(&node_index) - .expect("nodes_info is kept in sync with the underlying swarm") - .open_protocols.push(protocol_id); - Some(SwarmEvent::OpenedCustomProtocol { - node_index, - protocol: protocol_id, - version, - }) - }, - SubstrateOutEvent::CustomProtocolClosed { protocol_id, result } => { - trace!(target: "sub-libp2p", "Closed custom protocol with {:?}: {:?}", peer_id, result); - self.nodes_info.get_mut(&node_index) - .expect("nodes_info is kept in sync with the underlying swarm") - .open_protocols.retain(|p| p != &protocol_id); - Some(SwarmEvent::ClosedCustomProtocol { - node_index, - protocol: protocol_id, - }) - }, - SubstrateOutEvent::CustomMessage { protocol_id, data } => { - Some(SwarmEvent::CustomMessage { - node_index, - protocol_id, - data, - }) - }, - SubstrateOutEvent::SubstreamUpgradeFail(err) => { - debug!(target: "sub-libp2p", "Error while negotiating final protocol \ - with {:?}: {:?}", peer_id, err); - None - }, - } - } -} - -impl Stream for Swarm { - type Item = SwarmEvent; - type Error = io::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - loop { - let (peer_id, node_event) = match self.swarm.poll() { - Async::Ready(RawSwarmEvent::Connected { peer_id, endpoint }) => { - let node_index = self.next_node_index.clone(); - self.next_node_index += 1; - self.node_by_peer.insert(peer_id.clone(), node_index); - self.nodes_info.insert(node_index, NodeInfo { - peer_id: peer_id.clone(), - endpoint: match endpoint { - ConnectedPoint::Listener { .. } => Endpoint::Listener, - ConnectedPoint::Dialer { .. } => Endpoint::Dialer, - }, - open_protocols: Vec::new(), - }); - - return Ok(Async::Ready(Some(SwarmEvent::NodePending { - node_index, - peer_id, - endpoint - }))); - } - Async::Ready(RawSwarmEvent::Replaced { peer_id, endpoint, .. }) => { - let node_index = *self.node_by_peer.get(&peer_id) - .expect("node_by_peer is always kept in sync with the inner swarm"); - let infos = self.nodes_info.get_mut(&node_index) - .expect("nodes_info is always kept in sync with the swarm"); - debug_assert_eq!(infos.peer_id, peer_id); - infos.endpoint = match endpoint { - ConnectedPoint::Listener { .. } => Endpoint::Listener, - ConnectedPoint::Dialer { .. } => Endpoint::Dialer, - }; - let closed_custom_protocols = mem::replace(&mut infos.open_protocols, Vec::new()); - - return Ok(Async::Ready(Some(SwarmEvent::Reconnected { - node_index, - endpoint, - closed_custom_protocols, - }))); - }, - Async::Ready(RawSwarmEvent::NodeClosed { peer_id, .. }) => { - debug!(target: "sub-libp2p", "Connection to {:?} closed gracefully", peer_id); - let node_index = self.node_by_peer.remove(&peer_id) - .expect("node_by_peer is always kept in sync with the inner swarm"); - let infos = self.nodes_info.remove(&node_index) - .expect("nodes_info is always kept in sync with the inner swarm"); - debug_assert_eq!(infos.peer_id, peer_id); - return Ok(Async::Ready(Some(SwarmEvent::NodeClosed { - node_index, - peer_id, - closed_custom_protocols: infos.open_protocols, - }))); - }, - Async::Ready(RawSwarmEvent::NodeError { peer_id, error, .. }) => { - debug!(target: "sub-libp2p", "Closing {:?} because of error: {:?}", peer_id, error); - let node_index = self.node_by_peer.remove(&peer_id) - .expect("node_by_peer is always kept in sync with the inner swarm"); - let infos = self.nodes_info.remove(&node_index) - .expect("nodes_info is always kept in sync with the inner swarm"); - debug_assert_eq!(infos.peer_id, peer_id); - return Ok(Async::Ready(Some(SwarmEvent::NodeClosed { - node_index, - peer_id, - closed_custom_protocols: infos.open_protocols, - }))); - }, - Async::Ready(RawSwarmEvent::DialError { multiaddr, error, .. }) => - return Ok(Async::Ready(Some(SwarmEvent::DialFail { - address: multiaddr, - error, - }))), - Async::Ready(RawSwarmEvent::UnknownPeerDialError { multiaddr, error, .. }) => - return Ok(Async::Ready(Some(SwarmEvent::DialFail { - address: multiaddr, - error, - }))), - Async::Ready(RawSwarmEvent::ListenerClosed { listen_addr, result, .. }) => { - warn!(target: "sub-libp2p", "Listener closed for {}: {:?}", listen_addr, result); - continue; - }, - Async::Ready(RawSwarmEvent::NodeEvent { peer_id, event }) => (peer_id, event), - Async::Ready(RawSwarmEvent::IncomingConnection(incoming)) => { - trace!(target: "sub-libp2p", "Incoming connection with {} on listener {}", - incoming.send_back_addr(), incoming.listen_addr()); - incoming.accept(SubstrateNodeHandler::new(self.registered_custom.clone())); - continue; - }, - Async::Ready(RawSwarmEvent::IncomingConnectionError { listen_addr, send_back_addr, error }) => { - trace!(target: "sub-libp2p", "Incoming connection with {} on listener {} \ - errored: {:?}", send_back_addr, listen_addr, error); - continue; - }, - Async::NotReady => return Ok(Async::NotReady), - }; - - if let Some(event) = self.handle_node_event(peer_id, node_event) { - return Ok(Async::Ready(Some(event))); - } - } - } -} diff --git a/substrate/core/network-libp2p/src/topology.rs b/substrate/core/network-libp2p/src/topology.rs index 061a3d1795..0bd3067076 100644 --- a/substrate/core/network-libp2p/src/topology.rs +++ b/substrate/core/network-libp2p/src/topology.rs @@ -15,10 +15,11 @@ // along with Substrate. If not, see .? use fnv::FnvHashMap; -use parking_lot::Mutex; -use libp2p::{Multiaddr, PeerId}; +use libp2p::{Multiaddr, PeerId, identify::IdentifyTopology, multihash::Multihash}; +use libp2p::core::{PublicKey, swarm::ConnectedPoint, topology::DisconnectReason, topology::Topology}; +use libp2p::kad::{KBucketsPeerId, KadConnectionType, KademliaTopology}; use serde_json; -use std::{cmp, fs}; +use std::{cmp, fs, iter, vec}; 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}; @@ -46,8 +47,6 @@ const KADEMLIA_DISCOVERY_EXPIRATION: Duration = Duration::from_secs(2 * 3600); 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; -/// Score modifier to apply on a peer that has been determined to be useless. -const USELESS_PEER_SCORE_CHANGE: i32 = -9; /// 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); @@ -63,15 +62,16 @@ 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, + /// Optional path to the file that caches the serialized version of `store`. cache_path: Option, -} - -impl Default for NetTopology { - #[inline] - fn default() -> NetTopology { - NetTopology::memory() - } + /// Public key of the local node. + local_public_key: PublicKey, + /// PeerId of the local node. Derived from `local_public_key`. + local_peer_id: PeerId, + /// Known addresses for the local node to report to the network. + external_addresses: Vec, } impl NetTopology { @@ -79,10 +79,14 @@ impl NetTopology { /// /// `flush_to_disk()` will be a no-op. #[inline] - pub fn memory() -> NetTopology { + pub fn memory(local_public_key: PublicKey) -> NetTopology { + let local_peer_id = local_public_key.clone().into_peer_id(); NetTopology { store: Default::default(), cache_path: None, + local_peer_id, + local_public_key, + external_addresses: Vec::new(), } } @@ -92,19 +96,24 @@ impl NetTopology { /// or contains garbage data, the execution still continues. /// /// Calling `flush_to_disk()` in the future writes to the given path. - pub fn from_file>(path: P) -> NetTopology { + pub fn from_file>(local_public_key: PublicKey, path: P) -> NetTopology { let path = path.as_ref(); + let local_peer_id = local_public_key.clone().into_peer_id(); debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path); + let store = try_load(path, &local_peer_id); NetTopology { - store: try_load(path), + store, cache_path: Some(path.to_owned()), + local_peer_id, + local_public_key, + external_addresses: Vec::new(), } } /// Writes the topology into the path passed to `from_file`. /// /// No-op if the object was created with `memory()`. - pub fn flush_to_disk(&self) -> Result<(), IoError> { + pub fn flush_to_disk(&mut self) -> Result<(), IoError> { let path = match self.cache_path { Some(ref p) => p, None => return Ok(()) @@ -112,10 +121,10 @@ impl NetTopology { 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), &self.store) + serialize(BufWriter::with_capacity(1024 * 1024, file), &mut self.store) } - /// Returns the number of peers in the topology. + /// Returns the number of peers in the topology, excluding the local peer. #[inline] pub fn num_peers(&self) -> usize { self.store.len() @@ -127,40 +136,19 @@ impl NetTopology { pub fn cleanup(&mut self) { let now_systime = SystemTime::now(); self.store.retain(|_, peer| { - peer.addrs.retain(|a| { - a.expires > now_systime || a.is_connected() - }); + 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 the known potential addresses of a peer, ordered by score. Excludes backed-off - /// addresses. - /// - /// The boolean associated to each address indicates whether we're connected to it. - pub fn addrs_of_peer(&self, peer: &PeerId) -> impl Iterator { - let peer = if let Some(peer) = self.store.get(peer) { - peer - } else { - // TODO: use an EitherIterator or something - return Vec::new().into_iter(); - }; - - let now_st = SystemTime::now(); - let now_is = Instant::now(); - - let mut list = peer.addrs.iter().filter_map(move |addr| { - let (score, connected) = addr.score_and_is_connected(); - if (addr.expires >= now_st && score > 0 && addr.back_off_until < now_is) || connected { - Some((score, connected, &addr.addr)) - } else { - None - } - }).collect::>(); - list.sort_by(|a, b| a.0.cmp(&b.0)); - // TODO: meh, optimize - let l = list.into_iter().map(|(_, connec, addr)| (addr, connec)).collect::>(); - l.into_iter() + /// Add the external addresses that are known for the local node. + pub fn add_external_addrs(&mut self, addrs: TIter) + where TIter: Iterator { + self.external_addresses.extend(addrs); } /// Returns a list of all the known addresses of peers, ordered by the @@ -170,7 +158,7 @@ impl NetTopology { /// 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(&self) -> (impl Iterator, Instant) { + pub fn addrs_to_attempt(&mut self) -> (impl Iterator, Instant) { // TODO: optimize let now = Instant::now(); let now_systime = SystemTime::now(); @@ -179,20 +167,20 @@ impl NetTopology { let mut peer_addrs = Vec::new(); - 'peer_loop: for (peer, info) in &self.store { + 'peer_loop: for (peer, info) in &mut self.store { peer_addrs.clear(); - for addr in &info.addrs { + for addr in &mut info.addrs { let (score, is_connected) = addr.score_and_is_connected(); if is_connected { - continue 'peer_loop; + continue 'peer_loop } if score == 0 || addr.expires < now_systime { - continue; + continue } if addr.back_off_until > now { instant = cmp::min(instant, addr.back_off_until); - continue; + continue } peer_addrs.push(((peer, &addr.addr), score)); @@ -217,15 +205,19 @@ impl NetTopology { let peer = peer_access(&mut self.store, peer); let mut found = false; - peer.addrs.retain(|a| { - if a.expires < now_systime && !a.is_connected() { - return false; - } - if a.addr == addr { - found = true; - } - true - }); + 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 { @@ -233,50 +225,15 @@ impl NetTopology { expires: now_systime + BOOTSTRAP_NODE_EXPIRATION, back_off_until: now, next_back_off: FIRST_CONNECT_FAIL_BACKOFF, - score: Mutex::new(AddrScore { + score: AddrScore { connected_since: None, score: BOOTSTRAP_NODE_SCORE, latest_score_update: now, - }), + }, }); } } - /// Adds addresses that a node says it is listening on. - /// - /// The addresses are most likely to be valid. - /// - /// Returns `true` if the topology has changed in some way. Returns `false` if calling this - /// method was a no-op. - #[inline] - pub fn add_self_reported_listen_addrs( - &mut self, - peer_id: &PeerId, - addrs: I, - ) -> bool - where I: Iterator { - self.add_discovered_addrs(peer_id, addrs.map(|a| (a, true))) - } - - /// Adds addresses discovered through the Kademlia DHT. - /// - /// The addresses are not necessarily valid and should expire after a TTL. - /// - /// For each address, incorporates a boolean. If true, that means we have some sort of hint - /// that this address can be reached. - /// - /// Returns `true` if the topology has changed in some way. Returns `false` if calling this - /// method was a no-op. - #[inline] - pub fn add_kademlia_discovered_addrs( - &mut self, - peer_id: &PeerId, - addrs: I, - ) -> bool - where I: Iterator { - self.add_discovered_addrs(peer_id, addrs) - } - /// Inner implementaiton of the `add_*_discovered_addrs` methods. /// Returns `true` if the topology has changed in some way. Returns `false` if calling this /// method was a no-op. @@ -292,15 +249,19 @@ impl NetTopology { let peer = peer_access(&mut self.store, peer_id); - peer.addrs.retain(|a| { - if a.expires < now_systime && !a.is_connected() { - return false; - } - if let Some(pos) = addrs.iter().position(|&(ref addr, _)| addr == &a.addr) { - addrs.remove(pos); - } - true - }); + let new_addrs = peer.addrs + .drain(..) + .filter_map(|a| { + if a.expires < now_systime && !a.is_connected() { + return None + } + if let Some(pos) = addrs.iter().position(|&(ref addr, _)| addr == &a.addr) { + addrs.remove(pos); + } + Some(a) + }) + .collect(); + peer.addrs = new_addrs; let mut anything_changed = false; @@ -322,7 +283,7 @@ impl NetTopology { // Enforce `MAX_ADDRESSES_PER_PEER` before inserting, or skip this entry. while peer.addrs.len() >= MAX_ADDRESSES_PER_PEER { - let pos = peer.addrs.iter().position(|addr| addr.score() <= initial_score); + let pos = peer.addrs.iter_mut().position(|addr| addr.score() <= initial_score); if let Some(pos) = pos { let _ = peer.addrs.remove(pos); } else { @@ -336,23 +297,109 @@ impl NetTopology { expires: now_systime + KADEMLIA_DISCOVERY_EXPIRATION, back_off_until: now, next_back_off: FIRST_CONNECT_FAIL_BACKOFF, - score: Mutex::new(AddrScore { + score: AddrScore { connected_since: None, score: initial_score, latest_score_update: now, - }), + }, }); } anything_changed } +} + +impl KademliaTopology for NetTopology { + type ClosestPeersIter = vec::IntoIter; + type GetProvidersIter = iter::Empty; + + fn add_kad_discovered_address(&mut self, peer: PeerId, addr: Multiaddr, ty: KadConnectionType) { + self.add_discovered_addrs(&peer, iter::once((addr, ty == KadConnectionType::Connected))); + } + + fn closest_peers(&mut self, target: &Multihash, _max: usize) -> Self::ClosestPeersIter { + // TODO: very inefficient + let mut peers = self.store.keys().cloned().collect::>(); + peers.push(self.local_peer_id.clone()); + peers.sort_by(|a, b| { + b.as_ref().distance_with(target).cmp(&a.as_ref().distance_with(target)) + }); + peers.into_iter() + } + + fn add_provider(&mut self, _: Multihash, _: PeerId) { + // We don't implement ADD_PROVIDER/GET_PROVIDERS + } + + fn get_providers(&mut self, _: &Multihash) -> Self::GetProvidersIter { + // We don't implement ADD_PROVIDER/GET_PROVIDERS + iter::empty() + } +} + +impl IdentifyTopology for NetTopology { + #[inline] + fn add_identify_discovered_addrs(&mut self, peer: &PeerId, addrs: TIter) + where + TIter: Iterator + { + // These are addresses that peers indicate for themselves. + // The typical use case is: + // - A peer connects to one of our listening points. + // - We send an identify request to it, and it answers with a list of addresses. + // - If later it disconnects, we can try to dial it back through one of these addresses. + self.add_discovered_addrs(peer, addrs.map(move |a| (a, true))); + } +} + +impl Topology for NetTopology { + #[inline] + fn addresses_of_peer(&mut self, peer: &PeerId) -> Vec { + if peer == &self.local_peer_id { + return self.external_addresses.clone() + } + + let peer = if let Some(peer) = self.store.get_mut(peer) { + peer + } else { + return Vec::new() + }; + + let now_st = SystemTime::now(); + let now_is = Instant::now(); + + let mut list = peer.addrs.iter_mut().filter_map(move |addr| { + let (score, connected) = addr.score_and_is_connected(); + if (addr.expires >= now_st && score > 0 && addr.back_off_until < now_is) || connected { + Some((score, &addr.addr)) + } else { + None + } + }).collect::>(); + list.sort_by(|a, b| a.0.cmp(&b.0)); + // TODO: meh, optimize + list.into_iter().map(|(_, addr)| addr.clone()).collect::>() + } + + fn add_local_external_addrs(&mut self, addrs: TIter) + where TIter: Iterator { + self.add_external_addrs(addrs) + } + + fn local_peer_id(&self) -> &PeerId { + &self.local_peer_id + } + + fn local_public_key(&self) -> &PublicKey { + &self.local_public_key + } + + fn set_connected(&mut self, peer: &PeerId, endpoint: &ConnectedPoint) { + let addr = match endpoint { + ConnectedPoint::Dialer { address } => address, + ConnectedPoint::Listener { .. } => return + }; - /// Indicates the peer store that we're connected to this given address. - /// - /// This increases the score of the address that we connected to. Since we assume that only - /// one peer can be reached with any specific address, we also remove all addresses from other - /// peers that match the one we connected to. - pub fn report_connected(&mut self, addr: &Multiaddr, peer: &PeerId) { let now = Instant::now(); // Just making sure that we have an entry for this peer in `store`, but don't use it. @@ -364,20 +411,19 @@ impl NetTopology { addr.connected_now(CONNECTED_MINIMUM_SCORE); addr.back_off_until = now; addr.next_back_off = FIRST_CONNECT_FAIL_BACKOFF; - continue; + continue } - // TODO: a else block would be better, but we get borrowck errors 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: Mutex::new(AddrScore { + score: AddrScore { connected_since: Some(now), latest_score_update: now, score: CONNECTED_MINIMUM_SCORE, - }), + }, }); } else { @@ -391,17 +437,16 @@ impl NetTopology { } } - /// Indicates the peer store that we're disconnected from an address. - /// - /// There's no need to indicate a peer ID, as each address can only have one peer ID. - /// If we were indeed connected to this addr, then we can find out which peer ID it is. - pub fn report_disconnected(&mut self, addr: &Multiaddr, reason: DisconnectReason) { + fn set_disconnected(&mut self, _: &PeerId, endpoint: &ConnectedPoint, reason: DisconnectReason) { + let addr = match endpoint { + ConnectedPoint::Dialer { address } => address, + ConnectedPoint::Listener { .. } => return + }; + let score_diff = match reason { - DisconnectReason::NoSlot => -1, - DisconnectReason::FoundBetterAddr => -5, - DisconnectReason::RemoteClosed => -5, - DisconnectReason::Useless => -5, - DisconnectReason::Banned => -5, + DisconnectReason::Replaced => -3, + DisconnectReason::Graceful => -1, + DisconnectReason::Error => -5, }; for info in self.store.values_mut() { @@ -414,58 +459,26 @@ impl NetTopology { if a.expires < expires_push_back { a.expires = expires_push_back; } - return; + return } } } } - /// Indicates the peer store that we failed to connect to an address. - /// - /// We don't care about which peer is supposed to be behind that address. If we failed to dial - /// it for a specific peer, we would also fail to dial it for all peers that have this - /// address. - pub fn report_failed_to_connect(&mut self, addr: &Multiaddr) { + 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 { - 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); + if &a.addr != addr { + 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); } } } - - /// Indicates the peer store that the given peer is useless. - /// - /// This decreases the scores of the addresses of that peer. - pub fn report_useless(&mut self, peer: &PeerId) { - for (peer_in_store, info_in_store) in self.store.iter_mut() { - if peer == peer_in_store { - for addr in info_in_store.addrs.iter_mut() { - addr.adjust_score(USELESS_PEER_SCORE_CHANGE); - } - } - } - } -} - -/// Reason why we disconnected from a peer. -#[derive(Debug)] -pub enum DisconnectReason { - /// No slot available locally anymore for this peer. - NoSlot, - /// A better way to connect to this peer has been found, therefore we disconnect from - /// the old one. - FoundBetterAddr, - /// The remote closed the connection. - RemoteClosed, - /// This node is considered useless for our needs. This includes time outs. - Useless, - /// The peer has been banned. - Banned, } fn peer_access<'a>(store: &'a mut FnvHashMap, peer: &PeerId) -> &'a mut PeerInfo { @@ -488,17 +501,17 @@ struct Addr { next_back_off: Duration, /// Don't try to connect to this node until `Instant`. back_off_until: Instant, - score: Mutex, + score: AddrScore, } impl Clone for Addr { fn clone(&self) -> Addr { Addr { addr: self.addr.clone(), - expires: self.expires.clone(), - next_back_off: self.next_back_off.clone(), - back_off_until: self.back_off_until.clone(), - score: Mutex::new(self.score.lock().clone()), + expires: self.expires, + next_back_off: self.next_back_off, + back_off_until: self.back_off_until, + score: self.score.clone(), } } } @@ -516,58 +529,52 @@ struct AddrScore { impl Addr { /// Sets the addr to connected. If the score is lower than the given value, raises it to this /// value. - fn connected_now(&self, raise_to_min: u32) { - let mut score = self.score.lock(); + fn connected_now(&mut self, raise_to_min: u32) { let now = Instant::now(); - Addr::flush(&mut score, now); - score.connected_since = Some(now); - if score.score < raise_to_min { - score.score = raise_to_min; + 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(&self, score_diff: i32) { - let mut score = self.score.lock(); - Addr::flush(&mut score, Instant::now()); + fn adjust_score(&mut self, score_diff: i32) { + Addr::flush(&mut self.score, Instant::now()); if score_diff >= 0 { - score.score = cmp::min(MAX_SCORE, score.score + score_diff as u32); + self.score.score = cmp::min(MAX_SCORE, self.score.score + score_diff as u32); } else { - score.score = score.score.saturating_sub(-score_diff as u32); + 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(&self, score_diff: i32) { - let mut score = self.score.lock(); - Addr::flush(&mut score, Instant::now()); - score.connected_since = None; + fn disconnected_now(&mut self, score_diff: i32) { + Addr::flush(&mut self.score, Instant::now()); + self.score.connected_since = None; if score_diff >= 0 { - score.score = cmp::min(MAX_SCORE, score.score + score_diff as u32); + self.score.score = cmp::min(MAX_SCORE, self.score.score + score_diff as u32); } else { - score.score = score.score.saturating_sub(-score_diff as u32); + 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 { - let score = self.score.lock(); - score.connected_since.is_some() + self.score.connected_since.is_some() } /// Returns the score, and true if we are connected to this addr. - fn score_and_is_connected(&self) -> (u32, bool) { - let mut score = self.score.lock(); - Addr::flush(&mut score, Instant::now()); - let is_connected = score.connected_since.is_some(); - (score.score, is_connected) + 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(&self) -> u32 { - let mut score = self.score.lock(); - Addr::flush(&mut score, Instant::now()); - score.score + fn score(&mut self) -> u32 { + Addr::flush(&mut self.score, Instant::now()); + self.score.score } fn flush(score: &mut AddrScore, now: Instant) { @@ -588,8 +595,8 @@ impl Addr { /// 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 + (a.subsec_nanos() / 1_000) as u64; - let b_ms = b.as_secs() * 1_000_000 + (b.subsec_nanos() / 1_000) as u64; + 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 } @@ -607,8 +614,8 @@ struct SerializedAddr { score: u32, } -impl<'a> From<&'a Addr> for SerializedAddr { - fn from(addr: &'a Addr) -> SerializedAddr { +impl<'a> From<&'a mut Addr> for SerializedAddr { + fn from(addr: &'a mut Addr) -> SerializedAddr { SerializedAddr { addr: addr.addr.to_string(), expires: addr.expires, @@ -618,9 +625,10 @@ impl<'a> From<&'a Addr> for SerializedAddr { } /// 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) -> FnvHashMap { +fn try_load(path: impl AsRef, local_peer_id: &PeerId) -> FnvHashMap { let path = path.as_ref(); if !path.exists() { debug!(target: "sub-libp2p", "Peer storage file {:?} doesn't exist", path); @@ -664,7 +672,8 @@ fn try_load(path: impl AsRef) -> FnvHashMap { 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()), + 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); @@ -676,9 +685,10 @@ fn try_load(path: impl AsRef) -> FnvHashMap { /// Attempts to turn a deserialized version of the storage into the final version. /// -/// Skips entries that are invalid. +/// Skips entries that are invalid or equal to `local_peer_id`. fn deserialize_tolerant( - iter: impl Iterator + iter: impl Iterator, + local_peer_id: &PeerId ) -> FnvHashMap { let now = Instant::now(); let now_systime = SystemTime::now(); @@ -690,6 +700,10 @@ fn deserialize_tolerant( Err(_) => continue, }; + if &peer == local_peer_id { + continue + } + let info: SerializedPeerInfo = match serde_json::from_value(info) { Ok(i) => i, Err(_) => continue, @@ -711,16 +725,16 @@ fn deserialize_tolerant( expires: addr.expires, next_back_off: FIRST_CONNECT_FAIL_BACKOFF, back_off_until: now, - score: Mutex::new(AddrScore { + score: AddrScore { connected_since: None, score: addr.score, latest_score_update: now, - }), + }, }); } if addrs.is_empty() { - continue; + continue } out.insert(peer, PeerInfo { addrs }); @@ -732,18 +746,21 @@ fn deserialize_tolerant( /// Attempts to turn a deserialized version of the storage into the final version. /// /// Skips entries that are invalid or expired. -fn serialize(out: W, map: &FnvHashMap) -> Result<(), IoError> { +fn serialize(out: W, map: &mut FnvHashMap) -> Result<(), IoError> { let now = SystemTime::now(); - let array: FnvHashMap<_, _> = map.iter().filter_map(|(peer, info)| { + 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() - .filter(|a| a.expires > now || a.is_connected()) - .map(Into::into) + addrs: info.addrs.iter_mut() + .filter_map(|a| if a.expires > now || a.is_connected() { + Some(a.into()) + } else { + None + }) .collect(), }; diff --git a/substrate/core/network-libp2p/src/transport.rs b/substrate/core/network-libp2p/src/transport.rs index 89c6757bbc..b991917510 100644 --- a/substrate/core/network-libp2p/src/transport.rs +++ b/substrate/core/network-libp2p/src/transport.rs @@ -14,33 +14,33 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use libp2p::{self, PeerId, Transport, mplex, secio, yamux}; -use libp2p::core::{either, upgrade, transport::boxed::Boxed, muxing::StreamMuxerBox}; -use libp2p::transport_timeout::TransportTimeout; -use std::time::Duration; -use std::usize; +use futures::prelude::*; +use libp2p::{self, InboundUpgradeExt, OutboundUpgradeExt, PeerId, Transport, mplex, secio, yamux}; +use libp2p::core::{self, transport::boxed::Boxed, muxing::StreamMuxerBox}; +use std::{io, time::Duration, usize}; /// Builds the transport that serves as a common ground for all connections. pub fn build_transport( local_private_key: secio::SecioKeyPair -) -> Boxed<(PeerId, StreamMuxerBox)> { +) -> Boxed<(PeerId, StreamMuxerBox), io::Error> { let mut mplex_config = mplex::MplexConfig::new(); mplex_config.max_buffer_len_behaviour(mplex::MaxBufferBehaviour::Block); mplex_config.max_buffer_len(usize::MAX); - let base = libp2p::CommonTransport::new() + // TODO: rework the transport creation (https://github.com/libp2p/rust-libp2p/issues/783) + libp2p::tcp::TcpConfig::new() .with_upgrade(secio::SecioConfig::new(local_private_key)) .and_then(move |out, endpoint| { - let upgrade = upgrade::or( - upgrade::map(yamux::Config::default(), either::EitherOutput::First), - upgrade::map(mplex_config, either::EitherOutput::Second), - ); let peer_id = out.remote_key.into_peer_id(); - let upgrade = upgrade::map(upgrade, move |muxer| (peer_id, muxer)); - upgrade::apply(out.stream, upgrade, endpoint.into()) - }) - .map(|(id, muxer), _| (id, StreamMuxerBox::new(muxer))); + let peer_id2 = peer_id.clone(); + let upgrade = core::upgrade::SelectUpgrade::new(yamux::Config::default(), mplex_config) + .map_inbound(move |muxer| (peer_id, muxer)) + .map_outbound(move |muxer| (peer_id2, muxer)); - TransportTimeout::new(base, Duration::from_secs(20)) + core::upgrade::apply(out.stream, upgrade, endpoint) + .map(|(id, muxer)| (id, core::muxing::StreamMuxerBox::new(muxer))) + }) + .with_timeout(Duration::from_secs(20)) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) .boxed() } diff --git a/substrate/core/network-libp2p/tests/test.rs b/substrate/core/network-libp2p/tests/test.rs new file mode 100644 index 0000000000..985a7c436e --- /dev/null +++ b/substrate/core/network-libp2p/tests/test.rs @@ -0,0 +1,83 @@ +// Copyright 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 . + +#[macro_use] +extern crate futures; +#[macro_use] +extern crate substrate_network_libp2p; +extern crate tokio; + +use futures::{future, prelude::*}; +use std::{io, iter}; +use substrate_network_libp2p::ServiceEvent; + +/// Builds two services. The second one has the first one as its bootstrap node. +/// This is to be used only for testing, and a panic will happen if something goes wrong. +fn build_two_nodes() -> (substrate_network_libp2p::Service, substrate_network_libp2p::Service) { + let service1 = { + let config = substrate_network_libp2p::NetworkConfiguration { + listen_addresses: vec![multiaddr![Ip4([127, 0, 0, 1]), Tcp(0u16)]], + ..substrate_network_libp2p::NetworkConfiguration ::default() + }; + let proto = substrate_network_libp2p::RegisteredProtocol::new(*b"tst", &[1]); + substrate_network_libp2p::start_service(config, iter::once(proto)).unwrap() + }; + + let service2 = { + let mut bootnode = service1.listeners().next().unwrap().clone(); + bootnode.append(libp2p::multiaddr::Protocol::P2p(service1.peer_id().clone().into())); + + let config = substrate_network_libp2p::NetworkConfiguration { + listen_addresses: vec![multiaddr![Ip4([127, 0, 0, 1]), Tcp(0u16)]], + boot_nodes: vec![bootnode.to_string()], + ..substrate_network_libp2p::NetworkConfiguration::default() + }; + let proto = substrate_network_libp2p::RegisteredProtocol::new(*b"tst", &[1]); + substrate_network_libp2p::start_service(config, iter::once(proto)).unwrap() + }; + + (service1, service2) +} + +#[test] +fn basic_two_nodes_connectivity() { + let (mut service1, mut service2) = build_two_nodes(); + + let fut1 = future::poll_fn(move || -> io::Result<_> { + match try_ready!(service1.poll()) { + Some(ServiceEvent::OpenedCustomProtocol { protocol, version, .. }) => { + assert_eq!(protocol, *b"tst"); + assert_eq!(version, 1); + Ok(Async::Ready(())) + }, + _ => panic!(), + } + }); + + let fut2 = future::poll_fn(move || -> io::Result<_> { + match try_ready!(service2.poll()) { + Some(ServiceEvent::OpenedCustomProtocol { protocol, version, .. }) => { + assert_eq!(protocol, *b"tst"); + assert_eq!(version, 1); + Ok(Async::Ready(())) + }, + _ => panic!(), + } + }); + + let combined = fut1.select(fut2).map_err(|(err, _)| err); + tokio::runtime::Runtime::new().unwrap().block_on_all(combined).unwrap(); +} diff --git a/substrate/core/network/src/service.rs b/substrate/core/network/src/service.rs index 501b5d6eb3..635b31566f 100644 --- a/substrate/core/network/src/service.rs +++ b/substrate/core/network/src/service.rs @@ -260,23 +260,11 @@ impl, H: ExHashT> ManageNetwork } fn deny_unreserved_peers(&self) { - // This method can disconnect nodes, in which case we have to properly close them in the - // protocol. - let disconnected = self.network.lock().deny_unreserved_peers(); - let mut net_sync = NetSyncIo::new(&self.network, self.protocol_id); - for node_index in disconnected { - self.handler.on_peer_disconnected(&mut net_sync, node_index) - } + self.network.lock().deny_unreserved_peers(); } fn remove_reserved_peer(&self, peer: PeerId) { - // This method can disconnect a node, in which case we have to properly close it in the - // protocol. - let disconnected = self.network.lock().remove_reserved_peer(peer); - if let Some(node_index) = disconnected { - let mut net_sync = NetSyncIo::new(&self.network, self.protocol_id); - self.handler.on_peer_disconnected(&mut net_sync, node_index) - } + self.network.lock().remove_reserved_peer(peer); } fn add_reserved_peer(&self, peer: String) -> Result<(), String> { @@ -388,12 +376,6 @@ fn run_thread, H: ExHashT>( let mut net_sync = NetSyncIo::new(&network_service, protocol_id); match event { - NetworkServiceEvent::NodeClosed { node_index, closed_custom_protocols } => { - if !closed_custom_protocols.is_empty() { - debug_assert_eq!(closed_custom_protocols, &[protocol_id]); - protocol.on_peer_disconnected(&mut net_sync, node_index); - } - } NetworkServiceEvent::ClosedCustomProtocols { node_index, protocols } => { if !protocols.is_empty() { debug_assert_eq!(protocols, &[protocol_id]);