diff --git a/substrate/.gitlab-ci.yml b/substrate/.gitlab-ci.yml index b803ce3d57252629b1785724ee29679ad4ee7670..c87cdae7c3562ad2a90ce0b8cbcace2aec64b620 100644 --- a/substrate/.gitlab-ci.yml +++ b/substrate/.gitlab-ci.yml @@ -2,7 +2,7 @@ stages: - test - build -image: parity/rust:substrate +image: parity/rust:nightly variables: CI_SERVER_NAME: "GitLab CI" diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index df76975816b72f11d52ef325cb5a331f6fef3f84..ab11df3d8a09734c3745d6ff6ec8f8c26e3a5d5f 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -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,11 +1598,16 @@ 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", + "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)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "substrate-cli 0.3.0", + "substrate-client 0.1.0", + "substrate-consensus-aura 0.1.0", "substrate-network 0.1.0", "substrate-primitives 0.1.0", "substrate-service 0.3.0", @@ -1611,28 +1616,6 @@ dependencies = [ "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)", - "sr-primitives 0.1.0", - "srml-system 0.1.0", - "substrate-client 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)", -] - [[package]] name = "node-executor" version = "0.1.0" @@ -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" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index f47fa42507b6235472859a6ef4ed284f18e0d820..54ae7d9d82355cd57ee0b61404a3c6c8a32a6329 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -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", diff --git a/substrate/README.adoc b/substrate/README.adoc index f0aa15c4f9317208c04301869c2987f3ce7aef9b..11fdd616b239235fb77b392bd493f9ce36b68f36 100644 --- a/substrate/README.adoc +++ b/substrate/README.adoc @@ -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] diff --git a/substrate/core/client/Cargo.toml b/substrate/core/client/Cargo.toml index ba457fbb9cbc01db618e1f4caee80cadb187f08b..5eeb75940d4b188270921d440bd5469624ebf86b 100644 --- a/substrate/core/client/Cargo.toml +++ b/substrate/core/client/Cargo.toml @@ -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" } diff --git a/substrate/core/transaction-pool/src/README.adoc b/substrate/core/client/db/README.adoc similarity index 87% rename from substrate/core/transaction-pool/src/README.adoc rename to substrate/core/client/db/README.adoc index 48052d0fde96f171d25fcf8ddb849f4297b690eb..c0b123392c81687523fc582182c6278ebf085a53 100644 --- a/substrate/core/transaction-pool/src/README.adoc +++ b/substrate/core/client/db/README.adoc @@ -1,5 +1,5 @@ -= transaction-pool += Client DB .Summary [source, toml] diff --git a/substrate/core/client/db/src/lib.rs b/substrate/core/client/db/src/lib.rs index f35dd8a05da1d80eb94c28360d31323e6cdac2ee..36ab5f4b2a58c0748ab57a30c2340ca437b3a9b9 100644 --- a/substrate/core/client/db/src/lib.rs +++ b/substrate/core/client/db/src/lib.rs @@ -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 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 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 { - 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(); + BlockId::Number(i - 1) + }; + + 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()) } } diff --git a/substrate/core/client/db/src/light.rs b/substrate/core/client/db/src/light.rs index 49e5e85be1bf51406597796033df129c6d1ebc73..f336df4d28effc231b3cf37504c71a13f8b7a250 100644 --- a/substrate/core/client/db/src/light.rs +++ b/substrate/core/client/db/src/light.rs @@ -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); diff --git a/substrate/core/client/db/src/utils.rs b/substrate/core/client/db/src/utils.rs index b32b56bccc8593997b8cd6fba95bdfac0b3ba0ca..f7b81845e8e7ca93edb184722a74942147e0f6a2 100644 --- a/substrate/core/client/db/src/utils.rs +++ b/substrate/core/client/db/src/utils.rs @@ -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, diff --git a/substrate/core/client/src/call_executor.rs b/substrate/core/client/src/call_executor.rs index 2b442a35695847e2092da832e420bbf4b0a4880d..168d0a26c5fc0040f8f2b50b5fb34466cddae3ea 100644 --- a/substrate/core/client/src/call_executor.rs +++ b/substrate/core/client/src/call_executor.rs @@ -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) diff --git a/substrate/core/client/src/client.rs b/substrate/core/client/src/client.rs index 2567e43a951a1db63aa02ab8f24eb287299fbed9..a82b2133f0e10354e3e4e21e566b00a31bc03c1f 100644 --- a/substrate/core/client/src/client.rs +++ b/substrate/core/client/src/client.rs @@ -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}; diff --git a/substrate/core/client/src/error.rs b/substrate/core/client/src/error.rs index 5abc2617b2964d9e8c9ca1fcb4a5fae4b3db36e7..139cef13daba54de5c869d222ebc6159d4bbddfe 100644 --- a/substrate/core/client/src/error.rs +++ b/substrate/core/client/src/error.rs @@ -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) { diff --git a/substrate/core/client/src/lib.rs b/substrate/core/client/src/lib.rs index 9526091dadebd03352b21f3051f4ea6f5f84887c..a0332779052b48414607b0460af3eefb88ec2243 100644 --- a/substrate/core/client/src/lib.rs +++ b/substrate/core/client/src/lib.rs @@ -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; diff --git a/substrate/core/client/src/light/fetcher.rs b/substrate/core/client/src/light/fetcher.rs index 702c9b703458f84ca33b002be1d7e768a2c1995f..38a46c7d68dc6172af32d041e842bfaa1519c5e7 100644 --- a/substrate/core/client/src/light/fetcher.rs +++ b/substrate/core/client/src/light/fetcher.rs @@ -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}; diff --git a/substrate/core/consensus/aura/Cargo.toml b/substrate/core/consensus/aura/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..0f403ab2ff65f59b9039e55fa42c5267d5cc3bfb --- /dev/null +++ b/substrate/core/consensus/aura/Cargo.toml @@ -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", +] + diff --git a/substrate/core/consensus/aura/src/lib.rs b/substrate/core/consensus/aura/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7355119074eba88b7f51fc8cf24fb5ee90a026a7 --- /dev/null +++ b/substrate/core/consensus/aura/src/lib.rs @@ -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(); + } +} diff --git a/substrate/core/consensus/common/Cargo.toml b/substrate/core/consensus/common/Cargo.toml index ed39cf8fd4a0513fc4b7fba763655596ae304445..08689721a03fcba87158cce42c9fe3b8c14abbbb 100644 --- a/substrate/core/consensus/common/Cargo.toml +++ b/substrate/core/consensus/common/Cargo.toml @@ -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" diff --git a/substrate/core/consensus/common/README.adoc b/substrate/core/consensus/common/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..d8f9e1daf28d915bd78ed693d8f40933323aca2f --- /dev/null +++ b/substrate/core/consensus/common/README.adoc @@ -0,0 +1,12 @@ += Consensus Common + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/consensus/common/src/block_import.rs b/substrate/core/consensus/common/src/block_import.rs new file mode 100644 index 0000000000000000000000000000000000000000..582886d8272e1f853d6f4ee3483807c69bf48bed --- /dev/null +++ b/substrate/core/consensus/common/src/block_import.rs @@ -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>; +} \ No newline at end of file diff --git a/substrate/core/consensus/common/src/error.rs b/substrate/core/consensus/common/src/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..ccf57adb9f1be04fb4960c69c7380b62520a069c --- /dev/null +++ b/substrate/core/consensus/common/src/error.rs @@ -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()) + } + } +} diff --git a/substrate/node/consensus/src/evaluation.rs b/substrate/core/consensus/common/src/evaluation.rs similarity index 73% rename from substrate/node/consensus/src/evaluation.rs rename to substrate/core/consensus/common/src/evaluation.rs index c21c202e960bb7b1929180a099343cbf18aeb573..db35e2f4115c3c7bac0a1ec2db40be1b9d4d989b 100644 --- a/substrate/node/consensus/src/evaluation.rs +++ b/substrate/core/consensus/common/src/evaluation.rs @@ -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(()) diff --git a/substrate/core/consensus/common/src/lib.rs b/substrate/core/consensus/common/src/lib.rs index 390e7beadeabc9ba4e5e9f1997b4895480d2826a..12d5cfa70df2f27833997ca7adc7d65a9eafc71c 100644 --- a/substrate/core/consensus/common/src/lib.rs +++ b/substrate/core/consensus/common/src/lib.rs @@ -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) + } +} diff --git a/substrate/core/consensus/rhd/Cargo.toml b/substrate/core/consensus/rhd/Cargo.toml index f5b928c42920bf03e4e1f31427297dd8b86c8d9f..dce6a6d7f445abd16193672ea726cdf266f2f339 100644 --- a/substrate/core/consensus/rhd/Cargo.toml +++ b/substrate/core/consensus/rhd/Cargo.toml @@ -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", diff --git a/substrate/core/consensus/rhd/README.adoc b/substrate/core/consensus/rhd/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..ff7bde17146ad5e84d317517c6580347f4221112 --- /dev/null +++ b/substrate/core/consensus/rhd/README.adoc @@ -0,0 +1,12 @@ += Consensus Rhododendron (RHD) + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/consensus/rhd/src/error.rs b/substrate/core/consensus/rhd/src/error.rs index 806ba5624a3ad717e38127797fadd6321accbaf5..c18c36f679c830d20e623af83bc6f7b059349171 100644 --- a/substrate/core/consensus/rhd/src/error.rs +++ b/substrate/core/consensus/rhd/src/error.rs @@ -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), - } - - /// 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."), + NotValidator(id: AuthorityId) { + description("Local account ID not a validator at this block."), + display("Local account ID ({:?}) not a validator at this block.", id), } - - /// 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."), + PrematureDestruction { + description("Proposer destroyed before finishing proposing or evaluating"), + display("Proposer destroyed before finishing proposing or evaluating"), } - - /// Justification requirements not met. - InvalidJustification { - description("Invalid justification"), - display("Invalid justification."), + Timer(e: ::tokio::timer::Error) { + description("Failed to register or resolve async timer."), + display("Timer failed: {}", e), } - - /// 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() + } +} \ No newline at end of file diff --git a/substrate/core/consensus/rhd/src/lib.rs b/substrate/core/consensus/rhd/src/lib.rs index 4edc8fc89337fecf8a65c07a9bcda1e05c4588a4..b99ea4a24c71593654f223aee2edc67153a4e133 100644 --- a/substrate/core/consensus/rhd/src/lib.rs +++ b/substrate/core/consensus/rhd/src/lib.rs @@ -14,6 +14,7 @@ // 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[] //! BFT Agreement based on a rotating proposer in different rounds. //! //! Where this crate refers to input stream, should never logically conclude. @@ -29,61 +30,76 @@ //! conclude without having witnessed the conclusion. //! In general, this future should be pre-empted by the import of a justification //! set for this block height. +// end::description[] -#![cfg(feature = "rhd")] - -#![recursion_limit="128"] +#![cfg(feature="rhd")] +// FIXME: doesn't compile - https://github.com/paritytech/substrate/issues/1020 extern crate parity_codec as codec; extern crate substrate_primitives as primitives; +extern crate substrate_client as client; +extern crate substrate_consensus_common as consensus; +extern crate substrate_transaction_pool as transaction_pool; +extern crate srml_system; 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; extern crate parking_lot; extern crate rhododendron; +extern crate futures; +extern crate exit_future; +extern crate tokio; #[macro_use] extern crate log; - -extern crate futures; - #[macro_use] extern crate error_chain; -#[macro_use] -extern crate serde; - #[macro_use] extern crate parity_codec_derive; - -pub mod error; +#[cfg(test)] +extern crate substrate_keyring; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::time::{Instant, Duration}; - -use codec::Encode; -use runtime_primitives::{generic::BlockId, Justification}; +use std::time::{self, Instant, Duration}; + +use codec::{Decode, Encode}; +use consensus::offline_tracker::OfflineTracker; +use consensus::error::{ErrorKind as CommonErrorKind}; +use consensus::{Authorities, BlockImport, Environment, Proposer as BaseProposer}; +use client::{Client as SubstrateClient, CallExecutor}; +use client::runtime_api::{Core, BlockBuilder as BlockBuilderAPI, OldTxQueue, BlockBuilderError}; +use runtime_primitives::generic::{BlockId, Era, ImportResult, ImportBlock, BlockOrigin}; use runtime_primitives::traits::{Block, Header}; -use primitives::{AuthorityId, ed25519, ed25519::LocalizedSignature}; +use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, As, BlockNumberToHash}; +use runtime_primitives::Justification; +use primitives::{AuthorityId, ed25519, Blake2Hasher, ed25519::LocalizedSignature}; +use srml_system::Trait as SystemT; -use futures::{Async, Stream, Sink, Future, IntoFuture}; +use node_runtime::Runtime; +use transaction_pool::txpool::{self, Pool as TransactionPool}; + +use futures::prelude::*; +use futures::future; use futures::sync::oneshot; +use tokio::runtime::TaskExecutor; use tokio::timer::Delay; -use parking_lot::Mutex; +use parking_lot::{RwLock, Mutex}; -pub use rhododendron::{InputStreamConcluded, AdvanceRoundReason, - Message as RhdMessage, Vote as RhdMessageVote}; -pub use error::{Error, ErrorKind}; +pub use rhododendron::{ + self, InputStreamConcluded, AdvanceRoundReason, Message as RhdMessage, + Vote as RhdMessageVote, Communication as RhdCommunication, +}; +pub use self::error::{Error, ErrorKind}; // pub mod misbehaviour_check; +mod error; +mod service; // statuses for an agreement mod status { @@ -92,6 +108,10 @@ mod status { pub const GOOD: usize = 2; } +pub type Timestamp = u64; + +pub type AccountId = ::primitives::H256; + /// Localized message type. pub type LocalizedMessage<B> = rhododendron::LocalizedMessage< B, @@ -100,8 +120,6 @@ pub type LocalizedMessage<B> = rhododendron::LocalizedMessage< LocalizedSignature >; - - /// Justification of some hash. pub struct RhdJustification<H>(rhododendron::Justification<H, LocalizedSignature>); @@ -109,11 +127,12 @@ pub struct RhdJustification<H>(rhododendron::Justification<H, LocalizedSignature pub struct PrepareJustification<H>(rhododendron::PrepareJustification<H, LocalizedSignature>); /// Unchecked justification. +#[derive(Encode, Decode)] pub struct UncheckedJustification<H>(rhododendron::UncheckedJustification<H, LocalizedSignature>); impl<H> UncheckedJustification<H> { /// Create a new, unchecked justification. - pub fn new(digest: H, signatures: Vec<LocalizedSignature>, round_number: usize) -> Self { + pub fn new(digest: H, signatures: Vec<LocalizedSignature>, round_number: u32) -> Self { UncheckedJustification(rhododendron::UncheckedJustification { digest, signatures, @@ -122,40 +141,24 @@ impl<H> UncheckedJustification<H> { } } -impl<H> Into<Justification> for RhdJustification<H> { - fn into(self) -> Justification { - let p : Justification = UncheckedJustification(self.0.uncheck()).into(); - p - } -} - +impl<H: Decode> UncheckedJustification<H> { + /// Decode a justification. + pub fn decode_justification(justification: Justification) -> Option<Self> { + let inner: rhododendron::UncheckedJustification<_, _> = Decode::decode(&mut &justification[..])?; -impl<H> From<rhododendron::UncheckedJustification<H, LocalizedSignature>> for UncheckedJustification<H> { - fn from(inner: rhododendron::UncheckedJustification<H, LocalizedSignature>) -> Self { - UncheckedJustification(inner) + Some(UncheckedJustification(inner)) } } -impl<H> From<Justification> for UncheckedJustification<H> { - fn from(just: Justification) -> Self { - UncheckedJustification(rhododendron::UncheckedJustification { - round_number: just.round_number as usize, - digest: just.hash, - signatures: just.signatures.into_iter().map(|(from, sig)| LocalizedSignature { - signer: from.into(), - signature: sig, - }).collect(), - }) +impl<H: Encode> Into<Justification> for UncheckedJustification<H> { + fn into(self) -> Justification { + self.0.encode() } } -impl<H> Into<Justification> for UncheckedJustification<H> { - fn into(self) -> Justification { - Justification { - round_number: self.0.round_number as u32, - hash: self.0.digest, - signatures: self.0.signatures.into_iter().map(|s| (s.signer.into(), s.signature)).collect(), - } +impl<H> From<rhododendron::UncheckedJustification<H, LocalizedSignature>> for UncheckedJustification<H> { + fn from(inner: rhododendron::UncheckedJustification<H, LocalizedSignature>) -> Self { + UncheckedJustification(inner) } } @@ -168,59 +171,72 @@ pub type Communication<B> = rhododendron::Communication<B, <B as Block>::Hash, A /// Misbehavior observed from BFT participants. pub type Misbehavior<H> = rhododendron::Misbehavior<H, LocalizedSignature>; -/// Environment producer for a BFT instance. Creates proposer instance and communication streams. -pub trait Environment<B: Block> { - /// The proposer type this creates. - type Proposer: Proposer<B>; - /// The input stream type. - type Input: Stream<Item=Communication<B>, Error=<Self::Proposer as Proposer<B>>::Error>; - /// The output stream type. - type Output: Sink<SinkItem=Communication<B>, SinkError=<Self::Proposer as Proposer<B>>::Error>; - /// Error which can occur upon creation. - type Error: From<Error>; - - /// Initialize the proposal logic on top of a specific header. - /// Produces the proposer and message streams for this instance of BFT agreement. - // TODO: provide state context explicitly? - fn init(&self, parent_header: &B::Header, authorities: &[AuthorityId], sign_with: Arc<ed25519::Pair>) - -> Result<(Self::Proposer, Self::Input, Self::Output), Self::Error>; -} +/// Shared offline validator tracker. +pub type SharedOfflineTracker = Arc<RwLock<OfflineTracker>>; -/// 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> + From<InputStreamConcluded> + ::std::fmt::Debug + 'static; - /// Future that resolves to a committed proposal. - type Create: IntoFuture<Item=B,Error=Self::Error>; - /// Future that resolves when a proposal is evaluated. - type Evaluate: IntoFuture<Item=bool,Error=Self::Error>; - - /// Create a proposal. - fn propose(&self) -> Self::Create; - - /// Evaluate proposal. True means valid. - fn evaluate(&self, proposal: &B) -> Self::Evaluate; - - /// Import witnessed misbehavior. +/// A proposer for a rhododendron instance. This must implement the base proposer logic. +pub trait LocalProposer<B: Block>: BaseProposer<B, Error=Error> { + /// Import witnessed rhododendron misbehavior. fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, Misbehavior<B::Hash>)>); /// Determine the proposer for a given round. This should be a deterministic function /// with consistent results across all authorities. - fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId; + fn round_proposer(&self, round_number: u32, authorities: &[AuthorityId]) -> AuthorityId; /// Hook called when a BFT round advances without a proposal. - fn on_round_end(&self, _round_number: usize, _proposed: bool) { } + fn on_round_end(&self, _round_number: u32, _proposed: bool) { } +} + + +/// 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>; } -/// Trait for getting the authorities at a given block. -pub trait Authorities<B: Block> { - /// Get the authorities at the given block. - fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityId>, 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> + + 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, Error>; } +/// 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=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=Communication<Self::Block>,SinkError=Error>; + + /// Instantiate input and output streams. + fn communication_for( + &self, + validators: &[AuthorityId], + local_id: AuthorityId, + parent_hash: <Self::Block as BlockT>::Hash, + task_executor: TaskExecutor + ) -> (Self::Input, Self::Output); +} + + // caches the round number to start at if we end up with BFT consensus on the same // parent hash more than once (happens if block is bad). // @@ -229,7 +245,7 @@ pub trait Authorities<B: Block> { #[derive(Debug)] struct RoundCache<H> { hash: Option<H>, - start_round: usize, + start_round: u32, } /// Instance of BFT agreement. @@ -242,19 +258,19 @@ struct BftInstance<B: Block, P> { proposer: P, } -impl<B: Block, P: Proposer<B>> BftInstance<B, P> +impl<B: Block, P: LocalProposer<B>> BftInstance<B, P> where B: Clone + Eq, B::Hash: ::std::hash::Hash { - fn round_timeout_duration(&self, round: usize) -> Duration { + fn round_timeout_duration(&self, round: u32) -> Duration { // 2^(min(6, x/8)) * 10 // Grows exponentially starting from 10 seconds, capped at 640 seconds. - const ROUND_INCREMENT_STEP: usize = 8; + const ROUND_INCREMENT_STEP: u32 = 8; let round = round / ROUND_INCREMENT_STEP; - let round = ::std::cmp::min(6, round) as u32; + let round = ::std::cmp::min(6, round); let timeout = 1u64.checked_shl(round) .unwrap_or_else(u64::max_value) @@ -263,7 +279,7 @@ impl<B: Block, P: Proposer<B>> BftInstance<B, P> Duration::from_secs(timeout) } - fn update_round_cache(&self, current_round: usize) { + fn update_round_cache(&self, current_round: u32) { let mut cache = self.cache.lock(); if cache.hash.as_ref() == Some(&self.parent_hash) { cache.start_round = current_round + 1; @@ -271,7 +287,7 @@ impl<B: Block, P: Proposer<B>> BftInstance<B, P> } } -impl<B: Block, P: Proposer<B>> rhododendron::Context for BftInstance<B, P> +impl<B: Block, P: LocalProposer<B>> rhododendron::Context for BftInstance<B, P> where B: Clone + Eq, B::Hash: ::std::hash::Hash, @@ -301,7 +317,7 @@ impl<B: Block, P: Proposer<B>> rhododendron::Context for BftInstance<B, P> sign_message(message, &*self.key, self.parent_hash.clone()) } - fn round_proposer(&self, round: usize) -> AuthorityId { + fn round_proposer(&self, round: u32) -> AuthorityId { self.proposer.round_proposer(round, &self.authorities[..]) } @@ -309,10 +325,10 @@ impl<B: Block, P: Proposer<B>> rhododendron::Context for BftInstance<B, P> self.proposer.evaluate(proposal).into_future() } - fn begin_round_timeout(&self, round: usize) -> Self::RoundTimeout { + fn begin_round_timeout(&self, round: u32) -> Self::RoundTimeout { let timeout = self.round_timeout_duration(round); let fut = Delay::new(Instant::now() + timeout) - .map_err(|e| Error::from(ErrorKind::FaultyTimer(e))) + .map_err(|e| Error::from(CommonErrorKind::FaultyTimer(e))) .map_err(Into::into); Box::new(fut) @@ -320,9 +336,9 @@ impl<B: Block, P: Proposer<B>> rhododendron::Context for BftInstance<B, P> fn on_advance_round( &self, - accumulator: &::rhododendron::Accumulator<B, B::Hash, Self::AuthorityId, Self::Signature>, - round: usize, - next_round: usize, + accumulator: &rhododendron::Accumulator<B, B::Hash, Self::AuthorityId, Self::Signature>, + round: u32, + next_round: u32, reason: AdvanceRoundReason, ) { use std::collections::HashSet; @@ -332,12 +348,12 @@ impl<B: Block, P: Proposer<B>> rhododendron::Context for BftInstance<B, P> .collect::<Vec<_>>(); let round_timeout = self.round_timeout_duration(next_round); - debug!(target: "bft", "Advancing to round {} from {}", next_round, round); - debug!(target: "bft", "Participating authorities: {:?}", + debug!(target: "rhd", "Advancing to round {} from {}", next_round, round); + debug!(target: "rhd", "Participating authorities: {:?}", collect_pubkeys(accumulator.participants())); - debug!(target: "bft", "Voting authorities: {:?}", + debug!(target: "rhd", "Voting authorities: {:?}", collect_pubkeys(accumulator.voters())); - debug!(target: "bft", "Round {} should end in at most {} seconds from now", next_round, round_timeout.as_secs()); + debug!(target: "rhd", "Round {} should end in at most {} seconds from now", next_round, round_timeout.as_secs()); self.update_round_cache(next_round); @@ -352,9 +368,10 @@ impl<B: Block, P: Proposer<B>> rhododendron::Context for BftInstance<B, P> pub struct BftFuture<B, P, I, InStream, OutSink> where B: Block + Clone + Eq, B::Hash: ::std::hash::Hash, - P: Proposer<B>, - InStream: Stream<Item=Communication<B>, Error=P::Error>, - OutSink: Sink<SinkItem=Communication<B>, SinkError=P::Error>, + P: LocalProposer<B>, + P: BaseProposer<B, Error=Error>, + InStream: Stream<Item=Communication<B>, Error=Error>, + OutSink: Sink<SinkItem=Communication<B>, SinkError=Error>, { inner: rhododendron::Agreement<BftInstance<B, P>, InStream, OutSink>, status: Arc<AtomicUsize>, @@ -365,11 +382,11 @@ pub struct BftFuture<B, P, I, InStream, OutSink> where impl<B, P, I, InStream, OutSink> Future for BftFuture<B, P, I, InStream, OutSink> where B: Block + Clone + Eq, B::Hash: ::std::hash::Hash, - P: Proposer<B>, - P::Error: ::std::fmt::Display, + P: LocalProposer<B>, + P: BaseProposer<B, Error=Error>, I: BlockImport<B>, - InStream: Stream<Item=Communication<B>, Error=P::Error>, - OutSink: Sink<SinkItem=Communication<B>, SinkError=P::Error>, + InStream: Stream<Item=Communication<B>, Error=Error>, + OutSink: Sink<SinkItem=Communication<B>, SinkError=Error>, { type Item = (); type Error = (); @@ -381,7 +398,6 @@ impl<B, P, I, InStream, OutSink> Future for BftFuture<B, P, I, InStream, OutSink Ok(Async::NotReady) => false, }; - // TODO: handle and log this error in a way which isn't noisy on exit. let committed = match self.inner.poll().map_err(|_| ()) { Ok(Async::Ready(x)) => x, Ok(Async::NotReady) => @@ -396,23 +412,36 @@ impl<B, P, I, InStream, OutSink> Future for BftFuture<B, P, I, InStream, OutSink // we will get the block from the network later. if let Some(justified_block) = committed.candidate { let hash = justified_block.hash(); - info!(target: "bft", "Importing block #{} ({}) directly from BFT consensus", + info!(target: "rhd", "Importing block #{} ({}) directly from BFT consensus", justified_block.header().number(), hash); - let just : Justification = RhdJustification(committed.justification).into(); + let just: Justification = UncheckedJustification(committed.justification.uncheck()).into(); + let (header, body) = justified_block.deconstruct(); + let import_block = ImportBlock { + origin: BlockOrigin::ConsensusBroadcast, + header: header, + external_justification: just.into(), + body: Some(body), + finalized: true, + post_runtime_digests: Default::default(), + auxiliary: Default::default() + }; + + let new_status = match self.import.import_block(import_block, None) { + Err(e) => { + warn!(target: "rhd", "Error importing block {:?} in round #{}: {:?}", + hash, committed.round_number, e); + status::BAD + } + Ok(ImportResult::KnownBad) => { + warn!(target: "rhd", "{:?} was bad block agreed on in round #{}", + hash, committed.round_number); + status::BAD + } + _ => status::GOOD + }; + + self.status.store(new_status, Ordering::Release); - let import_ok = self.import.import_block( - justified_block, - just, - &self.inner.context().authorities - ); - - if !import_ok { - warn!(target: "bft", "{:?} was bad block agreed on in round #{}", - hash, committed.round_number); - self.status.store(status::BAD, Ordering::Release); - } else { - self.status.store(status::GOOD, Ordering::Release); - } } else { // assume good unless we received the proposal. self.status.store(status::GOOD, Ordering::Release); @@ -427,9 +456,10 @@ impl<B, P, I, InStream, OutSink> Future for BftFuture<B, P, I, InStream, OutSink impl<B, P, I, InStream, OutSink> Drop for BftFuture<B, P, I, InStream, OutSink> where B: Block + Clone + Eq, B::Hash: ::std::hash::Hash, - P: Proposer<B>, - InStream: Stream<Item=Communication<B>, Error=P::Error>, - OutSink: Sink<SinkItem=Communication<B>, SinkError=P::Error>, + P: LocalProposer<B>, + P: BaseProposer<B, Error=Error>, + InStream: Stream<Item=Communication<B>, Error=Error>, + OutSink: Sink<SinkItem=Communication<B>, SinkError=Error>, { fn drop(&mut self) { // TODO: have a trait member to pass misbehavior reports into. @@ -474,10 +504,10 @@ impl<B, P, I> BftService<B, P, I> where B: Block + Clone + Eq, P: Environment<B>, - <P::Proposer as Proposer<B>>::Error: ::std::fmt::Display, + P::Proposer: LocalProposer<B>, + P::Proposer: BaseProposer<B,Error=Error>, I: BlockImport<B> + Authorities<B>, { - /// Create a new service instance. pub fn new(client: Arc<I>, key: Arc<ed25519::Pair>, factory: P) -> BftService<B, P, I> { BftService { @@ -500,20 +530,29 @@ impl<B, P, I> BftService<B, P, I> } /// Signal that a valid block with the given header has been imported. + /// Provide communication streams that are localized to this block. + /// It's recommended to use the communication primitives provided by this + /// module for signature checking and decoding. See `CheckedStream` and + /// `SigningSink` for more details. + /// + /// Messages received on the stream that don't match the expected format + /// will be dropped. /// /// If the local signing key is an authority, this will begin the consensus process to build a /// block on top of it. If the executor fails to run the future, an error will be returned. /// Returns `None` if the agreement on the block with given parent is already in progress. - pub fn build_upon(&self, header: &B::Header) + pub fn build_upon<In, Out>(&self, header: &B::Header, input: In, output: Out) -> Result<Option< BftFuture< B, <P as Environment<B>>::Proposer, I, - <P as Environment<B>>::Input, - <P as Environment<B>>::Output, + In, + Out, >>, P::Error> where + In: Stream<Item=Communication<B>, Error=Error>, + Out: Sink<SinkItem=Communication<B>, SinkError=Error>, { let hash = header.hash(); @@ -525,22 +564,23 @@ impl<B, P, I> BftService<B, P, I> return Ok(None) } - let authorities = self.client.authorities(&BlockId::Hash(hash.clone()))?; + let authorities = self.client.authorities(&BlockId::Hash(hash.clone())) + .map_err(|e| CommonErrorKind::Other(Box::new(e)).into())?; let n = authorities.len(); let max_faulty = max_faulty_of(n); - trace!(target: "bft", "Initiating agreement on top of #{}, {:?}", header.number(), hash); - trace!(target: "bft", "max_faulty_of({})={}", n, max_faulty); + trace!(target: "rhd", "Initiating agreement on top of #{}, {:?}", header.number(), hash); + trace!(target: "rhd", "max_faulty_of({})={}", n, max_faulty); let local_id = self.local_id(); if !authorities.contains(&local_id) { // cancel current agreement live_agreement.take(); - Err(ErrorKind::InvalidAuthority(local_id).into())?; + Err(CommonErrorKind::InvalidAuthority(local_id).into())?; } - let (proposer, input, output) = self.factory.init(header, &authorities, self.key.clone())?; + let proposer = self.factory.init(header, &authorities, self.key.clone())?; let bft_instance = BftInstance { proposer, @@ -562,9 +602,9 @@ impl<B, P, I> BftService<B, P, I> // fast forward round number if necessary. { let mut cache = self.round_cache.lock(); - trace!(target: "bft", "Round cache: {:?}", &*cache); + trace!(target: "rhd", "Round cache: {:?}", &*cache); if cache.hash.as_ref() == Some(&hash) { - trace!(target: "bft", "Fast-forwarding to round {}", cache.start_round); + trace!(target: "rhd", "Fast-forwarding to round {}", cache.start_round); let start_round = cache.start_round; cache.start_round += 1; @@ -620,6 +660,103 @@ impl<B, P, I> BftService<B, P, I> } } +/// Stream that decodes rhododendron messages and checks signatures. +/// +/// This stream is localized to a specific parent block-hash, as all messages +/// will be signed in a way that accounts for it. When using this with +/// `BftService::build_upon`, the user should take care to use the same hash as for that. +pub struct CheckedStream<B: Block, S> { + inner: S, + local_id: AuthorityId, + authorities: Vec<AuthorityId>, + parent_hash: B::Hash, +} + +impl<B: Block, S> CheckedStream<B, S> { + /// Construct a new checked stream. + pub fn new( + inner: S, + local_id: AuthorityId, + authorities: Vec<AuthorityId>, + parent_hash: B::Hash, + ) -> Self { + CheckedStream { + inner, + local_id, + authorities, + parent_hash, + } + } +} + +impl<B: Block, S: Stream<Item=Vec<u8>>> Stream for CheckedStream<B, S> + where S::Error: From<InputStreamConcluded>, +{ + type Item = Communication<B>; + type Error = S::Error; + + fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { + use rhododendron::LocalizedMessage as RhdLocalized; + loop { + match self.inner.poll()? { + Async::Ready(Some(item)) => { + let comms: Communication<B> = match Decode::decode(&mut &item[..]) { + Some(x) => x, + None => continue, + }; + + match comms { + RhdCommunication::Auxiliary(prepare_just) => { + let checked = check_prepare_justification::<B>( + &self.authorities, + self.parent_hash, + UncheckedJustification(prepare_just.uncheck()), + ); + if let Ok(checked) = checked { + return Ok(Async::Ready( + Some(RhdCommunication::Auxiliary(checked.0)) + )); + } + } + RhdCommunication::Consensus(RhdLocalized::Propose(p)) => { + if p.sender == self.local_id { continue } + + let checked = check_proposal::<B>( + &self.authorities, + &self.parent_hash, + &p, + ); + + if let Ok(()) = checked { + return Ok(Async::Ready( + Some(RhdCommunication::Consensus(RhdLocalized::Propose(p))) + )); + } + } + RhdCommunication::Consensus(RhdLocalized::Vote(v)) => { + if v.sender == self.local_id { continue } + + let checked = check_vote::<B>( + &self.authorities, + &self.parent_hash, + &v, + ); + + if let Ok(()) = checked { + return Ok(Async::Ready( + Some(RhdCommunication::Consensus(RhdLocalized::Vote(v))) + )); + } + } + } + } + Async::Ready(None) => return Ok(Async::Ready(None)), + Async::NotReady => return Ok(Async::NotReady), + } + } + } +} + /// Given a total number of authorities, yield the maximum faulty that would be allowed. /// This will always be under 1/3. pub fn max_faulty_of(n: usize) -> usize { @@ -632,7 +769,116 @@ pub fn bft_threshold(n: usize) -> usize { n - max_faulty_of(n) } -// /// Sign a BFT message with the given key. +// actions in the signature scheme. +#[derive(Encode)] +enum Action<B, H> { + Prepare(u32, H), + Commit(u32, H), + AdvanceRound(u32), + // signatures of header hash and full candidate are both included. + ProposeHeader(u32, H), + Propose(u32, B), +} + +// encode something in a way which is localized to a specific parent-hash +fn localized_encode<H: Encode, E: Encode>(parent_hash: H, value: E) -> Vec<u8> { + (parent_hash, value).encode() +} + +fn check_justification_signed_message<H>( + authorities: &[AuthorityId], + message: &[u8], + just: UncheckedJustification<H>) +-> Result<RhdJustification<H>, UncheckedJustification<H>> { + // additional error information could be useful here. + just.0.check(authorities.len() - max_faulty_of(authorities.len()), |_, _, sig| { + let auth_id = sig.signer.clone().into(); + if !authorities.contains(&auth_id) { return None } + + if ed25519::verify_strong(&sig.signature, message, &sig.signer) { + Some(sig.signer.0) + } else { + None + } + }).map(RhdJustification).map_err(UncheckedJustification) +} + +/// Check a full justification for a header hash. +/// Provide all valid authorities. +/// +/// On failure, returns the justification back. +pub fn check_justification<B: Block>( + authorities: &[AuthorityId], + parent: B::Hash, + just: UncheckedJustification<B::Hash> +) -> Result<RhdJustification<B::Hash>, UncheckedJustification<B::Hash>> { + let vote: Action<B, B::Hash> = Action::Commit(just.0.round_number as u32, just.0.digest.clone()); + let message = localized_encode(parent, vote); + + check_justification_signed_message(authorities, &message[..], just) +} + +/// Check a prepare justification for a header hash. +/// Provide all valid authorities. +/// +/// On failure, returns the justification back. +pub fn check_prepare_justification<B: Block>(authorities: &[AuthorityId], parent: B::Hash, just: UncheckedJustification<B::Hash>) + -> Result<PrepareJustification<B::Hash>, UncheckedJustification<B::Hash>> +{ + let vote: Action<B, B::Hash> = Action::Prepare(just.0.round_number as u32, just.0.digest.clone()); + let message = localized_encode(parent, vote); + + check_justification_signed_message(authorities, &message[..], just).map(|e| PrepareJustification(e.0)) +} + +/// Check proposal message signatures and authority. +/// Provide all valid authorities. +pub fn check_proposal<B: Block + Clone>( + authorities: &[AuthorityId], + parent_hash: &B::Hash, + propose: &rhododendron::LocalizedProposal<B, B::Hash, AuthorityId, LocalizedSignature>) + -> Result<(), Error> +{ + if !authorities.contains(&propose.sender) { + return Err(CommonErrorKind::InvalidAuthority(propose.sender.into()).into()); + } + + let action_header = Action::ProposeHeader(propose.round_number as u32, propose.digest.clone()); + let action_propose = Action::Propose(propose.round_number as u32, propose.proposal.clone()); + check_action::<B>(action_header, parent_hash, &propose.digest_signature)?; + check_action::<B>(action_propose, parent_hash, &propose.full_signature) +} + +/// Check vote message signatures and authority. +/// Provide all valid authorities. +pub fn check_vote<B: Block>( + authorities: &[AuthorityId], + parent_hash: &B::Hash, + vote: &rhododendron::LocalizedVote<B::Hash, AuthorityId, LocalizedSignature>) + -> Result<(), Error> +{ + if !authorities.contains(&vote.sender) { + return Err(CommonErrorKind::InvalidAuthority(vote.sender.into()).into()); + } + + let action = match vote.vote { + rhododendron::Vote::Prepare(r, ref h) => Action::Prepare(r as u32, h.clone()), + rhododendron::Vote::Commit(r, ref h) => Action::Commit(r as u32, h.clone()), + rhododendron::Vote::AdvanceRound(r) => Action::AdvanceRound(r as u32), + }; + check_action::<B>(action, parent_hash, &vote.signature) +} + +fn check_action<B: Block>(action: Action<B, B::Hash>, parent_hash: &B::Hash, sig: &LocalizedSignature) -> Result<(), Error> { + let message = localized_encode(*parent_hash, action); + if ed25519::verify_strong(&sig.signature, &message, &sig.signer) { + Ok(()) + } else { + Err(CommonErrorKind::InvalidSignature(sig.signature.into(), sig.signer.clone().into()).into()) + } +} + +/// Sign a BFT message with the given key. pub fn sign_message<B: Block + Clone>( message: RhdMessage<B, B::Hash>, key: &ed25519::Pair, @@ -640,13 +886,9 @@ pub fn sign_message<B: Block + Clone>( ) -> LocalizedMessage<B> { let signer = key.public(); - let sign_action = |action: ::rhododendron::Vote<B>| { - let primitive = ::rhododendron::LocalizedVote { - parent: parent_hash.clone(), - action, - }; + let sign_action = |action: Action<B, B::Hash>| { + let to_sign = localized_encode(parent_hash.clone(), action); - let to_sign = Encode::encode(&primitive); LocalizedSignature { signer: signer.clone(), signature: key.sign(&to_sign), @@ -656,10 +898,10 @@ pub fn sign_message<B: Block + Clone>( match message { RhdMessage::Propose(r, proposal) => { let header_hash = proposal.hash(); - let action_header = ::rhododendron::ProposeHeader(r as u32, header_hash.clone()); - let action_propose = ::rhododendron::Propose(r as u32, proposal.clone()); + let action_header = Action::ProposeHeader(r as u32, header_hash.clone()); + let action_propose = Action::Propose(r as u32, proposal.clone()); - ::rhododendron::LocalizedMessage::Propose(::rhododendron::LocalizedProposal { + rhododendron::LocalizedMessage::Propose(rhododendron::LocalizedProposal { round_number: r, proposal, digest: header_hash, @@ -668,20 +910,443 @@ pub fn sign_message<B: Block + Clone>( full_signature: sign_action(action_propose), }) } - RhdMessage::Vote(vote) => ::rhododendron::LocalizedMessage::Vote( - ::rhododendron::LocalizedVote { + RhdMessage::Vote(vote) => rhododendron::LocalizedMessage::Vote({ + let action = match vote { + RhdMessageVote::Prepare(r, h) => Action::Prepare(r as u32, h), + RhdMessageVote::Commit(r, h) => Action::Commit(r as u32, h), + RhdMessageVote::AdvanceRound(r) => Action::AdvanceRound(r as u32), + }; + + rhododendron::LocalizedVote { vote: vote, sender: signer.clone().into(), signature: sign_action(action), } - ) + }) + } +} + + +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> { + 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> { + let runtime_version = self.runtime_version_at(at)?; + + let mut block_builder = self.new_block_at(at)?; + if runtime_version.has_api(*b"blkbuild", 1) { + for inherent in self.inherent_extrinsics(at, &inherent_data)? { + block_builder.push(inherent)?; + } + } + + build_ctx(&mut block_builder); + + block_builder.bake().map_err(Into::into) + } +} + + +/// 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: u64, +} + +impl<N, C, A> consensus::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 Error = Error; + + fn init( + &self, + parent_header: &<<C as AuthoringApi>::Block as BlockT>::Header, + authorities: &[AuthorityId], + sign_with: Arc<ed25519::Pair>, + ) -> Result<Self::Proposer, Error> { + 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, + network: self.network.clone() + }; + + Ok(proposer) } } +/// The proposer logic. +pub struct Proposer<C: AuthoringApi, A: txpool::ChainApi, N: Network> { + 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<AuthorityId>, + minimum_timestamp: u64, + network: N, +} + +impl<C: AuthoringApi, A: txpool::ChainApi> Proposer<C, A> { + fn primary_index(&self, round_number: u32, 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 as usize; + offset % len + } +} + +impl<C, A> BaseProposer<<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, Error>; + type Error = Error; + type Evaluate = Box<Future<Item=bool, Error=Error>>; + + fn propose(&self) -> Self::Create { + 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.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: "rhd", "evaluating block on top of parent ({}, {:?})", self.parent_number, self.parent_hash); + + // do initial serialization and structural integrity checks. + if let Err(e) = evaluation::evaluate_initial( + unchecked_proposal, + &self.parent_hash, + self.parent_number, + ) { + debug!(target: "rhd", "Invalid proposal: {:?}", 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(BlockBuilderError::TimestampInFuture(timestamp))) => Some(timestamp), + Ok(Err(e)) => { + debug!(target: "rhd", "Invalid proposal (check_inherents): {:?}", e); + return Box::new(future::ok(false)); + }, + Err(e) => { + debug!(target: "rhd", "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: "rhd", "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. + // it may be 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<_> + } +} + +impl<C, A> LocalProposer<<C as AuthoringApi>::Block> for Proposer<C, A> where + C: AuthoringApi + BlockNumberToHash, + A: txpool::ChainApi<Block=<C as AuthoringApi>::Block>, + Self: BaseProposer<<C as AuthoringApi>::Block, Error=Error>, + <<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> +{ + + fn round_proposer(&self, round_number: u32, authorities: &[AuthorityId]) -> AuthorityId { + let offset = self.primary_index(round_number, authorities.len()); + let proposer = authorities[offset as usize].clone(); + trace!(target: "rhd", "proposer for round {} is {}", round_number, proposer); + + proposer + } + + fn import_misbehavior(&self, _misbehavior: Vec<(AuthorityId, 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) + ); + + 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: u32, 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() -> u64 { + time::SystemTime::now().duration_since(time::UNIX_EPOCH) + .expect("now always later than unix epoch; qed") + .as_secs() +} + + #[cfg(test)] mod tests { use super::*; use std::collections::HashSet; + use std::marker::PhantomData; + use runtime_primitives::testing::{Block as GenericTestBlock, Header as TestHeader}; use primitives::H256; use self::keyring::Keyring; @@ -696,14 +1361,21 @@ mod tests { } impl BlockImport<TestBlock> for FakeClient { - fn import_block(&self, block: TestBlock, _justification: Justification, _authorities: &[AuthorityId]) -> bool { + type Error = Error; + + fn import_block(&self, + block: ImportBlock<TestBlock>, + _new_authorities: Option<Vec<AuthorityId>> + ) -> Result<ImportResult, Self::Error> { assert!(self.imported_heights.lock().insert(block.header.number)); - true + Ok(ImportResult::Queued) } } impl Authorities<TestBlock> for FakeClient { - fn authorities(&self, _at: &BlockId<TestBlock>) -> Result<Vec<AuthorityId>, Error> { + type Error = Error; + + fn authorities(&self, _at: &BlockId<TestBlock>) -> Result<Vec<AuthorityId>, Self::Error> { Ok(self.authorities.clone()) } } @@ -738,18 +1410,16 @@ mod tests { impl Environment<TestBlock> for DummyFactory { type Proposer = DummyProposer; - type Input = Comms<Error>; - type Output = Comms<Error>; type Error = Error; fn init(&self, parent_header: &TestHeader, _authorities: &[AuthorityId], _sign_with: Arc<ed25519::Pair>) - -> Result<(DummyProposer, Self::Input, Self::Output), Error> + -> Result<DummyProposer, Error> { - Ok((DummyProposer(parent_header.number + 1), Comms(::std::marker::PhantomData), Comms(::std::marker::PhantomData))) + Ok(DummyProposer(parent_header.number + 1)) } } - impl Proposer<TestBlock> for DummyProposer { + impl BaseProposer<TestBlock> for DummyProposer { type Error = Error; type Create = Result<TestBlock, Error>; type Evaluate = Result<bool, Error>; @@ -765,11 +1435,13 @@ mod tests { fn evaluate(&self, proposal: &TestBlock) -> Result<bool, Error> { Ok(proposal.header.number == self.0) } + } + impl LocalProposer<TestBlock> for DummyProposer { fn import_misbehavior(&self, _misbehavior: Vec<(AuthorityId, Misbehavior<H256>)>) {} - fn round_proposer(&self, round_number: usize, authorities: &[AuthorityId]) -> AuthorityId { - authorities[round_number % authorities.len()].clone() + fn round_proposer(&self, round_number: u32, authorities: &[AuthorityId]) -> AuthorityId { + authorities[(round_number as usize) % authorities.len()].clone() } } @@ -789,9 +1461,9 @@ mod tests { } } - fn sign_vote(vote: ::rhododendron::Vote<H256>, key: &ed25519::Pair, parent_hash: H256) -> LocalizedSignature { + fn sign_vote(vote: rhododendron::Vote<H256>, key: &ed25519::Pair, parent_hash: H256) -> LocalizedSignature { match sign_message::<TestBlock>(vote.into(), key, parent_hash) { - ::rhododendron::LocalizedMessage::Vote(vote) => vote.signature, + rhododendron::LocalizedMessage::Vote(vote) => vote.signature, _ => panic!("signing vote leads to signed vote"), } } @@ -827,10 +1499,10 @@ mod tests { second.parent_hash = first_hash; let _second_hash = second.hash(); - let mut first_bft = service.build_upon(&first).unwrap().unwrap(); + let mut first_bft = service.build_upon(&first, Comms(PhantomData), Comms(PhantomData)).unwrap().unwrap(); assert!(service.live_agreement.lock().as_ref().unwrap().0 == first); - let _second_bft = service.build_upon(&second).unwrap(); + let _second_bft = service.build_upon(&second, Comms(PhantomData), Comms(PhantomData)).unwrap(); assert!(service.live_agreement.lock().as_ref().unwrap().0 != first); assert!(service.live_agreement.lock().as_ref().unwrap().0 == second); @@ -927,8 +1599,8 @@ mod tests { extrinsics: Default::default() }; - let proposal = sign_message(::rhododendron::Message::Propose(1, block.clone()), &Keyring::Alice.pair(), parent_hash);; - if let ::rhododendron::LocalizedMessage::Propose(proposal) = proposal { + let proposal = sign_message(rhododendron::Message::Propose(1, block.clone()), &Keyring::Alice.pair(), parent_hash);; + if let rhododendron::LocalizedMessage::Propose(proposal) = proposal { assert!(check_proposal(&authorities, &parent_hash, &proposal).is_ok()); let mut invalid_round = proposal.clone(); invalid_round.round_number = 0; @@ -941,8 +1613,8 @@ mod tests { } // Not an authority - let proposal = sign_message::<TestBlock>(::rhododendron::Message::Propose(1, block), &Keyring::Bob.pair(), parent_hash);; - if let ::rhododendron::LocalizedMessage::Propose(proposal) = proposal { + let proposal = sign_message::<TestBlock>(rhododendron::Message::Propose(1, block), &Keyring::Bob.pair(), parent_hash);; + if let rhododendron::LocalizedMessage::Propose(proposal) = proposal { assert!(check_proposal(&authorities, &parent_hash, &proposal).is_err()); } else { assert!(false); @@ -959,8 +1631,8 @@ mod tests { Keyring::Eve.to_raw_public().into(), ]; - let vote = sign_message::<TestBlock>(::rhododendron::Message::Vote(::rhododendron::Vote::Prepare(1, hash)), &Keyring::Alice.pair(), parent_hash);; - if let ::rhododendron::LocalizedMessage::Vote(vote) = vote { + let vote = sign_message::<TestBlock>(rhododendron::Message::Vote(rhododendron::Vote::Prepare(1, hash)), &Keyring::Alice.pair(), parent_hash);; + if let rhododendron::LocalizedMessage::Vote(vote) = vote { assert!(check_vote::<TestBlock>(&authorities, &parent_hash, &vote).is_ok()); let mut invalid_sender = vote.clone(); invalid_sender.signature.signer = Keyring::Eve.into(); @@ -970,8 +1642,8 @@ mod tests { } // Not an authority - let vote = sign_message::<TestBlock>(::rhododendron::Message::Vote(::rhododendron::Vote::Prepare(1, hash)), &Keyring::Bob.pair(), parent_hash);; - if let ::rhododendron::LocalizedMessage::Vote(vote) = vote { + let vote = sign_message::<TestBlock>(rhododendron::Message::Vote(rhododendron::Vote::Prepare(1, hash)), &Keyring::Bob.pair(), parent_hash);; + if let rhododendron::LocalizedMessage::Vote(vote) = vote { assert!(check_vote::<TestBlock>(&authorities, &parent_hash, &vote).is_err()); } else { assert!(false); @@ -998,7 +1670,7 @@ mod tests { let mut second = from_block_number(3); second.parent_hash = first_hash; - let _ = service.build_upon(&first).unwrap(); + let _ = service.build_upon(&first, Comms(PhantomData), Comms(PhantomData)).unwrap(); assert!(service.live_agreement.lock().as_ref().unwrap().0 == first); service.live_agreement.lock().take(); } @@ -1026,14 +1698,14 @@ mod tests { let mut third = from_block_number(4); third.parent_hash = second.hash(); - let _ = service.build_upon(&first).unwrap(); + let _ = service.build_upon(&first, Comms(PhantomData), Comms(PhantomData)).unwrap(); assert!(service.live_agreement.lock().as_ref().unwrap().0 == first); // BFT has not seen second, but will move forward on third - service.build_upon(&third).unwrap(); + service.build_upon(&third, Comms(PhantomData), Comms(PhantomData)).unwrap(); assert!(service.live_agreement.lock().as_ref().unwrap().0 == third); // but we are not walking backwards - service.build_upon(&second).unwrap(); + service.build_upon(&second, Comms(PhantomData), Comms(PhantomData)).unwrap(); assert!(service.live_agreement.lock().as_ref().unwrap().0 == third); } } diff --git a/substrate/node/consensus/src/service.rs b/substrate/core/consensus/rhd/src/service.rs similarity index 89% rename from substrate/node/consensus/src/service.rs rename to substrate/core/consensus/rhd/src/service.rs index f8ebd6f421e543e170ff0f7b9e09a2a80ead901f..34efc942d4dae2a4e77b58d023ea5405be30e0e9 100644 --- a/substrate/node/consensus/src/service.rs +++ b/substrate/core/consensus/rhd/src/service.rs @@ -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 || { diff --git a/substrate/core/executor/src/lib.rs b/substrate/core/executor/src/lib.rs index df67db587fe586af42fffa4f8f1948200cbc62bc..64442b7f8e2b6e33e356681afa96fbefbddbf56f 100644 --- a/substrate/core/executor/src/lib.rs +++ b/substrate/core/executor/src/lib.rs @@ -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)] diff --git a/substrate/core/executor/src/native_executor.rs b/substrate/core/executor/src/native_executor.rs index 685aa485728f442e5a5b1a14872f39cd97e83d45..b51b43e14dd1976607b5fc3431ae527cef402fc6 100644 --- a/substrate/core/executor/src/native_executor.rs +++ b/substrate/core/executor/src/native_executor.rs @@ -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) => { diff --git a/substrate/core/finality-grandpa/README.adoc b/substrate/core/finality-grandpa/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..5338cf9e8cc715c589c2e812a9f65c92426b1eb5 --- /dev/null +++ b/substrate/core/finality-grandpa/README.adoc @@ -0,0 +1,12 @@ += Finality GRANDPA (aka SHAFT) + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/finality-grandpa/src/lib.rs b/substrate/core/finality-grandpa/src/lib.rs index 8b45ab56411e1a000839d1a107340f900436148c..988a13d74de1677f2a180197834e0be44911c752 100644 --- a/substrate/core/finality-grandpa/src/lib.rs +++ b/substrate/core/finality-grandpa/src/lib.rs @@ -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 } } diff --git a/substrate/core/keyring/src/lib.rs b/substrate/core/keyring/src/lib.rs index 3fab7c576972eb97b85063abcc7f92e28f4e33b2..6ba79d146cd920c79c72410629803206a0e112ad 100644 --- a/substrate/core/keyring/src/lib.rs +++ b/substrate/core/keyring/src/lib.rs @@ -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; diff --git a/substrate/core/network/Cargo.toml b/substrate/core/network/Cargo.toml index db4f6c34e2e13c5e63459f849f5a92ad34e4e04e..7eadefb3637f3ec2607f2534a6ba108e60cc3cdb 100644 --- a/substrate/core/network/Cargo.toml +++ b/substrate/core/network/Cargo.toml @@ -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" diff --git a/substrate/core/network/src/chain.rs b/substrate/core/network/src/chain.rs index 97c2322989e66b7a4d8817fcf7f997946d587174..74a01577a75dafb81e57ac772ada2ffc0d27f8bd 100644 --- a/substrate/core/network/src/chain.rs +++ b/substrate/core/network/src/chain.rs @@ -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) } diff --git a/substrate/core/network/src/import_queue.rs b/substrate/core/network/src/import_queue.rs index 328dc478dc5d097f8796c8daea72dcdd4f8d5fe4..4a6775a2a9def6921e0038d9af9a912200e11da5 100644 --- a/substrate/core/network/src/import_queue.rs +++ b/substrate/core/network/src/import_queue.rs @@ -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::*; diff --git a/substrate/core/network/src/lib.rs b/substrate/core/network/src/lib.rs index 82bdf0a877d62870f5727ffa935b49c6b2e7b00c..4a441dcc6fed0f84dd3dc0570005ae5b88f1d8de 100644 --- a/substrate/core/network/src/lib.rs +++ b/substrate/core/network/src/lib.rs @@ -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; diff --git a/substrate/core/network/src/protocol.rs b/substrate/core/network/src/protocol.rs index a8edaaceb670978419cae5b9ec94d81d2fdfe52e..4e98ee8f80f24712176dd9e6035ed826bf1bb3a9 100644 --- a/substrate/core/network/src/protocol.rs +++ b/substrate/core/network/src/protocol.rs @@ -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); )* } } } diff --git a/substrate/core/network/src/service.rs b/substrate/core/network/src/service.rs index 52db914d6ea0b96cc795b6e011a79b2e9f400dc5..0e46f50998b2331c7cd905e98b9538309b54b480 100644 --- a/substrate/core/network/src/service.rs +++ b/substrate/core/network/src/service.rs @@ -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(); diff --git a/substrate/core/network/src/specialization.rs b/substrate/core/network/src/specialization.rs index ccd1071adb4cef806ca97a1d307a795fe7be8a4e..70ad9e9b2e655fd88d9d585ac15eaed29834d643 100644 --- a/substrate/core/network/src/specialization.rs +++ b/substrate/core/network/src/specialization.rs @@ -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>); diff --git a/substrate/core/network/src/sync.rs b/substrate/core/network/src/sync.rs index b758b8f205b43faf445aa3ecfe2ef1df1d05baa3..e69b22fc578f148ebf2c936b602d38e65506e282 100644 --- a/substrate/core/network/src/sync.rs +++ b/substrate/core/network/src/sync.rs @@ -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 { diff --git a/substrate/core/network/src/test/mod.rs b/substrate/core/network/src/test/mod.rs index 50e644c2612175e49de290556678a66938aa55d5..34eb873cc640e8a452c800351d8671f5a9d9d256 100644 --- a/substrate/core/network/src/test/mod.rs +++ b/substrate/core/network/src/test/mod.rs @@ -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; } } diff --git a/substrate/core/network/src/test/sync.rs b/substrate/core/network/src/test/sync.rs index 02531259f25f41485d693c73f3238c7b13d9820a..0f9e40782873b964cca30e80ba5423cef081e836 100644 --- a/substrate/core/network/src/test/sync.rs +++ b/substrate/core/network/src/test/sync.rs @@ -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(); diff --git a/substrate/core/primitives/src/ed25519.rs b/substrate/core/primitives/src/ed25519.rs index 2047a0c7afc173b88a12505d068566152588b4ef..027298b4b1628ee45facad79c9bdd4a34e51d880 100644 --- a/substrate/core/primitives/src/ed25519.rs +++ b/substrate/core/primitives/src/ed25519.rs @@ -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); diff --git a/substrate/core/rpc/Cargo.toml b/substrate/core/rpc/Cargo.toml index 453b288c9dec1b20a10b6fcd2b69e8b51b905ab2..3f35394c9112928ed9d7176751fb6d089a2bd5b3 100644 --- a/substrate/core/rpc/Cargo.toml +++ b/substrate/core/rpc/Cargo.toml @@ -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" diff --git a/substrate/core/rpc/src/chain/mod.rs b/substrate/core/rpc/src/chain/mod.rs index 6c1724a787070d6d18a106e87728a83085a044a7..f56ec59c1a1222e9df25c3fb2d5aa97ff322fdb2 100644 --- a/substrate/core/rpc/src/chain/mod.rs +++ b/substrate/core/rpc/src/chain/mod.rs @@ -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)) + } } diff --git a/substrate/core/rpc/src/chain/tests.rs b/substrate/core/rpc/src/chain/tests.rs index fc9817140d7a1c1e4ce6c1bebe5cb4b559439018..644c7fed075bf74b26b4d6e057f6afeccb2844e4 100644 --- a/substrate/core/rpc/src/chain/tests.rs +++ b/substrate/core/rpc/src/chain/tests.rs @@ -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() { diff --git a/substrate/core/rpc/src/lib.rs b/substrate/core/rpc/src/lib.rs index 9e4bd969789d3feb5c16177b82a60635b710079e..dbbc8e3a6ad4477fb5c90bb9829a3b62ddde41fa 100644 --- a/substrate/core/rpc/src/lib.rs +++ b/substrate/core/rpc/src/lib.rs @@ -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; diff --git a/substrate/core/rpc/src/state/mod.rs b/substrate/core/rpc/src/state/mod.rs index 4c3110f8e14b30a93f59b5b3b5106d3c3dc976e5..3fda746dcb08af45d450f037eacba67e42cb6d0c 100644 --- a/substrate/core/rpc/src/state/mod.rs +++ b/substrate/core/rpc/src/state/mod.rs @@ -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; diff --git a/substrate/core/rpc/src/state/tests.rs b/substrate/core/rpc/src/state/tests.rs index 74b5fab8417b0f988c2a672ee3d7e8707463a24b..71978f88ea57f793d14fd22347dc1874d9113820 100644 --- a/substrate/core/rpc/src/state/tests.rs +++ b/substrate/core/rpc/src/state/tests.rs @@ -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}; diff --git a/substrate/core/service/Cargo.toml b/substrate/core/service/Cargo.toml index 694cd5a5534af110f40c1268ed72ea092db21c8e..a15e010d5c477f8147a2acd36ccff77e651562b8 100644 --- a/substrate/core/service/Cargo.toml +++ b/substrate/core/service/Cargo.toml @@ -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" } diff --git a/substrate/core/service/src/chain_ops.rs b/substrate/core/service/src/chain_ops.rs index a3cd5bb770f1e5ca4d4e6a465d5ae7a896580606..d23e82b1cfb32b5689d92ae6d9a2784b0aeb2b09 100644 --- a/substrate/core/service/src/chain_ops.rs +++ b/substrate/core/service/src/chain_ops.rs @@ -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}; diff --git a/substrate/core/service/src/components.rs b/substrate/core/service/src/components.rs index a30fb9940e081d4b3a3d43475608259c28cf9bbd..d2503ded239178aa6b9b07e95a949ce062f89ccc 100644 --- a/substrate/core/service/src/components.rs +++ b/substrate/core/service/src/components.rs @@ -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) } } diff --git a/substrate/core/service/src/consensus.rs b/substrate/core/service/src/consensus.rs new file mode 100644 index 0000000000000000000000000000000000000000..61968ee04d41b09aab57548eee630347509dadef --- /dev/null +++ b/substrate/core/service/src/consensus.rs @@ -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() +} diff --git a/substrate/core/service/src/lib.rs b/substrate/core/service/src/lib.rs index 848c96ae90a6784b53abfc3b36f13ff391ce7ff0..9e7c201e8f05724c7fdb2f22007e2e96ac5a5e6c 100644 --- a/substrate/core/service/src/lib.rs +++ b/substrate/core/service/src/lib.rs @@ -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) } diff --git a/substrate/core/service/test/Cargo.toml b/substrate/core/service/test/Cargo.toml index cfdfacf4da0e550dab00eb086e00b85bcedc2537..12282b16f15e370771e705c89703406d41cee934 100644 --- a/substrate/core/service/test/Cargo.toml +++ b/substrate/core/service/test/Cargo.toml @@ -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" } diff --git a/substrate/core/service/test/src/lib.rs b/substrate/core/service/test/src/lib.rs index 31ac007c4fbb0aba5dc6f188999ec74cecb8f314..0a967e3cd6c8183c2e3d3176a6e773a7fda6340a 100644 --- a/substrate/core/service/test/src/lib.rs +++ b/substrate/core/service/test/src/lib.rs @@ -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, diff --git a/substrate/core/sr-api/README.adoc b/substrate/core/sr-api/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..debd87e8ebddd4e47449271ae54c7b3c65b41269 --- /dev/null +++ b/substrate/core/sr-api/README.adoc @@ -0,0 +1,12 @@ += Runtime API + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/sr-api/src/lib.rs b/substrate/core/sr-api/src/lib.rs index 2021e2f2a0b740b18ad1d1f707b9893022ecc9c5..7fffc43590c78049cca3489c236338d90c6e022b 100644 --- a/substrate/core/sr-api/src/lib.rs +++ b/substrate/core/sr-api/src/lib.rs @@ -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. diff --git a/substrate/core/sr-primitives/Cargo.toml b/substrate/core/sr-primitives/Cargo.toml index df80d43a9f702cb59741aa9c5bf7efca2ee6bc17..45e0396df38a742a8b98b93d1c0b4786fa2c1dfa 100644 --- a/substrate/core/sr-primitives/Cargo.toml +++ b/substrate/core/sr-primitives/Cargo.toml @@ -31,3 +31,4 @@ std = [ "substrate-primitives/std", ] api-for-runtime = [] + diff --git a/substrate/core/sr-primitives/README.adoc b/substrate/core/sr-primitives/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..0e9d6361112734dc4430a9dac3a1fa1fde5e3f0a --- /dev/null +++ b/substrate/core/sr-primitives/README.adoc @@ -0,0 +1,12 @@ += Runtime Primitives + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/sr-primitives/src/generic/digest.rs b/substrate/core/sr-primitives/src/generic/digest.rs index 4d44ff5ce01793072e168c399458e93bcf9aa028..41ffd6da0d179667da3fd10e1ae236bd0e0a978d 100644 --- a/substrate/core/sr-primitives/src/generic/digest.rs +++ b/substrate/core/sr-primitives/src/generic/digest.rs @@ -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); diff --git a/substrate/core/sr-primitives/src/generic/header.rs b/substrate/core/sr-primitives/src/generic/header.rs index ff8222c59a1fd27527824348f0780446f5873929..fc6f73b5cf1b28a568477b4d8cd3296c0fbbadb6 100644 --- a/substrate/core/sr-primitives/src/generic/header.rs +++ b/substrate/core/sr-primitives/src/generic/header.rs @@ -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( diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index 15b86484a6f670517aaac2ee5ac2d35e624129de..36f5cda20748cfab124b54c3c5ce4b4abb70f573 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -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)] diff --git a/substrate/core/sr-primitives/src/testing.rs b/substrate/core/sr-primitives/src/testing.rs index ab57f1aa6c82b3e4b4ea96ad1a79697b71477646..847af9a3c2ec4ec344733fa86e3504bfb97bdbd5 100644 --- a/substrate/core/sr-primitives/src/testing.rs +++ b/substrate/core/sr-primitives/src/testing.rs @@ -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( diff --git a/substrate/core/sr-primitives/src/traits.rs b/substrate/core/sr-primitives/src/traits.rs index 82d28d013ef34a1eb64e3b322e535b168a5676b0..0ee2db117a2b5e38c50fd3efee71d4d88115e409 100644 --- a/substrate/core/sr-primitives/src/traits.rs +++ b/substrate/core/sr-primitives/src/traits.rs @@ -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> { diff --git a/substrate/core/sr-sandbox/src/lib.rs b/substrate/core/sr-sandbox/src/lib.rs index 7b6dc67feb28b3720ff6011c2ebce608afbc2396..6ed3243dc8bcbbf111a084d280039c94d93d48fb 100755 --- a/substrate/core/sr-sandbox/src/lib.rs +++ b/substrate/core/sr-sandbox/src/lib.rs @@ -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[] diff --git a/substrate/core/sr-version/README.adoc b/substrate/core/sr-version/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..28db6c615d3b9f65607882768bd3c5bd326f5013 --- /dev/null +++ b/substrate/core/sr-version/README.adoc @@ -0,0 +1,13 @@ + += Runtime Version + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/sr-version/src/lib.rs b/substrate/core/sr-version/src/lib.rs index 8af084da5ef945c75e6334d2fefb4abc8f4abddf..6f91692b8232d7ab12e23089985da944055b70e6 100644 --- a/substrate/core/sr-version/src/lib.rs +++ b/substrate/core/sr-version/src/lib.rs @@ -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)] diff --git a/substrate/core/state-machine/src/lib.rs b/substrate/core/state-machine/src/lib.rs index 4853b2afb5f1d9806f7a69f402920bef06755917..9bb91108863192f73beda6ac309e5418661766a0 100644 --- a/substrate/core/state-machine/src/lib.rs +++ b/substrate/core/state-machine/src/lib.rs @@ -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 diff --git a/substrate/core/telemetry/src/lib.rs b/substrate/core/telemetry/src/lib.rs index 729f6f76d95b7407e7c5c36f82f88d86acdc9fbb..aa7479cc828372ec44b70419c99c911decf3c9b7 100644 --- a/substrate/core/telemetry/src/lib.rs +++ b/substrate/core/telemetry/src/lib.rs @@ -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. diff --git a/substrate/core/test-client/Cargo.toml b/substrate/core/test-client/Cargo.toml index a1bf2f592e85067fb8847fe7d9d1c5331dbbe96c..aa48f95211131f293a350624736eed429344e7d3 100644 --- a/substrate/core/test-client/Cargo.toml +++ b/substrate/core/test-client/Cargo.toml @@ -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" } diff --git a/substrate/core/test-client/src/client_ext.rs b/substrate/core/test-client/src/client_ext.rs index 76e9888d0beb3c372d76b5e4cb5d880b34396db0..61133c4d9da811328ffa011537aefc82c1421cdf 100644 --- a/substrate/core/test-client/src/client_ext.rs +++ b/substrate/core/test-client/src/client_ext.rs @@ -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<()> { diff --git a/substrate/core/test-client/src/lib.rs b/substrate/core/test-client/src/lib.rs index b692d4858ba49b1b847b68bf0822377ded75e631..ff3cfbac0e59b21f13cee8b545742d3e6fd41687 100644 --- a/substrate/core/test-client/src/lib.rs +++ b/substrate/core/test-client/src/lib.rs @@ -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; diff --git a/substrate/core/test-client/src/trait_tests.rs b/substrate/core/test-client/src/trait_tests.rs index 86d08cd8a51b5be4edc0dde3ca7a9ab404a52f9c..3a05b78600003c324949c8f4e5528db1de57a415 100644 --- a/substrate/core/test-client/src/trait_tests.rs +++ b/substrate/core/test-client/src/trait_tests.rs @@ -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; diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5d9b1fcac3726fbcf0d4a685d6c9f8481ee438a8 Binary files /dev/null and b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/core/transaction-pool/README.adoc b/substrate/core/transaction-pool/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..336a67a8418fd0a3384a0b3f50a4655264fe1e3d --- /dev/null +++ b/substrate/core/transaction-pool/README.adoc @@ -0,0 +1,13 @@ + += Transaction Pool + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/trie/README.adoc b/substrate/core/trie/README.adoc new file mode 100644 index 0000000000000000000000000000000000000000..953724ca12061e90ec22189ef9518c8e5674f5f8 --- /dev/null +++ b/substrate/core/trie/README.adoc @@ -0,0 +1,12 @@ += Substrate Trie + +.Summary +[source, toml] +---- +include::Cargo.toml[lines=2..5] +---- + +.Description +---- +include::src/lib.rs[tag=description] +---- diff --git a/substrate/core/trie/README.md b/substrate/core/trie/README.md deleted file mode 100644 index 57d392057be403de764540e264af8d3843445a09..0000000000000000000000000000000000000000 --- a/substrate/core/trie/README.md +++ /dev/null @@ -1 +0,0 @@ -This crate provides utility functions to interact with Substrate's Modified Merkle Patricia tree ("trie"). \ No newline at end of file diff --git a/substrate/core/trie/src/lib.rs b/substrate/core/trie/src/lib.rs index 87d955a357fcb6fedcdeeb7a53f6c58c297394b0..68dacf2668bc4c4fadee260593e94ca6bb17c8c2 100644 --- a/substrate/core/trie/src/lib.rs +++ b/substrate/core/trie/src/lib.rs @@ -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 diff --git a/substrate/doc/packages/misc.adoc b/substrate/doc/packages/misc.adoc index 316cf44858c91d8327f5ecd4cb2ae91fffef2bde..2081d34efc471bf1c6aed9dbb9f8c5eb3b478f19 100644 --- a/substrate/doc/packages/misc.adoc +++ b/substrate/doc/packages/misc.adoc @@ -3,8 +3,6 @@ :leveloffset: +3 -include::../../safe-mix/README.adoc[] - include::../../subkey/README.adoc[] :leveloffset: -3 diff --git a/substrate/doc/packages/substrate.adoc b/substrate/doc/packages/substrate.adoc index ee246d090924a3d6bec0ebf167854b670ec0926e..3df3366def95c98bbe831f1835224fa390d1e539 100644 --- a/substrate/doc/packages/substrate.adoc +++ b/substrate/doc/packages/substrate.adoc @@ -1,62 +1,66 @@ == Substrate Packages +=== Substrate Core + :leveloffset: +3 -include::../../core/bft/README.adoc[] +include::../../core/client/README.adoc[] -include::../../core/cli/README.adoc[] +include::../../core/test-client/README.adoc[] -include::../../core/client/README.adoc[] +include::../../core/client/db/README.adoc[] + +include::../../core/state-db/README.adoc[] -include::../../codec/README.adoc[] +include::../../core/consensus/common/README.adoc[] -include::../../environmental/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/state-machine/README.adoc[] -include::../../core/serializer/README.adoc[] +include::../../core/test-runtime/README.adoc[] -include::../../core/service/README.adoc[] +include::../../core/telemetry/README.adoc[] -include::../../core/state-db/README.adoc[] +include::../../core/cli/README.adoc[] -include::../../core/state-machine/README.adoc[] +include::../../core/service/README.adoc[] -include::../../core/telemetry/README.adoc[] +include::../../core/trie/README.adoc[] -include::../../core/test-client/README.adoc[] +include::../../core/keystore/README.adoc[] -include::../../core/test-srml/README.adoc[] +include::../../core/primitives/README.adoc[] + +include::../../core/serializer/README.adoc[] :leveloffset: -3 diff --git a/substrate/node/cli/Cargo.toml b/substrate/node/cli/Cargo.toml index 61b31a5f67e74a516398f3975e293e897f1d8a31..6f1f92cc82e4e31c39b6e84fbe283193105afc3a 100644 --- a/substrate/node/cli/Cargo.toml +++ b/substrate/node/cli/Cargo.toml @@ -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" } diff --git a/substrate/node/cli/src/chain_spec.rs b/substrate/node/cli/src/chain_spec.rs index cc4612f27b8b5d6f8b9a0a34efae36d1fc6b610b..53cf074767b9e917673a65403849d708c0a3ba6c 100644 --- a/substrate/node/cli/src/chain_spec.rs +++ b/substrate/node/cli/src/chain_spec.rs @@ -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) diff --git a/substrate/node/cli/src/lib.rs b/substrate/node/cli/src/lib.rs index 0d8c9c4d71df002dcf4cdfd5609a26bb0d222e34..beb47f91ff86812dfffbc6f151ce99db2412fafc 100644 --- a/substrate/node/cli/src/lib.rs +++ b/substrate/node/cli/src/lib.rs @@ -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; diff --git a/substrate/node/cli/src/service.rs b/substrate/node/cli/src/service.rs index 4e718816e19d9b357f985218d258829353ba94f7..d02ea48767b19ce900ed3443258faf30fb7115e8 100644 --- a/substrate/node/cli/src/service.rs +++ b/substrate/node/cli/src/service.rs @@ -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")] diff --git a/substrate/node/consensus/Cargo.toml b/substrate/node/consensus/Cargo.toml deleted file mode 100644 index c45818ee07ab05edffd42ecfc772eacf27906a8e..0000000000000000000000000000000000000000 --- a/substrate/node/consensus/Cargo.toml +++ /dev/null @@ -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" } diff --git a/substrate/node/consensus/README.adoc b/substrate/node/consensus/README.adoc deleted file mode 100644 index ca2daa9eb2b09be8fe77ab432889c7a75799e6e5..0000000000000000000000000000000000000000 --- a/substrate/node/consensus/README.adoc +++ /dev/null @@ -1,5 +0,0 @@ - -= Substrate Consensus - -placeholder -//TODO Write content :) diff --git a/substrate/node/consensus/src/error.rs b/substrate/node/consensus/src/error.rs deleted file mode 100644 index 13192ae2020d3eb09d62c91cb15dd3bf26cc052b..0000000000000000000000000000000000000000 --- a/substrate/node/consensus/src/error.rs +++ /dev/null @@ -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() - } -} diff --git a/substrate/node/consensus/src/lib.rs b/substrate/node/consensus/src/lib.rs deleted file mode 100644 index 9638a39715ff84b9b35933985ee94ed47defa401..0000000000000000000000000000000000000000 --- a/substrate/node/consensus/src/lib.rs +++ /dev/null @@ -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() -} diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index 6a2b8061c373529ae3eaa66ce4f967b51e1dd435..bdd8b10235214db0c168dce1fa2ff98372ea62a5 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -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 { diff --git a/substrate/node/network/Cargo.toml b/substrate/node/network/Cargo.toml deleted file mode 100644 index 44fbdb5abae58196b5732ecf48525bdf64913b6d..0000000000000000000000000000000000000000 --- a/substrate/node/network/Cargo.toml +++ /dev/null @@ -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" diff --git a/substrate/node/network/src/consensus.rs b/substrate/node/network/src/consensus.rs deleted file mode 100644 index 44d338d3303982206179c3f7fc5e716125b0a53c..0000000000000000000000000000000000000000 --- a/substrate/node/network/src/consensus.rs +++ /dev/null @@ -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) - } -} diff --git a/substrate/node/network/src/lib.rs b/substrate/node/network/src/lib.rs deleted file mode 100644 index 9e2f96d5f75aa45f946798e50bca77509499ea84..0000000000000000000000000000000000000000 --- a/substrate/node/network/src/lib.rs +++ /dev/null @@ -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>, - } -} diff --git a/substrate/node/runtime/Cargo.toml b/substrate/node/runtime/Cargo.toml index ac37cff45632da9643ab9765f3e44bdbc90104a1..8add782018ad71762ab2e98ea63f8b983820975f 100644 --- a/substrate/node/runtime/Cargo.toml +++ b/substrate/node/runtime/Cargo.toml @@ -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", diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 36dcd347b9651e3e7fac819867b60321bb3ee4b9..998bb6640b047f9e2927fa7e64c934853ad79f65 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -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() - } - } } diff --git a/substrate/node/runtime/wasm/Cargo.lock b/substrate/node/runtime/wasm/Cargo.lock index fc45e6f94c531a6a7ad856d4dc40d58e01b2ce31..0aa58928c2a2dc926b3ec6e4ed254306657294b5 100644 --- a/substrate/node/runtime/wasm/Cargo.lock +++ b/substrate/node/runtime/wasm/Cargo.lock @@ -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" diff --git a/substrate/node/runtime/wasm/Cargo.toml b/substrate/node/runtime/wasm/Cargo.toml index 7fb33ff26b4c8fe82b9439adae28b6083ac5f0e1..7df582a8f0c92aac179af3b9ae46fd5282d470ed 100644 --- a/substrate/node/runtime/wasm/Cargo.toml +++ b/substrate/node/runtime/wasm/Cargo.toml @@ -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", ] diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 392b360796baf5f93c2a1b99150e48df37ed35c3..2a48d20c98d216742495a038849834566e6ccc45 100644 Binary files a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/substrate/srml/assets/src/lib.rs b/substrate/srml/assets/src/lib.rs index 61b36dc3c1c8e42210d1be9f3e54e323a9a8c139..bde551e8863ee22c13ae73becae63bc990170fc7 100644 --- a/substrate/srml/assets/src/lib.rs +++ b/substrate/srml/assets/src/lib.rs @@ -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::*; diff --git a/substrate/srml/balances/src/lib.rs b/substrate/srml/balances/src/lib.rs index 50c9b27d76a54fd24ae4b087ec94f823b4b6730c..224d02c0d1362446021f458acf9eb165ab84d943 100644 --- a/substrate/srml/balances/src/lib.rs +++ b/substrate/srml/balances/src/lib.rs @@ -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 { diff --git a/substrate/srml/balances/src/tests.rs b/substrate/srml/balances/src/tests.rs index b9c5b85902a49c8964b3a9ce5ffdf93f9a226d8c..9ad100fe6179c0e86552a9c1c9c768f8193e2569 100644 --- a/substrate/srml/balances/src/tests.rs +++ b/substrate/srml/balances/src/tests.rs @@ -280,6 +280,17 @@ fn balance_transfer_works() { }); } +#[test] +fn balance_reduction_works() { + with_externalities(&mut ExtBuilder::default().build(), || { + Balances::set_free_balance(&1, 111); + Balances::increase_total_stake_by(111); + assert_ok!(Balances::decrease_free_balance(&1, 69).map(|_| ())); + assert_eq!(Balances::total_balance(&1), 42); + assert_noop!(Balances::decrease_free_balance(&1, 69).map(|_| ()), "account has too few funds"); + }); +} + #[test] fn reserving_balance_should_work() { with_externalities(&mut ExtBuilder::default().build(), || { diff --git a/substrate/srml/consensus/src/lib.rs b/substrate/srml/consensus/src/lib.rs index 835d39a44cee237d57aecf5b1baa76532a2860cd..1c46e38541ed24aa230032ec56ef669cc69a851a 100644 --- a/substrate/srml/consensus/src/lib.rs +++ b/substrate/srml/consensus/src/lib.rs @@ -29,6 +29,7 @@ extern crate srml_support as runtime_support; #[macro_use] extern crate serde_derive; +extern crate parity_codec; #[macro_use] extern crate parity_codec_derive; @@ -42,13 +43,14 @@ extern crate sr_io as runtime_io; use rstd::prelude::*; use rstd::result; +use parity_codec::Encode; use runtime_support::{storage, Parameter}; use runtime_support::dispatch::Result; use runtime_support::storage::StorageValue; use runtime_support::storage::unhashed::StorageVec; use primitives::RuntimeString; use primitives::traits::{ - MaybeSerializeDebug, OnFinalise, Member, ProvideInherent, Block as BlockT + MaybeSerializeDebug, Member, ProvideInherent, Block as BlockT }; use substrate_primitives::storage::well_known_keys; use system::{ensure_signed, ensure_inherent}; @@ -143,63 +145,72 @@ decl_storage! { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn report_misbehavior(origin, report: Vec<u8>) -> Result; - fn note_offline(origin, offline_val_indices: Vec<u32>) -> Result; - fn remark(origin, remark: Vec<u8>) -> Result; - fn set_code(new: Vec<u8>) -> Result; - fn set_storage(items: Vec<KeyValue>) -> Result; - } -} + /// Report some misbehaviour. + fn report_misbehavior(origin, _report: Vec<u8>) -> Result { + ensure_signed(origin)?; + // TODO. + Ok(()) + } -impl<T: Trait> Module<T> { - /// Get the current set of authorities. These are the session keys. - pub fn authorities() -> Vec<T::SessionKey> { - AuthorityStorageVec::<T::SessionKey>::items() - } + /// Note the previous block's validator missed their opportunity to propose a block. + /// This only comes in if 2/3+1 of the validators agree that no proposal was submitted. + /// It's only relevant for the previous block. + fn note_offline(origin, offline_val_indices: Vec<u32>) -> Result { + ensure_inherent(origin)?; + assert!( + <system::Module<T>>::extrinsic_index() == Some(T::NOTE_OFFLINE_POSITION), + "note_offline extrinsic must be at position {} in the block", + T::NOTE_OFFLINE_POSITION + ); + + for validator_index in offline_val_indices.into_iter() { + T::OnOfflineValidator::on_offline_validator(validator_index as usize); + } - /// Set the new code. - fn set_code(new: Vec<u8>) -> Result { - storage::unhashed::put_raw(well_known_keys::CODE, &new); - Ok(()) - } + Ok(()) + } - /// Set some items of storage. - fn set_storage(items: Vec<KeyValue>) -> Result { - for i in &items { - storage::unhashed::put_raw(&i.0, &i.1); + /// Make some on-chain remark. + fn remark(origin, _remark: Vec<u8>) -> Result { + ensure_signed(origin)?; + Ok(()) } - Ok(()) - } - /// Report some misbehaviour. - fn report_misbehavior(origin: T::Origin, _report: Vec<u8>) -> Result { - ensure_signed(origin)?; - // TODO. - Ok(()) - } + /// Set the number of pages in the WebAssembly environment's heap. + fn set_heap_pages(pages: u64) -> Result { + storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode()); + Ok(()) + } - /// Note the previous block's validator missed their opportunity to propose a block. This only comes in - /// if 2/3+1 of the validators agree that no proposal was submitted. It's only relevant - /// for the previous block. - fn note_offline(origin: T::Origin, offline_val_indices: Vec<u32>) -> Result { - ensure_inherent(origin)?; - assert!( - <system::Module<T>>::extrinsic_index() == Some(T::NOTE_OFFLINE_POSITION), - "note_offline extrinsic must be at position {} in the block", - T::NOTE_OFFLINE_POSITION - ); - - for validator_index in offline_val_indices.into_iter() { - T::OnOfflineValidator::on_offline_validator(validator_index as usize); + /// Set the new code. + pub fn set_code(new: Vec<u8>) -> Result { + storage::unhashed::put_raw(well_known_keys::CODE, &new); + Ok(()) } - Ok(()) + /// Set some items of storage. + fn set_storage(items: Vec<KeyValue>) -> Result { + for i in &items { + storage::unhashed::put_raw(&i.0, &i.1); + } + Ok(()) + } + + fn on_finalise() { + if let Some(original_authorities) = <OriginalAuthorities<T>>::take() { + let current_authorities = AuthorityStorageVec::<T::SessionKey>::items(); + if current_authorities != original_authorities { + Self::deposit_log(RawLog::AuthoritiesChange(current_authorities)); + } + } + } } +} - /// Make some on-chain remark. - fn remark(origin: T::Origin, _remark: Vec<u8>) -> Result { - ensure_signed(origin)?; - Ok(()) +impl<T: Trait> Module<T> { + /// Get the current set of authorities. These are the session keys. + pub fn authorities() -> Vec<T::SessionKey> { + AuthorityStorageVec::<T::SessionKey>::items() } /// Set the current set of authorities' session keys. @@ -267,15 +278,3 @@ impl<T: Trait> ProvideInherent for Module<T> { ) } } - -/// Finalization hook for the consensus module. -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(_n: T::BlockNumber) { - if let Some(original_authorities) = <OriginalAuthorities<T>>::take() { - let current_authorities = AuthorityStorageVec::<T::SessionKey>::items(); - if current_authorities != original_authorities { - Self::deposit_log(RawLog::AuthoritiesChange(current_authorities)); - } - } - } -} diff --git a/substrate/srml/consensus/src/tests.rs b/substrate/srml/consensus/src/tests.rs index e27f617115109db50e93c2fae37b5b9c5624b1e9..b823367c15458f792d254f824f85a2fe4dfa76dc 100644 --- a/substrate/srml/consensus/src/tests.rs +++ b/substrate/srml/consensus/src/tests.rs @@ -18,8 +18,7 @@ #![cfg(test)] -use super::*; -use primitives::{generic, testing}; +use primitives::{generic, testing, traits::OnFinalise}; use runtime_io::with_externalities; use substrate_primitives::H256; use mock::{Consensus, System, new_test_ext}; diff --git a/substrate/srml/contract/src/lib.rs b/substrate/srml/contract/src/lib.rs index 31a7d4ed22b952cb06c6c8667884fc58bdbf3f80..5e3722bb04040e31fe002491fe1ddfa7e21ad486 100644 --- a/substrate/srml/contract/src/lib.rs +++ b/substrate/srml/contract/src/lib.rs @@ -103,7 +103,7 @@ use double_map::StorageDoubleMap; use rstd::prelude::*; use rstd::marker::PhantomData; use codec::{Codec, HasCompact}; -use runtime_primitives::traits::{Hash, As, SimpleArithmetic, OnFinalise}; +use runtime_primitives::traits::{Hash, As, SimpleArithmetic}; use runtime_support::dispatch::Result; use runtime_support::{Parameter, StorageMap, StorageValue}; use system::ensure_signed; @@ -151,22 +151,110 @@ where decl_module! { /// Contracts module. pub struct Module<T: Trait> for enum Call where origin: T::Origin { + fn deposit_event() = default; // TODO: Change AccountId to staking::Address + /// Make a call to a specified account, optionally transferring some balance. + /// Make a call to a specified account, optionally transferring some balance. fn call( origin, dest: T::AccountId, value: <T::Balance as HasCompact>::Type, gas_limit: <T::Gas as HasCompact>::Type, data: Vec<u8> - ) -> Result; + ) -> Result { + let origin = ensure_signed(origin)?; + let value = value.into(); + let gas_limit = gas_limit.into(); + + // Pay for the gas upfront. + // + // NOTE: it is very important to avoid any state changes before + // paying for the gas. + let mut gas_meter = gas::buy_gas::<T>(&origin, gas_limit)?; + + let mut ctx = ExecutionContext { + self_account: origin.clone(), + depth: 0, + overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb), + events: Vec::new(), + }; + + let mut output_data = Vec::new(); + let result = ctx.call(origin.clone(), dest, value, &mut gas_meter, &data, &mut output_data); + + if let Ok(_) = result { + // Commit all changes that made it thus far into the persistant storage. + account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); + + // Then deposit all events produced. + ctx.events.into_iter().for_each(Self::deposit_event); + } + + // Refund cost of the unused gas. + // + // NOTE: this should go after the commit to the storage, since the storage changes + // can alter the balance of the caller. + gas::refund_unused_gas::<T>(&origin, gas_meter); + + result.map(|_| ()) + } + /// Create a new contract, optionally transfering some balance to the created account. + /// + /// Creation is executed as follows: + /// + /// - the destination address is computed based on the sender and hash of the code. + /// - account is created at the computed address. + /// - the `ctor_code` is executed in the context of the newly created account. Buffer returned + /// after the execution is saved as the `code` of the account. That code will be invoked + /// upon any message received by this account. fn create( origin, - value: <T::Balance as HasCompact>::Type, + endowment: <T::Balance as HasCompact>::Type, gas_limit: <T::Gas as HasCompact>::Type, - init_code: Vec<u8>, + ctor_code: Vec<u8>, data: Vec<u8> - ) -> Result; + ) -> Result { + let origin = ensure_signed(origin)?; + let endowment = endowment.into(); + let gas_limit = gas_limit.into(); + + // Pay for the gas upfront. + // + // NOTE: it is very important to avoid any state changes before + // paying for the gas. + let mut gas_meter = gas::buy_gas::<T>(&origin, gas_limit)?; + + let mut ctx = ExecutionContext { + self_account: origin.clone(), + depth: 0, + overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb), + events: Vec::new(), + }; + let result = ctx.create(origin.clone(), endowment, &mut gas_meter, &ctor_code, &data); + + if let Ok(ref r) = result { + // Commit all changes that made it thus far into the persistant storage. + account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); + + // Then deposit all events produced. + ctx.events.into_iter().for_each(Self::deposit_event); + + Self::deposit_event(RawEvent::Created(origin.clone(), r.address.clone())); + } + + // Refund cost of the unused gas. + // + // NOTE: this should go after the commit to the storage, since the storage changes + // can alter the balance of the caller. + gas::refund_unused_gas::<T>(&origin, gas_meter); + + result.map(|_| ()) + } + + fn on_finalise() { + <GasSpent<T>>::kill(); + } } } @@ -178,6 +266,9 @@ decl_event! { { /// Transfer happened `from` -> `to` with given `value` as part of a `message-call` or `create`. Transfer(AccountId, AccountId, Balance), + + /// Contract deployed by address at the specified address. + Created(AccountId, AccountId), } } @@ -217,119 +308,9 @@ impl<T: Trait> double_map::StorageDoubleMap for StorageOf<T> { type Value = Vec<u8>; } -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()); - } - - /// Make a call to a specified account, optionally transferring some balance. - fn call( - origin: <T as system::Trait>::Origin, - dest: T::AccountId, - value: <T::Balance as HasCompact>::Type, - gas_limit: <T::Gas as HasCompact>::Type, - data: Vec<u8>, - ) -> Result { - let origin = ensure_signed(origin)?; - let value = value.into(); - let gas_limit = gas_limit.into(); - - // Pay for the gas upfront. - // - // NOTE: it is very important to avoid any state changes before - // paying for the gas. - let mut gas_meter = gas::buy_gas::<T>(&origin, gas_limit)?; - - let mut ctx = ExecutionContext { - self_account: origin.clone(), - depth: 0, - overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb), - events: Vec::new(), - }; - - let mut output_data = Vec::new(); - let result = ctx.call(origin.clone(), dest, value, &mut gas_meter, &data, &mut output_data); - - if let Ok(_) = result { - // Commit all changes that made it thus far into the persistant storage. - account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); - - // Then deposit all events produced. - ctx.events.into_iter().for_each(Self::deposit_event); - } - - // Refund cost of the unused gas. - // - // NOTE: this should go after the commit to the storage, since the storage changes - // can alter the balance of the caller. - gas::refund_unused_gas::<T>(&origin, gas_meter); - - result.map(|_| ()) - } - - /// Create a new contract, optionally transfering some balance to the created account. - /// - /// Creation is executed as follows: - /// - /// - the destination address is computed based on the sender and hash of the code. - /// - account is created at the computed address. - /// - the `ctor_code` is executed in the context of the newly created account. Buffer returned - /// after the execution is saved as the `code` of the account. That code will be invoked - /// upon any message received by this account. - fn create( - origin: <T as system::Trait>::Origin, - endowment: <T::Balance as HasCompact>::Type, - gas_limit: <T::Gas as HasCompact>::Type, - ctor_code: Vec<u8>, - data: Vec<u8>, - ) -> Result { - let origin = ensure_signed(origin)?; - let endowment = endowment.into(); - let gas_limit = gas_limit.into(); - - // Pay for the gas upfront. - // - // NOTE: it is very important to avoid any state changes before - // paying for the gas. - let mut gas_meter = gas::buy_gas::<T>(&origin, gas_limit)?; - - let mut ctx = ExecutionContext { - self_account: origin.clone(), - depth: 0, - overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb), - events: Vec::new(), - }; - let result = ctx.create(origin.clone(), endowment, &mut gas_meter, &ctor_code, &data); - - if let Ok(_) = result { - // Commit all changes that made it thus far into the persistant storage. - account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); - - // Then deposit all events produced. - ctx.events.into_iter().for_each(Self::deposit_event); - } - - // Refund cost of the unused gas. - // - // NOTE: this should go after the commit to the storage, since the storage changes - // can alter the balance of the caller. - gas::refund_unused_gas::<T>(&origin, gas_meter); - - result.map(|_| ()) - } -} - impl<T: Trait> balances::OnFreeBalanceZero<T::AccountId> for Module<T> { fn on_free_balance_zero(who: &T::AccountId) { <CodeOf<T>>::remove(who); <StorageOf<T>>::remove_prefix(who.clone()); } } - -/// Finalization hook for the smart-contract module. -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(_n: T::BlockNumber) { - <GasSpent<T>>::kill(); - } -} diff --git a/substrate/srml/contract/src/tests.rs b/substrate/srml/contract/src/tests.rs index f48769c97831bd39362b6c7118001ab82457d6f6..9e2d2f1f6800fa40ca0fdf4e4e6d044cf387aeae 100644 --- a/substrate/srml/contract/src/tests.rs +++ b/substrate/srml/contract/src/tests.rs @@ -617,6 +617,10 @@ fn top_level_create() { phase: Phase::ApplyExtrinsic(0), event: MetaEvent::contract(RawEvent::Transfer(0, derived_address, 11)), }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Created(0, 1)), + }, ]); }); } diff --git a/substrate/srml/council/src/motions.rs b/substrate/srml/council/src/motions.rs index ab6ea5f4ef01923fce184a8066afba494b8df7ac..a2c5115633f191504208cd0fccc3066ae48a6dc0 100644 --- a/substrate/srml/council/src/motions.rs +++ b/substrate/srml/council/src/motions.rs @@ -20,7 +20,7 @@ use rstd::prelude::*; use rstd::result; use codec::Compact; use substrate_primitives::u32_trait::Value as U32; -use primitives::traits::{Hash, EnsureOrigin, MaybeSerializeDebug, OnFinalise}; +use primitives::traits::{Hash, EnsureOrigin, MaybeSerializeDebug}; use srml_support::dispatch::{Result, Dispatchable, Parameter}; use srml_support::{StorageValue, StorageMap}; use super::{Trait as CouncilTrait, Module as Council}; @@ -68,8 +68,96 @@ decl_event!( decl_module! { #[cfg_attr(feature = "std", serde(bound(deserialize = "<T as Trait>::Proposal: ::serde::de::DeserializeOwned")))] pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin { - fn propose(origin, threshold: Compact<u32>, proposal: Box<<T as Trait>::Proposal>) -> Result; - fn vote(origin, proposal: T::Hash, index: Compact<ProposalIndex>, approve: bool) -> Result; + fn deposit_event() = default; + fn propose(origin, threshold: Compact<u32>, proposal: Box<<T as Trait>::Proposal>) -> Result { + let who = ensure_signed(origin)?; + let threshold = threshold.into(); + + ensure!(Self::is_councillor(&who), "proposer not on council"); + + let proposal_hash = T::Hashing::hash_of(&proposal); + + ensure!(!<ProposalOf<T>>::exists(proposal_hash), "duplicate proposals not allowed"); + + if threshold < 2 { + let ok = proposal.dispatch(Origin::Members(1).into()).is_ok(); + Self::deposit_event(RawEvent::Executed(proposal_hash, ok)); + } else { + let index = Self::proposal_count(); + <ProposalCount<T>>::mutate(|i| *i += 1); + <Proposals<T>>::mutate(|proposals| proposals.push(proposal_hash)); + <ProposalOf<T>>::insert(proposal_hash, *proposal); + <Voting<T>>::insert(proposal_hash, (index, threshold, vec![who.clone()], vec![])); + + Self::deposit_event(RawEvent::Proposed(who, index, proposal_hash, threshold)); + } + Ok(()) + } + + fn vote(origin, proposal: T::Hash, index: Compact<ProposalIndex>, approve: bool) -> Result { + let who = ensure_signed(origin)?; + let index = index.into(); + + ensure!(Self::is_councillor(&who), "voter not on council"); + + let mut voting = Self::voting(&proposal).ok_or("proposal must exist")?; + ensure!(voting.0 == index, "mismatched index"); + + let position_yes = voting.2.iter().position(|a| a == &who); + let position_no = voting.3.iter().position(|a| a == &who); + + if approve { + if position_yes.is_none() { + voting.2.push(who.clone()); + } else { + return Err("duplicate vote ignored") + } + if let Some(pos) = position_no { + voting.3.swap_remove(pos); + } + } else { + if position_no.is_none() { + voting.3.push(who.clone()); + } else { + return Err("duplicate vote ignored") + } + if let Some(pos) = position_yes { + voting.2.swap_remove(pos); + } + } + + let yes_votes = voting.2.len() as u32; + let no_votes = voting.3.len() as u32; + Self::deposit_event(RawEvent::Voted(who, proposal, approve, yes_votes, no_votes)); + + let threshold = voting.1; + let potential_votes = <Council<T>>::active_council().len() as u32; + let approved = yes_votes >= threshold; + let disapproved = potential_votes.saturating_sub(no_votes) < threshold; + if approved || disapproved { + if approved { + Self::deposit_event(RawEvent::Approved(proposal)); + + // execute motion, assuming it exists. + if let Some(p) = <ProposalOf<T>>::take(&proposal) { + let ok = p.dispatch(Origin::Members(threshold).into()).is_ok(); + Self::deposit_event(RawEvent::Executed(proposal, ok)); + } + } else { + // disapproved + Self::deposit_event(RawEvent::Disapproved(proposal)); + } + + // remove vote + <Voting<T>>::remove(&proposal); + <Proposals<T>>::mutate(|proposals| proposals.retain(|h| h != &proposal)); + } else { + // update voting + <Voting<T>>::insert(&proposal, voting); + } + + Ok(()) + } } } @@ -91,112 +179,10 @@ decl_storage! { } 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()); - } - pub fn is_councillor(who: &T::AccountId) -> bool { <Council<T>>::active_council().iter() .any(|&(ref a, _)| a == who) } - - // Dispatch - fn propose(origin: <T as system::Trait>::Origin, threshold: Compact<u32>, proposal: Box<<T as Trait>::Proposal>) -> Result { - let who = ensure_signed(origin)?; - let threshold = threshold.into(); - - ensure!(Self::is_councillor(&who), "proposer not on council"); - - let proposal_hash = T::Hashing::hash_of(&proposal); - - ensure!(!<ProposalOf<T>>::exists(proposal_hash), "duplicate proposals not allowed"); - - if threshold < 2 { - let ok = proposal.dispatch(Origin::Members(1).into()).is_ok(); - Self::deposit_event(RawEvent::Executed(proposal_hash, ok)); - } else { - let index = Self::proposal_count(); - <ProposalCount<T>>::mutate(|i| *i += 1); - <Proposals<T>>::mutate(|proposals| proposals.push(proposal_hash)); - <ProposalOf<T>>::insert(proposal_hash, *proposal); - <Voting<T>>::insert(proposal_hash, (index, threshold, vec![who.clone()], vec![])); - - Self::deposit_event(RawEvent::Proposed(who, index, proposal_hash, threshold)); - } - Ok(()) - } - - fn vote(origin: <T as system::Trait>::Origin, proposal: T::Hash, index: Compact<ProposalIndex>, approve: bool) -> Result { - let who = ensure_signed(origin)?; - let index = index.into(); - - ensure!(Self::is_councillor(&who), "voter not on council"); - - let mut voting = Self::voting(&proposal).ok_or("proposal must exist")?; - ensure!(voting.0 == index, "mismatched index"); - - let position_yes = voting.2.iter().position(|a| a == &who); - let position_no = voting.3.iter().position(|a| a == &who); - - if approve { - if position_yes.is_none() { - voting.2.push(who.clone()); - } else { - return Err("duplicate vote ignored") - } - if let Some(pos) = position_no { - voting.3.swap_remove(pos); - } - } else { - if position_no.is_none() { - voting.3.push(who.clone()); - } else { - return Err("duplicate vote ignored") - } - if let Some(pos) = position_yes { - voting.2.swap_remove(pos); - } - } - - let yes_votes = voting.2.len() as u32; - let no_votes = voting.3.len() as u32; - Self::deposit_event(RawEvent::Voted(who, proposal, approve, yes_votes, no_votes)); - - let threshold = voting.1; - let potential_votes = <Council<T>>::active_council().len() as u32; - let approved = yes_votes >= threshold; - let disapproved = potential_votes.saturating_sub(no_votes) < threshold; - if approved || disapproved { - if approved { - Self::deposit_event(RawEvent::Approved(proposal)); - - // execute motion, assuming it exists. - if let Some(p) = <ProposalOf<T>>::take(&proposal) { - let ok = p.dispatch(Origin::Members(threshold).into()).is_ok(); - Self::deposit_event(RawEvent::Executed(proposal, ok)); - } - } else { - // disapproved - Self::deposit_event(RawEvent::Disapproved(proposal)); - } - - // remove vote - <Voting<T>>::remove(&proposal); - <Proposals<T>>::mutate(|proposals| proposals.retain(|h| h != &proposal)); - } else { - // update voting - <Voting<T>>::insert(&proposal, voting); - } - - Ok(()) - } -} - -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(_n: T::BlockNumber) { - } } /// Ensure that the origin `o` represents at least `n` council members. Returns diff --git a/substrate/srml/council/src/seats.rs b/substrate/srml/council/src/seats.rs index 42c3858efbaee2073ea35f71ea807cfdd78baab3..957b69bdfe0a8479d5aacfae03ff197185fe69a8 100644 --- a/substrate/srml/council/src/seats.rs +++ b/substrate/srml/council/src/seats.rs @@ -18,7 +18,7 @@ use rstd::prelude::*; use codec::{Compact, HasCompact}; -use primitives::traits::{Zero, One, As, OnFinalise}; +use primitives::traits::{Zero, One, As}; use runtime_io::print; use srml_support::{StorageValue, StorageMap, dispatch::Result}; use democracy; @@ -87,16 +87,234 @@ pub trait Trait: democracy::Trait { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn set_approvals(origin, votes: Vec<bool>, index: Compact<VoteIndex>) -> Result; - fn reap_inactive_voter(origin, reporter_index: Compact<u32>, who: Address<T::AccountId, T::AccountIndex>, who_index: Compact<u32>, assumed_vote_index: Compact<VoteIndex>) -> Result; - fn retract_voter(origin, index: Compact<u32>) -> Result; - fn submit_candidacy(origin, slot: Compact<u32>) -> Result; - fn present_winner(origin, candidate: Address<T::AccountId, T::AccountIndex>, total: <T::Balance as HasCompact>::Type, index: Compact<VoteIndex>) -> Result; - - fn set_desired_seats(count: Compact<u32>) -> Result; - fn remove_member(who: Address<T::AccountId, T::AccountIndex>) -> Result; - fn set_presentation_duration(count: <T::BlockNumber as HasCompact>::Type) -> Result; - fn set_term_duration(count: <T::BlockNumber as HasCompact>::Type) -> Result; + fn deposit_event() = default; + + /// Set candidate approvals. Approval slots stay valid as long as candidates in those slots + /// are registered. + fn set_approvals(origin, votes: Vec<bool>, index: Compact<VoteIndex>) -> Result { + let who = ensure_signed(origin)?; + let index: VoteIndex = index.into(); + + ensure!(!Self::presentation_active(), "no approval changes during presentation period"); + ensure!(index == Self::vote_index(), "incorrect vote index"); + if !<LastActiveOf<T>>::exists(&who) { + // not yet a voter - deduct bond. + // NOTE: this must be the last potential bailer, since it changes state. + <balances::Module<T>>::reserve(&who, Self::voting_bond())?; + + <Voters<T>>::put({ + let mut v = Self::voters(); + v.push(who.clone()); + v + }); + } + <LastActiveOf<T>>::insert(&who, index); + <ApprovalsOf<T>>::insert(&who, votes); + Ok(()) + } + + /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices + /// must now be either unregistered or registered to a candidate that registered the slot after + /// the voter gave their last approval set. + /// + /// May be called by anyone. Returns the voter deposit to `signed`. + fn reap_inactive_voter( + origin, + reporter_index: Compact<u32>, + who: Address<T::AccountId, T::AccountIndex>, + who_index: Compact<u32>, + assumed_vote_index: Compact<VoteIndex> + ) -> Result { + let reporter = ensure_signed(origin)?; + let assumed_vote_index: VoteIndex = assumed_vote_index.into(); + + let who = <balances::Module<T>>::lookup(who)?; + ensure!(!Self::presentation_active(), "cannot reap during presentation period"); + ensure!(Self::voter_last_active(&reporter).is_some(), "reporter must be a voter"); + let last_active = Self::voter_last_active(&who).ok_or("target for inactivity cleanup must be active")?; + ensure!(assumed_vote_index == Self::vote_index(), "vote index not current"); + ensure!(last_active < assumed_vote_index - Self::inactivity_grace_period(), "cannot reap during grace perid"); + let voters = Self::voters(); + let reporter_index: u32 = reporter_index.into(); + let reporter_index = reporter_index as usize; + let who_index: u32 = who_index.into(); + let who_index = who_index as usize; + ensure!(reporter_index < voters.len() && voters[reporter_index] == reporter, "bad reporter index"); + ensure!(who_index < voters.len() && voters[who_index] == who, "bad target index"); + + // will definitely kill one of signed or who now. + + let valid = !Self::approvals_of(&who).iter() + .zip(Self::candidates().iter()) + .any(|(&appr, addr)| + appr && + *addr != T::AccountId::default() && + Self::candidate_reg_info(addr).map_or(false, |x| x.0 <= last_active)/*defensive only: all items in candidates list are registered*/ + ); + + Self::remove_voter( + if valid { &who } else { &reporter }, + if valid { who_index } else { reporter_index }, + voters + ); + if valid { + // This only fails if `who` doesn't exist, which it clearly must do since its the origin. + // Still, it's no more harmful to propagate any error at this point. + <balances::Module<T>>::repatriate_reserved(&who, &reporter, Self::voting_bond())?; + Self::deposit_event(RawEvent::VoterReaped(who, reporter)); + } else { + <balances::Module<T>>::slash_reserved(&reporter, Self::voting_bond()); + Self::deposit_event(RawEvent::BadReaperSlashed(reporter)); + } + Ok(()) + } + + /// Remove a voter. All votes are cancelled and the voter deposit is returned. + fn retract_voter(origin, index: Compact<u32>) -> Result { + let who = ensure_signed(origin)?; + + ensure!(!Self::presentation_active(), "cannot retract when presenting"); + ensure!(<LastActiveOf<T>>::exists(&who), "cannot retract non-voter"); + let voters = Self::voters(); + let index: u32 = index.into(); + let index = index as usize; + ensure!(index < voters.len(), "retraction index invalid"); + ensure!(voters[index] == who, "retraction index mismatch"); + + Self::remove_voter(&who, index, voters); + <balances::Module<T>>::unreserve(&who, Self::voting_bond()); + Ok(()) + } + + /// Submit oneself for candidacy. + /// + /// Account must have enough transferrable funds in it to pay the bond. + fn submit_candidacy(origin, slot: Compact<u32>) -> Result { + let who = ensure_signed(origin)?; + + ensure!(!Self::is_a_candidate(&who), "duplicate candidate submission"); + let slot: u32 = slot.into(); + let slot = slot as usize; + let count = Self::candidate_count() as usize; + let candidates = Self::candidates(); + ensure!( + (slot == count && count == candidates.len()) || + (slot < candidates.len() && candidates[slot] == T::AccountId::default()), + "invalid candidate slot" + ); + // NOTE: This must be last as it has side-effects. + <balances::Module<T>>::reserve(&who, Self::candidacy_bond()) + .map_err(|_| "candidate has not enough funds")?; + + <RegisterInfoOf<T>>::insert(&who, (Self::vote_index(), slot as u32)); + let mut candidates = candidates; + if slot == candidates.len() { + candidates.push(who); + } else { + candidates[slot] = who; + } + <Candidates<T>>::put(candidates); + <CandidateCount<T>>::put(count as u32 + 1); + Ok(()) + } + + /// Claim that `signed` is one of the top Self::carry_count() + current_vote().1 candidates. + /// Only works if the `block_number >= current_vote().0` and `< current_vote().0 + presentation_duration()`` + /// `signed` should have at least + fn present_winner( + origin, + candidate: Address<T::AccountId, T::AccountIndex>, + total: <T::Balance as HasCompact>::Type, + index: Compact<VoteIndex> + ) -> Result { + let who = ensure_signed(origin)?; + let total = total.into(); + let index: VoteIndex = index.into(); + + let candidate = <balances::Module<T>>::lookup(candidate)?; + ensure!(index == Self::vote_index(), "index not current"); + let (_, _, expiring) = Self::next_finalise().ok_or("cannot present outside of presentation period")?; + let stakes = Self::snapshoted_stakes(); + let voters = Self::voters(); + let bad_presentation_punishment = Self::present_slash_per_voter() * T::Balance::sa(voters.len() as u64); + ensure!(<balances::Module<T>>::can_slash(&who, bad_presentation_punishment), "presenter must have sufficient slashable funds"); + + let mut leaderboard = Self::leaderboard().ok_or("leaderboard must exist while present phase active")?; + ensure!(total > leaderboard[0].0, "candidate not worthy of leaderboard"); + + if let Some(p) = Self::active_council().iter().position(|&(ref c, _)| c == &candidate) { + ensure!(p < expiring.len(), "candidate must not form a duplicated member if elected"); + } + + let (registered_since, candidate_index): (VoteIndex, u32) = + Self::candidate_reg_info(&candidate).ok_or("presented candidate must be current")?; + let actual_total = voters.iter() + .zip(stakes.iter()) + .filter_map(|(voter, stake)| + match Self::voter_last_active(voter) { + Some(b) if b >= registered_since => + Self::approvals_of(voter).get(candidate_index as usize) + .and_then(|approved| if *approved { Some(*stake) } else { None }), + _ => None, + }) + .fold(Zero::zero(), |acc, n| acc + n); + let dupe = leaderboard.iter().find(|&&(_, ref c)| c == &candidate).is_some(); + if total == actual_total && !dupe { + // insert into leaderboard + leaderboard[0] = (total, candidate); + leaderboard.sort_by_key(|&(t, _)| t); + <Leaderboard<T>>::put(leaderboard); + Ok(()) + } else { + // we can rest assured it will be Ok since we checked `can_slash` earlier; still + // better safe than sorry. + let _ = <balances::Module<T>>::slash(&who, bad_presentation_punishment); + Err(if dupe { "duplicate presentation" } else { "incorrect total" }) + } + } + + /// Set the desired member count; if lower than the current count, then seats will not be up + /// election when they expire. If more, then a new vote will be started if one is not already + /// in progress. + fn set_desired_seats(count: Compact<u32>) -> Result { + let count: u32 = count.into(); + <DesiredSeats<T>>::put(count); + Ok(()) + } + + /// Remove a particular member. A tally will happen instantly (if not already in a presentation + /// period) to fill the seat if removal means that the desired members are not met. + /// This is effective immediately. + fn remove_member(who: Address<T::AccountId, T::AccountIndex>) -> Result { + let who = <balances::Module<T>>::lookup(who)?; + let new_council: Vec<(T::AccountId, T::BlockNumber)> = Self::active_council() + .into_iter() + .filter(|i| i.0 != who) + .collect(); + <ActiveCouncil<T>>::put(new_council); + Ok(()) + } + + /// Set the presentation duration. If there is currently a vote being presented for, will + /// invoke `finalise_vote`. + fn set_presentation_duration(count: <T::BlockNumber as HasCompact>::Type) -> Result { + <PresentationDuration<T>>::put(count.into()); + Ok(()) + } + + /// Set the presentation duration. If there is current a vote being presented for, will + /// invoke `finalise_vote`. + fn set_term_duration(count: <T::BlockNumber as HasCompact>::Type) -> Result { + <TermDuration<T>>::put(count.into()); + Ok(()) + } + + fn on_finalise(n: T::BlockNumber) { + if let Err(e) = Self::end_block(n) { + print("Guru meditation"); + print(e); + } + } } } @@ -170,12 +388,6 @@ decl_event!( ); 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()); - } - // exposed immutables. /// True if we're currently in a presentation period. @@ -224,230 +436,7 @@ impl<T: Trait> Module<T> { } } - // dispatch - - /// Set candidate approvals. Approval slots stay valid as long as candidates in those slots - /// are registered. - fn set_approvals(origin: T::Origin, votes: Vec<bool>, index: Compact<VoteIndex>) -> Result { - let who = ensure_signed(origin)?; - let index: VoteIndex = index.into(); - - ensure!(!Self::presentation_active(), "no approval changes during presentation period"); - ensure!(index == Self::vote_index(), "incorrect vote index"); - if !<LastActiveOf<T>>::exists(&who) { - // not yet a voter - deduct bond. - // NOTE: this must be the last potential bailer, since it changes state. - <balances::Module<T>>::reserve(&who, Self::voting_bond())?; - - <Voters<T>>::put({ - let mut v = Self::voters(); - v.push(who.clone()); - v - }); - } - <LastActiveOf<T>>::insert(&who, index); - <ApprovalsOf<T>>::insert(&who, votes); - Ok(()) - } - - /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices - /// must now be either unregistered or registered to a candidate that registered the slot after - /// the voter gave their last approval set. - /// - /// May be called by anyone. Returns the voter deposit to `signed`. - fn reap_inactive_voter( - origin: T::Origin, - reporter_index: Compact<u32>, - who: Address<T::AccountId, T::AccountIndex>, - who_index: Compact<u32>, - assumed_vote_index: Compact<VoteIndex> - ) -> Result { - let reporter = ensure_signed(origin)?; - let assumed_vote_index: VoteIndex = assumed_vote_index.into(); - - let who = <balances::Module<T>>::lookup(who)?; - ensure!(!Self::presentation_active(), "cannot reap during presentation period"); - ensure!(Self::voter_last_active(&reporter).is_some(), "reporter must be a voter"); - let last_active = Self::voter_last_active(&who).ok_or("target for inactivity cleanup must be active")?; - ensure!(assumed_vote_index == Self::vote_index(), "vote index not current"); - ensure!(last_active < assumed_vote_index - Self::inactivity_grace_period(), "cannot reap during grace perid"); - let voters = Self::voters(); - let reporter_index: u32 = reporter_index.into(); - let reporter_index = reporter_index as usize; - let who_index: u32 = who_index.into(); - let who_index = who_index as usize; - ensure!(reporter_index < voters.len() && voters[reporter_index] == reporter, "bad reporter index"); - ensure!(who_index < voters.len() && voters[who_index] == who, "bad target index"); - - // will definitely kill one of signed or who now. - - let valid = !Self::approvals_of(&who).iter() - .zip(Self::candidates().iter()) - .any(|(&appr, addr)| - appr && - *addr != T::AccountId::default() && - Self::candidate_reg_info(addr).map_or(false, |x| x.0 <= last_active)/*defensive only: all items in candidates list are registered*/ - ); - - Self::remove_voter( - if valid { &who } else { &reporter }, - if valid { who_index } else { reporter_index }, - voters - ); - if valid { - // This only fails if `who` doesn't exist, which it clearly must do since its the origin. - // Still, it's no more harmful to propagate any error at this point. - <balances::Module<T>>::repatriate_reserved(&who, &reporter, Self::voting_bond())?; - Self::deposit_event(RawEvent::VoterReaped(who, reporter)); - } else { - <balances::Module<T>>::slash_reserved(&reporter, Self::voting_bond()); - Self::deposit_event(RawEvent::BadReaperSlashed(reporter)); - } - Ok(()) - } - - /// Remove a voter. All votes are cancelled and the voter deposit is returned. - fn retract_voter(origin: T::Origin, index: Compact<u32>) -> Result { - let who = ensure_signed(origin)?; - - ensure!(!Self::presentation_active(), "cannot retract when presenting"); - ensure!(<LastActiveOf<T>>::exists(&who), "cannot retract non-voter"); - let voters = Self::voters(); - let index: u32 = index.into(); - let index = index as usize; - ensure!(index < voters.len(), "retraction index invalid"); - ensure!(voters[index] == who, "retraction index mismatch"); - - Self::remove_voter(&who, index, voters); - <balances::Module<T>>::unreserve(&who, Self::voting_bond()); - Ok(()) - } - - /// Submit oneself for candidacy. - /// - /// Account must have enough transferrable funds in it to pay the bond. - fn submit_candidacy(origin: T::Origin, slot: Compact<u32>) -> Result { - let who = ensure_signed(origin)?; - - ensure!(!Self::is_a_candidate(&who), "duplicate candidate submission"); - let slot: u32 = slot.into(); - let slot = slot as usize; - let count = Self::candidate_count() as usize; - let candidates = Self::candidates(); - ensure!( - (slot == count && count == candidates.len()) || - (slot < candidates.len() && candidates[slot] == T::AccountId::default()), - "invalid candidate slot" - ); - // NOTE: This must be last as it has side-effects. - <balances::Module<T>>::reserve(&who, Self::candidacy_bond()) - .map_err(|_| "candidate has not enough funds")?; - - <RegisterInfoOf<T>>::insert(&who, (Self::vote_index(), slot as u32)); - let mut candidates = candidates; - if slot == candidates.len() { - candidates.push(who); - } else { - candidates[slot] = who; - } - <Candidates<T>>::put(candidates); - <CandidateCount<T>>::put(count as u32 + 1); - Ok(()) - } - - /// Claim that `signed` is one of the top Self::carry_count() + current_vote().1 candidates. - /// Only works if the `block_number >= current_vote().0` and `< current_vote().0 + presentation_duration()`` - /// `signed` should have at least - fn present_winner( - origin: T::Origin, - candidate: Address<T::AccountId, T::AccountIndex>, - total: <T::Balance as HasCompact>::Type, - index: Compact<VoteIndex> - ) -> Result { - let who = ensure_signed(origin)?; - let total = total.into(); - let index: VoteIndex = index.into(); - - let candidate = <balances::Module<T>>::lookup(candidate)?; - ensure!(index == Self::vote_index(), "index not current"); - let (_, _, expiring) = Self::next_finalise().ok_or("cannot present outside of presentation period")?; - let stakes = Self::snapshoted_stakes(); - let voters = Self::voters(); - let bad_presentation_punishment = Self::present_slash_per_voter() * T::Balance::sa(voters.len() as u64); - ensure!(<balances::Module<T>>::can_slash(&who, bad_presentation_punishment), "presenter must have sufficient slashable funds"); - - let mut leaderboard = Self::leaderboard().ok_or("leaderboard must exist while present phase active")?; - ensure!(total > leaderboard[0].0, "candidate not worthy of leaderboard"); - - if let Some(p) = Self::active_council().iter().position(|&(ref c, _)| c == &candidate) { - ensure!(p < expiring.len(), "candidate must not form a duplicated member if elected"); - } - - let (registered_since, candidate_index): (VoteIndex, u32) = - Self::candidate_reg_info(&candidate).ok_or("presented candidate must be current")?; - let actual_total = voters.iter() - .zip(stakes.iter()) - .filter_map(|(voter, stake)| - match Self::voter_last_active(voter) { - Some(b) if b >= registered_since => - Self::approvals_of(voter).get(candidate_index as usize) - .and_then(|approved| if *approved { Some(*stake) } else { None }), - _ => None, - }) - .fold(Zero::zero(), |acc, n| acc + n); - let dupe = leaderboard.iter().find(|&&(_, ref c)| c == &candidate).is_some(); - if total == actual_total && !dupe { - // insert into leaderboard - leaderboard[0] = (total, candidate); - leaderboard.sort_by_key(|&(t, _)| t); - <Leaderboard<T>>::put(leaderboard); - Ok(()) - } else { - // we can rest assured it will be Ok since we checked `can_slash` earlier; still - // better safe than sorry. - let _ = <balances::Module<T>>::slash(&who, bad_presentation_punishment); - Err(if dupe { "duplicate presentation" } else { "incorrect total" }) - } - } - - /// Set the desired member count; if lower than the current count, then seats will not be up - /// election when they expire. If more, then a new vote will be started if one is not already - /// in progress. - fn set_desired_seats(count: Compact<u32>) -> Result { - let count: u32 = count.into(); - <DesiredSeats<T>>::put(count); - Ok(()) - } - - /// Remove a particular member. A tally will happen instantly (if not already in a presentation - /// period) to fill the seat if removal means that the desired members are not met. - /// This is effective immediately. - fn remove_member(who: Address<T::AccountId, T::AccountIndex>) -> Result { - let who = <balances::Module<T>>::lookup(who)?; - let new_council: Vec<(T::AccountId, T::BlockNumber)> = Self::active_council() - .into_iter() - .filter(|i| i.0 != who) - .collect(); - <ActiveCouncil<T>>::put(new_council); - Ok(()) - } - - /// Set the presentation duration. If there is currently a vote being presented for, will - /// invoke `finalise_vote`. - fn set_presentation_duration(count: <T::BlockNumber as HasCompact>::Type) -> Result { - <PresentationDuration<T>>::put(count.into()); - Ok(()) - } - - /// Set the presentation duration. If there is current a vote being presented for, will - /// invoke `finalise_vote`. - fn set_term_duration(count: <T::BlockNumber as HasCompact>::Type) -> Result { - <TermDuration<T>>::put(count.into()); - Ok(()) - } - - // private - + // Private /// Check there's nothing to do this block fn end_block(block_number: T::BlockNumber) -> Result { if (block_number % Self::voting_period()).is_zero() { @@ -560,15 +549,6 @@ impl<T: Trait> Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(n: T::BlockNumber) { - if let Err(e) = Self::end_block(n) { - print("Guru meditation"); - print(e); - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/substrate/srml/council/src/voting.rs b/substrate/srml/council/src/voting.rs index 094066327c07013942e54901b378f8ef6e8e2bf2..b598e8ca05257b1b91708148f389fe7431c06bcc 100644 --- a/substrate/srml/council/src/voting.rs +++ b/substrate/srml/council/src/voting.rs @@ -19,7 +19,7 @@ use rstd::prelude::*; use rstd::borrow::Borrow; use codec::HasCompact; -use primitives::traits::{OnFinalise, Hash, As}; +use primitives::traits::{Hash, As}; use runtime_io::print; use srml_support::dispatch::Result; use srml_support::{StorageValue, StorageMap, IsSubType}; @@ -33,12 +33,88 @@ pub trait Trait: CouncilTrait { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn propose(origin, proposal: Box<T::Proposal>) -> Result; - fn vote(origin, proposal: T::Hash, approve: bool) -> Result; - fn veto(origin, proposal_hash: T::Hash) -> Result; + fn deposit_event() = default; - fn set_cooloff_period(blocks: <T::BlockNumber as HasCompact>::Type) -> Result; - fn set_voting_period(blocks: <T::BlockNumber as HasCompact>::Type) -> Result; + fn propose(origin, proposal: Box<T::Proposal>) -> Result { + let who = ensure_signed(origin)?; + + let expiry = <system::Module<T>>::block_number() + Self::voting_period(); + ensure!(Self::will_still_be_councillor_at(&who, expiry), "proposer would not be on council"); + + let proposal_hash = T::Hashing::hash_of(&proposal); + + ensure!(!<ProposalOf<T>>::exists(proposal_hash), "duplicate proposals not allowed"); + ensure!(!Self::is_vetoed(&proposal_hash), "proposal is vetoed"); + + let mut proposals = Self::proposals(); + proposals.push((expiry, proposal_hash)); + proposals.sort_by_key(|&(expiry, _)| expiry); + Self::set_proposals(&proposals); + + <ProposalOf<T>>::insert(proposal_hash, *proposal); + <ProposalVoters<T>>::insert(proposal_hash, vec![who.clone()]); + <CouncilVoteOf<T>>::insert((proposal_hash, who.clone()), true); + + Ok(()) + } + + fn vote(origin, proposal: T::Hash, approve: bool) -> Result { + let who = ensure_signed(origin)?; + + ensure!(Self::is_councillor(&who), "only councillors may vote on council proposals"); + + if Self::vote_of((proposal, who.clone())).is_none() { + <ProposalVoters<T>>::mutate(proposal, |voters| voters.push(who.clone())); + } + <CouncilVoteOf<T>>::insert((proposal, who), approve); + Ok(()) + } + + fn veto(origin, proposal_hash: T::Hash) -> Result { + let who = ensure_signed(origin)?; + + ensure!(Self::is_councillor(&who), "only councillors may veto council proposals"); + ensure!(<ProposalVoters<T>>::exists(&proposal_hash), "proposal must exist to be vetoed"); + + let mut existing_vetoers = Self::veto_of(&proposal_hash) + .map(|pair| pair.1) + .unwrap_or_else(Vec::new); + let insert_position = existing_vetoers.binary_search(&who) + .err().ok_or("a councillor may not veto a proposal twice")?; + existing_vetoers.insert(insert_position, who); + Self::set_veto_of( + &proposal_hash, + <system::Module<T>>::block_number() + Self::cooloff_period(), + existing_vetoers + ); + + Self::set_proposals( + &Self::proposals().into_iter().filter(|&(_, h)| h != proposal_hash + ).collect::<Vec<_>>()); + <ProposalVoters<T>>::remove(proposal_hash); + <ProposalOf<T>>::remove(proposal_hash); + for (c, _) in <Council<T>>::active_council() { + <CouncilVoteOf<T>>::remove((proposal_hash, c)); + } + Ok(()) + } + + fn set_cooloff_period(blocks: <T::BlockNumber as HasCompact>::Type) -> Result { + <CooloffPeriod<T>>::put(blocks.into()); + Ok(()) + } + + fn set_voting_period(blocks: <T::BlockNumber as HasCompact>::Type) -> Result { + <VotingPeriod<T>>::put(blocks.into()); + Ok(()) + } + + fn on_finalise(n: T::BlockNumber) { + if let Err(e) = Self::end_block(n) { + print("Guru meditation"); + print(e); + } + } } } @@ -67,12 +143,6 @@ decl_event!( ); 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()); - } - pub fn is_vetoed<B: Borrow<T::Hash>>(proposal: B) -> bool { Self::veto_of(proposal.borrow()) .map(|(expiry, _): (T::BlockNumber, Vec<T::AccountId>)| <system::Module<T>>::block_number() < expiry) @@ -95,78 +165,7 @@ impl<T: Trait> Module<T> { Self::generic_tally(proposal_hash, |w: &T::AccountId, p: &T::Hash| Self::vote_of((*p, w.clone()))) } - // Dispatch - fn propose(origin: T::Origin, proposal: Box<T::Proposal>) -> Result { - let who = ensure_signed(origin)?; - - let expiry = <system::Module<T>>::block_number() + Self::voting_period(); - ensure!(Self::will_still_be_councillor_at(&who, expiry), "proposer would not be on council"); - - let proposal_hash = T::Hashing::hash_of(&proposal); - - ensure!(!<ProposalOf<T>>::exists(proposal_hash), "duplicate proposals not allowed"); - ensure!(!Self::is_vetoed(&proposal_hash), "proposal is vetoed"); - - let mut proposals = Self::proposals(); - proposals.push((expiry, proposal_hash)); - proposals.sort_by_key(|&(expiry, _)| expiry); - Self::set_proposals(&proposals); - - <ProposalOf<T>>::insert(proposal_hash, *proposal); - <ProposalVoters<T>>::insert(proposal_hash, vec![who.clone()]); - <CouncilVoteOf<T>>::insert((proposal_hash, who.clone()), true); - - Ok(()) - } - - fn vote(origin: T::Origin, proposal: T::Hash, approve: bool) -> Result { - let who = ensure_signed(origin)?; - - ensure!(Self::is_councillor(&who), "only councillors may vote on council proposals"); - - if Self::vote_of((proposal, who.clone())).is_none() { - <ProposalVoters<T>>::mutate(proposal, |voters| voters.push(who.clone())); - } - <CouncilVoteOf<T>>::insert((proposal, who), approve); - Ok(()) - } - - fn veto(origin: T::Origin, proposal_hash: T::Hash) -> Result { - let who = ensure_signed(origin)?; - - ensure!(Self::is_councillor(&who), "only councillors may veto council proposals"); - ensure!(<ProposalVoters<T>>::exists(&proposal_hash), "proposal must exist to be vetoed"); - - let mut existing_vetoers = Self::veto_of(&proposal_hash) - .map(|pair| pair.1) - .unwrap_or_else(Vec::new); - let insert_position = existing_vetoers.binary_search(&who) - .err().ok_or("a councillor may not veto a proposal twice")?; - existing_vetoers.insert(insert_position, who); - Self::set_veto_of(&proposal_hash, <system::Module<T>>::block_number() + Self::cooloff_period(), existing_vetoers); - - Self::set_proposals(&Self::proposals().into_iter().filter(|&(_, h)| h != proposal_hash).collect::<Vec<_>>()); - <ProposalVoters<T>>::remove(proposal_hash); - <ProposalOf<T>>::remove(proposal_hash); - for (c, _) in <Council<T>>::active_council() { - <CouncilVoteOf<T>>::remove((proposal_hash, c)); - } - Ok(()) - } - - fn set_cooloff_period(blocks: <T::BlockNumber as HasCompact>::Type) -> Result { - <CooloffPeriod<T>>::put(blocks.into()); - Ok(()) - } - - fn set_voting_period(blocks: <T::BlockNumber as HasCompact>::Type) -> Result { - <VotingPeriod<T>>::put(blocks.into()); - Ok(()) - } - - // private - - + // Private fn set_veto_of(proposal: &T::Hash, expiry: T::BlockNumber, vetoers: Vec<T::AccountId>) { <VetoedProposal<T>>::insert(proposal, (expiry, vetoers)); } @@ -227,15 +226,6 @@ impl<T: Trait> Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(n: T::BlockNumber) { - if let Err(e) = Self::end_block(n) { - print("Guru meditation"); - print(e); - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/substrate/srml/democracy/src/lib.rs b/substrate/srml/democracy/src/lib.rs index f5c3153251c57e6f57f05bc9674bc6df7762e8a3..9acacb2ea96512d3bfd19ced571a8986b09e4e6f 100644 --- a/substrate/srml/democracy/src/lib.rs +++ b/substrate/srml/democracy/src/lib.rs @@ -41,7 +41,7 @@ extern crate srml_system as system; use rstd::prelude::*; use rstd::result; use codec::{HasCompact, Compact}; -use primitives::traits::{Zero, OnFinalise, As, MaybeSerializeDebug}; +use primitives::traits::{Zero, As, MaybeSerializeDebug}; use srml_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType}; use srml_support::dispatch::Result; use system::ensure_signed; @@ -62,12 +62,79 @@ pub trait Trait: balances::Trait + Sized { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn propose(origin, proposal: Box<T::Proposal>, value: <T::Balance as HasCompact>::Type) -> Result; - fn second(origin, proposal: Compact<PropIndex>) -> Result; - fn vote(origin, ref_index: Compact<ReferendumIndex>, approve_proposal: bool) -> Result; + fn deposit_event() = default; + + /// Propose a sensitive action to be taken. + fn propose( + origin, + proposal: Box<T::Proposal>, + value: <T::Balance as HasCompact>::Type + ) -> Result { + let who = ensure_signed(origin)?; + let value = value.into(); + + ensure!(value >= Self::minimum_deposit(), "value too low"); + <balances::Module<T>>::reserve(&who, value) + .map_err(|_| "proposer's balance too low")?; + + let index = Self::public_prop_count(); + <PublicPropCount<T>>::put(index + 1); + <DepositOf<T>>::insert(index, (value, vec![who.clone()])); + + let mut props = Self::public_props(); + props.push((index, (*proposal).clone(), who)); + <PublicProps<T>>::put(props); + Ok(()) + } + + /// Propose a sensitive action to be taken. + fn second(origin, proposal: Compact<PropIndex>) -> Result { + let who = ensure_signed(origin)?; + let proposal: PropIndex = proposal.into(); + let mut deposit = Self::deposit_of(proposal) + .ok_or("can only second an existing proposal")?; + <balances::Module<T>>::reserve(&who, deposit.0) + .map_err(|_| "seconder's balance too low")?; + deposit.1.push(who); + <DepositOf<T>>::insert(proposal, deposit); + Ok(()) + } + + /// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal; + /// false would be a vote to keep the status quo. + fn vote(origin, ref_index: Compact<ReferendumIndex>, approve_proposal: bool) -> Result { + let who = ensure_signed(origin)?; + let ref_index = ref_index.into(); + ensure!(Self::is_active_referendum(ref_index), "vote given for invalid referendum."); + ensure!(!<balances::Module<T>>::total_balance(&who).is_zero(), + "transactor must have balance to signal approval."); + if !<VoteOf<T>>::exists(&(ref_index, who.clone())) { + <VotersFor<T>>::mutate(ref_index, |voters| voters.push(who.clone())); + } + <VoteOf<T>>::insert(&(ref_index, who), approve_proposal); + Ok(()) + } + + /// Start a referendum. + fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result { + Self::inject_referendum( + <system::Module<T>>::block_number() + Self::voting_period(), + *proposal, + vote_threshold + ).map(|_| ()) + } + + /// Remove a referendum. + fn cancel_referendum(ref_index: Compact<ReferendumIndex>) -> Result { + Self::clear_referendum(ref_index.into()); + Ok(()) + } - fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result; - fn cancel_referendum(ref_index: Compact<ReferendumIndex>) -> Result; + fn on_finalise(n: T::BlockNumber) { + if let Err(e) = Self::end_block(n) { + runtime_io::print(e); + } + } } } @@ -116,12 +183,6 @@ decl_event!( ); 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()); - } - // exposed immutables. /// Get the amount locked in support of `proposal`; `None` if proposal isn't a valid proposal @@ -162,71 +223,7 @@ impl<T: Trait> Module<T> { .fold((Zero::zero(), Zero::zero()), |(a, b), (c, d)| (a + c, b + d)) } - // dispatching. - - /// Propose a sensitive action to be taken. - fn propose(origin: T::Origin, proposal: Box<T::Proposal>, value: <T::Balance as HasCompact>::Type) -> Result { - let who = ensure_signed(origin)?; - let value = value.into(); - - ensure!(value >= Self::minimum_deposit(), "value too low"); - <balances::Module<T>>::reserve(&who, value) - .map_err(|_| "proposer's balance too low")?; - - let index = Self::public_prop_count(); - <PublicPropCount<T>>::put(index + 1); - <DepositOf<T>>::insert(index, (value, vec![who.clone()])); - - let mut props = Self::public_props(); - props.push((index, (*proposal).clone(), who)); - <PublicProps<T>>::put(props); - Ok(()) - } - - /// Propose a sensitive action to be taken. - fn second(origin: T::Origin, proposal: Compact<PropIndex>) -> Result { - let who = ensure_signed(origin)?; - let proposal: PropIndex = proposal.into(); - let mut deposit = Self::deposit_of(proposal) - .ok_or("can only second an existing proposal")?; - <balances::Module<T>>::reserve(&who, deposit.0) - .map_err(|_| "seconder's balance too low")?; - deposit.1.push(who); - <DepositOf<T>>::insert(proposal, deposit); - Ok(()) - } - - /// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal; - /// false would be a vote to keep the status quo. - fn vote(origin: T::Origin, ref_index: Compact<ReferendumIndex>, approve_proposal: bool) -> Result { - let who = ensure_signed(origin)?; - let ref_index = ref_index.into(); - ensure!(Self::is_active_referendum(ref_index), "vote given for invalid referendum."); - ensure!(!<balances::Module<T>>::total_balance(&who).is_zero(), - "transactor must have balance to signal approval."); - if !<VoteOf<T>>::exists(&(ref_index, who.clone())) { - <VotersFor<T>>::mutate(ref_index, |voters| voters.push(who.clone())); - } - <VoteOf<T>>::insert(&(ref_index, who), approve_proposal); - Ok(()) - } - - /// Start a referendum. - fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result { - Self::inject_referendum( - <system::Module<T>>::block_number() + Self::voting_period(), - *proposal, - vote_threshold - ).map(|_| ()) - } - - /// Remove a referendum. - fn cancel_referendum(ref_index: Compact<ReferendumIndex>) -> Result { - Self::clear_referendum(ref_index.into()); - Ok(()) - } - - // exposed mutables. + // Exposed mutables. /// Start a referendum. Can be called directly by the council. pub fn internal_start_referendum(proposal: T::Proposal, vote_threshold: VoteThreshold) -> result::Result<ReferendumIndex, &'static str> { @@ -308,14 +305,6 @@ impl<T: Trait> Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(n: T::BlockNumber) { - if let Err(e) = Self::end_block(n) { - runtime_io::print(e); - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/substrate/srml/example/src/lib.rs b/substrate/srml/example/src/lib.rs index f60168d37b3e9d0680a3af4a351ba225997c30df..d6d7ea31faf5f6d39f33754d8261c66298a5de25 100644 --- a/substrate/srml/example/src/lib.rs +++ b/substrate/srml/example/src/lib.rs @@ -57,7 +57,6 @@ extern crate srml_system as system; // might find it useful). extern crate srml_balances as balances; -use sr_primitives::traits::OnFinalise; use support::{StorageValue, dispatch::Result}; use system::ensure_signed; @@ -104,13 +103,97 @@ pub trait Trait: balances::Trait { 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 { + /// Deposit one of this module's events by using the default implementation. + /// It is also possible to provide a custom implementation. + fn deposit_event() = default; /// This is your public interface. Be extremely careful. /// This is just a simple example of how to interact with the module from the external /// world. - fn accumulate_dummy(origin, increase_by: T::Balance) -> Result; + // This just increases the value of `Dummy` by `increase_by`. + // + // Since this is a dispatched function there are two extremely important things to + // remember: + // + // - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an + // irreparably damaged state) must this function panic. + // - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return + // `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`. + // + // The first is relatively easy to audit for - just ensure all panickers are removed from + // logic that executes in production (which you do anyway, right?!). To ensure the second + // is followed, you should do all tests for validity at the top of your function. This + // is stuff like checking the sender (`origin`) or that state is such that the operation + // makes sense. + // + // Once you've determined that it's all good, then enact the operation and change storage. + // If you can't be certain that the operation will succeed without substantial computation + // then you have a classic blockchain attack scenario. The normal way of managing this is + // to attach a bond to the operation. As the first major alteration of storage, reserve + // some value from the sender's account (`Balances` module has a `reserve` function for + // exactly this scenario). This amount should be enough to cover any costs of the + // substantial execution in case it turns out that you can't proceed with the operation. + // + // If it eventually transpires that the operation is fine and, therefore, that the + // expense of the checks should be borne by the network, then you can refund the reserved + // deposit. If, however, the operation turns out to be invalid and the computation is + // wasted, then you can burn it or repatriate elsewhere. + // + // Security bonds ensure that attackers can't game it by ensuring that anyone interacting + // with the system either progresses it or pays for the trouble of faffing around with + // no progress. + // + // If you don't respect these rules, it is likely that your chain will be attackable. + fn accumulate_dummy(origin, increase_by: T::Balance) -> Result { + // This is a public call, so we ensure that the origin is some signed account. + let _sender = ensure_signed(origin)?; + + // Read the value of dummy from storage. + // let dummy = Self::dummy(); + // Will also work using the `::get` on the storage item type itself: + // let dummy = <Dummy<T>>::get(); + + // Calculate the new value. + // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); + + // Put the new value into storage. + // <Dummy<T>>::put(new_dummy); + // Will also work with a reference: + // <Dummy<T>>::put(&new_dummy); + + // Here's the new one of read and then modify the value. + <Dummy<T>>::mutate(|dummy| { + let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); + *dummy = Some(new_dummy); + }); + + // Let's deposit an event to let the outside world know this happened. + Self::deposit_event(RawEvent::Dummy(increase_by)); + + // All good. + Ok(()) + } /// A privileged call; in this case it resets our dummy value to something new. - fn set_dummy(new_dummy: T::Balance) -> Result; + // Implementation of a privileged call. This doesn't have an `origin` parameter because + // it's not (directly) from an extrinsic, but rather the system as a whole has decided + // to execute it. Different runtimes have different reasons for allow privileged + // calls to be executed - we don't need to care why. Because it's privileged, we can + // assume it's a one-off operation and substantial processing/storage/memory can be used + // without worrying about gameability or attack scenarios. + fn set_dummy(new_value: T::Balance) -> Result { + // Put the new value into storage. + <Dummy<T>>::put(new_value); + + // All good. + Ok(()) + } + + // The signature could also look like: `fn on_finalise()` + fn on_finalise(_n: T::BlockNumber) { + // Anything that needs to be done at the end of the block. + // We just kill our dummy storage item. + <Dummy<T>>::kill(); + } } } @@ -162,119 +245,27 @@ decl_storage! { // The main implementation block for the module. Functions here fall into three broad // categories: -// - Implementations of dispatch functions. The dispatch code generated by the module macro -// expects each of its functions to be implemented. // - Public interface. These are functions that are `pub` and generally fall into inspector // functions that do not write to storage and operation functions that do. // - Private functions. These are your usual private utilities unavailable to other modules. 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()); - } - - // Implement Calls and add public immutables and private mutables. - - // Implement dispatched function `accumulate_dummy`. This just increases the value - // of `Dummy` by `increase_by`. - // - // Since this is a dispatched function there are two extremely important things to - // remember: - // - // - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an - // irreparably damaged state) must this function panic. - // - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return - // `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`. - // - // The first is relatively easy to audit for - just ensure all panickers are removed from - // logic that executes in production (which you do anyway, right?!). To ensure the second - // is followed, you should do all tests for validity at the top of your function. This - // is stuff like checking the sender (`origin`) or that state is such that the operation - // makes sense. - // - // Once you've determined that it's all good, then enact the operation and change storage. - // If you can't be certain that the operation will succeed without substantial computation - // then you have a classic blockchain attack scenario. The normal way of managing this is - // to attach a bond to the operation. As the first major alteration of storage, reserve - // some value from the sender's account (`Balances` module has a `reserve` function for - // exactly this scenario). This amount should be enough to cover any costs of the - // substantial execution in case it turns out that you can't proceed with the operation. - // - // If it eventually transpires that the operation is fine and, therefore, that the - // expense of the checks should be borne by the network, then you can refund the reserved - // deposit. If, however, the operation turns out to be invalid and the computation is - // wasted, then you can burn it or repatriate elsewhere. - // - // Security bonds ensure that attackers can't game it by ensuring that anyone interacting - // with the system either progresses it or pays for the trouble of faffing around with - // no progress. - // - // If you don't respect these rules, it is likely that your chain will be attackable. - fn accumulate_dummy(origin: T::Origin, increase_by: T::Balance) -> Result { - // This is a public call, so we ensure that the origin is some signed account. - let _sender = ensure_signed(origin)?; - - // Read the value of dummy from storage. - // let dummy = Self::dummy(); - // Will also work using the `::get` on the storage item type itself: - // let dummy = <Dummy<T>>::get(); - - // Calculate the new value. - // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); - - // Put the new value into storage. - // <Dummy<T>>::put(new_dummy); - // Will also work with a reference: - // <Dummy<T>>::put(&new_dummy); - - // Here's the new one of read and then modify the value. - <Dummy<T>>::mutate(|dummy| { - let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); - *dummy = Some(new_dummy); - }); - - // Let's deposit an event to let the outside world know this happened. - Self::deposit_event(RawEvent::Dummy(increase_by)); - - // All good. - Ok(()) - } - + // Add public immutables and private mutables. #[allow(dead_code)] fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> Result { let _sender = ensure_signed(origin)?; + let prev = <Foo<T>>::get(); // Because Foo has 'default', the type of 'foo' in closure is the raw type instead of an Option<> type. - <Foo<T>>::mutate(|foo| *foo = *foo + increase_by); - - Ok(()) - } + let result = <Foo<T>>::mutate(|foo| { + *foo = *foo + increase_by; + *foo + }); + assert!(prev + increase_by == result); - // Implementation of a privileged call. This doesn't have an `origin` parameter because - // it's not (directly) from an extrinsic, but rather the system as a whole has decided - // to execute it. Different runtimes have different reasons for allow privileged - // calls to be executed - we don't need to care why. Because it's privileged, we can - // assume it's a one-off operation and substantial processing/storage/memory can be used - // without worrying about gameability or attack scenarios. - fn set_dummy(new_value: T::Balance) -> Result { - // Put the new value into storage. - <Dummy<T>>::put(new_value); - - // All good. Ok(()) } } -// This trait expresses what should happen when the block is finalised. -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(_: T::BlockNumber) { - // Anything that needs to be done at the end of the block. - // We just kill our dummy storage item. - <Dummy<T>>::kill(); - } -} - #[cfg(test)] mod tests { use super::*; @@ -283,7 +274,9 @@ mod tests { use substrate_primitives::{H256, Blake2Hasher}; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. - use sr_primitives::{BuildStorage, traits::{BlakeTwo256}, testing::{Digest, DigestItem, Header}}; + use sr_primitives::{ + BuildStorage, traits::{BlakeTwo256, OnFinalise}, testing::{Digest, DigestItem, Header} + }; impl_outer_origin! { pub enum Origin for Test {} diff --git a/substrate/srml/session/src/lib.rs b/substrate/srml/session/src/lib.rs index 087e37ecfe9a888cc98133eda2dab6bee626473b..cc75c75bc52b650d97f70b974a0e29bddbffb47c 100644 --- a/substrate/srml/session/src/lib.rs +++ b/substrate/srml/session/src/lib.rs @@ -42,7 +42,7 @@ extern crate srml_system as system; extern crate srml_timestamp as timestamp; use rstd::prelude::*; -use primitives::traits::{As, Zero, One, OnFinalise, Convert}; +use primitives::traits::{As, Zero, One, Convert}; use codec::HasCompact; use runtime_support::{StorageValue, StorageMap}; use runtime_support::dispatch::Result; @@ -67,10 +67,31 @@ pub trait Trait: timestamp::Trait { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn set_key(origin, key: T::SessionKey) -> Result; + fn deposit_event() = default; + + /// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next + /// session. + fn set_key(origin, key: T::SessionKey) -> Result { + let who = ensure_signed(origin)?; + // set new value for next session + <NextKeyFor<T>>::insert(who, key); + Ok(()) + } + + /// Set a new session length. Won't kick in until the next session change (at current length). + fn set_length(new: <T::BlockNumber as HasCompact>::Type) -> Result { + <NextSessionLength<T>>::put(new.into()); + Ok(()) + } - fn set_length(new: <T::BlockNumber as HasCompact>::Type) -> Result; - fn force_new_session(apply_rewards: bool) -> Result; + /// Forces a new session. + fn force_new_session(apply_rewards: bool) -> Result { + Self::apply_force_new_session(apply_rewards) + } + + fn on_finalise(n: T::BlockNumber) { + Self::check_rotate_session(n); + } } } @@ -108,12 +129,6 @@ decl_storage! { } 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()); - } - /// The number of validators currently. pub fn validator_count() -> u32 { <Validators<T>>::get().len() as u32 // TODO: can probably optimised @@ -124,28 +139,7 @@ impl<T: Trait> Module<T> { <LastLengthChange<T>>::get().unwrap_or_else(T::BlockNumber::zero) } - /// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next - /// session. - fn set_key(origin: T::Origin, key: T::SessionKey) -> Result { - let who = ensure_signed(origin)?; - // set new value for next session - <NextKeyFor<T>>::insert(who, key); - Ok(()) - } - - /// Set a new session length. Won't kick in until the next session change (at current length). - fn set_length(new: <T::BlockNumber as HasCompact>::Type) -> Result { - <NextSessionLength<T>>::put(new.into()); - Ok(()) - } - - /// Forces a new session. - pub fn force_new_session(apply_rewards: bool) -> Result { - Self::apply_force_new_session(apply_rewards) - } - // INTERNAL API (available to other runtime modules) - /// Forces a new session, no origin. pub fn apply_force_new_session(apply_rewards: bool) -> Result { <ForcingNewSession<T>>::put(apply_rewards); @@ -228,12 +222,6 @@ impl<T: Trait> Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(n: T::BlockNumber) { - Self::check_rotate_session(n); - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs index 6b47e01c33c1cd66da581004a868e8965c40cdb3..680da340c54c53a1633b05f718a2d8be813188a6 100644 --- a/substrate/srml/staking/src/lib.rs +++ b/substrate/srml/staking/src/lib.rs @@ -55,7 +55,7 @@ use codec::{HasCompact, Compact}; use runtime_support::{Parameter, StorageValue, StorageMap}; use runtime_support::dispatch::Result; use session::OnSessionChange; -use primitives::{Perbill, traits::{Zero, One, Bounded, OnFinalise, As}}; +use primitives::{Perbill, traits::{Zero, One, Bounded, As}}; use balances::{address::Address, OnDilution}; use system::ensure_signed; @@ -76,7 +76,7 @@ pub enum LockStatus<BlockNumber: Parameter> { /// Preference of what happens on a slash event. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -pub struct ValidatorPrefs<Balance: HasCompact + Copy> { // TODO: @bkchr shouldn't need this Copy but derive(Encode) breaks otherwise +pub struct ValidatorPrefs<Balance: HasCompact + Copy> { // TODO: @bkchr shouldn't need this Copy but derive(Encode) breaks otherwise /// Validator should ensure this many more slashes than is necessary before being unstaked. #[codec(compact)] pub unstake_threshold: u32, @@ -105,17 +105,140 @@ pub trait Trait: balances::Trait + session::Trait { decl_module! { #[cfg_attr(feature = "std", serde(bound(deserialize = "T::Balance: ::serde::de::DeserializeOwned")))] pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn stake(origin) -> Result; - fn unstake(origin, intentions_index: Compact<u32>) -> Result; - fn nominate(origin, target: Address<T::AccountId, T::AccountIndex>) -> Result; - fn unnominate(origin, target_index: Compact<u32>) -> Result; - fn register_preferences(origin, intentions_index: Compact<u32>, prefs: ValidatorPrefs<T::Balance>) -> Result; - - fn set_sessions_per_era(new: <T::BlockNumber as HasCompact>::Type) -> Result; - fn set_bonding_duration(new: <T::BlockNumber as HasCompact>::Type) -> Result; - fn set_validator_count(new: Compact<u32>) -> Result; - fn force_new_era(apply_rewards: bool) -> Result; - fn set_offline_slash_grace(new: Compact<u32>) -> Result; + fn deposit_event() = default; + + /// Declare the desire to stake for the transactor. + /// + /// Effects will be felt at the beginning of the next era. + fn stake(origin) -> Result { + let who = ensure_signed(origin)?; + ensure!(Self::nominating(&who).is_none(), "Cannot stake if already nominating."); + let mut intentions = <Intentions<T>>::get(); + // can't be in the list twice. + ensure!(intentions.iter().find(|&t| t == &who).is_none(), "Cannot stake if already staked."); + + <Bondage<T>>::insert(&who, T::BlockNumber::max_value()); + intentions.push(who); + <Intentions<T>>::put(intentions); + Ok(()) + } + + /// Retract the desire to stake for the transactor. + /// + /// Effects will be felt at the beginning of the next era. + fn unstake(origin, intentions_index: Compact<u32>) -> Result { + let who = ensure_signed(origin)?; + let intentions_index: u32 = intentions_index.into(); + // unstake fails in degenerate case of having too few existing staked parties + if Self::intentions().len() <= Self::minimum_validator_count() as usize { + return Err("cannot unstake when there are too few staked participants") + } + Self::apply_unstake(&who, intentions_index as usize) + } + + fn nominate(origin, target: Address<T::AccountId, T::AccountIndex>) -> Result { + let who = ensure_signed(origin)?; + let target = <balances::Module<T>>::lookup(target)?; + + ensure!(Self::nominating(&who).is_none(), "Cannot nominate if already nominating."); + ensure!(Self::intentions().iter().find(|&t| t == &who).is_none(), "Cannot nominate if already staked."); + + // update nominators_for + let mut t = Self::nominators_for(&target); + t.push(who.clone()); + <NominatorsFor<T>>::insert(&target, t); + + // update nominating + <Nominating<T>>::insert(&who, &target); + + // Update bondage + <Bondage<T>>::insert(&who, T::BlockNumber::max_value()); + + Ok(()) + } + + /// Will panic if called when source isn't currently nominating target. + /// Updates Nominating, NominatorsFor and NominationBalance. + fn unnominate(origin, target_index: Compact<u32>) -> Result { + let source = ensure_signed(origin)?; + let target_index: u32 = target_index.into(); + let target_index = target_index as usize; + + let target = <Nominating<T>>::get(&source).ok_or("Account must be nominating")?; + + let mut t = Self::nominators_for(&target); + if t.get(target_index) != Some(&source) { + return Err("Invalid target index") + } + + // Ok - all valid. + + // update nominators_for + t.swap_remove(target_index); + <NominatorsFor<T>>::insert(&target, t); + + // update nominating + <Nominating<T>>::remove(&source); + + // update bondage + <Bondage<T>>::insert( + source, + <system::Module<T>>::block_number() + Self::bonding_duration() + ); + Ok(()) + } + + /// Set the given account's preference for slashing behaviour should they be a validator. + /// + /// An error (no-op) if `Self::intentions()[intentions_index] != origin`. + fn register_preferences( + origin, + intentions_index: Compact<u32>, + prefs: ValidatorPrefs<T::Balance> + ) -> Result { + let who = ensure_signed(origin)?; + let intentions_index: u32 = intentions_index.into(); + + if Self::intentions().get(intentions_index as usize) != Some(&who) { + return Err("Invalid index") + } + + <ValidatorPreferences<T>>::insert(who, prefs); + + Ok(()) + } + + /// Set the number of sessions in an era. + fn set_sessions_per_era(new: <T::BlockNumber as HasCompact>::Type) -> Result { + <NextSessionsPerEra<T>>::put(new.into()); + Ok(()) + } + + /// The length of the bonding duration in eras. + fn set_bonding_duration(new: <T::BlockNumber as HasCompact>::Type) -> Result { + <BondingDuration<T>>::put(new.into()); + Ok(()) + } + + /// The length of a staking era in sessions. + fn set_validator_count(new: Compact<u32>) -> Result { + let new: u32 = new.into(); + <ValidatorCount<T>>::put(new); + Ok(()) + } + + /// Force there to be a new era. This also forces a new session immediately after. + /// `apply_rewards` should be true for validators to get the session reward. + fn force_new_era(apply_rewards: bool) -> Result { + Self::apply_force_new_era(apply_rewards) + } + + /// Set the offline slash grace period. + fn set_offline_slash_grace(new: Compact<u32>) -> Result { + let new: u32 = new.into(); + <OfflineSlashGrace<T>>::put(new); + Ok(()) + } } } @@ -189,10 +312,10 @@ decl_storage! { } 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()); + // Just force_new_era without origin check. + fn apply_force_new_era(apply_rewards: bool) -> Result { + <ForcingNewEra<T>>::put(()); + <session::Module<T>>::apply_force_new_session(apply_rewards) } // PUBLIC IMMUTABLES @@ -225,147 +348,6 @@ impl<T: Trait> Module<T> { } } - // PUBLIC DISPATCH - - /// Declare the desire to stake for the transactor. - /// - /// Effects will be felt at the beginning of the next era. - fn stake(origin: T::Origin) -> Result { - let who = ensure_signed(origin)?; - ensure!(Self::nominating(&who).is_none(), "Cannot stake if already nominating."); - let mut intentions = <Intentions<T>>::get(); - // can't be in the list twice. - ensure!(intentions.iter().find(|&t| t == &who).is_none(), "Cannot stake if already staked."); - - <Bondage<T>>::insert(&who, T::BlockNumber::max_value()); - intentions.push(who); - <Intentions<T>>::put(intentions); - Ok(()) - } - - /// Retract the desire to stake for the transactor. - /// - /// Effects will be felt at the beginning of the next era. - fn unstake(origin: T::Origin, intentions_index: Compact<u32>) -> Result { - let who = ensure_signed(origin)?; - let intentions_index: u32 = intentions_index.into(); - // unstake fails in degenerate case of having too few existing staked parties - if Self::intentions().len() <= Self::minimum_validator_count() as usize { - return Err("cannot unstake when there are too few staked participants") - } - Self::apply_unstake(&who, intentions_index as usize) - } - - fn nominate(origin: T::Origin, target: Address<T::AccountId, T::AccountIndex>) -> Result { - let who = ensure_signed(origin)?; - let target = <balances::Module<T>>::lookup(target)?; - - ensure!(Self::nominating(&who).is_none(), "Cannot nominate if already nominating."); - ensure!(Self::intentions().iter().find(|&t| t == &who).is_none(), "Cannot nominate if already staked."); - - // update nominators_for - let mut t = Self::nominators_for(&target); - t.push(who.clone()); - <NominatorsFor<T>>::insert(&target, t); - - // update nominating - <Nominating<T>>::insert(&who, &target); - - // Update bondage - <Bondage<T>>::insert(&who, T::BlockNumber::max_value()); - - Ok(()) - } - - /// Will panic if called when source isn't currently nominating target. - /// Updates Nominating, NominatorsFor and NominationBalance. - fn unnominate(origin: T::Origin, target_index: Compact<u32>) -> Result { - let source = ensure_signed(origin)?; - let target_index: u32 = target_index.into(); - let target_index = target_index as usize; - - let target = <Nominating<T>>::get(&source).ok_or("Account must be nominating")?; - - let mut t = Self::nominators_for(&target); - if t.get(target_index) != Some(&source) { - return Err("Invalid target index") - } - - // Ok - all valid. - - // update nominators_for - t.swap_remove(target_index); - <NominatorsFor<T>>::insert(&target, t); - - // update nominating - <Nominating<T>>::remove(&source); - - // update bondage - <Bondage<T>>::insert(source, <system::Module<T>>::block_number() + Self::bonding_duration()); - Ok(()) - } - - /// Set the given account's preference for slashing behaviour should they be a validator. - /// - /// An error (no-op) if `Self::intentions()[intentions_index] != origin`. - fn register_preferences( - origin: T::Origin, - intentions_index: Compact<u32>, - prefs: ValidatorPrefs<T::Balance> - ) -> Result { - let who = ensure_signed(origin)?; - let intentions_index: u32 = intentions_index.into(); - - if Self::intentions().get(intentions_index as usize) != Some(&who) { - return Err("Invalid index") - } - - <ValidatorPreferences<T>>::insert(who, prefs); - - Ok(()) - } - - // PRIV DISPATCH - - /// Set the number of sessions in an era. - fn set_sessions_per_era(new: <T::BlockNumber as HasCompact>::Type) -> Result { - <NextSessionsPerEra<T>>::put(new.into()); - Ok(()) - } - - /// The length of the bonding duration in eras. - fn set_bonding_duration(new: <T::BlockNumber as HasCompact>::Type) -> Result { - <BondingDuration<T>>::put(new.into()); - Ok(()) - } - - /// The length of a staking era in sessions. - fn set_validator_count(new: Compact<u32>) -> Result { - let new: u32 = new.into(); - <ValidatorCount<T>>::put(new); - Ok(()) - } - - /// Force there to be a new era. This also forces a new session immediately after. - /// `apply_rewards` should be true for validators to get the session reward. - fn force_new_era(apply_rewards: bool) -> Result { - Self::apply_force_new_era(apply_rewards) - } - - // Just force_new_era without origin check. - fn apply_force_new_era(apply_rewards: bool) -> Result { - <ForcingNewEra<T>>::put(()); - <session::Module<T>>::apply_force_new_session(apply_rewards) - } - - - /// Set the offline slash grace period. - fn set_offline_slash_grace(new: Compact<u32>) -> Result { - let new: u32 = new.into(); - <OfflineSlashGrace<T>>::put(new); - Ok(()) - } - // PUBLIC MUTABLES (DANGEROUS) /// Slash a given validator by a specific amount. Removes the slash from their balance by preference, @@ -525,11 +507,6 @@ impl<T: Trait> Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(_n: T::BlockNumber) { - } -} - impl<T: Trait> OnSessionChange<T::Moment> for Module<T> { fn on_session_change(elapsed: T::Moment, should_reward: bool) { Self::new_session(elapsed, should_reward); diff --git a/substrate/srml/support/src/dispatch.rs b/substrate/srml/support/src/dispatch.rs index a413f06b0f58694fdbd6e9593ae0f608295c1e68..dd52e35b3cf844673bf68f5b22354325ca69e563 100644 --- a/substrate/srml/support/src/dispatch.rs +++ b/substrate/srml/support/src/dispatch.rs @@ -75,7 +75,9 @@ macro_rules! decl_module { decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name> - for enum $call_type where origin: $origin_type where system = system + for enum $call_type where origin: $origin_type, system = system + {} + {} [] $($t)* ); @@ -83,14 +85,16 @@ macro_rules! decl_module { ( $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> - for enum $call_type:ident where origin: $origin_type:ty where system = $system:ident { + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $($t:tt)* } ) => { decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name> - for enum $call_type where origin: $origin_type where system = $system + for enum $call_type where origin: $origin_type, system = $system + {} + {} [] $($t)* ); @@ -99,58 +103,135 @@ macro_rules! decl_module { (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> - for enum $call_type:ident where origin: $origin_type:ty where system = $system:ident + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + {} + { $( $on_finalise:tt )* } + [ $($t:tt)* ] + $(#[doc = $doc_attr:tt])* + $vis:vis fn deposit_event() = default; + $($rest:tt)* + ) => { + decl_module!(@normalize + $(#[$attr])* + pub struct $mod_type<$trait_instance: $trait_name> + for enum $call_type where origin: $origin_type, system = $system + { $vis fn deposit_event() = default; } + { $( $on_finalise )* } + [ $($t)* ] + $($rest)* + ); + }; + (@normalize + $(#[$attr:meta])* + pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + {} + { $( $on_finalise:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* - fn $fn_name:ident(origin $(, $param_name:ident : $param:ty)* ) -> $result:ty ; + $vis:vis fn deposit_event($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name> - for enum $call_type where origin: $origin_type where system = $system - [ $($t)* $(#[doc = $doc_attr])* fn $fn_name(origin $( , $param_name : $param )* ) -> $result; ] + for enum $call_type where origin: $origin_type, system = $system + { $vis fn deposit_event($( $param_name: $param ),* ) { $( $impl )* } } + { $( $on_finalise )* } + [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> - for enum $call_type:ident where origin: $origin_type:ty where system = $system:ident + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $deposit_event:tt )* } + {} [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* - fn $fn_name:ident($( $param_name:ident : $param:ty),* ) -> $result:ty ; + fn on_finalise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name> - for enum $call_type where origin: $origin_type where system = $system - [ $($t)* $(#[doc = $doc_attr])* fn $fn_name(root $( , $param_name : $param )* ) -> $result; ] + for enum $call_type where origin: $origin_type, system = $system + { $( $deposit_event )* } + { fn on_finalise( $( $param_name : $param ),* ) { $( $impl )* } } + [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> - for enum $call_type:ident where origin: $origin_type:ty where system = $system:ident + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $deposit_event:tt )* } + { $( $on_finalise:tt )* } + [ $($t:tt)* ] + $(#[doc = $doc_attr:tt])* + $fn_vis:vis fn $fn_name:ident($origin:ident $(, $param_name:ident : $param:ty)* ) -> $result:ty { $( $impl:tt )* } + $($rest:tt)* + ) => { + decl_module!(@normalize + $(#[$attr])* + pub struct $mod_type<$trait_instance: $trait_name> + for enum $call_type where origin: $origin_type, system = $system + { $( $deposit_event )* } + { $( $on_finalise )* } + [ + $($t)* + $(#[doc = $doc_attr])* + $fn_vis fn $fn_name($origin $( , $param_name : $param )* ) -> $result { $( $impl )* } + ] + $($rest)* + ); + }; + (@normalize + $(#[$attr:meta])* + pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $deposit_event:tt )* } + { $( $on_finalise:tt )* } + [ $($t:tt)* ] + $(#[doc = $doc_attr:tt])* + $fn_vis:vis fn $fn_name:ident($( $param_name:ident : $param:ty),* ) -> $result:ty { $( $impl:tt )* } + $($rest:tt)* + ) => { + decl_module!(@normalize + $(#[$attr])* + pub struct $mod_type<$trait_instance: $trait_name> + for enum $call_type where origin: $origin_type, system = $system + { $( $deposit_event )* } + { $( $on_finalise )* } + [ + $($t)* + $(#[doc = $doc_attr])* + $fn_vis fn $fn_name(root $( , $param_name : $param )* ) -> $result { $( $impl )* } + ] + $($rest)* + ); + }; + (@normalize + $(#[$attr:meta])* + pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident + { $( $deposit_event:tt )* } + { $( $on_finalise:tt )* } [ $($t:tt)* ] ) => { decl_module!(@imp $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name> - for enum $call_type where origin: $origin_type where system = $system { + for enum $call_type where origin: $origin_type, system = $system { $($t)* } + { $( $deposit_event )* } + { $( $on_finalise )* } ); }; - (@call - origin - $mod_type:ident $trait_instance:ident $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] - ) => { - <$mod_type<$trait_instance>>::$fn_name( $origin $(, $param_name )* ) - }; (@call root $mod_type:ident $trait_instance:ident $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] @@ -160,15 +241,113 @@ macro_rules! decl_module { <$mod_type<$trait_instance>>::$fn_name( $( $param_name ),* ) } }; + (@call + $ingore:ident + $mod_type:ident $trait_instance:ident $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] + ) => { + <$mod_type<$trait_instance>>::$fn_name( $origin $(, $param_name )* ) + }; + + // no `deposit_event` function wanted + (@impl_deposit_event + $module:ident<$trait_instance:ident: $trait_name:ident>; + $system:ident; + ) => {}; + + (@impl_deposit_event + $module:ident<$trait_instance:ident: $trait_name:ident>; + $system:ident; + $vis:vis fn deposit_event() = default; + ) => { + impl<$trait_instance: $trait_name> $module<$trait_instance> { + $vis fn deposit_event(event: Event<$trait_instance>) { + <$system::Module<$trait_instance>>::deposit_event( + <$trait_instance as $trait_name>::Event::from(event).into() + ); + } + } + }; + + (@impl_deposit_event + $module:ident<$trait_instance:ident: $trait_name:ident>; + $system:ident; + $vis:vis fn deposit_event($param:ident : $param_ty:ty) { $( $impl:tt )* } + ) => { + impl<$trait_instance: $trait_name> $module<$trait_instance> { + $vis fn deposit_event($param: $param_ty) { + $( $impl )* + } + } + }; + + (@impl_on_finalise + $module:ident<$trait_instance:ident: $trait_name:ident>; + fn on_finalise() { $( $impl:tt )* } + ) => { + impl<$trait_instance: $trait_name> + $crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber> + for $module<$trait_instance> { + fn on_finalise(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } + } + }; + + (@impl_on_finalise + $module:ident<$trait_instance:ident: $trait_name:ident>; + fn on_finalise($param:ident : $param_ty:ty) { $( $impl:tt )* } + ) => { + impl<$trait_instance: $trait_name> + $crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber> + for $module<$trait_instance> { + fn on_finalise($param: $param_ty) { $( $impl )* } + } + }; + + (@impl_on_finalise + $module:ident<$trait_instance:ident: $trait_name:ident>; + ) => { + impl<$trait_instance: $trait_name> + $crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber> + for $module<$trait_instance> {} + }; + + (@impl_function + $module:ident<$trait_instance:ident: $trait_name:ident>; + $origin_ty:ty; + root; + $vis:vis fn $name:ident ( root $(, $param:ident : $param_ty:ty )* ) -> $result:ty { $( $impl:tt )* } + ) => { + impl<$trait_instance: $trait_name> $module<$trait_instance> { + $vis fn $name($( $param: $param_ty ),* ) -> $result { + $( $impl )* + } + } + }; + (@impl_function + $module:ident<$trait_instance:ident: $trait_name:ident>; + $origin_ty:ty; + $ignore:ident; + $vis:vis fn $name:ident ( $origin:ident $(, $param:ident : $param_ty:ty )* ) -> $result:ty { $( $impl:tt )* } + ) => { + impl<$trait_instance: $trait_name> $module<$trait_instance> { + $vis fn $name($origin: $origin_ty $(, $param: $param_ty )* ) -> $result { + $( $impl )* + } + } + }; (@imp $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident> - for enum $call_type:ident where origin: $origin_type:ty where system = $system:ident { - $( - $(#[doc = $doc_attr:tt])* - fn $fn_name:ident($from:ident $( , $param_name:ident : $param:ty)*) -> $result:ty; - )*} + for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { + $( + $(#[doc = $doc_attr:tt])* + $fn_vis:vis fn $fn_name:ident( + $from:ident $( , $param_name:ident : $param:ty)* + ) -> $result:ty { $( $impl:tt )* } + )* + } + { $( $deposit_event:tt )* } + { $( $on_finalise:tt )* } ) => { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] @@ -185,6 +364,29 @@ macro_rules! decl_module { #[cfg(not(feature = "std"))] pub struct $mod_type<$trait_instance: $trait_name>(::core::marker::PhantomData<$trait_instance>); + decl_module! { + @impl_on_finalise + $mod_type<$trait_instance: $trait_name>; + $( $on_finalise )* + } + + decl_module! { + @impl_deposit_event + $mod_type<$trait_instance: $trait_name>; + $system; + $( $deposit_event )* + } + + $( + decl_module! { + @impl_function + $mod_type<$trait_instance: $trait_name>; + $origin_type; + $from; + $fn_vis fn $fn_name ($from $(, $param_name : $param )* ) -> $result { $( $impl )* } + } + )* + #[cfg(feature = "std")] $(#[$attr])* #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] @@ -292,7 +494,11 @@ macro_rules! decl_module { match self { $( $call_type::$fn_name( $( $param_name ),* ) => { - decl_module!(@call $from $mod_type $trait_instance $fn_name _origin $system [ $( $param_name ),* ]) + decl_module!( + @call + $from + $mod_type $trait_instance $fn_name _origin $system [ $( $param_name ),* ] + ) }, )* _ => { panic!("__PhantomItem should never be used.") }, @@ -615,6 +821,7 @@ mod tests { pub trait Trait { type Origin; + type BlockNumber; } pub mod system { @@ -628,11 +835,11 @@ mod tests { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { /// Hi, this is a comment. - fn aux_0(origin) -> Result; - fn aux_1(origin, data: i32) -> Result; - fn aux_2(origin, data: i32, data2: String) -> Result; - fn aux_3() -> Result; - fn aux_4(data: i32) -> Result; + fn aux_0(_origin) -> Result { unreachable!() } + fn aux_1(_origin, _data: i32) -> Result { unreachable!() } + fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() } + fn aux_3() -> Result { unreachable!() } + fn aux_4(_data: i32) -> Result { unreachable!() } } } @@ -654,7 +861,7 @@ mod tests { name: DecodeDifferent::Encode("aux_1"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { - name: DecodeDifferent::Encode("data"), + name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("i32"), } ]), @@ -665,11 +872,11 @@ mod tests { name: DecodeDifferent::Encode("aux_2"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { - name: DecodeDifferent::Encode("data"), + name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("i32"), }, FunctionArgumentMetadata { - name: DecodeDifferent::Encode("data2"), + name: DecodeDifferent::Encode("_data2"), ty: DecodeDifferent::Encode("String"), } ]), @@ -686,7 +893,7 @@ mod tests { name: DecodeDifferent::Encode("aux_4"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { - name: DecodeDifferent::Encode("data"), + name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("i32"), } ]), @@ -696,32 +903,11 @@ mod tests { }, }; - impl<T: Trait> Module<T> { - fn aux_0(_: T::Origin) -> Result { - unreachable!() - } - - fn aux_1(_: T::Origin, _: i32) -> Result { - unreachable!() - } - - fn aux_2(_: T::Origin, _: i32, _: String) -> Result { - unreachable!() - } - - fn aux_3() -> Result { - unreachable!() - } - - fn aux_4(_: i32) -> Result { - unreachable!() - } - } - struct TraitImpl {} impl Trait for TraitImpl { type Origin = u32; + type BlockNumber = u32; } #[test] diff --git a/substrate/srml/support/src/event.rs b/substrate/srml/support/src/event.rs index 8a6c153029fe13bb7307940c4d33eee6fa9414aa..ae7ddea4124eb5bc0ba5ac4c92e183c18e60f32c 100644 --- a/substrate/srml/support/src/event.rs +++ b/substrate/srml/support/src/event.rs @@ -433,6 +433,7 @@ mod tests { mod system { pub trait Trait { type Origin; + type BlockNumber; } decl_module! { @@ -449,6 +450,7 @@ mod tests { mod system_renamed { pub trait Trait { type Origin; + type BlockNumber; } decl_module! { @@ -466,6 +468,7 @@ mod tests { pub trait Trait { type Origin; type Balance; + type BlockNumber; } decl_module! { @@ -488,6 +491,7 @@ mod tests { pub trait Trait { type Origin; type Balance; + type BlockNumber; } decl_module! { @@ -539,29 +543,35 @@ mod tests { impl event_module::Trait for TestRuntime { type Origin = u32; type Balance = u32; + type BlockNumber = u32; } impl event_module2::Trait for TestRuntime { type Origin = u32; type Balance = u32; + type BlockNumber = u32; } impl system::Trait for TestRuntime { type Origin = u32; + type BlockNumber = u32; } impl event_module::Trait for TestRuntime2 { type Origin = u32; type Balance = u32; + type BlockNumber = u32; } impl event_module2::Trait for TestRuntime2 { type Origin = u32; type Balance = u32; + type BlockNumber = u32; } impl system_renamed::Trait for TestRuntime2 { type Origin = u32; + type BlockNumber = u32; } const EXPECTED_METADATA: OuterEventMetadata = OuterEventMetadata { diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index 02747b199ae1a3760b9f9f13bfc4b2819a7010c1..e9cd35afa56781ac2aa44e5750150f70a466df26 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -24,7 +24,8 @@ #[cfg(feature = "std")] extern crate serde; -extern crate sr_std as rstd; +#[doc(hidden)] +pub extern crate sr_std as rstd; extern crate sr_io as runtime_io; #[doc(hidden)] pub extern crate sr_primitives as runtime_primitives; @@ -65,6 +66,7 @@ pub mod inherent; pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap}; pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; +pub use self::metadata::RuntimeMetadata; pub use runtime_io::print; #[macro_export] diff --git a/substrate/srml/support/src/metadata.rs b/substrate/srml/support/src/metadata.rs index a3095851a6158ca658a0e0f9d7be6fbbc8d07b1d..c1c4966442fbb7494ab7c5887920ccbba69be0ac 100644 --- a/substrate/srml/support/src/metadata.rs +++ b/substrate/srml/support/src/metadata.rs @@ -33,14 +33,12 @@ macro_rules! impl_runtime_metadata { $( $rest:tt )* ) => { impl $runtime { - pub fn metadata() -> Vec<u8> { - $crate::codec::Encode::encode( - &$crate::metadata::RuntimeMetadata { - outer_event: Self::outer_event_metadata(), - modules: __runtime_modules_to_metadata!($runtime;; $( $rest )*), - outer_dispatch: Self::outer_dispatch_metadata(), - } - ) + pub fn metadata() -> $crate::metadata::RuntimeMetadata { + $crate::metadata::RuntimeMetadata { + outer_event: Self::outer_event_metadata(), + modules: __runtime_modules_to_metadata!($runtime;; $( $rest )*), + outer_dispatch: Self::outer_dispatch_metadata(), + } } } } @@ -105,12 +103,13 @@ mod tests { StorageFunctionModifier, StorageFunctionType, FunctionMetadata, StorageMetadata, StorageFunctionMetadata, OuterDispatchMetadata, OuterDispatchCall }; - use codec::Decode; + use codec::{Decode, Encode}; mod system { pub trait Trait { type Origin: Into<Option<RawOrigin<Self::AccountId>>> + From<RawOrigin<Self::AccountId>>; type AccountId; + type BlockNumber; } decl_module! { @@ -148,6 +147,7 @@ mod tests { pub trait Trait { type Origin; type Balance; + type BlockNumber; } decl_event!( @@ -160,13 +160,7 @@ mod tests { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn aux_0(origin) -> Result; - } - } - - impl<T: Trait> Module<T> { - fn aux_0(_: T::Origin) -> Result { - unreachable!() + fn aux_0(_origin) -> Result { unreachable!() } } } } @@ -175,6 +169,7 @@ mod tests { pub trait Trait { type Origin; type Balance; + type BlockNumber; } decl_event!( @@ -226,16 +221,19 @@ mod tests { impl event_module::Trait for TestRuntime { type Origin = Origin; type Balance = u32; + type BlockNumber = u32; } impl event_module2::Trait for TestRuntime { type Origin = Origin; type Balance = u32; + type BlockNumber = u32; } impl system::Trait for TestRuntime { type Origin = Origin; type AccountId = u32; + type BlockNumber = u32; } impl_runtime_metadata!( @@ -346,7 +344,7 @@ mod tests { #[test] fn runtime_metadata() { - let metadata_encoded = TestRuntime::metadata(); + let metadata_encoded = TestRuntime::metadata().encode(); let metadata_decoded = RuntimeMetadata::decode(&mut &metadata_encoded[..]); assert_eq!(EXPECTED_METADATA, metadata_decoded.unwrap()); diff --git a/substrate/srml/support/src/storage/generator.rs b/substrate/srml/support/src/storage/generator.rs index 8398819ebe5644b2a014d27d36915a10693afa43..4604c5b3b01bacc0cfcd30cd83a1e8bc74a2732c 100644 --- a/substrate/srml/support/src/storage/generator.rs +++ b/substrate/srml/support/src/storage/generator.rs @@ -119,7 +119,7 @@ pub trait StorageValue<T: codec::Codec> { } /// Mutate this value - fn mutate<F: FnOnce(&mut Self::Query), S: Storage>(f: F, storage: &S); + fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(f: F, storage: &S) -> R; /// Clear the storage value. fn kill<S: Storage>(storage: &S) { @@ -190,7 +190,7 @@ pub trait StorageMap<K: codec::Codec, V: codec::Codec> { } /// Mutate the value under a key. - fn mutate<F: FnOnce(&mut Self::Query), S: Storage>(key: &K, f: F, storage: &S); + fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(key: &K, f: F, storage: &S) -> R; } // TODO: Remove this in favour of `decl_storage` macro. @@ -342,10 +342,10 @@ macro_rules! __storage_items_internal { } /// Mutate this value. - fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(f: F, storage: &S) { + fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(f: F, storage: &S) -> R { let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage); - f(&mut val); + let ret = f(&mut val); __handle_wrap_internal!($wraptype { // raw type case @@ -353,10 +353,12 @@ macro_rules! __storage_items_internal { } { // Option<> type case match val { - Some(val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage), + Some(ref val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage), None => <Self as $crate::storage::generator::StorageValue<$ty>>::kill(storage), } }); + + ret } } }; @@ -379,7 +381,7 @@ macro_rules! __storage_items_internal { } /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &$kty) -> Vec<u8> { + fn key_for(x: &$kty) -> $crate::rstd::vec::Vec<u8> { let mut key = $prefix.to_vec(); $crate::codec::Encode::encode_to(x, &mut key); key @@ -398,10 +400,10 @@ macro_rules! __storage_items_internal { } /// Mutate the value under a key. - fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) { + fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) -> R { let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage); - f(&mut val); + let ret = f(&mut val); __handle_wrap_internal!($wraptype { // raw type case @@ -409,10 +411,12 @@ macro_rules! __storage_items_internal { } { // Option<> type case match val { - Some(val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage), + Some(ref val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage), None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage), } }); + + ret } } }; @@ -441,21 +445,21 @@ macro_rules! __storage_items_internal { /// Get the key used to put the length field. // TODO: concat macro should accept byte literals. - fn len_key() -> Vec<u8> { + fn len_key() -> $crate::rstd::vec::Vec<u8> { let mut key = $prefix.to_vec(); key.extend(b"len"); key } /// Get the storage key used to fetch a value at a given index. - fn key_for(index: u32) -> Vec<u8> { + fn key_for(index: u32) -> $crate::rstd::vec::Vec<u8> { let mut key = $prefix.to_vec(); $crate::codec::Encode::encode_to(&index, &mut key); key } /// Read out all the items. - fn items<S: $crate::GenericStorage>(storage: &S) -> Vec<$ty> { + fn items<S: $crate::GenericStorage>(storage: &S) -> $crate::rstd::vec::Vec<$ty> { (0..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage)) .map(|i| <$name as $crate::storage::generator::StorageList<$ty>>::get(i, storage).expect("all items within length are set; qed")) .collect() @@ -677,7 +681,7 @@ macro_rules! __generate_genesis_config { #[macro_export] macro_rules! decl_storage { ( - trait $storetype:ident for $modulename:ident<$traitinstance:ident: $traittype:ident> as $cratename:ident { + $pub:vis trait $storetype:ident for $modulename:ident<$traitinstance:ident: $traittype:ident> as $cratename:ident { $($t:tt)* } add_extra_genesis { @@ -686,7 +690,7 @@ macro_rules! decl_storage { } ) => { __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - trait $storetype { + $pub trait $storetype { __decl_store_items!($($t)*); } impl<$traitinstance: $traittype> $storetype for $modulename<$traitinstance> { @@ -699,33 +703,12 @@ macro_rules! decl_storage { __decl_genesis_config_items!([$traittype $traitinstance] [] [] [] [$( $(#[$attr])* $extrafield : $extraty $(= $default)* ; )* ] [$call] $($t)*); }; ( - pub trait $storetype:ident for $modulename:ident<$traitinstance:ident: $traittype:ident> as $cratename:ident { + $pub:vis trait $storetype:ident for $modulename:ident<$traitinstance:ident: $traittype:ident> as $cratename:ident { $($t:tt)* } - add_extra_genesis { - $( $(#[$attr:meta])* config($extrafield:ident) : $extraty:ty $(= $default:expr)* ;)* - build($call:expr); - } ) => { __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - pub trait $storetype { - __decl_store_items!($($t)*); - } - impl<$traitinstance: $traittype> $storetype for $modulename<$traitinstance> { - __impl_store_items!($traitinstance $($t)*); - } - impl<$traitinstance: $traittype> $modulename<$traitinstance> { - __impl_store_fns!($traitinstance $($t)*); - } - __decl_genesis_config_items!([$traittype $traitinstance] [] [] [] [$( $(#[$attr])* $extrafield : $extraty $(= $default)* ; )* ] [$call] $($t)*); - }; - ( - trait $storetype:ident for $modulename:ident<$traitinstance:ident: $traittype:ident> as $cratename:ident { - $($t:tt)* - } - ) => { - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - trait $storetype { + $pub trait $storetype { __decl_store_items!($($t)*); } impl<$traitinstance: $traittype> $storetype for $modulename<$traitinstance> { @@ -737,26 +720,8 @@ macro_rules! decl_storage { } __decl_genesis_config_items!([$traittype $traitinstance] [] [] [] [] [|_, _|{}] $($t)*); }; - ( - pub trait $storetype:ident for $modulename:ident<$traitinstance:ident: $traittype:ident> as $cratename:ident { - $($t:tt)* - } - ) => { - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - pub trait $storetype { - __decl_store_items!($($t)*); - } - impl<$traitinstance: $traittype> $storetype for $modulename<$traitinstance> { - __impl_store_items!($traitinstance $($t)*); - } - impl<$traitinstance: $traittype> $modulename<$traitinstance> { - __impl_store_fns!($traitinstance $($t)*); - } - __decl_genesis_config_items!([$traittype $traitinstance] [] [] [] [] [|_, _|{}] $($t)*); - } } -// TODO: when 'vis' is stablized, we could save the lines by half. #[macro_export] #[doc(hidden)] macro_rules! __decl_genesis_config_items { @@ -765,25 +730,13 @@ macro_rules! __decl_genesis_config_items { // - $default // we don't allow any config() or build() on this pattern. ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty; - $($t:tt)* - ) => { - __decl_genesis_config_items!([$traittype $traitinstance] [$($cur)*] [$($nb)*] [$($mapcur)*] [$($extras)*] [$call] $($t)*); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!([$traittype $traitinstance] [$($cur)*] [$($nb)*] [$($mapcur)*] [$($extras)*] [$call] $($t)*); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!([$traittype $traitinstance] [$($cur)*] [$($nb)*] [$($mapcur)*] [$($extras)*] [$call] $($t)*); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!([$traittype $traitinstance] [$($cur)*] [$($nb)*] [$($mapcur)*] [$($extras)*] [$call] $($t)*); @@ -793,23 +746,8 @@ macro_rules! __decl_genesis_config_items { // - pub // - build() // - $default - // so there are 8 cases here. - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) : map $kty:ty => $ty:ty; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) : map $kty:ty => $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) : map $kty:ty => $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -823,36 +761,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) build($build:expr) : map $kty:ty => $ty:ty; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)* $name ($build);] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) build($build:expr) : map $kty:ty => $ty:ty = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)* $name ($build);] - [$($extras)*] - [$call] - $($t)* - ); - }; - - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) : map $kty:ty => $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) : map $kty:ty => $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -866,35 +775,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) : map $kty:ty => $ty:ty = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) build($build:expr) : map $kty:ty => $ty:ty; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)* $name ($build);] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) build($build:expr) : map $kty:ty => $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) build($build:expr) : map $kty:ty => $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -907,395 +788,32 @@ macro_rules! __decl_genesis_config_items { $($t)* ); }; - - // simple values without getters: - // - pub - // - $default - // so there are 4 cases here. - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident : $ty:ty; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident : $ty:ty = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident : $ty:ty; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident : $ty:ty = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - - // simple values with getters: - // - pub - // - (empty) / config() / config(myname) - // - build() - // - $default - // so there are 24 cases here. - // Option<> types - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = Default::default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$getfn.clone());] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = $default.unwrap_or_default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$getfn.clone());] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $myname : $ty = Default::default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$myname.clone()); ] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $myname : $ty = $default.unwrap_or_default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$myname.clone()); ] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - // build - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) build($build:expr) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) build($build:expr) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() build($build:expr) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = Default::default();] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() build($build:expr) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = $default.unwrap_or_default();] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $myname : $ty = Default::default();] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $myname : $ty = $default.unwrap_or_default();] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - - // pub - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)*] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = Default::default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$getfn.clone());] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = $default.unwrap_or_default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$getfn.clone());] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $myname : $ty = Default::default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$myname.clone()); ] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $myname : $ty = $default.unwrap_or_default();] - [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$myname.clone()); ] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - // build ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) build($build:expr) : Option<$ty:ty>; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) build($build:expr) : map $kty:ty => $ty:ty = $default:expr; $($t:tt)* ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) build($build:expr) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)*] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() build($build:expr) : Option<$ty:ty>; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = Default::default();] - [$($nb)* $name ($build);] - [$($mapcur)*] - [$($extras)*] - [$call] - $($t)* - ); - }; - ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() build($build:expr) : Option<$ty:ty> = $default:expr; - $($t:tt)* - ) => { - __decl_genesis_config_items!( - [$traittype $traitinstance] - [$($cur)* $getfn : $ty = $default.unwrap_or_default();] - [$($nb)* $name ($build);] - [$($mapcur)*] + __decl_genesis_config_items!( + [$traittype $traitinstance] + [$($cur)*] + [$($nb)*] + [$($mapcur)* $name ($build);] [$($extras)*] [$call] $($t)* ); }; + + // simple values without getters: + // - pub + // - $default ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : Option<$ty:ty>; + $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( [$traittype $traitinstance] - [$($cur)* $myname : $ty = Default::default();] - [$($nb)* $name ($build);] + [$($cur)*] + [$($nb)*] [$($mapcur)*] [$($extras)*] [$call] @@ -1303,13 +821,13 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : Option<$ty:ty> = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( [$traittype $traitinstance] - [$($cur)* $myname : $ty = $default.unwrap_or_default();] - [$($nb)* $name ($build);] + [$($cur)*] + [$($nb)*] [$($mapcur)*] [$($extras)*] [$call] @@ -1317,10 +835,14 @@ macro_rules! __decl_genesis_config_items { ); }; - - // raw types + // simple values with getters: + // - pub + // - (empty) / config() / config(myname) + // - build() + // - $default + // Option<> types ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) : Option<$ty:ty>; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1334,7 +856,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) : Option<$ty:ty> = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1348,7 +870,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() : Option<$ty:ty>; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1362,12 +884,12 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() : Option<$ty:ty> = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( [$traittype $traitinstance] - [$($cur)* $getfn : $ty = $default;] + [$($cur)* $getfn : $ty = $default.unwrap_or_default();] [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$getfn.clone());] [$($mapcur)*] [$($extras)*] @@ -1376,7 +898,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) : Option<$ty:ty>; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1390,12 +912,12 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) : Option<$ty:ty> = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( [$traittype $traitinstance] - [$($cur)* $myname : $ty = $default;] + [$($cur)* $myname : $ty = $default.unwrap_or_default();] [$($nb)* $name (|config: &GenesisConfig<$traitinstance>| config.$myname.clone()); ] [$($mapcur)*] [$($extras)*] @@ -1405,7 +927,7 @@ macro_rules! __decl_genesis_config_items { }; // build ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) build($build:expr) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) build($build:expr) : Option<$ty:ty>; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1419,7 +941,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) build($build:expr) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) build($build:expr) : Option<$ty:ty> = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1433,7 +955,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() build($build:expr) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() build($build:expr) : Option<$ty:ty>; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1447,12 +969,12 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config() build($build:expr) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() build($build:expr) : Option<$ty:ty> = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( [$traittype $traitinstance] - [$($cur)* $getfn : $ty = $default;] + [$($cur)* $getfn : $ty = $default.unwrap_or_default();] [$($nb)* $name ($build);] [$($mapcur)*] [$($extras)*] @@ -1461,7 +983,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : Option<$ty:ty>; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1475,12 +997,12 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : Option<$ty:ty> = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( [$traittype $traitinstance] - [$($cur)* $myname : $ty = $default;] + [$($cur)* $myname : $ty = $default.unwrap_or_default();] [$($nb)* $name ($build);] [$($mapcur)*] [$($extras)*] @@ -1489,9 +1011,9 @@ macro_rules! __decl_genesis_config_items { ); }; - // pub + // raw types ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1505,7 +1027,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1519,7 +1041,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1533,7 +1055,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1547,7 +1069,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1561,7 +1083,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1576,7 +1098,7 @@ macro_rules! __decl_genesis_config_items { }; // build ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) build($build:expr) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) build($build:expr) : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1590,7 +1112,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) build($build:expr) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) build($build:expr) : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1604,7 +1126,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() build($build:expr) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() build($build:expr) : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1618,7 +1140,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config() build($build:expr) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config() build($build:expr) : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1632,7 +1154,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : $ty:ty; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : $ty:ty; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1646,7 +1168,7 @@ macro_rules! __decl_genesis_config_items { ); }; ([$traittype:ident $traitinstance:ident] [$($cur:tt)*] [$($nb:tt)*] [$($mapcur:tt)*] [$($extras:tt)*] [$call:expr] - $(#[$doc:meta])* pub $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : $ty:ty = $default:expr; + $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) config($myname:ident) build($build:expr) : $ty:ty = $default:expr; $($t:tt)* ) => { __decl_genesis_config_items!( @@ -1676,42 +1198,24 @@ macro_rules! __decl_storage_items { // maps: // - pub // - $default - // so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; // maps with getters: // - pub // - $default - // so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: map $kty => $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; @@ -1719,42 +1223,24 @@ macro_rules! __decl_storage_items { // maps: // - pub // - $default - // so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; // maps: // - pub // - $default - // so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($fn:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: map $kty => $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; @@ -1762,21 +1248,12 @@ macro_rules! __decl_storage_items { // simple values without getters: // - pub // - $default - // so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : Option<$ty:ty>; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : Option<$ty:ty> = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; @@ -1785,42 +1262,24 @@ macro_rules! __decl_storage_items { // - config() // - build() // - $default - // config() and build() can be combined, so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : Option<$ty:ty>; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : Option<$ty:ty>; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : Option<$ty:ty> = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (OPTION_TYPE Option<$ty>) $cratename $name: $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; // simple values without getters: // - pub // - $default - // so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; @@ -1829,21 +1288,12 @@ macro_rules! __decl_storage_items { // - config() // - build() // - $default - // config() and build() can be combined, so there are 4 cases here. - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : $ty:ty; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = Default::default()); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = Default::default()); - __decl_storage_items!($cratename $traittype $traitinstance $($t)*); - }; - ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = $default); + ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($rename:ident)*))* $(build($fn:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { + __decl_storage_item!(($pub) ($traittype as $traitinstance) (RAW_TYPE $ty) $cratename $name: $ty = $default); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; @@ -1855,8 +1305,8 @@ macro_rules! __decl_storage_items { #[doc(hidden)] macro_rules! __decl_storage_item { // generator for maps. - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($wraptype:ident $gettype:ty) $cratename:ident $name:ident : map $kty:ty => $ty:ty = $default:expr) => { - $($vis)* struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>); + (($pub:vis) ($traittype:ident as $traitinstance:ident) ($wraptype:ident $gettype:ty) $cratename:ident $name:ident : map $kty:ty => $ty:ty = $default:expr) => { + $pub struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>); impl<$traitinstance: $traittype> $crate::storage::generator::StorageMap<$kty, $ty> for $name<$traitinstance> { type Query = $gettype; @@ -1867,7 +1317,7 @@ macro_rules! __decl_storage_item { } /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &$kty) -> Vec<u8> { + fn key_for(x: &$kty) -> $crate::rstd::vec::Vec<u8> { let mut key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::prefix().to_vec(); $crate::codec::Encode::encode_to(x, &mut key); key @@ -1900,10 +1350,10 @@ macro_rules! __decl_storage_item { } /// Mutate the value under a key - fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) { + fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) -> R { let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage); - f(&mut val); + let ret = f(&mut val); __handle_wrap_internal!($wraptype { // raw type case @@ -1911,16 +1361,18 @@ macro_rules! __decl_storage_item { } { // Option<> type case match val { - Some(val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage), + Some(ref val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage), None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage), } }); + + ret } } }; // generator for values. - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($wraptype:ident $gettype:ty) $cratename:ident $name:ident : $ty:ty = $default:expr) => { - $($vis)* struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>); + (($pub:vis) ($traittype:ident as $traitinstance:ident) ($wraptype:ident $gettype:ty) $cratename:ident $name:ident : $ty:ty = $default:expr) => { + $pub struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>); impl<$traitinstance: $traittype> $crate::storage::generator::StorageValue<$ty> for $name<$traitinstance> { type Query = $gettype; @@ -1959,10 +1411,10 @@ macro_rules! __decl_storage_item { } /// Mutate the value under a key. - fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(f: F, storage: &S) { + fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(f: F, storage: &S) -> R { let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage); - f(&mut val); + let ret = f(&mut val); __handle_wrap_internal!($wraptype { // raw type case @@ -1970,10 +1422,12 @@ macro_rules! __decl_storage_item { } { // Option<> type case match val { - Some(val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage), + Some(ref val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage), None => <Self as $crate::storage::generator::StorageValue<$ty>>::kill(storage), } }); + + ret } } }; @@ -1985,68 +1439,40 @@ macro_rules! __decl_store_items { // maps: // - pub // - $default - // so there are 4 cases here. - ($(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; - ($(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; // maps: // - pub // - $default - // so there are 4 cases here. - ($(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; - ($(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; // simple values without getters: // - pub // - $default - // so there are 4 cases here. - ($(#[$doc:meta])* $name:ident : $ty:ty; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* pub $name:ident : $ty:ty; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident : $ty:ty; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; - ($(#[$doc:meta])* pub $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; // simple values with getters: // - pub // - $default - // so there are 4 cases here. - ($(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; - ($(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { - __decl_store_item!($name); __decl_store_items!($($t)*); - }; - ($(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { + ($(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { __decl_store_item!($name); __decl_store_items!($($t)*); }; @@ -2067,20 +1493,11 @@ macro_rules! __impl_store_fns { // maps: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) map $kty => $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) map $kty => $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty>; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) map $kty => $ty); __impl_store_fns!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty> = $default:expr; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) map $kty => $ty); __impl_store_fns!($traitinstance $($t)*); }; @@ -2089,37 +1506,21 @@ macro_rules! __impl_store_fns { // maps: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { __impl_store_fns!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_fns!($traitinstance $($t)*); }; // maps: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn ($ty) map $kty => $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn ($ty) map $kty => $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn ($ty) map $kty => $ty); __impl_store_fns!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn ($ty) map $kty => $ty); __impl_store_fns!($traitinstance $($t)*); }; @@ -2128,20 +1529,11 @@ macro_rules! __impl_store_fns { // simple values with getters: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty>; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty> = $default:expr; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty>; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty>; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) $ty); __impl_store_fns!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty> = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty> = $default:expr; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) $ty); __impl_store_fns!($traitinstance $($t)*); }; @@ -2150,37 +1542,21 @@ macro_rules! __impl_store_fns { // simple values without getters: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty; $($t:tt)*) => { - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty; $($t:tt)*) => { __impl_store_fns!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty; $($t:tt)*) => { - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_fns!($traitinstance $($t)*); }; // simple values with getters: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn ($ty) $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn ($ty) $ty); - __impl_store_fns!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn ($ty) $ty); __impl_store_fns!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_fn!($traitinstance $name $getfn ($ty) $ty); __impl_store_fns!($traitinstance $($t)*); }; @@ -2210,20 +1586,11 @@ macro_rules! __impl_store_items { // maps: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; @@ -2231,20 +1598,11 @@ macro_rules! __impl_store_items { // maps: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; @@ -2252,20 +1610,11 @@ macro_rules! __impl_store_items { // simple values without getters: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident : $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; @@ -2273,20 +1622,11 @@ macro_rules! __impl_store_items { // simple values with getters: // - pub // - $default - // so there are 4 cases here. - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { - __impl_store_item!($name $traitinstance); - __impl_store_items!($traitinstance $($t)*); - }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; - ($traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { + ($traitinstance:ident $(#[$doc:meta])* $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty = $default:expr; $($t:tt)*) => { __impl_store_item!($name $traitinstance); __impl_store_items!($traitinstance $($t)*); }; @@ -2325,23 +1665,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident : - map $kty:ty => Option<$ty:ty> $(= $default:expr)*; - $( $t:tt )* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($kty, $ty); - $crate::storage::generator::StorageFunctionModifier::Optional - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident : + $pub:vis $name:ident : map $kty:ty => Option<$ty:ty> $(= $default:expr)*; $($t:tt)* ) => { @@ -2359,23 +1683,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident : - map $kty:ty => $ty:ty $(= $default:expr)*; - $( $t:tt )* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($kty, $ty); - $crate::storage::generator::StorageFunctionModifier::Default - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident : + $pub:vis $name:ident : map $kty:ty => $ty:ty $(= $default:expr)*; $($t:tt)* ) => { @@ -2394,23 +1702,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident get($getfn:ident) $(build($build:expr))* : - map $kty:ty => Option<$ty:ty> $(= $default:expr)*; - $($t:tt)* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($kty, $ty); - $crate::storage::generator::StorageFunctionModifier::Optional - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident get($getfn:ident) $(build($build:expr))* : + $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => Option<$ty:ty> $(= $default:expr)*; $($t:tt)* ) => { @@ -2429,23 +1721,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident get($getfn:ident) $(build($build:expr))* : - map $kty:ty => $ty:ty $(= $default:expr)*; - $($t:tt)* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($kty, $ty); - $crate::storage::generator::StorageFunctionModifier::Default - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident get($getfn:ident) $(build($build:expr))* : + $pub:vis $name:ident get($getfn:ident) $(build($build:expr))* : map $kty:ty => $ty:ty $(= $default:expr)*; $($t:tt)* ) => { @@ -2463,22 +1739,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident : Option<$ty:ty> $(= $default:expr)*; - $($t:tt)* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($ty); - $crate::storage::generator::StorageFunctionModifier::Optional - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident : Option<$ty:ty> $(= $default:expr)*; + $pub:vis $name:ident : Option<$ty:ty> $(= $default:expr)*; $($t:tt)* ) => { __store_functions_to_metadata!( @@ -2494,22 +1755,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident : $ty:ty $(= $default:expr)*; - $($t:tt)* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($ty); - $crate::storage::generator::StorageFunctionModifier::Default - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident : $ty:ty $(= $default:expr)*; + $pub:vis $name:ident : $ty:ty $(= $default:expr)*; $($t:tt)* ) => { __store_functions_to_metadata!( @@ -2527,23 +1773,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : - Option<$ty:ty> $(= $default:expr)*; - $($t:tt)* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($ty); - $crate::storage::generator::StorageFunctionModifier::Optional - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : + $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : Option<$ty:ty> $(= $default:expr)*; $($t:tt)* ) => { @@ -2561,23 +1791,7 @@ macro_rules! __store_functions_to_metadata { ( $( $metadata:expr ),*; $(#[doc = $doc_attr:tt])* - $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : - $ty:ty $(= $default:expr)*; - $($t:tt)* - ) => { - __store_functions_to_metadata!( - $( $metadata, )* - __store_function_to_metadata!( - $( $doc_attr ),*; $name; __store_type_to_metadata!($ty); - $crate::storage::generator::StorageFunctionModifier::Default - ); - $( $t )* - ) - }; - ( - $( $metadata:expr ),*; - $(#[doc = $doc_attr:tt])* - pub $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : + $pub:vis $name:ident get($getfn:ident) $(config($($myname:ident)*))* $(build($build:expr))* : $ty:ty $(= $default:expr)*; $($t:tt)* ) => { @@ -2702,7 +1916,8 @@ mod tests { } pub trait Trait { - type Origin: codec::Encode + codec::Decode + ::std::default::Default; + type Origin: codec::Encode + codec::Decode + ::std::default::Default; + type BlockNumber; } decl_module! { @@ -2754,6 +1969,7 @@ mod tests { impl Trait for TraitImpl { type Origin = u32; + type BlockNumber = u32; } const EXPECTED_METADATA: StorageMetadata = StorageMetadata { @@ -2932,7 +2148,8 @@ mod tests { #[allow(dead_code)] mod test2 { pub trait Trait { - type Origin; + type Origin; + type BlockNumber; } decl_module! { @@ -2959,5 +2176,6 @@ mod test2 { impl Trait for TraitImpl { type Origin = u32; + type BlockNumber = u32; } } diff --git a/substrate/srml/support/src/storage/mod.rs b/substrate/srml/support/src/storage/mod.rs index 637ecc688abc05399571f8c0564b16d069450ce3..6e1302718abd1bf574f107c4f8b755f159a33186 100644 --- a/substrate/srml/support/src/storage/mod.rs +++ b/substrate/srml/support/src/storage/mod.rs @@ -169,7 +169,7 @@ pub trait StorageValue<T: Codec> { fn put<Arg: Borrow<T>>(val: Arg); /// Mutate the value - fn mutate<F: FnOnce(&mut Self::Query)>(f: F); + fn mutate<R, F: FnOnce(&mut Self::Query) -> R>(f: F) -> R; /// Clear the storage value. fn kill(); @@ -193,7 +193,7 @@ impl<T: Codec, U> StorageValue<T> for U where U: generator::StorageValue<T> { fn put<Arg: Borrow<T>>(val: Arg) { U::put(val.borrow(), &RuntimeStorage) } - fn mutate<F: FnOnce(&mut Self::Query)>(f: F) { + fn mutate<R, F: FnOnce(&mut Self::Query) -> R>(f: F) -> R { U::mutate(f, &RuntimeStorage) } fn kill() { @@ -296,7 +296,7 @@ pub trait StorageMap<K: Codec, V: Codec> { fn remove<KeyArg: Borrow<K>>(key: KeyArg); /// Mutate the value under a key. - fn mutate<KeyArg: Borrow<K>, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F); + fn mutate<KeyArg: Borrow<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R; /// Take the value under a key. fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query; @@ -329,7 +329,7 @@ impl<K: Codec, V: Codec, U> StorageMap<K, V> for U where U: generator::StorageMa U::remove(key.borrow(), &RuntimeStorage) } - fn mutate<KeyArg: Borrow<K>, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F) { + fn mutate<KeyArg: Borrow<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R { U::mutate(key.borrow(), f, &RuntimeStorage) } diff --git a/substrate/srml/system/src/lib.rs b/substrate/srml/system/src/lib.rs index ad8957c3491d947f211cc8de41bda21bd7cb14eb..c34f11bf8dbd78835753a4e6a30711829637b2fa 100644 --- a/substrate/srml/system/src/lib.rs +++ b/substrate/srml/system/src/lib.rs @@ -86,7 +86,16 @@ pub trait Trait: Eq + Clone { pub type DigestItemOf<T> = <<T as Trait>::Digest as traits::Digest>::Item; decl_module! { - pub struct Module<T: Trait> for enum Call where origin: T::Origin {} + pub struct Module<T: Trait> for enum Call where origin: T::Origin { + /// Deposits an event onto this block's event record. + pub fn deposit_event(event: T::Event) { + let extrinsic_index = Self::extrinsic_index(); + let phase = extrinsic_index.map_or(Phase::Finalization, |c| Phase::ApplyExtrinsic(c)); + let mut events = Self::events(); + events.push(EventRecord { phase, event }); + <Events<T>>::put(events); + } + } } /// A phase of a block's execution. @@ -301,15 +310,6 @@ impl<T: Trait> Module<T> { <Digest<T>>::put(l); } - /// Deposits an event onto this block's event record. - pub fn deposit_event(event: T::Event) { - let extrinsic_index = Self::extrinsic_index(); - let phase = extrinsic_index.map_or(Phase::Finalization, |c| Phase::ApplyExtrinsic(c)); - let mut events = Self::events(); - events.push(EventRecord { phase, event }); - <Events<T>>::put(events); - } - /// Calculate the current block's random seed. fn calculate_random() -> T::Hash { assert!(Self::block_number() > Zero::zero(), "Block number may never be zero"); diff --git a/substrate/srml/timestamp/src/lib.rs b/substrate/srml/timestamp/src/lib.rs index c13972c7da808c3c10e7e2b4639db55f502a0856..1779807af137becd16fbbc0cd54010e30c2cebdc 100644 --- a/substrate/srml/timestamp/src/lib.rs +++ b/substrate/srml/timestamp/src/lib.rs @@ -59,7 +59,7 @@ use runtime_support::{StorageValue, Parameter}; use runtime_support::dispatch::Result; use runtime_primitives::RuntimeString; use runtime_primitives::traits::{ - As, OnFinalise, SimpleArithmetic, Zero, ProvideInherent, Block as BlockT, Extrinsic + As, SimpleArithmetic, Zero, ProvideInherent, Block as BlockT, Extrinsic }; use system::ensure_inherent; use rstd::{result, ops::{Mul, Div}, vec::Vec}; @@ -74,7 +74,36 @@ pub trait Trait: consensus::Trait + system::Trait { decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { - fn set(origin, now: <T::Moment as HasCompact>::Type) -> Result; + /// Set the current time. + /// + /// Extrinsic with this call should be placed at the specific position in the each block + /// (specified by the Trait::TIMESTAMP_SET_POSITION) typically at the start of the each block. + /// This call should be invoked exactly once per block. It will panic at the finalization phase, + /// if this call hasn't been invoked by that time. + /// + /// The timestamp should be greater than the previous one by the amount specified by `block_period`. + fn set(origin, now: <T::Moment as HasCompact>::Type) -> Result { + ensure_inherent(origin)?; + let now = now.into(); + + assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block"); + assert!( + <system::Module<T>>::extrinsic_index() == Some(T::TIMESTAMP_SET_POSITION), + "Timestamp extrinsic must be at position {} in the block", + T::TIMESTAMP_SET_POSITION + ); + assert!( + Self::now().is_zero() || now >= Self::now() + Self::block_period(), + "Timestamp must increment by at least <BlockPeriod> between sequential blocks" + ); + <Self as Store>::Now::put(now); + <Self as Store>::DidUpdate::put(true); + Ok(()) + } + + fn on_finalise() { + assert!(<Self as Store>::DidUpdate::take(), "Timestamp must be updated once in the block"); + } } } @@ -100,33 +129,6 @@ impl<T: Trait> Module<T> { Self::now() } - /// Set the current time. - /// - /// Extrinsic with this call should be placed at the specific position in the each block - /// (specified by the Trait::TIMESTAMP_SET_POSITION) typically at the start of the each block. - /// This call should be invoked exactly once per block. It will panic at the finalization phase, - /// if this call hasn't been invoked by that time. - /// - /// The timestamp should be greater than the previous one by the amount specified by `block_period`. - fn set(origin: T::Origin, now: <T::Moment as HasCompact>::Type) -> Result { - ensure_inherent(origin)?; - let now = now.into(); - - assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block"); - assert!( - <system::Module<T>>::extrinsic_index() == Some(T::TIMESTAMP_SET_POSITION), - "Timestamp extrinsic must be at position {} in the block", - T::TIMESTAMP_SET_POSITION - ); - assert!( - Self::now().is_zero() || now >= Self::now() + Self::block_period(), - "Timestamp must increment by at least <BlockPeriod> between sequential blocks" - ); - <Self as Store>::Now::put(now); - <Self as Store>::DidUpdate::put(true); - Ok(()) - } - /// Set the timestamp to something in particular. Only used for tests. #[cfg(feature = "std")] pub fn set_timestamp(now: T::Moment) { @@ -171,12 +173,6 @@ impl<T: Trait> ProvideInherent for Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(_n: T::BlockNumber) { - assert!(<Self as Store>::DidUpdate::take(), "Timestamp must be updated once in the block"); - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/substrate/srml/treasury/src/lib.rs b/substrate/srml/treasury/src/lib.rs index febe5fed891d5c6ecea25c85b4bf02c8fb4953ca..7d314674bc3925c743c9f13f37164e138ae0f3f5 100644 --- a/substrate/srml/treasury/src/lib.rs +++ b/substrate/srml/treasury/src/lib.rs @@ -45,7 +45,7 @@ extern crate srml_balances as balances; use rstd::prelude::*; use runtime_support::{StorageValue, StorageMap}; use runtime_support::dispatch::Result; -use runtime_primitives::{Permill, traits::{OnFinalise, Zero, EnsureOrigin}}; +use runtime_primitives::{Permill, traits::{Zero, EnsureOrigin}}; use codec::{HasCompact, Compact}; use balances::{OnDilution, address::Address}; use system::ensure_signed; @@ -73,23 +73,87 @@ type ProposalIndex = 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 { - // Put forward a suggestion for spending. A deposit proportional to the value - // is reserved and slashed if the proposal is rejected. It is returned once the - // proposal is awarded. - fn propose_spend(origin, value: <T::Balance as HasCompact>::Type, beneficiary: Address<T::AccountId, T::AccountIndex>) -> Result; + fn deposit_event() = default; + /// Put forward a suggestion for spending. A deposit proportional to the value + /// is reserved and slashed if the proposal is rejected. It is returned once the + /// proposal is awarded. + fn propose_spend( + origin, + value: <T::Balance as HasCompact>::Type, + beneficiary: Address<T::AccountId, T::AccountIndex> + ) -> Result { + let proposer = ensure_signed(origin)?; + let beneficiary = <balances::Module<T>>::lookup(beneficiary)?; + let value = value.into(); + + let bond = Self::calculate_bond(value); + <balances::Module<T>>::reserve(&proposer, bond) + .map_err(|_| "Proposer's balance too low")?; + + let c = Self::proposal_count(); + <ProposalCount<T>>::put(c + 1); + <Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond }); + + Self::deposit_event(RawEvent::Proposed(c)); + + Ok(()) + } + + /// Set the balance of funds available to spend. + fn set_pot(new_pot: <T::Balance as HasCompact>::Type) -> Result { + // Put the new value into storage. + <Pot<T>>::put(new_pot.into()); + + // All good. + Ok(()) + } + + /// (Re-)configure this module. + fn configure( + proposal_bond: Permill, + proposal_bond_minimum: <T::Balance as HasCompact>::Type, + spend_period: <T::BlockNumber as HasCompact>::Type, + burn: Permill + ) -> Result { + <ProposalBond<T>>::put(proposal_bond); + <ProposalBondMinimum<T>>::put(proposal_bond_minimum.into()); + <SpendPeriod<T>>::put(spend_period.into()); + <Burn<T>>::put(burn); + Ok(()) + } + + /// Reject a proposed spend. The original deposit will be slashed. + fn reject_proposal(origin, proposal_id: Compact<ProposalIndex>) -> Result { + T::RejectOrigin::ensure_origin(origin)?; + let proposal_id: ProposalIndex = proposal_id.into(); + + let proposal = <Proposals<T>>::take(proposal_id).ok_or("No proposal at that index")?; + + let value = proposal.bond; + let _ = <balances::Module<T>>::slash_reserved(&proposal.proposer, value); + + Ok(()) + } - // Set the balance of funds available to spend. - fn set_pot(new_pot: <T::Balance as HasCompact>::Type) -> Result; + /// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary + /// and the original deposit will be returned. + fn approve_proposal(origin, proposal_id: Compact<ProposalIndex>) -> Result { + T::ApproveOrigin::ensure_origin(origin)?; + let proposal_id = proposal_id.into(); - // (Re-)configure this module. - fn configure(proposal_bond: Permill, proposal_bond_minimum: <T::Balance as HasCompact>::Type, spend_period: <T::BlockNumber as HasCompact>::Type, burn: Permill) -> Result; + ensure!(<Proposals<T>>::exists(proposal_id), "No proposal at that index"); - // Reject a proposed spend. The original deposit will be slashed. - fn reject_proposal(origin, proposal_id: Compact<ProposalIndex>) -> Result; + <Approvals<T>>::mutate(|v| v.push(proposal_id)); - // Approve a proposal. At a later time, the proposal will be allocated to the beneficiary - // and the original deposit will be returned. - fn approve_proposal(origin, proposal_id: Compact<ProposalIndex>) -> Result; + Ok(()) + } + + fn on_finalise(n: T::BlockNumber) { + // Check to see if we should spend some funds! + if (n % Self::spend_period()).is_zero() { + Self::spend_funds(); + } + } } } @@ -153,74 +217,7 @@ decl_event!( ); 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()); - } - - // Implement Calls and add public immutables and private mutables. - - fn propose_spend(origin: T::Origin, value: <T::Balance as HasCompact>::Type, beneficiary: Address<T::AccountId, T::AccountIndex>) -> Result { - let proposer = ensure_signed(origin)?; - let beneficiary = <balances::Module<T>>::lookup(beneficiary)?; - let value = value.into(); - - let bond = Self::calculate_bond(value); - <balances::Module<T>>::reserve(&proposer, bond) - .map_err(|_| "Proposer's balance too low")?; - - let c = Self::proposal_count(); - <ProposalCount<T>>::put(c + 1); - <Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond }); - - Self::deposit_event(RawEvent::Proposed(c)); - - Ok(()) - } - - fn reject_proposal(origin: T::Origin, proposal_id: Compact<ProposalIndex>) -> Result { - T::RejectOrigin::ensure_origin(origin)?; - let proposal_id: ProposalIndex = proposal_id.into(); - - let proposal = <Proposals<T>>::take(proposal_id).ok_or("No proposal at that index")?; - - let value = proposal.bond; - let _ = <balances::Module<T>>::slash_reserved(&proposal.proposer, value); - - Ok(()) - } - - fn approve_proposal(origin: T::Origin, proposal_id: Compact<ProposalIndex>) -> Result { - T::ApproveOrigin::ensure_origin(origin)?; - let proposal_id = proposal_id.into(); - - ensure!(<Proposals<T>>::exists(proposal_id), "No proposal at that index"); - - <Approvals<T>>::mutate(|v| v.push(proposal_id)); - - Ok(()) - } - - fn set_pot(new_pot: <T::Balance as HasCompact>::Type) -> Result { - // Put the new value into storage. - <Pot<T>>::put(new_pot.into()); - - // All good. - Ok(()) - } - - fn configure( - proposal_bond: Permill, - proposal_bond_minimum: <T::Balance as HasCompact>::Type, - spend_period: <T::BlockNumber as HasCompact>::Type, - burn: Permill - ) -> Result { - <ProposalBond<T>>::put(proposal_bond); - <ProposalBondMinimum<T>>::put(proposal_bond_minimum.into()); - <SpendPeriod<T>>::put(spend_period.into()); - <Burn<T>>::put(burn); - Ok(()) - } + // Add public immutables and private mutables. /// The needed bond for a proposal whose spend is `value`. fn calculate_bond(value: T::Balance) -> T::Balance { @@ -284,15 +281,6 @@ impl<T: Trait> OnDilution<T::Balance> for Module<T> { } } -impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { - fn on_finalise(n: T::BlockNumber) { - // Check to see if we should spend some funds! - if (n % Self::spend_period()).is_zero() { - Self::spend_funds(); - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -300,7 +288,7 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; use runtime_primitives::BuildStorage; - use runtime_primitives::traits::{BlakeTwo256}; + use runtime_primitives::traits::{BlakeTwo256, OnFinalise}; use runtime_primitives::testing::{Digest, DigestItem, Header}; impl_outer_origin! { diff --git a/substrate/srml/upgrade-key/Cargo.toml b/substrate/srml/upgrade-key/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..980a7240a90aa41ba30961c33e03be6179b3ebf0 --- /dev/null +++ b/substrate/srml/upgrade-key/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "srml-upgrade-key" +version = "0.1.0" +authors = ["Parity Technologies <admin@parity.io>"] + +[dependencies] +hex-literal = "0.1.0" +serde = { version = "1.0", default-features = false } +serde_derive = { version = "1.0", optional = true } +parity-codec = { version = "2.1", default-features = false } +parity-codec-derive = { version = "2.1", default-features = false } +substrate-primitives = { path = "../../core/primitives", default-features = false } +sr-std = { path = "../../core/sr-std", default-features = false } +sr-io = { path = "../../core/sr-io", default-features = false } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } +srml-support = { path = "../support", default-features = false } +srml-system = { path = "../system", default-features = false } +srml-consensus = { path = "../consensus", default-features = false } + +[features] +default = ["std"] +std = [ + "serde/std", + "serde_derive", + "parity-codec/std", + "parity-codec-derive/std", + "sr-std/std", + "sr-io/std", + "sr-primitives/std", + "substrate-primitives/std", + "srml-support/std", + "srml-system/std", + "srml-consensus/std", +] diff --git a/substrate/srml/upgrade-key/src/lib.rs b/substrate/srml/upgrade-key/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..28433d8fbd5db4d4955f30f3365042eda1e76d7e --- /dev/null +++ b/substrate/srml/upgrade-key/src/lib.rs @@ -0,0 +1,90 @@ +// 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/>. + +//! The Example: A simple example of a runtime module demonstrating +//! concepts, APIs and structures common to most runtime modules. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate sr_std; +#[cfg(test)] +extern crate sr_io; +#[cfg(test)] +extern crate substrate_primitives; +extern crate sr_primitives; +#[cfg(feature = "std")] +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate parity_codec_derive; +extern crate parity_codec as codec; +#[macro_use] +extern crate srml_support as support; +extern crate srml_system as system; +extern crate srml_consensus as consensus; + +use sr_std::prelude::*; +use support::{StorageValue, dispatch::Result}; +use system::ensure_signed; + +pub trait Trait: consensus::Trait + system::Trait { + /// The overarching event type. + type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>; +} + +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; + fn upgrade(origin, new: Vec<u8>) -> Result { + // This is a public call, so we ensure that the origin is some signed account. + let _sender = ensure_signed(origin)?; + ensure!(_sender == Self::key(), "only the current upgrade key can use the upgrade_key module"); + + <consensus::Module<T>>::set_code(new)?; + Self::deposit_event(RawEvent::Upgraded); + + Ok(()) + } + + fn set_key(origin, new: T::AccountId) -> Result { + // This is a public call, so we ensure that the origin is some signed account. + let _sender = ensure_signed(origin)?; + ensure!(_sender == Self::key(), "only the current upgrade key can use the upgrade_key module"); + + Self::deposit_event(RawEvent::KeyChanged(Self::key())); + <Key<T>>::put(new); + + Ok(()) + } + } +} + +/// An event in this module. +decl_event!( + pub enum Event<T> where AccountId = <T as system::Trait>::AccountId { + /// An upgrade just happened. + Upgraded, + /// An upgrade just happened; old key is supplied as an argument. + KeyChanged(AccountId), + } +); + +decl_storage! { + trait Store for Module<T: Trait> as UpgradeKey { + Key get(key) config(): T::AccountId; + } +}