diff --git a/Cargo.lock b/Cargo.lock index b8f8d3158c934..45febf685df14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,20 @@ dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "aio-limited" +version = "0.1.0" +source = "git+https://github.com/paritytech/aio-limited.git#1f42497dcd2a6f85b83af97cd80314b26a1e4a9e" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ansi_term" version = "0.9.0" @@ -35,6 +49,11 @@ dependencies = [ "xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayref" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayvec" version = "0.4.7" @@ -43,6 +62,14 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "asn1_der" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "etrace 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "assert_matches" version = "1.2.0" @@ -79,6 +106,11 @@ dependencies = [ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base-x" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "base58" version = "0.1.0" @@ -101,6 +133,15 @@ dependencies = [ "safemem 0.2.0 (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.3 (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.1" @@ -110,6 +151,15 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bigint" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.9.1" @@ -129,6 +179,30 @@ dependencies = [ "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bs58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byte-tools" +version = "0.2.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 = "1.2.3" @@ -156,6 +230,15 @@ name = "cfg-if" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chashmap" +version = "2.2.1" +source = "git+https://github.com/redox-os/tfs#3e7dcdb0c586d0d8bb3f25bfd948d2f418a4ab10" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "chrono" version = "0.4.2" @@ -166,6 +249,24 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cid" +version = "0.2.3" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "integer-encoding 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + +[[package]] +name = "circular-buffer" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "smallvec 0.6.0 (git+https://github.com/Vurich/rust-smallvec.git?branch=array-zero)", +] + [[package]] name = "clap" version = "2.32.0" @@ -181,6 +282,14 @@ dependencies = [ "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cmake" version = "0.1.31" @@ -297,6 +406,19 @@ dependencies = [ "winapi 0.2.8 (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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "base64 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chashmap 2.2.1 (git+https://github.com/redox-os/tfs)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "demo-cli" version = "0.1.0" @@ -395,6 +517,14 @@ name = "difference" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "digest" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dtoa" version = "0.4.2" @@ -443,6 +573,14 @@ dependencies = [ name = "environmental" version = "0.1.0" +[[package]] +name = "error-chain" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "error-chain" version = "0.12.0" @@ -498,7 +636,6 @@ dependencies = [ "crossbeam 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)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -538,41 +675,6 @@ dependencies = [ "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", ] -[[package]] -name = "ethcore-network-devp2p" -version = "1.12.0" -source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" -dependencies = [ - "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-bytes 0.1.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-crypto 0.1.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-logger 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)", - "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnetwork 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity.git)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "path 0.1.0 (git+https://github.com/paritytech/parity.git)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1 (git+https://github.com/paritytech/parity.git)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", - "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethereum-types" version = "0.3.2" @@ -617,6 +719,11 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "etrace" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "exit-future" version = "0.1.2" @@ -626,6 +733,11 @@ dependencies = [ "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fdlimit" version = "0.1.1" @@ -709,11 +821,28 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "futures-mutex" +version = "0.3.0" +source = "git+https://github.com/paritytech/futures-mutex#18ca11258512a1846826bc83782e538ac692d990" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "generic-array" +version = "0.9.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 = "getopts" version = "0.2.17" @@ -830,20 +959,9 @@ dependencies = [ ] [[package]] -name = "igd" -version = "0.7.0" +name = "integer-encoding" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "integer-sqrt" @@ -993,55 +1111,321 @@ dependencies = [ ] [[package]] -name = "kvdb-memorydb" +name = "kvdb-memorydb" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" +dependencies = [ + "kvdb 0.1.0 (git+https://github.com/paritytech/parity.git)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kvdb-rocksdb" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" +dependencies = [ + "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fs-swap 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kvdb 0.1.0 (git+https://github.com/paritytech/parity.git)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)", +] + +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazycell" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.41" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libp2p" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-dns 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-floodsub 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-identify 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-kad 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-mplex 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-ping 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-ratelimit 0.1.1 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-relay 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-secio 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-tcp-transport 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-transport-timeout 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-websocket 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "stdweb 0.1.3 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-core" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bs58 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "multistream-select 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "tokio-dns-unofficial 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bs58 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + +[[package]] +name = "libp2p-identify" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen-pure 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + +[[package]] +name = "libp2p-kad" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bigint 4.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bs58 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-identify 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-ping 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + +[[package]] +name = "libp2p-mplex" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "circular-buffer 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-mutex 0.3.0 (git+https://github.com/paritytech/futures-mutex)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + +[[package]] +name = "libp2p-peerstore" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bs58 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.64 (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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "multistream-select 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-ratelimit" +version = "0.1.1" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "aio-limited 0.1.0 (git+https://github.com/paritytech/aio-limited.git)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + +[[package]] +name = "libp2p-secio" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "asn1_der 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen-pure 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rw-stream-sink 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libp2p-tcp-transport" version = "0.1.0" -source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" dependencies = [ - "kvdb 0.1.0 (git+https://github.com/paritytech/parity.git)", - "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "kvdb-rocksdb" +name = "libp2p-transport-timeout" version = "0.1.0" -source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" dependencies = [ - "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fs-swap 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kvdb 0.1.0 (git+https://github.com/paritytech/parity.git)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (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 = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazycell" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.41" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libp2p-websocket" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "rw-stream-sink 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "websocket 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "linked-hash-map" @@ -1170,6 +1554,47 @@ 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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cid 0.2.3 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "integer-encoding 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "multibase" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base-x 0.2.2 (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=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "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)", +] + +[[package]] +name = "multistream-select" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", +] + [[package]] name = "nan-preserving-float" version = "0.1.0" @@ -1204,6 +1629,15 @@ name = "nodrop" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.38" @@ -1212,6 +1646,14 @@ dependencies = [ "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.4" @@ -1321,11 +1763,6 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "path" -version = "0.1.0" -source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" - [[package]] name = "patricia-trie" version = "0.1.0" @@ -1648,6 +2085,33 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "protobuf" +version = "1.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "protobuf" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "protobuf-codegen" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pulldown-cmark" version = "0.0.3" @@ -1711,6 +2175,23 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rayon" version = "0.8.2" @@ -1894,6 +2375,16 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rw-stream-sink" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "safe-mix" version = "0.1.0" @@ -1988,6 +2479,22 @@ name = "sha1" version = "0.2.0" source = "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 = "sha2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "shell32-sys" version = "0.1.2" @@ -2006,11 +2513,6 @@ dependencies = [ "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "slab" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "slab" version = "0.3.0" @@ -2067,6 +2569,16 @@ name = "smallvec" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "smallvec" +version = "0.6.0" +source = "git+https://github.com/Vurich/rust-smallvec.git?branch=array-zero#cccd87359f8b52b109e96abe3f94815c14b01a67" + [[package]] name = "smallvec" version = "0.6.1" @@ -2095,6 +2607,11 @@ name = "stable_deref_trait" version = "1.0.0" 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 = "strsim" version = "0.7.0" @@ -2270,7 +2787,6 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)", "ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-network-devp2p 1.12.0 (git+https://github.com/paritytech/parity.git)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2283,6 +2799,7 @@ dependencies = [ "substrate-client 0.1.0", "substrate-codec 0.1.0", "substrate-keyring 0.1.0", + "substrate-network-libp2p 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-primitives 0.1.0", "substrate-runtime-support 0.1.0", @@ -2290,6 +2807,28 @@ dependencies = [ "substrate-test-client 0.1.0", ] +[[package]] +name = "substrate-network-libp2p" +version = "0.1.0" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-bytes 0.1.0 (git+https://github.com/paritytech/parity.git)", + "ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)", + "ethcore-logger 1.12.0 (git+https://github.com/paritytech/parity.git)", + "ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)", + "ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.3 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "varint 0.1.0 (git+https://github.com/libp2p/rust-libp2p)", +] + [[package]] name = "substrate-primitives" version = "0.1.0" @@ -2738,6 +3277,18 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.1" @@ -2826,6 +3377,17 @@ dependencies = [ "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-dns-unofficial" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-executor" version = "0.1.2" @@ -2884,17 +3446,6 @@ dependencies = [ "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-retry" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-service" version = "0.1.0" @@ -2929,15 +3480,6 @@ dependencies = [ "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-timer" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-timer" version = "0.2.4" @@ -3035,6 +3577,11 @@ name = "typeable" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.1" @@ -3128,6 +3675,32 @@ name = "utf8-ranges" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "varint" +version = "0.1.0" +source = "git+https://github.com/libp2p/rust-libp2p#857c6653ecc70e480bbedea5a0f393f74af8f414" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "varint" +version = "0.1.0" +source = "git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc#77b1c445807e53b8c5e4e5e2da751222da15b8cc" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "vcpkg" version = "0.2.3" @@ -3269,22 +3842,6 @@ name = "xdg" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "xml-rs" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "xmltree" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "yaml-rust" version = "0.3.5" @@ -3292,28 +3849,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" +"checksum aio-limited 0.1.0 (git+https://github.com/paritytech/aio-limited.git)" = "" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "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" +"checksum arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0fd1479b7c29641adbd35ff3b5c293922d696a92f25c8c975da3e0acbc87258f" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum asn1_der 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f9dec199e4d3e3263a71ec23fd7f0259b3c6963ff83e6bb4871d9d91343d4c81" "checksum assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "664470abf00fae0f31c0eb6e1ca12d82961b2a2541ef898bc9dd51a9254d218b" "checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" "checksum backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbdd17cd962b570302f5297aea8648d5923e22e555c2ed2d8b2e34eca646bf6d" "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" +"checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum base64 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5032d51da2741729bfdaeb2664d9b8c6d9fd1e2b90715c660b6def36628499c2" "checksum base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9263aa6a38da271eec5c91a83ce1e800f093c8535788d403d626d8d5c3f8f007" +"checksum bigint 4.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da1dde4308822ffaa13665757273a1b787481212f3f9b1c470a864b179a01f1b" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "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 bs58 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e6ea4851598d7433fbdba71fa2509d9b0df68124b9c0effe7588f5149692d9f" +"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" "checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" +"checksum chashmap 2.2.1 (git+https://github.com/redox-os/tfs)" = "" "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" +"checksum cid 0.2.3 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum circular-buffer 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" @@ -3328,12 +3899,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" +"checksum datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" +"checksum digest 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3cae2388d706b52f2f2f9afe280f9d768be36544bd71d1b8120cb34ea6450b55" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum edit-distance 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3bd26878c3d921f89797a4e1a1711919f999a9f6946bb6f5a4ffda126d297b7e" "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" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "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 ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" @@ -3342,11 +3916,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-logger 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" -"checksum ethcore-network-devp2p 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c48729b8aea8aedb12cf4cb2e5cef439fdfe2dda4a89e47eeebd15778ef53b6" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)" = "" +"checksum etrace 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5a3eb49b4ae7e88cc23caa812e8072c9f83a3e202e0b789ff4f9319cf796d8ca" "checksum exit-future 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9aa7b56cef68c4182db7212dece19cc9f6e2916cf9412e57e6cea53ec02f316d" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.1.3 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" @@ -3358,7 +3933,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +"checksum futures-mutex 0.3.0 (git+https://github.com/paritytech/futures-mutex)" = "" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" +"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" "checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d" "checksum hashdb 0.1.1 (git+https://github.com/paritytech/parity.git)" = "" @@ -3370,7 +3947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" -"checksum igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a254e265e8810deb357a9de757f784787ec415d056ededf410c0aa460afee9e" +"checksum integer-encoding 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26746cbc2e680af687e88d717f20ff90079bd10fc984ad57d277cd0e37309fa5" "checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "" "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -3394,6 +3971,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)" = "ac8ebf8343a981e2fa97042b14768f02ed3e1d602eac06cae6166df3c8ced206" +"checksum libp2p 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-dns 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-floodsub 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-identify 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-kad 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-mplex 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-peerstore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-ping 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-ratelimit 0.1.1 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-relay 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-secio 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-tcp-transport 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-transport-timeout 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum libp2p-websocket 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ceb20f39ff7ae42f3ff9795f3986b1daad821caaa1e1732a0944103a5a1a66" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" @@ -3409,11 +4001,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum mime 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b28683d0b09bbc20be1c9b3f6f24854efb1356ffcffee08ea3f6e65596e85fa" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "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=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" +"checksum multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" +"checksum multistream-select 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" "checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f" "checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" +"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" "checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" @@ -3426,7 +4024,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" "checksum parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "901d6514273469bb17380c1ac3f51fb3ce54be1f960e51a6f04901eba313ab8d" "checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" -"checksum path 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum patricia-trie 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" @@ -3435,12 +4032,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" "checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" "checksum proc-macro2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1fa93823f53cfd0f5ac117b189aed6cfdfb2cfc0a9d82e956dd7927595ed7d46" +"checksum protobuf 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "52fbc45bf6709565e44ef31847eb7407b3c3c80af811ee884a04da071dcca12b" +"checksum protobuf 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7fec4b8f0fa26c52d29c66e93e8624aad859458ec5e5d4f6ddf923954293436a" +"checksum protobuf-codegen 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9cbd14b640510ad5a4339d8f78ab913a6da1f7b384400fa113616bf216cbdfe8" +"checksum protobuf-codegen-pure 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7fcc3085b0644bcad72ea33f174f267c24e558e56a97115e3ef31a4483581a1b" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pwasm-utils 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "efd695333cfae6e9dbe2703a6d040e252b57a6fc3b9a65c712615ac042b2e0c5" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rand 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6802c0e883716383777e147b7c21323d5de7527257c8b6dc1365a7f2983e90f6" +"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" @@ -3462,6 +4065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-hex 2.0.0 (git+https://github.com/rphmeier/rustc-hex.git)" = "" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a" +"checksum rw-stream-sink 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" @@ -3474,9 +4078,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)" = "79e4620ba6fbe051fc7506fab6f84205823564d55da18d55b695160fb3479cd8" "checksum serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "84b8035cabe9b35878adec8ac5fe03d5f6bc97ff6edd7ccb96b44c1276ba390e" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" +"checksum sha1 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171698ce4ec7cbb93babeb3190021b4d72e96ccb98e33d277ae4ea959d6f2d9e" +"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" "checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum skeptic 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24ebf8a06f5f8bae61ae5bbc7af7aac4ef6907ae975130faba1199e5fe82256a" -"checksum slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6dbdd334bd28d328dad1c41b0ea662517883d8880d8533895ef96c8003dec9c4" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2f7bfce6405155042d42ec0e645efe43eddedd7be280063ce0623b120014e7f9" @@ -3485,16 +4090,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum slog-scope 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "053344c94c0e2b22da6305efddb698d7c485809427cf40555dc936085f67a9df" "checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" "checksum smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4f357e8cd37bf8822e1b964e96fd39e2cb5a0424f8aaa284ccaccc2162411c" +"checksum smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "872c0ff227000041c520cca51e883b858d388ab0ecf646bab76f065cebaec025" +"checksum smallvec 0.6.0 (git+https://github.com/Vurich/rust-smallvec.git?branch=array-zero)" = "" "checksum smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03dab98ab5ded3a8b43b2c80751194608d0b2aa0f1d46cf95d1c35e192844aa7" "checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" +"checksum stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb" "checksum syn 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6dfd71b2be5a58ee30a6f8ea355ba8290d397131c00dfa55c3d34e6e13db5101" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" "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_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" @@ -3503,16 +4112,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" "checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" +"checksum tokio-dns-unofficial 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be509b88bef660929f3066a6ed30260f8c1f3035c5ac80a7c67bb39c9cf28376" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" "checksum tokio-fs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76766830bbf9a2d5bfb50c95350d56a2e79e2c80f675967fff448bc615899708" "checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b" -"checksum tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f05746ae87dca83a2016b4f5dba5b237b897dd12fd324f60afe282112f16969a" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" "checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d" -"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" "checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9" "checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" "checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" @@ -3524,6 +4132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" "checksum twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "475352206e7a290c5fccc27624a163e8d0d115f7bb60ca18a64fc9ce056d7435" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "" "checksum uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38051a96565903d81c9a9210ce11076b2218f3b352926baa1f5f6abbdfce8273" @@ -3537,6 +4146,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum varint 0.1.0 (git+https://github.com/libp2p/rust-libp2p)" = "" +"checksum varint 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)" = "" "checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" @@ -3554,6 +4165,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)" = "" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" -"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" -"checksum xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9cfb54ca6b8f17d2377219ce485b134d53561b77e1393c7ea416f543a527431" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/README.md b/README.md index ccf8d7b165937..15533d032ae05 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ polkadot --chain=local --validator --key Alice -d /tmp/alice and in the other, run: ``` -polkadot --chain=local --validator --key Bob -d /tmp/bob --port 30334 --bootnodes 'enode://ALICE_BOOTNODE_ID_HERE@127.0.0.1:30333' +polkadot --chain=local --validator --key Bob -d /tmp/bob --port 30334 --bootnodes '/ip4/127.0.0.1/tcp/30333/p2p/ALICE_BOOTNODE_ID_HERE' ``` Ensure you replace `ALICE_BOOTNODE_ID_HERE` with the node ID from the output of diff --git a/substrate/network-libp2p/Cargo.toml b/substrate/network-libp2p/Cargo.toml new file mode 100644 index 0000000000000..442b807ad23cd --- /dev/null +++ b/substrate/network-libp2p/Cargo.toml @@ -0,0 +1,27 @@ +[package] +description = "libp2p implementation of the ethcore network library" +homepage = "http://parity.io" +license = "GPL-3.0" +name = "substrate-network-libp2p" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +bytes = "0.4" +fnv = "1.0" +futures = "0.1" +libp2p = { git = "https://github.com/tomaka/libp2p-rs", rev = "77b1c445807e53b8c5e4e5e2da751222da15b8cc", default-features = false, features = ["libp2p-secio", "libp2p-secio-secp256k1"] } +ethcore-network = { git = "https://github.com/paritytech/parity.git" } +ethkey = { git = "https://github.com/paritytech/parity.git" } +parking_lot = "0.5" +log = "0.3" +rand = "0.5.0" +tokio-core = "0.1" +tokio-io = "0.1" +tokio-timer = "0.2" +varint = { git = "https://github.com/libp2p/rust-libp2p" } + +[dev-dependencies] +ethcore-bytes = { git = "https://github.com/paritytech/parity.git" } +ethcore-io = { git = "https://github.com/paritytech/parity.git" } +ethcore-logger = { git = "https://github.com/paritytech/parity.git" } diff --git a/substrate/network-libp2p/src/custom_proto.rs b/substrate/network-libp2p/src/custom_proto.rs new file mode 100644 index 0000000000000..ed98377951755 --- /dev/null +++ b/substrate/network-libp2p/src/custom_proto.rs @@ -0,0 +1,287 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see .? + +use bytes::{Bytes, BytesMut}; +use network::ProtocolId; +use libp2p::core::{Multiaddr, ConnectionUpgrade, Endpoint}; +use network::PacketId; +use std::io::Error as IoError; +use std::vec::IntoIter as VecIntoIter; +use futures::{future, Future, stream, Stream, Sink}; +use futures::sync::mpsc; +use tokio_io::{AsyncRead, AsyncWrite}; +use varint::VarintCodec; + +/// Connection upgrade for a single protocol. +/// +/// Note that "a single protocol" here refers to `par` for example. However +/// each protocol can have multiple different versions for networking purposes. +#[derive(Clone)] +pub struct RegisteredProtocol { + /// Id of the protocol for API purposes. + id: ProtocolId, + /// Base name of the protocol as advertised on the network. + /// Ends with `/` so that we can append a version number behind. + base_name: Bytes, + /// List of protocol versions that we support, plus their packet count. + /// Ordered in descending order so that the best comes first. + /// The packet count is used to filter out invalid messages. + supported_versions: Vec<(u8, u8)>, + /// Custom data. + custom_data: T, +} + +/// Output of a `RegisteredProtocol` upgrade. +pub struct RegisteredProtocolOutput { + /// Data passed to `RegisteredProtocol::new`. + pub custom_data: T, + + /// Id of the protocol. + pub protocol_id: ProtocolId, + + /// Version of the protocol that was negotiated. + pub protocol_version: u8, + + /// Channel to sender outgoing messages to. Closing this channel closes the + /// connection. + // TODO: consider assembling packet_id here + pub outgoing: mpsc::UnboundedSender, + + /// Stream where incoming messages are received. The stream ends whenever + /// either side is closed. + pub incoming: Box>, +} + +impl RegisteredProtocol { + /// Creates a new `RegisteredProtocol`. The `custom_data` parameter will be + /// passed inside the `RegisteredProtocolOutput`. + pub fn new(custom_data: T, protocol: ProtocolId, versions: &[(u8, u8)]) + -> Self { + let mut proto_name = Bytes::from_static(b"/substrate/"); + proto_name.extend_from_slice(&protocol); + proto_name.extend_from_slice(b"/"); + + RegisteredProtocol { + base_name: proto_name, + id: protocol, + supported_versions: { + let mut tmp: Vec<_> = versions.iter().rev().cloned().collect(); + tmp.sort_unstable_by(|a, b| b.1.cmp(&a.1)); + tmp + }, + custom_data: custom_data, + } + } + + /// Returns the ID of the protocol. + pub fn id(&self) -> ProtocolId { + self.id + } + + /// Returns the custom data that was passed to `new`. + pub fn custom_data(&self) -> &T { + &self.custom_data + } +} + +// `Maf` is short for `MultiaddressFuture` +impl ConnectionUpgrade for RegisteredProtocol +where C: AsyncRead + AsyncWrite + 'static, // TODO: 'static :-/ + Maf: Future + 'static, // TODO: 'static :( +{ + type NamesIter = VecIntoIter<(Bytes, Self::UpgradeIdentifier)>; + type UpgradeIdentifier = u8; // Protocol version + + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + // Report each version as an individual protocol. + self.supported_versions.iter().map(|&(ver, _)| { + let num = ver.to_string(); + let mut name = self.base_name.clone(); + name.extend_from_slice(num.as_bytes()); + (name, ver) + }).collect::>().into_iter() + } + + type Output = RegisteredProtocolOutput; + type MultiaddrFuture = Maf; + type Future = future::FutureResult<(Self::Output, Self::MultiaddrFuture), IoError>; + + fn upgrade( + self, + socket: C, + protocol_version: Self::UpgradeIdentifier, + endpoint: Endpoint, + remote_addr: Maf + ) -> Self::Future { + let packet_count = self.supported_versions + .iter() + .find(|&(v, _)| *v == protocol_version) + .expect("negotiated protocol version that wasn't advertised ; \ + programmer error") + .1; + + // This function is called whenever we successfully negotiated a + // protocol with a remote (both if initiated by us or by the remote) + + // This channel is used to send outgoing packets to the custom_data + // for this open substream. + let (msg_tx, msg_rx) = mpsc::unbounded(); + + // Build the sink for outgoing network bytes, and the stream for + // incoming instructions. `stream` implements `Stream`. + enum Message { + /// Received data from the network. + RecvSocket(BytesMut), + /// Data to send to the network. + /// The packet_id must already be inside the `Bytes`. + SendReq(Bytes), + /// The socket has been closed. + Finished, + } + + let (sink, stream) = { + let framed = AsyncRead::framed(socket, VarintCodec::default()); + let msg_rx = msg_rx.map(Message::SendReq) + .chain(stream::once(Ok(Message::Finished))) + .map_err(|()| unreachable!("mpsc::UnboundedReceiver never errors")); + let (sink, stream) = framed.split(); + let stream = stream.map(Message::RecvSocket) + .chain(stream::once(Ok(Message::Finished))); + (sink, msg_rx.select(stream)) + }; + + let incoming = stream::unfold((sink, stream, false), move |(sink, stream, finished)| { + if finished { + return None + } + + Some(stream + .into_future() + .map_err(|(err, _)| err) + .and_then(move |(message, stream)| + match message { + Some(Message::RecvSocket(mut data)) => { + // The `data` should be prefixed by the packet ID, + // therefore an empty packet is invalid. + if data.is_empty() { + debug!(target: "sub-libp2p", "ignoring incoming \ + packet because it was empty"); + let f = future::ok((None, (sink, stream, false))); + return future::Either::A(f) + } + + let packet_id = data[0]; + let data = data.split_off(1); + + if packet_id >= packet_count { + debug!(target: "sub-libp2p", "ignoring incoming packet \ + because packet_id {} is too large", packet_id); + let f = future::ok((None, (sink, stream, false))); + future::Either::A(f) + } else { + let out = Some((packet_id, data.freeze())); + let f = future::ok((out, (sink, stream, false))); + future::Either::A(f) + } + }, + + Some(Message::SendReq(data)) => { + let fut = sink.send(data) + .map(move |sink| (None, (sink, stream, false))); + future::Either::B(fut) + }, + + Some(Message::Finished) | None => { + let f = future::ok((None, (sink, stream, true))); + future::Either::A(f) + }, + } + )) + }).filter_map(|v| v); + + let out = RegisteredProtocolOutput { + custom_data: self.custom_data, + protocol_id: self.id, + protocol_version: protocol_version, + outgoing: msg_tx, + incoming: Box::new(incoming), + }; + + future::ok((out, remote_addr)) + } +} + +// Connection upgrade for all the protocols contained in it. +#[derive(Clone)] +pub struct RegisteredProtocols(pub Vec>); + +impl RegisteredProtocols { + /// 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) + } +} + +impl Default for RegisteredProtocols { + fn default() -> Self { + RegisteredProtocols(Vec::new()) + } +} + +impl ConnectionUpgrade for RegisteredProtocols +where C: AsyncRead + AsyncWrite + 'static, // TODO: 'static :-/ + Maf: Future + 'static, // TODO: 'static :( +{ + type NamesIter = VecIntoIter<(Bytes, Self::UpgradeIdentifier)>; + type UpgradeIdentifier = (usize, + as ConnectionUpgrade>::UpgradeIdentifier); + + fn protocol_names(&self) -> Self::NamesIter { + // 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))) + ).collect::>().into_iter() + } + + type Output = as ConnectionUpgrade>::Output; + type MultiaddrFuture = as + ConnectionUpgrade>::MultiaddrFuture; + type Future = as ConnectionUpgrade>::Future; + + #[inline] + fn upgrade( + self, + socket: C, + upgrade_identifier: Self::UpgradeIdentifier, + endpoint: Endpoint, + remote_addr: Maf + ) -> 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, remote_addr) + } +} diff --git a/substrate/network-libp2p/src/lib.rs b/substrate/network-libp2p/src/lib.rs new file mode 100644 index 0000000000000..59104fcd84dc8 --- /dev/null +++ b/substrate/network-libp2p/src/lib.rs @@ -0,0 +1,49 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see .? + +#![type_length_limit = "268435456"] + +extern crate parking_lot; +extern crate fnv; +extern crate futures; +extern crate tokio_core; +extern crate tokio_io; +extern crate tokio_timer; +extern crate ethkey; +extern crate ethcore_network as network; +extern crate libp2p; +extern crate rand; +extern crate bytes; +extern crate varint; + +#[macro_use] +extern crate log; + +mod custom_proto; +mod network_state; +mod service; +mod timeouts; +mod transport; + +pub use service::NetworkService; + +/// Check if node url is valid +pub fn validate_node_url(url: &str) -> Result<(), network::Error> { + match url.parse::() { + Ok(_) => Ok(()), + Err(_) => Err(network::ErrorKind::InvalidNodeId.into()), + } +} diff --git a/substrate/network-libp2p/src/network_state.rs b/substrate/network-libp2p/src/network_state.rs new file mode 100644 index 0000000000000..ff8e34c139fa5 --- /dev/null +++ b/substrate/network-libp2p/src/network_state.rs @@ -0,0 +1,861 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see .? + +use bytes::Bytes; +use fnv::{FnvHashMap, FnvHashSet}; +use futures::{future, Future, Stream, sync::mpsc}; +use libp2p::core::{Multiaddr, AddrComponent, Endpoint}; +use libp2p::core::{PeerId as PeerstorePeerId, PublicKey}; +use libp2p::kad::KadConnecController; +use libp2p::peerstore::{Peerstore, PeerAccess}; +use libp2p::peerstore::json_peerstore::JsonPeerstore; +use libp2p::peerstore::memory_peerstore::MemoryPeerstore; +use libp2p::secio; +use network::{Error, ErrorKind, NetworkConfiguration, NonReservedPeerMode}; +use network::{PeerId, ProtocolId, SessionInfo}; +use parking_lot::{Mutex, RwLock}; +use rand::{self, Rng}; +use std::cmp; +use std::fs; +use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read, Write}; +use std::path::Path; +use std::sync::atomic; +use std::time::Duration; + +// File where the peers are stored. +const NODES_FILE: &str = "nodes.json"; +// File where the private key is stored. +const SECRET_FILE: &str = "secret"; + +// Common struct shared throughout all the components of the service. +pub struct NetworkState { + /// Contains the information about the network. + peerstore: PeersStorage, + + /// Active connections. + connections: RwLock, + + /// `min_peers` taken from the configuration. + min_peers: u32, + /// `max_peers` taken from the configuration. + max_peers: u32, + + /// If true, only reserved peers can connect. + reserved_only: atomic::AtomicBool, + /// List of the IDs of the reserved peers. + reserved_peers: RwLock>, + + /// Each peer gets assigned a new unique ID. This ID increases linearly. + next_peer_id: atomic::AtomicUsize, + + /// List of the IDs of the disabled peers. These peers will see their + /// connections refused. + disabled_peers: RwLock>, + + /// Local private key. + local_private_key: secio::SecioKeyPair, + /// Local public key. + local_public_key: PublicKey, +} + +enum PeersStorage { + /// Peers are stored in memory. Nothing is stored on disk. + Memory(MemoryPeerstore), + /// Peers are stored in a JSON file on the disk. + Json(JsonPeerstore), +} + +struct Connections { + /// For each libp2p peer ID, the ID of the peer in the API we expose. + /// Also corresponds to the index in `info_by_peer`. + peer_by_nodeid: FnvHashMap, + + /// For each peer ID, information about our connection to this peer. + info_by_peer: FnvHashMap, +} + +struct PeerConnectionInfo { + /// A list of message senders per protocol, and the protocol version. + /// The sender can be used to transmit data for the remote. Note that the + /// packet_id has to be inside the `Bytes`. + /// Closing the sender will drop the substream of this protocol. + senders: Vec<(ProtocolId, mpsc::UnboundedSender, u8)>, + + /// True if we dialed a Kad connection towards this peer. + /// This indicates that `kad_connec` should eventually resolve, even + /// without doing anything. + opened_kad: bool, + + /// When a Kad connection is received, we send it on this channel so that + /// it will be received by `kad_connec`. + incoming_kad_channel: mpsc::UnboundedSender, + + /// The Kademlia connection to this node. + /// Contains the receiving end of `incoming_kad_channel`. If `opened_kad` + /// is true, we are guaranteed to finish. + /// TODO: proper error handling if a kad connection is closed + kad_connec: future::Shared>>, + + /// Id of the peer. + id: PeerstorePeerId, + + /// True if this connection was initiated by us. + /// Note that it is theoretically possible that we dial the remote at the + /// same time they dial us, in which case the protocols may be dispatched + /// between both connections, and in which case the value here will be racy. + originated: bool, + + /// Latest known ping duration. + ping: Mutex>, + + /// The client version of the remote, or `None` if not known. + client_version: Option, + + /// The multiaddress of the remote, or `None` if not known. + remote_address: Option, + + /// The local multiaddress used to communicate with the remote, or `None` + /// if not known. + local_address: Option, +} + +impl NetworkState { + pub fn new(config: &NetworkConfiguration) -> Result { + // Private and public keys configuration. + let local_private_key = obtain_private_key(&config)?; + let local_public_key = local_private_key.to_public_key(); + + // Build the storage for peers, including the bootstrap nodes. + let peerstore = if let Some(ref path) = config.net_config_path { + let path = Path::new(path).join(NODES_FILE); + if let Ok(peerstore) = JsonPeerstore::new(path.clone()) { + debug!(target: "sub-libp2p", "Initialized peer store for JSON \ + file {:?}", path); + PeersStorage::Json(peerstore) + } else { + warn!(target: "sub-libp2p", "Failed to open peer storage {:?} \ + ; peers won't be saved", path); + PeersStorage::Memory(MemoryPeerstore::empty()) + } + } else { + debug!(target: "sub-libp2p", "No peers file configured ; peers \ + won't be saved"); + PeersStorage::Memory(MemoryPeerstore::empty()) + }; + + for bootnode in config.boot_nodes.iter() { + parse_and_add_to_peerstore(bootnode, &peerstore)?; + } + + let reserved_peers = { + let mut reserved_peers = FnvHashSet::with_capacity_and_hasher( + config.reserved_nodes.len(), + Default::default() + ); + for peer in config.reserved_nodes.iter() { + let id = parse_and_add_to_peerstore(peer, &peerstore)?; + reserved_peers.insert(id); + } + RwLock::new(reserved_peers) + }; + + let expected_max_peers = cmp::max(config.max_peers as usize, + config.reserved_nodes.len()); + + Ok(NetworkState { + peerstore, + min_peers: config.min_peers, + max_peers: config.max_peers, + connections: RwLock::new(Connections { + peer_by_nodeid: FnvHashMap::with_capacity_and_hasher(expected_max_peers, Default::default()), + info_by_peer: FnvHashMap::with_capacity_and_hasher(expected_max_peers, Default::default()), + }), + reserved_only: atomic::AtomicBool::new(false), + reserved_peers, + next_peer_id: atomic::AtomicUsize::new(0), + disabled_peers: RwLock::new(Default::default()), + local_private_key, + local_public_key, + }) + } + + /// Returns the private key of the local node. + pub fn local_private_key(&self) -> &secio::SecioKeyPair { + &self.local_private_key + } + + /// Returns the public key of the local node. + pub fn local_public_key(&self) -> &PublicKey { + &self.local_public_key + } + + /// Returns all the IDs of the peer we have knowledge of. + /// + /// This includes peers we are not connected to. + pub fn known_peers(&self) -> impl Iterator { + match self.peerstore { + PeersStorage::Memory(ref mem) => + mem.peers().collect::>().into_iter(), + PeersStorage::Json(ref json) => + json.peers().collect::>().into_iter(), + } + } + + /// Returns true if we are connected to any peer at all. + pub fn has_connected_peer(&self) -> bool { + !self.connections.read().peer_by_nodeid.is_empty() + } + + /// Get a list of all connected peers by id. + pub fn connected_peers(&self) -> Vec { + self.connections.read().peer_by_nodeid.values().cloned().collect() + } + + /// Returns true if the given `PeerId` is valid. + /// + /// `PeerId`s are never reused, so once this function returns `false` it + /// will never return `true` again for the same `PeerId`. + pub fn is_peer_connected(&self, peer: PeerId) -> bool { + self.connections.read().info_by_peer.contains_key(&peer) + } + + /// Reports the ping of the peer. Returned later by `session_info()`. + /// No-op if the `peer_id` is not valid/expired. + pub fn report_ping(&self, peer_id: PeerId, ping: Duration) { + let connections = self.connections.read(); + let info = match connections.info_by_peer.get(&peer_id) { + Some(info) => info, + None => return, + }; + + *info.ping.lock() = Some(ping); + } + + /// If we're connected to a peer with the given protocol, returns + /// information about the connection. Otherwise, returns `None`. + pub fn session_info(&self, peer: PeerId, protocol: ProtocolId) + -> Option { + let connections = self.connections.read(); + let info = match connections.info_by_peer.get(&peer) { + Some(info) => info, + None => return None, + }; + + let protocol_version = match info.senders.iter().find(|&(ref p, _, _)| p == &protocol) { + Some(&(_, _, version)) => version as u32, + None => return None, + }; + + let ping = info.ping.lock().clone(); + + Some(SessionInfo { + id: None, // TODO: ???? what to do??? wrong format! + client_version: info.client_version.clone().take().unwrap_or(String::new()), + protocol_version, + capabilities: Vec::new(), // TODO: list of supported protocols ; hard + peer_capabilities: Vec::new(), // TODO: difference with `peer_capabilities`? + ping, + originated: info.originated, + remote_address: info.remote_address.as_ref().map(|a| a.to_string()) + .unwrap_or(String::new()), + local_address: info.local_address.as_ref().map(|a| a.to_string()) + .unwrap_or(String::new()), + }) + } + + /// If we're connected to a peer with the given protocol, returns the + /// protocol version. Otherwise, returns `None`. + pub fn protocol_version(&self, peer: PeerId, protocol: ProtocolId) + -> Option { + let connections = self.connections.read(); + let peer = match connections.info_by_peer.get(&peer) { + Some(peer) => peer, + None => return None, + }; + + peer.senders.iter().find(|p| p.0 == protocol).map(|p| p.2) + } + + /// Equivalent to `session_info(peer).map(|info| info.client_version)`. + pub fn peer_client_version(&self, peer: PeerId, protocol: ProtocolId) + -> Option { + // TODO: implement more directly, without going through `session_info` + self.session_info(peer, protocol) + .map(|info| info.client_version) + } + + /// Adds an address discovered by Kademlia. + /// Note that we don't have to be connected to a peer to add an address. + pub fn add_kad_discovered_addr(&self, node_id: &PeerstorePeerId, addr: Multiaddr) { + match self.peerstore { + PeersStorage::Memory(ref mem) => + mem.peer_or_create(node_id) + .add_addr(addr, Duration::from_secs(3600)), + PeersStorage::Json(ref json) => + json.peer_or_create(node_id) + .add_addr(addr, Duration::from_secs(3600)), + } + } + + /// Signals that an address doesn't match the corresponding node ID. + /// This removes the address from the peer store, so that it is not + /// returned by `addrs_of_peer` again in the future. + pub fn set_invalid_kad_address(&self, node_id: &PeerstorePeerId, + addr: &Multiaddr) { + // TODO: blacklist the address? + match self.peerstore { + PeersStorage::Memory(ref mem) => + if let Some(mut peer) = mem.peer(node_id) { + peer.rm_addr(addr.clone()) // TODO: cloning necessary? + }, + PeersStorage::Json(ref json) => + if let Some(mut peer) = json.peer(node_id) { + peer.rm_addr(addr.clone()) // TODO: cloning necessary? + }, + } + } + + /// Returns the known multiaddresses of a peer. + pub fn addrs_of_peer(&self, node_id: &PeerstorePeerId) -> Vec { + match self.peerstore { + PeersStorage::Memory(ref mem) => + mem.peer(node_id) + .into_iter() + .flat_map(|p| p.addrs()) + .collect::>(), + PeersStorage::Json(ref json) => + json.peer(node_id) + .into_iter() + .flat_map(|p| p.addrs()) + .collect::>(), + } + } + + /// Sets information about a peer. + pub fn set_peer_info( + &self, + node_id: PeerstorePeerId, + endpoint: Endpoint, + client_version: String, + local_addr: Multiaddr, + remote_addr: Multiaddr + ) -> Result { + let mut connections = self.connections.write(); + let peer_id = accept_connection(&mut connections, &self.next_peer_id, + node_id.clone(), endpoint)?; + let infos = connections.info_by_peer.get_mut(&peer_id) + .expect("Newly-created peer id is always valid"); + + infos.client_version = Some(client_version); + infos.remote_address = Some(remote_addr); + infos.local_address = Some(local_addr); + + Ok(peer_id) + } + + /// Adds a reserved peer to the list of reserved peers. + /// Returns an error if the peer address is invalid. + pub fn add_reserved_peer(&self, peer: &str) -> Result<(), Error> { + let id = parse_and_add_to_peerstore(peer, &self.peerstore)?; + self.reserved_peers.write().insert(id); + Ok(()) + } + + /// Removes the peer from the list of reserved peers. If we're in reserved mode, drops any + /// active connection to this peer. + /// Returns an error if the peer address is invalid. + pub fn remove_reserved_peer(&self, peer: &str) -> Result<(), Error> { + let id = parse_and_add_to_peerstore(peer, &self.peerstore)?; + self.reserved_peers.write().remove(&id); + + // Dropping the peer if we're in reserved mode. + if self.reserved_only.load(atomic::Ordering::SeqCst) { + let mut connections = self.connections.write(); + if let Some(peer_id) = connections.peer_by_nodeid.remove(&id) { + connections.info_by_peer.remove(&peer_id); + } + } + + Ok(()) + } + + /// Set the non-reserved peer mode. + pub fn set_non_reserved_mode(&self, mode: NonReservedPeerMode) { + match mode { + NonReservedPeerMode::Accept => + self.reserved_only.store(false, atomic::Ordering::SeqCst), + NonReservedPeerMode::Deny => + // TODO: drop existing peers? + self.reserved_only.store(true, atomic::Ordering::SeqCst), + } + } + + /// Returns true if we should open a new outgoing connection to a peer. + /// This takes into account the number of active peers. + pub fn should_open_outgoing_connections(&self) -> bool { + !self.reserved_only.load(atomic::Ordering::Relaxed) && + self.connections.read().peer_by_nodeid.len() < self.min_peers as usize + } + + /// Returns true if we are connected to the given node. + pub fn has_connection(&self, node_id: &PeerstorePeerId) -> bool { + let connections = self.connections.read(); + connections.peer_by_nodeid.contains_key(node_id) + } + + /// Returns true if we are connected to the given node with the given protocol. + pub fn has_protocol_connection(&self, node_id: &PeerstorePeerId, + protocol_id: ProtocolId) -> bool { + let connections = self.connections.read(); + if let Some(peer) = connections.peer_by_nodeid.get(node_id) { + let info = match connections.info_by_peer.get(&peer) { + Some(peer) => peer, + None => return false, + }; + info.senders.iter().any(|p| p.0 == protocol_id) + } else { + false + } + } + + /// Call this when a Kademlia connection has been opened from a remote. + pub fn incoming_kad_connection(&self, node_id: PeerstorePeerId, + ctrl: KadConnecController) -> Result { + // TODO: check that the peer is disabled? should disabling a peer also prevent + // kad from working? + let mut connections = self.connections.write(); + let peer_id = accept_connection(&mut connections, &self.next_peer_id, + node_id, Endpoint::Listener)?; + let infos = connections.info_by_peer.get_mut(&peer_id) + .expect("Newly-created peer id is always valid"); + let _ = infos.incoming_kad_channel.unbounded_send(ctrl); + Ok(peer_id) + } + + /// Obtain a Kademlia connection to the given peer. + pub fn obtain_kad_connection(&self, node_id: PeerstorePeerId, opener: F) + -> Result<(PeerId, impl Future), IoError> + where F: FnOnce() -> Fut, Fut: Future + { + let mut connections = self.connections.write(); + let peer_id = accept_connection(&mut connections, &self.next_peer_id, + node_id, Endpoint::Dialer)?; + let infos = connections.info_by_peer.get_mut(&peer_id) + .expect("Newly-created peer id is always valid"); + + let future_to_process = if !infos.opened_kad { + let tx = infos.incoming_kad_channel.clone(); + let new_kad = opener().and_then(move |ctrl| { + tx.unbounded_send(ctrl.clone()) + .map_err(|err| IoError::new(IoErrorKind::ConnectionAborted, err))?; + Ok(ctrl) + }); + infos.opened_kad = true; + future::Either::A(new_kad) + } else { + future::Either::B(future::empty()) + }; + + let fut = infos.kad_connec + .clone() + .map(|ctrl| (*ctrl).clone()) + .map_err(|err| IoError::new(IoErrorKind::ConnectionAborted, err)) + .select(future_to_process) + .map(|(item, _)| item) + .map_err(|(err, _)| err); + + Ok((peer_id, fut)) + } + + /// Disconnect the Kademlia controller with the peer. + pub fn disconnect_kademlia(&self, peer_id: PeerId) { + let mut connections = self.connections.write(); + if let Some(peer) = connections.info_by_peer.get_mut(&peer_id) { + // TODO: that's code duplication + let (tx, rx) = mpsc::unbounded(); + let rx = rx.into_future() + .map_err(|_| -> IoError { unreachable!("an `UnboundedReceiver` can never produce an error") }) + .and_then(|i| i.0.ok_or(IoError::new( + IoErrorKind::ConnectionAborted, "kad aborted"))); + let kad_connec = Box::new(rx) as Box>; + + peer.incoming_kad_channel = tx; + peer.kad_connec = kad_connec.shared(); + peer.opened_kad = false; + } + } + + /// Try to add a new connection to a node in the list. + /// + /// Returns a `PeerId` to allow further interfacing with this connection. + /// Note that all `PeerId`s are unique and never reused. + /// + /// Can return an error if we are refusing the connection to the remote. + /// + /// You must pass an `UnboundedSender` which will be used by the `send` + /// method. Actually sending the data is not covered by this code. + /// + /// The various methods of the `NetworkState` that close a connection do + /// so by dropping this sender. + pub fn accept_custom_proto( + &self, + node_id: PeerstorePeerId, + protocol_id: ProtocolId, + protocol_version: u8, + endpoint: Endpoint, + msg_tx: mpsc::UnboundedSender + ) -> Result { + let mut connections = self.connections.write(); + + if self.disabled_peers.read().contains(&node_id) { + debug!(target: "sub-libp2p", "Refusing node {:?} because it was \ + disabled", node_id); + return Err(IoError::new(IoErrorKind::PermissionDenied, + "disabled peer")) + } + + let peer_id = accept_connection(&mut connections, &self.next_peer_id, + node_id.clone(), endpoint)?; + + let connections = &mut *connections; + let info_by_peer = &mut connections.info_by_peer; + let peer_by_nodeid = &mut connections.peer_by_nodeid; + let infos = info_by_peer.get_mut(&peer_id) + .expect("Newly-created peer id is always valid"); + + let node_is_reserved = self.reserved_peers.read().contains(&infos.id); + if !node_is_reserved { + if self.reserved_only.load(atomic::Ordering::Relaxed) || + peer_by_nodeid.len() >= self.max_peers as usize + { + debug!(target: "sub-libp2p", "Refusing node {:?} because we \ + reached the max number of peers", node_id); + return Err(IoError::new(IoErrorKind::PermissionDenied, + "maximum number of peers reached")) + } + } + + if !infos.senders.iter().any(|&(prot, _, _)| prot == protocol_id) { + infos.senders.push((protocol_id.clone(), msg_tx, protocol_version)); + } + + Ok(peer_id) + } + + /// Sends some data to the given peer, using the sender that was passed + /// to `accept_custom_proto`. + pub fn send(&self, protocol: ProtocolId, peer_id: PeerId, message: Bytes) + -> Result<(), Error> { + if let Some(peer) = self.connections.read().info_by_peer.get(&peer_id) { + let sender = peer.senders.iter().find(|elem| elem.0 == protocol) + .map(|e| &e.1); + if let Some(sender) = sender { + sender.unbounded_send(message) + .map_err(|err| ErrorKind::Io(IoError::new(IoErrorKind::Other, err)))?; + Ok(()) + } else { + // We are connected to this peer, but not with the current + // protocol. + debug!(target: "sub-libp2p", "Tried to send message to peer {} \ + for which we aren't connected with the requested protocol", + peer_id); + return Err(ErrorKind::PeerNotFound.into()) + } + } else { + debug!(target: "sub-libp2p", "Tried to send message to invalid \ + peer ID {}", peer_id); + return Err(ErrorKind::PeerNotFound.into()) + } + } + + /// Disconnects a peer, if a connection exists (ie. drops the Kademlia + /// controller, and the senders that were passed to `accept_custom_proto`). + pub fn disconnect_peer(&self, peer_id: PeerId) { + let mut connections = self.connections.write(); + if let Some(peer_info) = connections.info_by_peer.remove(&peer_id) { + let old = connections.peer_by_nodeid.remove(&peer_info.id); + debug_assert_eq!(old, Some(peer_id)); + } + } + + /// Disconnects all the peers. + /// This destroys all the Kademlia controllers and the senders that were + /// passed to `accept_custom_proto`. + pub fn disconnect_all(&self) { + let mut connec = self.connections.write(); + *connec = Connections { + info_by_peer: FnvHashMap::with_capacity_and_hasher( + connec.peer_by_nodeid.capacity(), Default::default()), + peer_by_nodeid: FnvHashMap::with_capacity_and_hasher( + connec.peer_by_nodeid.capacity(), Default::default()), + }; + } + + /// Disables a peer. This adds the peer to the list of disabled peers, and + /// drops any existing connections if necessary (ie. drops the sender that + /// was passed to `accept_custom_proto`). + pub fn disable_peer(&self, peer_id: PeerId) { + // TODO: what do we do if the peer is reserved? + let mut connections = self.connections.write(); + let peer_info = if let Some(peer_info) = connections.info_by_peer.remove(&peer_id) { + let old = connections.peer_by_nodeid.remove(&peer_info.id); + debug_assert_eq!(old, Some(peer_id)); + peer_info + } else { + return + }; + + drop(connections); + self.disabled_peers.write().insert(peer_info.id.clone()); + } + + /// Returns true if a peer is disabled. + pub fn is_peer_disabled(&self, node_id: &PeerstorePeerId) -> bool { + self.disabled_peers.read().contains(&node_id) + } + + /// Flushes the caches to the disk. + /// + /// This is done in an atomical way, so that an error doesn't corrupt + /// anything. + pub fn flush_caches_to_disk(&self) -> Result<(), IoError> { + match self.peerstore { + PeersStorage::Memory(_) => Ok(()), + PeersStorage::Json(ref json) => + match json.flush() { + Ok(()) => { + debug!(target: "sub-libp2p", "Flushed JSON peer store \ + to disk"); + Ok(()) + } + Err(err) => { + warn!(target: "sub-libp2p", "Failed to flush changes \ + to JSON peer store: {}", err); + Err(err) + } + } + } + } +} + +impl Drop for NetworkState { + fn drop(&mut self) { + let _ = self.flush_caches_to_disk(); + } +} + +/// Assigns a `PeerId` to a node, or returns an existing ID if any exists. +/// +/// The function only accepts already-locked structs, so that we don't risk +/// any deadlock. +fn accept_connection( + connections: &mut Connections, + next_peer_id: &atomic::AtomicUsize, + node_id: PeerstorePeerId, + endpoint: Endpoint +) -> Result { + let peer_by_nodeid = &mut connections.peer_by_nodeid; + let info_by_peer = &mut connections.info_by_peer; + + let peer_id = *peer_by_nodeid.entry(node_id.clone()).or_insert_with(|| { + let new_id = next_peer_id.fetch_add(1, atomic::Ordering::Relaxed); + + let (tx, rx) = mpsc::unbounded(); + let rx = rx + .into_future() + .map_err(|_| -> IoError { unreachable!("an `UnboundedReceiver` can never produce an error") }) + .and_then(|i| i.0.ok_or(IoError::new(IoErrorKind::ConnectionAborted, "kad aborted"))); + let kad_connec = Box::new(rx) as Box>; + + info_by_peer.insert(new_id, PeerConnectionInfo { + senders: Vec::new(), // TODO: Vec::with_capacity(num_registered_protocols), + opened_kad: false, + incoming_kad_channel: tx, + kad_connec: kad_connec.shared(), + id: node_id.clone(), + originated: endpoint == Endpoint::Dialer, + ping: Mutex::new(None), + client_version: None, + local_address: None, + remote_address: None, + }); + new_id + }); + + Ok(peer_id) +} + +/// Parses an address of the form `/ip4/x.x.x.x/tcp/x/p2p/xxxxxx`, and adds it +/// to the given peerstore. Returns the corresponding peer ID. +fn parse_and_add_to_peerstore(addr_str: &str, peerstore: &PeersStorage) + -> Result { + let mut addr: Multiaddr = addr_str.parse() + .map_err(|_| ErrorKind::AddressParse)?; + let p2p_component = addr.pop().ok_or(ErrorKind::AddressParse)?; + let peer_id = match p2p_component { + AddrComponent::P2P(key) | AddrComponent::IPFS(key) => + PeerstorePeerId::from_bytes(key).map_err(|_| ErrorKind::AddressParse)?, + _ => return Err(ErrorKind::BadProtocol.into()), + }; + + // Registering the bootstrap node with a TTL of 100000 years TODO: wrong + match peerstore { + PeersStorage::Memory(ref peerstore) => + peerstore + .peer_or_create(&peer_id) + .add_addr(addr, Duration::from_secs(100000 * 365 * 24 * 3600)), + PeersStorage::Json(ref peerstore) => + peerstore + .peer_or_create(&peer_id) + .add_addr(addr, Duration::from_secs(100000 * 365 * 24 * 3600)), + } + + Ok(peer_id) +} + +/// Obtains or generates the local private key using the configuration. +fn obtain_private_key(config: &NetworkConfiguration) + -> Result { + if let Some(ref secret) = config.use_secret { + // Key was specified in the configuration. + secio::SecioKeyPair::secp256k1_raw_key(&secret[..]) + .map_err(|err| IoError::new(IoErrorKind::InvalidData, err)) + + } else { + if let Some(ref path) = config.net_config_path { + fs::create_dir_all(Path::new(path))?; + + // Try fetch the key from a the file containing th esecret. + let secret_path = Path::new(path).join(SECRET_FILE); + match load_private_key_from_file(&secret_path) { + Ok(s) => Ok(s), + Err(err) => { + // Failed to fetch existing file ; generate a new key + trace!(target: "sub-libp2p", "Failed to load existing \ + secret key file {:?}, generating new key ; err = {:?}", + secret_path, err); + Ok(gen_key_and_try_write_to_file(&secret_path)) + } + } + + } else { + // No path in the configuration, nothing we can do except generate + // a new key. + let mut key: [u8; 32] = [0; 32]; + rand::rngs::EntropyRng::new().fill(&mut key); + Ok(secio::SecioKeyPair::secp256k1_raw_key(&key) + .expect("randomly-generated key with correct len should \ + always be valid")) + } + } +} + +/// Tries to load a private key from a file located at the given path. +fn load_private_key_from_file

(path: P) + -> Result + where P: AsRef + { + fs::File::open(path) + .and_then(|mut file| { + // We are in 2018 and there is still no method on `std::io::Read` + // that directly returns a `Vec`. + let mut buf = Vec::new(); + file.read_to_end(&mut buf).map(|_| buf) + }) + .and_then(|content| + secio::SecioKeyPair::secp256k1_raw_key(&content) + .map_err(|err| IoError::new(IoErrorKind::InvalidData, err)) + ) +} + +/// Generates a new secret key and tries to write it to the given file. +/// Doesn't error if we couldn't open or write to the file. +fn gen_key_and_try_write_to_file

(path: P) -> secio::SecioKeyPair + where P: AsRef { + let raw_key: [u8; 32] = rand::rngs::EntropyRng::new().gen(); + let secio_key = secio::SecioKeyPair::secp256k1_raw_key(&raw_key) + .expect("randomly-generated key with correct len should always be valid"); + + // And store the newly-generated key in the file if possible. + // Errors that happen while doing so are ignored. + match open_priv_key_file(&path) { + Ok(mut file) => + match file.write_all(&raw_key) { + Ok(()) => (), + Err(err) => warn!(target: "sub-libp2p", "Failed to write \ + secret key in file {:?} ; err = {:?}", path.as_ref(), err), + }, + Err(err) => + warn!(target: "sub-libp2p", "Failed to store secret key in file \ + {:?} ; err = {:?}", path.as_ref(), err), + } + + secio_key +} + +/// Opens a file containing a private key in write mode. +#[cfg(unix)] +fn open_priv_key_file

(path: P) -> Result + where P: AsRef +{ + use std::os::unix::fs::OpenOptionsExt; + fs::OpenOptions::new() + .write(true) + .create_new(true) + .mode(256 | 128) // 0o600 in decimal + .open(path) +} +/// Opens a file containing a private key in write mode. +#[cfg(not(unix))] +fn open_priv_key_file

(path: P) -> Result + where P: AsRef +{ + fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(path) +} + +#[cfg(test)] +mod tests { + use futures::sync::mpsc; + use libp2p::core::{Endpoint, PublicKey}; + use network_state::NetworkState; + + #[test] + fn refuse_disabled_peer() { + let state = NetworkState::new(&Default::default()).unwrap(); + let example_peer = PublicKey::Rsa(vec![1, 2, 3, 4]).into_peer_id(); + + let peer_id = state.accept_custom_proto( + example_peer.clone(), + [1, 2, 3], + 1, + Endpoint::Dialer, + mpsc::unbounded().0 + ).unwrap(); + + state.disable_peer(peer_id); + + assert!(state.accept_custom_proto( + example_peer.clone(), + [1, 2, 3], + 1, + Endpoint::Dialer, + mpsc::unbounded().0 + ).is_err()); + } +} diff --git a/substrate/network-libp2p/src/service.rs b/substrate/network-libp2p/src/service.rs new file mode 100644 index 0000000000000..1983fc60eb234 --- /dev/null +++ b/substrate/network-libp2p/src/service.rs @@ -0,0 +1,1101 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see .? + +use bytes::Bytes; +use network::{Error, ErrorKind, NetworkConfiguration, NetworkProtocolHandler}; +use network::{NonReservedPeerMode, NetworkContext, PeerId, ProtocolId}; +use parking_lot::{Mutex, RwLock}; +use libp2p; +use libp2p::multiaddr::{AddrComponent, Multiaddr}; +use libp2p::kad::{KadSystem, KadConnecConfig, KadSystemConfig}; +use libp2p::kad::{KadIncomingRequest, KadConnecController, KadPeer}; +use libp2p::kad::{KadConnectionType, KadQueryEvent}; +use libp2p::identify::{IdentifyInfo, IdentifyOutput, IdentifyTransportOutcome}; +use libp2p::identify::{IdentifyProtocolConfig, PeerIdTransport}; +use libp2p::core::{upgrade, Transport, MuxedTransport, ConnectionUpgrade}; +use libp2p::core::{Endpoint, PeerId as PeerstorePeerId, PublicKey}; +use libp2p::core::SwarmController; +use libp2p::ping; +use network::{PacketId, SessionInfo, ConnectionFilter, TimerToken}; +use rand; +use std::io::{Error as IoError, ErrorKind as IoErrorKind}; +use std::iter; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::sync::Arc; +use std::sync::mpsc as sync_mpsc; +use std::thread; +use std::time::{Duration, Instant}; +use futures::{future, Future, Stream, IntoFuture}; +use futures::sync::{mpsc, oneshot}; +use tokio_core::reactor::{Core, Handle}; +use tokio_io::{AsyncRead, AsyncWrite}; +use tokio_timer; + +use custom_proto::{RegisteredProtocol, RegisteredProtocols}; +use custom_proto::RegisteredProtocolOutput; +use network_state::NetworkState; +use timeouts; +use transport; + +/// IO Service with networking. +pub struct NetworkService { + shared: Arc, + + /// Holds the networking-running background thread alive. The `Option` is + /// `None` if the service is stopped. + /// Sending a message on the channel will trigger the end of the + /// background thread. We can then wait on the join handle. + bg_thread: Mutex, thread::JoinHandle<()>)>>, +} + +/// Common struct shared throughout all the components of the service. +struct Shared { + /// Original configuration of the service. + config: NetworkConfiguration, + + /// Contains the state of the network. + network_state: NetworkState, + + /// Kademlia system. Contains the DHT. + kad_system: KadSystem, + + /// Configuration for the Kademlia upgrade. + kad_upgrade: KadConnecConfig, + + /// List of protocols available on the network. It is a logic error to + /// remote protocols from this list, and the code may assume that protocols + /// stay at the same index forever. + protocols: RwLock>>, + + /// Use this channel to send a timeout request to the background thread's + /// events loop. After the timeout, elapsed, it will call `timeout` on the + /// `NetworkProtocolHandler`. This can be closed if the background thread + /// is not running. The sender will be overwritten every time we start + /// the service. + timeouts_register_tx: RwLock, ProtocolId, TimerToken))>>, + + /// Original address from the configuration, after being adjusted by the `Transport`. + /// Contains `None` if the network hasn't started yet. + original_listened_addr: RwLock>, + + /// Contains the addresses we known about ourselves. + listened_addrs: RwLock>, +} + +impl NetworkService { + /// Starts IO event loop + pub fn new(config: NetworkConfiguration, filter: Option>) + -> Result { + // TODO: for now `filter` is always `None` ; remove it from the code or implement it + assert!(filter.is_none()); + + let network_state = NetworkState::new(&config)?; + + let local_peer_id = network_state.local_public_key().clone().into_peer_id(); + // TODO: debug! instead? + info!(target: "sub-libp2p", "Local node id = {:?}", local_peer_id); + + let kad_system = KadSystem::without_init(KadSystemConfig { + parallelism: 3, + local_peer_id: local_peer_id.clone(), + kbuckets_timeout: Duration::from_secs(10), + request_timeout: Duration::from_secs(10), + known_initial_peers: network_state.known_peers().collect(), + }); + + let shared = Arc::new(Shared { + network_state, + protocols: RwLock::new(Default::default()), + kad_system, + kad_upgrade: KadConnecConfig::new(), + config, + timeouts_register_tx: RwLock::new(mpsc::unbounded().0), + original_listened_addr: RwLock::new(None), + listened_addrs: RwLock::new(Vec::new()), + }); + + Ok(NetworkService { + shared, + bg_thread: Mutex::new(None), + }) + } + + /// Register a new protocol handler with the event loop. + pub fn register_protocol( + &self, + handler: Arc, + protocol: ProtocolId, + versions: &[(u8, u8)] + ) { + if self.shared.network_state.has_connected_peer() { + // TODO: figure out if that's correct + warn!(target: "sub-libp2p", "a new network protocol was registered \ + while the service was already active ; this is a programmer \ + error"); + } + + self.shared.protocols.write().0 + .push(RegisteredProtocol::new(handler.clone(), protocol, versions)); + + handler.initialize(&NetworkContextImpl { + inner: self.shared.clone(), + protocol: protocol.clone(), + current_peer: None, + }); + } + + /// Returns network configuration. + pub fn config(&self) -> &NetworkConfiguration { + &self.shared.config + } + + pub fn external_url(&self) -> Option { + // TODO: in the context of libp2p, it is hard to define what an external + // URL is, as different nodes can have multiple different ways to + // reach us + self.shared.original_listened_addr.read().as_ref() + .map(|addr| + format!("{}/p2p/{}", addr, + self.shared.kad_system.local_peer_id().to_base58()) + ) + } + + /// Start network IO + // TODO (design): the notion of having a `NetworkService` alive should mean + // that it is running ; the `start` and `stop` functions are bad design + pub fn start(&self) -> Result<(), (Error, Option)> { + // TODO: check that service is started already? + + *self.shared.protocols.write() = Default::default(); + + // Channel we use to signal success or failure of the bg thread + // initialization process. + let (init_tx, init_rx) = sync_mpsc::channel(); + // Channel the main thread uses to signal the bg thread that it + // should stop + let (close_tx, close_rx) = oneshot::channel(); + let (timeouts_register_tx, timeouts_register_rx) = mpsc::unbounded(); + let shared = self.shared.clone(); + let join_handle = thread::spawn(move || { + // Tokio core that is going to run everything in this thread. + let mut core = match Core::new() { + Ok(c) => c, + Err(err) => { + let _ = init_tx.send(Err(err.into())); + return + } + }; + + let fut = match init_thread(core.handle(), shared, + timeouts_register_rx, close_rx) { + Ok(future) => { + debug!(target: "sub-libp2p", "Successfully started \ + networking service"); + let _ = init_tx.send(Ok(())); + future + }, + Err(err) => { + let _ = init_tx.send(Err(err)); + return + } + }; + + match core.run(fut) { + Ok(()) => debug!(target: "sub-libp2p", "libp2p future finished"), + Err(err) => error!(target: "sub-libp2p", "error while running \ + libp2p: {:?}", err), + } + }); + + init_rx.recv().expect("libp2p background thread panicked") + .map_err(|err| (err, self.shared.config.listen_address.clone()))?; + + *self.bg_thread.lock() = Some((close_tx, join_handle)); + *self.shared.timeouts_register_tx.write() = timeouts_register_tx; + Ok(()) + } + + /// Stop network IO. + pub fn stop(&self) { + if let Some((close_tx, join)) = self.bg_thread.lock().take() { + let _ = close_tx.send(()); + if let Err(e) = join.join() { + warn!(target: "sub-libp2p", "error while waiting on libp2p \ + background thread: {:?}", e); + } + } + + debug_assert!(!self.shared.network_state.has_connected_peer()); + } + + /// Get a list of all connected peers by id. + pub fn connected_peers(&self) -> Vec { + self.shared.network_state.connected_peers() + } + + /// Try to add a reserved peer. + pub fn add_reserved_peer(&self, peer: &str) -> Result<(), Error> { + // TODO: try to dial the peer? + self.shared.network_state.add_reserved_peer(peer) + } + + /// Try to remove a reserved peer. + pub fn remove_reserved_peer(&self, peer: &str) -> Result<(), Error> { + self.shared.network_state.remove_reserved_peer(peer) + } + + /// Set the non-reserved peer mode. + pub fn set_non_reserved_mode(&self, mode: NonReservedPeerMode) { + self.shared.network_state.set_non_reserved_mode(mode) + } + + /// Executes action in the network context + pub fn with_context(&self, protocol: ProtocolId, action: F) + where F: FnOnce(&NetworkContext) { + self.with_context_eval(protocol, action); + } + + /// Evaluates function in the network context + pub fn with_context_eval(&self, protocol: ProtocolId, action: F) + -> Option + where F: FnOnce(&NetworkContext) -> T { + if !self.shared.protocols.read().has_protocol(protocol) { + return None + } + + Some(action(&NetworkContextImpl { + inner: self.shared.clone(), + protocol: protocol.clone(), + current_peer: None, + })) + } +} + +impl Drop for NetworkService { + fn drop(&mut self) { + self.stop() + } +} + +#[derive(Clone)] +struct NetworkContextImpl { + inner: Arc, + protocol: ProtocolId, + current_peer: Option, +} + +impl NetworkContext for NetworkContextImpl { + fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) + -> Result<(), Error> { + self.send_protocol(self.protocol, peer, packet_id, data) + } + + fn send_protocol( + &self, + protocol: ProtocolId, + peer: PeerId, + packet_id: PacketId, + data: Vec + ) -> Result<(), Error> { + debug_assert!(self.inner.protocols.read().has_protocol(protocol), + "invalid protocol id requested in the API of the libp2p networking"); + // TODO: could be "optimized" by building `message` only after checking the validity of + // the peer, but that's probably not worth the effort + let mut message = Bytes::with_capacity(1 + data.len()); + message.extend_from_slice(&[packet_id]); + message.extend_from_slice(&data); + self.inner.network_state.send(protocol, peer, message) + } + + fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), Error> { + if let Some(peer) = self.current_peer { + self.send_protocol(self.protocol, peer, packet_id, data) + } else { + panic!("respond() called outside of a received message"); + } + } + + fn disable_peer(&self, peer: PeerId) { + debug!(target: "sub-libp2p", "Request to disable peer {}", peer); + self.inner.network_state.disable_peer(peer); + } + + fn disconnect_peer(&self, peer: PeerId) { + debug!(target: "sub-libp2p", "Request to disconnect peer {}", peer); + self.inner.network_state.disconnect_peer(peer); + } + + fn is_expired(&self) -> bool { + if let Some(current_peer) = self.current_peer { + !self.inner.network_state.is_peer_connected(current_peer) + } else { + // TODO: is this correct? + true + } + } + + fn register_timer(&self, token: usize, duration: Duration) + -> Result<(), Error> { + let handler = self.inner.protocols + .read() + .find_protocol(self.protocol) + .ok_or(ErrorKind::BadProtocol)? + .custom_data() + .clone(); + let at = Instant::now() + duration; + self.inner.timeouts_register_tx.read() + .unbounded_send((at, (handler, self.protocol, token))) + .map_err(|err| ErrorKind::Io(IoError::new(IoErrorKind::Other, err)))?; + Ok(()) + } + + fn peer_client_version(&self, peer: PeerId) -> String { + // Devp2p returns "unknown" on unknown peer ID, so we do the same. + self.inner.network_state.peer_client_version(peer, self.protocol) + .unwrap_or_else(|| "unknown".to_string()) + } + + fn session_info(&self, peer: PeerId) -> Option { + self.inner.network_state.session_info(peer, self.protocol) + } + + fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option { + self.inner.network_state.protocol_version(peer, protocol) + } + + fn subprotocol_name(&self) -> ProtocolId { + self.protocol.clone() + } +} + +/// Builds the main `Future` for the network service. +/// +/// - `timeouts_register_rx` should receive newly-registered timeouts. +/// - `close_rx` should be triggered when we want to close the network. +fn init_thread( + core: Handle, + shared: Arc, + timeouts_register_rx: mpsc::UnboundedReceiver<(Instant, (Arc, ProtocolId, TimerToken))>, + close_rx: oneshot::Receiver<()> +) -> Result, Error> { + // Build the transport layer. + let transport = { + let base = transport::build_transport( + core.clone(), + transport::UnencryptedAllowed::Denied, + shared.network_state.local_private_key().clone() + ); + + let addr_resolver = { + let shared = shared.clone(); + move |peer_id| { + let addrs = shared.network_state.addrs_of_peer(&peer_id); + trace!(target: "sub-libp2p", "Peer store: loaded {} addresses \ + for {:?}", addrs.len(), peer_id); + addrs.into_iter() + } + }; + + PeerIdTransport::new(base.clone(), addr_resolver).and_then({ + let shared = shared.clone(); + move |out, endpoint, remote_addr| { + let original_addr = out.original_addr.clone(); + let info = out.info.and_then(move |info| { + process_identify_info(shared, &info, original_addr, + endpoint, &base)?; + Ok(info) + }); + + let out = TransportOutput { + socket: out.socket, + info: Box::new(info) as Box<_>, + original_addr: out.original_addr, + }; + + future::ok((out, remote_addr)) + } + }) + }; + + // Build the swarm. The swarm is the single entry point where successfully + // negotiated protocols arrive. + let (swarm_controller, swarm_future) = { + let upgraded_transport = transport.clone() + .and_then({ + let shared = shared.clone(); + move |out, endpoint, client_addr| { + let original_addr = out.original_addr; + let listener_upgrade = upgrade::or(upgrade::or(upgrade::or( + upgrade::map(shared.kad_upgrade.clone(), FinalUpgrade::Kad), + upgrade::map(IdentifyProtocolConfig, |id| FinalUpgrade::Identify(id, original_addr))), + upgrade::map(ping::Ping, |(p, f)| FinalUpgrade::Ping(p, f))), + upgrade::map(DelayedProtosList(shared), FinalUpgrade::Custom)); + upgrade::apply(out.socket, listener_upgrade, endpoint, client_addr) + } + }) + .map(|out, _| (out, Endpoint::Listener)); + let shared = shared.clone(); + + libp2p::core::swarm( + upgraded_transport, + move |(upgrade, endpoint), client_addr| + listener_handle(shared.clone(), upgrade, endpoint, client_addr) + ) + }; + + // Listen on multiaddress. + // TODO: change the network config to directly contain a `Multiaddr` + { + let listen_addr = config_to_listen_addr(&shared.config); + debug!(target: "sub-libp2p", "Libp2p listening on {}", listen_addr); + match swarm_controller.listen_on(listen_addr.clone()) { + Ok(new_addr) => { + *shared.original_listened_addr.write() = Some(new_addr.clone()); + shared.listened_addrs.write().push(new_addr); + }, + Err(_) => { + warn!(target: "sub-libp2p", "Can't listen on {}, protocol not \ + supported", listen_addr); + return Err(ErrorKind::BadProtocol.into()) + }, + } + } + + // Build the timeouts system for the `register_timeout` function. + // (note: this has nothing to do with socket timeouts) + let timeouts = timeouts::build_timeouts_stream(core.clone(), timeouts_register_rx) + .for_each({ + let shared = shared.clone(); + move |(handler, protocol_id, timer_token)| { + handler.timeout(&NetworkContextImpl { + inner: shared.clone(), + protocol: protocol_id, + current_peer: None, + }, timer_token); + Ok(()) + } + }); + + // Start the process of periodically discovering nodes to connect to. + let discovery = start_kademlia_discovery(shared.clone(), transport, + swarm_controller); + + // Merge all the futures into one! + Ok(swarm_future + .select(discovery).map_err(|(err, _)| err).and_then(|(_, rest)| rest) + .select(timeouts).map_err(|(err, _)| err).and_then(|(_, rest)| rest) + .select(close_rx.then(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err) + + .and_then(move |_| { + debug!(target: "sub-libp2p", "Networking ended ; disconnecting \ + all peers"); + shared.network_state.disconnect_all(); + Ok(()) + })) +} + +/// Output of the common transport layer. +struct TransportOutput { + socket: S, + info: Box>, + original_addr: Multiaddr, +} + +/// Enum of all the possible protocols our service handles. +enum FinalUpgrade { + Kad((KadConnecController, Box>)), + /// The remote identification system, and the multiaddress we see the remote as. + Identify(IdentifyOutput, Multiaddr), + Ping(ping::Pinger, Box>), + /// `Custom` means anything not in the core libp2p and is handled + /// by `CustomProtoConnectionUpgrade`. + Custom(RegisteredProtocolOutput>), +} + +/// Called whenever we successfully open a multistream with a remote. +fn listener_handle<'a, C, F>( + shared: Arc, + upgrade: FinalUpgrade, + endpoint: Endpoint, + client_addr: F, +) -> Box + 'a> + where C: AsyncRead + AsyncWrite + 'a, + F: Future + 'a { + match upgrade { + FinalUpgrade::Kad((controller, kademlia_stream)) => { + trace!(target: "sub-libp2p", "Opened kademlia substream with \ + remote as {:?}", endpoint); + + let shared = shared.clone(); + Box::new(client_addr.and_then(move |client_addr| + handle_kademlia_connection(shared, client_addr, controller, kademlia_stream) + ).flatten()) + }, + + FinalUpgrade::Identify(IdentifyOutput::Sender { sender }, original_addr) => { + trace!(target: "sub-libp2p", "Sending back identification info"); + sender.send( + IdentifyInfo { + public_key: shared.network_state.local_public_key().clone(), + protocol_version: concat!("substrate/", + env!("CARGO_PKG_VERSION")).to_owned(), // TODO: ? + agent_version: concat!("substrate/", + env!("CARGO_PKG_VERSION")).to_owned(), + listen_addrs: shared.listened_addrs.read().clone(), + protocols: Vec::new(), // TODO: protocols_to_report, + }, + &original_addr + ) + }, + + FinalUpgrade::Identify(IdentifyOutput::RemoteInfo { .. }, _) => + unreachable!("We are never dialing with the identify protocol"), + + FinalUpgrade::Ping(_pinger, future) => future, + + FinalUpgrade::Custom(custom_proto_out) => { + // A "custom" protocol is one that is part of substrate and not part of libp2p. + let shared = shared.clone(); + let fut = client_addr.and_then(move |client_addr| + handle_custom_connection(shared, client_addr, endpoint, custom_proto_out)); + Box::new(fut) as Box<_> + }, + } +} + +/// Handles a newly-opened Kademlia connection. +fn handle_kademlia_connection( + shared: Arc, + client_addr: Multiaddr, + controller: KadConnecController, + kademlia_stream: Box> +) -> Result, IoError> { + // We add the Kademlia controller to the network state, and use a guard to remove + // it later. + struct KadDisconnectGuard(Arc, PeerId); + impl Drop for KadDisconnectGuard { + fn drop(&mut self) { self.0.network_state.disconnect_kademlia(self.1); } + } + + let node_id = p2p_multiaddr_to_node_id(client_addr); + let peer_id = shared.network_state.incoming_kad_connection(node_id.clone(), controller)?; + let kad_live_guard = KadDisconnectGuard(shared.clone(), peer_id); + + let future = kademlia_stream.for_each({ + let shared = shared.clone(); + move |req| { + let shared = shared.clone(); + shared.kad_system.update_kbuckets(node_id.clone()); + match req { + KadIncomingRequest::FindNode { searched, responder } => + responder.respond(build_kademlia_response(&shared, &searched)), + KadIncomingRequest::PingPong => (), + } + Ok(()) + } + }).then(move |val| { + // Makes sure that `kad_live_guard` is kept alive until here. + drop(kad_live_guard); + val + }); + + Ok(future) +} + +/// When a remote performs a `FIND_NODE` Kademlia request for `searched`, +/// this function builds the response to send back. +fn build_kademlia_response(shared: &Arc, searched: &PeerstorePeerId) + -> Vec { + shared.kad_system + // TODO the iter of `known_closest_peers` should be infinite + .known_closest_peers(searched) + .map(move |peer_id| { + let addrs = shared.network_state.addrs_of_peer(&peer_id); + let connec_ty = if shared.network_state.has_connection(&peer_id) { + // TODO: this only checks connections with substrate ; but what + // if we're connected through Kademlia only? + KadConnectionType::Connected + } else { + KadConnectionType::NotConnected + }; + + KadPeer { + node_id: peer_id.clone(), + multiaddrs: addrs, + connection_ty: connec_ty, + } + }) + .collect::>() +} + +/// Handles a newly-opened connection to a remote with a custom protocol +/// (eg. `/substrate/dot/0`). +/// Returns a future that corresponds to when the handling is finished. +fn handle_custom_connection( + shared: Arc, + client_addr: Multiaddr, + endpoint: Endpoint, + custom_proto_out: RegisteredProtocolOutput> +) -> impl Future { + let handler = custom_proto_out.custom_data; + let protocol_id = custom_proto_out.protocol_id; + + // We're using the `PeerIdTransport` layer, so all the multiaddresses received + // here should be of the format `/p2p/`. + let node_id = p2p_multiaddr_to_node_id(client_addr); + + // Determine the ID of this peer, or drop the connection if the peer is disabled, + // if we reached `max_peers`, or a similar reason. + // TODO: is there a better way to refuse connections than to drop the + // newly-opened substream? should we refuse the connection + // beforehand? + let peer_id = match shared.network_state.accept_custom_proto( + node_id.clone(), + protocol_id, + custom_proto_out.protocol_version, + endpoint, + custom_proto_out.outgoing + ) { + Ok(peer_id) => peer_id, + Err(err) => return future::Either::A(future::err(err.into())), + }; + + debug!(target: "sub-libp2p", "Successfully connected to {:?} (peer id \ + {}) with protocol {:?} version {}", node_id, peer_id, protocol_id, + custom_proto_out.protocol_version); + handler.connected(&NetworkContextImpl { + inner: shared.clone(), + protocol: protocol_id, + current_peer: Some(peer_id), + }, &peer_id); + + struct KadDisconnectGuard { + inner: Arc, + peer_id: PeerId, + node_id: PeerstorePeerId, + handler: Arc, + protocol: ProtocolId + } + + impl Drop for KadDisconnectGuard { + fn drop(&mut self) { + debug!(target: "sub-libp2p", "Node {:?} with peer ID {} \ + through protocol {:?} disconnected", self.node_id, self.peer_id, + self.protocol); + self.handler.disconnected(&NetworkContextImpl { + inner: self.inner.clone(), + protocol: self.protocol, + current_peer: Some(self.peer_id), + }, &self.peer_id); + + // When any custom protocol drops, we drop the peer entirely. + // TODO: is this correct? + self.inner.network_state.disconnect_peer(self.peer_id); + } + } + + let dc_guard = KadDisconnectGuard { + inner: shared.clone(), + peer_id, + node_id: node_id.clone(), + handler: handler.clone(), + protocol: protocol_id, + }; + + future::Either::B(custom_proto_out + .incoming + .for_each(move |(packet_id, data)| { + shared.kad_system.update_kbuckets(node_id.clone()); + handler.read(&NetworkContextImpl { + inner: shared.clone(), + protocol: protocol_id, + current_peer: Some(peer_id.clone()), + }, &peer_id, packet_id, &data); + Ok(()) + }) + .then(move |val| { + // Makes sure that `dc_guard` is kept alive until here. + drop(dc_guard); + val + })) +} + +/// Builds the multiaddress corresponding to the address we need to listen to +/// according to the config. +// TODO: put the `Multiaddr` directly in the `NetworkConfiguration` +fn config_to_listen_addr(config: &NetworkConfiguration) -> Multiaddr { + if let Some(addr) = config.listen_address { + let ip = match addr.ip() { + IpAddr::V4(addr) => AddrComponent::IP4(addr), + IpAddr::V6(addr) => AddrComponent::IP6(addr), + }; + iter::once(ip).chain(iter::once(AddrComponent::TCP(addr.port()))).collect() + } else { + let host = AddrComponent::IP4(Ipv4Addr::new(0, 0, 0, 0)); + let port = AddrComponent::TCP(0); + iter::once(host).chain(iter::once(port)).collect() + } +} + +/// Randomly discovers peers to connect to. +/// This works by running a round at a regular interval, and skipping if we +/// reached `min_peers`. When we are over `min_peers`, we stop trying to dial +/// nodes and only accept incoming connections. +fn start_kademlia_discovery(shared: Arc, transport: T, + swarm_controller: SwarmController) -> impl Future + where T: MuxedTransport> + Clone + 'static, + T::MultiaddrFuture: 'static, + To: AsyncRead + AsyncWrite + 'static, + St: MuxedTransport, Endpoint)> + Clone + 'static, + C: 'static { + let local_peer_id = shared.network_state.local_public_key().clone().into_peer_id(); + + let kad_init = shared.kad_system.perform_initialization({ + let shared = shared.clone(); + let transport = transport.clone(); + let swarm_controller = swarm_controller.clone(); + move |peer_id| + obtain_kad_connection( + shared.clone(), + peer_id.clone(), + transport.clone(), + swarm_controller.clone() + ) + }); + + let discovery = tokio_timer::Interval::new(Instant::now(), Duration::from_secs(30)) + // TODO: add a timeout to the lookups + .map_err(|err| IoError::new(IoErrorKind::Other, err)) + .and_then({ + let shared = shared.clone(); + let transport = transport.clone(); + let swarm_controller = swarm_controller.clone(); + move |_| { + // Note that this is a small hack. We flush the caches here so + // that we don't need to run a timer just for flushing. + let _ = shared.network_state.flush_caches_to_disk(); + + if shared.network_state.should_open_outgoing_connections() { + future::Either::A(perform_kademlia_query(shared.clone(), + transport.clone(), swarm_controller.clone())) + } else { + // If we shouldn't open connections (eg. we reached + // `min_peers`), pretend we did a lookup but with an empty + // result. + trace!(target: "sub-libp2p", "Bypassing kademlia discovery"); + future::Either::B(future::ok(Vec::new())) + } + } + }) + .for_each({ + let shared = shared.clone(); + move |results| { + process_kad_results(shared.clone(), transport.clone(), + swarm_controller.clone(), results, &local_peer_id); + Ok(()) + } + }); + + let final_future = kad_init + .select(discovery) + .map_err(|(err, _)| err) + .and_then(|(_, rest)| rest); + + // Note that we use a Box in order to speed compilation time. + Box::new(final_future) as Box> +} + +/// Performs a kademlia request to a random node, and returns the results. +fn perform_kademlia_query(shared: Arc, transport: T, + swarm_controller: SwarmController) + -> impl Future, Error = IoError> + where T: MuxedTransport> + Clone + 'static, + T::MultiaddrFuture: 'static, + To: AsyncRead + AsyncWrite + 'static, + St: MuxedTransport, Endpoint)> + Clone + 'static, + C: 'static { + // 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. + let random_key = PublicKey::Ed25519((0 .. 32) + .map(|_| -> u8 { rand::random() }).collect()); + let random_peer_id = random_key.into_peer_id(); + trace!(target: "sub-libp2p", "Start kademlia discovery for {:?}", + random_peer_id); + + shared.clone() + .kad_system + .find_node(random_peer_id, { + let shared = shared.clone(); + let transport = transport.clone(); + let swarm_controller = swarm_controller.clone(); + move |peer_id| obtain_kad_connection(shared.clone(), peer_id.clone(), + transport.clone(), swarm_controller.clone()) + }) + .filter_map(move |event| + match event { + KadQueryEvent::NewKnownMultiaddrs(peers) => { + for (peer, addrs) in peers { + trace!(target: "sub-libp2p", "Peer store: adding \ + addresses {:?} for {:?}", addrs, peer); + for addr in addrs { + shared.network_state.add_kad_discovered_addr(&peer, addr); + } + } + None + }, + KadQueryEvent::Finished(out) => Some(out), + } + ) + .into_future() + .map_err(|(err, _)| err) + .map(|(out, _)| out.unwrap()) +} + +/// Processes the results of a Kademlia discovery. +fn process_kad_results(shared: Arc, transport: T, + swarm_controller: SwarmController, results: Vec, + local_peer_id: &PeerstorePeerId) + where T: MuxedTransport> + Clone + 'static, + T::MultiaddrFuture: 'static, + To: AsyncRead + AsyncWrite + 'static, + St: MuxedTransport, Endpoint)> + Clone + 'static, + C: 'static { + trace!(target: "sub-libp2p", "Processing Kademlia discovery results \ + (len = {})", results.len()); + + for discovered_peer in results { + // Skip if we reach `min_peers`. + // Also skip nodes we are already connected to, in order to not connect twice. + // TODO: better API in network_state + if !shared.network_state.should_open_outgoing_connections() || + discovered_peer == *local_peer_id || + shared.network_state.is_peer_disabled(&discovered_peer) + { + trace!(target: "sub-libp2p", "Skipping discovered node {:?}", discovered_peer); + continue + } + + // Try to dial that node for each registered protocol. Since dialing + // upgrades the connection to use multiplexing, dialing multiple times + // should automatically open multiple substreams. + let addr: Multiaddr = AddrComponent::P2P(discovered_peer.clone().into_bytes()).into(); + trace!(target: "sub-libp2p", "Dialing discovered node {:?} for each protocol", addr); + for proto in shared.protocols.read().0.clone().into_iter() { + if shared.network_state.has_protocol_connection(&discovered_peer, proto.id()) { + continue + } + + // TODO: check that the secio key matches the id given by kademlia + if let Err(err) = dial_peer_custom_proto( + shared.clone(), + transport.clone(), + proto, addr.clone(), + discovered_peer.clone(), + &swarm_controller + ) { + warn!(target: "sub-libp2p", "Error while dialing {}: {:?}", addr, err); + } + } + } +} + +/// Dials the given address for the given protocol and using the +/// given `swarm_controller`. +/// Checks that the peer ID matches `expected_peer_id`. +fn dial_peer_custom_proto( + shared: Arc, + base_transport: T, + proto: RegisteredProtocol>, + addr: Multiaddr, + expected_peer_id: PeerstorePeerId, + swarm_controller: &SwarmController +) -> Result<(), IoError> + where T: MuxedTransport> + Clone + 'static, + T::MultiaddrFuture: 'static, + To: AsyncRead + AsyncWrite + 'static, + St: MuxedTransport, Endpoint)> + Clone + 'static, + C: 'static, +{ + let proto_id = proto.id(); + + // TODO: check that the secio key matches the id given by kademlia + let with_proto = base_transport + .clone() + .and_then(move |out, endpoint, client_addr| { + let socket = out.socket; + let original_addr = out.original_addr; + out.info + .and_then(move |info| + if info.info.public_key.into_peer_id() == expected_peer_id { + Ok(socket) + } else { + debug!(target: "sub-libp2p", "Public key mismatch for \ + node {:?} with proto {:?}", expected_peer_id, proto_id); + trace!(target: "sub-libp2p", "Removing addr {} for {:?}", + original_addr, expected_peer_id); + shared.network_state.set_invalid_kad_address(&expected_peer_id, &original_addr); + Err(IoErrorKind::InvalidData.into()) // TODO: correct err + } + ) + .and_then(move |socket| + upgrade::apply(socket, proto, endpoint, client_addr) + ) + }) + .and_then(move |out, endpoint, client_addr| + future::ok(((FinalUpgrade::Custom(out), endpoint), client_addr)) + ); + + swarm_controller.dial(addr, with_proto) + .map_err(|_| IoError::new(IoErrorKind::Other, "multiaddr not supported")) +} + +/// Obtain a Kademlia connection to the given peer. +fn obtain_kad_connection(shared: Arc, + peer_id: PeerstorePeerId, transport: T, swarm_controller: SwarmController) + -> impl Future + where T: MuxedTransport> + Clone + 'static, + T::MultiaddrFuture: 'static, + To: AsyncRead + AsyncWrite + 'static, + St: MuxedTransport, Endpoint)> + Clone + 'static, + C: 'static { + let kad_upgrade = shared.kad_upgrade.clone(); + let final_future = shared.network_state + .obtain_kad_connection(peer_id.clone(), move || { + let addr: Multiaddr = AddrComponent::P2P(peer_id.clone().into_bytes()).into(); + trace!(target: "sub-libp2p", "Opening new kademlia connection to {}", addr); + let (tx, rx) = oneshot::channel(); + let tx = Arc::new(Mutex::new(Some(tx))); + swarm_controller.dial(addr, + transport + .and_then(move |out, endpoint, client_addr| + upgrade::apply(out.socket, kad_upgrade.clone(), + endpoint, client_addr) + ) + .map(move |(kad_ctrl, stream), _| { + if let Some(tx) = tx.lock().take() { + let _ = tx.send(kad_ctrl.clone()); + } + (FinalUpgrade::Kad((kad_ctrl, stream)), Endpoint::Dialer) + }) + ) + .expect("cannot dial"); + rx.map_err(|err| IoError::new(IoErrorKind::ConnectionAborted, err)) + }) + .into_future() + .and_then(|(_peer_id, kad_ctrl)| kad_ctrl); + + // Note that we use a Box in order to speed compilation time. + Box::new(final_future) as Box> +} + +/// Processes the information about a node. +/// +/// - `original_addr` is the address used to originally dial this node. +/// - `endpoint` is whether we dialed or listened to this node. +/// - `transport` is used for the `nat_traversal` method. +/// +/// Returns an error if the node has been refused access. +fn process_identify_info( + shared: Arc, + info: &IdentifyTransportOutcome, + original_addr: Multiaddr, + endpoint: Endpoint, + transport: &impl Transport +) -> Result<(), IoError> { + let node_id = info.info.public_key.clone().into_peer_id(); + let _peer_id = shared.network_state.set_peer_info(node_id.clone(), endpoint, + info.info.agent_version.clone(), original_addr.clone(), + original_addr.clone())?; // TODO: wrong local addr + + if let Some(ref original_listened_addr) = *shared.original_listened_addr.read() { + if let Some(ext_addr) = transport.nat_traversal(original_listened_addr, &info.observed_addr) { + let mut listened_addrs = shared.listened_addrs.write(); + if !listened_addrs.iter().any(|a| a == &ext_addr) { + trace!(target: "sub-libp2p", "NAT traversal: remote observes us as \ + {} ; registering {} as one of our own addresses", + info.observed_addr, ext_addr); + listened_addrs.push(ext_addr); + } + } + } + + for addr in info.info.listen_addrs.iter() { + trace!(target: "sub-libp2p", "Peer store: adding address {} for {:?}", + addr, node_id); + shared.network_state.add_kad_discovered_addr(&node_id, addr.clone()); + } + + Ok(()) +} + +/// Expects a multiaddr of the format `/p2p/` and returns the node ID. +/// Panics if the format is not correct. +fn p2p_multiaddr_to_node_id(client_addr: Multiaddr) -> PeerstorePeerId { + let (first, second); + { + let mut iter = client_addr.iter(); + first = iter.next(); + second = iter.next(); + } + match (first, second) { + (Some(AddrComponent::P2P(node_id)), None) => + PeerstorePeerId::from_bytes(node_id).expect("libp2p always reports a valid node id"), + _ => panic!("Reported multiaddress is in the wrong format ; programmer error") + } +} + +/// Since new protocols are added after the networking starts, we have to load the protocols list +/// in a lazy way. This is what this wrapper does. +#[derive(Clone)] +struct DelayedProtosList(Arc); +// `Maf` is short for `MultiaddressFuture` +impl ConnectionUpgrade for DelayedProtosList +where C: AsyncRead + AsyncWrite + 'static, // TODO: 'static :-/ + Maf: Future + 'static, // TODO: 'static :( +{ + type NamesIter = > as ConnectionUpgrade>::NamesIter; + type UpgradeIdentifier = > as ConnectionUpgrade>::UpgradeIdentifier; + + fn protocol_names(&self) -> Self::NamesIter { + ConnectionUpgrade::::protocol_names(&*self.0.protocols.read()) + } + + type Output = > as ConnectionUpgrade>::Output; + type MultiaddrFuture = > as ConnectionUpgrade>::MultiaddrFuture; + type Future = > as ConnectionUpgrade>::Future; + + #[inline] + fn upgrade(self, socket: C, id: Self::UpgradeIdentifier, endpoint: Endpoint, + remote_addr: Maf) -> Self::Future + { + self.0.protocols.read() + .clone() + .upgrade(socket, id, endpoint, remote_addr) + } +} + +#[cfg(test)] +mod tests { + use super::NetworkService; + + #[test] + fn builds_and_finishes_in_finite_time() { + // Checks that merely starting the network doesn't end up in an infinite loop. + let service = NetworkService::new(Default::default(), None).unwrap(); + service.start().map_err(|(err, _)| err).unwrap(); + } +} diff --git a/substrate/network-libp2p/src/timeouts.rs b/substrate/network-libp2p/src/timeouts.rs new file mode 100644 index 0000000000000..c0c7d30e7acfa --- /dev/null +++ b/substrate/network-libp2p/src/timeouts.rs @@ -0,0 +1,87 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see .? + +use futures::{future, Future, stream, Stream, sync::mpsc}; +use std::io::Error as IoError; +use std::time::Instant; +use tokio_core::reactor::{Handle, Timeout}; + +/// Builds the timeouts system. +/// +/// The `timeouts_rx` should be a stream receiving newly-created timeout +/// requests. Returns a stream that produces items as their timeout elapses. +/// `T` can be anything you want, as it is transparently passed from the input +/// to the output. +pub fn build_timeouts_stream( + core: Handle, + timeouts_rx: mpsc::UnboundedReceiver<(Instant, T)> +) -> impl Stream { + let next_timeout = next_in_timeouts_stream(timeouts_rx); + + // The `unfold` function is essentially a loop turned into a stream. The + // first parameter is the initial state, and the closure returns the new + // state and an item. + stream::unfold(vec![future::Either::A(next_timeout)], move |timeouts| { + // `timeouts` is a `Vec` of futures that produce an `Out`. + + let core = core.clone(); + + // `select_ok` panics if `timeouts` is empty anyway. + if timeouts.is_empty() { + return None + } + + Some(future::select_ok(timeouts.into_iter()) + .and_then(move |(item, mut timeouts)| + match item { + Out::NewTimeout((Some((at, item)), next_timeouts)) => { + // Received a new timeout request on the channel. + let next_timeout = next_in_timeouts_stream(next_timeouts); + let timeout = Timeout::new_at(at, &core)? + .map(move |()| Out::Timeout(item)); + timeouts.push(future::Either::B(timeout)); + timeouts.push(future::Either::A(next_timeout)); + Ok((None, timeouts)) + }, + Out::NewTimeout((None, _)) => + // The channel has been closed. + Ok((None, timeouts)), + Out::Timeout(item) => + // A timeout has happened. + Ok((Some(item), timeouts)), + } + ) + ) + }).filter_map(|item| item) +} + +/// Local enum representing the output of the selection. +enum Out { + NewTimeout(A), + Timeout(B), +} + +/// Convenience function that calls `.into_future()` on the timeouts stream, +/// and applies some modifiers. +/// This function is necessary. Otherwise if we copy-paste its content we run +/// into errors because the type of the copy-pasted closures differs. +fn next_in_timeouts_stream(stream: mpsc::UnboundedReceiver) + -> impl Future, mpsc::UnboundedReceiver), B>, Error = IoError> { + stream + .into_future() + .map(Out::NewTimeout) + .map_err(|_| unreachable!("an UnboundedReceiver can never error")) +} diff --git a/substrate/network-libp2p/src/transport.rs b/substrate/network-libp2p/src/transport.rs new file mode 100644 index 0000000000000..d017e20638e68 --- /dev/null +++ b/substrate/network-libp2p/src/transport.rs @@ -0,0 +1,62 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see .? + +use libp2p::{self, Transport, secio}; +use libp2p::core::{MuxedTransport, either, upgrade}; +use tokio_core::reactor::Handle; +use tokio_io::{AsyncRead, AsyncWrite}; + +/// Builds the transport that serves as a common ground for all connections. +pub fn build_transport( + core: Handle, + unencrypted_allowed: UnencryptedAllowed, + local_private_key: secio::SecioKeyPair +) -> impl MuxedTransport + Clone { + libp2p::CommonTransport::new(core) + .with_upgrade({ + let secio = secio::SecioConfig { + key: local_private_key, + }; + + let mut plaintext = upgrade::toggleable(upgrade::PlainTextConfig); + match unencrypted_allowed { + UnencryptedAllowed::Allowed => plaintext.disable(), + UnencryptedAllowed::Denied => (), + }; + + // TODO: this `EitherOutput` thing shows that libp2p's API could be improved + upgrade::or( + upgrade::map(plaintext, |out| + (either::EitherOutput::First(out), None) + ), + upgrade::map(secio, |out: secio::SecioOutput<_>| + (either::EitherOutput::Second(out.stream), + Some(out.remote_key)) + ), + ) + }) + // TODO: check that the public key matches what is reported by identify + .map(|(socket, _key), _| socket) + .with_upgrade(libp2p::mplex::MultiplexConfig::new()) + .into_connection_reuse() +} + +/// Specifies whether unencrypted communications are allowed or denied. +#[derive(Debug, Copy, Clone)] +pub enum UnencryptedAllowed { + Allowed, + Denied, +} diff --git a/substrate/network-libp2p/tests/tests.rs b/substrate/network-libp2p/tests/tests.rs new file mode 100644 index 0000000000000..a70baf0aafcf7 --- /dev/null +++ b/substrate/network-libp2p/tests/tests.rs @@ -0,0 +1,149 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +extern crate parking_lot; +extern crate ethcore_bytes; +extern crate ethcore_io as io; +extern crate ethcore_logger; +extern crate ethcore_network; +extern crate substrate_network_libp2p; +extern crate ethkey; + +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; +use std::sync::Arc; +use std::thread; +use std::time::*; +use parking_lot::Mutex; +use ethcore_bytes::Bytes; +use ethcore_network::*; +use substrate_network_libp2p::NetworkService; +use ethkey::{Random, Generator}; +use io::TimerToken; + +pub struct TestProtocol { + drop_session: bool, + pub packet: Mutex, + pub got_timeout: AtomicBool, + pub got_disconnect: AtomicBool, +} + +impl TestProtocol { + pub fn new(drop_session: bool) -> Self { + TestProtocol { + packet: Mutex::new(Vec::new()), + got_timeout: AtomicBool::new(false), + got_disconnect: AtomicBool::new(false), + drop_session: drop_session, + } + } + /// Creates and register protocol with the network service + pub fn register(service: &mut NetworkService, drop_session: bool) -> Arc { + let handler = Arc::new(TestProtocol::new(drop_session)); + service.register_protocol(handler.clone(), *b"tst", &[(42u8, 1), (43u8, 1)]); + handler + } + + pub fn got_packet(&self) -> bool { + self.packet.lock()[..] == b"hello"[..] + } + + pub fn got_timeout(&self) -> bool { + self.got_timeout.load(AtomicOrdering::Relaxed) + } + + pub fn got_disconnect(&self) -> bool { + self.got_disconnect.load(AtomicOrdering::Relaxed) + } +} + +impl NetworkProtocolHandler for TestProtocol { + fn initialize(&self, io: &NetworkContext) { + io.register_timer(0, Duration::from_millis(10)).unwrap(); + } + + fn read(&self, _io: &NetworkContext, _peer: &PeerId, packet_id: u8, data: &[u8]) { + assert_eq!(packet_id, 33); + self.packet.lock().extend(data); + } + + fn connected(&self, io: &NetworkContext, peer: &PeerId) { + if self.drop_session { + io.disconnect_peer(*peer) + } else { + io.respond(33, "hello".to_owned().into_bytes()).unwrap(); + } + } + + fn disconnected(&self, _io: &NetworkContext, _peer: &PeerId) { + self.got_disconnect.store(true, AtomicOrdering::Relaxed); + } + + /// Timer function called after a timeout created with `NetworkContext::timeout`. + fn timeout(&self, _io: &NetworkContext, timer: TimerToken) { + assert_eq!(timer, 0); + self.got_timeout.store(true, AtomicOrdering::Relaxed); + } +} + + +#[test] +fn net_service() { + let service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); + service.start().unwrap(); + service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", &[(1u8, 1)]); +} + +#[test] +fn net_start_stop() { + let config = NetworkConfiguration::new_local(); + let service = NetworkService::new(config, None).unwrap(); + service.start().unwrap(); + service.stop(); + service.start().unwrap(); +} + +#[test] +#[ignore] // TODO: how is this test even supposed to work? +fn net_disconnect() { + let key1 = Random.generate().unwrap(); + let mut config1 = NetworkConfiguration::new_local(); + config1.use_secret = Some(key1.secret().clone()); + config1.boot_nodes = vec![ ]; + let mut service1 = NetworkService::new(config1, None).unwrap(); + service1.start().unwrap(); + let handler1 = TestProtocol::register(&mut service1, false); + let mut config2 = NetworkConfiguration::new_local(); + config2.boot_nodes = vec![ service1.external_url().unwrap() ]; + let mut service2 = NetworkService::new(config2, None).unwrap(); + service2.start().unwrap(); + let handler2 = TestProtocol::register(&mut service2, true); + while !(handler1.got_disconnect() && handler2.got_disconnect()) { + thread::sleep(Duration::from_millis(50)); + } + assert!(handler1.got_disconnect()); + assert!(handler2.got_disconnect()); +} + +#[test] +fn net_timeout() { + let config = NetworkConfiguration::new_local(); + let mut service = NetworkService::new(config, None).unwrap(); + service.start().unwrap(); + let handler = TestProtocol::register(&mut service, false); + while !handler.got_timeout() { + thread::sleep(Duration::from_millis(50)); + } +} diff --git a/substrate/network/Cargo.toml b/substrate/network/Cargo.toml index 93066e8d38fee..eaa61d1114e07 100644 --- a/substrate/network/Cargo.toml +++ b/substrate/network/Cargo.toml @@ -19,7 +19,6 @@ serde_json = "1.0" futures = "0.1.17" linked-hash-map = "0.5" ethcore-network = { git = "https://github.com/paritytech/parity.git" } -ethcore-network-devp2p = { git = "https://github.com/paritytech/parity.git" } ethcore-io = { git = "https://github.com/paritytech/parity.git" } ed25519 = { path = "../../substrate/ed25519" } substrate-primitives = { path = "../../substrate/primitives" } @@ -29,6 +28,7 @@ substrate-runtime-support = { path = "../../substrate/runtime-support" } substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" } substrate-bft = { path = "../../substrate/bft" } substrate-codec = { path = "../../substrate/codec" } +substrate-network-libp2p = { path = "../../substrate/network-libp2p" } [dev-dependencies] env_logger = "0.4" diff --git a/substrate/network/src/lib.rs b/substrate/network/src/lib.rs index bfa949a5273b1..d4982d5ef22a5 100644 --- a/substrate/network/src/lib.rs +++ b/substrate/network/src/lib.rs @@ -19,7 +19,6 @@ //! Substrate-specific P2P networking: synchronizing blocks, propagating BFT messages. //! Allows attachment of an optional subprotocol for chain-specific requests. -extern crate ethcore_network_devp2p as network_devp2p; extern crate ethcore_network as network; extern crate ethcore_io as core_io; extern crate linked_hash_map; @@ -30,6 +29,7 @@ extern crate substrate_serializer as ser; extern crate substrate_client as client; extern crate substrate_runtime_support as runtime_support; extern crate substrate_runtime_primitives as runtime_primitives; +extern crate substrate_network_libp2p as network_libp2p; extern crate substrate_bft; extern crate substrate_codec as codec; extern crate serde; diff --git a/substrate/network/src/service.rs b/substrate/network/src/service.rs index 20d4bf32196e2..9405455df3b22 100644 --- a/substrate/network/src/service.rs +++ b/substrate/network/src/service.rs @@ -21,7 +21,7 @@ use std::time::Duration; use futures::sync::{oneshot, mpsc}; use network::{NetworkProtocolHandler, NetworkContext, PeerId, ProtocolId, NetworkConfiguration , NonReservedPeerMode, ErrorKind}; -use network_devp2p::{NetworkService}; +use network_libp2p::{NetworkService}; use core_io::{TimerToken}; use io::NetSyncIo; use protocol::{Protocol, ProtocolContext, Context, ProtocolStatus, PeerInfo as ProtocolPeerInfo}; @@ -199,8 +199,7 @@ impl> Service { Err(err) => warn!("Error starting network: {}", err), _ => {}, }; - self.network.register_protocol(self.handler.clone(), self.protocol_id, &[(::protocol::CURRENT_VERSION as u8, ::protocol::CURRENT_PACKET_COUNT)]) - .unwrap_or_else(|e| warn!("Error registering polkadot protocol: {:?}", e)); + self.network.register_protocol(self.handler.clone(), self.protocol_id, &[(::protocol::CURRENT_VERSION as u8, ::protocol::CURRENT_PACKET_COUNT)]); } fn stop(&self) {