diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 7e654e6729..ec9c313c71 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1286,29 +1286,29 @@ dependencies = [ [[package]] name = "libp2p" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-dns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-floodsub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-kad 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mdns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-mplex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-noise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-plaintext 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ratelimit 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-secio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-tcp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-uds 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-websocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-yamux 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-dns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-floodsub 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-identify 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-kad 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-mdns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-mplex 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-noise 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ping 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-plaintext 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ratelimit 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-secio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-tcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-uds 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-websocket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-yamux 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1321,11 +1321,14 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1337,18 +1340,23 @@ dependencies = [ "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-core-derive" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1357,11 +1365,11 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1370,7 +1378,7 @@ dependencies = [ [[package]] name = "libp2p-floodsub" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1378,7 +1386,7 @@ dependencies = [ "cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1389,13 +1397,13 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1410,7 +1418,7 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1419,9 +1427,9 @@ dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-identify 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-ping 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-identify 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-ping 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1438,13 +1446,13 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1459,13 +1467,13 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1475,28 +1483,31 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "snow 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-ping" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1509,22 +1520,22 @@ dependencies = [ [[package]] name = "libp2p-plaintext" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libp2p-ratelimit" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aio-limited 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1532,18 +1543,17 @@ dependencies = [ [[package]] name = "libp2p-secio" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "asn1_der 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1559,11 +1569,11 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tk-listen 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1573,11 +1583,11 @@ dependencies = [ [[package]] name = "libp2p-uds" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1585,11 +1595,11 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1600,14 +1610,14 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "yamux 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3673,6 +3683,7 @@ dependencies = [ "substrate-state-machine 0.1.0", "substrate-telemetry 0.3.1", "sysinfo 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3970,7 +3981,7 @@ dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libp2p 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3978,6 +3989,7 @@ dependencies = [ "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4988,6 +5000,16 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x25519-dalek" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xdg" version = "2.2.0" @@ -5000,7 +5022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "yamux" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5014,6 +5036,11 @@ dependencies = [ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "zeroize" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eaf9f0d0b1cc33a4d2aee14fb4b2eac03462ef4db29c8ac4057327d8a71ad86f" "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" @@ -5161,24 +5188,24 @@ dependencies = [ "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" -"checksum libp2p 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395d54c4c96fa175eabf4505e8a7bd616d916fa49fa27c60ceaa6d5d9b51bc" -"checksum libp2p-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c8dc95c7fda9de223bc195b637290918e8decb18e63fd3d03005f84b8ce380b" -"checksum libp2p-core-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e9ff3bb639d0be41e1aff9d0d28715e54474e4d15e43aa4865bdec44867d8d3" -"checksum libp2p-dns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d310aa56671539a2bce6124cf4326482278b0d0b841c3ba1514e44d8597096" -"checksum libp2p-floodsub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8256d778f0dc087be409d8cbd081a11bc41ea27ddcd4862814e50e8cfa9c6df0" -"checksum libp2p-identify 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d128febfc8fe57b597e627f545bafea43ae009bf85cc9480b583996f244ab685" -"checksum libp2p-kad 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0691fcca7648369798c6466c61139d31dbb7e2afad311e44fcc4e220ce1e4d78" -"checksum libp2p-mdns 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63289f296e39752180d8a45e024cc38d1028a6db41deab3943ff2ccb9d1224cd" -"checksum libp2p-mplex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "791e375a6a230568f0d8f56f6236403de8e4bf4bd870c3c5f605fd1778da70b2" -"checksum libp2p-noise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70d28b0ca9eb9818d45e037b4a8a0915553c5c1f8d878d8d6170f60451ad37d2" -"checksum libp2p-ping 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "53db5fafd4ca0a32f339371198196795b8e14d8ecb360d8d03ada03299c12a10" -"checksum libp2p-plaintext 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4383404cba7e4483e0b7d78b3ac5e66f8b024233a5095df9da65d5a1e975d692" -"checksum libp2p-ratelimit 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bad4fe925d50cc886608ab3b3a7a962b5064ecc49db8b66fd063a950d469c757" -"checksum libp2p-secio 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f9a7641a314d54ad7797f0445685818edb4d3c2f21690cea900f12ea73501b" -"checksum libp2p-tcp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4625bedbb083d676903a8ede4c5c42f9bf7bd5dee788f3cba29d8e01b785d253" -"checksum libp2p-uds 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5f5d900e381b02ebea2f0621555a2f25a7735772355291aeb70fd9e0da3692" -"checksum libp2p-websocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96b6dfdd776a248d7494aeaf22f149b4d5f6784146546bc34f7b094c7162e141" -"checksum libp2p-yamux 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5a6197ae647c963f5a711c6fb00ba07b9a2812df26f6284870221f654fe9313" +"checksum libp2p 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96bec5a2470cf03c5f0a74c55fc7b26fe969a1530d09d40e02ed76b287e3f9d9" +"checksum libp2p-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d53c885b93897902e5fdfd02340459bd940e970b73dd2cf506d4009e527489bf" +"checksum libp2p-core-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ab475ca93c07ce539691003b682a0ff025f7dfb51e4ab29f5474457ded59b" +"checksum libp2p-dns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "983bc7e80b6b5c89f5c6b674880bc058d37f481812692431914732ee2aeaf87a" +"checksum libp2p-floodsub 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aca5042008a7f7ddc53f5d40e6411ffebd66af22989a364303f2996fc5f39c79" +"checksum libp2p-identify 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9036ddde527bba0ae8a9037af7637c6c7a10ccdcdff6d2b00e7fe01f7620d400" +"checksum libp2p-kad 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f42265a4ad1c3a153465babcf64ea32d33b3872f4e2a27fb1dc3d1ed9301fd" +"checksum libp2p-mdns 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "260cb7644da51ee2680c6413d350cee35441e78699b38e63600397867e32e3ab" +"checksum libp2p-mplex 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938678badaa29182f826308d86a89db53b99dd401121c551a979fd1b0a87af48" +"checksum libp2p-noise 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8820b79d0967de619e5dc991f84ffd5b888d06969bc62cf041412b2e9fc1e5c" +"checksum libp2p-ping 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad1b0983dbc2bf126583555c7a855ceaa28abfe764b9ede087d308b80ff7b2a" +"checksum libp2p-plaintext 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7cb42f7def0cb74781f6793f0fecbcfa0db79baee80adf18215abc30b1b6912c" +"checksum libp2p-ratelimit 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6971c2fc1cd938cd702b2320d3b5e3b5a353b1a3310de974769c3fa670d26e" +"checksum libp2p-secio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48a881b9c1b6ff0d35d985437d9f59d2d3ee2c529375aa188a978a1bd1d6f261" +"checksum libp2p-tcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79583caf603d93dc43ee314409c57e070e9a70c760631eea91822a25e898d1af" +"checksum libp2p-uds 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d72965117a6b0ead9b78af8682b0ab6d8c3d71dbb9aadbcb947ef2ef78c2c8a" +"checksum libp2p-websocket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b69b73fcef9d58ae90c6742389a1d29e14dcf3a4ab30bba2f0ca7e984fa59f9f" +"checksum libp2p-yamux 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "563222e2c303516fa097686573f003ee74761eb8d6b6df4204ae1aa07f5dc16c" "checksum librocksdb-sys 5.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9024327233e7fac7982440f73301c00046d438c5b1011e8f4e394226ce19007" "checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" @@ -5407,6 +5434,8 @@ dependencies = [ "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum x25519-dalek 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca1ba6bec2719576bd20dfe5b24d9359552e616d10bff257e50cd85f745d17" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" -"checksum yamux 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2269402a82beb59192319ad64a199850b6dcf3a14ef941206cdad3d7b9cfb598" +"checksum yamux 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "302defd1bed8a9a6d43b82f0e5a50510dfdfbbd02c270c93ff9d6f3f5e2dea89" +"checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" diff --git a/substrate/core/cli/Cargo.toml b/substrate/core/cli/Cargo.toml index 2790cd5180..c5bf34063d 100644 --- a/substrate/core/cli/Cargo.toml +++ b/substrate/core/cli/Cargo.toml @@ -33,3 +33,6 @@ substrate-telemetry = { path = "../../core/telemetry" } keyring = { package = "substrate-keyring", path = "../keyring" } names = "0.11.0" structopt = "0.2" + +[dev-dependencies] +tempdir = "0.3" diff --git a/substrate/core/cli/src/lib.rs b/substrate/core/cli/src/lib.rs index 0344ae5178..1868d79d74 100644 --- a/substrate/core/cli/src/lib.rs +++ b/substrate/core/cli/src/lib.rs @@ -32,7 +32,8 @@ use service::{ FactoryGenesis, PruningMode, ChainSpec, }; use network::{ - Protocol, config::{NetworkConfiguration, NonReservedPeerMode, Secret}, + self, multiaddr::Protocol, + config::{NetworkConfiguration, NonReservedPeerMode, NodeKeyConfig}, build_multiaddr, }; use primitives::H256; @@ -50,6 +51,7 @@ pub use structopt::clap::App; use params::{ RunCmd, PurgeChainCmd, RevertCmd, ImportBlocksCmd, ExportBlocksCmd, BuildSpecCmd, NetworkConfigurationParams, SharedParams, MergeParameters, TransactionPoolParams, + NodeKeyParams, NodeKeyType }; pub use params::{NoCustom, CoreParams}; pub use traits::{GetLogFilter, AugmentClap}; @@ -61,7 +63,18 @@ use lazy_static::lazy_static; use futures::Future; use substrate_telemetry::TelemetryEndpoints; -const MAX_NODE_NAME_LENGTH: usize = 32; +/// The maximum number of characters for a node name. +const NODE_NAME_MAX_LENGTH: usize = 32; + +/// The file name of the node's Secp256k1 secret key inside the chain-specific +/// network config directory, if neither `--node-key` nor `--node-key-file` +/// is specified in combination with `--node-key-type=secp256k1`. +const NODE_KEY_SECP256K1_FILE: &str = "secret"; + +/// The file name of the node's Ed25519 secret key inside the chain-specific +/// network config directory, if neither `--node-key` nor `--node-key-file` +/// is specified in combination with `--node-key-type=ed25519`. +const NODE_KEY_ED25519_FILE: &str = "secret_ed25519"; /// Executable version. Used to pass version information from the root crate. pub struct VersionInfo { @@ -101,7 +114,7 @@ fn generate_node_name() -> String { let node_name = Generator::with_naming(Name::Numbered).next().unwrap(); let count = node_name.chars().count(); - if count < MAX_NODE_NAME_LENGTH { + if count < NODE_NAME_MAX_LENGTH { break node_name } }; @@ -133,14 +146,14 @@ fn base_path(cli: &SharedParams, version: &VersionInfo) -> PathBuf { ) } -fn create_input_err>(msg: T) -> error::Error { +fn input_err>(msg: T) -> error::Error { error::ErrorKind::Input(msg.into()).into() } /// Check whether a node name is considered as valid fn is_node_name_valid(_name: &str) -> Result<(), &str> { let name = _name.to_string(); - if name.chars().count() >= MAX_NODE_NAME_LENGTH { + if name.chars().count() >= NODE_NAME_MAX_LENGTH { return Err("Node name too long"); } @@ -231,14 +244,60 @@ where } } -fn parse_node_key(key: Option) -> error::Result> { - match key.map(|k| H256::from_str(&k)) { - Some(Ok(secret)) => Ok(Some(secret.into())), - Some(Err(err)) => Err(create_input_err(format!("Error parsing node key: {}", err))), - None => Ok(None), +/// Create a `NodeKeyConfig` from the given `NodeKeyParams` in the context +/// of an optional network config storage directory. +fn node_key_config

(params: NodeKeyParams, net_config_dir: &Option

) + -> error::Result +where + P: AsRef +{ + match params.node_key_type { + NodeKeyType::Secp256k1 => + params.node_key.as_ref().map(parse_secp256k1_secret).unwrap_or_else(|| + Ok(params.node_key_file + .or_else(|| net_config_file(net_config_dir, NODE_KEY_SECP256K1_FILE)) + .map(network::Secret::File) + .unwrap_or(network::Secret::New))) + .map(NodeKeyConfig::Secp256k1), + + NodeKeyType::Ed25519 => + params.node_key.as_ref().map(parse_ed25519_secret).unwrap_or_else(|| + Ok(params.node_key_file + .or_else(|| net_config_file(net_config_dir, NODE_KEY_ED25519_FILE)) + .map(network::Secret::File) + .unwrap_or(network::Secret::New))) + .map(NodeKeyConfig::Ed25519) } } +fn net_config_file

(net_config_dir: &Option

, name: &str) -> Option +where + P: AsRef +{ + net_config_dir.as_ref().map(|d| d.as_ref().join(name)) +} + +/// Create an error caused by an invalid node key argument. +fn invalid_node_key(e: impl std::fmt::Display) -> error::Error { + input_err(format!("Invalid node key: {}", e)) +} + +/// Parse a Secp256k1 secret key from a hex string into a `network::Secret`. +fn parse_secp256k1_secret(hex: &String) -> error::Result { + H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes| + network::identity::secp256k1::SecretKey::from_bytes(bytes) + .map(network::Secret::Input) + .map_err(invalid_node_key)) +} + +/// Parse a Ed25519 secret key from a hex string into a `network::Secret`. +fn parse_ed25519_secret(hex: &String) -> error::Result { + H256::from_str(&hex).map_err(invalid_node_key).and_then(|bytes| + network::identity::ed25519::SecretKey::from_bytes(bytes) + .map(network::Secret::Input) + .map_err(invalid_node_key)) +} + /// Fill the given `PoolConfiguration` by looking at the cli parameters. fn fill_transaction_pool_configuration( options: &mut FactoryFullConfiguration, @@ -295,7 +354,7 @@ fn fill_network_configuration( config.public_addresses = Vec::new(); config.client_version = client_id; - config.use_secret = parse_node_key(cli.node_key)?; + config.node_key = node_key_config(cli.node_key_params, &config.net_config_path)?; config.in_peers = cli.in_peers; config.out_peers = cli.out_peers; @@ -324,7 +383,7 @@ where match is_node_name_valid(&config.name) { Ok(_) => (), Err(msg) => bail!( - create_input_err( + input_err( format!("Invalid node name '{}'. Reason: {}. If unsure, use none.", config.name, msg @@ -347,7 +406,7 @@ where Some(ref s) if s == "archive" => PruningMode::ArchiveAll, None => PruningMode::default(), Some(s) => PruningMode::keep_blocks( - s.parse().map_err(|_| create_input_err("Invalid pruning mode specified"))? + s.parse().map_err(|_| input_err("Invalid pruning mode specified"))? ), }; @@ -443,23 +502,19 @@ where // 9926-9949 Unassigned fn with_default_boot_node( - mut spec: ChainSpec>, - cli: &BuildSpecCmd, + spec: &mut ChainSpec>, + cli: BuildSpecCmd, version: &VersionInfo, -) -> error::Result>> +) -> error::Result<()> where F: ServiceFactory { if spec.boot_nodes().is_empty() { - let network_path = - Some(network_path(&base_path(&cli.shared_params, version), spec.id()).to_string_lossy().into()); - let network_key = parse_node_key(cli.node_key.clone())?; - - let network_keys = - network::obtain_private_key(&network_key, &network_path) - .map_err(|err| format!("Error obtaining network key: {}", err))?; - - let peer_id = network_keys.to_peer_id(); + let base_path = base_path(&cli.shared_params, version); + let storage_path = network_path(&base_path, spec.id()); + let node_key = node_key_config(cli.node_key_params, &Some(storage_path))?; + let keys = node_key.into_keypair()?; + let peer_id = keys.public().into_peer_id(); let addr = build_multiaddr![ Ip4([127, 0, 0, 1]), Tcp(30333u16), @@ -467,7 +522,7 @@ where ]; spec.add_boot_node(addr) } - Ok(spec) + Ok(()) } fn build_spec( @@ -480,9 +535,10 @@ where S: FnOnce(&str) -> Result>>, String>, { info!("Building chain spec"); - let spec = load_spec(&cli.shared_params, spec_factory)?; - let spec = with_default_boot_node::(spec, &cli, version)?; - let json = service::chain_ops::build_spec::>(spec, cli.raw)?; + let raw_output = cli.raw; + let mut spec = load_spec(&cli.shared_params, spec_factory)?; + with_default_boot_node::(&mut spec, cli, version)?; + let json = service::chain_ops::build_spec::>(spec, raw_output)?; print!("{}", json); @@ -707,6 +763,8 @@ fn kill_color(s: &str) -> String { #[cfg(test)] mod tests { use super::*; + use tempdir::TempDir; + use network::identity::{secp256k1, ed25519}; #[test] fn tests_node_name_good() { @@ -722,4 +780,111 @@ mod tests { assert!(is_node_name_valid("www.visit.me").is_err()); assert!(is_node_name_valid("email@domain").is_err()); } + + #[test] + fn test_node_key_config_input() { + fn secret_input(net_config_dir: Option) -> error::Result<()> { + NodeKeyType::variants().into_iter().try_for_each(|t| { + let node_key_type = NodeKeyType::from_str(t).unwrap(); + let sk = match node_key_type { + NodeKeyType::Secp256k1 => secp256k1::SecretKey::generate().as_ref().to_vec(), + NodeKeyType::Ed25519 => ed25519::SecretKey::generate().as_ref().to_vec() + }; + let params = NodeKeyParams { + node_key_type, + node_key: Some(format!("{:x}", H256::from_slice(sk.as_ref()))), + node_key_file: None + }; + node_key_config(params, &net_config_dir).and_then(|c| match c { + NodeKeyConfig::Secp256k1(network::Secret::Input(ref ski)) + if node_key_type == NodeKeyType::Secp256k1 && + &sk[..] == ski.as_ref() => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::Input(ref ski)) + if node_key_type == NodeKeyType::Ed25519 && + &sk[..] == ski.as_ref() => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + assert!(secret_input(None).is_ok()); + assert!(secret_input(Some("x".to_string())).is_ok()); + } + + #[test] + fn test_node_key_config_file() { + fn secret_file(net_config_dir: Option) -> error::Result<()> { + NodeKeyType::variants().into_iter().try_for_each(|t| { + let node_key_type = NodeKeyType::from_str(t).unwrap(); + let tmp = TempDir::new("alice")?; + let file = tmp.path().join(format!("{}_mysecret", t)).to_path_buf(); + let params = NodeKeyParams { + node_key_type, + node_key: None, + node_key_file: Some(file.clone()) + }; + node_key_config(params, &net_config_dir).and_then(|c| match c { + NodeKeyConfig::Secp256k1(network::Secret::File(ref f)) + if node_key_type == NodeKeyType::Secp256k1 && f == &file => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::File(ref f)) + if node_key_type == NodeKeyType::Ed25519 && f == &file => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + assert!(secret_file(None).is_ok()); + assert!(secret_file(Some("x".to_string())).is_ok()); + } + + #[test] + fn test_node_key_config_default() { + fn with_def_params(f: F) -> error::Result<()> + where + F: Fn(NodeKeyParams) -> error::Result<()> + { + NodeKeyType::variants().into_iter().try_for_each(|t| { + let node_key_type = NodeKeyType::from_str(t).unwrap(); + f(NodeKeyParams { + node_key_type, + node_key: None, + node_key_file: None + }) + }) + } + + fn no_config_dir() -> error::Result<()> { + with_def_params(|params| { + let typ = params.node_key_type; + node_key_config::(params, &None) + .and_then(|c| match c { + NodeKeyConfig::Secp256k1(network::Secret::New) + if typ == NodeKeyType::Secp256k1 => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::New) + if typ == NodeKeyType::Ed25519 => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + fn some_config_dir(net_config_dir: String) -> error::Result<()> { + with_def_params(|params| { + let dir = PathBuf::from(net_config_dir.clone()); + let typ = params.node_key_type; + node_key_config(params, &Some(net_config_dir.clone())) + .and_then(move |c| match c { + NodeKeyConfig::Secp256k1(network::Secret::File(ref f)) + if typ == NodeKeyType::Secp256k1 && + f == &dir.join(NODE_KEY_SECP256K1_FILE) => Ok(()), + NodeKeyConfig::Ed25519(network::Secret::File(ref f)) + if typ == NodeKeyType::Ed25519 && + f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()), + _ => Err(input_err("Unexpected node key config")) + }) + }) + } + + assert!(no_config_dir().is_ok()); + assert!(some_config_dir("x".to_string()).is_ok()); + } } diff --git a/substrate/core/cli/src/params.rs b/substrate/core/cli/src/params.rs index ace9959678..d84f202501 100644 --- a/substrate/core/cli/src/params.rs +++ b/substrate/core/cli/src/params.rs @@ -68,7 +68,7 @@ pub struct SharedParams { #[structopt(long = "base-path", short = "d", value_name = "PATH", parse(from_os_str))] pub base_path: Option, - ///Sets a custom logging filter + /// Sets a custom logging filter #[structopt(short = "l", long = "log", value_name = "LOG_PATTERN")] pub log: Option, } @@ -98,10 +98,6 @@ pub struct NetworkConfigurationParams { #[structopt(long = "port", value_name = "PORT")] pub port: Option, - /// Specify node secret key (64-character hex string) - #[structopt(long = "node-key", value_name = "KEY")] - pub node_key: Option, - /// Specify the number of outgoing connections we're trying to maintain #[structopt(long = "out-peers", value_name = "OUT_PEERS", default_value = "25")] pub out_peers: u32, @@ -109,6 +105,93 @@ pub struct NetworkConfigurationParams { /// Specify the maximum number of incoming connections we're accepting #[structopt(long = "in-peers", value_name = "IN_PEERS", default_value = "25")] pub in_peers: u32, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub node_key_params: NodeKeyParams +} + +arg_enum! { + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum NodeKeyType { + Secp256k1, + Ed25519 + } +} + +/// Parameters used to create the `NodeKeyConfig`, which determines the keypair +/// used for libp2p networking. +#[derive(Debug, StructOpt, Clone)] +pub struct NodeKeyParams { + /// The secret key to use for libp2p networking. + /// + /// The value is a string that is parsed according to the choice of + /// `--node-key-type` as follows: + /// + /// `secp256k1`: + /// The value is parsed as a hex-encoded Secp256k1 32 bytes secret key, + /// i.e. 64 hex characters. + /// + /// `ed25519`: + /// The value is parsed as a hex-encoded Ed25519 32 bytes secret key, + /// i.e. 64 hex characters. + /// + /// The value of this option takes precedence over `--node-key-file`. + /// + /// WARNING: Secrets provided as command-line arguments are easily exposed. + /// Use of this option should be limited to development and testing. To use + /// an externally managed secret key, use `--node-key-file` instead. + #[structopt(long = "node-key", value_name = "KEY")] + pub node_key: Option, + + /// The type of secret key to use for libp2p networking. + /// + /// The secret key of the node is obtained as follows: + /// + /// * If the `--node-key` option is given, the value is parsed as a secret key + /// according to the type. See the documentation for `--node-key`. + /// + /// * If the `--node-key-file` option is given, the secret key is read from the + /// specified file. See the documentation for `--node-key-file`. + /// + /// * Otherwise, the secret key is read from a file with a predetermined, + /// type-specific name from the chain-specific network config directory + /// inside the base directory specified by `--base-dir`. If this file does + /// not exist, it is created with a newly generated secret key of the + /// chosen type. + /// + /// The node's secret key determines the corresponding public key and hence the + /// node's peer ID in the context of libp2p. + /// + /// NOTE: The current default key type is `secp256k1` for a transition period only + /// but will eventually change to `ed25519` in a future release. To continue using + /// `secp256k1` keys, use `--node-key-type=secp256k1`. + #[structopt( + long = "node-key-type", + value_name = "TYPE", + raw( + possible_values = "&NodeKeyType::variants()", + case_insensitive = "true", + default_value = r#""Secp256k1""# + ) + )] + pub node_key_type: NodeKeyType, + + /// The file from which to read the node's secret key to use for libp2p networking. + /// + /// The contents of the file are parsed according to the choice of `--node-key-type` + /// as follows: + /// + /// `secp256k1`: + /// The file must contain an unencoded 32 bytes Secp256k1 secret key. + /// + /// `ed25519`: + /// The file must contain an unencoded 32 bytes Ed25519 secret key. + /// + /// If the file does not exist, it is created with a newly generated secret key of + /// the chosen type. + #[structopt(long = "node-key-file", value_name = "FILE")] + pub node_key_file: Option } /// Parameters used to create the pool configuration. @@ -169,7 +252,7 @@ pub struct RunCmd { #[structopt(long = "name", value_name = "NAME")] pub name: Option, - /// Should not connect to the Substrate telemetry server (telemetry is on by default on global chains) + /// Disable connecting to the Substrate telemetry server (telemetry is on by default on global chains). #[structopt(long = "no-telemetry")] pub no_telemetry: bool, @@ -343,9 +426,9 @@ pub struct BuildSpecCmd { #[structopt(flatten)] pub shared_params: SharedParams, - /// Specify node secret key (64-character hex string) - #[structopt(long = "node-key", value_name = "KEY")] - pub node_key: Option, + #[allow(missing_docs)] + #[structopt(flatten)] + pub node_key_params: NodeKeyParams, } impl_get_log_filter!(BuildSpecCmd); diff --git a/substrate/core/network-libp2p/Cargo.toml b/substrate/core/network-libp2p/Cargo.toml index ab784ac978..35761c8c57 100644 --- a/substrate/core/network-libp2p/Cargo.toml +++ b/substrate/core/network-libp2p/Cargo.toml @@ -13,7 +13,7 @@ bytes = "0.4" error-chain = { version = "0.12", default-features = false } fnv = "1.0" futures = "0.1" -libp2p = { version = "0.4.0", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] } +libp2p = { version = "0.5.0", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] } parking_lot = "0.7.1" lazy_static = "1.2" log = "0.4" @@ -27,3 +27,7 @@ tokio-io = "0.1" tokio-timer = "0.2" unsigned-varint = { version = "0.2.1", features = ["codec"] } void = "1.0" + +[dev-dependencies] +tempdir = "0.3" + diff --git a/substrate/core/network-libp2p/src/behaviour.rs b/substrate/core/network-libp2p/src/behaviour.rs index ba79e0ef32..38ec22b0ac 100644 --- a/substrate/core/network-libp2p/src/behaviour.rs +++ b/substrate/core/network-libp2p/src/behaviour.rs @@ -25,7 +25,7 @@ use libp2p::identify::{Identify, IdentifyEvent, protocol::IdentifyInfo}; use libp2p::kad::{Kademlia, KademliaOut, KadConnectionType}; use libp2p::ping::{Ping, PingEvent}; use log::{debug, trace, warn}; -use std::{cmp, io, time::Duration, time::Instant}; +use std::{cmp, io, fmt, time::Duration, time::Instant}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_timer::Delay; use void; @@ -445,3 +445,26 @@ where } } +/// The severity of misbehaviour of a peer that is reported. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Severity { + /// Peer is timing out. Could be bad connectivity of overload of work on either of our sides. + Timeout, + /// Peer has been notably useless. E.g. unable to answer a request that we might reasonably consider + /// it could answer. + Useless(String), + /// Peer has behaved in an invalid manner. This doesn't necessarily need to be Byzantine, but peer + /// must have taken concrete action in order to behave in such a way which is wantanly invalid. + Bad(String), +} + +impl fmt::Display for Severity { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Severity::Timeout => write!(fmt, "Timeout"), + Severity::Useless(r) => write!(fmt, "Useless ({})", r), + Severity::Bad(r) => write!(fmt, "Bad ({})", r), + } + } +} + diff --git a/substrate/core/network-libp2p/src/config.rs b/substrate/core/network-libp2p/src/config.rs new file mode 100644 index 0000000000..61fae1a398 --- /dev/null +++ b/substrate/core/network-libp2p/src/config.rs @@ -0,0 +1,286 @@ +// Copyright 2015-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Libp2p network configuration. + +use libp2p::identity::{Keypair, secp256k1, ed25519}; +use libp2p::{Multiaddr, multiaddr::Protocol}; +use std::error::Error; +use std::{io::{self, Write}, iter, fs, net::Ipv4Addr, path::{Path, PathBuf}}; + +/// Network service configuration. +#[derive(Clone)] +pub struct NetworkConfiguration { + /// Directory path to store general network configuration. None means nothing will be saved. + pub config_path: Option, + /// Directory path to store network-specific configuration. None means nothing will be saved. + pub net_config_path: Option, + /// Multiaddresses to listen for incoming connections. + pub listen_addresses: Vec, + /// Multiaddresses to advertise. Detected automatically if empty. + pub public_addresses: Vec, + /// List of initial node addresses + pub boot_nodes: Vec, + /// The node key configuration, which determines the node's network identity keypair. + pub node_key: NodeKeyConfig, + /// Maximum allowed number of incoming connections. + pub in_peers: u32, + /// Number of outgoing connections we're trying to maintain. + pub out_peers: u32, + /// List of reserved node addresses. + pub reserved_nodes: Vec, + /// The non-reserved peer mode. + pub non_reserved_mode: NonReservedPeerMode, + /// Client identifier. Sent over the wire for debugging purposes. + pub client_version: String, + /// Name of the node. Sent over the wire for debugging purposes. + pub node_name: String, +} + +impl Default for NetworkConfiguration { + fn default() -> Self { + NetworkConfiguration { + config_path: None, + net_config_path: None, + listen_addresses: Vec::new(), + public_addresses: Vec::new(), + boot_nodes: Vec::new(), + node_key: NodeKeyConfig::Secp256k1(Secret::New), + in_peers: 25, + out_peers: 75, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Accept, + client_version: "unknown".into(), + node_name: "unknown".into(), + } + } +} + +impl NetworkConfiguration { + /// Create a new instance of default settings. + pub fn new() -> Self { + Self::default() + } + + /// Create new default configuration for localhost-only connection with random port (useful for testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_addresses = vec![ + iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(Protocol::Tcp(0))) + .collect() + ]; + config + } +} + +/// The policy for connections to non-reserved peers. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonReservedPeerMode { + /// Accept them. This is the default. + Accept, + /// Deny them. + Deny, +} + +impl NonReservedPeerMode { + /// Attempt to parse the peer mode from a string. + pub fn parse(s: &str) -> Option { + match s { + "accept" => Some(NonReservedPeerMode::Accept), + "deny" => Some(NonReservedPeerMode::Deny), + _ => None, + } + } +} + +/// The configuration of a node's secret key, describing the type of key +/// and how it is obtained. A node's identity keypair is the result of +/// the evaluation of the node key configuration. +#[derive(Clone)] +pub enum NodeKeyConfig { + /// A Secp256k1 secret key configuration. + Secp256k1(Secret), + /// A Ed25519 secret key configuration. + Ed25519(Secret) +} + +/// The options for obtaining a Secp256k1 secret key. +pub type Secp256k1Secret = Secret; + +/// The options for obtaining a Ed25519 secret key. +pub type Ed25519Secret = Secret; + +/// The configuration options for obtaining a secret key `K`. +#[derive(Clone)] +pub enum Secret { + /// Use the given secret key `K`. + Input(K), + /// Read the secret key from a file. If the file does not exist, + /// it is created with a newly generated secret key `K`. The format + /// of the file is determined by `K`: + /// + /// * `secp256k1::SecretKey`: An unencoded 32 bytes Secp256k1 secret key. + /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. + File(PathBuf), + /// Always generate a new secret key `K`. + New +} + +impl NodeKeyConfig { + /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: + /// + /// * If the secret is configured as input, the corresponding keypair is returned. + /// + /// * If the secret is configured as a file, it is read from that file, if it exists. + /// Otherwise a new secret is generated and stored. In either case, the + /// keypair obtained from the secret is returned. + /// + /// * If the secret is configured to be new, it is generated and the corresponding + /// keypair is returned. + pub fn into_keypair(self) -> io::Result { + use NodeKeyConfig::*; + match self { + Secp256k1(Secret::New) => + Ok(Keypair::generate_secp256k1()), + + Secp256k1(Secret::Input(k)) => + Ok(Keypair::Secp256k1(k.into())), + + Secp256k1(Secret::File(f)) => + get_secret(f, + |mut b| secp256k1::SecretKey::from_bytes(&mut b), + secp256k1::SecretKey::generate) + .map(secp256k1::Keypair::from) + .map(Keypair::Secp256k1), + + Ed25519(Secret::New) => + Ok(Keypair::generate_ed25519()), + + Ed25519(Secret::Input(k)) => + Ok(Keypair::Ed25519(k.into())), + + Ed25519(Secret::File(f)) => + get_secret(f, + |mut b| ed25519::SecretKey::from_bytes(&mut b), + ed25519::SecretKey::generate) + .map(ed25519::Keypair::from) + .map(Keypair::Ed25519), + } + } +} + +/// Load a secret key from a file, if it exists, or generate a +/// new secret key and write it to that file. In either case, +/// the secret key is returned. +fn get_secret(file: P, parse: F, generate: G) -> io::Result +where + P: AsRef, + F: for<'r> FnOnce(&'r mut [u8]) -> Result, + G: FnOnce() -> K, + E: Error + Send + Sync + 'static, + K: AsRef<[u8]> +{ + std::fs::read(&file) + .and_then(|mut sk_bytes| + parse(&mut sk_bytes) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))) + .or_else(|e| { + if e.kind() == io::ErrorKind::NotFound { + file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?; + let sk = generate(); + write_secret_file(file, sk.as_ref())?; + Ok(sk) + } else { + Err(e) + } + }) +} + +/// Write secret bytes to a file. +fn write_secret_file

(path: P, sk_bytes: &[u8]) -> io::Result<()> +where + P: AsRef +{ + let mut file = open_secret_file(&path)?; + file.write_all(sk_bytes) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(unix)] +fn open_secret_file

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

(path: P) -> Result +where + P: AsRef +{ + fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(path) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempdir::TempDir; + + fn secret_bytes(kp: &Keypair) -> Vec { + match kp { + Keypair::Ed25519(p) => p.secret().as_ref().iter().cloned().collect(), + Keypair::Secp256k1(p) => p.secret().as_ref().iter().cloned().collect(), + _ => panic!("Unexpected keypair.") + } + } + + #[test] + fn test_secret_file() { + let tmp = TempDir::new("x").unwrap(); + std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated + let file = tmp.path().join("x").to_path_buf(); + let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2)) + } + + #[test] + fn test_secret_input() { + let sk = secp256k1::SecretKey::generate(); + let kp1 = NodeKeyConfig::Secp256k1(Secret::Input(sk.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Secp256k1(Secret::Input(sk)).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); + } + + #[test] + fn test_secret_new() { + let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) != secret_bytes(&kp2)); + } +} + diff --git a/substrate/core/network-libp2p/src/custom_proto/behaviour.rs b/substrate/core/network-libp2p/src/custom_proto/behaviour.rs index 1332dfd0df..ab64b42daf 100644 --- a/substrate/core/network-libp2p/src/custom_proto/behaviour.rs +++ b/substrate/core/network-libp2p/src/custom_proto/behaviour.rs @@ -71,7 +71,7 @@ pub struct CustomProtos { /// List of the IDs of peers that are forbidden, and the moment their ban expires. banned_peers: Vec<(PeerId, Instant)>, - /// When this delay expires, we need to synchronize our active connectons with the + /// When this delay expires, we need to synchronize our active connections with the /// network topology. next_connect_to_nodes: Delay, diff --git a/substrate/core/network-libp2p/src/custom_proto/handler.rs b/substrate/core/network-libp2p/src/custom_proto/handler.rs index bb326923e1..947dc2ddd4 100644 --- a/substrate/core/network-libp2p/src/custom_proto/handler.rs +++ b/substrate/core/network-libp2p/src/custom_proto/handler.rs @@ -132,11 +132,6 @@ enum PerProtocolState { reenable: bool, }, - /// We are trying to shut down the connection and thus should refuse any incoming connection. - /// Contains substreams that are being closed. Once all the substreams are closed, we close - /// the connection. - ShuttingDown(SmallVec<[RegisteredProtocolSubstream; 6]>), - /// We sometimes temporarily switch to this state during processing. If we are in this state /// at the beginning of a method, that means something bad happend in the source code. Poisoned, @@ -232,10 +227,6 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { return_value = None; PerProtocolState::Disabled { shutdown, reenable: true } } - PerProtocolState::ShuttingDown(list) => { - return_value = None; - PerProtocolState::ShuttingDown(list) - } }; return_value @@ -289,61 +280,11 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { PerProtocolState::Disabled { shutdown, .. } => PerProtocolState::Disabled { shutdown, reenable: false }, - PerProtocolState::ShuttingDown(list) => - PerProtocolState::ShuttingDown(list), }; return_value } - /// Shuts down all the substream. Returns `true` if the protocol was closed, `false` if it was - /// already closed or not open yet. - fn shutdown(&mut self) -> bool { - let mut return_value = false; - self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) { - PerProtocolState::Poisoned => { - error!(target: "sub-libp2p", "Handler is in poisoned state"); - PerProtocolState::Poisoned - } - - PerProtocolState::Init { substreams: mut list, .. } => { - for s in &mut list { s.shutdown(); } - PerProtocolState::ShuttingDown(list) - } - - PerProtocolState::Opening { .. } => { - PerProtocolState::ShuttingDown(SmallVec::new()) - } - - PerProtocolState::BackCompat { mut substream, mut shutdown } => { - substream.shutdown(); - shutdown.push(substream); - return_value = true; - PerProtocolState::ShuttingDown(shutdown.into_iter().collect()) - } - - PerProtocolState::Normal(state) => { - let mut out: SmallVec<[_; 6]> = SmallVec::new(); - out.extend(state.outgoing_substream.into_iter()); - out.extend(state.incoming_substreams.into_iter()); - out.extend(state.pending_response.into_iter().map(|(_, s)| s)); - out.extend(state.pending_send_back.into_iter().map(|(_, s)| s)); - for s in &mut out { - s.shutdown(); - } - out.extend(state.shutdown.into_iter()); - return_value = true; - PerProtocolState::ShuttingDown(out) - } - - PerProtocolState::Disabled { shutdown, .. } => - PerProtocolState::ShuttingDown(shutdown), - PerProtocolState::ShuttingDown(list) => - PerProtocolState::ShuttingDown(list), - }; - return_value - } - /// Polls the state for events. Optionally returns an event to produce. #[must_use] fn poll(&mut self) @@ -353,7 +294,7 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) { PerProtocolState::Poisoned => { error!(target: "sub-libp2p", "Handler is in poisoned state; shutting down"); - return_value = Some(ProtocolsHandlerEvent::Shutdown); + return_value = None; PerProtocolState::Poisoned } @@ -468,12 +409,6 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite { PerProtocolState::Disabled { shutdown, reenable } } } - - PerProtocolState::ShuttingDown(mut list) => { - shutdown_list(&mut list); - return_value = None; - PerProtocolState::ShuttingDown(list) - } }; return_value @@ -793,12 +728,6 @@ where shutdown.push(substream); PerProtocolState::Disabled { shutdown, reenable: false } } - - PerProtocolState::ShuttingDown(mut list) => { - substream.shutdown(); - list.push(substream); - PerProtocolState::ShuttingDown(list) - } }; } @@ -909,9 +838,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { } } - #[inline] - fn inject_inbound_closed(&mut self) {} - #[inline] fn inject_dial_upgrade_error(&mut self, protocol_id: Self::OutboundOpenInfo, err: ProtocolsHandlerUpgrErr) { let is_severe = match err { @@ -942,7 +868,7 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { PerProtocolState::Init { .. } | PerProtocolState::Opening { .. } => {} PerProtocolState::BackCompat { .. } | PerProtocolState::Normal { .. } => keep_forever = true, - PerProtocolState::Disabled { .. } | PerProtocolState::ShuttingDown(_) | + PerProtocolState::Disabled { .. } | PerProtocolState::Poisoned => return KeepAlive::Now, } } @@ -954,18 +880,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { } } - fn shutdown(&mut self) { - for protocol in &mut self.protocols { - if protocol.shutdown() { - let event = CustomProtosHandlerOut::CustomProtocolClosed { - protocol_id: protocol.protocol.id(), - result: Ok(()) - }; - self.events_queue.push(ProtocolsHandlerEvent::Custom(event)); - } - } - } - fn poll( &mut self, ) -> Poll< @@ -985,16 +899,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage { } } - // Shut down the node if everything is closed. - let can_shut_down = self.protocols.iter().all(|p| - match p.state { - PerProtocolState::ShuttingDown(ref list) if list.is_empty() => true, - _ => false - }); - if can_shut_down { - return Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)) - } - Ok(Async::NotReady) } } diff --git a/substrate/core/network-libp2p/src/lib.rs b/substrate/core/network-libp2p/src/lib.rs index a6336e4163..362a47c19d 100644 --- a/substrate/core/network-libp2p/src/lib.rs +++ b/substrate/core/network-libp2p/src/lib.rs @@ -17,29 +17,38 @@ //! Networking layer of Substrate. mod behaviour; +mod config; mod custom_proto; -mod secret; mod service_task; -mod traits; mod transport; +pub use crate::behaviour::Severity; +pub use crate::config::*; pub use crate::custom_proto::{CustomMessage, CustomMessageId, RegisteredProtocol}; -pub use crate::secret::obtain_private_key; +pub use crate::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPeerMode}; pub use crate::service_task::{start_service, Service, ServiceEvent}; -pub use crate::traits::{NetworkConfiguration, NodeIndex, NodeId, NonReservedPeerMode}; -pub use crate::traits::{ProtocolId, Secret, Severity}; -pub use libp2p::{Multiaddr, multiaddr::Error as MultiaddrError, multiaddr::Protocol, build_multiaddr, PeerId, core::PublicKey}; +pub use libp2p::{Multiaddr, multiaddr, build_multiaddr}; +pub use libp2p::{identity, PeerId, core::PublicKey}; use libp2p::core::nodes::ConnectedPoint; use serde_derive::Serialize; use std::{collections::{HashMap, HashSet}, error, fmt, time::Duration}; +/// Protocol / handler id +pub type ProtocolId = [u8; 3]; + +/// Node public key +pub type NodeId = PeerId; + +/// Local (temporary) peer session ID. +pub type NodeIndex = usize; + /// Parses a string address and returns the component, if valid. pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> { let mut addr: Multiaddr = addr_str.parse()?; let who = match addr.pop() { - Some(Protocol::P2p(key)) => PeerId::from_multihash(key) + Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key) .map_err(|_| ParseErr::InvalidPeerId)?, _ => return Err(ParseErr::PeerIdMissing), }; @@ -51,7 +60,7 @@ pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> { #[derive(Debug)] pub enum ParseErr { /// Error while parsing the multiaddress. - MultiaddrParse(MultiaddrError), + MultiaddrParse(multiaddr::Error), /// Multihash of the peer ID is invalid. InvalidPeerId, /// The peer ID is missing from the address. @@ -78,8 +87,8 @@ impl error::Error for ParseErr { } } -impl From for ParseErr { - fn from(err: MultiaddrError) -> ParseErr { +impl From for ParseErr { + fn from(err: multiaddr::Error) -> ParseErr { ParseErr::MultiaddrParse(err) } } diff --git a/substrate/core/network-libp2p/src/secret.rs b/substrate/core/network-libp2p/src/secret.rs deleted file mode 100644 index f7a25d000c..0000000000 --- a/substrate/core/network-libp2p/src/secret.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2018-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -use crate::NetworkConfiguration; -use libp2p::secio; -use log::{trace, warn}; -use rand::Rng; -use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read, Write}; -use std::{fs, path::Path}; - -// File where the private key is stored. -const SECRET_FILE: &str = "secret"; - -/// Obtains or generates the local private key using the configuration. -pub fn obtain_private_key_from_config( - config: &NetworkConfiguration -) -> Result { - obtain_private_key(&config.use_secret, &config.net_config_path) -} - -/// Obtains or generates the local private key using the configuration. -pub fn obtain_private_key( - secret: &Option<[u8; 32]>, - net_config_path: &Option, -) -> Result { - if let Some(ref secret) = 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) = net_config_path { - fs::create_dir_all(Path::new(path))?; - // Try fetch the key from a the file containing the secret. - 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) -} diff --git a/substrate/core/network-libp2p/src/service_task.rs b/substrate/core/network-libp2p/src/service_task.rs index 4cab435c8b..0c23fc4120 100644 --- a/substrate/core/network-libp2p/src/service_task.rs +++ b/substrate/core/network-libp2p/src/service_task.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . use crate::{ - behaviour::Behaviour, behaviour::BehaviourOut, secret::obtain_private_key_from_config, + behaviour::Behaviour, behaviour::BehaviourOut, transport, NetworkState, NetworkStatePeer, NetworkStateNotConnectedPeer }; use crate::custom_proto::{CustomMessage, RegisteredProtocol, RegisteredProtocols}; @@ -49,15 +49,15 @@ where TProtos: IntoIterator>, } // Private and public keys configuration. - let local_private_key = obtain_private_key_from_config(&config)?; - let local_public_key = local_private_key.to_public_key(); - let local_peer_id = local_public_key.clone().into_peer_id(); + let local_identity = config.node_key.clone().into_keypair()?; + let local_public = local_identity.public(); + let local_peer_id = local_public.clone().into_peer_id(); // Build the swarm. let (mut swarm, bandwidth) = { let registered_custom = RegisteredProtocols(registered_custom.into_iter().collect()); - let behaviour = Behaviour::new(&config, local_public_key.clone(), registered_custom); - let (transport, bandwidth) = transport::build_transport(local_private_key); + let behaviour = Behaviour::new(&config, local_public, registered_custom); + let (transport, bandwidth) = transport::build_transport(local_identity); (Swarm::new(transport, behaviour, local_peer_id.clone()), bandwidth) }; diff --git a/substrate/core/network-libp2p/src/traits.rs b/substrate/core/network-libp2p/src/traits.rs deleted file mode 100644 index 63ccda54d1..0000000000 --- a/substrate/core/network-libp2p/src/traits.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2015-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -use std::{fmt, iter, net::Ipv4Addr, str}; -use libp2p::{multiaddr::Protocol, Multiaddr, PeerId}; - -/// Protocol / handler id -pub type ProtocolId = [u8; 3]; - -/// Node public key -pub type NodeId = PeerId; - -/// Local (temporary) peer session ID. -pub type NodeIndex = usize; - -/// secio secret key; -pub type Secret = [u8; 32]; - -/// Network service configuration -#[derive(Debug, PartialEq, Clone)] -pub struct NetworkConfiguration { - /// Directory path to store general network configuration. None means nothing will be saved - pub config_path: Option, - /// Directory path to store network-specific configuration. None means nothing will be saved - pub net_config_path: Option, - /// Multiaddresses to listen for incoming connections. - pub listen_addresses: Vec, - /// Multiaddresses to advertise. Detected automatically if empty. - pub public_addresses: Vec, - /// List of initial node addresses - pub boot_nodes: Vec, - /// Use provided node key instead of default - pub use_secret: Option, - /// Maximum allowed number of incoming connections - pub in_peers: u32, - /// Number of outgoing connections we're trying to maintain - pub out_peers: u32, - /// List of reserved node addresses. - pub reserved_nodes: Vec, - /// The non-reserved peer mode. - pub non_reserved_mode: NonReservedPeerMode, - /// Client identifier. Sent over the wire for debugging purposes. - pub client_version: String, - /// Name of the node. Sent over the wire for debugging purposes. - pub node_name: String, -} - -impl Default for NetworkConfiguration { - fn default() -> Self { - NetworkConfiguration::new() - } -} - -impl NetworkConfiguration { - /// Create a new instance of default settings. - pub fn new() -> Self { - NetworkConfiguration { - config_path: None, - net_config_path: None, - listen_addresses: Vec::new(), - public_addresses: Vec::new(), - boot_nodes: Vec::new(), - use_secret: None, - in_peers: 25, - out_peers: 75, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Accept, - client_version: "unknown".into(), - node_name: "unknown".into(), - } - } - - /// Create new default configuration for localhost-only connection with random port (useful for testing) - pub fn new_local() -> NetworkConfiguration { - let mut config = NetworkConfiguration::new(); - config.listen_addresses = vec![ - iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(Protocol::Tcp(0))) - .collect() - ]; - config - } -} - -/// The severity of misbehaviour of a peer that is reported. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Severity { - /// Peer is timing out. Could be bad connectivity of overload of work on either of our sides. - Timeout, - /// Peer has been notably useless. E.g. unable to answer a request that we might reasonably consider - /// it could answer. - Useless(String), - /// Peer has behaved in an invalid manner. This doesn't necessarily need to be Byzantine, but peer - /// must have taken concrete action in order to behave in such a way which is wantanly invalid. - Bad(String), -} - -impl fmt::Display for Severity { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - Severity::Timeout => write!(fmt, "Timeout"), - Severity::Useless(r) => write!(fmt, "Useless ({})", r), - Severity::Bad(r) => write!(fmt, "Bad ({})", r), - } - } -} - -/// Non-reserved peer modes. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum NonReservedPeerMode { - /// Accept them. This is the default. - Accept, - /// Deny them. - Deny, -} - -impl NonReservedPeerMode { - /// Attempt to parse the peer mode from a string. - pub fn parse(s: &str) -> Option { - match s { - "accept" => Some(NonReservedPeerMode::Accept), - "deny" => Some(NonReservedPeerMode::Deny), - _ => None, - } - } -} diff --git a/substrate/core/network-libp2p/src/transport.rs b/substrate/core/network-libp2p/src/transport.rs index de0639a7b5..404fdb6bda 100644 --- a/substrate/core/network-libp2p/src/transport.rs +++ b/substrate/core/network-libp2p/src/transport.rs @@ -17,7 +17,7 @@ use futures::prelude::*; use libp2p::{ InboundUpgradeExt, OutboundUpgradeExt, PeerId, Transport, - mplex, secio, yamux, tcp, dns, websocket, bandwidth + mplex, identity, secio, yamux, tcp, dns, websocket, bandwidth }; use libp2p::core::{self, transport::boxed::Boxed, muxing::StreamMuxerBox}; use std::{io, sync::Arc, time::Duration, usize}; @@ -29,7 +29,7 @@ pub use self::bandwidth::BandwidthSinks; /// Returns a `BandwidthSinks` object that allows querying the average bandwidth produced by all /// the connections spawned with this transport. pub fn build_transport( - local_private_key: secio::SecioKeyPair + keypair: identity::Keypair ) -> (Boxed<(PeerId, StreamMuxerBox), io::Error>, Arc) { let mut mplex_config = mplex::MplexConfig::new(); mplex_config.max_buffer_len_behaviour(mplex::MaxBufferBehaviour::Block); @@ -42,7 +42,7 @@ pub fn build_transport( // TODO: rework the transport creation (https://github.com/libp2p/rust-libp2p/issues/783) let transport = transport - .with_upgrade(secio::SecioConfig::new(local_private_key)) + .with_upgrade(secio::SecioConfig::new(keypair)) .and_then(move |out, endpoint| { let peer_id = out.remote_key.into_peer_id(); let peer_id2 = peer_id.clone(); diff --git a/substrate/core/network-libp2p/tests/test.rs b/substrate/core/network-libp2p/tests/test.rs index 979cf9b044..a514b0b9bb 100644 --- a/substrate/core/network-libp2p/tests/test.rs +++ b/substrate/core/network-libp2p/tests/test.rs @@ -17,7 +17,7 @@ use futures::{future, stream, prelude::*, try_ready}; use rand::seq::SliceRandom; use std::{io, iter}; -use substrate_network_libp2p::{CustomMessage, Protocol, ServiceEvent, build_multiaddr}; +use substrate_network_libp2p::{CustomMessage, ServiceEvent, multiaddr::Protocol, build_multiaddr}; /// Builds two services. The second one and further have the first one as its bootstrap node. /// This is to be used only for testing, and a panic will happen if something goes wrong. diff --git a/substrate/core/network/src/config.rs b/substrate/core/network/src/config.rs index 7dd4b52b31..2491fc21c4 100644 --- a/substrate/core/network/src/config.rs +++ b/substrate/core/network/src/config.rs @@ -16,7 +16,7 @@ //! Configuration for the networking layer of Substrate. -pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, Secret}; +pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, NodeKeyConfig, Secret}; use bitflags::bitflags; use crate::chain::Client; diff --git a/substrate/core/network/src/lib.rs b/substrate/core/network/src/lib.rs index de4597d597..296eaeb00c 100644 --- a/substrate/core/network/src/lib.rs +++ b/substrate/core/network/src/lib.rs @@ -42,9 +42,11 @@ pub use service::{Service, FetchFuture, TransactionPool, ManageNetwork, NetworkM pub use protocol::{ProtocolStatus, PeerInfo, Context}; pub use sync::{Status as SyncStatus, SyncState}; pub use network_libp2p::{ - NodeIndex, ProtocolId, Severity, Protocol, Multiaddr, + identity, multiaddr, + NodeIndex, ProtocolId, Severity, Multiaddr, NetworkState, NetworkStatePeer, NetworkStateNotConnectedPeer, NetworkStatePeerEndpoint, - obtain_private_key, build_multiaddr, PeerId, PublicKey + NodeKeyConfig, Secret, Secp256k1Secret, Ed25519Secret, + build_multiaddr, PeerId, PublicKey }; pub use message::{generic as generic_message, RequestId, Status as StatusMessage, ConsensusEngineId}; pub use error::Error; diff --git a/substrate/core/network/src/service.rs b/substrate/core/network/src/service.rs index 34f82d2ddc..9485203a0d 100644 --- a/substrate/core/network/src/service.rs +++ b/substrate/core/network/src/service.rs @@ -23,7 +23,7 @@ use futures::{Async, Future, Stream, stream, sync::oneshot, sync::mpsc}; use parking_lot::{Mutex, RwLock}; use network_libp2p::{ProtocolId, NetworkConfiguration, NodeIndex, Severity}; use network_libp2p::{start_service, parse_str_addr, Service as NetworkService, ServiceEvent as NetworkServiceEvent}; -use network_libp2p::{Protocol as Libp2pProtocol, RegisteredProtocol, NetworkState}; +use network_libp2p::{multiaddr, RegisteredProtocol, NetworkState}; use consensus::import_queue::{ImportQueue, Link}; use crate::consensus_gossip::ConsensusGossip; use crate::message::{Message, ConsensusEngineId}; @@ -361,7 +361,7 @@ impl> ManageNetwork for Service .next() .map(|addr| { let mut addr = addr.clone(); - addr.append(Libp2pProtocol::P2p(network.peer_id().clone().into())); + addr.append(multiaddr::Protocol::P2p(network.peer_id().clone().into())); addr.to_string() }); ret diff --git a/substrate/core/service/test/src/lib.rs b/substrate/core/service/test/src/lib.rs index 3a3c4515f7..72372f9292 100644 --- a/substrate/core/service/test/src/lib.rs +++ b/substrate/core/service/test/src/lib.rs @@ -25,7 +25,6 @@ use futures::{Future, Stream}; use tempdir::TempDir; use tokio::runtime::Runtime; use tokio::timer::Interval; -use primitives::blake2_256; use service::{ ServiceFactory, Configuration, @@ -34,8 +33,8 @@ use service::{ Roles, FactoryExtrinsic, }; -use network::{Protocol, SyncProvider, ManageNetwork}; -use network::config::{NetworkConfiguration, NonReservedPeerMode}; +use network::{multiaddr, SyncProvider, ManageNetwork}; +use network::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPeerMode}; use sr_primitives::traits::As; use sr_primitives::generic::BlockId; use consensus::{ImportBlock, BlockImport}; @@ -64,10 +63,6 @@ impl TestNet { } } -fn node_private_key_string(index: u32) -> String { - format!("N{}", index) -} - fn node_config ( index: u32, spec: &FactoryChainSpec, @@ -83,17 +78,20 @@ fn node_config ( keys.push(seed); } + let config_path = Some(String::from(root.join("network").to_str().unwrap())); + let net_config_path = config_path.clone(); + let network_config = NetworkConfiguration { - config_path: Some(root.join("network").to_str().unwrap().into()), - net_config_path: Some(root.join("network").to_str().unwrap().into()), + config_path, + net_config_path, listen_addresses: vec! [ - iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(Protocol::Tcp(base_port + index as u16))) + iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(base_port + index as u16))) .collect() ], public_addresses: vec![], boot_nodes: vec![], - use_secret: Some(blake2_256(node_private_key_string(index).as_bytes())), + node_key: NodeKeyConfig::Ed25519(Secret::New), in_peers: 50, out_peers: 450, reserved_nodes: vec![],