mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 23:21:02 +00:00
Merge branch 'master' into rh-grandpa-dynamic2
This commit is contained in:
@@ -2,7 +2,7 @@ stages:
|
||||
- test
|
||||
- build
|
||||
|
||||
image: parity/rust:substrate
|
||||
image: parity/rust:nightly
|
||||
|
||||
variables:
|
||||
CI_SERVER_NAME: "GitLab CI"
|
||||
|
||||
Generated
+175
-170
@@ -5,7 +5,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -329,8 +329,8 @@ dependencies = [
|
||||
"isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"simplelog 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -427,7 +427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -451,7 +451,7 @@ 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.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -704,7 +704,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -805,13 +805,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.12.11"
|
||||
version = "0.12.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -894,21 +894,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "jsonrpc-core"
|
||||
version = "9.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#8d41129955e9abf08399cd052b4a6df4e0743ad6"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#207a277b098943864ecaf22dbab7a5e309866d6b"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-http-server"
|
||||
version = "9.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#8d41129955e9abf08399cd052b4a6df4e0743ad6"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#207a277b098943864ecaf22dbab7a5e309866d6b"
|
||||
dependencies = [
|
||||
"hyper 0.12.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"jsonrpc-server-utils 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -919,17 +919,17 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-macros"
|
||||
version = "9.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#8d41129955e9abf08399cd052b4a6df4e0743ad6"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#207a277b098943864ecaf22dbab7a5e309866d6b"
|
||||
dependencies = [
|
||||
"jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"jsonrpc-pubsub 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-pubsub"
|
||||
version = "9.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#8d41129955e9abf08399cd052b4a6df4e0743ad6"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#207a277b098943864ecaf22dbab7a5e309866d6b"
|
||||
dependencies = [
|
||||
"jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -939,7 +939,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-server-utils"
|
||||
version = "9.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#8d41129955e9abf08399cd052b4a6df4e0743ad6"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#207a277b098943864ecaf22dbab7a5e309866d6b"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -955,7 +955,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-ws-server"
|
||||
version = "9.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#8d41129955e9abf08399cd052b4a6df4e0743ad6"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git#207a277b098943864ecaf22dbab7a5e309866d6b"
|
||||
dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
@@ -1216,8 +1216,8 @@ dependencies = [
|
||||
"libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=8111062f0177fd7423626f2db9560273644a4c4d)",
|
||||
"multiaddr 0.3.0 (git+https://github.com/tomaka/libp2p-rs?rev=8111062f0177fd7423626f2db9560273644a4c4d)",
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1276,7 +1276,7 @@ dependencies = [
|
||||
"aes-ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"asn1_der 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p-core 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=8111062f0177fd7423626f2db9560273644a4c4d)",
|
||||
@@ -1514,7 +1514,7 @@ dependencies = [
|
||||
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"multihash 0.8.1-pre (git+https://github.com/tomaka/libp2p-rs?rev=8111062f0177fd7423626f2db9560273644a4c4d)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unsigned-varint 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1598,37 +1598,20 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"node-executor 0.1.0",
|
||||
"node-network 0.1.0",
|
||||
"node-primitives 0.1.0",
|
||||
"node-runtime 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-cli 0.3.0",
|
||||
"substrate-network 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-service 0.3.0",
|
||||
"substrate-service-test 0.3.0",
|
||||
"substrate-transaction-pool 0.1.0",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "node-consensus"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"exit-future 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"node-primitives 0.1.0",
|
||||
"node-runtime 0.1.0",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rhododendron 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"srml-system 0.1.0",
|
||||
"substrate-cli 0.3.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-consensus-aura 0.1.0",
|
||||
"substrate-network 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-service 0.3.0",
|
||||
"substrate-service-test 0.3.0",
|
||||
"substrate-transaction-pool 0.1.0",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1661,21 +1644,6 @@ dependencies = [
|
||||
"wabt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "node-network"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"node-consensus 0.1.0",
|
||||
"node-primitives 0.1.0",
|
||||
"rhododendron 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-consensus-rhd 0.1.0",
|
||||
"substrate-network 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "node-primitives"
|
||||
version = "0.1.0"
|
||||
@@ -1683,8 +1651,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
@@ -1701,8 +1669,8 @@ dependencies = [
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-api 0.1.0",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
@@ -1720,6 +1688,7 @@ dependencies = [
|
||||
"srml-system 0.1.0",
|
||||
"srml-timestamp 0.1.0",
|
||||
"srml-treasury 0.1.0",
|
||||
"srml-upgrade-key 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
]
|
||||
@@ -1794,12 +1763,12 @@ dependencies = [
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.13"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1807,12 +1776,12 @@ dependencies = [
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.37"
|
||||
version = "0.9.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1834,21 +1803,13 @@ name = "parity-bytes"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "parity-codec"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parity-codec"
|
||||
version = "2.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2201,20 +2162,10 @@ dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhododendron"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhododendron"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/paritytech/rhododendron.git#64b46b577479a3b6c493fa6db5420a265a445ff9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2357,20 +2308,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2380,7 +2328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2468,7 +2416,7 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2529,8 +2477,8 @@ dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2563,8 +2511,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
]
|
||||
@@ -2576,8 +2524,8 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2594,8 +2542,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2612,8 +2560,8 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2631,8 +2579,8 @@ dependencies = [
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pwasm-utils 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-sandbox 0.1.0",
|
||||
@@ -2652,8 +2600,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2672,8 +2620,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2690,8 +2638,8 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2708,8 +2656,8 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2727,8 +2675,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2747,8 +2695,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2771,8 +2719,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2787,8 +2735,8 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2803,8 +2751,8 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2821,8 +2769,8 @@ dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
@@ -2832,6 +2780,24 @@ dependencies = [
|
||||
"substrate-primitives 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srml-upgrade-key"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
"srml-consensus 0.1.0",
|
||||
"srml-support 0.1.0",
|
||||
"srml-system 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.1.1"
|
||||
@@ -2877,7 +2843,7 @@ dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"node-cli 0.1.0",
|
||||
"vergen 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vergen 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2929,7 +2895,7 @@ dependencies = [
|
||||
"slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-api 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-consensus-rhd 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
@@ -2962,12 +2928,44 @@ dependencies = [
|
||||
"substrate-trie 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-consensus-aura"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-version 0.1.0",
|
||||
"srml-consensus 0.1.0",
|
||||
"srml-support 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-network 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-service 0.3.0",
|
||||
"substrate-test-client 0.1.0",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-consensus-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-version 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2975,21 +2973,25 @@ name = "substrate-consensus-rhd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"exit-future 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rhododendron 0.4.0 (git+https://github.com/paritytech/rhododendron.git)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rhododendron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-version 0.1.0",
|
||||
"srml-consensus 0.1.0",
|
||||
"srml-support 0.1.0",
|
||||
"srml-system 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-transaction-pool 0.1.0",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -3005,8 +3007,8 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-version 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
@@ -3053,8 +3055,8 @@ dependencies = [
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-crypto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-primitives 0.1.0",
|
||||
"subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3067,8 +3069,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3088,6 +3090,7 @@ dependencies = [
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-network-libp2p 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
@@ -3110,8 +3113,8 @@ dependencies = [
|
||||
"parity-bytes 0.1.0 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3137,8 +3140,8 @@ dependencies = [
|
||||
"pretty_assertions 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-std 0.1.0",
|
||||
"substrate-serializer 0.1.0",
|
||||
"twox-hash 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3164,6 +3167,7 @@ dependencies = [
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-version 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-test-client 0.1.0",
|
||||
@@ -3179,7 +3183,7 @@ dependencies = [
|
||||
"jsonrpc-pubsub 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"jsonrpc-ws-server 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-rpc 0.1.0",
|
||||
]
|
||||
@@ -3188,7 +3192,7 @@ dependencies = [
|
||||
name = "substrate-serializer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -3203,14 +3207,15 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-client-db 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keystore 0.1.0",
|
||||
"substrate-network 0.1.0",
|
||||
@@ -3233,6 +3238,7 @@ dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-network 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-service 0.3.0",
|
||||
@@ -3289,6 +3295,7 @@ dependencies = [
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-consensus-common 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
@@ -3303,8 +3310,8 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-api 0.1.0",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
@@ -3324,8 +3331,8 @@ dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 0.1.0",
|
||||
"substrate-test-runtime 0.1.0",
|
||||
]
|
||||
@@ -3391,7 +3398,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.9"
|
||||
version = "0.15.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3916,7 +3923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "2.1.2"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3940,8 +3947,8 @@ name = "wabt"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -4070,7 +4077,7 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4163,7 +4170,7 @@ dependencies = [
|
||||
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
|
||||
"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
|
||||
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
|
||||
"checksum ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50ac3add446ec1f8fe3dc007cd838f5b22bbf33186394feac505451ecc43c018"
|
||||
"checksum ctr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4b669fcb8e20124db86dbd9b01e74ec0e9e420e65381311ce5249864fc7ff0c0"
|
||||
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
|
||||
"checksum datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=8111062f0177fd7423626f2db9560273644a4c4d)" = "<none>"
|
||||
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
||||
@@ -4197,7 +4204,7 @@ dependencies = [
|
||||
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
|
||||
"checksum getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54c7f36a235738bb25904d6a2b3dbb28f6f5736cd3918c4bf80d6bb236200782"
|
||||
"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865"
|
||||
"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"
|
||||
"checksum h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd33bafe2e6370e6c8eb0cf1b8c5f93390b90acde7e9b03723f166b28b648ed"
|
||||
"checksum hash-db 0.9.0 (git+https://github.com/paritytech/trie)" = "<none>"
|
||||
"checksum hash256-std-hasher 0.9.0 (git+https://github.com/paritytech/trie)" = "<none>"
|
||||
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
|
||||
@@ -4208,7 +4215,7 @@ dependencies = [
|
||||
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
|
||||
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
|
||||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
||||
"checksum hyper 0.12.11 (registry+https://github.com/rust-lang/crates.io-index)" = "78d50abbd1790e0f4c74cb1d4a2211b439bac661d54107ad5564c55e77906762"
|
||||
"checksum hyper 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)" = "4aca412c241a2dd53af261efc7adf7736fdebd67dc0d1cc1ffdbcb9407e0e810"
|
||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220"
|
||||
"checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "<none>"
|
||||
@@ -4286,12 +4293,11 @@ dependencies = [
|
||||
"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"
|
||||
"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7"
|
||||
"checksum openssl 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5af9e83eb3c51ee806387d26a43056f3246d865844caa6dd704d2ba7e831c264"
|
||||
"checksum openssl 0.10.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6285ab297861546af7a2753593b3160bfc09f0ab9d1f5bb009e39d81a169b499"
|
||||
"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985"
|
||||
"checksum openssl-sys 0.9.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d4edbc8dfa63f557aee3a498179af2cc6a989e12ba1751840046c79afc9e615a"
|
||||
"checksum openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)" = "278c1ad40a89aa1e741a1eed089a2f60b18fab8089c3139b542140fc7d674106"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5168b4cf41f3835e4bc6ffb32f51bc9365dc50cb351904595b3931d917fd0c"
|
||||
"checksum parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bee4edfcfa19892f7178cb299a659866015dc131459865a1d808269cf7e7eb9e"
|
||||
"checksum parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dca389ea5e1632c89b2ce54f7e2b4a8a8c9d278042222a91e0bf95451218cb4c"
|
||||
"checksum parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa42c2cb493b60b12c75b26e8c94cb734af4df4d7f2cc229dc04c1953dac189"
|
||||
"checksum parity-crypto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1117f6574377d21309bfa1f7d69ff734120685d92b02c3f362b122585758840"
|
||||
@@ -4334,8 +4340,7 @@ dependencies = [
|
||||
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
|
||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum rhododendron 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e20523445e693f394c0e487113ae656071311c9ee4c1e914441bece8c929b21d"
|
||||
"checksum rhododendron 0.4.0 (git+https://github.com/paritytech/rhododendron.git)" = "<none>"
|
||||
"checksum rhododendron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a09bc21b21795c366c8bf0e87afb71175f5f736b3a5b279b6f4e81839d0a877b"
|
||||
"checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c"
|
||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||
@@ -4354,8 +4359,8 @@ dependencies = [
|
||||
"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9"
|
||||
"checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe"
|
||||
"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
|
||||
"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
|
||||
"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce"
|
||||
"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"
|
||||
@@ -4380,7 +4385,7 @@ dependencies = [
|
||||
"checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb"
|
||||
"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
"checksum syn 0.15.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b10ee269228fb723234fce98e9aac0eaed2bd5f1ad2f6930e8d5b93f04445a1a"
|
||||
"checksum syn 0.15.12 (registry+https://github.com/rust-lang/crates.io-index)" = "34ab9797e47d24cb76b8dc4d24ff36807018c7cc549c4cba050b068be0c586b0"
|
||||
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
|
||||
"checksum sysinfo 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "11c5f6e8a7a7146f26ffed9a5ff8bab2706f1ac8a413a415e1d211b819d5c24d"
|
||||
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
||||
@@ -4437,7 +4442,7 @@ dependencies = [
|
||||
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
|
||||
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum vergen 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4cae5a72131fdf47d4fbc9286393ec8622ec7a5502fbe77b291d9aba21d3f179"
|
||||
"checksum vergen 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "93fb2d57fbc535fcd45548c99b141d2d960995daaf04b864c4d9fe1ea011c819"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum wabt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "182ae543249ccf2705f324d233891c1176fca142e137b55ba43d9dbfe93f18a2"
|
||||
|
||||
@@ -23,6 +23,7 @@ members = [
|
||||
"core/client",
|
||||
"core/client/db",
|
||||
"core/consensus/common",
|
||||
"core/consensus/aura",
|
||||
"core/consensus/rhd",
|
||||
"core/executor",
|
||||
"core/finality-grandpa",
|
||||
@@ -54,6 +55,7 @@ members = [
|
||||
"srml/system",
|
||||
"srml/timestamp",
|
||||
"srml/treasury",
|
||||
"srml/upgrade-key",
|
||||
"core/serializer",
|
||||
"core/service",
|
||||
"core/service/test",
|
||||
@@ -64,9 +66,7 @@ members = [
|
||||
"core/trie",
|
||||
"core/keystore",
|
||||
"node/cli",
|
||||
"node/consensus",
|
||||
"node/executor",
|
||||
"node/network",
|
||||
"node/primitives",
|
||||
"node/runtime",
|
||||
"subkey",
|
||||
|
||||
+106
-5
@@ -221,11 +221,112 @@ cargo run
|
||||
|
||||
include::doc/packages/packages.adoc[]
|
||||
|
||||
include::CONTRIBUTING.adoc[leveloffset=+1]
|
||||
== Documentation
|
||||
|
||||
include::CODE_OF_CONDUCT.adoc[leveloffset=+1]
|
||||
=== Viewing documentation for Substrate packages
|
||||
|
||||
You can generate documentation for a Substrate Rust package and have it automatically open in your web browser using https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html#using-rustdoc-with-cargo[rustdoc with Cargo],
|
||||
(of the The Rustdoc Book), by running the the following command:
|
||||
|
||||
```
|
||||
cargo doc --package <spec> --open
|
||||
```
|
||||
|
||||
Replacing `<spec>` with one of the following (i.e. `cargo doc --package node-cli --open`):
|
||||
|
||||
* Substrate Core
|
||||
[source, shell]
|
||||
substrate, substrate-bft, substrate-cli, substrate-client, substrate-client-db,
|
||||
substrate-executor, substrate-finality-grandpa, substrate-keyring, substrate-keystore,
|
||||
substrate-metadata, substrate-misbehavior-check, substrate-network,
|
||||
substrate-network-libp2p, substrate-primitives, substrate-rpc, substrate-rpc-servers,
|
||||
substrate-serializer, substrate-service, substrate-service-test, substrate-state-db,
|
||||
substrate-state-machine, substrate-telemetry, substrate-test-client,
|
||||
substrate-test-runtime, substrate-transaction-graph, substrate-transaction-pool,
|
||||
substrate-trie
|
||||
* Substrate Runtime
|
||||
[source, shell]
|
||||
sr-api, sr-io, sr-primitives, sr-sandbox, sr-std, sr-version
|
||||
* Substrate Runtime Module Library (SRML)
|
||||
[source, shell]
|
||||
srml-balances, srml-consensus, srml-contract, srml-council, srml-democracy, srml-example,
|
||||
srml-executive, srml-session, srml-staking, srml-support, srml-system, srml-timestamp,
|
||||
srml-treasury
|
||||
* Node
|
||||
[source, shell]
|
||||
node-cli, node-consensus, node-executor, node-network, node-primitives, node-runtime, node-service
|
||||
* Subkey
|
||||
[source, shell]
|
||||
subkey
|
||||
|
||||
|
||||
=== Contributing to documentation for Substrate packages
|
||||
|
||||
https://doc.rust-lang.org/1.9.0/book/documentation.html[Document source code] for Substrate packages by annotating the source code with documentation comments.
|
||||
|
||||
Example (generic):
|
||||
```markdown
|
||||
/// Summary
|
||||
///
|
||||
/// Description
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Summary of Example 1
|
||||
///
|
||||
/// ```rust
|
||||
/// // insert example 1 code here
|
||||
/// ```
|
||||
///
|
||||
```
|
||||
|
||||
* Important notes:
|
||||
** Documentation comments must use annotations with a triple slash `///`
|
||||
** Modules are documented using `//!`
|
||||
```
|
||||
//! Summary (of module)
|
||||
//!
|
||||
//! Description (of module)
|
||||
```
|
||||
* Special section header is indicated with a hash `#`.
|
||||
** `Panics` section requires an explanation if the function triggers a panic
|
||||
** `Errors` section is for describing conditions under which a function of method returns `Err(E)` if it returns a `Result<T, E>`
|
||||
** `Safety` section requires an explanation if the function is `unsafe`
|
||||
** `Examples` section includes examples of using the function or method
|
||||
* Code block annotations for examples are included between triple graves, as shown above.
|
||||
Instead of including the programming language to use for syntax highlighting as the annotation
|
||||
after the triple graves, alternative annotations include the `ignore`, `text`, `should_panic`, or `no_run`.
|
||||
* Summary sentence is a short high level sinngle sentence of its functionality
|
||||
* Description paragraph is for details additional to the summary sentence
|
||||
* Missing documentation annotations may be used to identify where to generate warnings with `#![warn(missing_docs)]`
|
||||
or errors `#![deny(missing_docs)]`
|
||||
* Hide documentation for items with `#[doc(hidden)]`
|
||||
|
||||
=== Contributing to documentation (tests, extended examples, macros) for Substrate packages
|
||||
|
||||
The code block annotations in the `# Example` section may be used as https://doc.rust-lang.org/1.9.0/book/documentation.html#documentation-as-tests[documentation as tests and for extended examples].
|
||||
|
||||
* Important notes:
|
||||
** Rustdoc will automatically add a `main()` wrapper around the code block to test it
|
||||
** https://doc.rust-lang.org/1.9.0/book/documentation.html#documenting-macros[Documentating macros].
|
||||
** Documentation as tests examples are included when running `cargo test`
|
||||
|
||||
== Contributing
|
||||
|
||||
=== Contributing Guidelines
|
||||
|
||||
include::CONTRIBUTING.adoc[]
|
||||
|
||||
=== Contributor Code of Conduct
|
||||
|
||||
include::CODE_OF_CONDUCT.adoc[]
|
||||
|
||||
== License
|
||||
----
|
||||
include::LICENSE[]
|
||||
----
|
||||
|
||||
https://github.com/paritytech/substrate/blob/master/LICENSE[LICENSE]
|
||||
|
||||
@@ -12,7 +12,7 @@ hex-literal = "0.1"
|
||||
futures = "0.1.17"
|
||||
slog = "^2"
|
||||
heapsize = "0.4"
|
||||
substrate-consensus-rhd = { path = "../consensus/rhd" }
|
||||
substrate-consensus-common = { path = "../consensus/common" }
|
||||
parity-codec = "2.1"
|
||||
substrate-executor = { path = "../executor" }
|
||||
substrate-primitives = { path = "../primitives" }
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
|
||||
= transaction-pool
|
||||
= Client DB
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
@@ -534,7 +534,9 @@ impl<Block: BlockT> Backend<Block> {
|
||||
meta.finalized_hash, f_hash),
|
||||
).into())
|
||||
}
|
||||
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, f_hash.as_ref());
|
||||
|
||||
let lookup_key = ::utils::number_to_lookup_key(f_num);
|
||||
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, &lookup_key);
|
||||
|
||||
let commit = self.storage.state_db.canonicalize_block(&f_hash);
|
||||
apply_state_commit(transaction, commit);
|
||||
@@ -586,11 +588,20 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
|
||||
-> Result<(), client::error::Error>
|
||||
{
|
||||
let mut transaction = DBTransaction::new();
|
||||
|
||||
if let Some(pending_block) = operation.pending_block {
|
||||
let hash = pending_block.header.hash();
|
||||
let parent_hash = *pending_block.header.parent_hash();
|
||||
let number = pending_block.header.number().clone();
|
||||
|
||||
// blocks in longest chain are keyed by number
|
||||
let lookup_key = if pending_block.leaf_state.is_best() {
|
||||
::utils::number_to_lookup_key(number).to_vec()
|
||||
} else {
|
||||
// other blocks are keyed by number + hash
|
||||
::utils::number_and_hash_to_lookup_key(number, hash)
|
||||
};
|
||||
|
||||
if pending_block.leaf_state.is_best() {
|
||||
let meta = self.blockchain.meta.read();
|
||||
|
||||
@@ -678,17 +689,9 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
|
||||
}
|
||||
}
|
||||
|
||||
transaction.put(columns::META, meta_keys::BEST_BLOCK, hash.as_ref());
|
||||
transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
|
||||
}
|
||||
|
||||
// blocks in longest chain are keyed by number
|
||||
let lookup_key = if pending_block.leaf_state.is_best() {
|
||||
::utils::number_to_lookup_key(number).to_vec()
|
||||
} else {
|
||||
// other blocks are keyed by number + hash
|
||||
::utils::number_and_hash_to_lookup_key(number, hash)
|
||||
};
|
||||
|
||||
transaction.put(columns::HEADER, &lookup_key, &pending_block.header.encode());
|
||||
if let Some(body) = pending_block.body {
|
||||
transaction.put(columns::BODY, &lookup_key, &body.encode());
|
||||
@@ -700,7 +703,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
|
||||
transaction.put(columns::HASH_LOOKUP, hash.as_ref(), &lookup_key);
|
||||
|
||||
if number == Zero::zero() {
|
||||
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, hash.as_ref());
|
||||
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, &lookup_key);
|
||||
transaction.put(columns::META, meta_keys::GENESIS_HASH, hash.as_ref());
|
||||
}
|
||||
|
||||
@@ -797,7 +800,8 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
|
||||
|| client::error::ErrorKind::UnknownBlock(
|
||||
format!("Error reverting to {}. Block header not found.", best)))?;
|
||||
|
||||
transaction.put(columns::META, meta_keys::BEST_BLOCK, header.hash().as_ref());
|
||||
let lookup_key = ::utils::number_to_lookup_key(header.number().clone());
|
||||
transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
|
||||
transaction.delete(columns::HASH_LOOKUP, header.hash().as_ref());
|
||||
self.storage.db.write(transaction).map_err(db_err)?;
|
||||
self.blockchain.update_meta(header.hash().clone(), best.clone(), true, false);
|
||||
@@ -927,40 +931,49 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn block_hash_inserted_correctly() {
|
||||
let db = Backend::<Block>::new_test(1, 0);
|
||||
for i in 0..10 {
|
||||
assert!(db.blockchain().hash(i).unwrap().is_none());
|
||||
let backing = {
|
||||
let db = Backend::<Block>::new_test(1, 0);
|
||||
for i in 0..10 {
|
||||
assert!(db.blockchain().hash(i).unwrap().is_none());
|
||||
|
||||
{
|
||||
let id = if i == 0 {
|
||||
BlockId::Hash(Default::default())
|
||||
} else {
|
||||
BlockId::Number(i - 1)
|
||||
};
|
||||
|
||||
let mut op = db.begin_operation(id).unwrap();
|
||||
let header = Header {
|
||||
number: i,
|
||||
parent_hash: if i == 0 {
|
||||
Default::default()
|
||||
{
|
||||
let id = if i == 0 {
|
||||
BlockId::Hash(Default::default())
|
||||
} else {
|
||||
db.blockchain.hash(i - 1).unwrap().unwrap()
|
||||
},
|
||||
state_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
extrinsics_root: Default::default(),
|
||||
};
|
||||
BlockId::Number(i - 1)
|
||||
};
|
||||
|
||||
op.set_block_data(
|
||||
header,
|
||||
Some(vec![]),
|
||||
None,
|
||||
NewBlockState::Best,
|
||||
).unwrap();
|
||||
db.commit_operation(op).unwrap();
|
||||
let mut op = db.begin_operation(id).unwrap();
|
||||
let header = Header {
|
||||
number: i,
|
||||
parent_hash: if i == 0 {
|
||||
Default::default()
|
||||
} else {
|
||||
db.blockchain.hash(i - 1).unwrap().unwrap()
|
||||
},
|
||||
state_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
extrinsics_root: Default::default(),
|
||||
};
|
||||
|
||||
op.set_block_data(
|
||||
header,
|
||||
Some(vec![]),
|
||||
None,
|
||||
NewBlockState::Best,
|
||||
).unwrap();
|
||||
db.commit_operation(op).unwrap();
|
||||
}
|
||||
|
||||
assert!(db.blockchain().hash(i).unwrap().is_some())
|
||||
}
|
||||
db.storage.db.clone()
|
||||
};
|
||||
|
||||
assert!(db.blockchain().hash(i).unwrap().is_some())
|
||||
let backend = Backend::<Block>::from_kvdb(backing, PruningMode::keep_blocks(1), 0).unwrap();
|
||||
assert_eq!(backend.blockchain().info().unwrap().best_number, 9);
|
||||
for i in 0..10 {
|
||||
assert!(backend.blockchain().hash(i).unwrap().is_some())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,8 @@ impl<Block: BlockT> LightStorage<Block> {
|
||||
).into())
|
||||
}
|
||||
|
||||
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, hash.as_ref());
|
||||
let lookup_key = ::utils::number_to_lookup_key(header.number().clone());
|
||||
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, &lookup_key);
|
||||
|
||||
// build new CHT if required
|
||||
if let Some(new_cht_number) = cht::is_build_required(cht::SIZE, *header.number()) {
|
||||
@@ -244,6 +245,14 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
|
||||
let number = *header.number();
|
||||
let parent_hash = *header.parent_hash();
|
||||
|
||||
// blocks in longest chain are keyed by number
|
||||
let lookup_key = if leaf_state.is_best() {
|
||||
::utils::number_to_lookup_key(number).to_vec()
|
||||
} else {
|
||||
// other blocks are keyed by number + hash
|
||||
::utils::number_and_hash_to_lookup_key(number, hash)
|
||||
};
|
||||
|
||||
if leaf_state.is_best() {
|
||||
// handle reorg.
|
||||
{
|
||||
@@ -298,17 +307,9 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
|
||||
}
|
||||
}
|
||||
|
||||
transaction.put(columns::META, meta_keys::BEST_BLOCK, hash.as_ref());
|
||||
transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
|
||||
}
|
||||
|
||||
// blocks in longest chain are keyed by number
|
||||
let lookup_key = if leaf_state.is_best() {
|
||||
::utils::number_to_lookup_key(number).to_vec()
|
||||
} else {
|
||||
// other blocks are keyed by number + hash
|
||||
::utils::number_and_hash_to_lookup_key(number, hash)
|
||||
};
|
||||
|
||||
transaction.put(columns::HEADER, &lookup_key, &header.encode());
|
||||
transaction.put(columns::HASH_LOOKUP, hash.as_ref(), &lookup_key);
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ pub mod meta_keys {
|
||||
}
|
||||
|
||||
/// Database metadata.
|
||||
#[derive(Debug)]
|
||||
pub struct Meta<N, H> {
|
||||
/// Hash of the best known block.
|
||||
pub best_hash: H,
|
||||
|
||||
@@ -150,7 +150,7 @@ where
|
||||
let heap_pages = state.storage(well_known_keys::HEAP_PAGES)
|
||||
.map_err(|e| error::ErrorKind::Execution(Box::new(e)))?
|
||||
.and_then(|v| u64::decode(&mut &v[..]))
|
||||
.unwrap_or(8) as usize;
|
||||
.unwrap_or(1024) as usize;
|
||||
|
||||
let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage());
|
||||
self.executor.runtime_version(&mut ext, heap_pages, &code)
|
||||
|
||||
+127
-186
@@ -26,6 +26,7 @@ use runtime_primitives::{
|
||||
generic::{BlockId, SignedBlock, Block as RuntimeBlock},
|
||||
transaction_validity::{TransactionValidity, TransactionTag},
|
||||
};
|
||||
use consensus::{ImportBlock, ImportResult, BlockOrigin};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash};
|
||||
use runtime_primitives::{ApplyResult, BuildStorage};
|
||||
use runtime_api as api;
|
||||
@@ -44,7 +45,7 @@ use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend
|
||||
use call_executor::{CallExecutor, LocalCallExecutor};
|
||||
use executor::{RuntimeVersion, RuntimeInfo};
|
||||
use notifications::{StorageNotifications, StorageEventStream};
|
||||
use {cht, error, in_mem, block_builder, genesis};
|
||||
use {cht, error, in_mem, block_builder, genesis, consensus};
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotification<Block>>;
|
||||
@@ -106,21 +107,6 @@ pub struct ClientInfo<Block: BlockT> {
|
||||
pub best_queued_hash: Option<Block::Hash>,
|
||||
}
|
||||
|
||||
/// Block import result.
|
||||
#[derive(Debug)]
|
||||
pub enum ImportResult {
|
||||
/// Added to the import queue.
|
||||
Queued,
|
||||
/// Already in the import queue.
|
||||
AlreadyQueued,
|
||||
/// Already in the blockchain.
|
||||
AlreadyInChain,
|
||||
/// Block or parent is known to be bad.
|
||||
KnownBad,
|
||||
/// Block parent is not in the chain.
|
||||
UnknownParent,
|
||||
}
|
||||
|
||||
/// Block status.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum BlockStatus {
|
||||
@@ -134,70 +120,6 @@ pub enum BlockStatus {
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Block data origin.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BlockOrigin {
|
||||
/// Genesis block built into the client.
|
||||
Genesis,
|
||||
/// Block is part of the initial sync with the network.
|
||||
NetworkInitialSync,
|
||||
/// Block was broadcasted on the network.
|
||||
NetworkBroadcast,
|
||||
/// Block that was received from the network and validated in the consensus process.
|
||||
ConsensusBroadcast,
|
||||
/// Block that was collated by this node.
|
||||
Own,
|
||||
/// Block was imported from a file.
|
||||
File,
|
||||
}
|
||||
|
||||
/// Data required to import a Block
|
||||
pub struct ImportBlock<Block: BlockT> {
|
||||
/// Origin of the Block
|
||||
pub origin: BlockOrigin,
|
||||
/// Header
|
||||
pub header: Block::Header,
|
||||
/// Justification provided for this block from the outside
|
||||
pub external_justification: Justification,
|
||||
/// Internal Justification for the block
|
||||
pub internal_justification: Vec<u8>, // Block::Digest::DigestItem?
|
||||
/// Block's body
|
||||
pub body: Option<Vec<Block::Extrinsic>>,
|
||||
/// Is this block finalized already?
|
||||
/// `true` implies instant finality.
|
||||
pub finalized: bool,
|
||||
/// Auxiliary consensus data produced by the block.
|
||||
/// Contains a list of key-value pairs. If values are `None`, the keys
|
||||
/// will be deleted.
|
||||
pub auxiliary: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> ImportBlock<Block> {
|
||||
/// Deconstruct the justified header into parts.
|
||||
pub fn into_inner(self)
|
||||
-> (
|
||||
BlockOrigin,
|
||||
<Block as BlockT>::Header,
|
||||
Justification,
|
||||
Justification,
|
||||
Option<Vec<<Block as BlockT>::Extrinsic>>,
|
||||
bool,
|
||||
Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
) {
|
||||
(
|
||||
self.origin,
|
||||
self.header,
|
||||
self.external_justification,
|
||||
self.internal_justification,
|
||||
self.body,
|
||||
self.finalized,
|
||||
self.auxiliary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Summary of an imported block
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BlockImportNotification<Block: BlockT> {
|
||||
@@ -222,6 +144,41 @@ pub struct FinalityNotification<Block: BlockT> {
|
||||
pub header: Block::Header,
|
||||
}
|
||||
|
||||
// used in importing a block, where additional changes are made after the runtime
|
||||
// executed.
|
||||
enum PrePostHeader<H> {
|
||||
// they are the same: no post-runtime digest items.
|
||||
Same(H),
|
||||
// different headers (pre, post).
|
||||
Different(H, H),
|
||||
}
|
||||
|
||||
impl<H> PrePostHeader<H> {
|
||||
// get a reference to the "pre-header" -- the header as it should be just after the runtime.
|
||||
fn pre(&self) -> &H {
|
||||
match *self {
|
||||
PrePostHeader::Same(ref h) => h,
|
||||
PrePostHeader::Different(ref h, _) => h,
|
||||
}
|
||||
}
|
||||
|
||||
// get a reference to the "post-header" -- the header as it should be after all changes are applied.
|
||||
fn post(&self) -> &H {
|
||||
match *self {
|
||||
PrePostHeader::Same(ref h) => h,
|
||||
PrePostHeader::Different(_, ref h) => h,
|
||||
}
|
||||
}
|
||||
|
||||
// convert to the "post-header" -- the header as it should be after all changes are applied.
|
||||
fn into_post(self) -> H {
|
||||
match self {
|
||||
PrePostHeader::Same(h) => h,
|
||||
PrePostHeader::Different(_, h) => h,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an instance of in-memory client.
|
||||
pub fn new_in_mem<E, Block, S>(
|
||||
executor: E,
|
||||
@@ -346,11 +303,6 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
&self.executor
|
||||
}
|
||||
|
||||
/// Returns the runtime metadata.
|
||||
pub fn metadata(&self, id: &BlockId<Block>) -> error::Result<Vec<u8>> {
|
||||
self.executor.call(id, "metadata",&[]).map(|v| v.return_data)
|
||||
}
|
||||
|
||||
/// Reads storage value at a given block + key, returning read proof.
|
||||
pub fn read_proof(&self, id: &BlockId<Block>, key: &[u8]) -> error::Result<Vec<Vec<u8>>> {
|
||||
self.state_at(id)
|
||||
@@ -518,52 +470,6 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
)
|
||||
}
|
||||
|
||||
/// Import a checked and validated block
|
||||
pub fn import_block(
|
||||
&self,
|
||||
import_block: ImportBlock<Block>,
|
||||
new_authorities: Option<Vec<AuthorityId>>,
|
||||
) -> error::Result<ImportResult> {
|
||||
|
||||
let (
|
||||
origin,
|
||||
header,
|
||||
_,
|
||||
justification,
|
||||
body,
|
||||
finalized,
|
||||
_aux, // TODO: write this to DB also
|
||||
) = import_block.into_inner();
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
|
||||
match self.backend.blockchain().status(BlockId::Hash(parent_hash))? {
|
||||
blockchain::BlockStatus::InChain => {},
|
||||
blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
|
||||
}
|
||||
let hash = header.hash();
|
||||
let _import_lock = self.import_lock.lock();
|
||||
let height: u64 = header.number().as_();
|
||||
*self.importing_block.write() = Some(hash);
|
||||
|
||||
let result = self.execute_and_import_block(
|
||||
origin,
|
||||
hash,
|
||||
header,
|
||||
justification,
|
||||
body,
|
||||
new_authorities,
|
||||
finalized,
|
||||
);
|
||||
|
||||
*self.importing_block.write() = None;
|
||||
telemetry!("block.import";
|
||||
"height" => height,
|
||||
"best" => ?hash,
|
||||
"origin" => ?origin
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
// TODO [ToDr] Optimize and re-use tags from the pool.
|
||||
fn transaction_tags(&self, at: Block::Hash, body: &Option<Vec<Block::Extrinsic>>) -> error::Result<Vec<TransactionTag>> {
|
||||
let id = BlockId::Hash(at);
|
||||
@@ -592,13 +498,13 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
&self,
|
||||
origin: BlockOrigin,
|
||||
hash: Block::Hash,
|
||||
header: Block::Header,
|
||||
import_headers: PrePostHeader<Block::Header>,
|
||||
justification: Justification,
|
||||
body: Option<Vec<Block::Extrinsic>>,
|
||||
authorities: Option<Vec<AuthorityId>>,
|
||||
finalized: bool,
|
||||
) -> error::Result<ImportResult> {
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
let parent_hash = import_headers.post().parent_hash().clone();
|
||||
match self.backend.blockchain().status(BlockId::Hash(hash))? {
|
||||
blockchain::BlockStatus::InChain => return Ok(ImportResult::AlreadyInChain),
|
||||
blockchain::BlockStatus::Unknown => {},
|
||||
@@ -632,12 +538,13 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
transaction_state,
|
||||
&mut overlay,
|
||||
"execute_block",
|
||||
&<Block as BlockT>::new(header.clone(), body.clone().unwrap_or_default()).encode(),
|
||||
&<Block as BlockT>::new(import_headers.pre().clone(), body.clone().unwrap_or_default()).encode(),
|
||||
match (origin, self.block_execution_strategy) {
|
||||
(BlockOrigin::NetworkInitialSync, _) | (_, ExecutionStrategy::NativeWhenPossible) =>
|
||||
ExecutionManager::NativeWhenPossible,
|
||||
(_, ExecutionStrategy::AlwaysWasm) => ExecutionManager::AlwaysWasm,
|
||||
_ => ExecutionManager::Both(|wasm_result, native_result| {
|
||||
let header = import_headers.post();
|
||||
warn!("Consensus error between wasm and native block execution at block {}", hash);
|
||||
warn!(" Header {:?}", header);
|
||||
warn!(" Native result {:?}", native_result);
|
||||
@@ -659,7 +566,7 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
};
|
||||
|
||||
// TODO: non longest-chain rule.
|
||||
let is_new_best = finalized || header.number() > &last_best_number;
|
||||
let is_new_best = finalized || import_headers.post().number() > &last_best_number;
|
||||
let leaf_state = if finalized {
|
||||
::backend::NewBlockState::Final
|
||||
} else if is_new_best {
|
||||
@@ -668,10 +575,10 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
::backend::NewBlockState::Normal
|
||||
};
|
||||
|
||||
trace!("Imported {}, (#{}), best={}, origin={:?}", hash, header.number(), is_new_best, origin);
|
||||
trace!("Imported {}, (#{}), best={}, origin={:?}", hash, import_headers.post().number(), is_new_best, origin);
|
||||
|
||||
transaction.set_block_data(
|
||||
header.clone(),
|
||||
import_headers.post().clone(),
|
||||
body,
|
||||
Some(justification),
|
||||
leaf_state,
|
||||
@@ -698,7 +605,7 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
if finalized {
|
||||
let notification = FinalityNotification::<Block> {
|
||||
hash,
|
||||
header: header.clone(),
|
||||
header: import_headers.post().clone(),
|
||||
};
|
||||
|
||||
self.finality_notification_sinks.lock()
|
||||
@@ -708,7 +615,7 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
let notification = BlockImportNotification::<Block> {
|
||||
hash,
|
||||
origin,
|
||||
header,
|
||||
header: import_headers.into_post(),
|
||||
is_new_best,
|
||||
tags,
|
||||
};
|
||||
@@ -986,6 +893,84 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<B, E, Block> consensus::BlockImport<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
/// Import a checked and validated block
|
||||
fn import_block(
|
||||
&self,
|
||||
import_block: ImportBlock<Block>,
|
||||
new_authorities: Option<Vec<AuthorityId>>,
|
||||
) -> Result<ImportResult, Self::Error> {
|
||||
use runtime_primitives::traits::Digest;
|
||||
|
||||
let ImportBlock {
|
||||
origin,
|
||||
header,
|
||||
external_justification,
|
||||
post_runtime_digests,
|
||||
body,
|
||||
finalized,
|
||||
..
|
||||
} = import_block;
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
|
||||
match self.backend.blockchain().status(BlockId::Hash(parent_hash))? {
|
||||
blockchain::BlockStatus::InChain => {},
|
||||
blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
|
||||
}
|
||||
|
||||
let import_headers = if post_runtime_digests.is_empty() {
|
||||
PrePostHeader::Same(header)
|
||||
} else {
|
||||
let mut post_header = header.clone();
|
||||
for item in post_runtime_digests {
|
||||
post_header.digest_mut().push(item);
|
||||
}
|
||||
PrePostHeader::Different(header, post_header)
|
||||
};
|
||||
|
||||
let hash = import_headers.post().hash();
|
||||
let _import_lock = self.import_lock.lock();
|
||||
let height: u64 = import_headers.post().number().as_();
|
||||
*self.importing_block.write() = Some(hash);
|
||||
|
||||
let result = self.execute_and_import_block(
|
||||
origin,
|
||||
hash,
|
||||
import_headers,
|
||||
external_justification,
|
||||
body,
|
||||
new_authorities,
|
||||
finalized,
|
||||
);
|
||||
|
||||
*self.importing_block.write() = None;
|
||||
telemetry!("block.import";
|
||||
"height" => height,
|
||||
"best" => ?hash,
|
||||
"origin" => ?origin
|
||||
);
|
||||
result.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> consensus::Authorities<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
Block: BlockT,
|
||||
{
|
||||
type Error = Error;
|
||||
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, Self::Error> {
|
||||
self.authorities_at(at).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> CurrentHeight for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Clone,
|
||||
@@ -1076,7 +1061,7 @@ impl<B, E, Block> api::Core<Block, AuthorityId> for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::Metadata<Block> for Client<B, E, Block> where
|
||||
impl<B, E, Block> api::Metadata<Block, Vec<u8>> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT,
|
||||
@@ -1084,7 +1069,7 @@ impl<B, E, Block> api::Metadata<Block> for Client<B, E, Block> where
|
||||
type Error = Error;
|
||||
|
||||
fn metadata(&self, at: &BlockId<Block>) -> Result<Vec<u8>, Self::Error> {
|
||||
self.call_api_at(at, "metadata", &())
|
||||
self.executor.call(at, "metadata",&[]).map(|v| v.return_data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,26 +1127,6 @@ impl<B, E, Block> api::BlockBuilder<Block> for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::OldTxQueue<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn account_nonce<AccountId: Encode + Decode, Index: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>, account: &AccountId
|
||||
) -> Result<Index, Self::Error> {
|
||||
self.call_api_at(at, "account_nonce", &(account))
|
||||
}
|
||||
|
||||
fn lookup_address<Address: Encode + Decode, AccountId: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>, address: &Address
|
||||
) -> Result<Option<AccountId>, Self::Error> {
|
||||
self.call_api_at(at, "lookup_address", &(address))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::TaggedTransactionQueue<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
@@ -1176,30 +1141,6 @@ impl<B, E, Block> api::TaggedTransactionQueue<Block> for Client<B, E, Block> whe
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> api::Miscellaneous<Block> for Client<B, E, Block> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn validator_count(&self, at: &BlockId<Block>) -> Result<u32, Self::Error> {
|
||||
self.call_api_at(at, "validator_count", &())
|
||||
}
|
||||
|
||||
fn validators<AccountId: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>
|
||||
) -> Result<Vec<AccountId>, Self::Error> {
|
||||
self.call_api_at(at, "validators", &())
|
||||
}
|
||||
|
||||
fn timestamp<Moment: Encode + Decode>(
|
||||
&self, at: &BlockId<Block>
|
||||
) -> Result<Moment, Self::Error> {
|
||||
self.call_api_at(at, "timestamp", &())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::collections::HashMap;
|
||||
@@ -1209,7 +1150,7 @@ pub(crate) mod tests {
|
||||
use runtime_primitives::traits::{Digest as DigestT, DigestItem as DigestItemT};
|
||||
use runtime_primitives::generic::DigestItem;
|
||||
use test_client::{self, TestClient};
|
||||
use test_client::client::BlockOrigin;
|
||||
use consensus::BlockOrigin;
|
||||
use test_client::client::backend::Backend as TestBackend;
|
||||
use test_client::BlockBuilderExt;
|
||||
use test_client::runtime::{self, Block, Transfer};
|
||||
|
||||
@@ -16,11 +16,17 @@
|
||||
|
||||
//! Substrate client possible errors.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std;
|
||||
use state_machine;
|
||||
use runtime_primitives::ApplyError;
|
||||
use consensus;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
Consensus(consensus::Error, consensus::ErrorKind);
|
||||
}
|
||||
errors {
|
||||
/// Backend error.
|
||||
Backend(s: String) {
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Substrate Client and associated logic.
|
||||
// end::description[]
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![recursion_limit="128"]
|
||||
@@ -24,6 +26,7 @@ extern crate parity_codec as codec;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate substrate_state_machine as state_machine;
|
||||
extern crate substrate_consensus_common as consensus;
|
||||
#[cfg(test)] extern crate substrate_keyring as keyring;
|
||||
#[cfg(test)] extern crate substrate_test_client as test_client;
|
||||
#[macro_use] extern crate substrate_telemetry;
|
||||
@@ -61,8 +64,8 @@ pub use call_executor::{CallResult, CallExecutor, LocalCallExecutor};
|
||||
pub use client::{
|
||||
new_with_backend,
|
||||
new_in_mem,
|
||||
BlockBody, BlockStatus, BlockOrigin, ImportNotifications, FinalityNotifications, BlockchainEvents,
|
||||
Client, ClientInfo, ChainHead, ImportResult, ImportBlock,
|
||||
BlockBody, BlockStatus, ImportNotifications, FinalityNotifications, BlockchainEvents,
|
||||
Client, ClientInfo, ChainHead,
|
||||
};
|
||||
pub use notifications::{StorageEventStream, StorageChangeSet};
|
||||
pub use state_machine::ExecutionStrategy;
|
||||
|
||||
@@ -270,7 +270,8 @@ pub mod tests {
|
||||
use error::Error as ClientError;
|
||||
use test_client::{self, TestClient};
|
||||
use test_client::runtime::{self, Hash, Block, Header};
|
||||
use test_client::client::BlockOrigin;
|
||||
use consensus::BlockOrigin;
|
||||
|
||||
use in_mem::{Blockchain as InMemoryBlockchain};
|
||||
use light::fetcher::{Fetcher, FetchChecker, LightDataChecker,
|
||||
RemoteCallRequest, RemoteHeaderRequest};
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
[package]
|
||||
name = "substrate-consensus-aura"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Rhododendron Round-Based consensus-algorithm for substrate"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1.17"
|
||||
parity-codec = { version = "2.1" }
|
||||
substrate-consensus-common = { path = "../common" }
|
||||
substrate-client = { path = "../../client" }
|
||||
substrate-primitives = { path = "../../primitives" }
|
||||
substrate-network = { path = "../../network" }
|
||||
srml-support = { path = "../../../srml/support" }
|
||||
sr-primitives = { path = "../../sr-primitives" }
|
||||
sr-version = { path = "../../sr-version" }
|
||||
sr-io = { path = "../../sr-io" }
|
||||
srml-consensus = { path = "../../../srml/consensus" }
|
||||
tokio = "0.1.7"
|
||||
parking_lot = "0.4"
|
||||
error-chain = "0.12"
|
||||
log = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-keyring = { path = "../../keyring" }
|
||||
substrate-executor = { path = "../../executor" }
|
||||
substrate-service = { path = "../../service" }
|
||||
substrate-test-client = { path = "../../test-client" }
|
||||
env_logger = { version = "0.4" }
|
||||
|
||||
[target.'cfg(test)'.dependencies]
|
||||
substrate-network = { path = "../../network", features = ["test-helpers"] }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"substrate-primitives/std",
|
||||
"srml-support/std",
|
||||
"sr-primitives/std",
|
||||
"sr-version/std",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,560 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Aura (Authority-round) consensus in substrate.
|
||||
//!
|
||||
//! Aura works by having a list of authorities A who are expected to roughly
|
||||
//! agree on the current time. Time is divided up into discrete slots of t
|
||||
//! seconds each. For each slot s, the author of that slot is A[s % |A|].
|
||||
//!
|
||||
//! The author is allowed to issue one block but not more during that slot,
|
||||
//! and it will be built upon the longest valid chain that has been seen.
|
||||
//!
|
||||
//! Blocks from future steps will be either deferred or rejected depending on how
|
||||
//! far in the future they are.
|
||||
|
||||
extern crate parity_codec as codec;
|
||||
extern crate substrate_consensus_common as consensus_common;
|
||||
extern crate substrate_client as client;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate substrate_network as network;
|
||||
extern crate srml_support as runtime_support;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate sr_version as runtime_version;
|
||||
extern crate sr_io as runtime_io;
|
||||
extern crate tokio;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate substrate_keyring as keyring;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_service as service;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_test_client as test_client;
|
||||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
|
||||
extern crate parking_lot;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate futures;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use codec::Encode;
|
||||
use consensus_common::{Authorities, BlockImport, Environment, Proposer};
|
||||
use client::ChainHead;
|
||||
use consensus_common::{ImportBlock, BlockOrigin};
|
||||
use runtime_primitives::{generic, generic::BlockId};
|
||||
use runtime_primitives::traits::{Block, Header, Digest, DigestItemFor};
|
||||
use network::import_queue::{Verifier, BasicQueue};
|
||||
use primitives::{AuthorityId, ed25519};
|
||||
|
||||
use futures::{Stream, Future, IntoFuture, future::{self, Either}};
|
||||
use tokio::timer::Interval;
|
||||
|
||||
pub use consensus_common::SyncOracle;
|
||||
|
||||
/// A handle to the network. This is generally implemented by providing some
|
||||
/// handle to a gossip service or similar.
|
||||
///
|
||||
/// Intended to be a lightweight handle such as an `Arc`.
|
||||
pub trait Network: Clone {
|
||||
/// A stream of input messages for a topic.
|
||||
type In: Stream<Item=Vec<u8>,Error=()>;
|
||||
|
||||
/// Send a message at a specific round out.
|
||||
fn send_message(&self, slot: u64, message: Vec<u8>);
|
||||
}
|
||||
|
||||
/// Configuration for Aura consensus.
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
/// The local authority keypair. Can be none if this is just an observer.
|
||||
pub local_key: Option<Arc<ed25519::Pair>>,
|
||||
/// The slot duration in seconds.
|
||||
pub slot_duration: u64
|
||||
}
|
||||
|
||||
/// Get slot author for given block along with authorities.
|
||||
fn slot_author(slot_num: u64, authorities: &[AuthorityId]) -> Option<AuthorityId> {
|
||||
if authorities.is_empty() { return None }
|
||||
|
||||
let idx = slot_num % (authorities.len() as u64);
|
||||
assert!(idx <= usize::max_value() as u64,
|
||||
"It is impossible to have a vector with length beyond the address space; qed");
|
||||
|
||||
let current_author = *authorities.get(idx as usize)
|
||||
.expect("authorities not empty; index constrained to list length;\
|
||||
this is a valid index; qed");
|
||||
|
||||
Some(current_author)
|
||||
}
|
||||
|
||||
fn duration_now() -> Option<Duration> {
|
||||
use std::time::SystemTime;
|
||||
|
||||
let now = SystemTime::now();
|
||||
now.duration_since(SystemTime::UNIX_EPOCH).map_err(|e| {
|
||||
warn!("Current time {:?} is before unix epoch. Something is wrong: {:?}", now, e);
|
||||
}).ok()
|
||||
}
|
||||
|
||||
/// Get the slot for now.
|
||||
fn slot_now(slot_duration: u64) -> Option<u64> {
|
||||
duration_now().map(|s| s.as_secs() / slot_duration)
|
||||
}
|
||||
|
||||
/// A digest item which is usable with aura consensus.
|
||||
pub trait CompatibleDigestItem: Sized {
|
||||
/// Construct a digest item which is a slot number and a signature on the
|
||||
/// hash.
|
||||
fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self;
|
||||
|
||||
/// If this item is an Aura seal, return the slot number and signature.
|
||||
fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)>;
|
||||
}
|
||||
|
||||
impl CompatibleDigestItem for generic::DigestItem<primitives::H256, u64> {
|
||||
/// Construct a digest item which is a slot number and a signature on the
|
||||
/// hash.
|
||||
fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self {
|
||||
generic::DigestItem::Seal(slot_number, signature)
|
||||
}
|
||||
/// If this item is an Aura seal, return the slot number and signature.
|
||||
fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)> {
|
||||
match self {
|
||||
generic::DigestItem::Seal(slot, ref sign) => Some((*slot, sign)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CompatibleDigestItem for generic::DigestItem<primitives::H256, primitives::AuthorityId> {
|
||||
/// Construct a digest item which is a slot number and a signature on the
|
||||
/// hash.
|
||||
fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self {
|
||||
generic::DigestItem::Seal(slot_number, signature)
|
||||
}
|
||||
/// If this item is an Aura seal, return the slot number and signature.
|
||||
fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)> {
|
||||
match self {
|
||||
generic::DigestItem::Seal(slot, ref sign) => Some((*slot, sign)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the aura worker. This should be run in a tokio runtime.
|
||||
pub fn start_aura<B, C, E, SO, Error>(
|
||||
config: Config,
|
||||
client: Arc<C>,
|
||||
env: Arc<E>,
|
||||
sync_oracle: SO,
|
||||
)
|
||||
-> impl Future<Item=(),Error=()> where
|
||||
B: Block,
|
||||
C: Authorities<B, Error=Error> + BlockImport<B, Error=Error> + ChainHead<B>,
|
||||
E: Environment<B, Error=Error>,
|
||||
E::Proposer: Proposer<B, Error=Error>,
|
||||
SO: SyncOracle + Send + Clone,
|
||||
DigestItemFor<B>: CompatibleDigestItem,
|
||||
Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>,
|
||||
{
|
||||
let make_authorship = move || {
|
||||
let config = config.clone();
|
||||
let client = client.clone();
|
||||
let env = env.clone();
|
||||
let sync_oracle = sync_oracle.clone();
|
||||
|
||||
let local_keys = config.local_key.map(|pair| (pair.public(), pair));
|
||||
let slot_duration = config.slot_duration;
|
||||
let mut last_authored_slot = 0;
|
||||
let next_slot_start = duration_now().map(|now| {
|
||||
let remaining_full_secs = slot_duration - (now.as_secs() % slot_duration) - 1;
|
||||
let remaining_nanos = 1_000_000_000 - now.subsec_nanos();
|
||||
Instant::now() + Duration::new(remaining_full_secs, remaining_nanos)
|
||||
}).unwrap_or_else(|| Instant::now());
|
||||
|
||||
Interval::new(next_slot_start, Duration::from_secs(slot_duration))
|
||||
.filter(move |_| !sync_oracle.is_major_syncing()) // only propose when we are not syncing.
|
||||
.filter_map(move |_| local_keys.clone()) // skip if not authoring.
|
||||
.map_err(|e| debug!(target: "aura", "Faulty timer: {:?}", e))
|
||||
.for_each(move |(public_key, key)| {
|
||||
use futures::future;
|
||||
|
||||
let slot_num = match slot_now(slot_duration) {
|
||||
Some(n) => n,
|
||||
None => return Either::B(future::err(())),
|
||||
};
|
||||
|
||||
if last_authored_slot >= slot_num { return Either::B(future::ok(())) }
|
||||
last_authored_slot = slot_num;
|
||||
|
||||
let chain_head = match client.best_block_header() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
warn!(target:"aura", "Unable to author block in slot {}. no best block header: {:?}", slot_num, e);
|
||||
return Either::B(future::ok(()))
|
||||
}
|
||||
};
|
||||
|
||||
let authorities = match client.authorities(&BlockId::Hash(chain_head.hash())){
|
||||
Ok(authorities) => authorities,
|
||||
Err(e) => {
|
||||
warn!("Unable to fetch authorities at block {:?}: {:?}", chain_head.hash(), e);
|
||||
return Either::B(future::ok(()));
|
||||
}
|
||||
};
|
||||
|
||||
let proposal_work = match slot_author(slot_num, &authorities) {
|
||||
None => return Either::B(future::ok(())),
|
||||
Some(author) => if author.0 == public_key.0 {
|
||||
// we are the slot author. make a block and sign it.
|
||||
let proposer = match env.init(&chain_head, &authorities, key.clone()) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
warn!("Unable to author block in slot {:?}: {:?}", slot_num, e);
|
||||
return Either::B(future::ok(()))
|
||||
}
|
||||
};
|
||||
|
||||
proposer.propose().into_future()
|
||||
} else {
|
||||
return Either::B(future::ok(()));
|
||||
}
|
||||
};
|
||||
|
||||
let block_import = client.clone();
|
||||
Either::A(proposal_work
|
||||
.map(move |b| {
|
||||
let (header, body) = b.deconstruct();
|
||||
let pre_hash = header.hash();
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
|
||||
// sign the pre-sealed hash of the block and then
|
||||
// add it to a digest item.
|
||||
let to_sign = (slot_num, pre_hash).encode();
|
||||
let signature = key.sign(&to_sign[..]);
|
||||
let item = <DigestItemFor<B> as CompatibleDigestItem>::aura_seal(slot_num, signature);
|
||||
let import_block = ImportBlock {
|
||||
origin: BlockOrigin::Own,
|
||||
header,
|
||||
external_justification: Vec::new(),
|
||||
post_runtime_digests: vec![item],
|
||||
body: Some(body),
|
||||
finalized: false,
|
||||
auxiliary: Vec::new(),
|
||||
};
|
||||
|
||||
if let Err(e) = block_import.import_block(import_block, None) {
|
||||
warn!(target: "aura", "Error with block built on {:?}: {:?}", parent_hash, e);
|
||||
}
|
||||
})
|
||||
.map_err(|e| warn!("Failed to construct block: {:?}", e))
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
future::loop_fn((), move |()| {
|
||||
let authorship_task = ::std::panic::AssertUnwindSafe(make_authorship());
|
||||
authorship_task.catch_unwind().then(|res| {
|
||||
match res {
|
||||
Ok(Ok(())) => (),
|
||||
Ok(Err(())) => warn!("Aura authorship task terminated unexpectedly. Restarting"),
|
||||
Err(e) => {
|
||||
if let Some(s) = e.downcast_ref::<&'static str>() {
|
||||
warn!("Aura authorship task panicked at {:?}", s);
|
||||
}
|
||||
|
||||
warn!("Restarting Aura authorship task");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(future::Loop::Continue(()))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// a header which has been checked
|
||||
enum CheckedHeader<H> {
|
||||
// a header which has slot in the future. this is the full header (not stripped)
|
||||
// and the slot in which it should be processed.
|
||||
Deferred(H, u64),
|
||||
// a header which is fully checked, including signature. This is the pre-header
|
||||
// accompanied by the seal components.
|
||||
Checked(H, u64, ed25519::Signature),
|
||||
}
|
||||
|
||||
|
||||
/// check a header has been signed by the right key. If the slot is too far in the future, an error will be returned.
|
||||
/// if it's successful, returns the pre-header, the slot number, and the signat.
|
||||
//
|
||||
// FIXME: needs misbehavior types - https://github.com/paritytech/substrate/issues/1018
|
||||
fn check_header<B: Block>(slot_now: u64, mut header: B::Header, hash: B::Hash, authorities: &[AuthorityId])
|
||||
-> Result<CheckedHeader<B::Header>, String>
|
||||
where DigestItemFor<B>: CompatibleDigestItem
|
||||
{
|
||||
let digest_item = match header.digest_mut().pop() {
|
||||
Some(x) => x,
|
||||
None => return Err(format!("Header {:?} is unsealed", hash)),
|
||||
};
|
||||
let (slot_num, &sig) = match digest_item.as_aura_seal() {
|
||||
Some(x) => x,
|
||||
None => return Err(format!("Header {:?} is unsealed", hash)),
|
||||
};
|
||||
|
||||
if slot_num > slot_now {
|
||||
header.digest_mut().push(digest_item);
|
||||
Ok(CheckedHeader::Deferred(header, slot_num))
|
||||
} else {
|
||||
// check the signature is valid under the expected authority and
|
||||
// chain state.
|
||||
|
||||
let expected_author = match slot_author(slot_num, &authorities) {
|
||||
None => return Err("Slot Author not found".to_string()),
|
||||
Some(author) => author
|
||||
};
|
||||
|
||||
let pre_hash = header.hash();
|
||||
let to_sign = (slot_num, pre_hash).encode();
|
||||
let public = ed25519::Public(expected_author.0);
|
||||
|
||||
if ed25519::verify_strong(&sig, &to_sign[..], public) {
|
||||
Ok(CheckedHeader::Checked(header, slot_num, sig))
|
||||
} else {
|
||||
Err(format!("Bad signature on {:?}", hash))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A verifier for Aura blocks.
|
||||
pub struct AuraVerifier<C> {
|
||||
config: Config,
|
||||
client: Arc<C>,
|
||||
}
|
||||
|
||||
impl<B: Block, C> Verifier<B> for AuraVerifier<C> where
|
||||
C: Authorities<B> + BlockImport<B> + Send + Sync,
|
||||
DigestItemFor<B>: CompatibleDigestItem,
|
||||
{
|
||||
fn verify(
|
||||
&self,
|
||||
origin: BlockOrigin,
|
||||
header: B::Header,
|
||||
_justification: Vec<u8>,
|
||||
body: Option<Vec<B::Extrinsic>>
|
||||
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityId>>), String> {
|
||||
let slot_now = slot_now(self.config.slot_duration)
|
||||
.ok_or("System time is before UnixTime?".to_owned())?;
|
||||
let hash = header.hash();
|
||||
let parent_hash = *header.parent_hash();
|
||||
let authorities = self.client.authorities(&BlockId::Hash(parent_hash))
|
||||
.map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?;
|
||||
|
||||
// we add one to allow for some small drift.
|
||||
// FIXME: in the future, alter this queue to allow deferring of headers
|
||||
// https://github.com/paritytech/substrate/issues/1019
|
||||
let checked_header = check_header::<B>(slot_now + 1, header, hash, &authorities[..])?;
|
||||
match checked_header {
|
||||
CheckedHeader::Checked(pre_header, slot_num, sig) => {
|
||||
let item = <DigestItemFor<B>>::aura_seal(slot_num, sig);
|
||||
|
||||
debug!(target: "aura", "Checked {:?}; importing.", pre_header);
|
||||
|
||||
let import_block = ImportBlock {
|
||||
origin,
|
||||
header: pre_header,
|
||||
external_justification: Vec::new(),
|
||||
post_runtime_digests: vec![item],
|
||||
body,
|
||||
finalized: false,
|
||||
auxiliary: Vec::new(),
|
||||
};
|
||||
|
||||
// FIXME: extract authorities - https://github.com/paritytech/substrate/issues/1019
|
||||
Ok((import_block, None))
|
||||
}
|
||||
CheckedHeader::Deferred(a, b) => {
|
||||
debug!(target: "aura", "Checking {:?} failed; {:?}, {:?}.", hash, a, b);
|
||||
Err(format!("Header {:?} rejected: too far in the future", hash))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Aura import queue type.
|
||||
pub type AuraImportQueue<B, C> = BasicQueue<B, AuraVerifier<C>>;
|
||||
|
||||
/// Start an import queue for the Aura consensus algorithm.
|
||||
pub fn import_queue<B, C>(config: Config, client: Arc<C>) -> AuraImportQueue<B, C> where
|
||||
B: Block,
|
||||
C: Authorities<B> + BlockImport<B> + Send + Sync,
|
||||
DigestItemFor<B>: CompatibleDigestItem,
|
||||
{
|
||||
let verifier = Arc::new(AuraVerifier { config, client });
|
||||
BasicQueue::new(verifier)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use consensus_common::NoNetwork as DummyOracle;
|
||||
use network::test::*;
|
||||
use network::test::{Block as TestBlock, PeersClient};
|
||||
use runtime_primitives::traits::Block as BlockT;
|
||||
use network::ProtocolConfig;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::runtime::current_thread;
|
||||
use keyring::Keyring;
|
||||
use client::BlockchainEvents;
|
||||
use test_client;
|
||||
|
||||
type Error = client::error::Error;
|
||||
|
||||
type TestClient = client::Client<test_client::Backend, test_client::Executor, TestBlock>;
|
||||
|
||||
struct DummyFactory(Arc<TestClient>);
|
||||
struct DummyProposer(u64, Arc<TestClient>);
|
||||
|
||||
impl Environment<TestBlock> for DummyFactory {
|
||||
type Proposer = DummyProposer;
|
||||
type Error = Error;
|
||||
|
||||
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[AuthorityId], _sign_with: Arc<ed25519::Pair>)
|
||||
-> Result<DummyProposer, Error>
|
||||
{
|
||||
Ok(DummyProposer(parent_header.number + 1, self.0.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Proposer<TestBlock> for DummyProposer {
|
||||
type Error = Error;
|
||||
type Create = Result<TestBlock, Error>;
|
||||
|
||||
fn propose(&self) -> Result<TestBlock, Error> {
|
||||
self.1.new_block().unwrap().bake().map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
const SLOT_DURATION: u64 = 1;
|
||||
const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50);
|
||||
|
||||
pub struct AuraTestNet {
|
||||
peers: Vec<Arc<Peer<AuraVerifier<PeersClient>>>>,
|
||||
started: bool
|
||||
}
|
||||
|
||||
impl TestNetFactory for AuraTestNet {
|
||||
type Verifier = AuraVerifier<PeersClient>;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
AuraTestNet {
|
||||
peers: Vec::new(),
|
||||
started: false
|
||||
}
|
||||
}
|
||||
|
||||
fn make_verifier(&self, client: Arc<PeersClient>, _cfg: &ProtocolConfig)
|
||||
-> Arc<Self::Verifier>
|
||||
{
|
||||
let config = Config { local_key: None, slot_duration: SLOT_DURATION };
|
||||
Arc::new(AuraVerifier { client, config })
|
||||
}
|
||||
|
||||
fn peer(&self, i: usize) -> &Peer<Self::Verifier> {
|
||||
&self.peers[i]
|
||||
}
|
||||
|
||||
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier>>> {
|
||||
&self.peers
|
||||
}
|
||||
|
||||
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier>>>)>(&mut self, closure: F ) {
|
||||
closure(&mut self.peers);
|
||||
}
|
||||
|
||||
fn started(&self) -> bool {
|
||||
self.started
|
||||
}
|
||||
|
||||
fn set_started(&mut self, new: bool) {
|
||||
self.started = new;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authoring_blocks() {
|
||||
::env_logger::init().ok();
|
||||
let mut net = AuraTestNet::new(3);
|
||||
|
||||
net.start();
|
||||
|
||||
let peers = &[
|
||||
(0, Keyring::Alice),
|
||||
(1, Keyring::Bob),
|
||||
(2, Keyring::Charlie),
|
||||
];
|
||||
|
||||
let net = Arc::new(Mutex::new(net));
|
||||
let mut import_notifications = Vec::new();
|
||||
|
||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||
for (peer_id, key) in peers {
|
||||
let mut client = net.lock().peer(*peer_id).client().clone();
|
||||
let environ = Arc::new(DummyFactory(client.clone()));
|
||||
import_notifications.push(
|
||||
client.import_notification_stream()
|
||||
.take_while(|n| {
|
||||
Ok(!(n.origin != BlockOrigin::Own && n.header.number() < &5))
|
||||
})
|
||||
.for_each(move |_| Ok(()))
|
||||
);
|
||||
let aura = start_aura(
|
||||
Config {
|
||||
local_key: Some(Arc::new(key.clone().into())),
|
||||
slot_duration: SLOT_DURATION
|
||||
},
|
||||
client,
|
||||
environ.clone(),
|
||||
DummyOracle,
|
||||
);
|
||||
|
||||
runtime.spawn(aura);
|
||||
}
|
||||
|
||||
// wait for all finalized on each.
|
||||
let wait_for = ::futures::future::join_all(import_notifications)
|
||||
.map(|_| ())
|
||||
.map_err(|_| ());
|
||||
|
||||
let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL)
|
||||
.for_each(move |_| {
|
||||
net.lock().send_import_notifications();
|
||||
net.lock().sync();
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
.map_err(|_| ());
|
||||
|
||||
runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,11 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Common utilities for substrate consensus"
|
||||
|
||||
[dependencies]
|
||||
substrate-primitives = { path = "../../primitives"}
|
||||
substrate-primitives = { path= "../../primitives" }
|
||||
error-chain = "0.12"
|
||||
futures = "0.1"
|
||||
sr-version = { path = "../../sr-version" }
|
||||
sr-primitives = { path = "../../sr-primitives" }
|
||||
tokio = "0.1.7"
|
||||
parity-codec = "2.1"
|
||||
parity-codec-derive = "2.0"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
= Consensus Common
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::traits::{Block as BlockT, DigestItemFor};
|
||||
use runtime_primitives::Justification;
|
||||
|
||||
/// Block import result.
|
||||
#[derive(Debug)]
|
||||
pub enum ImportResult {
|
||||
/// Added to the import queue.
|
||||
Queued,
|
||||
/// Already in the import queue.
|
||||
AlreadyQueued,
|
||||
/// Already in the blockchain.
|
||||
AlreadyInChain,
|
||||
/// Block or parent is known to be bad.
|
||||
KnownBad,
|
||||
/// Block parent is not in the chain.
|
||||
UnknownParent,
|
||||
}
|
||||
|
||||
/// Block data origin.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BlockOrigin {
|
||||
/// Genesis block built into the client.
|
||||
Genesis,
|
||||
/// Block is part of the initial sync with the network.
|
||||
NetworkInitialSync,
|
||||
/// Block was broadcasted on the network.
|
||||
NetworkBroadcast,
|
||||
/// Block that was received from the network and validated in the consensus process.
|
||||
ConsensusBroadcast,
|
||||
/// Block that was collated by this node.
|
||||
Own,
|
||||
/// Block was imported from a file.
|
||||
File,
|
||||
}
|
||||
|
||||
/// Data required to import a Block
|
||||
pub struct ImportBlock<Block: BlockT> {
|
||||
/// Origin of the Block
|
||||
pub origin: BlockOrigin,
|
||||
/// The header, without consensus post-digests applied. This should be in the same
|
||||
/// state as it comes out of the runtime.
|
||||
///
|
||||
/// Consensus engines which alter the header (by adding post-runtime digests)
|
||||
/// should strip those off in the initial verification process and pass them
|
||||
/// via the `post_runtime_digests` field. During block authorship, they should
|
||||
/// not be pushed to the header directly.
|
||||
///
|
||||
/// The reason for this distinction is so the header can be directly
|
||||
/// re-executed in a runtime that checks digest equivalence -- the
|
||||
/// post-runtime digests are pushed back on after.
|
||||
pub header: Block::Header,
|
||||
/// Justification provided for this block from the outside:.
|
||||
pub external_justification: Justification,
|
||||
/// Digest items that have been added after the runtime for external
|
||||
/// work, like a consensus signature.
|
||||
pub post_runtime_digests: Vec<DigestItemFor<Block>>,
|
||||
/// Block's body
|
||||
pub body: Option<Vec<Block::Extrinsic>>,
|
||||
/// Is this block finalized already?
|
||||
/// `true` implies instant finality.
|
||||
pub finalized: bool,
|
||||
/// Auxiliary consensus data produced by the block.
|
||||
/// Contains a list of key-value pairs. If values are `None`, the keys
|
||||
/// will be deleted.
|
||||
pub auxiliary: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> ImportBlock<Block> {
|
||||
/// Deconstruct the justified header into parts.
|
||||
pub fn into_inner(self)
|
||||
-> (
|
||||
BlockOrigin,
|
||||
<Block as BlockT>::Header,
|
||||
Justification,
|
||||
Vec<DigestItemFor<Block>>,
|
||||
Option<Vec<<Block as BlockT>::Extrinsic>>,
|
||||
bool,
|
||||
Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
) {
|
||||
(
|
||||
self.origin,
|
||||
self.header,
|
||||
self.external_justification,
|
||||
self.post_runtime_digests,
|
||||
self.body,
|
||||
self.finalized,
|
||||
self.auxiliary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Block import trait.
|
||||
pub trait BlockImport<B: BlockT> {
|
||||
type Error: ::std::error::Error + Send + 'static;
|
||||
/// Import a Block alongside the new authorities valid form this block forward
|
||||
fn import_block(&self,
|
||||
block: ImportBlock<B>,
|
||||
new_authorities: Option<Vec<AuthorityId>>
|
||||
) -> Result<ImportResult, Self::Error>;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright 2017-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Error types in Consensus
|
||||
use runtime_version::RuntimeVersion;
|
||||
|
||||
error_chain! {
|
||||
errors {
|
||||
/// Missing state at block with given descriptor.
|
||||
StateUnavailable(b: String) {
|
||||
description("State missing at given block."),
|
||||
display("State unavailable at block {}", b),
|
||||
}
|
||||
|
||||
/// I/O terminated unexpectedly
|
||||
IoTerminated {
|
||||
description("I/O terminated unexpectedly."),
|
||||
display("I/O terminated unexpectedly."),
|
||||
}
|
||||
|
||||
/// Unable to schedule wakeup.
|
||||
FaultyTimer(e: ::tokio::timer::Error) {
|
||||
description("Timer error"),
|
||||
display("Timer error: {}", e),
|
||||
}
|
||||
|
||||
/// Unable to propose a block.
|
||||
CannotPropose {
|
||||
description("Unable to create block proposal."),
|
||||
display("Unable to create block proposal."),
|
||||
}
|
||||
|
||||
/// Error checking signature
|
||||
InvalidSignature(s: ::primitives::ed25519::Signature, a: ::primitives::AuthorityId) {
|
||||
description("Message signature is invalid"),
|
||||
display("Message signature {:?} by {:?} is invalid.", s, a),
|
||||
}
|
||||
|
||||
/// Account is not an authority.
|
||||
InvalidAuthority(a: ::primitives::AuthorityId) {
|
||||
description("Message sender is not a valid authority"),
|
||||
display("Message sender {:?} is not a valid authority.", a),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
IncompatibleAuthoringRuntime(native: RuntimeVersion, on_chain: RuntimeVersion) {
|
||||
description("Authoring for current runtime is not supported"),
|
||||
display("Authoring for current runtime is not supported. Native ({}) cannot author for on-chain ({}).", native, on_chain),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
RuntimeVersionMissing {
|
||||
description("Current runtime has no version"),
|
||||
display("Authoring for current runtime is not supported since it has no version."),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
NativeRuntimeMissing {
|
||||
description("This build has no native runtime"),
|
||||
display("Authoring in current build is not supported since it has no runtime."),
|
||||
}
|
||||
|
||||
/// Justification requirements not met.
|
||||
InvalidJustification {
|
||||
description("Invalid justification"),
|
||||
display("Invalid justification."),
|
||||
}
|
||||
|
||||
/// Some other error.
|
||||
Other(e: Box<::std::error::Error + Send>) {
|
||||
description("Other error")
|
||||
display("Other error: {}", e.description())
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-17
@@ -18,11 +18,10 @@
|
||||
|
||||
use super::MAX_TRANSACTIONS_SIZE;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use node_runtime::{Block as GenericBlock};
|
||||
use node_primitives::{Hash, BlockNumber};
|
||||
use codec::Encode;
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As};
|
||||
|
||||
type BlockNumber = u64;
|
||||
|
||||
error_chain! {
|
||||
errors {
|
||||
@@ -30,13 +29,13 @@ error_chain! {
|
||||
description("Proposal provided not a block."),
|
||||
display("Proposal provided not a block."),
|
||||
}
|
||||
WrongParentHash(expected: Hash, got: Hash) {
|
||||
WrongParentHash(expected: String, got: String) {
|
||||
description("Proposal had wrong parent hash."),
|
||||
display("Proposal had wrong parent hash. Expected {:?}, got {:?}", expected, got),
|
||||
}
|
||||
WrongNumber(expected: BlockNumber, got: BlockNumber) {
|
||||
description("Proposal had wrong number."),
|
||||
display("Proposal had wrong number. Expected {:?}, got {:?}", expected, got),
|
||||
display("Proposal had wrong number. Expected {}, got {}", expected, got),
|
||||
}
|
||||
ProposalTooLarge(size: usize) {
|
||||
description("Proposal exceeded the maximum size."),
|
||||
@@ -50,20 +49,17 @@ error_chain! {
|
||||
|
||||
/// Attempt to evaluate a substrate block as a node block, returning error
|
||||
/// upon any initial validity checks failing.
|
||||
pub fn evaluate_initial<Block: BlockT, Hash>(
|
||||
pub fn evaluate_initial<Block: BlockT>(
|
||||
proposal: &Block,
|
||||
parent_hash: &Hash,
|
||||
parent_hash: &<Block as BlockT>::Hash,
|
||||
parent_number: <<Block as BlockT>::Header as HeaderT>::Number,
|
||||
) -> Result<()>
|
||||
where
|
||||
Hash: PartialEq<<<GenericBlock as BlockT>::Header as HeaderT>::Hash>,
|
||||
Hash: Into<self::Hash> + Clone,
|
||||
{
|
||||
) -> Result<()> {
|
||||
|
||||
let encoded = Encode::encode(proposal);
|
||||
let proposal = GenericBlock::decode(&mut &encoded[..])
|
||||
let proposal = Block::decode(&mut &encoded[..])
|
||||
.ok_or_else(|| ErrorKind::BadProposalFormat)?;
|
||||
|
||||
let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
|
||||
let transactions_size = proposal.extrinsics().iter().fold(0, |a, tx| {
|
||||
a + Encode::encode(tx).len()
|
||||
});
|
||||
|
||||
@@ -72,11 +68,14 @@ where
|
||||
}
|
||||
|
||||
if *parent_hash != *proposal.header().parent_hash() {
|
||||
bail!(ErrorKind::WrongParentHash((*parent_hash).clone().into(), proposal.header.parent_hash));
|
||||
bail!(ErrorKind::WrongParentHash(
|
||||
format!("{:?}", *parent_hash),
|
||||
format!("{:?}", proposal.header().parent_hash())
|
||||
));
|
||||
}
|
||||
|
||||
if parent_number.as_() + 1 != *proposal.header().number() {
|
||||
bail!(ErrorKind::WrongNumber(parent_number.as_() + 1, proposal.header.number));
|
||||
if parent_number.as_() + 1 != proposal.header().number().as_() {
|
||||
bail!(ErrorKind::WrongNumber(parent_number.as_() + 1, proposal.header().number().as_()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -14,21 +14,119 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate Consensus Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Tracks offline validators.
|
||||
// tag::description[]
|
||||
//! Consensus basics and common features
|
||||
// end::description[]
|
||||
|
||||
// This provides "unused" building blocks to other crates
|
||||
#![allow(dead_code)]
|
||||
|
||||
// our error-chain could potentially blow up otherwise
|
||||
#![recursion_limit="128"]
|
||||
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate sr_primitives;
|
||||
extern crate futures;
|
||||
extern crate sr_version as runtime_version;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate tokio;
|
||||
|
||||
use sr_primitives::{generic::BlockId};
|
||||
use sr_primitives::traits::{Block, Header};
|
||||
use sr_primitives::Justification;
|
||||
use primitives::AuthorityId;
|
||||
extern crate parity_codec as codec;
|
||||
#[macro_use]
|
||||
extern crate parity_codec_derive;
|
||||
|
||||
/// Block import trait.
|
||||
pub trait BlockImport<B: Block> {
|
||||
/// Import a block alongside its corresponding justification.
|
||||
fn import_block(&self, block: B, justification: Justification, authorities: &[AuthorityId]) -> bool;
|
||||
}
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use primitives::{ed25519, AuthorityId};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::Block;
|
||||
use futures::prelude::*;
|
||||
|
||||
pub mod offline_tracker;
|
||||
pub mod error;
|
||||
mod block_import;
|
||||
pub mod evaluation;
|
||||
|
||||
// block size limit.
|
||||
const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
pub use self::error::{Error, ErrorKind};
|
||||
pub use block_import::{BlockImport, ImportBlock, BlockOrigin, ImportResult};
|
||||
|
||||
/// Trait for getting the authorities at a given block.
|
||||
pub trait Authorities<B: Block> {
|
||||
type Error: ::std::error::Error + Send + 'static; /// Get the authorities at the given block.
|
||||
fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityId>, Self::Error>;
|
||||
}
|
||||
|
||||
/// Environment producer for a Consensus instance. Creates proposer instance and communication streams.
|
||||
pub trait Environment<B: Block> {
|
||||
/// The proposer type this creates.
|
||||
type Proposer: Proposer<B>;
|
||||
/// Error which can occur upon creation.
|
||||
type Error: From<Error>;
|
||||
|
||||
/// Initialize the proposal logic on top of a specific header. Provide
|
||||
/// the authorities at that header, and a local key to sign any additional
|
||||
/// consensus messages with as well.
|
||||
fn init(&self, parent_header: &B::Header, authorities: &[AuthorityId], sign_with: Arc<ed25519::Pair>)
|
||||
-> Result<Self::Proposer, Self::Error>;
|
||||
}
|
||||
|
||||
/// Logic for a proposer.
|
||||
///
|
||||
/// This will encapsulate creation and evaluation of proposals at a specific
|
||||
/// block.
|
||||
pub trait Proposer<B: Block> {
|
||||
/// Error type which can occur when proposing or evaluating.
|
||||
type Error: From<Error> + ::std::fmt::Debug + 'static;
|
||||
/// Future that resolves to a committed proposal.
|
||||
type Create: IntoFuture<Item=B,Error=Self::Error>;
|
||||
/// Create a proposal.
|
||||
fn propose(&self) -> Self::Create;
|
||||
}
|
||||
|
||||
/// Inherent data to include in a block.
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct InherentData {
|
||||
/// Current timestamp.
|
||||
pub timestamp: u64,
|
||||
/// Indices of offline validators.
|
||||
pub offline_indices: Vec<u32>,
|
||||
}
|
||||
|
||||
impl InherentData {
|
||||
/// Create a new `InherentData` instance.
|
||||
pub fn new(timestamp: u64, offline_indices: Vec<u32>) -> Self {
|
||||
Self {
|
||||
timestamp,
|
||||
offline_indices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An oracle for when major synchronization work is being undertaken.
|
||||
///
|
||||
/// Generally, consensus authoring work isn't undertaken while well behind
|
||||
/// the head of the chain.
|
||||
pub trait SyncOracle {
|
||||
/// Whether the synchronization service is undergoing major sync.
|
||||
/// Returns true if so.
|
||||
fn is_major_syncing(&self) -> bool;
|
||||
}
|
||||
|
||||
/// A synchronization oracle for when there is no network.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct NoNetwork;
|
||||
|
||||
impl SyncOracle for NoNetwork {
|
||||
fn is_major_syncing(&self) -> bool { false }
|
||||
}
|
||||
|
||||
impl<T: SyncOracle> SyncOracle for Arc<T> {
|
||||
fn is_major_syncing(&self) -> bool {
|
||||
T::is_major_syncing(&*self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,30 +6,33 @@ description = "Rhododendron Round-Based consensus-algorithm for substrate"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1.17"
|
||||
parity-codec = { version = "1.1" }
|
||||
parity-codec = { version = "2.1" }
|
||||
parity-codec-derive = { version = "2.0" }
|
||||
substrate-primitives = { path = "../../primitives" }
|
||||
substrate-consensus-common = { path = "../common" }
|
||||
substrate-client = { path = "../../client" }
|
||||
substrate-transaction-pool = { path = "../../transaction-pool" }
|
||||
srml-support = { path = "../../../srml/support" }
|
||||
srml-system = { path = "../../../srml/system" }
|
||||
srml-consensus = { path = "../../../srml/consensus" }
|
||||
sr-primitives = { path = "../../sr-primitives" }
|
||||
sr-version = { path = "../../sr-version" }
|
||||
sr-io = { path = "../../sr-io" }
|
||||
srml-consensus = { path = "../../../srml/consensus" }
|
||||
tokio = "0.1.7"
|
||||
parking_lot = "0.4"
|
||||
error-chain = "0.12"
|
||||
log = "0.3"
|
||||
rhododendron = { git = "https://github.com/paritytech/rhododendron.git", features = ["codec"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
rhododendron = { version = "0.4.0", features = ["codec"] }
|
||||
exit-future = "0.1"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-keyring = { path = "../../keyring" }
|
||||
substrate-executor = { path = "../../executor" }
|
||||
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"serde/std",
|
||||
"substrate-primitives/std",
|
||||
"srml-support/std",
|
||||
"sr-primitives/std",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
= Consensus Rhododendron (RHD)
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2018 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
@@ -14,81 +14,44 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Error types in the BFT service.
|
||||
use runtime_version::RuntimeVersion;
|
||||
//! Error types in the rhododendron Consensus service.
|
||||
use consensus::error::{Error as CommonError, ErrorKind as CommonErrorKind};
|
||||
use primitives::AuthorityId;
|
||||
use client;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
Client(client::error::Error, client::error::ErrorKind);
|
||||
Common(CommonError, CommonErrorKind);
|
||||
}
|
||||
errors {
|
||||
/// Missing state at block with given descriptor.
|
||||
StateUnavailable(b: String) {
|
||||
description("State missing at given block."),
|
||||
display("State unavailable at block {}", b),
|
||||
NotValidator(id: AuthorityId) {
|
||||
description("Local account ID not a validator at this block."),
|
||||
display("Local account ID ({:?}) not a validator at this block.", id),
|
||||
}
|
||||
|
||||
/// I/O terminated unexpectedly
|
||||
IoTerminated {
|
||||
description("I/O terminated unexpectedly."),
|
||||
display("I/O terminated unexpectedly."),
|
||||
PrematureDestruction {
|
||||
description("Proposer destroyed before finishing proposing or evaluating"),
|
||||
display("Proposer destroyed before finishing proposing or evaluating"),
|
||||
}
|
||||
|
||||
/// Unable to schedule wakeup.
|
||||
FaultyTimer(e: ::tokio::timer::Error) {
|
||||
description("Timer error"),
|
||||
display("Timer error: {}", e),
|
||||
Timer(e: ::tokio::timer::Error) {
|
||||
description("Failed to register or resolve async timer."),
|
||||
display("Timer failed: {}", e),
|
||||
}
|
||||
|
||||
/// Unable to propose a block.
|
||||
CannotPropose {
|
||||
description("Unable to create block proposal."),
|
||||
display("Unable to create block proposal."),
|
||||
}
|
||||
|
||||
/// Error checking signature
|
||||
InvalidSignature(s: ::primitives::ed25519::Signature, a: ::primitives::AuthorityId) {
|
||||
description("Message signature is invalid"),
|
||||
display("Message signature {:?} by {:?} is invalid.", s, a),
|
||||
}
|
||||
|
||||
/// Account is not an authority.
|
||||
InvalidAuthority(a: ::primitives::AuthorityId) {
|
||||
description("Message sender is not a valid authority"),
|
||||
display("Message sender {:?} is not a valid authority.", a),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
IncompatibleAuthoringRuntime(native: RuntimeVersion, on_chain: RuntimeVersion) {
|
||||
description("Authoring for current runtime is not supported"),
|
||||
display("Authoring for current runtime is not supported. Native ({}) cannot author for on-chain ({}).", native, on_chain),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
RuntimeVersionMissing {
|
||||
description("Current runtime has no version"),
|
||||
display("Authoring for current runtime is not supported since it has no version."),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
NativeRuntimeMissing {
|
||||
description("This build has no native runtime"),
|
||||
display("Authoring in current build is not supported since it has no runtime."),
|
||||
}
|
||||
|
||||
/// Justification requirements not met.
|
||||
InvalidJustification {
|
||||
description("Invalid justification"),
|
||||
display("Invalid justification."),
|
||||
}
|
||||
|
||||
/// Some other error.
|
||||
Other(e: Box<::std::error::Error + Send>) {
|
||||
description("Other error")
|
||||
display("Other error: {}", e.description())
|
||||
Executor(e: ::futures::future::ExecuteErrorKind) {
|
||||
description("Unable to dispatch agreement future"),
|
||||
display("Unable to dispatch agreement future: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::rhododendron::InputStreamConcluded> for Error {
|
||||
fn from(_: ::rhododendron::InputStreamConcluded) -> Error {
|
||||
ErrorKind::IoTerminated.into()
|
||||
fn from(_: ::rhododendron::InputStreamConcluded) -> Self {
|
||||
CommonErrorKind::IoTerminated.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommonErrorKind> for Error {
|
||||
fn from(e: CommonErrorKind) -> Self {
|
||||
CommonError::from(e).into()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+11
-12
@@ -22,12 +22,9 @@ use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::sync::Arc;
|
||||
|
||||
use rhd::{self, BftService};
|
||||
use client::{BlockchainEvents, ChainHead, BlockBody};
|
||||
use ed25519;
|
||||
use futures::prelude::*;
|
||||
use transaction_pool::txpool::{Pool as TransactionPool, ChainApi as PoolChainApi};
|
||||
use primitives;
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, BlockNumberToHash};
|
||||
|
||||
use tokio::executor::current_thread::TaskExecutor as LocalThreadHandle;
|
||||
@@ -35,8 +32,11 @@ use tokio::runtime::TaskExecutor as ThreadPoolHandle;
|
||||
use tokio::runtime::current_thread::Runtime as LocalRuntime;
|
||||
use tokio::timer::Interval;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use consensus::offline_tracker::OfflineTracker;
|
||||
|
||||
use super::{Network, ProposerFactory, AuthoringApi};
|
||||
use error;
|
||||
use {consensus, primitives, ed25519, error, BftService, LocalProposer};
|
||||
|
||||
const TIMER_DELAY_MS: u64 = 5000;
|
||||
const TIMER_INTERVAL_MS: u64 = 500;
|
||||
@@ -47,11 +47,12 @@ fn start_bft<F, C, Block>(
|
||||
header: <Block as BlockT>::Header,
|
||||
bft_service: Arc<BftService<Block, F, C>>,
|
||||
) where
|
||||
F: rhd::Environment<Block> + 'static,
|
||||
C: rhd::BlockImport<Block> + rhd::Authorities<Block> + 'static,
|
||||
F: consensus::Environment<Block> + 'static,
|
||||
C: consensus::BlockImport<Block> + consensus::Authorities<Block> + 'static,
|
||||
F::Error: ::std::fmt::Debug,
|
||||
<F::Proposer as rhd::Proposer<Block>>::Error: ::std::fmt::Display + Into<error::Error>,
|
||||
<F as rhd::Environment<Block>>::Error: ::std::fmt::Display,
|
||||
<F::Proposer as consensus::Proposer<Block>>::Error: ::std::fmt::Display + Into<error::Error>,
|
||||
<F as consensus::Environment<Block>>::Proposer : LocalProposer<Block>,
|
||||
<F as consensus::Environment<Block>>::Error: ::std::fmt::Display,
|
||||
Block: BlockT,
|
||||
{
|
||||
let mut handle = LocalThreadHandle::current();
|
||||
@@ -88,14 +89,12 @@ impl Service {
|
||||
C: BlockchainEvents<<A as AuthoringApi>::Block>
|
||||
+ ChainHead<<A as AuthoringApi>::Block>
|
||||
+ BlockBody<<A as AuthoringApi>::Block>,
|
||||
C: bft::BlockImport<<A as AuthoringApi>::Block>
|
||||
+ bft::Authorities<<A as AuthoringApi>::Block> + Send + Sync + 'static,
|
||||
C: consensus::BlockImport<<A as AuthoringApi>::Block>
|
||||
+ consensus::Authorities<<A as AuthoringApi>::Block> + Send + Sync + 'static,
|
||||
primitives::H256: From<<<A as AuthoringApi>::Block as BlockT>::Hash>,
|
||||
<<A as AuthoringApi>::Block as BlockT>::Hash: PartialEq<primitives::H256> + PartialEq,
|
||||
N: Network<Block = <A as AuthoringApi>::Block> + Send + 'static,
|
||||
{
|
||||
use parking_lot::RwLock;
|
||||
use super::OfflineTracker;
|
||||
|
||||
let (signal, exit) = ::exit_future::signal();
|
||||
let thread = thread::spawn(move || {
|
||||
@@ -24,7 +24,7 @@
|
||||
//! - execute_block(bytes)
|
||||
//! - init_block(PrevBlock?) -> InProgressBlock
|
||||
//! - add_transaction(InProgressBlock) -> InProgressBlock
|
||||
//! I leave it as is for now as it might be removed before this is ever done.
|
||||
//! It is left as is for now as it might be removed before this is ever done.
|
||||
// end::description[]
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
@@ -196,13 +196,9 @@ impl<D: NativeExecutionDispatch> CodeExecutor<Blake2Hasher> for NativeExecutor<D
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! native_executor_instance {
|
||||
(pub $name:ident, $dispatcher:path, $version:path, $code:expr) => {
|
||||
pub struct $name;
|
||||
native_executor_instance!(IMPL $name, $dispatcher, $version, $code);
|
||||
};
|
||||
($name:ident, $dispatcher:path, $version:path, $code:expr) => {
|
||||
( $pub:vis $name:ident, $dispatcher:path, $version:path, $code:expr) => {
|
||||
/// A unit struct which implements `NativeExecutionDispatch` feeding in the hard-coded runtime.
|
||||
struct $name;
|
||||
$pub struct $name;
|
||||
native_executor_instance!(IMPL $name, $dispatcher, $version, $code);
|
||||
};
|
||||
(IMPL $name:ident, $dispatcher:path, $version:path, $code:expr) => {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
= Finality GRANDPA (aka SHAFT)
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -14,9 +14,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Integration of the GRANDPA finality gadget into substrate.
|
||||
//!
|
||||
//! This is a long-running future that produces finality notifications.
|
||||
// end::description[]
|
||||
|
||||
extern crate finality_grandpa as grandpa;
|
||||
extern crate futures;
|
||||
@@ -45,11 +47,11 @@ use futures::stream::Fuse;
|
||||
use futures::sync::mpsc;
|
||||
use client::{Client, error::Error as ClientError, ImportNotifications, backend::Backend, CallExecutor};
|
||||
use codec::{Encode, Decode};
|
||||
use consensus_common::BlockImport;
|
||||
use consensus_common::{BlockImport, ImportBlock, ImportResult};
|
||||
use runtime_primitives::traits::{
|
||||
NumberFor, Block as BlockT, Header as HeaderT, DigestItemFor,
|
||||
};
|
||||
use runtime_primitives::{generic::BlockId, Justification};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use substrate_primitives::{ed25519, AuthorityId, Blake2Hasher};
|
||||
use tokio::timer::Interval;
|
||||
|
||||
@@ -702,21 +704,24 @@ pub struct GrandpaBlockImport<B, E, Block: BlockT> {
|
||||
|
||||
impl<B, E, Block: BlockT> BlockImport<Block> for GrandpaBlockImport<B, E, Block> where
|
||||
B: Backend<Block, Blake2Hasher> + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone,
|
||||
DigestItemFor<Block>: CompatibleDigestItem<NumberFor<Block>>,
|
||||
{
|
||||
fn import_block(&self, block: Block, _justification: Justification, _authorities: &[AuthorityId]) -> bool {
|
||||
type Error = ClientError;
|
||||
|
||||
fn import_block(&self, block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityId>>)
|
||||
-> Result<ImportResult, Self::Error>
|
||||
{
|
||||
use runtime_primitives::traits::Digest;
|
||||
use authorities::PendingChange;
|
||||
|
||||
let maybe_event = block.header().digest().logs().iter()
|
||||
let maybe_event = block.header.digest().logs().iter()
|
||||
.filter_map(|log| log.scheduled_change())
|
||||
.next()
|
||||
.map(|change| (block.header().hash(), *block.header().number(), change));
|
||||
.map(|change| (block.header.hash(), *block.header.number(), change));
|
||||
|
||||
// TODO [now]: use import-block trait for client when implemented
|
||||
let result = self.inner.import_block(unimplemented!(), unimplemented!()).is_ok();
|
||||
if let (true, Some((hash, number, change))) = (result, maybe_event) {
|
||||
let result = self.inner.import_block(block, new_authorities);
|
||||
if let (true, Some((hash, number, change))) = (result.is_ok(), maybe_event) {
|
||||
self.authority_set.add_pending_change(PendingChange {
|
||||
next_authorities: change.next_authorities,
|
||||
finalization_depth: number + change.delay,
|
||||
@@ -726,6 +731,7 @@ impl<B, E, Block: BlockT> BlockImport<Block> for GrandpaBlockImport<B, E, Block>
|
||||
|
||||
// TODO [now]: write to DB, and what to do on failure?
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Support code for the runtime.
|
||||
//! Support code for the runtime. A set of test accounts.
|
||||
// end::description[]
|
||||
|
||||
#[macro_use] extern crate hex_literal;
|
||||
|
||||
@@ -17,6 +17,7 @@ linked-hash-map = "0.5"
|
||||
rustc-hex = "1.0"
|
||||
rand = "0.5"
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
substrate-consensus-common = { path = "../../core/consensus/common" }
|
||||
substrate-client = { path = "../../core/client" }
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
parity-codec = "2.1"
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
//! Blockchain access trait
|
||||
|
||||
use client::{self, Client as SubstrateClient, ImportBlock, ImportResult, ClientInfo, BlockStatus, CallExecutor};
|
||||
use client::{self, Client as SubstrateClient, ClientInfo, BlockStatus, CallExecutor};
|
||||
use client::error::Error;
|
||||
use consensus::BlockImport;
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::generic::{BlockId};
|
||||
use consensus::{ImportBlock, ImportResult};
|
||||
use runtime_primitives::Justification;
|
||||
use primitives::{Blake2Hasher, AuthorityId};
|
||||
|
||||
@@ -69,9 +71,12 @@ pub trait Client<Block: BlockT>: Send + Sync {
|
||||
impl<B, E, Block> Client<Block> for SubstrateClient<B, E, Block> where
|
||||
B: client::backend::Backend<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
Block: BlockT,
|
||||
Self: BlockImport<Block, Error=Error>,
|
||||
Block: BlockT
|
||||
{
|
||||
fn import(&self, block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityId>>) -> Result<ImportResult, Error> {
|
||||
fn import(&self, block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityId>>)
|
||||
-> Result<ImportResult, Error>
|
||||
{
|
||||
(self as &SubstrateClient<B, E, Block>).import_block(block, new_authorities)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ use std::collections::{HashSet, VecDeque};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use parking_lot::{Condvar, Mutex, RwLock};
|
||||
|
||||
pub use client::{BlockOrigin, ImportBlock, ImportResult};
|
||||
use network_libp2p::{NodeIndex, Severity};
|
||||
use primitives::AuthorityId;
|
||||
|
||||
@@ -42,6 +40,9 @@ use protocol::Context;
|
||||
use service::ExecuteInContext;
|
||||
use sync::ChainSync;
|
||||
|
||||
pub use consensus::{ImportBlock, ImportResult, BlockOrigin};
|
||||
|
||||
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
use std::cell::RefCell;
|
||||
|
||||
@@ -428,7 +429,6 @@ fn import_single_block<B: BlockT, V: Verifier<B>>(
|
||||
trace!(target: "sync", "Verifying {}({}) failed: {}", number, hash, msg);
|
||||
}
|
||||
BlockImportError::VerificationFailed(peer, msg)
|
||||
|
||||
})?;
|
||||
|
||||
match chain.import(import_block, new_authorities) {
|
||||
@@ -552,7 +552,7 @@ impl<B: BlockT> Verifier<B> for PassThroughVerifier {
|
||||
body,
|
||||
finalized: self.0,
|
||||
external_justification: justification,
|
||||
internal_justification: vec![],
|
||||
post_runtime_digests: vec![],
|
||||
auxiliary: Vec::new(),
|
||||
}, None))
|
||||
}
|
||||
@@ -615,7 +615,6 @@ pub mod tests {
|
||||
use message;
|
||||
use test_client::{self, TestClient};
|
||||
use test_client::runtime::{Block, Hash};
|
||||
use on_demand::tests::DummyExecutor;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use std::cell::Cell;
|
||||
use super::*;
|
||||
|
||||
@@ -28,6 +28,7 @@ extern crate substrate_primitives as primitives;
|
||||
extern crate substrate_client as client;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate substrate_network_libp2p as network_libp2p;
|
||||
extern crate substrate_consensus_common as consensus;
|
||||
extern crate parity_codec as codec;
|
||||
extern crate futures;
|
||||
extern crate rustc_hex;
|
||||
|
||||
@@ -776,41 +776,41 @@ macro_rules! construct_simple_protocol {
|
||||
|
||||
fn on_connect(
|
||||
&mut self,
|
||||
ctx: &mut $crate::Context<$block>,
|
||||
who: $crate::NodeIndex,
|
||||
status: $crate::StatusMessage<$block>
|
||||
_ctx: &mut $crate::Context<$block>,
|
||||
_who: $crate::NodeIndex,
|
||||
_status: $crate::StatusMessage<$block>
|
||||
) {
|
||||
$( self.$sub_protocol_name.on_connect(ctx, who, status); )*
|
||||
$( self.$sub_protocol_name.on_connect(_ctx, _who, _status); )*
|
||||
}
|
||||
|
||||
fn on_disconnect(&mut self, ctx: &mut $crate::Context<$block>, who: $crate::NodeIndex) {
|
||||
$( self.$sub_protocol_name.on_disconnect(ctx, who); )*
|
||||
fn on_disconnect(&mut self, _ctx: &mut $crate::Context<$block>, _who: $crate::NodeIndex) {
|
||||
$( self.$sub_protocol_name.on_disconnect(_ctx, _who); )*
|
||||
}
|
||||
|
||||
fn on_message(
|
||||
&mut self,
|
||||
ctx: &mut $crate::Context<$block>,
|
||||
who: $crate::NodeIndex,
|
||||
message: &mut Option<$crate::message::Message<$block>>
|
||||
_ctx: &mut $crate::Context<$block>,
|
||||
_who: $crate::NodeIndex,
|
||||
_message: &mut Option<$crate::message::Message<$block>>
|
||||
) {
|
||||
$( self.$sub_protocol_name.on_message(ctx, who, message); )*
|
||||
$( self.$sub_protocol_name.on_message(_ctx, _who, _message); )*
|
||||
}
|
||||
|
||||
fn on_abort(&mut self) {
|
||||
$( self.$sub_protocol_name.on_abort(); )*
|
||||
}
|
||||
|
||||
fn maintain_peers(&mut self, ctx: &mut $crate::Context<$block>) {
|
||||
$( self.$sub_protocol_name.maintain_peers(ctx); )*
|
||||
fn maintain_peers(&mut self, _ctx: &mut $crate::Context<$block>) {
|
||||
$( self.$sub_protocol_name.maintain_peers(_ctx); )*
|
||||
}
|
||||
|
||||
fn on_block_imported(
|
||||
&mut self,
|
||||
ctx: &mut $crate::Context<$block>,
|
||||
hash: <$block as $crate::BlockT>::Hash,
|
||||
header: &<$block as $crate::BlockT>::Header
|
||||
_ctx: &mut $crate::Context<$block>,
|
||||
_hash: <$block as $crate::BlockT>::Hash,
|
||||
_header: &<$block as $crate::BlockT>::Header
|
||||
) {
|
||||
$( self.$sub_protocol_name.on_block_imported(ctx, hash, header); )*
|
||||
$( self.$sub_protocol_name.on_block_imported(_ctx, _hash, _header); )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +181,12 @@ impl<B: BlockT + 'static, S: Specialization<B>, H: ExHashT> Service<B, S, H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BlockT + 'static, S: Specialization<B>, H: ExHashT> ::consensus::SyncOracle for Service<B, S, H> {
|
||||
fn is_major_syncing(&self) -> bool {
|
||||
self.handler.sync().read().status().is_major_syncing()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BlockT + 'static, S: Specialization<B>, H:ExHashT> Drop for Service<B, S, H> {
|
||||
fn drop(&mut self) {
|
||||
self.handler.stop();
|
||||
|
||||
@@ -25,9 +25,6 @@ pub trait Specialization<B: BlockT>: Send + Sync + 'static {
|
||||
/// Get the current specialization-status.
|
||||
fn status(&self) -> Vec<u8>;
|
||||
|
||||
/// Called on start-up.
|
||||
fn on_start(&mut self) { }
|
||||
|
||||
/// Called when a peer successfully handshakes.
|
||||
fn on_connect(&mut self, ctx: &mut Context<B>, who: NodeIndex, status: ::message::Status<B>);
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use protocol::Context;
|
||||
use network_libp2p::{Severity, NodeIndex};
|
||||
use client::{BlockStatus, BlockOrigin, ClientInfo};
|
||||
use client::{BlockStatus, ClientInfo};
|
||||
use consensus::BlockOrigin;
|
||||
use client::error::Error as ClientError;
|
||||
use blocks::{self, BlockCollection};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor};
|
||||
@@ -77,6 +78,17 @@ pub struct Status<B: BlockT> {
|
||||
pub best_seen_block: Option<NumberFor<B>>,
|
||||
}
|
||||
|
||||
impl<B: BlockT> Status<B> {
|
||||
/// Whether the synchronization status is doing major downloading work or
|
||||
/// is near the head of the chain.
|
||||
pub fn is_major_syncing(&self) -> bool {
|
||||
match self.state {
|
||||
SyncState::Idle => false,
|
||||
SyncState::Downloading => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BlockT> ChainSync<B> {
|
||||
/// Create a new instance.
|
||||
pub(crate) fn new(role: Roles, info: &ClientInfo<B>, import_queue: Arc<ImportQueue<B>>) -> Self {
|
||||
|
||||
@@ -34,14 +34,16 @@ use service::TransactionPool;
|
||||
use network_libp2p::{NodeIndex, PeerId, Severity};
|
||||
use keyring::Keyring;
|
||||
use codec::Encode;
|
||||
use import_queue::{SyncImportQueue, PassThroughVerifier};
|
||||
use test_client::{self, TestClient};
|
||||
use import_queue::{SyncImportQueue, PassThroughVerifier, Verifier};
|
||||
use consensus::BlockOrigin;
|
||||
use specialization::Specialization;
|
||||
use consensus_gossip::ConsensusGossip;
|
||||
use import_queue::ImportQueue;
|
||||
use service::ExecuteInContext;
|
||||
use test_client;
|
||||
|
||||
pub use test_client::runtime::{Block, Hash, Transfer, Extrinsic};
|
||||
pub use test_client::TestClient;
|
||||
|
||||
struct DummyContextExecutor(Arc<Protocol<Block, DummySpecialization, Hash>>, Arc<RwLock<VecDeque<TestPacket>>>);
|
||||
unsafe impl Send for DummyContextExecutor {}
|
||||
@@ -135,20 +137,22 @@ pub struct TestPacket {
|
||||
recipient: NodeIndex,
|
||||
}
|
||||
|
||||
pub struct Peer {
|
||||
client: Arc<client::Client<test_client::Backend, test_client::Executor, Block>>,
|
||||
pub type PeersClient = client::Client<test_client::Backend, test_client::Executor, Block>;
|
||||
|
||||
pub struct Peer<V: Verifier<Block>> {
|
||||
client: Arc<PeersClient>,
|
||||
pub sync: Arc<Protocol<Block, DummySpecialization, Hash>>,
|
||||
pub queue: Arc<RwLock<VecDeque<TestPacket>>>,
|
||||
import_queue: Arc<SyncImportQueue<Block, PassThroughVerifier>>,
|
||||
import_queue: Arc<SyncImportQueue<Block, V>>,
|
||||
executor: Arc<DummyContextExecutor>,
|
||||
}
|
||||
|
||||
impl Peer {
|
||||
impl<V: 'static + Verifier<Block>> Peer<V> {
|
||||
fn new(
|
||||
client: Arc<client::Client<test_client::Backend, test_client::Executor, Block>>,
|
||||
client: Arc<PeersClient>,
|
||||
sync: Arc<Protocol<Block, DummySpecialization, Hash>>,
|
||||
queue: Arc<RwLock<VecDeque<TestPacket>>>,
|
||||
import_queue: Arc<SyncImportQueue<Block, PassThroughVerifier>>,
|
||||
import_queue: Arc<SyncImportQueue<Block, V>>,
|
||||
) -> Self {
|
||||
let executor = Arc::new(DummyContextExecutor(sync.clone(), queue.clone()));
|
||||
Peer { client, sync, queue, import_queue, executor}
|
||||
@@ -204,6 +208,13 @@ impl Peer {
|
||||
self.sync.tick(&mut TestIo::new(&self.queue, None));
|
||||
}
|
||||
|
||||
/// Send block import notifications.
|
||||
fn send_import_notifications(&self) {
|
||||
let info = self.client.info().expect("In-mem client does not fail");
|
||||
let header = self.client.header(&BlockId::Hash(info.chain.best_hash)).unwrap().unwrap();
|
||||
self.sync.on_block_imported(&mut TestIo::new(&self.queue, None), info.chain.best_hash, &header);
|
||||
}
|
||||
|
||||
/// Restart sync for a peer.
|
||||
fn restart_sync(&self) {
|
||||
self.sync.abort();
|
||||
@@ -221,15 +232,18 @@ impl Peer {
|
||||
}
|
||||
|
||||
/// Add blocks to the peer -- edit the block before adding
|
||||
pub fn generate_blocks<F>(&self, count: usize, mut edit_block: F)
|
||||
pub fn generate_blocks<F>(&self, count: usize, origin: BlockOrigin, mut edit_block: F)
|
||||
where F: FnMut(&mut BlockBuilder<test_client::Backend, test_client::Executor, Block, Blake2Hasher>)
|
||||
{
|
||||
for _ in 0 .. count {
|
||||
let mut builder = self.client.new_block().unwrap();
|
||||
edit_block(&mut builder);
|
||||
let block = builder.bake().unwrap();
|
||||
trace!("Generating {}, (#{}, parent={})", block.header.hash(), block.header.number, block.header.parent_hash);
|
||||
self.client.justify_and_import(client::BlockOrigin::File, block).unwrap();
|
||||
let hash = block.header.hash();
|
||||
trace!("Generating {}, (#{}, parent={})", hash, block.header.number, block.header.parent_hash);
|
||||
let header = block.header.clone();
|
||||
self.client.justify_and_import(origin, block).unwrap();
|
||||
self.sync.on_block_imported(&mut TestIo::new(&self.queue, None), hash, &header);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +251,7 @@ impl Peer {
|
||||
pub fn push_blocks(&self, count: usize, with_tx: bool) {
|
||||
let mut nonce = 0;
|
||||
if with_tx {
|
||||
self.generate_blocks(count, |builder| {
|
||||
self.generate_blocks(count, BlockOrigin::File, |builder| {
|
||||
let transfer = Transfer {
|
||||
from: Keyring::Alice.to_raw_public().into(),
|
||||
to: Keyring::Alice.to_raw_public().into(),
|
||||
@@ -249,7 +263,7 @@ impl Peer {
|
||||
nonce = nonce + 1;
|
||||
});
|
||||
} else {
|
||||
self.generate_blocks(count, |_| ());
|
||||
self.generate_blocks(count, BlockOrigin::File, |_| ());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +275,7 @@ impl Peer {
|
||||
}
|
||||
|
||||
/// Get a reference to the client.
|
||||
pub fn client(&self) -> &Arc<client::Client<test_client::Backend, test_client::Executor, Block>> {
|
||||
pub fn client(&self) -> &Arc<PeersClient> {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
@@ -280,25 +294,30 @@ impl TransactionPool<Hash, Block> for EmptyTransactionPool {
|
||||
fn on_broadcasted(&self, _: HashMap<Hash, Vec<String>>) {}
|
||||
}
|
||||
|
||||
pub struct TestNet {
|
||||
peers: Vec<Arc<Peer>>,
|
||||
started: bool,
|
||||
disconnect_events: Vec<(NodeIndex, NodeIndex)>, //disconnected (initiated by, to)
|
||||
}
|
||||
pub trait TestNetFactory: Sized {
|
||||
type Verifier: 'static + Verifier<Block>;
|
||||
|
||||
impl TestNet {
|
||||
/// Create new test network with this many peers.
|
||||
pub fn new(n: usize) -> Self {
|
||||
Self::new_with_config(n, ProtocolConfig::default())
|
||||
/// These two need to be implemented!
|
||||
fn from_config(config: &ProtocolConfig) -> Self;
|
||||
fn make_verifier(&self, client: Arc<PeersClient>, config: &ProtocolConfig) -> Arc<Self::Verifier>;
|
||||
|
||||
|
||||
/// Get reference to peer.
|
||||
fn peer(&self, i: usize) -> &Peer<Self::Verifier>;
|
||||
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier>>>;
|
||||
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier>>>)>(&mut self, closure: F );
|
||||
|
||||
fn started(&self) -> bool;
|
||||
fn set_started(&mut self, now: bool);
|
||||
|
||||
fn default_config() -> ProtocolConfig {
|
||||
ProtocolConfig::default()
|
||||
}
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
pub fn new_with_config(n: usize, config: ProtocolConfig) -> Self {
|
||||
let mut net = TestNet {
|
||||
peers: Vec::new(),
|
||||
started: false,
|
||||
disconnect_events: Vec::new(),
|
||||
};
|
||||
/// Create new test network with this many peers.
|
||||
fn new(n: usize) -> Self {
|
||||
let config = Self::default_config();
|
||||
let mut net = Self::from_config(&config);
|
||||
|
||||
for _ in 0..n {
|
||||
net.add_peer(&config);
|
||||
@@ -307,10 +326,11 @@ impl TestNet {
|
||||
}
|
||||
|
||||
/// Add a peer.
|
||||
pub fn add_peer(&mut self, config: &ProtocolConfig) {
|
||||
fn add_peer(&mut self, config: &ProtocolConfig) {
|
||||
let client = Arc::new(test_client::new());
|
||||
let tx_pool = Arc::new(EmptyTransactionPool);
|
||||
let import_queue = Arc::new(SyncImportQueue::new(Arc::new(PassThroughVerifier(false))));
|
||||
let verifier = self.make_verifier(client.clone(), config);
|
||||
let import_queue = Arc::new(SyncImportQueue::new(verifier));
|
||||
let specialization = DummySpecialization {
|
||||
gossip: ConsensusGossip::new(),
|
||||
};
|
||||
@@ -323,93 +343,107 @@ impl TestNet {
|
||||
specialization
|
||||
).unwrap();
|
||||
|
||||
self.peers.push(Arc::new(Peer::new(
|
||||
let peer = Arc::new(Peer::new(
|
||||
client,
|
||||
Arc::new(sync),
|
||||
Arc::new(RwLock::new(VecDeque::new())),
|
||||
import_queue
|
||||
)));
|
||||
}
|
||||
));
|
||||
|
||||
/// Get reference to peer.
|
||||
pub fn peer(&self, i: usize) -> &Peer {
|
||||
&self.peers[i]
|
||||
self.mut_peers(|peers| {
|
||||
peers.push(peer.clone())
|
||||
});
|
||||
}
|
||||
|
||||
/// Start network.
|
||||
fn start(&mut self) {
|
||||
if self.started {
|
||||
if self.started() {
|
||||
return;
|
||||
}
|
||||
for peer in 0..self.peers.len() {
|
||||
self.peers[peer].start();
|
||||
for client in 0..self.peers.len() {
|
||||
if peer != client {
|
||||
self.peers[peer].on_connect(client as NodeIndex);
|
||||
self.mut_peers(|peers| {
|
||||
for peer in 0..peers.len() {
|
||||
peers[peer].start();
|
||||
for client in 0..peers.len() {
|
||||
if peer != client {
|
||||
peers[peer].on_connect(client as NodeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.started = true;
|
||||
});
|
||||
self.set_started(true);
|
||||
}
|
||||
|
||||
/// Do one step of routing.
|
||||
pub fn route(&mut self) {
|
||||
for peer in 0..self.peers.len() {
|
||||
let packet = self.peers[peer].pending_message();
|
||||
if let Some(packet) = packet {
|
||||
let disconnecting = {
|
||||
let recipient = packet.recipient;
|
||||
trace!("--- {} -> {} ---", peer, recipient);
|
||||
let to_disconnect = self.peers[recipient].receive_message(peer as NodeIndex, packet);
|
||||
for d in &to_disconnect {
|
||||
// notify this that disconnecting peers are disconnecting
|
||||
self.peers[recipient].on_disconnect(*d as NodeIndex);
|
||||
self.disconnect_events.push((peer, *d));
|
||||
fn route(&mut self) {
|
||||
self.mut_peers(move |peers| {
|
||||
for peer in 0..peers.len() {
|
||||
let packet = peers[peer].pending_message();
|
||||
if let Some(packet) = packet {
|
||||
let disconnecting = {
|
||||
let recipient = packet.recipient;
|
||||
trace!(target: "sync", "--- {} -> {} ---", peer, recipient);
|
||||
let to_disconnect = peers[recipient].receive_message(peer as NodeIndex, packet);
|
||||
for d in &to_disconnect {
|
||||
// notify this that disconnecting peers are disconnecting
|
||||
peers[recipient].on_disconnect(*d as NodeIndex);
|
||||
}
|
||||
to_disconnect
|
||||
};
|
||||
for d in &disconnecting {
|
||||
// notify other peers that this peer is disconnecting
|
||||
peers[*d].on_disconnect(peer as NodeIndex);
|
||||
}
|
||||
to_disconnect
|
||||
};
|
||||
for d in &disconnecting {
|
||||
// notify other peers that this peer is disconnecting
|
||||
self.peers[*d].on_disconnect(peer as NodeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Route messages between peers until all queues are empty.
|
||||
pub fn route_until_complete(&mut self) {
|
||||
fn route_until_complete(&mut self) {
|
||||
while !self.done() {
|
||||
self.route()
|
||||
}
|
||||
}
|
||||
|
||||
/// Do a step of synchronization.
|
||||
pub fn sync_step(&mut self) {
|
||||
fn sync_step(&mut self) {
|
||||
self.route();
|
||||
|
||||
for peer in &mut self.peers {
|
||||
peer.sync_step();
|
||||
}
|
||||
self.mut_peers(|peers| {
|
||||
for peer in peers {
|
||||
peer.sync_step();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Send block import notifications for all peers.
|
||||
fn send_import_notifications(&mut self) {
|
||||
self.mut_peers(|peers| {
|
||||
for peer in peers {
|
||||
peer.send_import_notifications();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Restart sync for a peer.
|
||||
pub fn restart_peer(&mut self, i: usize) {
|
||||
self.peers[i].restart_sync();
|
||||
fn restart_peer(&mut self, i: usize) {
|
||||
self.peers()[i].restart_sync();
|
||||
}
|
||||
|
||||
/// Perform synchronization until complete.
|
||||
pub fn sync(&mut self) -> u32 {
|
||||
fn sync(&mut self) -> u32 {
|
||||
self.start();
|
||||
let mut total_steps = 0;
|
||||
while !self.done() {
|
||||
self.sync_step();
|
||||
total_steps += 1;
|
||||
self.route();
|
||||
}
|
||||
total_steps
|
||||
}
|
||||
|
||||
/// Do the given amount of sync steps.
|
||||
pub fn sync_steps(&mut self, count: usize) {
|
||||
fn sync_steps(&mut self, count: usize) {
|
||||
self.start();
|
||||
for _ in 0..count {
|
||||
self.sync_step();
|
||||
@@ -417,7 +451,50 @@ impl TestNet {
|
||||
}
|
||||
|
||||
/// Whether all peers have synced.
|
||||
pub fn done(&self) -> bool {
|
||||
self.peers.iter().all(|p| p.is_done())
|
||||
fn done(&self) -> bool {
|
||||
self.peers().iter().all(|p| p.is_done())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestNet {
|
||||
peers: Vec<Arc<Peer<PassThroughVerifier>>>,
|
||||
started: bool
|
||||
}
|
||||
|
||||
impl TestNetFactory for TestNet {
|
||||
type Verifier = PassThroughVerifier;
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
fn from_config(_config: &ProtocolConfig) -> Self {
|
||||
TestNet {
|
||||
peers: Vec::new(),
|
||||
started: false
|
||||
}
|
||||
}
|
||||
|
||||
fn make_verifier(&self, _client: Arc<PeersClient>, _config: &ProtocolConfig)
|
||||
-> Arc<Self::Verifier>
|
||||
{
|
||||
Arc::new(PassThroughVerifier(false))
|
||||
}
|
||||
|
||||
fn peer(&self, i: usize) -> &Peer<Self::Verifier> {
|
||||
&self.peers[i]
|
||||
}
|
||||
|
||||
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier>>> {
|
||||
&self.peers
|
||||
}
|
||||
|
||||
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier>>>)>(&mut self, closure: F ) {
|
||||
closure(&mut self.peers);
|
||||
}
|
||||
|
||||
fn started(&self) -> bool {
|
||||
self.started
|
||||
}
|
||||
|
||||
fn set_started(&mut self, new: bool) {
|
||||
self.started = new;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
use client::backend::Backend;
|
||||
use client::blockchain::HeaderBackend as BlockchainHeaderBackend;
|
||||
use consensus::BlockOrigin;
|
||||
use sync::SyncState;
|
||||
use Roles;
|
||||
use super::*;
|
||||
@@ -68,6 +69,7 @@ fn sync_no_common_longer_chain_fails() {
|
||||
fn sync_after_fork_works() {
|
||||
::env_logger::init().ok();
|
||||
let mut net = TestNet::new(3);
|
||||
net.sync_step();
|
||||
net.peer(0).push_blocks(30, false);
|
||||
net.peer(1).push_blocks(30, false);
|
||||
net.peer(2).push_blocks(30, false);
|
||||
@@ -87,6 +89,20 @@ fn sync_after_fork_works() {
|
||||
assert!(net.peer(2).client.backend().blockchain().canon_equals_to(&peer1_chain));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn own_blocks_are_announced() {
|
||||
::env_logger::init().ok();
|
||||
let mut net = TestNet::new(3);
|
||||
net.sync(); // connect'em
|
||||
net.peer(0).generate_blocks(1, BlockOrigin::Own, |_| ());
|
||||
net.sync();
|
||||
assert_eq!(net.peer(0).client.backend().blockchain().info().unwrap().best_number, 1);
|
||||
assert_eq!(net.peer(1).client.backend().blockchain().info().unwrap().best_number, 1);
|
||||
let peer0_chain = net.peer(0).client.backend().blockchain().clone();
|
||||
assert!(net.peer(1).client.backend().blockchain().canon_equals_to(&peer0_chain));
|
||||
assert!(net.peer(2).client.backend().blockchain().canon_equals_to(&peer0_chain));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocks_are_not_announced_by_light_nodes() {
|
||||
::env_logger::init().ok();
|
||||
|
||||
@@ -31,7 +31,7 @@ pub type Signature = H512;
|
||||
pub const PKCS_LEN: usize = 85;
|
||||
|
||||
/// A localized signature also contains sender information.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)]
|
||||
pub struct LocalizedSignature {
|
||||
/// The signer of the signature.
|
||||
pub signer: Public,
|
||||
@@ -40,6 +40,7 @@ pub struct LocalizedSignature {
|
||||
}
|
||||
|
||||
/// Verify a message without type checking the parameters' types for the right size.
|
||||
/// Returns true if the signature is good.
|
||||
pub fn verify<P: AsRef<[u8]>>(sig: &[u8], message: &[u8], public: P) -> bool {
|
||||
let public_key = untrusted::Input::from(public.as_ref());
|
||||
let msg = untrusted::Input::from(message);
|
||||
@@ -52,7 +53,7 @@ pub fn verify<P: AsRef<[u8]>>(sig: &[u8], message: &[u8], public: P) -> bool {
|
||||
}
|
||||
|
||||
/// A public key.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
pub struct Public(pub [u8; 32]);
|
||||
|
||||
/// A key pair.
|
||||
@@ -246,7 +247,7 @@ impl Pair {
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify a signature on a message.
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
pub fn verify_strong<P: AsRef<Public>>(sig: &Signature, message: &[u8], pubkey: P) -> bool {
|
||||
let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]);
|
||||
let msg = untrusted::Input::from(message);
|
||||
|
||||
@@ -22,5 +22,6 @@ tokio = "0.1.7"
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.1"
|
||||
substrate-test-client = { path = "../test-client" }
|
||||
substrate-consensus-common = { path = "../consensus/common" }
|
||||
rustc-hex = "2.0"
|
||||
hex-literal = "0.1"
|
||||
|
||||
@@ -26,7 +26,7 @@ use rpc::futures::{stream, Future, Sink, Stream};
|
||||
use runtime_primitives::generic::{BlockId, SignedBlock};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header, NumberFor};
|
||||
use runtime_version::RuntimeVersion;
|
||||
use primitives::{Blake2Hasher};
|
||||
use primitives::{Blake2Hasher, storage};
|
||||
|
||||
use subscriptions::Subscriptions;
|
||||
|
||||
@@ -68,6 +68,16 @@ build_rpc_trait! {
|
||||
#[rpc(name = "chain_unsubscribeNewHead", alias = ["unsubscribe_newHead", ])]
|
||||
fn unsubscribe_new_head(&self, SubscriptionId) -> RpcResult<bool>;
|
||||
}
|
||||
|
||||
#[pubsub(name = "chain_runtimeVersion")] {
|
||||
/// New runtime version subscription
|
||||
#[rpc(name = "chain_subscribeRuntimeVersion")]
|
||||
fn subscribe_runtime_version(&self, Self::Metadata, pubsub::Subscriber<RuntimeVersion>);
|
||||
|
||||
/// Unsubscribe from runtime version subscription
|
||||
#[rpc(name = "chain_unsubscribeRuntimeVersion")]
|
||||
fn unsubscribe_runtime_version(&self, SubscriptionId) -> RpcResult<bool>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,4 +173,53 @@ impl<B, E, Block> ChainApi<Block::Hash, Block::Header, NumberFor<Block>, Block::
|
||||
fn unsubscribe_new_head(&self, id: SubscriptionId) -> RpcResult<bool> {
|
||||
Ok(self.subscriptions.cancel(id))
|
||||
}
|
||||
|
||||
|
||||
fn subscribe_runtime_version(&self, _meta: Self::Metadata, subscriber: pubsub::Subscriber<RuntimeVersion>) {
|
||||
let stream = match self.client.storage_changes_notification_stream(Some(&[storage::StorageKey(storage::well_known_keys::CODE.to_vec())])) {
|
||||
Ok(stream) => stream,
|
||||
Err(err) => {
|
||||
let _ = subscriber.reject(error::Error::from(err).into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.subscriptions.add(subscriber, |sink| {
|
||||
let version = self.runtime_version(None.into())
|
||||
.map_err(Into::into);
|
||||
|
||||
let client = self.client.clone();
|
||||
let mut previous_version = version.clone();
|
||||
|
||||
let stream = stream
|
||||
.map_err(|e| warn!("Error creating storage notification stream: {:?}", e))
|
||||
.filter_map(move |_| {
|
||||
let version = client.info().and_then(|info| {
|
||||
client.runtime_version_at(&BlockId::hash(info.chain.best_hash))
|
||||
})
|
||||
.map_err(error::Error::from)
|
||||
.map_err(Into::into);
|
||||
if previous_version != version {
|
||||
previous_version = version.clone();
|
||||
Some(version)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
sink
|
||||
.sink_map_err(|e| warn!("Error sending notifications: {:?}", e))
|
||||
.send_all(
|
||||
stream::iter_result(vec![Ok(version)])
|
||||
.chain(stream)
|
||||
)
|
||||
// we ignore the resulting Stream (if the first stream is over we are unsubscribed)
|
||||
.map(|_| ())
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
fn unsubscribe_runtime_version(&self, id: SubscriptionId) -> RpcResult<bool> {
|
||||
Ok(self.subscriptions.cancel(id))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
use super::*;
|
||||
use jsonrpc_macros::pubsub;
|
||||
use client::BlockOrigin;
|
||||
use test_client::{self, TestClient};
|
||||
use test_client::runtime::{Block, Header};
|
||||
use consensus::BlockOrigin;
|
||||
|
||||
#[test]
|
||||
fn should_return_header() {
|
||||
|
||||
@@ -47,6 +47,8 @@ extern crate hex_literal;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_test_client as test_client;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_consensus_common as consensus;
|
||||
#[cfg(test)]
|
||||
extern crate rustc_hex;
|
||||
|
||||
mod errors;
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use client::{self, Client, CallExecutor, BlockchainEvents};
|
||||
use client::{self, Client, CallExecutor, BlockchainEvents, runtime_api::Metadata};
|
||||
use jsonrpc_macros::Trailing;
|
||||
use jsonrpc_macros::pubsub;
|
||||
use jsonrpc_pubsub::SubscriptionId;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use super::*;
|
||||
use self::error::{Error, ErrorKind};
|
||||
|
||||
use client::BlockOrigin;
|
||||
use consensus::BlockOrigin;
|
||||
use jsonrpc_macros::pubsub;
|
||||
use rustc_hex::FromHex;
|
||||
use test_client::{self, runtime, keyring::Keyring, TestClient, BlockBuilderExt};
|
||||
|
||||
@@ -20,6 +20,7 @@ substrate-keystore = { path = "../../core/keystore" }
|
||||
sr-io = { path = "../../core/sr-io" }
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
substrate-consensus-common = { path = "../../core/consensus/common" }
|
||||
substrate-network = { path = "../../core/network" }
|
||||
substrate-client = { path = "../../core/client" }
|
||||
substrate-client-db = { path = "../../core/client/db" }
|
||||
|
||||
@@ -20,11 +20,12 @@ use std::{self, io::{Read, Write}};
|
||||
use futures::Future;
|
||||
use serde_json;
|
||||
|
||||
use client::BlockOrigin;
|
||||
use runtime_primitives::generic::{SignedBlock, BlockId};
|
||||
use runtime_primitives::traits::{As, Block, Header};
|
||||
use network::import_queue::{ImportQueue, Link, BlockData};
|
||||
use network::message;
|
||||
|
||||
use consensus_common::BlockOrigin;
|
||||
use components::{self, Components, ServiceFactory, FactoryFullConfiguration, FactoryBlockNumber, RuntimeGenesis};
|
||||
use new_client;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
@@ -25,7 +25,7 @@ use chain_spec::ChainSpec;
|
||||
use client_db;
|
||||
use client::{self, Client};
|
||||
use {error, Service};
|
||||
use network::{self, OnDemand};
|
||||
use network::{self, OnDemand, import_queue::ImportQueue};
|
||||
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
|
||||
use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool};
|
||||
use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, BuildStorage};
|
||||
@@ -136,8 +136,10 @@ pub trait ServiceFactory: 'static + Sized {
|
||||
type FullService: Deref<Target = Service<FullComponents<Self>>> + Send + Sync + 'static;
|
||||
/// Extended light service type.
|
||||
type LightService: Deref<Target = Service<LightComponents<Self>>> + Send + Sync + 'static;
|
||||
/// ImportQueue
|
||||
type ImportQueue: network::import_queue::ImportQueue<Self::Block> + 'static;
|
||||
/// ImportQueue for full client
|
||||
type FullImportQueue: network::import_queue::ImportQueue<Self::Block> + 'static;
|
||||
/// ImportQueue for light clients
|
||||
type LightImportQueue: network::import_queue::ImportQueue<Self::Block> + 'static;
|
||||
|
||||
//TODO: replace these with a constructor trait. that TransactionPool implements.
|
||||
/// Extrinsic pool constructor for the full client.
|
||||
@@ -162,7 +164,7 @@ pub trait ServiceFactory: 'static + Sized {
|
||||
fn build_full_import_queue(
|
||||
config: &FactoryFullConfiguration<Self>,
|
||||
_client: Arc<FullClient<Self>>
|
||||
) -> Result<Self::ImportQueue, error::Error> {
|
||||
) -> Result<Self::FullImportQueue, error::Error> {
|
||||
if let Some(name) = config.chain_spec.consensus_engine() {
|
||||
match name {
|
||||
_ => Err(format!("Chain Specification defines unknown consensus engine '{}'", name).into())
|
||||
@@ -177,7 +179,7 @@ pub trait ServiceFactory: 'static + Sized {
|
||||
fn build_light_import_queue(
|
||||
config: &FactoryFullConfiguration<Self>,
|
||||
_client: Arc<LightClient<Self>>
|
||||
) -> Result<Self::ImportQueue, error::Error> {
|
||||
) -> Result<Self::LightImportQueue, error::Error> {
|
||||
if let Some(name) = config.chain_spec.consensus_engine() {
|
||||
match name {
|
||||
_ => Err(format!("Chain Specification defines unknown consensus engine '{}'", name).into())
|
||||
@@ -196,13 +198,16 @@ pub trait Components: 'static {
|
||||
/// Client backend.
|
||||
type Backend: 'static + client::backend::Backend<FactoryBlock<Self::Factory>, Blake2Hasher>;
|
||||
/// Client executor.
|
||||
type Executor: 'static + client::CallExecutor<FactoryBlock<Self::Factory>, Blake2Hasher> + Send + Sync;
|
||||
type Executor: 'static + client::CallExecutor<FactoryBlock<Self::Factory>, Blake2Hasher> + Send + Sync + Clone;
|
||||
/// Extrinsic pool type.
|
||||
type TransactionPoolApi: 'static + txpool::ChainApi<
|
||||
Hash = <<Self::Factory as ServiceFactory>::Block as BlockT>::Hash,
|
||||
Block = FactoryBlock<Self::Factory>
|
||||
>;
|
||||
|
||||
/// Our Import Queue
|
||||
type ImportQueue: ImportQueue<FactoryBlock<Self::Factory>> + 'static;
|
||||
|
||||
/// Create client.
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Self::Factory>,
|
||||
@@ -221,7 +226,7 @@ pub trait Components: 'static {
|
||||
fn build_import_queue(
|
||||
config: &FactoryFullConfiguration<Self::Factory>,
|
||||
client: Arc<ComponentClient<Self>>
|
||||
) -> Result<<Self::Factory as ServiceFactory>::ImportQueue, error::Error>;
|
||||
) -> Result<Self::ImportQueue, error::Error>;
|
||||
}
|
||||
|
||||
/// A struct that implement `Components` for the full client.
|
||||
@@ -234,6 +239,7 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
|
||||
type Executor = FullExecutor<Factory>;
|
||||
type Backend = FullBackend<Factory>;
|
||||
type TransactionPoolApi = <Factory as ServiceFactory>::FullTransactionPoolApi;
|
||||
type ImportQueue = Factory::FullImportQueue;
|
||||
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
@@ -267,7 +273,7 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
|
||||
fn build_import_queue(
|
||||
config: &FactoryFullConfiguration<Self::Factory>,
|
||||
client: Arc<ComponentClient<Self>>
|
||||
) -> Result<<Self::Factory as ServiceFactory>::ImportQueue, error::Error> {
|
||||
) -> Result<Self::ImportQueue, error::Error> {
|
||||
Factory::build_full_import_queue(config, client)
|
||||
}
|
||||
}
|
||||
@@ -282,6 +288,7 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
|
||||
type Executor = LightExecutor<Factory>;
|
||||
type Backend = LightBackend<Factory>;
|
||||
type TransactionPoolApi = <Factory as ServiceFactory>::LightTransactionPoolApi;
|
||||
type ImportQueue = <Factory as ServiceFactory>::LightImportQueue;
|
||||
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
@@ -316,7 +323,7 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
|
||||
fn build_import_queue(
|
||||
config: &FactoryFullConfiguration<Self::Factory>,
|
||||
client: Arc<ComponentClient<Self>>
|
||||
) -> Result<<Self::Factory as ServiceFactory>::ImportQueue, error::Error> {
|
||||
) -> Result<Self::ImportQueue, error::Error> {
|
||||
Factory::build_light_import_queue(config, client)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! provide consensus service to substrate.
|
||||
|
||||
// FIXME: move this into substrate-consensus-common - https://github.com/paritytech/substrate/issues/1021
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::{self, Duration, Instant};
|
||||
use std;
|
||||
|
||||
use client::{self, error, Client as SubstrateClient, CallExecutor};
|
||||
use client::runtime_api::{Core, BlockBuilder as BlockBuilderAPI, id::BLOCK_BUILDER};
|
||||
use codec::{Decode, Encode};
|
||||
use consensus_common::{self, InherentData, evaluation, offline_tracker::OfflineTracker};
|
||||
use primitives::{AuthorityId, ed25519, Blake2Hasher};
|
||||
use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use transaction_pool::txpool::{self, Pool as TransactionPool};
|
||||
|
||||
use parking_lot::RwLock;
|
||||
|
||||
/// Shared offline validator tracker.
|
||||
pub type SharedOfflineTracker = Arc<RwLock<OfflineTracker>>;
|
||||
type Timestamp = u64;
|
||||
|
||||
// block size limit.
|
||||
const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
/// Build new blocks.
|
||||
pub trait BlockBuilder<Block: BlockT> {
|
||||
/// Push an extrinsic onto the block. Fails if the extrinsic is invalid.
|
||||
fn push_extrinsic(&mut self, extrinsic: <Block as BlockT>::Extrinsic) -> Result<(), error::Error>;
|
||||
}
|
||||
|
||||
/// Local client abstraction for the consensus.
|
||||
pub trait AuthoringApi:
|
||||
Send
|
||||
+ Sync
|
||||
+ BlockBuilderAPI<<Self as AuthoringApi>::Block, Error=<Self as AuthoringApi>::Error>
|
||||
+ Core<<Self as AuthoringApi>::Block, AuthorityId, Error=<Self as AuthoringApi>::Error>
|
||||
{
|
||||
/// The block used for this API type.
|
||||
type Block: BlockT;
|
||||
/// The error used by this API type.
|
||||
type Error: std::error::Error;
|
||||
|
||||
/// Build a block on top of the given, with inherent extrinsics pre-pushed.
|
||||
fn build_block<F: FnMut(&mut BlockBuilder<Self::Block>) -> ()>(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
inherent_data: InherentData,
|
||||
build_ctx: F,
|
||||
) -> Result<Self::Block, error::Error>;
|
||||
}
|
||||
|
||||
impl<'a, B, E, Block> BlockBuilder<Block> for client::block_builder::BlockBuilder<'a, B, E, Block, Blake2Hasher> where
|
||||
B: client::backend::Backend<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone + 'static,
|
||||
Block: BlockT
|
||||
{
|
||||
fn push_extrinsic(&mut self, extrinsic: <Block as BlockT>::Extrinsic) -> Result<(), error::Error> {
|
||||
client::block_builder::BlockBuilder::push(self, extrinsic).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B, E, Block> AuthoringApi for SubstrateClient<B, E, Block> where
|
||||
B: client::backend::Backend<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone + 'static,
|
||||
Block: BlockT,
|
||||
{
|
||||
type Block = Block;
|
||||
type Error = client::error::Error;
|
||||
|
||||
fn build_block<F: FnMut(&mut BlockBuilder<Self::Block>) -> ()>(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
inherent_data: InherentData,
|
||||
mut build_ctx: F,
|
||||
) -> Result<Self::Block, error::Error> {
|
||||
let runtime_version = self.runtime_version_at(at)?;
|
||||
|
||||
let mut block_builder = self.new_block_at(at)?;
|
||||
if runtime_version.has_api(BLOCK_BUILDER, 1) {
|
||||
self.inherent_extrinsics(at, &inherent_data)?
|
||||
.into_iter().try_for_each(|i| block_builder.push(i))?;
|
||||
}
|
||||
|
||||
build_ctx(&mut block_builder);
|
||||
|
||||
block_builder.bake().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Proposer factory.
|
||||
pub struct ProposerFactory<C, A> where
|
||||
C: AuthoringApi,
|
||||
A: txpool::ChainApi,
|
||||
{
|
||||
/// The client instance.
|
||||
pub client: Arc<C>,
|
||||
/// The transaction pool.
|
||||
pub transaction_pool: Arc<TransactionPool<A>>,
|
||||
/// Offline-tracker.
|
||||
pub offline: SharedOfflineTracker,
|
||||
/// Force delay in evaluation this long.
|
||||
pub force_delay: Timestamp,
|
||||
}
|
||||
|
||||
impl<C, A> consensus_common::Environment<<C as AuthoringApi>::Block> for ProposerFactory<C, A> where
|
||||
C: AuthoringApi,
|
||||
A: txpool::ChainApi<Block=<C as AuthoringApi>::Block>,
|
||||
client::error::Error: From<<C as AuthoringApi>::Error>
|
||||
{
|
||||
type Proposer = Proposer<C, A>;
|
||||
type Error = error::Error;
|
||||
|
||||
fn init(
|
||||
&self,
|
||||
parent_header: &<<C as AuthoringApi>::Block as BlockT>::Header,
|
||||
_: &[AuthorityId],
|
||||
_: Arc<ed25519::Pair>,
|
||||
) -> Result<Self::Proposer, error::Error> {
|
||||
let parent_hash = parent_header.hash();
|
||||
|
||||
let id = BlockId::hash(parent_hash);
|
||||
|
||||
let authorities: Vec<AuthorityId> = self.client.authorities(&id)?;
|
||||
self.offline.write().note_new_block(&authorities[..]);
|
||||
|
||||
info!("Starting consensus session on top of parent {:?}", parent_hash);
|
||||
|
||||
let now = Instant::now();
|
||||
let proposer = Proposer {
|
||||
client: self.client.clone(),
|
||||
start: now,
|
||||
parent_hash,
|
||||
parent_id: id,
|
||||
parent_number: *parent_header.number(),
|
||||
transaction_pool: self.transaction_pool.clone(),
|
||||
offline: self.offline.clone(),
|
||||
authorities,
|
||||
minimum_timestamp: current_timestamp() + self.force_delay,
|
||||
};
|
||||
|
||||
Ok(proposer)
|
||||
}
|
||||
}
|
||||
|
||||
/// The proposer logic.
|
||||
pub struct Proposer<C: AuthoringApi, A: txpool::ChainApi> {
|
||||
client: Arc<C>,
|
||||
start: Instant,
|
||||
parent_hash: <<C as AuthoringApi>::Block as BlockT>::Hash,
|
||||
parent_id: BlockId<<C as AuthoringApi>::Block>,
|
||||
parent_number: <<<C as AuthoringApi>::Block as BlockT>::Header as HeaderT>::Number,
|
||||
transaction_pool: Arc<TransactionPool<A>>,
|
||||
offline: SharedOfflineTracker,
|
||||
authorities: Vec<AuthorityId>,
|
||||
minimum_timestamp: u64,
|
||||
}
|
||||
|
||||
impl<C, A> consensus_common::Proposer<<C as AuthoringApi>::Block> for Proposer<C, A> where
|
||||
C: AuthoringApi,
|
||||
A: txpool::ChainApi<Block=<C as AuthoringApi>::Block>,
|
||||
client::error::Error: From<<C as AuthoringApi>::Error>
|
||||
{
|
||||
type Create = Result<<C as AuthoringApi>::Block, error::Error>;
|
||||
type Error = error::Error;
|
||||
|
||||
fn propose(&self) -> Result<<C as AuthoringApi>::Block, error::Error> {
|
||||
use runtime_primitives::traits::BlakeTwo256;
|
||||
|
||||
const MAX_VOTE_OFFLINE_SECONDS: Duration = Duration::from_secs(60);
|
||||
|
||||
let timestamp = ::std::cmp::max(self.minimum_timestamp, current_timestamp());
|
||||
|
||||
let elapsed_since_start = self.start.elapsed();
|
||||
let offline_indices = if elapsed_since_start > MAX_VOTE_OFFLINE_SECONDS {
|
||||
Vec::new()
|
||||
} else {
|
||||
self.offline.read().reports(&self.authorities[..])
|
||||
};
|
||||
|
||||
if !offline_indices.is_empty() {
|
||||
info!("Submitting offline authorities {:?} for slash-vote",
|
||||
offline_indices.iter().map(|&i| self.authorities[i as usize]).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
|
||||
let inherent_data = InherentData {
|
||||
timestamp,
|
||||
offline_indices,
|
||||
};
|
||||
|
||||
let block = self.client.build_block(
|
||||
&self.parent_id,
|
||||
inherent_data,
|
||||
|block_builder| {
|
||||
let mut unqueue_invalid = Vec::new();
|
||||
let mut pending_size = 0;
|
||||
let pending_iterator = self.transaction_pool.ready();
|
||||
|
||||
for pending in pending_iterator {
|
||||
// TODO [ToDr] Probably get rid of it, and validate in runtime.
|
||||
let encoded_size = pending.data.encode().len();
|
||||
if pending_size + encoded_size >= MAX_TRANSACTIONS_SIZE { break }
|
||||
|
||||
match block_builder.push_extrinsic(pending.data.clone()) {
|
||||
Ok(()) => {
|
||||
pending_size += encoded_size;
|
||||
}
|
||||
Err(e) => {
|
||||
trace!(target: "transaction-pool", "Invalid transaction: {}", e);
|
||||
unqueue_invalid.push(pending.hash.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.transaction_pool.remove_invalid(&unqueue_invalid);
|
||||
})?;
|
||||
|
||||
info!("Proposing block [number: {}; hash: {}; parent_hash: {}; extrinsics: [{}]]",
|
||||
block.header().number(),
|
||||
<<C as AuthoringApi>::Block as BlockT>::Hash::from(block.header().hash()),
|
||||
block.header().parent_hash(),
|
||||
block.extrinsics().iter()
|
||||
.map(|xt| format!("{}", BlakeTwo256::hash_of(xt)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
|
||||
let substrate_block = Decode::decode(&mut block.encode().as_slice())
|
||||
.expect("blocks are defined to serialize to substrate blocks correctly; qed");
|
||||
|
||||
assert!(evaluation::evaluate_initial(
|
||||
&substrate_block,
|
||||
&self.parent_hash,
|
||||
self.parent_number,
|
||||
).is_ok());
|
||||
|
||||
Ok(substrate_block)
|
||||
}
|
||||
}
|
||||
|
||||
fn current_timestamp() -> Timestamp {
|
||||
time::SystemTime::now().duration_since(time::UNIX_EPOCH)
|
||||
.expect("now always later than unix epoch; qed")
|
||||
.as_secs()
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Substrate service. Starts a thread that spins the network, the client and the extrinsic pool.
|
||||
//! Substrate service. Starts a thread that spins up the network, client, and extrinsic pool.
|
||||
//! Manages communication between them.
|
||||
// end::description[]
|
||||
|
||||
@@ -29,6 +29,7 @@ extern crate parking_lot;
|
||||
extern crate substrate_keystore as keystore;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate substrate_consensus_common as consensus_common;
|
||||
extern crate substrate_network as network;
|
||||
extern crate substrate_executor;
|
||||
extern crate substrate_client as client;
|
||||
@@ -56,6 +57,7 @@ mod error;
|
||||
mod chain_spec;
|
||||
pub mod config;
|
||||
pub mod chain_ops;
|
||||
pub mod consensus;
|
||||
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
@@ -63,7 +65,7 @@ use std::collections::HashMap;
|
||||
#[doc(hidden)]
|
||||
pub use std::{ops::Deref, result::Result, sync::Arc};
|
||||
use futures::prelude::*;
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use keystore::Store as Keystore;
|
||||
use client::BlockchainEvents;
|
||||
use runtime_primitives::traits::{Header, As};
|
||||
@@ -80,6 +82,8 @@ pub use chain_spec::ChainSpec;
|
||||
pub use transaction_pool::txpool::{self, Pool as TransactionPool, Options as TransactionPoolOptions, ChainApi, IntoPoolError};
|
||||
pub use client::ExecutionStrategy;
|
||||
|
||||
use consensus_common::offline_tracker::OfflineTracker;
|
||||
pub use consensus::ProposerFactory;
|
||||
pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend,
|
||||
LightExecutor, Components, PoolApi, ComponentClient,
|
||||
ComponentBlock, FullClient, LightClient, FullComponents, LightComponents,
|
||||
@@ -98,6 +102,7 @@ pub struct Service<Components: components::Components> {
|
||||
keystore: Keystore,
|
||||
exit: ::exit_future::Exit,
|
||||
signal: Option<Signal>,
|
||||
proposer: Arc<ProposerFactory<ComponentClient<Components>, Components::TransactionPoolApi>>,
|
||||
_rpc_http: Option<rpc::HttpServer>,
|
||||
_rpc_ws: Option<Mutex<rpc::WsServer>>, // WsServer is not `Sync`, but the service needs to be.
|
||||
_telemetry: Option<tel::Telemetry>,
|
||||
@@ -118,6 +123,7 @@ pub fn new_client<Factory: components::ServiceFactory>(config: &FactoryFullConfi
|
||||
impl<Components> Service<Components>
|
||||
where
|
||||
Components: components::Components,
|
||||
<Components as components::Components>::Executor: std::clone::Clone,
|
||||
txpool::ExHash<Components::TransactionPoolApi>: serde::de::DeserializeOwned + serde::Serialize,
|
||||
txpool::ExtrinsicFor<Components::TransactionPoolApi>: serde::de::DeserializeOwned + serde::Serialize,
|
||||
{
|
||||
@@ -254,6 +260,13 @@ impl<Components> Service<Components>
|
||||
)
|
||||
};
|
||||
|
||||
let proposer = Arc::new(ProposerFactory {
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
offline: Arc::new(RwLock::new(OfflineTracker::new())),
|
||||
force_delay: 0 // FIXME: allow this to be configured
|
||||
});
|
||||
|
||||
// Telemetry
|
||||
let telemetry = match config.telemetry_url {
|
||||
Some(url) => {
|
||||
@@ -287,6 +300,7 @@ impl<Components> Service<Components>
|
||||
transaction_pool: transaction_pool,
|
||||
signal: Some(signal),
|
||||
keystore: keystore,
|
||||
proposer,
|
||||
exit,
|
||||
_rpc_http: rpc_http,
|
||||
_rpc_ws: rpc_ws.map(Mutex::new),
|
||||
@@ -303,6 +317,13 @@ impl<Components> Service<Components> where
|
||||
self.client.clone()
|
||||
}
|
||||
|
||||
/// Get shared proposer instance
|
||||
pub fn proposer(&self)
|
||||
-> Arc<ProposerFactory<ComponentClient<Components>, Components::TransactionPoolApi>>
|
||||
{
|
||||
self.proposer.clone()
|
||||
}
|
||||
|
||||
/// Get shared network instance.
|
||||
pub fn network(&self) -> Arc<components::NetworkService<Components::Factory>> {
|
||||
self.network.as_ref().expect("self.network always Some").clone()
|
||||
@@ -324,6 +345,7 @@ impl<Components> Service<Components> where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<Components> Drop for Service<Components> where Components: components::Components {
|
||||
fn drop(&mut self) {
|
||||
debug!(target: "service", "Substrate service shutdown");
|
||||
@@ -450,7 +472,7 @@ macro_rules! construct_simple_service {
|
||||
$name: ident
|
||||
) => {
|
||||
pub struct $name<C: $crate::Components> {
|
||||
inner: $crate::Service<C>,
|
||||
inner: $crate::Arc<$crate::Service<C>>,
|
||||
}
|
||||
|
||||
impl<C: $crate::Components> $name<C> {
|
||||
@@ -460,7 +482,7 @@ macro_rules! construct_simple_service {
|
||||
) -> $crate::Result<Self, $crate::Error> {
|
||||
Ok(
|
||||
Self {
|
||||
inner: $crate::Service::new(config, executor)?
|
||||
inner: $crate::Arc::new($crate::Service::new(config, executor)?)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -525,8 +547,9 @@ macro_rules! construct_service_factory {
|
||||
Configuration = $config:ty,
|
||||
FullService = $full_service:ty { $( $full_service_init:tt )* },
|
||||
LightService = $light_service:ty { $( $light_service_init:tt )* },
|
||||
ImportQueue = $import_queue:ty
|
||||
{ $( $full_import_queue_init:tt )* }
|
||||
FullImportQueue = $full_import_queue:ty
|
||||
{ $( $full_import_queue_init:tt )* },
|
||||
LightImportQueue = $light_import_queue:ty
|
||||
{ $( $light_import_queue_init:tt )* },
|
||||
}
|
||||
) => {
|
||||
@@ -544,7 +567,8 @@ macro_rules! construct_service_factory {
|
||||
type Configuration = $config;
|
||||
type FullService = $full_service;
|
||||
type LightService = $light_service;
|
||||
type ImportQueue = $import_queue;
|
||||
type FullImportQueue = $full_import_queue;
|
||||
type LightImportQueue = $light_import_queue;
|
||||
|
||||
fn build_full_transaction_pool(
|
||||
config: $crate::TransactionPoolOptions,
|
||||
@@ -571,14 +595,14 @@ macro_rules! construct_service_factory {
|
||||
fn build_full_import_queue(
|
||||
config: &$crate::FactoryFullConfiguration<Self>,
|
||||
client: $crate::Arc<$crate::FullClient<Self>>,
|
||||
) -> $crate::Result<Self::ImportQueue, $crate::Error> {
|
||||
) -> $crate::Result<Self::FullImportQueue, $crate::Error> {
|
||||
( $( $full_import_queue_init )* ) (config, client)
|
||||
}
|
||||
|
||||
fn build_light_import_queue(
|
||||
config: &FactoryFullConfiguration<Self>,
|
||||
client: Arc<$crate::LightClient<Self>>,
|
||||
) -> Result<Self::ImportQueue, $crate::Error> {
|
||||
) -> Result<Self::LightImportQueue, $crate::Error> {
|
||||
( $( $light_import_queue_init )* ) (config, client)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ env_logger = "0.4"
|
||||
fdlimit = "0.1"
|
||||
substrate-service = { path = "../../../core/service" }
|
||||
substrate-network = { path = "../../../core/network" }
|
||||
substrate-consensus-common = { path = "../../../core/consensus/common" }
|
||||
substrate-primitives = { path = "../../../core/primitives" }
|
||||
substrate-client = { path = "../../../core/client" }
|
||||
sr-primitives = { path = "../../../core/sr-primitives" }
|
||||
|
||||
@@ -27,6 +27,7 @@ extern crate substrate_service as service;
|
||||
extern crate substrate_network as network;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate substrate_client as client;
|
||||
extern crate substrate_consensus_common as consensus;
|
||||
extern crate sr_primitives;
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
@@ -47,9 +48,9 @@ use service::{
|
||||
FactoryExtrinsic,
|
||||
};
|
||||
use network::{NetworkConfiguration, NonReservedPeerMode, Protocol, SyncProvider, ManageNetwork};
|
||||
use client::ImportBlock;
|
||||
use sr_primitives::traits::As;
|
||||
use sr_primitives::generic::BlockId;
|
||||
use consensus::{ImportBlock, BlockImport};
|
||||
|
||||
struct TestNet<F: ServiceFactory> {
|
||||
runtime: Runtime,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
= Runtime API
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -14,7 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! API's for interfacing with the runtime via native/wasm.
|
||||
// end::description[]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
@@ -26,7 +28,7 @@ extern crate sr_version as runtime_version;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use primitives::{traits::Block as BlockT, generic::BlockId, transaction_validity::TransactionValidity, ApplyResult};
|
||||
use runtime_version::RuntimeVersion;
|
||||
use runtime_version::{ApiId, RuntimeVersion};
|
||||
use rstd::vec::Vec;
|
||||
#[doc(hidden)]
|
||||
pub use rstd::slice;
|
||||
@@ -427,6 +429,20 @@ macro_rules! decl_apis {
|
||||
};
|
||||
}
|
||||
|
||||
/// The ApiIds for the various standard runtime APIs.
|
||||
pub mod id {
|
||||
use super::ApiId;
|
||||
|
||||
/// ApiId for the BlockBuilder trait.
|
||||
pub const BLOCK_BUILDER: ApiId = *b"blkbuild";
|
||||
|
||||
/// ApiId for the TaggedTransactionQueue trait.
|
||||
pub const TAGGED_TRANSACTION_QUEUE: ApiId = *b"validatx";
|
||||
|
||||
/// ApiId for the Metadata trait.
|
||||
pub const METADATA: ApiId = *b"metadata";
|
||||
}
|
||||
|
||||
decl_apis! {
|
||||
/// The `Core` api trait that is mandantory for each runtime.
|
||||
pub trait Core<Block: BlockT, AuthorityId> {
|
||||
@@ -436,8 +452,8 @@ decl_apis! {
|
||||
}
|
||||
|
||||
/// The `Metadata` api trait that returns metadata for the runtime.
|
||||
pub trait Metadata {
|
||||
fn metadata() -> Vec<u8>;
|
||||
pub trait Metadata<Data> {
|
||||
fn metadata() -> Data;
|
||||
}
|
||||
|
||||
/// The `OldTxQueue` api trait for interfering with the old transaction queue.
|
||||
@@ -451,13 +467,6 @@ decl_apis! {
|
||||
fn validate_transaction<TransactionValidity>(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
|
||||
}
|
||||
|
||||
/// The `Miscellaneous` api trait for getting miscellaneous information from the runtime.
|
||||
pub trait Miscellaneous {
|
||||
fn validator_count() -> u32;
|
||||
fn validators<AccountId>() -> Vec<AccountId>;
|
||||
fn timestamp<Moment>() -> Moment;
|
||||
}
|
||||
|
||||
/// The `BlockBuilder` api trait that provides required functions for building a block for a runtime.
|
||||
pub trait BlockBuilder<Block: BlockT> ExtraClientSide <OverlayedChanges> {
|
||||
/// Initialise a block with the given header.
|
||||
|
||||
@@ -31,3 +31,4 @@ std = [
|
||||
"substrate-primitives/std",
|
||||
]
|
||||
api-for-runtime = []
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
= Runtime Primitives
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -21,6 +21,8 @@ use rstd::prelude::*;
|
||||
use codec::{Decode, Encode, Codec, Input};
|
||||
use traits::{self, Member, DigestItem as DigestItemT};
|
||||
|
||||
use substrate_primitives::hash::H512 as Signature;
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
|
||||
pub struct Digest<Item> {
|
||||
@@ -46,6 +48,10 @@ impl<Item> traits::Digest for Digest<Item> where
|
||||
fn push(&mut self, item: Self::Item) {
|
||||
self.logs.push(item);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<Self::Item> {
|
||||
self.logs.pop()
|
||||
}
|
||||
}
|
||||
|
||||
/// Digest item that is able to encode/decode 'system' digest items and
|
||||
@@ -60,10 +66,13 @@ pub enum DigestItem<Hash, AuthorityId> {
|
||||
/// block. It is created for every block iff runtime supports changes
|
||||
/// trie creation.
|
||||
ChangesTrieRoot(Hash),
|
||||
/// Put a Seal on it
|
||||
Seal(u64, Signature),
|
||||
/// Any 'non-system' digest item, opaque to the native code.
|
||||
Other(Vec<u8>),
|
||||
}
|
||||
|
||||
|
||||
/// A 'referencing view' for digest item. Does not own its contents. Used by
|
||||
/// final runtime implementations for encoding/decoding its log items.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
@@ -73,6 +82,9 @@ pub enum DigestItemRef<'a, Hash: 'a, AuthorityId: 'a> {
|
||||
AuthoritiesChange(&'a [AuthorityId]),
|
||||
/// Reference to `DigestItem::ChangesTrieRoot`.
|
||||
ChangesTrieRoot(&'a Hash),
|
||||
/// A sealed signature for testing
|
||||
Seal(&'a u64, &'a Signature),
|
||||
/// Any 'non-system' digest item, opaque to the native code.
|
||||
/// Reference to `DigestItem::Other`.
|
||||
Other(&'a Vec<u8>),
|
||||
}
|
||||
@@ -87,6 +99,7 @@ enum DigestItemType {
|
||||
Other = 0,
|
||||
AuthoritiesChange,
|
||||
ChangesTrieRoot,
|
||||
Seal,
|
||||
}
|
||||
|
||||
impl<Hash, AuthorityId> DigestItem<Hash, AuthorityId> {
|
||||
@@ -103,6 +116,7 @@ impl<Hash, AuthorityId> DigestItem<Hash, AuthorityId> {
|
||||
match *self {
|
||||
DigestItem::AuthoritiesChange(ref v) => DigestItemRef::AuthoritiesChange(v),
|
||||
DigestItem::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v),
|
||||
DigestItem::Seal(ref v, ref s) => DigestItemRef::Seal(v, s),
|
||||
DigestItem::Other(ref v) => DigestItemRef::Other(v),
|
||||
}
|
||||
}
|
||||
@@ -137,6 +151,10 @@ impl<Hash: Decode, AuthorityId: Decode> Decode for DigestItem<Hash, AuthorityId>
|
||||
DigestItemType::ChangesTrieRoot => Some(DigestItem::ChangesTrieRoot(
|
||||
Decode::decode(input)?,
|
||||
)),
|
||||
DigestItemType::Seal => {
|
||||
let vals: (u64, Signature) = Decode::decode(input)?;
|
||||
Some(DigestItem::Seal(vals.0, vals.1))
|
||||
},
|
||||
DigestItemType::Other => Some(DigestItem::Other(
|
||||
Decode::decode(input)?,
|
||||
)),
|
||||
@@ -173,6 +191,10 @@ impl<'a, Hash: Encode, AuthorityId: Encode> Encode for DigestItemRef<'a, Hash, A
|
||||
DigestItemType::ChangesTrieRoot.encode_to(&mut v);
|
||||
changes_trie_root.encode_to(&mut v);
|
||||
},
|
||||
DigestItemRef::Seal(val, sig) => {
|
||||
DigestItemType::Seal.encode_to(&mut v);
|
||||
(val, sig).encode_to(&mut v);
|
||||
},
|
||||
DigestItemRef::Other(val) => {
|
||||
DigestItemType::Other.encode_to(&mut v);
|
||||
val.encode_to(&mut v);
|
||||
|
||||
@@ -137,6 +137,7 @@ impl<Number, Hash, DigestItem> traits::Header for Header<Number, Hash, DigestIte
|
||||
fn set_parent_hash(&mut self, hash: Self::Hash) { self.parent_hash = hash }
|
||||
|
||||
fn digest(&self) -> &Self::Digest { &self.digest }
|
||||
fn digest_mut(&mut self) -> &mut Self::Digest { &mut self.digest }
|
||||
fn set_digest(&mut self, digest: Self::Digest) { self.digest = digest }
|
||||
|
||||
fn new(
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code
|
||||
//! and depositing logs.
|
||||
// end::description[]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ impl traits::Digest for Digest {
|
||||
fn push(&mut self, item: Self::Item) {
|
||||
self.logs.push(item);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<Self::Item> {
|
||||
self.logs.pop()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug, Encode, Decode)]
|
||||
@@ -74,6 +78,7 @@ impl traits::Header for Header {
|
||||
fn set_parent_hash(&mut self, hash: Self::Hash) { self.parent_hash = hash }
|
||||
|
||||
fn digest(&self) -> &Self::Digest { &self.digest }
|
||||
fn digest_mut(&mut self) -> &mut Self::Digest { &mut self.digest }
|
||||
fn set_digest(&mut self, digest: Self::Digest) { self.digest = digest }
|
||||
|
||||
fn new(
|
||||
|
||||
@@ -197,11 +197,13 @@ impl<T: Default + Eq + PartialEq> Clear for T {
|
||||
pub trait SimpleBitOps:
|
||||
Sized + Clear +
|
||||
rstd::ops::BitOr<Self, Output = Self> +
|
||||
rstd::ops::BitXor<Self, Output = Self> +
|
||||
rstd::ops::BitAnd<Self, Output = Self>
|
||||
{}
|
||||
impl<T:
|
||||
Sized + Clear +
|
||||
rstd::ops::BitOr<Self, Output = Self> +
|
||||
rstd::ops::BitXor<Self, Output = Self> +
|
||||
rstd::ops::BitAnd<Self, Output = Self>
|
||||
> SimpleBitOps for T {}
|
||||
|
||||
@@ -429,6 +431,8 @@ pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebug + 'stat
|
||||
fn set_parent_hash(&mut self, Self::Hash);
|
||||
|
||||
fn digest(&self) -> &Self::Digest;
|
||||
/// Get a mutable reference to the digest.
|
||||
fn digest_mut(&mut self) -> &mut Self::Digest;
|
||||
fn set_digest(&mut self, Self::Digest);
|
||||
|
||||
fn hash(&self) -> Self::Hash {
|
||||
@@ -520,6 +524,8 @@ pub trait Digest: Member + Default {
|
||||
fn logs(&self) -> &[Self::Item];
|
||||
/// Push new digest item.
|
||||
fn push(&mut self, item: Self::Item);
|
||||
/// Pop a digest item.
|
||||
fn pop(&mut self) -> Option<Self::Item>;
|
||||
|
||||
/// Get reference to the first digest item that matches the passed predicate.
|
||||
fn log<T, F: Fn(&Self::Item) -> Option<&T>>(&self, predicate: F) -> Option<&T> {
|
||||
|
||||
@@ -15,25 +15,25 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! This crate provides means of instantiation and execution of wasm modules.
|
||||
//! This crate provides means to instantiate and execute wasm modules.
|
||||
//!
|
||||
//! It works even when the user of this library is itself executes
|
||||
//! inside the wasm VM. In this case same VM is used for execution
|
||||
//! It works even when the user of this library executes from
|
||||
//! inside the wasm VM. In this case the same VM is used for execution
|
||||
//! of both the sandbox owner and the sandboxed module, without compromising security
|
||||
//! and without performance penalty of full wasm emulation inside wasm.
|
||||
//! and without the performance penalty of full wasm emulation inside wasm.
|
||||
//!
|
||||
//! This is achieved by using bindings to wasm VM which are published by the host API.
|
||||
//! This API is thin and consists of only handful functions. It contains functions for instantiating
|
||||
//! modules and executing them and for example doesn't contain functions for inspecting the module
|
||||
//! structure. The user of this library is supposed to read wasm module by it's own means.
|
||||
//! This is achieved by using bindings to the wasm VM, which are published by the host API.
|
||||
//! This API is thin and consists of only a handful functions. It contains functions for instantiating
|
||||
//! modules and executing them, but doesn't contain functions for inspecting the module
|
||||
//! structure. The user of this library is supposed to read the wasm module.
|
||||
//!
|
||||
//! When this crate is used in `std` environment all these functions are implemented by directly
|
||||
//! calling wasm VM.
|
||||
//! When this crate is used in the `std` environment all these functions are implemented by directly
|
||||
//! calling the wasm VM.
|
||||
//!
|
||||
//! Example of possible use-cases for this library are following:
|
||||
//! Example of possible use-cases for this library are the following:
|
||||
//!
|
||||
//! - implementing smart-contract runtimes which uses wasm for contract code
|
||||
//! - executing wasm substrate runtime inside of a wasm parachain
|
||||
//! - implementing smart-contract runtimes that use wasm for contract code
|
||||
//! - executing a wasm substrate runtime inside of a wasm parachain
|
||||
//! - etc
|
||||
// end::description[]
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
= Runtime Version
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -14,7 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Version module for runtime; Provide a function that returns runtime version.
|
||||
// tag::description[]
|
||||
//! Version module for the Substrate runtime; Provides a function that returns the runtime version.
|
||||
// end::description[]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ pub use overlayed_changes::OverlayedChanges;
|
||||
pub use trie_backend_essence::Storage;
|
||||
pub use trie_backend::TrieBackend;
|
||||
|
||||
/// Default num of pages for the heap
|
||||
const DEFAULT_HEAP_PAGES :u64 = 1024;
|
||||
|
||||
/// State Machine Error bound.
|
||||
///
|
||||
/// This should reflect WASM error type bound for future compatibility.
|
||||
@@ -291,7 +294,7 @@ where
|
||||
.to_vec();
|
||||
|
||||
let heap_pages = try_read_overlay_value(overlay, backend, well_known_keys::HEAP_PAGES)?
|
||||
.and_then(|v| u64::decode(&mut &v[..])).unwrap_or(8) as usize;
|
||||
.and_then(|v| u64::decode(&mut &v[..])).unwrap_or(DEFAULT_HEAP_PAGES) as usize;
|
||||
|
||||
// read changes trie configuration. The reason why we're doing it here instead of the
|
||||
// `OverlayedChanges` constructor is that we need proofs for this read as a part of
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// tag::description[]
|
||||
//! Telemetry utils.
|
||||
//!
|
||||
//! `telemetry` macro be used from whereever in the Substrate codebase
|
||||
//! `telemetry` macro may be used anywhere in the Substrate codebase
|
||||
//! in order to send real-time logging information to the telemetry
|
||||
//! server (if there is one). We use the async drain adapter of `slog`
|
||||
//! so that the logging thread doesn't get held up at all.
|
||||
|
||||
@@ -7,6 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
substrate-client = { path = "../client" }
|
||||
parity-codec = "2.1"
|
||||
substrate-executor = { path = "../executor" }
|
||||
substrate-consensus-common = { path = "../consensus/common" }
|
||||
substrate-keyring = { path = "../../core/keyring" }
|
||||
substrate-primitives = { path = "../primitives" }
|
||||
substrate-test-runtime = { path = "../test-runtime" }
|
||||
|
||||
@@ -16,15 +16,17 @@
|
||||
|
||||
//! Client extension for tests.
|
||||
|
||||
use client::{self, ImportBlock, Client};
|
||||
use client::{self, Client};
|
||||
use consensus::{ImportBlock, BlockImport, BlockOrigin};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use primitives::Blake2Hasher;
|
||||
use runtime;
|
||||
|
||||
/// Extension trait for a test client.
|
||||
pub trait TestClient {
|
||||
pub trait TestClient: Sized {
|
||||
/// Justify and import block to the chain. No finality.
|
||||
fn justify_and_import(&self, origin: client::BlockOrigin, block: runtime::Block) -> client::error::Result<()>;
|
||||
fn justify_and_import(&self, origin: BlockOrigin, block: runtime::Block)
|
||||
-> client::error::Result<()>;
|
||||
|
||||
/// Finalize a block.
|
||||
fn finalize_block(&self, id: BlockId<runtime::Block>) -> client::error::Result<()>;
|
||||
@@ -36,21 +38,23 @@ pub trait TestClient {
|
||||
impl<B, E> TestClient for Client<B, E, runtime::Block>
|
||||
where
|
||||
B: client::backend::Backend<runtime::Block, Blake2Hasher>,
|
||||
E: client::CallExecutor<runtime::Block, Blake2Hasher>
|
||||
E: client::CallExecutor<runtime::Block, Blake2Hasher>,
|
||||
Self: BlockImport<runtime::Block, Error=client::error::Error>
|
||||
{
|
||||
fn justify_and_import(&self, origin: client::BlockOrigin, block: runtime::Block) -> client::error::Result<()> {
|
||||
fn justify_and_import(&self, origin: BlockOrigin, block: runtime::Block)
|
||||
-> client::error::Result<()>
|
||||
{
|
||||
let import = ImportBlock {
|
||||
origin,
|
||||
header: block.header,
|
||||
external_justification: vec![],
|
||||
internal_justification: vec![],
|
||||
post_runtime_digests: vec![],
|
||||
body: Some(block.extrinsics),
|
||||
finalized: false,
|
||||
auxiliary: Vec::new(),
|
||||
};
|
||||
self.import_block(import, None)?;
|
||||
|
||||
Ok(())
|
||||
self.import_block(import, None).map(|_| ())
|
||||
}
|
||||
|
||||
fn finalize_block(&self, id: BlockId<runtime::Block>) -> client::error::Result<()> {
|
||||
|
||||
@@ -28,6 +28,7 @@ extern crate sr_primitives as runtime_primitives;
|
||||
pub extern crate substrate_client as client;
|
||||
pub extern crate substrate_keyring as keyring;
|
||||
pub extern crate substrate_test_runtime as runtime;
|
||||
pub extern crate substrate_consensus_common as consensus;
|
||||
|
||||
pub mod client_ext;
|
||||
pub mod trait_tests;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use keyring::Keyring;
|
||||
use client::BlockOrigin;
|
||||
use consensus::BlockOrigin;
|
||||
use primitives::Blake2Hasher;
|
||||
use ::TestClient;
|
||||
use runtime_primitives::traits::Block as BlockT;
|
||||
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
|
||||
= Transaction Pool
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -0,0 +1,12 @@
|
||||
= Substrate Trie
|
||||
|
||||
.Summary
|
||||
[source, toml]
|
||||
----
|
||||
include::Cargo.toml[lines=2..5]
|
||||
----
|
||||
|
||||
.Description
|
||||
----
|
||||
include::src/lib.rs[tag=description]
|
||||
----
|
||||
@@ -1 +0,0 @@
|
||||
This crate provides utility functions to interact with Substrate's Modified Merkle Patricia tree ("trie").
|
||||
@@ -14,7 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate-format Base-16 Modified Merkle Patricia Tree (Trie).
|
||||
// tag::description[]
|
||||
//! Utility functions to interact with Substrate's Base-16 Modified Merkle Patricia tree ("trie").
|
||||
// end::description[]
|
||||
|
||||
// TODO: no_std
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
:leveloffset: +3
|
||||
|
||||
include::../../safe-mix/README.adoc[]
|
||||
|
||||
include::../../subkey/README.adoc[]
|
||||
|
||||
:leveloffset: -3
|
||||
|
||||
@@ -1,62 +1,66 @@
|
||||
|
||||
== Substrate Packages
|
||||
|
||||
=== Substrate Core
|
||||
|
||||
:leveloffset: +3
|
||||
|
||||
include::../../core/bft/README.adoc[]
|
||||
|
||||
include::../../core/cli/README.adoc[]
|
||||
|
||||
include::../../core/client/README.adoc[]
|
||||
|
||||
include::../../codec/README.adoc[]
|
||||
include::../../core/test-client/README.adoc[]
|
||||
|
||||
include::../../environmental/README.adoc[]
|
||||
include::../../core/client/db/README.adoc[]
|
||||
|
||||
include::../../core/state-db/README.adoc[]
|
||||
|
||||
include::../../core/consensus/common/README.adoc[]
|
||||
|
||||
include::../../core/consensus/rhd/README.adoc[]
|
||||
|
||||
include::../../core/executor/README.adoc[]
|
||||
|
||||
include::../../core/finality-grandpa/README.adoc[]
|
||||
|
||||
include::../../core/transaction-pool/README.adoc[]
|
||||
|
||||
include::../../core/keyring/README.adoc[]
|
||||
|
||||
include::../../core/keystore/README.adoc[]
|
||||
|
||||
include::../../core/misbehavior-check/README.adoc[]
|
||||
|
||||
include::../../core/network/README.adoc[]
|
||||
|
||||
include::../../core/network-libp2p/README.adoc[]
|
||||
|
||||
include::../../core/primitives/README.adoc[]
|
||||
|
||||
include::../../pwasm-alloc/README.adoc[]
|
||||
|
||||
include::../../core/rpc/README.adoc[]
|
||||
|
||||
include::../../core/rpc-servers/README.adoc[]
|
||||
|
||||
include::../../srml/README.adoc[]
|
||||
|
||||
include::../../core/sr-api/README.adoc[]
|
||||
|
||||
include::../../core/sr-io/README.adoc[]
|
||||
|
||||
include::../../core/sr-primitives/README.adoc[]
|
||||
|
||||
include::../../core/sr-sandbox/README.adoc[]
|
||||
|
||||
include::../../core/sr-std/README.adoc[]
|
||||
|
||||
include::../../core/runtime-support/README.adoc[]
|
||||
|
||||
include::../../core/serializer/README.adoc[]
|
||||
|
||||
include::../../core/service/README.adoc[]
|
||||
|
||||
include::../../core/state-db/README.adoc[]
|
||||
|
||||
include::../../core/state-machine/README.adoc[]
|
||||
|
||||
include::../../core/test-runtime/README.adoc[]
|
||||
|
||||
include::../../core/telemetry/README.adoc[]
|
||||
|
||||
include::../../core/test-client/README.adoc[]
|
||||
include::../../core/cli/README.adoc[]
|
||||
|
||||
include::../../core/test-srml/README.adoc[]
|
||||
include::../../core/service/README.adoc[]
|
||||
|
||||
include::../../core/trie/README.adoc[]
|
||||
|
||||
include::../../core/keystore/README.adoc[]
|
||||
|
||||
include::../../core/primitives/README.adoc[]
|
||||
|
||||
include::../../core/serializer/README.adoc[]
|
||||
|
||||
:leveloffset: -3
|
||||
|
||||
@@ -9,14 +9,19 @@ log = "0.4"
|
||||
tokio = "0.1.7"
|
||||
exit-future = "0.1"
|
||||
substrate-cli = { path = "../../core/cli" }
|
||||
parity-codec = { version = "2.1" }
|
||||
parking_lot = "0.4"
|
||||
slog = "^2"
|
||||
sr-io = { path = "../../core/sr-io" }
|
||||
substrate-client = { path = "../../core/client" }
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
node-runtime = { path = "../runtime" }
|
||||
node-primitives = { path = "../primitives" }
|
||||
node-network = { path = "../network" }
|
||||
hex-literal = "0.1"
|
||||
substrate-service = { path = "../../core/service" }
|
||||
substrate-transaction-pool = { path = "../../core/transaction-pool" }
|
||||
substrate-network = { path = "../../core/network" }
|
||||
substrate-consensus-aura = { path = "../../core/consensus/aura" }
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
node-executor = { path = "../executor" }
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
//! Substrate chain configurations.
|
||||
|
||||
use primitives::{AuthorityId, ed25519};
|
||||
use node_primitives::AccountId;
|
||||
use node_runtime::{GenesisConfig, ConsensusConfig, CouncilSeatsConfig, CouncilVotingConfig, DemocracyConfig,
|
||||
SessionConfig, StakingConfig, TimestampConfig, BalancesConfig, TreasuryConfig,
|
||||
SessionConfig, StakingConfig, TimestampConfig, BalancesConfig, TreasuryConfig, UpgradeKeyConfig,
|
||||
ContractConfig, Permill, Perbill};
|
||||
use substrate_service;
|
||||
|
||||
@@ -45,7 +46,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
const CENTS: u128 = 1_000 * MILLICENTS; // assume this is worth about a cent.
|
||||
const DOLLARS: u128 = 100 * CENTS;
|
||||
|
||||
const SECS_PER_BLOCK: u64 = 5;
|
||||
const SECS_PER_BLOCK: u64 = 4;
|
||||
const MINUTES: u64 = 60 / SECS_PER_BLOCK;
|
||||
const HOURS: u64 = MINUTES * 60;
|
||||
const DAYS: u64 = HOURS * 24;
|
||||
@@ -121,6 +122,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
max_depth: 1024,
|
||||
block_gas_limit: 10_000_000,
|
||||
}),
|
||||
upgrade_key: Some(UpgradeKeyConfig {
|
||||
key: endowed_accounts[0].clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +143,7 @@ pub fn staging_testnet_config() -> ChainSpec {
|
||||
)
|
||||
}
|
||||
|
||||
fn testnet_genesis(initial_authorities: Vec<AuthorityId>) -> GenesisConfig {
|
||||
fn testnet_genesis(initial_authorities: Vec<AuthorityId>, upgrade_key: AccountId) -> GenesisConfig {
|
||||
let endowed_accounts = vec![
|
||||
ed25519::Pair::from_seed(b"Alice ").public().0.into(),
|
||||
ed25519::Pair::from_seed(b"Bob ").public().0.into(),
|
||||
@@ -220,13 +224,18 @@ fn testnet_genesis(initial_authorities: Vec<AuthorityId>) -> GenesisConfig {
|
||||
max_depth: 1024,
|
||||
block_gas_limit: 10_000_000,
|
||||
}),
|
||||
upgrade_key: Some(UpgradeKeyConfig {
|
||||
key: upgrade_key,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn development_config_genesis() -> GenesisConfig {
|
||||
testnet_genesis(vec![
|
||||
ed25519::Pair::from_seed(b"Alice ").public().into(),
|
||||
])
|
||||
],
|
||||
ed25519::Pair::from_seed(b"Alice ").public().0.into()
|
||||
)
|
||||
}
|
||||
|
||||
/// Development config (single validator Alice)
|
||||
@@ -238,7 +247,9 @@ fn local_testnet_genesis() -> GenesisConfig {
|
||||
testnet_genesis(vec![
|
||||
ed25519::Pair::from_seed(b"Alice ").public().into(),
|
||||
ed25519::Pair::from_seed(b"Bob ").public().into(),
|
||||
])
|
||||
],
|
||||
ed25519::Pair::from_seed(b"Alice ").public().0.into()
|
||||
)
|
||||
}
|
||||
|
||||
/// Local testnet config (multivalidator Alice + Bob)
|
||||
|
||||
@@ -30,9 +30,9 @@ extern crate hex_literal;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_service_test as service_test;
|
||||
extern crate substrate_transaction_pool as transaction_pool;
|
||||
#[macro_use]
|
||||
extern crate substrate_network as network;
|
||||
extern crate node_network;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate substrate_consensus_aura as consensus;
|
||||
extern crate node_primitives;
|
||||
#[macro_use]
|
||||
extern crate substrate_service;
|
||||
|
||||
@@ -22,38 +22,19 @@ use std::sync::Arc;
|
||||
use transaction_pool::{self, txpool::{Pool as TransactionPool}};
|
||||
use node_primitives::Block;
|
||||
use node_runtime::GenesisConfig;
|
||||
use node_network::Protocol as NodeProtocol;
|
||||
use substrate_service::{
|
||||
FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
|
||||
LightBackend, FullExecutor, LightExecutor
|
||||
FullClient, LightClient, LightBackend, FullExecutor, LightExecutor,
|
||||
Roles, TaskExecutor,
|
||||
};
|
||||
use network::import_queue::{BasicQueue, BlockOrigin, ImportBlock, Verifier};
|
||||
use runtime_primitives::{traits::Block as BlockT};
|
||||
use primitives::AuthorityId;
|
||||
use node_executor;
|
||||
use consensus::{import_queue, start_aura, Config as AuraConfig, AuraImportQueue};
|
||||
|
||||
// TODO: Remove me, when we have a functional consensus.
|
||||
/// A verifier that doesn't actually do any checks
|
||||
pub struct NoneVerifier;
|
||||
/// This Verifiyer accepts all data as valid
|
||||
impl<B: BlockT> Verifier<B> for NoneVerifier {
|
||||
fn verify(
|
||||
&self,
|
||||
origin: BlockOrigin,
|
||||
header: B::Header,
|
||||
justification: Vec<u8>,
|
||||
body: Option<Vec<B::Extrinsic>>
|
||||
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityId>>), String> {
|
||||
Ok((ImportBlock {
|
||||
origin,
|
||||
header,
|
||||
body,
|
||||
finalized: true,
|
||||
external_justification: justification,
|
||||
internal_justification: vec![],
|
||||
auxiliary: Vec::new(),
|
||||
}, None))
|
||||
}
|
||||
const AURA_SLOT_DURATION: u64 = 6;
|
||||
|
||||
construct_simple_protocol! {
|
||||
/// Demo protocol attachment for substrate.
|
||||
pub struct NodeProtocol where Block = Block { }
|
||||
}
|
||||
|
||||
construct_simple_service!(Service);
|
||||
@@ -70,15 +51,48 @@ construct_service_factory! {
|
||||
Genesis = GenesisConfig,
|
||||
Configuration = (),
|
||||
FullService = Service<FullComponents<Self>>
|
||||
{ |config, executor| Service::<FullComponents<Factory>>::new(config, executor) },
|
||||
{ |config: FactoryFullConfiguration<Self>, executor: TaskExecutor| {
|
||||
let is_auth = config.roles == Roles::AUTHORITY;
|
||||
Service::<FullComponents<Factory>>::new(config, executor.clone()).map(move |service|{
|
||||
if is_auth {
|
||||
if let Ok(Some(Ok(key))) = service.keystore().contents()
|
||||
.map(|keys| keys.get(0).map(|k| service.keystore().load(k, "")))
|
||||
{
|
||||
info!("Using authority key {}", key.public());
|
||||
let task = start_aura(
|
||||
AuraConfig {
|
||||
local_key: Some(Arc::new(key)),
|
||||
slot_duration: AURA_SLOT_DURATION,
|
||||
},
|
||||
service.client(),
|
||||
service.proposer(),
|
||||
service.network(),
|
||||
);
|
||||
|
||||
executor.spawn(task);
|
||||
}
|
||||
}
|
||||
|
||||
service
|
||||
})
|
||||
}
|
||||
},
|
||||
LightService = Service<LightComponents<Self>>
|
||||
{ |config, executor| Service::<LightComponents<Factory>>::new(config, executor) },
|
||||
ImportQueue = BasicQueue<Block, NoneVerifier>
|
||||
{ |_, _| Ok(BasicQueue::new(Arc::new(NoneVerifier {}))) }
|
||||
{ |_, _| Ok(BasicQueue::new(Arc::new(NoneVerifier {}))) },
|
||||
FullImportQueue = AuraImportQueue<Self::Block, FullClient<Self>>
|
||||
{ |config, client| Ok(import_queue(AuraConfig {
|
||||
local_key: None,
|
||||
slot_duration: 5
|
||||
}, client)) },
|
||||
LightImportQueue = AuraImportQueue<Self::Block, LightClient<Self>>
|
||||
{ |config, client| Ok(import_queue(AuraConfig {
|
||||
local_key: None,
|
||||
slot_duration: 5
|
||||
}, client)) },
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(feature = "rhd")]
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
[package]
|
||||
name = "node-consensus"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
error-chain = "0.12"
|
||||
exit-future = "0.1"
|
||||
futures = "0.1.17"
|
||||
log = "0.4"
|
||||
node-primitives = { path = "../primitives" }
|
||||
node-runtime = { path = "../runtime" }
|
||||
parity-codec = "2.1"
|
||||
parking_lot = "0.4"
|
||||
rhododendron = "0.3"
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
srml-system = { path = "../../srml/system" }
|
||||
substrate-client = { path = "../../core/client" }
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
substrate-transaction-pool = { path = "../../core/transaction-pool" }
|
||||
tokio = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-keyring = { path = "../../core/keyring" }
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
= Substrate Consensus
|
||||
|
||||
placeholder
|
||||
//TODO Write content :)
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Errors that can occur during the consensus process.
|
||||
|
||||
use primitives::AuthorityId;
|
||||
use client;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
Client(client::error::Error, client::error::ErrorKind);
|
||||
Bft(::bft::Error, ::bft::ErrorKind);
|
||||
}
|
||||
|
||||
errors {
|
||||
NotValidator(id: AuthorityId) {
|
||||
description("Local account ID not a validator at this block."),
|
||||
display("Local account ID ({:?}) not a validator at this block.", id),
|
||||
}
|
||||
PrematureDestruction {
|
||||
description("Proposer destroyed before finishing proposing or evaluating"),
|
||||
display("Proposer destroyed before finishing proposing or evaluating"),
|
||||
}
|
||||
Timer(e: ::tokio::timer::Error) {
|
||||
description("Failed to register or resolve async timer."),
|
||||
display("Timer failed: {}", e),
|
||||
}
|
||||
Executor(e: ::futures::future::ExecuteErrorKind) {
|
||||
description("Unable to dispatch agreement future"),
|
||||
display("Unable to dispatch agreement future: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::bft::InputStreamConcluded> for Error {
|
||||
fn from(err: ::bft::InputStreamConcluded) -> Self {
|
||||
::bft::Error::from(err).into()
|
||||
}
|
||||
}
|
||||
@@ -1,529 +0,0 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! This service uses BFT consensus provided by the substrate.
|
||||
|
||||
#![cfg(feature="rhd")]
|
||||
|
||||
extern crate node_runtime;
|
||||
extern crate node_primitives;
|
||||
|
||||
extern crate parity_codec as codec;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate srml_system;
|
||||
extern crate substrate_bft as bft;
|
||||
extern crate substrate_client as client;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate substrate_transaction_pool as transaction_pool;
|
||||
|
||||
extern crate exit_future;
|
||||
extern crate futures;
|
||||
extern crate parking_lot;
|
||||
extern crate rhododendron;
|
||||
extern crate tokio;
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate substrate_keyring;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::{self, Duration, Instant};
|
||||
|
||||
use client::{Client as SubstrateClient, CallExecutor};
|
||||
use client::runtime_api::{Core, BlockBuilder as BlockBuilderAPI, Miscellaneous, OldTxQueue};
|
||||
use codec::{Decode, Encode};
|
||||
use node_primitives::{AccountId, Timestamp, SessionKey};
|
||||
use node_runtime::{Runtime, InherentError, TimestampInherentError, InherentData};
|
||||
use primitives::{AuthorityId, ed25519, Blake2Hasher};
|
||||
use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, As, BlockNumberToHash};
|
||||
use runtime_primitives::generic::{BlockId, Era};
|
||||
use srml_system::Trait as SystemT;
|
||||
use transaction_pool::txpool::{self, Pool as TransactionPool};
|
||||
use tokio::runtime::TaskExecutor;
|
||||
use tokio::timer::Delay;
|
||||
|
||||
use futures::prelude::*;
|
||||
use futures::future;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
pub use self::error::{ErrorKind, Error, Result};
|
||||
pub use self::offline_tracker::OfflineTracker;
|
||||
pub use service::Service;
|
||||
|
||||
mod evaluation;
|
||||
mod error;
|
||||
mod service;
|
||||
|
||||
/// Shared offline validator tracker.
|
||||
pub type SharedOfflineTracker = Arc<RwLock<OfflineTracker>>;
|
||||
|
||||
// block size limit.
|
||||
const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
/// Build new blocks.
|
||||
pub trait BlockBuilder<Block: BlockT> {
|
||||
/// Push an extrinsic onto the block. Fails if the extrinsic is invalid.
|
||||
fn push_extrinsic(&mut self, extrinsic: <Block as BlockT>::Extrinsic) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Local client abstraction for the consensus.
|
||||
pub trait AuthoringApi:
|
||||
Send
|
||||
+ Sync
|
||||
+ BlockBuilderAPI<<Self as AuthoringApi>::Block, Error=<Self as AuthoringApi>::Error>
|
||||
+ Core<<Self as AuthoringApi>::Block, AuthorityId, Error=<Self as AuthoringApi>::Error>
|
||||
+ Miscellaneous<<Self as AuthoringApi>::Block, Error=<Self as AuthoringApi>::Error>
|
||||
+ OldTxQueue<<Self as AuthoringApi>::Block, Error=<Self as AuthoringApi>::Error>
|
||||
{
|
||||
/// The block used for this API type.
|
||||
type Block: BlockT;
|
||||
/// The error used by this API type.
|
||||
type Error: std::error::Error;
|
||||
|
||||
/// Build a block on top of the given, with inherent extrinsics pre-pushed.
|
||||
fn build_block<F: FnMut(&mut BlockBuilder<Self::Block>) -> ()>(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
inherent_data: InherentData,
|
||||
build_ctx: F,
|
||||
) -> Result<Self::Block>;
|
||||
}
|
||||
|
||||
impl<'a, B, E, Block> BlockBuilder<Block> for client::block_builder::BlockBuilder<'a, B, E, Block, Blake2Hasher> where
|
||||
B: client::backend::Backend<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone + 'static,
|
||||
Block: BlockT
|
||||
{
|
||||
fn push_extrinsic(&mut self, extrinsic: <Block as BlockT>::Extrinsic) -> Result<()> {
|
||||
client::block_builder::BlockBuilder::push(self, extrinsic).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B, E, Block> AuthoringApi for SubstrateClient<B, E, Block> where
|
||||
B: client::backend::Backend<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone + 'static,
|
||||
Block: BlockT,
|
||||
{
|
||||
type Block = Block;
|
||||
type Error = client::error::Error;
|
||||
|
||||
fn build_block<F: FnMut(&mut BlockBuilder<Self::Block>) -> ()>(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
inherent_data: InherentData,
|
||||
mut build_ctx: F,
|
||||
) -> Result<Self::Block> {
|
||||
let runtime_version = self.runtime_version_at(at)?;
|
||||
|
||||
let mut block_builder = self.new_block_at(at)?;
|
||||
if runtime_version.has_api(*b"inherent", 1) {
|
||||
self.inherent_extrinsics(at, &inherent_data)?
|
||||
.into_iter().try_for_each(|i| block_builder.push(i))?;
|
||||
}
|
||||
|
||||
build_ctx(&mut block_builder);
|
||||
|
||||
block_builder.bake().map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// A long-lived network which can create BFT message routing processes on demand.
|
||||
pub trait Network {
|
||||
/// The block used for this API type.
|
||||
type Block: BlockT;
|
||||
/// The input stream of BFT messages. Should never logically conclude.
|
||||
type Input: Stream<Item=bft::Communication<Self::Block>,Error=Error>;
|
||||
/// The output sink of BFT messages. Messages sent here should eventually pass to all
|
||||
/// current authorities.
|
||||
type Output: Sink<SinkItem=bft::Communication<Self::Block>,SinkError=Error>;
|
||||
|
||||
/// Instantiate input and output streams.
|
||||
fn communication_for(
|
||||
&self,
|
||||
validators: &[SessionKey],
|
||||
local_id: SessionKey,
|
||||
parent_hash: <Self::Block as BlockT>::Hash,
|
||||
task_executor: TaskExecutor
|
||||
) -> (Self::Input, Self::Output);
|
||||
}
|
||||
|
||||
/// Proposer factory.
|
||||
pub struct ProposerFactory<N, C, A> where
|
||||
C: AuthoringApi,
|
||||
A: txpool::ChainApi,
|
||||
{
|
||||
/// The client instance.
|
||||
pub client: Arc<C>,
|
||||
/// The transaction pool.
|
||||
pub transaction_pool: Arc<TransactionPool<A>>,
|
||||
/// The backing network handle.
|
||||
pub network: N,
|
||||
/// handle to remote task executor
|
||||
pub handle: TaskExecutor,
|
||||
/// Offline-tracker.
|
||||
pub offline: SharedOfflineTracker,
|
||||
/// Force delay in evaluation this long.
|
||||
pub force_delay: Timestamp,
|
||||
}
|
||||
|
||||
impl<N, C, A> bft::Environment<<C as AuthoringApi>::Block> for ProposerFactory<N, C, A> where
|
||||
N: Network<Block=<C as AuthoringApi>::Block>,
|
||||
C: AuthoringApi + BlockNumberToHash,
|
||||
A: txpool::ChainApi<Block=<C as AuthoringApi>::Block>,
|
||||
<<C as AuthoringApi>::Block as BlockT>::Hash:
|
||||
Into<<Runtime as SystemT>::Hash> + PartialEq<primitives::H256> + Into<primitives::H256>,
|
||||
Error: From<<C as AuthoringApi>::Error>
|
||||
{
|
||||
type Proposer = Proposer<C, A>;
|
||||
type Input = N::Input;
|
||||
type Output = N::Output;
|
||||
type Error = Error;
|
||||
|
||||
fn init(
|
||||
&self,
|
||||
parent_header: &<<C as AuthoringApi>::Block as BlockT>::Header,
|
||||
authorities: &[AuthorityId],
|
||||
sign_with: Arc<ed25519::Pair>,
|
||||
) -> Result<(Self::Proposer, Self::Input, Self::Output)> {
|
||||
use runtime_primitives::traits::Hash as HashT;
|
||||
let parent_hash = parent_header.hash();
|
||||
|
||||
let id = BlockId::hash(parent_hash);
|
||||
let random_seed = self.client.random_seed(&id)?;
|
||||
let random_seed = <<<C as AuthoringApi>::Block as BlockT>::Header as HeaderT>::Hashing::hash(random_seed.as_ref());
|
||||
|
||||
let validators = self.client.validators(&id)?;
|
||||
self.offline.write().note_new_block(&validators[..]);
|
||||
|
||||
info!("Starting consensus session on top of parent {:?}", parent_hash);
|
||||
|
||||
let local_id = sign_with.public().0.into();
|
||||
let (input, output) = self.network.communication_for(
|
||||
authorities,
|
||||
local_id,
|
||||
parent_hash.clone(),
|
||||
self.handle.clone(),
|
||||
);
|
||||
let now = Instant::now();
|
||||
let proposer = Proposer {
|
||||
client: self.client.clone(),
|
||||
start: now,
|
||||
local_key: sign_with,
|
||||
parent_hash,
|
||||
parent_id: id,
|
||||
parent_number: *parent_header.number(),
|
||||
random_seed,
|
||||
transaction_pool: self.transaction_pool.clone(),
|
||||
offline: self.offline.clone(),
|
||||
validators,
|
||||
minimum_timestamp: current_timestamp() + self.force_delay,
|
||||
};
|
||||
|
||||
Ok((proposer, input, output))
|
||||
}
|
||||
}
|
||||
|
||||
/// The proposer logic.
|
||||
pub struct Proposer<C: AuthoringApi, A: txpool::ChainApi> {
|
||||
client: Arc<C>,
|
||||
start: Instant,
|
||||
local_key: Arc<ed25519::Pair>,
|
||||
parent_hash: <<C as AuthoringApi>::Block as BlockT>::Hash,
|
||||
parent_id: BlockId<<C as AuthoringApi>::Block>,
|
||||
parent_number: <<<C as AuthoringApi>::Block as BlockT>::Header as HeaderT>::Number,
|
||||
random_seed: <<C as AuthoringApi>::Block as BlockT>::Hash,
|
||||
transaction_pool: Arc<TransactionPool<A>>,
|
||||
offline: SharedOfflineTracker,
|
||||
validators: Vec<AccountId>,
|
||||
minimum_timestamp: u64,
|
||||
}
|
||||
|
||||
impl<C: AuthoringApi, A: txpool::ChainApi> Proposer<C, A> {
|
||||
fn primary_index(&self, round_number: usize, len: usize) -> usize {
|
||||
use primitives::uint::U256;
|
||||
|
||||
let big_len = U256::from(len);
|
||||
let offset = U256::from_big_endian(self.random_seed.as_ref()) % big_len;
|
||||
let offset = offset.low_u64() as usize + round_number;
|
||||
offset % len
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, A> bft::Proposer<<C as AuthoringApi>::Block> for Proposer<C, A> where
|
||||
C: AuthoringApi + BlockNumberToHash,
|
||||
A: txpool::ChainApi<Block=<C as AuthoringApi>::Block>,
|
||||
<<C as AuthoringApi>::Block as BlockT>::Hash:
|
||||
Into<<Runtime as SystemT>::Hash> + PartialEq<primitives::H256> + Into<primitives::H256>,
|
||||
error::Error: From<<C as AuthoringApi>::Error>
|
||||
{
|
||||
type Create = Result<<C as AuthoringApi>::Block>;
|
||||
type Error = Error;
|
||||
type Evaluate = Box<Future<Item=bool, Error=Error>>;
|
||||
|
||||
fn propose(&self) -> Result<<C as AuthoringApi>::Block> {
|
||||
use runtime_primitives::traits::BlakeTwo256;
|
||||
|
||||
const MAX_VOTE_OFFLINE_SECONDS: Duration = Duration::from_secs(60);
|
||||
|
||||
// TODO: handle case when current timestamp behind that in state.
|
||||
let timestamp = ::std::cmp::max(self.minimum_timestamp, current_timestamp());
|
||||
|
||||
let elapsed_since_start = self.start.elapsed();
|
||||
let offline_indices = if elapsed_since_start > MAX_VOTE_OFFLINE_SECONDS {
|
||||
Vec::new()
|
||||
} else {
|
||||
self.offline.read().reports(&self.validators[..])
|
||||
};
|
||||
|
||||
if !offline_indices.is_empty() {
|
||||
info!(
|
||||
"Submitting offline validators {:?} for slash-vote",
|
||||
offline_indices.iter().map(|&i| self.validators[i as usize]).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
|
||||
let inherent_data = InherentData {
|
||||
timestamp,
|
||||
offline_indices,
|
||||
};
|
||||
|
||||
let block = self.client.build_block(
|
||||
&self.parent_id,
|
||||
inherent_data,
|
||||
|block_builder| {
|
||||
let mut unqueue_invalid = Vec::new();
|
||||
self.transaction_pool.ready(|pending_iterator| {
|
||||
let mut pending_size = 0;
|
||||
for pending in pending_iterator {
|
||||
// TODO [ToDr] Probably get rid of it, and validate in runtime.
|
||||
let encoded_size = pending.data.encode().len();
|
||||
if pending_size + encoded_size >= MAX_TRANSACTIONS_SIZE { break }
|
||||
|
||||
match block_builder.push_extrinsic(pending.data.clone()) {
|
||||
Ok(()) => {
|
||||
pending_size += encoded_size;
|
||||
}
|
||||
Err(e) => {
|
||||
trace!(target: "transaction-pool", "Invalid transaction: {}", e);
|
||||
unqueue_invalid.push(pending.hash.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.transaction_pool.remove_invalid(&unqueue_invalid);
|
||||
})?;
|
||||
|
||||
info!("Proposing block [number: {}; hash: {}; parent_hash: {}; extrinsics: [{}]]",
|
||||
block.header().number(),
|
||||
<<C as AuthoringApi>::Block as BlockT>::Hash::from(block.header().hash()),
|
||||
block.header().parent_hash(),
|
||||
block.extrinsics().iter()
|
||||
.map(|xt| format!("{}", BlakeTwo256::hash_of(xt)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
|
||||
let substrate_block = Decode::decode(&mut block.encode().as_slice())
|
||||
.expect("blocks are defined to serialize to substrate blocks correctly; qed");
|
||||
|
||||
assert!(evaluation::evaluate_initial(
|
||||
&substrate_block,
|
||||
&self.parent_hash,
|
||||
self.parent_number,
|
||||
).is_ok());
|
||||
|
||||
Ok(substrate_block)
|
||||
}
|
||||
|
||||
fn evaluate(&self, unchecked_proposal: &<C as AuthoringApi>::Block) -> Self::Evaluate {
|
||||
debug!(target: "bft", "evaluating block on top of parent ({}, {:?})", self.parent_number, self.parent_hash);
|
||||
|
||||
// do initial serialization and structural integrity checks.
|
||||
match evaluation::evaluate_initial(
|
||||
unchecked_proposal,
|
||||
&self.parent_hash,
|
||||
self.parent_number,
|
||||
) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
// TODO: these errors are easily re-checked in runtime.
|
||||
debug!(target: "bft", "Invalid proposal (initial evaluation failed): {:?}", e);
|
||||
return Box::new(future::ok(false));
|
||||
}
|
||||
};
|
||||
|
||||
let current_timestamp = current_timestamp();
|
||||
let inherent = InherentData::new(
|
||||
current_timestamp,
|
||||
self.offline.read().reports(&self.validators)
|
||||
);
|
||||
let proposed_timestamp = match self.client.check_inherents(
|
||||
&self.parent_id,
|
||||
&unchecked_proposal,
|
||||
&inherent
|
||||
) {
|
||||
Ok(Ok(())) => None,
|
||||
Ok(Err(InherentError::Timestamp(TimestampInherentError::TimestampInFuture(timestamp)))) => Some(timestamp),
|
||||
Ok(Err(e)) => {
|
||||
debug!(target: "bft", "Invalid proposal (check_inherents): {:?}", e);
|
||||
return Box::new(future::ok(false));
|
||||
},
|
||||
Err(e) => {
|
||||
debug!(target: "bft", "Could not call into runtime: {:?}", e);
|
||||
return Box::new(future::ok(false));
|
||||
}
|
||||
};
|
||||
|
||||
let vote_delays = {
|
||||
// the duration until the given timestamp is current
|
||||
let proposed_timestamp = ::std::cmp::max(self.minimum_timestamp, proposed_timestamp.unwrap_or(0));
|
||||
let timestamp_delay = if proposed_timestamp > current_timestamp {
|
||||
let delay_s = proposed_timestamp - current_timestamp;
|
||||
debug!(target: "bft", "Delaying evaluation of proposal for {} seconds", delay_s);
|
||||
Some(Instant::now() + Duration::from_secs(delay_s))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match timestamp_delay {
|
||||
Some(duration) => future::Either::A(
|
||||
Delay::new(duration).map_err(|e| ErrorKind::Timer(e).into())
|
||||
),
|
||||
None => future::Either::B(future::ok(())),
|
||||
}
|
||||
};
|
||||
|
||||
// evaluate whether the block is actually valid.
|
||||
// TODO: is it better to delay this until the delays are finished?
|
||||
let evaluated = match self.client.execute_block(&self.parent_id, &unchecked_proposal.clone()).map_err(Error::from) {
|
||||
Ok(()) => Ok(true),
|
||||
Err(err) => match err.kind() {
|
||||
error::ErrorKind::Client(client::error::ErrorKind::Execution(_)) => Ok(false),
|
||||
_ => Err(err)
|
||||
}
|
||||
};
|
||||
|
||||
let future = future::result(evaluated).and_then(move |good| {
|
||||
let end_result = future::ok(good);
|
||||
if good {
|
||||
// delay a "good" vote.
|
||||
future::Either::A(vote_delays.and_then(|_| end_result))
|
||||
} else {
|
||||
// don't delay a "bad" evaluation.
|
||||
future::Either::B(end_result)
|
||||
}
|
||||
});
|
||||
|
||||
Box::new(future) as Box<_>
|
||||
}
|
||||
|
||||
fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId {
|
||||
let offset = self.primary_index(round_number, authorities.len());
|
||||
let proposer = authorities[offset].clone();
|
||||
trace!(target: "bft", "proposer for round {} is {}", round_number, proposer);
|
||||
|
||||
proposer
|
||||
}
|
||||
|
||||
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior<<<C as AuthoringApi>::Block as BlockT>::Hash>)>) {
|
||||
use rhododendron::Misbehavior as GenericMisbehavior;
|
||||
use runtime_primitives::bft::{MisbehaviorKind, MisbehaviorReport};
|
||||
use node_runtime::{Call, UncheckedExtrinsic, ConsensusCall};
|
||||
|
||||
let mut next_index = {
|
||||
let local_id = self.local_key.public().0;
|
||||
// let cur_index = self.transaction_pool.cull_and_get_pending(&BlockId::hash(self.parent_hash), |pending| pending
|
||||
// .filter(|tx| tx.verified.sender == local_id)
|
||||
// .last()
|
||||
// .map(|tx| Ok(tx.verified.index()))
|
||||
// .unwrap_or_else(|| self.client.account_nonce(&self.parent_id, local_id))
|
||||
// .map_err(Error::from)
|
||||
// );
|
||||
// TODO [ToDr] Use pool data
|
||||
let cur_index: Result<u64> = self.client.account_nonce(&self.parent_id, &local_id).map_err(Error::from);
|
||||
|
||||
match cur_index {
|
||||
Ok(cur_index) => cur_index + 1,
|
||||
Err(e) => {
|
||||
warn!(target: "consensus", "Error computing next transaction index: {:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (target, misbehavior) in misbehavior {
|
||||
let report = MisbehaviorReport {
|
||||
parent_hash: self.parent_hash.into(),
|
||||
parent_number: self.parent_number.as_(),
|
||||
target,
|
||||
misbehavior: match misbehavior {
|
||||
GenericMisbehavior::ProposeOutOfTurn(_, _, _) => continue,
|
||||
GenericMisbehavior::DoublePropose(_, _, _) => continue,
|
||||
GenericMisbehavior::DoublePrepare(round, (h1, s1), (h2, s2))
|
||||
=> MisbehaviorKind::BftDoublePrepare(round as u32, (h1.into(), s1.signature), (h2.into(), s2.signature)),
|
||||
GenericMisbehavior::DoubleCommit(round, (h1, s1), (h2, s2))
|
||||
=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1.into(), s1.signature), (h2.into(), s2.signature)),
|
||||
}
|
||||
};
|
||||
let payload = (next_index, Call::Consensus(ConsensusCall::report_misbehavior(report)), Era::immortal(), self.client.genesis_hash());
|
||||
let signature = self.local_key.sign(&payload.encode()).into();
|
||||
next_index += 1;
|
||||
|
||||
let local_id = self.local_key.public().0.into();
|
||||
let extrinsic = UncheckedExtrinsic {
|
||||
signature: Some((node_runtime::RawAddress::Id(local_id), signature, payload.0, Era::immortal())),
|
||||
function: payload.1,
|
||||
};
|
||||
let uxt: <<C as AuthoringApi>::Block as BlockT>::Extrinsic = Decode::decode(&mut extrinsic.encode().as_slice()).expect("Encoded extrinsic is valid");
|
||||
let hash = BlockId::<<C as AuthoringApi>::Block>::hash(self.parent_hash);
|
||||
if let Err(e) = self.transaction_pool.submit_one(&hash, uxt) {
|
||||
warn!("Error importing misbehavior report: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_round_end(&self, round_number: usize, was_proposed: bool) {
|
||||
let primary_validator = self.validators[
|
||||
self.primary_index(round_number, self.validators.len())
|
||||
];
|
||||
|
||||
|
||||
// alter the message based on whether we think the empty proposer was forced to skip the round.
|
||||
// this is determined by checking if our local validator would have been forced to skip the round.
|
||||
if !was_proposed {
|
||||
let public = ed25519::Public::from_raw(primary_validator.0);
|
||||
info!(
|
||||
"Potential Offline Validator: {} failed to propose during assigned slot: {}",
|
||||
public,
|
||||
round_number,
|
||||
);
|
||||
}
|
||||
|
||||
self.offline.write().note_round_end(primary_validator, was_proposed);
|
||||
}
|
||||
}
|
||||
|
||||
fn current_timestamp() -> Timestamp {
|
||||
time::SystemTime::now().duration_since(time::UNIX_EPOCH)
|
||||
.expect("now always later than unix epoch; qed")
|
||||
.as_secs()
|
||||
}
|
||||
@@ -254,6 +254,7 @@ mod tests {
|
||||
timestamp: Some(Default::default()),
|
||||
treasury: Some(Default::default()),
|
||||
contract: Some(Default::default()),
|
||||
upgrade_key: Some(Default::default()),
|
||||
}.build_storage().unwrap())
|
||||
}
|
||||
|
||||
@@ -291,9 +292,9 @@ mod tests {
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
if support_changes_trie {
|
||||
hex!("ffa85ed1832eae3e25e684d4f993ff0b5e8b6ac4d7ba0f40a5fb0114fda22f3d").into()
|
||||
hex!("978a3ff733a86638da39d36a349c693b5cf562bcc8db30fec6c2b6c40f925a9b").into()
|
||||
} else {
|
||||
hex!("98971908b8923d07944cdf7ee658c203d17042ef447169adbdfec8160cfabcad").into()
|
||||
hex!("7bbad534e3de3db3c8cda015c4e8ed8ba10dde7e3fca21f4fd4fbc686e6c1410").into()
|
||||
},
|
||||
if support_changes_trie {
|
||||
Some(hex!("1f8f44dcae8982350c14dee720d34b147e73279f5a2ce1f9781195a991970978").into())
|
||||
@@ -317,7 +318,7 @@ mod tests {
|
||||
construct_block(
|
||||
2,
|
||||
block1(false).1,
|
||||
hex!("788a2e8b23e4b30e1bce347ca6415fd0080e989d40741c86995b9ad539bb76b3").into(),
|
||||
hex!("7be30152ee2ee909047cffad5f0a28bf8c2b0a97c124b500aeac112f6917738e").into(),
|
||||
None,
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
@@ -340,7 +341,7 @@ mod tests {
|
||||
construct_block(
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
hex!("acc03af5b3972deaf9dde4dfd99c5614a5360454313681b6fc299d1644ae8a59").into(),
|
||||
hex!("325a73726dc640af41becb42938e7152e218f130219c0695aae35b6a156f93f3").into(),
|
||||
None,
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
@@ -622,7 +623,7 @@ mod tests {
|
||||
let b = construct_block(
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
hex!("21fb6fb965f012ae3c6e521b71b5b57d6df17c738c52f202ec2809ca235eb082").into(),
|
||||
hex!("d68586d5098535e04ff7a12d71a9c9dc719960f318862e636e78a8e98cf4b8d4").into(),
|
||||
None,
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
[package]
|
||||
name = "node-network"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Substrate node networking protocol"
|
||||
|
||||
[dependencies]
|
||||
node-consensus = { path = "../consensus" }
|
||||
node-primitives = { path = "../primitives" }
|
||||
substrate-consensus-rhd = { path = "../../core/consensus/rhd" }
|
||||
substrate-network = { path = "../../core/network" }
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
futures = "0.1"
|
||||
tokio = "0.1.7"
|
||||
log = "0.4"
|
||||
rhododendron = "0.3"
|
||||
@@ -1,293 +0,0 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The "consensus" networking code built on top of the base network service.
|
||||
//! This fulfills the `node_consensus::Network` trait, providing a hook to be called
|
||||
//! each time consensus begins on a new chain head.
|
||||
|
||||
use bft;
|
||||
use substrate_primitives::ed25519;
|
||||
use substrate_network::{self as net, generic_message as msg};
|
||||
use substrate_network::consensus_gossip::ConsensusMessage;
|
||||
use node_consensus::{AuthoringApi, Network};
|
||||
use node_primitives::{Block, Hash, SessionKey};
|
||||
use rhododendron;
|
||||
|
||||
use futures::prelude::*;
|
||||
use futures::sync::mpsc;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::runtime::TaskExecutor;
|
||||
use tokio::executor::Executor;
|
||||
|
||||
use super::NetworkService;
|
||||
|
||||
/// Sink for output BFT messages.
|
||||
pub struct BftSink<E> {
|
||||
network: Arc<NetworkService>,
|
||||
parent_hash: Hash,
|
||||
_marker: ::std::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> Sink for BftSink<E> {
|
||||
type SinkItem = bft::Communication<Block>;
|
||||
// TODO: replace this with the ! type when that's stabilized
|
||||
type SinkError = E;
|
||||
|
||||
fn start_send(&mut self, message: bft::Communication<Block>)
|
||||
-> ::futures::StartSend<bft::Communication<Block>, E>
|
||||
{
|
||||
let network_message = net::LocalizedBftMessage {
|
||||
message: match message {
|
||||
rhododendron::Communication::Consensus(c) => msg::BftMessage::Consensus(match c {
|
||||
rhododendron::LocalizedMessage::Propose(proposal) => msg::SignedConsensusMessage::Propose(msg::SignedConsensusProposal {
|
||||
round_number: proposal.round_number as u32,
|
||||
proposal: proposal.proposal,
|
||||
digest: proposal.digest,
|
||||
sender: proposal.sender,
|
||||
digest_signature: proposal.digest_signature.signature,
|
||||
full_signature: proposal.full_signature.signature,
|
||||
}),
|
||||
rhododendron::LocalizedMessage::Vote(vote) => msg::SignedConsensusMessage::Vote(msg::SignedConsensusVote {
|
||||
sender: vote.sender,
|
||||
signature: vote.signature.signature,
|
||||
vote: match vote.vote {
|
||||
rhododendron::Vote::Prepare(r, h) => msg::ConsensusVote::Prepare(r as u32, h),
|
||||
rhododendron::Vote::Commit(r, h) => msg::ConsensusVote::Commit(r as u32, h),
|
||||
rhododendron::Vote::AdvanceRound(r) => msg::ConsensusVote::AdvanceRound(r as u32),
|
||||
}
|
||||
}),
|
||||
}),
|
||||
rhododendron::Communication::Auxiliary(justification) => {
|
||||
let unchecked: bft::UncheckedJustification<_> = justification.uncheck().into();
|
||||
msg::BftMessage::Auxiliary(unchecked.into())
|
||||
}
|
||||
},
|
||||
parent_hash: self.parent_hash,
|
||||
};
|
||||
self.network.with_spec(
|
||||
move |spec, ctx| spec.consensus_gossip.multicast_bft_message(ctx, network_message)
|
||||
);
|
||||
Ok(::futures::AsyncSink::Ready)
|
||||
}
|
||||
|
||||
fn poll_complete(&mut self) -> ::futures::Poll<(), E> {
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
}
|
||||
|
||||
// check signature and authority validity of message.
|
||||
fn process_bft_message(
|
||||
msg: msg::LocalizedBftMessage<Block, Hash>,
|
||||
local_id: &SessionKey,
|
||||
authorities: &[SessionKey]
|
||||
) -> Result<Option<bft::Communication<Block>>, bft::Error>
|
||||
{
|
||||
Ok(Some(match msg.message {
|
||||
msg::BftMessage::Consensus(c) => rhododendron::Communication::Consensus(match c {
|
||||
msg::SignedConsensusMessage::Propose(proposal) => rhododendron::LocalizedMessage::Propose({
|
||||
if &proposal.sender == local_id { return Ok(None) }
|
||||
let proposal = rhododendron::LocalizedProposal {
|
||||
round_number: proposal.round_number as usize,
|
||||
proposal: proposal.proposal,
|
||||
digest: proposal.digest,
|
||||
sender: proposal.sender,
|
||||
digest_signature: ed25519::LocalizedSignature {
|
||||
signature: proposal.digest_signature,
|
||||
signer: ed25519::Public(proposal.sender.into()),
|
||||
},
|
||||
full_signature: ed25519::LocalizedSignature {
|
||||
signature: proposal.full_signature,
|
||||
signer: ed25519::Public(proposal.sender.into()),
|
||||
}
|
||||
};
|
||||
bft::check_proposal(authorities, &msg.parent_hash, &proposal)?;
|
||||
|
||||
trace!(target: "bft", "importing proposal message for round {} from {}", proposal.round_number, Hash::from(proposal.sender.0));
|
||||
proposal
|
||||
}),
|
||||
msg::SignedConsensusMessage::Vote(vote) => rhododendron::LocalizedMessage::Vote({
|
||||
if &vote.sender == local_id { return Ok(None) }
|
||||
let vote = rhododendron::LocalizedVote {
|
||||
sender: vote.sender,
|
||||
signature: ed25519::LocalizedSignature {
|
||||
signature: vote.signature,
|
||||
signer: ed25519::Public(vote.sender.0),
|
||||
},
|
||||
vote: match vote.vote {
|
||||
msg::ConsensusVote::Prepare(r, h) => rhododendron::Vote::Prepare(r as usize, h),
|
||||
msg::ConsensusVote::Commit(r, h) => rhododendron::Vote::Commit(r as usize, h),
|
||||
msg::ConsensusVote::AdvanceRound(r) => rhododendron::Vote::AdvanceRound(r as usize),
|
||||
}
|
||||
};
|
||||
bft::check_vote::<Block>(authorities, &msg.parent_hash, &vote)?;
|
||||
|
||||
trace!(target: "bft", "importing vote {:?} from {}", vote.vote, Hash::from(vote.sender.0));
|
||||
vote
|
||||
}),
|
||||
}),
|
||||
msg::BftMessage::Auxiliary(a) => {
|
||||
let justification = bft::UncheckedJustification::from(a);
|
||||
// TODO: get proper error
|
||||
let justification: Result<_, bft::Error> = bft::check_prepare_justification::<Block>(authorities, msg.parent_hash, justification)
|
||||
.map_err(|_| bft::ErrorKind::InvalidJustification.into());
|
||||
rhododendron::Communication::Auxiliary(justification?)
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
// task that processes all gossipped consensus messages,
|
||||
// checking signatures
|
||||
struct MessageProcessTask {
|
||||
inner_stream: mpsc::UnboundedReceiver<ConsensusMessage<Block>>,
|
||||
bft_messages: mpsc::UnboundedSender<bft::Communication<Block>>,
|
||||
validators: Vec<SessionKey>,
|
||||
local_id: SessionKey,
|
||||
}
|
||||
|
||||
impl MessageProcessTask {
|
||||
fn process_message(&self, msg: ConsensusMessage<Block>) -> Option<Async<()>> {
|
||||
match msg {
|
||||
ConsensusMessage::Bft(msg) => {
|
||||
match process_bft_message(msg, &self.local_id, &self.validators[..]) {
|
||||
Ok(Some(msg)) => {
|
||||
if let Err(_) = self.bft_messages.unbounded_send(msg) {
|
||||
// if the BFT receiving stream has ended then
|
||||
// we should just bail.
|
||||
trace!(target: "bft", "BFT message stream appears to have closed");
|
||||
return Some(Async::Ready(()));
|
||||
}
|
||||
}
|
||||
Ok(None) => {} // ignored local message
|
||||
Err(e) => {
|
||||
debug!("Message validation failed: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
ConsensusMessage::ChainSpecific(_, _) => {
|
||||
panic!("ChainSpecific messages are not allowed by the top level message handler");
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for MessageProcessTask {
|
||||
type Item = ();
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> Poll<(), ()> {
|
||||
loop {
|
||||
match self.inner_stream.poll() {
|
||||
Ok(Async::Ready(Some(val))) => if let Some(async) = self.process_message(val) {
|
||||
return Ok(async);
|
||||
},
|
||||
Ok(Async::Ready(None)) => return Ok(Async::Ready(())),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Err(e) => {
|
||||
debug!(target: "node-network", "Error getting consensus message: {:?}", e);
|
||||
return Err(e);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Input stream from the consensus network.
|
||||
pub struct InputAdapter {
|
||||
input: mpsc::UnboundedReceiver<bft::Communication<Block>>,
|
||||
}
|
||||
|
||||
impl Stream for InputAdapter {
|
||||
type Item = bft::Communication<Block>;
|
||||
type Error = ::node_consensus::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
match self.input.poll() {
|
||||
Err(_) | Ok(Async::Ready(None)) => Err(bft::InputStreamConcluded.into()),
|
||||
Ok(x) => Ok(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around the network service
|
||||
pub struct ConsensusNetwork<P> {
|
||||
network: Arc<NetworkService>,
|
||||
api: Arc<P>,
|
||||
}
|
||||
|
||||
impl<P> ConsensusNetwork<P> {
|
||||
/// Create a new consensus networking object.
|
||||
pub fn new(network: Arc<NetworkService>, api: Arc<P>) -> Self {
|
||||
ConsensusNetwork { network, api }
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> Clone for ConsensusNetwork<P> {
|
||||
fn clone(&self) -> Self {
|
||||
ConsensusNetwork {
|
||||
network: self.network.clone(),
|
||||
api: self.api.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A long-lived network which can create parachain statement and BFT message routing processes on demand.
|
||||
impl<P: AuthoringApi + Send + Sync + 'static> Network for ConsensusNetwork<P> {
|
||||
/// The input stream of BFT messages. Should never logically conclude.
|
||||
type Input = InputAdapter;
|
||||
/// The output sink of BFT messages. Messages sent here should eventually pass to all
|
||||
/// current validators.
|
||||
type Output = BftSink<::node_consensus::Error>;
|
||||
type Block = Block;
|
||||
|
||||
/// Get input and output streams of BFT messages.
|
||||
fn communication_for(
|
||||
&self, validators: &[SessionKey],
|
||||
local_id: SessionKey,
|
||||
parent_hash: Hash,
|
||||
mut task_executor: TaskExecutor
|
||||
) -> (Self::Input, Self::Output)
|
||||
{
|
||||
let sink = BftSink {
|
||||
network: self.network.clone(),
|
||||
parent_hash,
|
||||
_marker: Default::default(),
|
||||
};
|
||||
|
||||
let (bft_send, bft_recv) = mpsc::unbounded();
|
||||
|
||||
// spin up a task in the background that processes all incoming statements
|
||||
// TODO: propagate statements on a timer?
|
||||
let process_task = self.network.with_spec(|spec, _ctx| {
|
||||
spec.consensus_gossip.new_session(parent_hash);
|
||||
MessageProcessTask {
|
||||
inner_stream: spec.consensus_gossip.messages_for(parent_hash),
|
||||
bft_messages: bft_send,
|
||||
validators: validators.to_vec(),
|
||||
local_id,
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(e) = Executor::spawn(&mut task_executor, Box::new(process_task)) {
|
||||
debug!(target: "node-network", "Cannot spawn message processing: {:?}", e)
|
||||
}
|
||||
|
||||
(InputAdapter { input: bft_recv }, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate-specific network implementation.
|
||||
//!
|
||||
//! This manages gossip of consensus messages for BFT.
|
||||
|
||||
#![warn(unused_extern_crates)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate substrate_network;
|
||||
extern crate node_primitives;
|
||||
|
||||
use node_primitives::{Block, Hash};
|
||||
use substrate_network::consensus_gossip::ConsensusGossip;
|
||||
|
||||
/// Specialization of the network service for the node protocol.
|
||||
pub type NetworkService = ::substrate_network::Service<Block, Protocol, Hash>;
|
||||
|
||||
construct_simple_protocol! {
|
||||
/// Demo protocol attachment for substrate.
|
||||
pub struct Protocol where Block = Block {
|
||||
consensus_gossip: ConsensusGossip<Block>,
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ srml-staking = { path = "../../srml/staking" }
|
||||
srml-system = { path = "../../srml/system" }
|
||||
srml-timestamp = { path = "../../srml/timestamp" }
|
||||
srml-treasury = { path = "../../srml/treasury" }
|
||||
srml-upgrade-key = { path = "../../srml/upgrade-key" }
|
||||
sr-version = { path = "../../core/sr-version" }
|
||||
node-primitives = { path = "../primitives" }
|
||||
|
||||
@@ -53,6 +54,7 @@ std = [
|
||||
"srml-system/std",
|
||||
"srml-timestamp/std",
|
||||
"srml-treasury/std",
|
||||
"srml-upgrade-key/std",
|
||||
"sr-version/std",
|
||||
"node-primitives/std",
|
||||
"serde_derive",
|
||||
|
||||
@@ -52,6 +52,7 @@ extern crate srml_staking as staking;
|
||||
extern crate srml_system as system;
|
||||
extern crate srml_timestamp as timestamp;
|
||||
extern crate srml_treasury as treasury;
|
||||
extern crate srml_upgrade_key as upgrade_key;
|
||||
#[macro_use]
|
||||
extern crate sr_version as version;
|
||||
extern crate node_primitives;
|
||||
@@ -62,12 +63,12 @@ use node_primitives::{
|
||||
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
|
||||
SessionKey, Signature
|
||||
};
|
||||
use runtime_api::runtime::*;
|
||||
use runtime_api::{runtime::*, id::*};
|
||||
use runtime_primitives::ApplyResult;
|
||||
use runtime_primitives::transaction_validity::TransactionValidity;
|
||||
use runtime_primitives::generic;
|
||||
use runtime_primitives::traits::{Convert, BlakeTwo256, Block as BlockT};
|
||||
use version::{RuntimeVersion, ApiId};
|
||||
use version::RuntimeVersion;
|
||||
use council::{motions as council_motions, voting as council_voting};
|
||||
#[cfg(feature = "std")]
|
||||
use council::seats as council_seats;
|
||||
@@ -81,14 +82,11 @@ pub use timestamp::Call as TimestampCall;
|
||||
pub use balances::Call as BalancesCall;
|
||||
pub use runtime_primitives::{Permill, Perbill};
|
||||
pub use timestamp::BlockPeriod;
|
||||
pub use srml_support::StorageValue;
|
||||
pub use srml_support::{StorageValue, RuntimeMetadata};
|
||||
|
||||
const TIMESTAMP_SET_POSITION: u32 = 0;
|
||||
const NOTE_OFFLINE_POSITION: u32 = 1;
|
||||
|
||||
const INHERENT: ApiId = *b"inherent";
|
||||
const VALIDATX: ApiId = *b"validatx";
|
||||
|
||||
/// Runtime version.
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: ver_str!("node"),
|
||||
@@ -96,7 +94,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
authoring_version: 1,
|
||||
spec_version: 1,
|
||||
impl_version: 0,
|
||||
apis: apis_vec!([(INHERENT, 1), (VALIDATX, 1)]),
|
||||
apis: apis_vec!([
|
||||
(BLOCK_BUILDER, 1),
|
||||
(TAGGED_TRANSACTION_QUEUE, 1),
|
||||
(METADATA, 1)
|
||||
]),
|
||||
};
|
||||
|
||||
/// Native version.
|
||||
@@ -191,15 +193,19 @@ impl contract::Trait for Runtime {
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
impl upgrade_key::Trait for Runtime {
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime with Log(InternalLog: DigestItem<Hash, SessionKey>) where
|
||||
Block = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic
|
||||
{
|
||||
System: system::{default, Log(ChangesTrieRoot)},
|
||||
Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent},
|
||||
Consensus: consensus::{Module, Call, Storage, Config<T>, Log(AuthoritiesChange), Inherent},
|
||||
Balances: balances,
|
||||
Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent},
|
||||
Session: session,
|
||||
Staking: staking,
|
||||
Democracy: democracy,
|
||||
@@ -209,6 +215,7 @@ construct_runtime!(
|
||||
CouncilSeats: council_seats::{Config<T>},
|
||||
Treasury: treasury,
|
||||
Contract: contract::{Module, Call, Config<T>, Event<T>},
|
||||
UpgradeKey: upgrade_key,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -246,8 +253,8 @@ impl_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl Metadata for Runtime {
|
||||
fn metadata() -> Vec<u8> {
|
||||
impl Metadata<RuntimeMetadata> for Runtime {
|
||||
fn metadata() -> RuntimeMetadata {
|
||||
Runtime::metadata()
|
||||
}
|
||||
}
|
||||
@@ -278,33 +285,9 @@ impl_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl OldTxQueue<AccountId, Index, Address, AccountId> for Runtime {
|
||||
fn account_nonce(account: AccountId) -> Index {
|
||||
System::account_nonce(&account)
|
||||
}
|
||||
|
||||
fn lookup_address(address: Address) -> Option<AccountId> {
|
||||
Balances::lookup_address(address)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaggedTransactionQueue<Block, TransactionValidity> for Runtime {
|
||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
Executive::validate_transaction(tx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Miscellaneous<AccountId, u64> for Runtime {
|
||||
fn validator_count() -> u32 {
|
||||
Session::validator_count()
|
||||
}
|
||||
|
||||
fn validators() -> Vec<AccountId> {
|
||||
Session::validators()
|
||||
}
|
||||
|
||||
fn timestamp() -> u64 {
|
||||
Timestamp::get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+19
@@ -285,6 +285,7 @@ dependencies = [
|
||||
"srml-system 0.1.0",
|
||||
"srml-timestamp 0.1.0",
|
||||
"srml-treasury 0.1.0",
|
||||
"srml-upgrade-key 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
]
|
||||
|
||||
@@ -817,6 +818,24 @@ dependencies = [
|
||||
"substrate-primitives 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srml-upgrade-key"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 0.1.0",
|
||||
"sr-primitives 0.1.0",
|
||||
"sr-std 0.1.0",
|
||||
"srml-consensus 0.1.0",
|
||||
"srml-support 0.1.0",
|
||||
"srml-system 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.1.1"
|
||||
|
||||
@@ -28,6 +28,7 @@ srml-staking = { path = "../../../srml/staking", default-features = false }
|
||||
srml-system = { path = "../../../srml/system", default-features = false }
|
||||
srml-timestamp = { path = "../../../srml/timestamp", default-features = false }
|
||||
srml-treasury = { path = "../../../srml/treasury", default-features = false }
|
||||
srml-upgrade-key = { path = "../../../srml/upgrade-key", default-features = false }
|
||||
sr-version = { path = "../../../core/sr-version", default-features = false }
|
||||
node-primitives = { path = "../../primitives", default-features = false }
|
||||
|
||||
@@ -53,6 +54,7 @@ std = [
|
||||
"srml-system/std",
|
||||
"srml-timestamp/std",
|
||||
"srml-treasury/std",
|
||||
"srml-upgrade-key/std",
|
||||
"sr-version/std",
|
||||
"node-primitives/std",
|
||||
]
|
||||
|
||||
BIN
Binary file not shown.
@@ -52,7 +52,6 @@ extern crate sr_primitives as primitives;
|
||||
// depend on it being around.
|
||||
extern crate srml_system as system;
|
||||
|
||||
use primitives::traits::OnFinalise;
|
||||
use runtime_support::{StorageValue, StorageMap, dispatch::Result, Parameter};
|
||||
use primitives::traits::{Member, SimpleArithmetic, Zero};
|
||||
use system::ensure_signed;
|
||||
@@ -70,16 +69,47 @@ type AssetId = u32;
|
||||
decl_module! {
|
||||
// Simple declaration of the `Module` type. Lets the macro know what its working on.
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
fn deposit_event() = default;
|
||||
/// Issue a new class of fungible assets. There are, and will only ever be, `total`
|
||||
/// such assets and they'll all belong to the `origin` initially. It will have an
|
||||
/// identifier `AssetId` instance: this will be specified in the `Issued` event.
|
||||
fn issue(origin, total: T::Balance) -> Result;
|
||||
fn issue(origin, total: T::Balance) -> Result {
|
||||
let origin = ensure_signed(origin)?;
|
||||
|
||||
let id = Self::next_asset_id();
|
||||
<NextAssetId<T>>::mutate(|id| *id += 1);
|
||||
|
||||
<Balances<T>>::insert((id, origin.clone()), total);
|
||||
|
||||
Self::deposit_event(RawEvent::Issued(id, origin, total));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move some assets from one holder to another.
|
||||
fn transfer(origin, id: AssetId, target: T::AccountId, total: T::Balance) -> Result;
|
||||
fn transfer(origin, id: AssetId, target: T::AccountId, amount: T::Balance) -> Result {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let origin_account = (id, origin.clone());
|
||||
let origin_balance = <Balances<T>>::get(&origin_account);
|
||||
ensure!(origin_balance >= amount, "origin account balance must be greater than amount");
|
||||
|
||||
Self::deposit_event(RawEvent::Transfered(id, origin, target.clone(), amount));
|
||||
<Balances<T>>::insert(origin_account, origin_balance - amount);
|
||||
<Balances<T>>::mutate((id, target), |balance| *balance += amount);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Destroy any assets of `id` owned by `origin`.
|
||||
fn destroy(origin, id: AssetId) -> Result;
|
||||
fn destroy(origin, id: AssetId) -> Result {
|
||||
let origin = ensure_signed(origin)?;
|
||||
|
||||
let balance = <Balances<T>>::take((id, origin.clone()));
|
||||
ensure!(!balance.is_zero(), "origin balance should be non-zero");
|
||||
|
||||
Self::deposit_event(RawEvent::Destroyed(id, origin, balance));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,62 +138,14 @@ decl_storage! {
|
||||
|
||||
// The main implementation block for the module.
|
||||
impl<T: Trait> Module<T> {
|
||||
/// Deposit one of this module's events.
|
||||
// TODO: move into `decl_module` macro.
|
||||
fn deposit_event(event: Event<T>) {
|
||||
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
|
||||
}
|
||||
|
||||
// Public immutables
|
||||
|
||||
/// Get the asset `id` balance of `who`.
|
||||
pub fn balance(id: AssetId, who: T::AccountId) -> T::Balance {
|
||||
<Balances<T>>::get((id, who))
|
||||
}
|
||||
|
||||
// Implement Calls and add public immutables and private mutables.
|
||||
|
||||
fn issue(origin: T::Origin, total: T::Balance) -> Result {
|
||||
let origin = ensure_signed(origin)?;
|
||||
|
||||
let id = Self::next_asset_id();
|
||||
<NextAssetId<T>>::mutate(|id| *id += 1);
|
||||
|
||||
|
||||
<Balances<T>>::insert((id, origin.clone()), total);
|
||||
|
||||
Self::deposit_event(RawEvent::Issued(id, origin, total));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer(origin: T::Origin, id: AssetId, target: T::AccountId, amount: T::Balance) -> Result {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let origin_account = (id, origin.clone());
|
||||
let origin_balance = <Balances<T>>::get(&origin_account);
|
||||
ensure!(origin_balance >= amount, "origin account balance must be greater than amount");
|
||||
|
||||
Self::deposit_event(RawEvent::Transfered(id, origin, target.clone(), amount));
|
||||
<Balances<T>>::insert(origin_account, origin_balance - amount);
|
||||
<Balances<T>>::mutate((id, target), |balance| *balance += amount);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy(origin: T::Origin, id: AssetId) -> Result {
|
||||
let origin = ensure_signed(origin)?;
|
||||
|
||||
let balance = <Balances<T>>::take((id, origin.clone()));
|
||||
ensure!(!balance.is_zero(), "origin balance should be non-zero");
|
||||
|
||||
Self::deposit_event(RawEvent::Destroyed(id, origin, balance));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// This trait expresses what should happen when the block is finalised.
|
||||
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -44,7 +44,7 @@ use rstd::{cmp, result};
|
||||
use codec::{Encode, Decode, Codec, Input, Output, HasCompact};
|
||||
use runtime_support::{StorageValue, StorageMap, Parameter};
|
||||
use runtime_support::dispatch::Result;
|
||||
use primitives::traits::{Zero, One, SimpleArithmetic, OnFinalise, MakePayment,
|
||||
use primitives::traits::{Zero, One, SimpleArithmetic, MakePayment,
|
||||
As, Lookup, Member, CheckedAdd, CheckedSub, CurrentHeight, BlockNumberToHash};
|
||||
use address::Address as RawAddress;
|
||||
use system::ensure_signed;
|
||||
@@ -125,8 +125,64 @@ pub trait Trait: system::Trait {
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
fn transfer(origin, dest: RawAddress<T::AccountId, T::AccountIndex>, value: <T::Balance as HasCompact>::Type) -> Result;
|
||||
fn set_balance(who: RawAddress<T::AccountId, T::AccountIndex>, free: <T::Balance as HasCompact>::Type, reserved: <T::Balance as HasCompact>::Type) -> Result;
|
||||
fn deposit_event() = default;
|
||||
|
||||
/// Transfer some liquid free balance to another staker.
|
||||
pub fn transfer(
|
||||
origin,
|
||||
dest: RawAddress<T::AccountId, T::AccountIndex>,
|
||||
value: <T::Balance as HasCompact>::Type
|
||||
) -> Result {
|
||||
let transactor = ensure_signed(origin)?;
|
||||
|
||||
let dest = Self::lookup(dest)?;
|
||||
let value = value.into();
|
||||
let from_balance = Self::free_balance(&transactor);
|
||||
let to_balance = Self::free_balance(&dest);
|
||||
let would_create = to_balance.is_zero();
|
||||
let fee = if would_create { Self::creation_fee() } else { Self::transfer_fee() };
|
||||
let liability = match value.checked_add(&fee) {
|
||||
Some(l) => l,
|
||||
None => return Err("got overflow after adding a fee to value"),
|
||||
};
|
||||
|
||||
let new_from_balance = match from_balance.checked_sub(&liability) {
|
||||
Some(b) => b,
|
||||
None => return Err("balance too low to send value"),
|
||||
};
|
||||
if would_create && value < Self::existential_deposit() {
|
||||
return Err("value too low to create account");
|
||||
}
|
||||
T::EnsureAccountLiquid::ensure_account_liquid(&transactor)?;
|
||||
|
||||
// NOTE: total stake being stored in the same type means that this could never overflow
|
||||
// but better to be safe than sorry.
|
||||
let new_to_balance = match to_balance.checked_add(&value) {
|
||||
Some(b) => b,
|
||||
None => return Err("destination balance too high to receive value"),
|
||||
};
|
||||
|
||||
if transactor != dest {
|
||||
Self::set_free_balance(&transactor, new_from_balance);
|
||||
Self::decrease_total_stake_by(fee);
|
||||
Self::set_free_balance_creating(&dest, new_to_balance);
|
||||
Self::deposit_event(RawEvent::Transfer(transactor, dest, value, fee));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the balances of a given account.
|
||||
fn set_balance(
|
||||
who: RawAddress<T::AccountId, T::AccountIndex>,
|
||||
free: <T::Balance as HasCompact>::Type,
|
||||
reserved: <T::Balance as HasCompact>::Type
|
||||
) -> Result {
|
||||
let who = Self::lookup(who)?;
|
||||
Self::set_free_balance(&who, free.into());
|
||||
Self::set_reserved_balance(&who, reserved.into());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,12 +288,6 @@ pub enum UpdateBalanceOutcome {
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
|
||||
/// Deposit one of this module's events.
|
||||
fn deposit_event(event: Event<T>) {
|
||||
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
|
||||
}
|
||||
|
||||
// PUBLIC IMMUTABLES
|
||||
|
||||
/// The combined balance of `who`.
|
||||
@@ -285,58 +335,7 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// PUBLIC DISPATCH
|
||||
|
||||
/// Transfer some liquid free balance to another staker.
|
||||
pub fn transfer(origin: T::Origin, dest: Address<T>, value: <T::Balance as HasCompact>::Type) -> Result {
|
||||
let transactor = ensure_signed(origin)?;
|
||||
|
||||
let dest = Self::lookup(dest)?;
|
||||
let value = value.into();
|
||||
let from_balance = Self::free_balance(&transactor);
|
||||
let to_balance = Self::free_balance(&dest);
|
||||
let would_create = to_balance.is_zero();
|
||||
let fee = if would_create { Self::creation_fee() } else { Self::transfer_fee() };
|
||||
let liability = match value.checked_add(&fee) {
|
||||
Some(l) => l,
|
||||
None => return Err("got overflow after adding a fee to value"),
|
||||
};
|
||||
|
||||
let new_from_balance = match from_balance.checked_sub(&liability) {
|
||||
Some(b) => b,
|
||||
None => return Err("balance too low to send value"),
|
||||
};
|
||||
if would_create && value < Self::existential_deposit() {
|
||||
return Err("value too low to create account");
|
||||
}
|
||||
T::EnsureAccountLiquid::ensure_account_liquid(&transactor)?;
|
||||
|
||||
// NOTE: total stake being stored in the same type means that this could never overflow
|
||||
// but better to be safe than sorry.
|
||||
let new_to_balance = match to_balance.checked_add(&value) {
|
||||
Some(b) => b,
|
||||
None => return Err("destination balance too high to receive value"),
|
||||
};
|
||||
|
||||
if transactor != dest {
|
||||
Self::set_free_balance(&transactor, new_from_balance);
|
||||
Self::decrease_total_stake_by(fee);
|
||||
Self::set_free_balance_creating(&dest, new_to_balance);
|
||||
Self::deposit_event(RawEvent::Transfer(transactor, dest, value, fee));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the balances of a given account.
|
||||
fn set_balance(who: Address<T>, free: <T::Balance as HasCompact>::Type, reserved: <T::Balance as HasCompact>::Type) -> Result {
|
||||
let who = Self::lookup(who)?;
|
||||
Self::set_free_balance(&who, free.into());
|
||||
Self::set_reserved_balance(&who, reserved.into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// PUBLIC MUTABLES (DANGEROUS)
|
||||
//PUBLIC MUTABLES (DANGEROUS)
|
||||
|
||||
/// Set the free balance of an account to some new value.
|
||||
///
|
||||
@@ -424,6 +423,23 @@ impl<T: Trait> Module<T> {
|
||||
Self::set_free_balance_creating(who, Self::free_balance(who) + value)
|
||||
}
|
||||
|
||||
/// Substrates `value` from the free balance of `who`. If the whole amount cannot be
|
||||
/// deducted, an error is returned.
|
||||
///
|
||||
/// NOTE: This assumes that the total stake remains unchanged after this operation. If
|
||||
/// you mean to actually burn value out of existence, then use `slash` instead.
|
||||
pub fn decrease_free_balance(
|
||||
who: &T::AccountId,
|
||||
value: T::Balance
|
||||
) -> result::Result<UpdateBalanceOutcome, &'static str> {
|
||||
T::EnsureAccountLiquid::ensure_account_liquid(who)?;
|
||||
let b = Self::free_balance(who);
|
||||
if b < value {
|
||||
return Err("account has too few funds")
|
||||
}
|
||||
Ok(Self::set_free_balance(who, b - value))
|
||||
}
|
||||
|
||||
/// Deducts up to `value` from the combined balance of `who`, preferring to deduct from the
|
||||
/// free balance. This function cannot fail.
|
||||
///
|
||||
@@ -652,11 +668,6 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
|
||||
fn on_finalise(_n: T::BlockNumber) {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChainContext<T>(::rstd::marker::PhantomData<T>);
|
||||
impl<T> Default for ChainContext<T> {
|
||||
fn default() -> Self {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user