From 53bf81e57cdcae34f50bb9359813053e9498b1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 22 Jan 2019 17:52:08 +0100 Subject: [PATCH] Rewrite Inherent data (#1488) * Implement new inherent data * Fixes compilation on wasm * Fixes after rebase * Switch back to generate inherent stuff by macro * Update after rebase * Apply suggestions from code review Co-Authored-By: bkchr * Fix compilation after rebase * Address grumbles * Remove `InherentDataProviders` from `Client` * Update wasm files after rebase * Address grumbles * Fixes compilation after latest merge * Last fix --- Cargo.lock | 108 ++-- Cargo.toml | 1 + core/basic-authorship/Cargo.toml | 13 +- core/basic-authorship/src/basic_authorship.rs | 71 +-- core/basic-authorship/src/lib.rs | 2 +- core/client/Cargo.toml | 4 +- core/client/src/block_builder/api.rs | 7 +- .../client/src/block_builder/block_builder.rs | 9 +- core/client/src/client.rs | 19 +- core/consensus/aura/Cargo.toml | 3 +- core/consensus/aura/src/lib.rs | 294 ++++++--- core/consensus/aura/src/slots.rs | 42 +- core/consensus/common/Cargo.toml | 1 + core/consensus/common/src/error.rs | 6 + core/consensus/common/src/lib.rs | 12 +- core/inherents/Cargo.toml | 21 + core/inherents/src/lib.rs | 575 ++++++++++++++++++ core/network/src/test/mod.rs | 3 +- core/service/src/chain_ops.rs | 23 +- core/service/src/components.rs | 4 +- core/service/src/error.rs | 2 + core/service/src/lib.rs | 15 +- core/service/test/src/lib.rs | 2 +- core/sr-primitives/Cargo.toml | 2 - core/sr-primitives/src/lib.rs | 51 -- core/sr-primitives/src/traits.rs | 20 - core/test-client/src/block_builder_ext.rs | 9 +- core/test-runtime/Cargo.toml | 2 + core/test-runtime/src/lib.rs | 12 +- core/test-runtime/wasm/Cargo.lock | 44 +- .../substrate_test_runtime.compact.wasm | Bin 47531 -> 60251 bytes core/trie/src/node_header.rs | 5 +- node/cli/Cargo.toml | 1 + node/cli/src/chain_spec.rs | 2 +- node/cli/src/lib.rs | 1 + node/cli/src/service.rs | 42 +- node/primitives/src/lib.rs | 2 - node/runtime/src/lib.rs | 61 +- node/runtime/wasm/Cargo.lock | 81 +-- .../release/node_runtime.compact.wasm | Bin 829083 -> 837718 bytes srml/aura/Cargo.toml | 2 + srml/aura/src/lib.rs | 128 +++- srml/aura/src/mock.rs | 3 - srml/consensus/Cargo.toml | 2 + srml/consensus/src/lib.rs | 76 +-- srml/consensus/src/mock.rs | 1 - srml/consensus/src/tests.rs | 20 +- srml/session/src/lib.rs | 3 - srml/staking/src/mock.rs | 2 - srml/support/Cargo.toml | 2 + srml/support/src/inherent.rs | 90 +-- srml/support/src/lib.rs | 1 + srml/support/src/runtime.rs | 123 ++-- srml/timestamp/Cargo.toml | 4 + srml/timestamp/src/lib.rs | 143 ++++- 55 files changed, 1512 insertions(+), 660 deletions(-) create mode 100644 core/inherents/Cargo.toml create mode 100644 core/inherents/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index febe287964e09..6dc6440056f8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -843,7 +843,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1933,6 +1933,7 @@ dependencies = [ "substrate-client 0.1.0", "substrate-consensus-aura 0.1.0", "substrate-finality-grandpa 0.1.0", + "substrate-inherents 0.1.0", "substrate-keystore 0.1.0", "substrate-network 0.1.0", "substrate-primitives 0.1.0", @@ -1977,7 +1978,7 @@ name = "node-primitives" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1995,7 +1996,7 @@ dependencies = [ "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 0.1.0", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2165,12 +2166,12 @@ dependencies = [ [[package]] name = "parity-codec-derive" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2637,7 +2638,7 @@ dependencies = [ "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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2967,7 +2968,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3002,7 +3003,7 @@ version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -3015,7 +3016,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3032,7 +3033,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3043,6 +3044,7 @@ dependencies = [ "srml-support 0.1.0", "srml-system 0.1.0", "srml-timestamp 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -3052,7 +3054,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3070,13 +3072,14 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (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-support 0.1.0", "srml-system 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -3087,7 +3090,7 @@ dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3108,7 +3111,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3127,7 +3130,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3145,7 +3148,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3162,7 +3165,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3180,7 +3183,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3199,7 +3202,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ref_thread_local 0.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.84 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3217,7 +3220,7 @@ name = "srml-metadata" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", @@ -3230,7 +3233,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3249,7 +3252,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3271,7 +3274,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3290,7 +3293,7 @@ dependencies = [ "mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3299,6 +3302,7 @@ dependencies = [ "sr-std 0.1.0", "srml-metadata 0.1.0", "srml-support-procedural 0.1.0", + "substrate-inherents 0.1.0", ] [[package]] @@ -3337,7 +3341,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3353,6 +3357,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3360,6 +3365,7 @@ dependencies = [ "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -3369,7 +3375,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3386,7 +3392,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -3520,6 +3526,7 @@ dependencies = [ "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-common 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", "substrate-transaction-pool 0.1.0", ] @@ -3577,6 +3584,7 @@ dependencies = [ "sr-version 0.1.0", "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", @@ -3596,7 +3604,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", @@ -3622,12 +3630,14 @@ dependencies = [ "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-version 0.1.0", + "srml-aura 0.1.0", "srml-consensus 0.1.0", "srml-support 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-network 0.1.0", "substrate-primitives 0.1.0", @@ -3657,10 +3667,11 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", "substrate-test-client 0.1.0", "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3675,7 +3686,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rhododendron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3727,7 +3738,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -3747,13 +3758,24 @@ name = "substrate-finality-grandpa-primitives" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "substrate-client 0.1.0", "substrate-primitives 0.1.0", ] +[[package]] +name = "substrate-inherents" +version = "0.1.0" +dependencies = [ + "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 0.1.0", + "sr-std 0.1.0", +] + [[package]] name = "substrate-keyring" version = "0.1.0" @@ -3790,7 +3812,7 @@ dependencies = [ "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3840,7 +3862,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3961,7 +3983,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 0.1.0", ] @@ -4018,7 +4040,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -4029,6 +4051,7 @@ dependencies = [ "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-executor 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", ] @@ -4112,16 +4135,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.15.24" @@ -5105,7 +5118,7 @@ dependencies = [ "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b6a1290fe78aa6bbb5f3338ecede3062687a98b9e40cd1dbcaa47261d44097" -"checksum parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa42c2cb493b60b12c75b26e8c94cb734af4df4d7f2cc229dc04c1953dac189" +"checksum parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2632f530f37c8b939c7c194636a82ecbe41ab115e74e88f947ad41e483bbf19" "checksum parity-crypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8adf489acb31f1922db0ce43803b6f48a425241a8473611be3cc625a8e4a4c47" "checksum parity-multiaddr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a8e5d637787fe097ec1bfca2aa3eb687396518003df991c6c7216d86682d5ff" "checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076" @@ -5210,7 +5223,6 @@ dependencies = [ "checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "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.24 (registry+https://github.com/rust-lang/crates.io-index)" = "734ecc29cd36e8123850d9bf21dfd62ef8300aaa8f879aabaa899721808be37c" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" diff --git a/Cargo.toml b/Cargo.toml index d67f32ed3c4fe..5d38f53648f84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ members = [ "core/keystore", "core/transaction-pool", "core/transaction-pool/graph", + "core/inherents", "srml/support", "srml/support/procedural", "srml/support/procedural/tools", diff --git a/core/basic-authorship/Cargo.toml b/core/basic-authorship/Cargo.toml index 6a5ef1087dab0..0c09c84e78cba 100644 --- a/core/basic-authorship/Cargo.toml +++ b/core/basic-authorship/Cargo.toml @@ -6,9 +6,10 @@ authors = ["Parity Technologies "] [dependencies] log = "0.4" parity-codec = "2.2" -sr-primitives = { path = "../../core/sr-primitives" } -substrate-client = { path = "../../core/client" } -substrate-consensus-aura-primitives = { path = "../../core/consensus/aura/primitives" } -substrate-consensus-common = { path = "../../core/consensus/common" } -substrate-primitives = { path = "../../core/primitives" } -substrate-transaction-pool = { path = "../../core/transaction-pool" } +sr-primitives = { path = "../sr-primitives" } +substrate-client = { path = "../client" } +substrate-consensus-aura-primitives = { path = "../consensus/aura/primitives" } +substrate-consensus-common = { path = "../consensus/common" } +substrate-primitives = { path = "../primitives" } +substrate-inherents = { path = "../inherents" } +substrate-transaction-pool = { path = "../transaction-pool" } diff --git a/core/basic-authorship/src/basic_authorship.rs b/core/basic-authorship/src/basic_authorship.rs index d3b6421e6ab2c..a666d48ba4b63 100644 --- a/core/basic-authorship/src/basic_authorship.rs +++ b/core/basic-authorship/src/basic_authorship.rs @@ -18,9 +18,7 @@ // FIXME: move this into substrate-consensus-common - https://github.com/paritytech/substrate/issues/1021 -use std::sync::Arc; -use std::time; -use std; +use std::{sync::Arc, self}; use client::{ self, error, Client as SubstrateClient, CallExecutor, @@ -29,13 +27,12 @@ use client::{ use codec::{Decode, Encode}; use consensus_common::{self, evaluation}; use primitives::{H256, Blake2Hasher}; -use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, ProvideRuntimeApi, AuthorityIdFor}; +use runtime_primitives::traits::{ + Block as BlockT, Hash as HashT, Header as HeaderT, ProvideRuntimeApi, AuthorityIdFor +}; use runtime_primitives::generic::BlockId; -use runtime_primitives::BasicInherentData; use transaction_pool::txpool::{self, Pool as TransactionPool}; -use aura_primitives::AuraConsensusData; - -type Timestamp = u64; +use inherents::InherentData; // block size limit. const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024; @@ -59,20 +56,20 @@ pub trait AuthoringApi: Send + Sync + ProvideRuntimeApi where fn build_block) -> ()>( &self, at: &BlockId, - inherent_data: BasicInherentData, + inherent_data: InherentData, build_ctx: F, ) -> Result; } impl<'a, B, E, Block, RA> BlockBuilder - for client::block_builder::BlockBuilder<'a, Block, BasicInherentData, SubstrateClient> + for client::block_builder::BlockBuilder<'a, Block, SubstrateClient> where B: client::backend::Backend + 'static, E: CallExecutor + Send + Sync + Clone + 'static, Block: BlockT, RA: Send + Sync + 'static, SubstrateClient : ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: BlockBuilderApi, + as ProvideRuntimeApi>::Api: BlockBuilderApi, { fn push_extrinsic(&mut self, extrinsic: ::Extrinsic) -> Result<(), error::Error> { client::block_builder::BlockBuilder::push(self, extrinsic).map_err(Into::into) @@ -85,7 +82,7 @@ impl AuthoringApi for SubstrateClient where Block: BlockT, RA: Send + Sync + 'static, SubstrateClient : ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: BlockBuilderApi, + as ProvideRuntimeApi>::Api: BlockBuilderApi, { type Block = Block; type Error = client::error::Error; @@ -93,13 +90,13 @@ impl AuthoringApi for SubstrateClient where fn build_block) -> ()>( &self, at: &BlockId, - inherent_data: BasicInherentData, + inherent_data: InherentData, mut build_ctx: F, ) -> Result { let mut block_builder = self.new_block_at(at)?; let runtime_api = self.runtime_api(); - if runtime_api.has_api::>(at)? { + if runtime_api.has_api::>(at)? { runtime_api.inherent_extrinsics(at, inherent_data)? .into_iter().try_for_each(|i| block_builder.push(i))?; } @@ -118,12 +115,12 @@ pub struct ProposerFactory where A: txpool::ChainApi { pub transaction_pool: Arc>, } -impl consensus_common::Environment<::Block, ConsensusData> for ProposerFactory where +impl consensus_common::Environment<::Block> for ProposerFactory where C: AuthoringApi, - ::Api: BlockBuilderApi<::Block, BasicInherentData>, + ::Api: BlockBuilderApi<::Block>, A: txpool::ChainApi::Block>, client::error::Error: From<::Error>, - Proposer<::Block, C, A>: consensus_common::Proposer<::Block, ConsensusData>, + Proposer<::Block, C, A>: consensus_common::Proposer<::Block>, { type Proposer = Proposer<::Block, C, A>; type Error = error::Error; @@ -151,10 +148,6 @@ impl consensus_common::Environment<::Blo } } -struct ConsensusData { - timestamp: Option, -} - /// The proposer logic. pub struct Proposer { client: Arc, @@ -164,53 +157,35 @@ pub struct Proposer { transaction_pool: Arc>, } -impl consensus_common::Proposer<::Block, AuraConsensusData> for Proposer where +impl consensus_common::Proposer<::Block> for Proposer where Block: BlockT, C: AuthoringApi, - ::Api: BlockBuilderApi, + ::Api: BlockBuilderApi, A: txpool::ChainApi, client::error::Error: From<::Error> { type Create = Result<::Block, error::Error>; type Error = error::Error; - fn propose(&self, consensus_data: AuraConsensusData) + fn propose(&self, inherent_data: InherentData) -> Result<::Block, error::Error> { - self.propose_with(ConsensusData { timestamp: Some(consensus_data.timestamp) }) - } -} - -impl consensus_common::Proposer<::Block, ()> for Proposer where - Block: BlockT, - C: AuthoringApi, - ::Api: BlockBuilderApi, - A: txpool::ChainApi, - client::error::Error: From<::Error> -{ - type Create = Result<::Block, error::Error>; - type Error = error::Error; - - fn propose(&self, _consensus_data: ()) -> Result<::Block, error::Error> { - self.propose_with(ConsensusData { timestamp: None }) + self.propose_with(inherent_data) } } impl Proposer where Block: BlockT, C: AuthoringApi, - ::Api: BlockBuilderApi, + ::Api: BlockBuilderApi, A: txpool::ChainApi, client::error::Error: From<::Error>, { - fn propose_with(&self, consensus_data: ConsensusData) + fn propose_with(&self, inherent_data: InherentData) -> Result<::Block, error::Error> { use runtime_primitives::traits::BlakeTwo256; - let timestamp = consensus_data.timestamp.unwrap_or_else(current_timestamp); - let inherent_data = BasicInherentData::new(timestamp, 0); - let block = self.client.build_block( &self.parent_id, inherent_data, @@ -261,9 +236,3 @@ impl Proposer where 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/core/basic-authorship/src/lib.rs b/core/basic-authorship/src/lib.rs index 0d7e31075084e..aafb2d0535d72 100644 --- a/core/basic-authorship/src/lib.rs +++ b/core/basic-authorship/src/lib.rs @@ -18,13 +18,13 @@ #![warn(unused_extern_crates)] -extern crate substrate_consensus_aura_primitives as aura_primitives; extern crate substrate_primitives as primitives; extern crate sr_primitives as runtime_primitives; extern crate substrate_consensus_common as consensus_common; extern crate substrate_client as client; extern crate parity_codec as codec; extern crate substrate_transaction_pool as transaction_pool; +extern crate substrate_inherents as inherents; #[macro_use] extern crate log; diff --git a/core/client/Cargo.toml b/core/client/Cargo.toml index e06139cc11dec..e1bafb0f09d4d 100644 --- a/core/client/Cargo.toml +++ b/core/client/Cargo.toml @@ -22,11 +22,12 @@ substrate-telemetry = { path = "../telemetry", optional = true } hash-db = { version = "0.9" , optional = true } kvdb = { git = "https://github.com/paritytech/parity-common", optional = true, rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } -codec = { package = "parity-codec", version = "2.1", default-features = false } +codec = { package = "parity-codec", version = "2.2", default-features = false } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } runtime-primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false } runtime-version = { package = "sr-version", path = "../sr-version", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } +inherents = { package = "substrate-inherents", path = "../inherents", default-features = false } sr-api-macros = { path = "../sr-api-macros" } [dev-dependencies] @@ -39,6 +40,7 @@ std = [ "codec/std", "consensus", "primitives/std", + "inherents/std", "parking_lot", "error-chain", "fnv", diff --git a/core/client/src/block_builder/api.rs b/core/client/src/block_builder/api.rs index 540c135de226e..72cfea309fb7d 100644 --- a/core/client/src/block_builder/api.rs +++ b/core/client/src/block_builder/api.rs @@ -16,13 +16,14 @@ //! The runtime api for building blocks. -use runtime_primitives::{traits::Block as BlockT, ApplyResult, CheckInherentError}; +use runtime_primitives::{traits::Block as BlockT, ApplyResult}; use rstd::vec::Vec; use sr_api_macros::decl_runtime_apis; +pub use inherents::{InherentData, CheckInherentsResult}; decl_runtime_apis! { /// The `BlockBuilder` api trait that provides required functions for building a block for a runtime. - pub trait BlockBuilder { + pub trait BlockBuilder { /// Apply the given extrinsics. fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult; /// Finish the current block. @@ -30,7 +31,7 @@ decl_runtime_apis! { /// Generate inherent extrinsics. The inherent data will vary from chain to chain. fn inherent_extrinsics(inherent: InherentData) -> Vec<::Extrinsic>; /// Check that the inherents are valid. The inherent data will vary from chain to chain. - fn check_inherents(block: Block, data: InherentData) -> Result<(), CheckInherentError>; + fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult; /// Generate a random seed. fn random_seed() -> ::Hash; } diff --git a/core/client/src/block_builder/block_builder.rs b/core/client/src/block_builder/block_builder.rs index a0e9d67827b64..4df12d94e2afb 100644 --- a/core/client/src/block_builder/block_builder.rs +++ b/core/client/src/block_builder/block_builder.rs @@ -16,7 +16,6 @@ use super::api::BlockBuilder as BlockBuilderApi; use std::vec::Vec; -use std::marker::PhantomData; use codec::Encode; use crate::blockchain::HeaderBackend; use runtime_primitives::traits::{ @@ -30,19 +29,18 @@ use runtime_primitives::ApplyOutcome; /// Utility for building new (valid) blocks from a stream of extrinsics. -pub struct BlockBuilder<'a, Block, InherentData, A: ProvideRuntimeApi> where Block: BlockT { +pub struct BlockBuilder<'a, Block, A: ProvideRuntimeApi> where Block: BlockT { header: ::Header, extrinsics: Vec<::Extrinsic>, api: ApiRef<'a, A::Api>, block_id: BlockId, - _marker: PhantomData, } -impl<'a, Block, A, InherentData> BlockBuilder<'a, Block, InherentData, A> +impl<'a, Block, A> BlockBuilder<'a, Block, A> where Block: BlockT, A: ProvideRuntimeApi + HeaderBackend + 'a, - A::Api: BlockBuilderApi, + A::Api: BlockBuilderApi, { /// Create a new instance of builder from the given client, building on the latest block. pub fn new(api: &'a A) -> error::Result { @@ -75,7 +73,6 @@ where extrinsics: Vec::new(), api, block_id: *block_id, - _marker: PhantomData, }) } diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 67052ff7f176c..87a91de3d9979 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -47,7 +47,9 @@ use state_machine::{ }; use crate::backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage}; -use crate::blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend}; +use crate::blockchain::{ + self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend +}; use crate::call_executor::{CallExecutor, LocalCallExecutor}; use executor::{RuntimeVersion, RuntimeInfo}; use crate::notifications::{StorageNotifications, StorageEventStream}; @@ -78,7 +80,8 @@ pub struct Client where Block: BlockT { import_notification_sinks: Mutex>>>, finality_notification_sinks: Mutex>>>, import_lock: Mutex<()>, - importing_block: RwLock>, // holds the block hash currently being imported. TODO: replace this with block queue + // holds the block hash currently being imported. TODO: replace this with block queue + importing_block: RwLock>, block_execution_strategy: ExecutionStrategy, api_execution_strategy: ExecutionStrategy, _phantom: PhantomData, @@ -557,25 +560,25 @@ impl Client where } /// Create a new block, built on the head of the chain. - pub fn new_block( + pub fn new_block( &self - ) -> error::Result> where + ) -> error::Result> where E: Clone + Send + Sync, RA: Send + Sync, Self: ProvideRuntimeApi, - ::Api: BlockBuilderAPI + ::Api: BlockBuilderAPI { block_builder::BlockBuilder::new(self) } /// Create a new block, built on top of `parent`. - pub fn new_block_at( + pub fn new_block_at( &self, parent: &BlockId - ) -> error::Result> where + ) -> error::Result> where E: Clone + Send + Sync, RA: Send + Sync, Self: ProvideRuntimeApi, - ::Api: BlockBuilderAPI + ::Api: BlockBuilderAPI { block_builder::BlockBuilder::at_block(parent, &self) } diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index 2cc5c6cfa36d7..d0ab6f8d4ca7a 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -13,8 +13,9 @@ sr-primitives = { path = "../../sr-primitives" } sr-version = { path = "../../sr-version" } sr-io = { path = "../../sr-io" } substrate-consensus-aura-primitives = { path = "primitives" } - +substrate-inherents = { path = "../../inherents" } srml-consensus = { path = "../../../srml/consensus" } +srml-aura = { path = "../../../srml/aura" } futures = "0.1.17" tokio = "0.1.7" parking_lot = "0.7.1" diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 374c4d613f08b..8aed003c5166f 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -33,6 +33,8 @@ extern crate srml_support as runtime_support; extern crate sr_io as runtime_io; extern crate sr_primitives as runtime_primitives; extern crate substrate_consensus_aura_primitives as aura_primitives; +extern crate srml_aura; +extern crate substrate_inherents as inherents; extern crate substrate_consensus_common as consensus_common; extern crate tokio; @@ -57,24 +59,33 @@ extern crate env_logger; mod slots; -use std::sync::Arc; -use std::time::Duration; +use std::{sync::{Arc, mpsc}, time::Duration, thread}; use codec::Encode; -use consensus_common::{Authorities, BlockImport, Environment, Error as ConsensusError, Proposer, ForkChoiceStrategy}; +use consensus_common::{ + Authorities, BlockImport, Environment, Error as ConsensusError, Proposer, ForkChoiceStrategy +}; use consensus_common::import_queue::{Verifier, BasicQueue}; use client::ChainHead; use client::block_builder::api::BlockBuilder as BlockBuilderApi; use consensus_common::{ImportBlock, BlockOrigin}; -use runtime_primitives::{generic, generic::BlockId, Justification, BasicInherentData}; -use runtime_primitives::traits::{Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi}; +use runtime_primitives::{generic, generic::BlockId, Justification}; +use runtime_primitives::traits::{ + Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi +}; use primitives::{Ed25519AuthorityId, ed25519}; +use inherents::{InherentDataProviders, InherentData, RuntimeString}; use futures::{Stream, Future, IntoFuture, future::{self, Either}}; use tokio::timer::Timeout; use api::AuraApi; use slots::Slots; +use srml_aura::{ + InherentType as AuraInherent, AuraInherentData, + timestamp::{TimestampInherentData, InherentType as TimestampInherent, InherentError as TIError} +}; + pub use aura_primitives::*; pub use consensus_common::SyncOracle; @@ -114,18 +125,23 @@ fn duration_now() -> Option { }).ok() } -fn timestamp_and_slot_now(slot_duration: u64) -> Option<(u64, u64)> { - duration_now().map(|s| { - let s = s.as_secs(); - (s, s / slot_duration) - }) -} - /// Get the slot for now. fn slot_now(slot_duration: u64) -> Option { duration_now().map(|s| s.as_secs() / slot_duration) } +fn extract_timestamp_and_slot( + data: &InherentData +) -> Result<(TimestampInherent, AuraInherent), consensus_common::Error> { + data.timestamp_inherent_data() + .and_then(|t| data.aura_inherent_data().map(|a| (t, a))) + .map_err(inherent_to_common_error) +} + +fn inherent_to_common_error(err: RuntimeString) -> consensus_common::Error { + consensus_common::ErrorKind::InherentData(err.into()).into() +} + /// 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 @@ -160,11 +176,12 @@ pub fn start_aura_thread( env: Arc, sync_oracle: SO, on_exit: impl Future + Send + 'static, -) where + inherent_data_providers: InherentDataProviders, +) -> Result<(), consensus_common::Error> where B: Block + 'static, C: Authorities + ChainHead + Send + Sync + 'static, - E: Environment + Send + Sync + 'static, - E::Proposer: Proposer + 'static, + E: Environment + Send + Sync + 'static, + E::Proposer: Proposer + 'static, I: BlockImport + Send + Sync + 'static, Error: From + From + 'static, SO: SyncOracle + Send + Clone + 'static, @@ -173,7 +190,9 @@ pub fn start_aura_thread( { use tokio::runtime::current_thread::Runtime; - ::std::thread::spawn(move || { + let (result_sender, result_recv) = mpsc::channel(); + + thread::spawn(move || { let mut runtime = match Runtime::new() { Ok(r) => r, Err(e) => { @@ -182,7 +201,7 @@ pub fn start_aura_thread( } }; - let _ = runtime.block_on(start_aura( + let aura_future = match start_aura( slot_duration, local_key, client, @@ -190,8 +209,26 @@ pub fn start_aura_thread( env, sync_oracle, on_exit, - )); + inherent_data_providers, + ) { + Ok(aura_future) => { + result_sender + .send(Ok(())) + .expect("Receive is not dropped before receiving a result; qed"); + aura_future + }, + Err(e) => { + result_sender + .send(Err(e)) + .expect("Receive is not dropped before receiving a result; qed"); + return; + } + }; + + let _ = runtime.block_on(aura_future); }); + + result_recv.recv().expect("Aura start thread result sender dropped") } /// Start the aura worker. The returned future should be run in a tokio runtime. @@ -203,17 +240,20 @@ pub fn start_aura( env: Arc, sync_oracle: SO, on_exit: impl Future, -) -> impl Future where + inherent_data_providers: InherentDataProviders, +) -> Result, consensus_common::Error> where B: Block, C: Authorities + ChainHead, - E: Environment, - E::Proposer: Proposer, + E: Environment, + E::Proposer: Proposer, I: BlockImport, Error: From + From, SO: SyncOracle + Send + Clone, DigestItemFor: CompatibleDigestItem + DigestItem, Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>, { + register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.0)?; + let make_authorship = move || { let client = client.clone(); @@ -222,9 +262,10 @@ pub fn start_aura( let env = env.clone(); let sync_oracle = sync_oracle.clone(); let SlotDuration(slot_duration) = slot_duration; + let inherent_data_providers = inherent_data_providers.clone(); // rather than use a timer interval, we schedule our waits ourselves - Slots::new(slot_duration) + Slots::new(slot_duration, inherent_data_providers) .map_err(|e| debug!(target: "aura", "Faulty timer: {:?}", e)) .for_each(move |slot_info| { let client = client.clone(); @@ -244,7 +285,7 @@ pub fn start_aura( let chain_head = match client.best_block_header() { Ok(x) => x, Err(e) => { - warn!(target:"aura", "Unable to author block in slot {}. \ + warn!(target: "aura", "Unable to author block in slot {}. \ no best block header: {:?}", slot_num, e); return Either::B(future::ok(())) } @@ -253,8 +294,11 @@ pub fn start_aura( 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); + warn!( + "Unable to fetch authorities at block {:?}: {:?}", + chain_head.hash(), + e + ); return Either::B(future::ok(())); } }; @@ -262,8 +306,11 @@ pub fn start_aura( let proposal_work = match slot_author(slot_num, &authorities) { None => return Either::B(future::ok(())), Some(author) => if author.0 == public_key.0 { - debug!(target: "aura", "Starting authorship at slot {}; timestamp = {}", - slot_num, timestamp); + debug!( + target: "aura", "Starting authorship at slot {}; timestamp = {}", + slot_num, + timestamp + ); // we are the slot author. make a block and sign it. let proposer = match env.init(&chain_head, &authorities) { @@ -274,17 +321,12 @@ pub fn start_aura( } }; - let consensus_data = AuraConsensusData { - timestamp, - slot: slot_num, - slot_duration, - }; - + let remaining_duration = slot_info.remaining_duration(); // deadline our production to approx. the end of the // slot Timeout::new( - proposer.propose(consensus_data).into_future(), - slot_info.remaining_duration(), + proposer.propose(slot_info.inherent_data).into_future(), + remaining_duration, ) } else { return Either::B(future::ok(())); @@ -298,8 +340,10 @@ pub fn start_aura( // that is actually set by the proposer. let slot_after_building = slot_now(slot_duration); if slot_after_building != Some(slot_num) { - info!("Discarding proposal for slot {}; block production took too long", - slot_num); + info!( + "Discarding proposal for slot {}; block production took too long", + slot_num + ); return } @@ -363,7 +407,7 @@ pub fn start_aura( }) }); - work.select(on_exit).then(|_| Ok(())) + Ok(work.select(on_exit).then(|_| Ok(()))) } // a header which has been checked @@ -431,11 +475,58 @@ pub trait ExtraVerification: Send + Sync { } /// A verifier for Aura blocks. -pub struct AuraVerifier { - slot_duration: SlotDuration, +pub struct AuraVerifier { client: Arc, - make_inherent: MakeInherent, extra: E, + inherent_data_providers: inherents::InherentDataProviders, +} + +impl AuraVerifier +{ + fn check_inherents( + &self, + block: B, + block_id: BlockId, + inherent_data: InherentData, + timestamp_now: u64, + ) -> Result<(), String> + where C: ProvideRuntimeApi, C::Api: BlockBuilderApi + { + const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; + + let inherent_res = self.client.runtime_api().check_inherents( + &block_id, + block, + inherent_data, + ).map_err(|e| format!("{:?}", e))?; + + if !inherent_res.ok() { + inherent_res + .into_errors() + .try_for_each(|(i, e)| match TIError::try_from(&i, &e) { + Some(TIError::ValidAtTimestamp(timestamp)) => { + // halt import until timestamp is valid. + // reject when too far ahead. + if timestamp > timestamp_now + MAX_TIMESTAMP_DRIFT_SECS { + return Err("Rejecting block too far in future".into()); + } + + let diff = timestamp.saturating_sub(timestamp_now); + info!( + target: "aura", + "halting for block {} seconds in the future", + diff + ); + thread::sleep(Duration::from_secs(diff)); + Ok(()) + }, + Some(TIError::Other(e)) => Err(e.into()), + None => Err(self.inherent_data_providers.error_to_string(&i, &e)), + }) + } else { + Ok(()) + } + } } /// No-op extra verification. @@ -450,12 +541,11 @@ impl ExtraVerification for NothingExtra { } } -impl Verifier for AuraVerifier where +impl Verifier for AuraVerifier where C: Authorities + BlockImport + ProvideRuntimeApi + Send + Sync, - C::Api: BlockBuilderApi, + C::Api: BlockBuilderApi, DigestItemFor: CompatibleDigestItem + DigestItem, E: ExtraVerification, - MakeInherent: Fn(u64, u64) -> Inherent + Send + Sync, { fn verify( &self, @@ -464,11 +554,9 @@ impl Verifier for AuraVerifier, mut body: Option>, ) -> Result<(ImportBlock, Option>), String> { - use runtime_primitives::CheckInherentError; - const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; - - let (timestamp_now, slot_now) = timestamp_and_slot_now(self.slot_duration.0) - .ok_or("System time is before UnixTime?".to_owned())?; + let mut inherent_data = self.inherent_data_providers.create_inherent_data().map_err(String::from)?; + let (timestamp_now, slot_now) = extract_timestamp_and_slot(&inherent_data) + .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; let hash = header.hash(); let parent_hash = *header.parent_hash(); let authorities = self.client.authorities(&BlockId::Hash(parent_hash)) @@ -491,30 +579,15 @@ impl Verifier for AuraVerifier {} - Err(CheckInherentError::ValidAtTimestamp(timestamp)) => { - // halt import until timestamp is valid. - // reject when too far ahead. - if timestamp > timestamp_now + MAX_TIMESTAMP_DRIFT_SECS { - return Err("Rejecting block too far in future".into()); - } - - let diff = timestamp.saturating_sub(timestamp_now); - info!(target: "aura", "halting for block {} seconds in the future", diff); - ::std::thread::sleep(Duration::from_secs(diff)); - }, - Err(CheckInherentError::Other(s)) => return Err(s.into_owned()), - } + BlockId::Hash(parent_hash), + inherent_data, + timestamp_now, + )?; let (_, inner_body) = block.deconstruct(); body = Some(inner_body); @@ -546,16 +619,8 @@ impl Verifier for AuraVerifier BasicInherentData { - BasicInherentData::new(timestamp, slot_now) -} - -/// A type for a function which produces inherent. -pub type InherentProducingFn = fn(u64, u64) -> I; - /// The Aura import queue type. -pub type AuraImportQueue = BasicQueue>; +pub type AuraImportQueue = BasicQueue>; /// A slot duration. Create with `get_or_compute`. // The internal member should stay private here. @@ -584,8 +649,10 @@ impl SlotDuration { let genesis_slot_duration = client.runtime_api() .slot_duration(&BlockId::number(Zero::zero()))?; - info!("Loaded block-time = {:?} seconds from genesis on first-launch", - genesis_slot_duration); + info!( + "Loaded block-time = {:?} seconds from genesis on first-launch", + genesis_slot_duration + ); genesis_slot_duration.using_encoded(|s| { client.insert_aux(&[(SLOT_KEY, &s[..])], &[]) @@ -597,22 +664,39 @@ impl SlotDuration { } } +/// Register the aura inherent data provider, if not registered already. +fn register_aura_inherent_data_provider( + inherent_data_providers: &InherentDataProviders, + slot_duration: u64, +) -> Result<(), consensus_common::Error> { + if !inherent_data_providers.has_provider(&srml_aura::INHERENT_IDENTIFIER) { + inherent_data_providers + .register_provider(srml_aura::InherentDataProvider::new(slot_duration)) + .map_err(inherent_to_common_error) + } else { + Ok(()) + } +} + /// Start an import queue for the Aura consensus algorithm. -pub fn import_queue( +pub fn import_queue( slot_duration: SlotDuration, client: Arc, extra: E, - make_inherent: MakeInherent, -) -> AuraImportQueue where + inherent_data_providers: InherentDataProviders, +) -> Result, consensus_common::Error> where B: Block, - C: Authorities + BlockImport + ProvideRuntimeApi + Send + Sync, - C::Api: BlockBuilderApi, + C: Authorities + BlockImport + ProvideRuntimeApi + Send + Sync, + C::Api: BlockBuilderApi, DigestItemFor: CompatibleDigestItem + DigestItem, E: ExtraVerification, - MakeInherent: Fn(u64, u64) -> Inherent + Send + Sync, { - let verifier = Arc::new(AuraVerifier { slot_duration, client: client.clone(), extra, make_inherent }); - BasicQueue::new(verifier, client) + register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.0)?; + + let verifier = Arc::new( + AuraVerifier { client: client.clone(), extra, inherent_data_providers } + ); + Ok(BasicQueue::new(verifier, client)) } #[cfg(test)] @@ -636,7 +720,7 @@ mod tests { struct DummyFactory(Arc); struct DummyProposer(u64, Arc); - impl Environment for DummyFactory { + impl Environment for DummyFactory { type Proposer = DummyProposer; type Error = Error; @@ -647,11 +731,11 @@ mod tests { } } - impl Proposer for DummyProposer { + impl Proposer for DummyProposer { type Error = Error; type Create = Result; - fn propose(&self, _consensus_data: AuraConsensusData) -> Result { + fn propose(&self, _: InherentData) -> Result { self.1.new_block().unwrap().bake().map_err(|e| e.into()) } } @@ -663,36 +747,38 @@ mod tests { peers: Vec, >, ()>>>, - started: bool + started: bool, } impl TestNetFactory for AuraTestNet { - type Verifier = AuraVerifier>; + type Verifier = AuraVerifier; type PeerData = (); /// Create new test network with peers and given config. fn from_config(_config: &ProtocolConfig) -> Self { AuraTestNet { peers: Vec::new(), - started: false + started: false, } } fn make_verifier(&self, client: Arc, _cfg: &ProtocolConfig) -> Arc { - fn make_inherent(_: u64, _: u64) { () } let slot_duration = SlotDuration::get_or_compute(&*client) .expect("slot duration available"); + let inherent_data_providers = InherentDataProviders::new(); + register_aura_inherent_data_provider( + &inherent_data_providers, + slot_duration.0 + ).expect("Registers aura inherent data provider"); assert_eq!(slot_duration.0, SLOT_DURATION); Arc::new(AuraVerifier { client, - slot_duration, extra: NothingExtra, - make_inherent: make_inherent as _, + inherent_data_providers, }) } @@ -748,6 +834,11 @@ mod tests { let slot_duration = SlotDuration::get_or_compute(&*client) .expect("slot duration available"); + let inherent_data_providers = InherentDataProviders::new(); + register_aura_inherent_data_provider( + &inherent_data_providers, slot_duration.0 + ).expect("Registers aura inherent data provider"); + let aura = start_aura( slot_duration, Arc::new(key.clone().into()), @@ -756,7 +847,8 @@ mod tests { environ.clone(), DummyOracle, futures::empty(), - ); + inherent_data_providers, + ).expect("Starts aura"); runtime.spawn(aura); } diff --git a/core/consensus/aura/src/slots.rs b/core/consensus/aura/src/slots.rs index 37db3b17636b4..faf966e329553 100644 --- a/core/consensus/aura/src/slots.rs +++ b/core/consensus/aura/src/slots.rs @@ -22,6 +22,10 @@ use std::time::{Instant, Duration}; use tokio::timer::Delay; use futures::prelude::*; +use inherents::{InherentDataProviders, InherentData}; + +use consensus_common::{Error, ErrorKind}; + /// Returns the duration until the next slot, based on current duration since pub(crate) fn time_until_next(now: Duration, slot_duration: u64) -> Duration { let remaining_full_secs = slot_duration - (now.as_secs() % slot_duration) - 1; @@ -30,7 +34,6 @@ pub(crate) fn time_until_next(now: Duration, slot_duration: u64) -> Duration { } /// Information about a slot. -#[derive(Debug, Clone)] pub(crate) struct SlotInfo { /// The slot number. pub(crate) number: u64, @@ -38,6 +41,8 @@ pub(crate) struct SlotInfo { pub(crate) timestamp: u64, /// The instant at which the slot ends. pub(crate) ends_at: Instant, + /// The inherent data. + pub(crate) inherent_data: InherentData, } impl SlotInfo { @@ -57,22 +62,24 @@ pub(crate) struct Slots { last_slot: u64, slot_duration: u64, inner_delay: Option, + inherent_data_providers: InherentDataProviders, } impl Slots { - /// Create a new `slots` stream. - pub(crate) fn new(slot_duration: u64) -> Self { + /// Create a new `Slots` stream. + pub(crate) fn new(slot_duration: u64, inherent_data_providers: InherentDataProviders) -> Self { Slots { last_slot: 0, slot_duration, inner_delay: None, + inherent_data_providers, } } } impl Stream for Slots { type Item = SlotInfo; - type Error = tokio::timer::Error; + type Error = Error; fn poll(&mut self) -> Poll, Self::Error> { let slot_duration = self.slot_duration; @@ -90,30 +97,33 @@ impl Stream for Slots { }; if let Some(ref mut inner_delay) = self.inner_delay { - try_ready!(inner_delay.poll()); + try_ready!(inner_delay.poll().map_err(|e| Error::from(ErrorKind::FaultyTimer(e)))); } // timeout has fired. - let (timestamp, slot_num) = match ::timestamp_and_slot_now(slot_duration) { - None => return Ok(Async::Ready(None)), - Some(x) => x, - }; + let inherent_data = self.inherent_data_providers.create_inherent_data() + .map_err(::inherent_to_common_error)?; + let (timestamp, slot_num) = ::extract_timestamp_and_slot(&inherent_data)?; // reschedule delay for next slot. - let ends_at = Instant::now() - + time_until_next(Duration::from_secs(timestamp), slot_duration); + let ends_at = Instant::now() + time_until_next(Duration::from_secs(timestamp), slot_duration); self.inner_delay = Some(Delay::new(ends_at)); // never yield the same slot twice. if slot_num > self.last_slot { self.last_slot = slot_num; - Ok(Async::Ready(Some(SlotInfo { - number: slot_num, - timestamp, - ends_at, - }))) + Ok( + Async::Ready( + Some(SlotInfo { + number: slot_num, + timestamp, + ends_at, + inherent_data, + }) + ) + ) } else { // re-poll until we get a new slot. self.poll() diff --git a/core/consensus/common/Cargo.toml b/core/consensus/common/Cargo.toml index f8ae47d70f2c1..1c3f335207f7a 100644 --- a/core/consensus/common/Cargo.toml +++ b/core/consensus/common/Cargo.toml @@ -8,6 +8,7 @@ description = "Common utilities for substrate consensus" log = "0.4" parking_lot = "0.7.1" substrate-primitives = { path= "../../primitives" } +substrate-inherents = { path= "../../inherents" } error-chain = "0.12" futures = "0.1" sr-version = { path = "../../sr-version" } diff --git a/core/consensus/common/src/error.rs b/core/consensus/common/src/error.rs index ec378d24cbd48..caf325eeb351b 100644 --- a/core/consensus/common/src/error.rs +++ b/core/consensus/common/src/error.rs @@ -37,6 +37,12 @@ error_chain! { display("Timer error: {}", e), } + /// Error while working with inherent data. + InherentData(e: String) { + description("InherentData error"), + display("InherentData error: {}", e), + } + /// Unable to propose a block. CannotPropose { description("Unable to create block proposal."), diff --git a/core/consensus/common/src/lib.rs b/core/consensus/common/src/lib.rs index 453b6844309eb..861eaf9554882 100644 --- a/core/consensus/common/src/lib.rs +++ b/core/consensus/common/src/lib.rs @@ -27,6 +27,7 @@ #![recursion_limit="128"] extern crate substrate_primitives as primitives; +extern crate substrate_inherents as inherents; extern crate futures; extern crate parking_lot; extern crate sr_version as runtime_version; @@ -47,6 +48,7 @@ use std::sync::Arc; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{AuthorityIdFor, Block}; use futures::prelude::*; +pub use inherents::InherentData; pub mod offline_tracker; pub mod error; @@ -67,9 +69,9 @@ pub trait Authorities { } /// Environment producer for a Consensus instance. Creates proposer instance and communication streams. -pub trait Environment { +pub trait Environment { /// The proposer type this creates. - type Proposer: Proposer; + type Proposer: Proposer; /// Error which can occur upon creation. type Error: From; @@ -85,13 +87,13 @@ pub trait Environment { /// block. /// /// Proposers are generic over bits of "consensus data" which are engine-specific. -pub trait Proposer { +pub trait Proposer { /// Error type which can occur when proposing or evaluating. type Error: From + ::std::fmt::Debug + 'static; /// Future that resolves to a committed proposal. - type Create: IntoFuture; + type Create: IntoFuture; /// Create a proposal. - fn propose(&self, consensus_data: ConsensusData) -> Self::Create; + fn propose(&self, inherent_data: InherentData) -> Self::Create; } /// An oracle for when major synchronization work is being undertaken. diff --git a/core/inherents/Cargo.toml b/core/inherents/Cargo.toml new file mode 100644 index 0000000000000..7820926a8a6d2 --- /dev/null +++ b/core/inherents/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "substrate-inherents" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +parking_lot = { version = "0.7", optional = true } +rstd = { package = "sr-std", path = "../sr-std", default-features = false } +parity-codec = { version = "2.2", default-features = false } +parity-codec-derive = { version = "2.2", default-features = false } +runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false } + +[features] +default = [ "std" ] +std = [ + "parking_lot", + "rstd/std", + "parity-codec/std", + "runtime_primitives/std", +] diff --git a/core/inherents/src/lib.rs b/core/inherents/src/lib.rs new file mode 100644 index 0000000000000..16910fd4ab39d --- /dev/null +++ b/core/inherents/src/lib.rs @@ -0,0 +1,575 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Provides types and traits for creating and checking inherents. +//! +//! Each inherent is added to a produced block. Each runtime decides on which inherents its +//! want to attach to its blocks. All data that is required for the runtime to create the inherents +//! is stored in the `InherentData`. This `InherentData` is constructed by the node and given to +//! the runtime. +//! +//! Types that provide data for inherents, should implement `InherentDataProvider` and need to be +//! registered at `InherentDataProviders`. +//! +//! In the runtime, modules need to implement `ProvideInherent` when they can create and/or check +//! inherents. By implementing `ProvideInherent`, a module is not enforced to create an inherent. +//! A module can also just check given inherents. For using a module as inherent provider, it needs +//! to be registered by the `construct_runtime!` macro. The macro documentation gives more +//! information on how that is done. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate parity_codec as codec; + +use parity_codec_derive::{Encode, Decode}; + +use rstd::{collections::btree_map::{BTreeMap, IntoIter, Entry}, vec::Vec}; + +#[cfg(feature = "std")] +use parking_lot::RwLock; + +#[cfg(feature = "std")] +use std::{sync::Arc, format}; + +pub use runtime_primitives::RuntimeString; + +/// An identifier for an inherent. +pub type InherentIdentifier = [u8; 8]; + +/// Inherent data to include in a block. +pub struct InherentData { + /// All inherent data encoded with parity-codec and an identifier. + data: BTreeMap> +} + +impl InherentData { + /// Create a new instance. + pub fn new() -> Self { + Self { + data: Default::default(), + } + } + + /// Put data for an inherent into the internal storage. + /// + /// # Return + /// + /// Returns `Ok(())` if the data could be inserted an no data for an inherent with the same + /// identifier existed, otherwise an error is returned. + /// + /// Inherent identifiers need to be unique, otherwise decoding of these values will not work! + pub fn put_data( + &mut self, + identifier: InherentIdentifier, + inherent: &I, + ) -> Result<(), RuntimeString> { + match self.data.entry(identifier) { + Entry::Vacant(entry) => { + entry.insert(inherent.encode()); + Ok(()) + }, + Entry::Occupied(_) => { + Err("Inherent with same identifier already exists!".into()) + } + } + } + + /// Replace the data for an inherent. + /// + /// If it does not exist, the data is just inserted. + pub fn replace_data( + &mut self, + identifier: InherentIdentifier, + inherent: &I, + ) { + self.data.insert(identifier, inherent.encode()); + } + + /// Returns the data for the requested inherent. + /// + /// # Return + /// + /// - `Ok(Some(I))` if the data could be found and deserialized. + /// - `Ok(None)` if the data could not be found. + /// - `Err(_)` if the data could be found, but deserialization did not work. + pub fn get_data( + &self, + identifier: &InherentIdentifier, + ) -> Result, RuntimeString> { + match self.data.get(identifier) { + Some(inherent) => + I::decode(&mut &inherent[..]) + .ok_or_else(|| "Could not decode requested inherent type!".into()) + .map(Some), + None => Ok(None) + } + } +} + +impl codec::Encode for InherentData { + fn encode(&self) -> Vec { + let keys = self.data.keys().collect::>(); + let values = self.data.values().collect::>(); + + let mut encoded = keys.encode(); + encoded.extend(values.encode()); + encoded + } +} + +impl codec::Decode for InherentData { + fn decode(value: &mut I) -> Option { + Vec::::decode(value) + .and_then(|i| Vec::>::decode(value).map(|v| (i, v))) + .and_then(|(i, v)| { + if i.len() == v.len() { + Some(Self { + data: i.into_iter().zip(v.into_iter()).collect() + }) + } else { + None + } + }) + } +} + +/// The result of checking inherents. +/// +/// It either returns okay for all checks, stores all occurred errors or just one fatal error. +/// +/// When a fatal error occurres, all other errors are removed and the implementation needs to +/// abbort checking inherents. +#[derive(Encode, Decode)] +pub struct CheckInherentsResult { + /// Did the check succeed? + okay: bool, + /// Did we encounter a fatal error? + fatal_error: bool, + /// We use the `InherentData` to store our errors. + errors: InherentData, +} + +impl CheckInherentsResult { + /// Create a new instance. + pub fn new() -> Self { + Self { + okay: true, + errors: InherentData::new(), + fatal_error: false, + } + } + + /// Put an error into the result. + /// + /// This makes this result resolve to `ok() == false`. + /// + /// # Parameters + /// + /// - identifier - The identifier of the inherent that generated the error. + /// - error - The error that will be encoded. + pub fn put_error( + &mut self, + identifier: InherentIdentifier, + error: &E, + ) -> Result<(), RuntimeString> { + // Don't accept any other error + if self.fatal_error { + return Err("No other errors are accepted after an hard error!".into()) + } + + if error.is_fatal_error() { + // remove the other errors. + self.errors.data.clear(); + } + + self.errors.put_data(identifier, error)?; + + self.okay = false; + self.fatal_error = error.is_fatal_error(); + Ok(()) + } + + /// Get an error out of the result. + /// + /// # Return + /// + /// - `Ok(Some(I))` if the error could be found and deserialized. + /// - `Ok(None)` if the error could not be found. + /// - `Err(_)` if the error could be found, but deserialization did not work. + pub fn get_error( + &self, + identifier: &InherentIdentifier, + ) -> Result, RuntimeString> { + self.errors.get_data(identifier) + } + + /// Convert into an iterator over all contained errors. + pub fn into_errors(self) -> IntoIter> { + self.errors.data.into_iter() + } + + /// Is this result ok? + pub fn ok(&self) -> bool { + self.okay + } + + /// Is this a fatal error? + pub fn fatal_error(&self) -> bool { + self.fatal_error + } +} + +#[cfg(feature = "std")] +impl PartialEq for CheckInherentsResult { + fn eq(&self, other: &Self) -> bool { + self.fatal_error == other.fatal_error && + self.okay == other.okay && + self.errors.data == other.errors.data + } +} + +/// All `InherentData` providers. +#[cfg(feature = "std")] +#[derive(Clone)] +pub struct InherentDataProviders { + providers: Arc>>>, +} + +#[cfg(feature = "std")] +impl InherentDataProviders { + /// Create a new instance. + pub fn new() -> Self { + Self { + providers: Default::default(), + } + } + + /// Register an `InherentData` provider. + /// + /// The registration order is preserved and this order will also be used when creating the + /// inherent data. + /// + /// # Result + /// + /// Will return an error, if a provider with the same identifier already exists. + pub fn register_provider( + &self, + provider: P, + ) -> Result<(), RuntimeString> { + if self.has_provider(&provider.inherent_identifier()) { + Err( + format!( + "Inherent data provider with identifier {:?} already exists!", + &provider.inherent_identifier() + ).into() + ) + } else { + provider.on_register(self)?; + self.providers.write().push(Box::new(provider)); + Ok(()) + } + } + + /// Returns if a provider for the given identifier exists. + pub fn has_provider(&self, identifier: &InherentIdentifier) -> bool { + self.providers.read().iter().any(|p| p.inherent_identifier() == identifier) + } + + /// Create inherent data. + pub fn create_inherent_data(&self) -> Result { + let mut data = InherentData::new(); + self.providers.read().iter().try_for_each(|p| { + p.provide_inherent_data(&mut data) + .map_err(|e| format!("Error for `{:?}`: {:?}", p.inherent_identifier(), e)) + })?; + Ok(data) + } + + /// Converts a given encoded error into a `String`. + /// + /// Useful if the implementation encouters an error for an identifier it does not know. + pub fn error_to_string(&self, identifier: &InherentIdentifier, error: &[u8]) -> String { + let res = self.providers.read().iter().filter_map(|p| + if p.inherent_identifier() == identifier { + Some( + p.error_to_string(error) + .unwrap_or_else(|| error_to_string_fallback(identifier)) + ) + } else { + None + } + ).next(); + + match res { + Some(res) => res, + None => format!( + "Error while checking inherent of type \"{}\", but this inherent type is unknown.", + String::from_utf8_lossy(identifier) + ) + } + } +} + +/// Something that provides inherent data. +#[cfg(feature = "std")] +pub trait ProvideInherentData { + /// Is called when this inherent data provider is registered at the given + /// `InherentDataProviders`. + fn on_register(&self, _: &InherentDataProviders) -> Result<(), RuntimeString> { + Ok(()) + } + + /// The identifier of the inherent for that data will be provided. + fn inherent_identifier(&self) -> &'static InherentIdentifier; + + /// Provide inherent data that should be included in a block. + /// + /// The data should be stored in the given `InherentData` structure. + fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), RuntimeString>; + + /// Convert the given encoded error to a string. + /// + /// If the given error could not be decoded, `None` should be returned. + fn error_to_string(&self, error: &[u8]) -> Option; +} + +/// A fallback function, if the decoding of an error fails. +#[cfg(feature = "std")] +fn error_to_string_fallback(identifier: &InherentIdentifier) -> String { + format!( + "Error while checking inherent of type \"{}\", but error could not be decoded.", + String::from_utf8_lossy(identifier) + ) +} + +/// Did we encounter a fatal error while checking an inherent? +/// +/// A fatal error is everything that fails while checking an inherent error, e.g. the inherent +/// was not found, could not be decoded etc. +/// Then there are cases where you not want the inherent check to fail, but report that there is an +/// action required. For example a timestamp of a block is in the future, the timestamp is still +/// correct, but it is required to verify the block at a later time again and then the inherent +/// check will succeed. +pub trait IsFatalError { + /// Is this a fatal error? + fn is_fatal_error(&self) -> bool; +} + +/// Auxiliary to make any given error resolve to `is_fatal_error() == true`. +#[derive(Encode)] +pub struct MakeFatalError(E); + +impl From for MakeFatalError { + fn from(err: E) -> Self { + MakeFatalError(err) + } +} + +impl IsFatalError for MakeFatalError { + fn is_fatal_error(&self) -> bool { + true + } +} + +/// A module that provides an inherent and may also verifies it. +pub trait ProvideInherent { + /// The call type of the module. + type Call; + /// The error returned by `check_inherent`. + type Error: codec::Encode + IsFatalError; + /// The inherent identifier used by this inherent. + const INHERENT_IDENTIFIER: self::InherentIdentifier; + + /// Create an inherent out of the given `InherentData`. + fn create_inherent(data: &InherentData) -> Option; + + /// Check the given inherent if it is valid. + /// Checking the inherent is optional and can be ommitted. + fn check_inherent(_: &Self::Call, _: &InherentData) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::{Encode, Decode}; + + const TEST_INHERENT_0: InherentIdentifier = *b"testinh0"; + const TEST_INHERENT_1: InherentIdentifier = *b"testinh1"; + + #[derive(Encode)] + struct NoFatalError(E); + impl IsFatalError for NoFatalError { + fn is_fatal_error(&self) -> bool { + false + } + } + + #[test] + fn inherent_data_encodes_and_decodes() { + let inherent_0 = vec![1, 2, 3]; + let inherent_1: u32 = 7; + + let mut data = InherentData::new(); + data.put_data(TEST_INHERENT_0, &inherent_0).unwrap(); + data.put_data(TEST_INHERENT_1, &inherent_1).unwrap(); + + let encoded = data.encode(); + + let decoded = InherentData::decode(&mut &encoded[..]).unwrap(); + + assert_eq!(decoded.get_data::>(&TEST_INHERENT_0).unwrap().unwrap(), inherent_0); + assert_eq!(decoded.get_data::(&TEST_INHERENT_1).unwrap().unwrap(), inherent_1); + } + + #[test] + fn adding_same_inherent_returns_an_error() { + let mut data = InherentData::new(); + data.put_data(TEST_INHERENT_0, &8).unwrap(); + assert!(data.put_data(TEST_INHERENT_0, &10).is_err()); + } + + #[derive(Clone)] + struct TestInherentDataProvider { + registered: Arc>, + } + + impl TestInherentDataProvider { + fn new() -> Self { + let inst = Self { + registered: Default::default(), + }; + + // just make sure + assert!(!inst.is_registered()); + + inst + } + + fn is_registered(&self) -> bool { + *self.registered.read() + } + } + + const ERROR_TO_STRING: &str = "Found error!"; + + impl ProvideInherentData for TestInherentDataProvider { + fn on_register(&self, _: &InherentDataProviders) -> Result<(), RuntimeString> { + *self.registered.write() = true; + Ok(()) + } + + fn inherent_identifier(&self) -> &'static InherentIdentifier { + &TEST_INHERENT_0 + } + + fn provide_inherent_data(&self, data: &mut InherentData) -> Result<(), RuntimeString> { + data.put_data(TEST_INHERENT_0, &42) + } + + fn error_to_string(&self, _: &[u8]) -> Option { + Some(ERROR_TO_STRING.into()) + } + } + + #[test] + fn registering_inherent_provider() { + let provider = TestInherentDataProvider::new(); + let providers = InherentDataProviders::new(); + + providers.register_provider(provider.clone()).unwrap(); + assert!(provider.is_registered()); + assert!(providers.has_provider(provider.inherent_identifier())); + + // Second time should fail + assert!(providers.register_provider(provider.clone()).is_err()); + } + + #[test] + fn create_inherent_data_from_all_providers() { + let provider = TestInherentDataProvider::new(); + let providers = InherentDataProviders::new(); + + providers.register_provider(provider.clone()).unwrap(); + assert!(provider.is_registered()); + + let inherent_data = providers.create_inherent_data().unwrap(); + + assert_eq!( + inherent_data.get_data::(provider.inherent_identifier()).unwrap().unwrap(), + 42u32 + ); + } + + #[test] + fn encoded_error_to_string() { + let provider = TestInherentDataProvider::new(); + let providers = InherentDataProviders::new(); + + providers.register_provider(provider.clone()).unwrap(); + assert!(provider.is_registered()); + + assert_eq!( + &providers.error_to_string(&TEST_INHERENT_0, &[1, 2]), ERROR_TO_STRING + ); + + assert!( + providers + .error_to_string(&TEST_INHERENT_1, &[1, 2]) + .contains("inherent type is unknown") + ); + } + + #[test] + fn check_inherents_result_encodes_and_decodes() { + let mut result = CheckInherentsResult::new(); + assert!(result.ok()); + + result.put_error(TEST_INHERENT_0, &NoFatalError(2u32)).unwrap(); + assert!(!result.ok()); + assert!(!result.fatal_error()); + + let encoded = result.encode(); + + let decoded = CheckInherentsResult::decode(&mut &encoded[..]).unwrap(); + + assert_eq!(decoded.get_error::(&TEST_INHERENT_0).unwrap().unwrap(), 2); + assert!(!decoded.ok()); + assert!(!decoded.fatal_error()); + } + + #[test] + fn check_inherents_result_removes_other_errors_on_fatal_error() { + let mut result = CheckInherentsResult::new(); + assert!(result.ok()); + + result.put_error(TEST_INHERENT_0, &NoFatalError(2u32)).unwrap(); + assert!(!result.ok()); + assert!(!result.fatal_error()); + + result.put_error(TEST_INHERENT_1, &MakeFatalError(4u32)).unwrap(); + assert!(!result.ok()); + assert!(result.fatal_error()); + + assert!(result.put_error(TEST_INHERENT_0, &NoFatalError(5u32)).is_err()); + + result.into_errors().for_each(|(i, e)| match i { + TEST_INHERENT_1 => assert_eq!(u32::decode(&mut &e[..]).unwrap(), 4), + _ => panic!("There should be no other error!"), + }); + } +} diff --git a/core/network/src/test/mod.rs b/core/network/src/test/mod.rs index 3e451885447c2..13fc86d1a5f3d 100644 --- a/core/network/src/test/mod.rs +++ b/core/network/src/test/mod.rs @@ -406,7 +406,7 @@ impl, D> Peer { /// Add blocks to the peer -- edit the block before adding pub fn generate_blocks(&self, count: usize, origin: BlockOrigin, mut edit_block: F) - where F: FnMut(BlockBuilder) -> Block + where F: FnMut(BlockBuilder) -> Block { for _ in 0..count { let builder = self.client.new_block().unwrap(); @@ -493,7 +493,6 @@ pub trait TestNetFactory: Sized { fn from_config(config: &ProtocolConfig) -> Self; fn make_verifier(&self, client: Arc, config: &ProtocolConfig) -> Arc; - /// Get reference to peer. fn peer(&self, i: usize) -> &Peer; fn peers(&self) -> &Vec>>; diff --git a/core/service/src/chain_ops.rs b/core/service/src/chain_ops.rs index 75d4688669f76..522f60a5cf7ff 100644 --- a/core/service/src/chain_ops.rs +++ b/core/service/src/chain_ops.rs @@ -32,7 +32,14 @@ use error; use chain_spec::ChainSpec; /// Export a range of blocks to a binary stream. -pub fn export_blocks(config: FactoryFullConfiguration, exit: E, mut output: W, from: FactoryBlockNumber, to: Option>, json: bool) -> error::Result<()> +pub fn export_blocks( + config: FactoryFullConfiguration, + exit: E, + mut output: W, + from: FactoryBlockNumber, + to: Option>, + json: bool +) -> error::Result<()> where F: ServiceFactory, E: Future + Send + 'static, @@ -68,7 +75,8 @@ pub fn export_blocks(config: FactoryFullConfiguration, exit: E, mut match client.block(&BlockId::number(block))? { Some(block) => { if json { - serde_json::to_writer(&mut output, &block).map_err(|e| format!("Eror writing JSON: {}", e))?; + serde_json::to_writer(&mut output, &block) + .map_err(|e| format!("Eror writing JSON: {}", e))?; } else { output.write(&block.encode())?; } @@ -87,7 +95,11 @@ pub fn export_blocks(config: FactoryFullConfiguration, exit: E, mut } /// Import blocks from a binary stream. -pub fn import_blocks(mut config: FactoryFullConfiguration, exit: E, mut input: R) -> error::Result<()> +pub fn import_blocks( + mut config: FactoryFullConfiguration, + exit: E, + mut input: R +) -> error::Result<()> where F: ServiceFactory, E: Future + Send + 'static, R: Read, { struct DummyLink; @@ -148,7 +160,10 @@ pub fn import_blocks(mut config: FactoryFullConfiguration, exit: E, } /// Revert the chain. -pub fn revert_chain(config: FactoryFullConfiguration, blocks: FactoryBlockNumber) -> error::Result<()> +pub fn revert_chain( + config: FactoryFullConfiguration, + blocks: FactoryBlockNumber +) -> error::Result<()> where F: ServiceFactory, { let client = new_client::(&config)?; diff --git a/core/service/src/components.rs b/core/service/src/components.rs index 8756f580091ef..0cdf11cc88314 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -27,7 +27,9 @@ use consensus_common::import_queue::ImportQueue; use network::{self, OnDemand}; use substrate_executor::{NativeExecutor, NativeExecutionDispatch}; use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool}; -use runtime_primitives::{BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId}; +use runtime_primitives::{ + BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId +}; use config::Configuration; use primitives::{Blake2Hasher, H256}; use rpc::{self, apis::system::SystemInfo}; diff --git a/core/service/src/error.rs b/core/service/src/error.rs index c3bacd198066b..f346db434a5c9 100644 --- a/core/service/src/error.rs +++ b/core/service/src/error.rs @@ -19,6 +19,7 @@ use client; use network; use keystore; +use consensus_common; error_chain! { foreign_links { @@ -27,6 +28,7 @@ error_chain! { links { Client(client::error::Error, client::error::ErrorKind) #[doc="Client error"]; + Consensus(consensus_common::Error, consensus_common::ErrorKind) #[doc="Consesus error"]; Network(network::error::Error, network::error::ErrorKind) #[doc="Network error"]; Keystore(keystore::Error, keystore::ErrorKind) #[doc="Keystore error"]; } diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 2eeaff6385034..170f38fd4edd8 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -77,7 +77,9 @@ use codec::{Encode, Decode}; pub use self::error::{ErrorKind, Error}; pub use config::{Configuration, Roles, PruningMode}; pub use chain_spec::{ChainSpec, Properties}; -pub use transaction_pool::txpool::{self, Pool as TransactionPool, Options as TransactionPoolOptions, ChainApi, IntoPoolError}; +pub use transaction_pool::txpool::{ + self, Pool as TransactionPool, Options as TransactionPoolOptions, ChainApi, IntoPoolError +}; pub use client::{ExecutionStrategy, FinalityNotifications}; pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend, @@ -294,7 +296,8 @@ impl Service { properties: config.chain_spec.properties(), }; let rpc = Components::RPC::start_rpc( - client.clone(), network.clone(), has_bootnodes, system_info, config.rpc_http, config.rpc_ws, task_executor.clone(), transaction_pool.clone(), + client.clone(), network.clone(), has_bootnodes, system_info, config.rpc_http, + config.rpc_ws, task_executor.clone(), transaction_pool.clone(), )?; // Telemetry @@ -392,8 +395,8 @@ impl Drop for Service where Components: components::Comp } } -fn maybe_start_server(address: Option, start: F) -> Result, io::Error> where - F: Fn(&SocketAddr) -> Result, +fn maybe_start_server(address: Option, start: F) -> Result, io::Error> + where F: Fn(&SocketAddr) -> Result, { Ok(match address { Some(mut address) => Some(start(&address) @@ -428,7 +431,9 @@ impl TransactionPoolAdapter { } } -impl network::TransactionPool, ComponentBlock> for TransactionPoolAdapter where ::RuntimeApi: Send + Sync{ +impl network::TransactionPool, ComponentBlock> for + TransactionPoolAdapter where ::RuntimeApi: Send + Sync +{ fn transactions(&self) -> Vec<(ComponentExHash, ComponentExtrinsic)> { self.pool.ready() .map(|t| { diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index cc0947372cc2d..c179a8f562ce4 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -182,7 +182,7 @@ impl TestNet { } } -pub fn connectivity(spec: FactoryChainSpec) { +pub fn connectivity(spec: FactoryChainSpec) { const NUM_NODES: u32 = 10; { let temp = TempDir::new("substrate-connectivity-test").expect("Error creating test dir"); diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 81fb8eddff4fe..e5a2c2576fc8a 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -30,5 +30,3 @@ std = [ "parity-codec/std", "substrate-primitives/std", ] -api-for-runtime = [] - diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 01ef2f171f0c4..c0480591cb199 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -511,57 +511,6 @@ macro_rules! impl_outer_log { }; } -//TODO: https://github.com/paritytech/substrate/issues/1022 -/// Basic Inherent data to include in a block; used by simple runtimes. -#[derive(Encode, Decode)] -pub struct BasicInherentData { - /// Current timestamp. - pub timestamp: u64, - /// Blank report. - pub consensus: (), - /// Aura expected slot. Can take any value during block construction. - pub aura_expected_slot: u64, -} - -impl BasicInherentData { - /// Create a new `BasicInherentData` instance. - pub fn new(timestamp: u64, expected_slot: u64) -> Self { - Self { - timestamp, - consensus: (), - aura_expected_slot: expected_slot, - } - } -} - -//TODO: https://github.com/paritytech/substrate/issues/1022 -/// Error type used while checking inherents. -#[derive(Encode, PartialEq)] -#[cfg_attr(feature = "std", derive(Decode))] -pub enum CheckInherentError { - /// The inherents are generally valid but a delay until the given timestamp - /// is required. - ValidAtTimestamp(u64), - /// Some other error has occurred. - Other(RuntimeString), -} - -impl CheckInherentError { - /// Combine two results, taking the "worse" of the two. - pub fn combine_results Result<(), Self>>(this: Result<(), Self>, other: F) -> Result<(), Self> { - match this { - Ok(()) => other(), - Err(CheckInherentError::Other(s)) => Err(CheckInherentError::Other(s)), - Err(CheckInherentError::ValidAtTimestamp(x)) => match other() { - Ok(()) => Err(CheckInherentError::ValidAtTimestamp(x)), - Err(CheckInherentError::ValidAtTimestamp(y)) - => Err(CheckInherentError::ValidAtTimestamp(rstd::cmp::max(x, y))), - Err(CheckInherentError::Other(s)) => Err(CheckInherentError::Other(s)), - } - } - } -} - /// Simple blob to hold an extrinsic without commiting to its format and ensure it is serialized /// correctly. #[derive(PartialEq, Eq, Clone, Default, Encode, Decode)] diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 8723dbec91ed7..623d04a938bac 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -621,26 +621,6 @@ pub trait DigestItem: Codec + Member + MaybeSerializeDebugButNotDeserialize { fn as_changes_trie_root(&self) -> Option<&Self::Hash>; } -/// Something that provides an inherent for a runtime. -pub trait ProvideInherent { - /// The inherent that is provided. - type Inherent: Encode + MaybeDecode; - /// The call for setting the inherent. - type Call: Encode + MaybeDecode; - - /// Create the inherent extrinsics. - /// - /// # Return - /// - /// Returns a vector with tuples containing the index for the extrinsic and the extrinsic itself. - fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)>; - - /// Check that the given inherent is valid. - fn check_inherent Option<&Self::Call>>( - block: &Block, data: Self::Inherent, extract_function: &F - ) -> Result<(), super::CheckInherentError>; -} - /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. pub struct ApiRef<'a, T>(T, rstd::marker::PhantomData<&'a ()>); diff --git a/core/test-client/src/block_builder_ext.rs b/core/test-client/src/block_builder_ext.rs index 5803c5303d4e5..f2febf8836a63 100644 --- a/core/test-client/src/block_builder_ext.rs +++ b/core/test-client/src/block_builder_ext.rs @@ -29,9 +29,9 @@ pub trait BlockBuilderExt { fn push_transfer(&mut self, transfer: runtime::Transfer) -> Result<(), client::error::Error>; } -impl<'a, A> BlockBuilderExt for client::block_builder::BlockBuilder<'a, runtime::Block, (), A> where +impl<'a, A> BlockBuilderExt for client::block_builder::BlockBuilder<'a, runtime::Block, A> where A: ProvideRuntimeApi + client::blockchain::HeaderBackend + 'a, - A::Api: BlockBuilder + A::Api: BlockBuilder { fn push_transfer(&mut self, transfer: runtime::Transfer) -> Result<(), client::error::Error> { self.push(sign_tx(transfer)) @@ -39,6 +39,9 @@ impl<'a, A> BlockBuilderExt for client::block_builder::BlockBuilder<'a, runtime: } fn sign_tx(transfer: runtime::Transfer) -> runtime::Extrinsic { - let signature = keyring::Keyring::from_raw_public(transfer.from.to_fixed_bytes()).unwrap().sign(&codec::Encode::encode(&transfer)).into(); + let signature = keyring::Keyring::from_raw_public(transfer.from.to_fixed_bytes()) + .unwrap() + .sign(&codec::Encode::encode(&transfer)) + .into(); runtime::Extrinsic::Transfer(transfer, signature) } diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index f7838450cc10f..d1e81350496f3 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -13,6 +13,7 @@ parity-codec-derive = { version = "2.1", default-features = false } substrate-keyring = { path = "../keyring", optional = true } substrate-client = { path = "../client", default-features = false } substrate-primitives = { path = "../primitives", default-features = false } +substrate-inherents = { path = "../inherents", default-features = false } substrate-consensus-aura-primitives = { path = "../consensus/aura/primitives", default-features = false } sr-std = { path = "../sr-std", default-features = false } sr-io = { path = "../sr-io", default-features = false } @@ -37,6 +38,7 @@ std = [ "sr-io/std", "srml-support/std", "substrate-primitives/std", + "substrate-inherents/std", "sr-primitives/std", "sr-version/std", "substrate-consensus-aura-primitives/std", diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index fd87782e38a4d..e60025de31dc2 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -24,6 +24,7 @@ extern crate serde; extern crate sr_std as rstd; extern crate parity_codec as codec; extern crate sr_primitives as runtime_primitives; +extern crate substrate_inherents as inherents; extern crate substrate_consensus_aura_primitives as consensus_aura; #[macro_use] @@ -59,7 +60,7 @@ use runtime_primitives::{ traits::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, GetNodeBlockType, GetRuntimeBlockType - }, CheckInherentError + } }; use runtime_version::RuntimeVersion; pub use primitives::hash::H256; @@ -67,6 +68,7 @@ use primitives::{Ed25519AuthorityId, OpaqueMetadata}; #[cfg(any(feature = "std", test))] use runtime_version::NativeVersion; use consensus_aura::api as aura_api; +use inherents::{CheckInherentsResult, InherentData}; /// Test runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -238,7 +240,7 @@ impl_runtime_apis! { } } - impl block_builder_api::BlockBuilder for Runtime { + impl block_builder_api::BlockBuilder for Runtime { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult { system::execute_transaction(extrinsic) } @@ -247,12 +249,12 @@ impl_runtime_apis! { system::finalise_block() } - fn inherent_extrinsics(_data: ()) -> Vec<::Extrinsic> { + fn inherent_extrinsics(_data: InherentData) -> Vec<::Extrinsic> { unimplemented!() } - fn check_inherents(_block: Block, _data: ()) -> Result<(), CheckInherentError> { - Ok(()) + fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult { + CheckInherentsResult::new() } fn random_seed() -> ::Hash { diff --git a/core/test-runtime/wasm/Cargo.lock b/core/test-runtime/wasm/Cargo.lock index d8aad89ba7967..0c20da9c2b98d 100644 --- a/core/test-runtime/wasm/Cargo.lock +++ b/core/test-runtime/wasm/Cargo.lock @@ -542,12 +542,12 @@ dependencies = [ [[package]] name = "parity-codec-derive" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -914,7 +914,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -935,7 +935,7 @@ version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -947,7 +947,7 @@ name = "srml-metadata" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", @@ -969,6 +969,7 @@ dependencies = [ "sr-std 0.1.0", "srml-metadata 0.1.0", "srml-support-procedural 0.1.0", + "substrate-inherents 0.1.0", ] [[package]] @@ -1032,6 +1033,7 @@ dependencies = [ "sr-version 0.1.0", "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", @@ -1060,10 +1062,11 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1090,6 +1093,17 @@ dependencies = [ "wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-inherents" +version = "0.1.0" +dependencies = [ + "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 0.1.0", + "sr-std 0.1.0", +] + [[package]] name = "substrate-keyring" version = "0.1.0" @@ -1111,7 +1125,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1168,7 +1182,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1178,6 +1192,7 @@ dependencies = [ "srml-support 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", ] @@ -1200,16 +1215,6 @@ dependencies = [ "trie-root 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.15.22" @@ -1625,7 +1630,7 @@ dependencies = [ "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b6a1290fe78aa6bbb5f3338ecede3062687a98b9e40cd1dbcaa47261d44097" -"checksum parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa42c2cb493b60b12c75b26e8c94cb734af4df4d7f2cc229dc04c1953dac189" +"checksum parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2632f530f37c8b939c7c194636a82ecbe41ab115e74e88f947ad41e483bbf19" "checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" @@ -1669,7 +1674,6 @@ dependencies = [ "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" diff --git a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 4cc222f4566adf48ae5a9cd51af7b58597718d05..204a87d33d1b29908e7f10e9f3e242104cadc20a 100644 GIT binary patch delta 21448 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 XWf~I6MsTv-kf?8+oT#6iXsP>OX}1cN delta 8890 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 diff --git a/core/trie/src/node_header.rs b/core/trie/src/node_header.rs index e337661bfdc1d..99b1241cab452 100644 --- a/core/trie/src/node_header.rs +++ b/core/trie/src/node_header.rs @@ -34,10 +34,10 @@ impl Encode for NodeHeader { fn encode_to(&self, output: &mut T) { match self { NodeHeader::Null => output.push_byte(EMPTY_TRIE), - + NodeHeader::Branch(true) => output.push_byte(BRANCH_NODE_WITH_VALUE), NodeHeader::Branch(false) => output.push_byte(BRANCH_NODE_NO_VALUE), - + NodeHeader::Leaf(nibble_count) if *nibble_count < LEAF_NODE_THRESHOLD as usize => output.push_byte(LEAF_NODE_OFFSET + *nibble_count as u8), NodeHeader::Leaf(nibble_count) => { @@ -72,7 +72,6 @@ impl Decode for NodeHeader { BRANCH_NODE_NO_VALUE => NodeHeader::Branch(false), // 254 BRANCH_NODE_WITH_VALUE => NodeHeader::Branch(true), // 255 - _ => unreachable!(), }) } diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index f0d570a8d268f..04fa67b4ad030 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -16,6 +16,7 @@ slog = "^2" sr-io = { path = "../../core/sr-io" } substrate-client = { path = "../../core/client" } substrate-primitives = { path = "../../core/primitives" } +substrate-inherents = { path = "../../core/inherents" } node-runtime = { path = "../runtime" } node-primitives = { path = "../primitives" } hex-literal = "0.1" diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 78e6d923410a6..825df6f8e03e0 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -318,6 +318,6 @@ mod tests { #[test] fn test_connectivity() { - service_test::connectivity::(integration_test_config()); + service_test::connectivity::(integration_test_config()); } } diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index 55ab1822ea44e..65c74bebd74d4 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -40,6 +40,7 @@ extern crate node_primitives; extern crate substrate_service; extern crate node_executor; extern crate substrate_keystore; +extern crate substrate_inherents as inherents; #[macro_use] extern crate log; diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 38f34aedf5a0d..dd2b14e74e4d1 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -26,13 +26,14 @@ use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration, Nothing use grandpa; use node_executor; use primitives::ed25519::Pair; -use node_primitives::{Block, InherentData}; +use node_primitives::Block; use node_runtime::{GenesisConfig, RuntimeApi}; use substrate_service::{ FactoryFullConfiguration, LightComponents, FullComponents, FullBackend, - FullClient, LightClient, LightBackend, FullExecutor, LightExecutor, TaskExecutor + FullClient, LightClient, LightBackend, FullExecutor, LightExecutor, TaskExecutor, }; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; +use inherents::InherentDataProviders; construct_simple_protocol! { /// Demo protocol attachment for substrate. @@ -45,12 +46,14 @@ pub struct NodeConfig { // FIXME: rather than putting this on the config, let's have an actual intermediate setup state // https://github.com/paritytech/substrate/issues/1134 pub grandpa_import_setup: Option<(Arc>, grandpa::LinkHalfForService)>, + inherent_data_providers: InherentDataProviders, } impl Default for NodeConfig where F: substrate_service::ServiceFactory { fn default() -> NodeConfig { NodeConfig { grandpa_import_setup: None, + inherent_data_providers: InherentDataProviders::new(), } } } @@ -91,7 +94,8 @@ construct_service_factory! { proposer, service.network(), service.on_exit(), - )); + service.config.custom.inherent_data_providers.clone(), + )?); info!("Running Grandpa session as Authority {}", key.public()); } @@ -99,7 +103,8 @@ construct_service_factory! { executor.spawn(grandpa::run_grandpa( grandpa::Config { local_key, - gossip_duration: Duration::new(4, 0), // FIXME: make this available through chainspec? + // FIXME: make this available through chainspec? + gossip_duration: Duration::new(4, 0), justification_period: 4096, name: Some(service.config.name.clone()) }, @@ -117,35 +122,38 @@ construct_service_factory! { Self::Block, grandpa::BlockImportForService, NothingExtra, - ::consensus::InherentProducingFn, > { |config: &mut FactoryFullConfiguration , client: Arc>| { let slot_duration = SlotDuration::get_or_compute(&*client)?; - let (block_import, link_half) = grandpa::block_import::<_, _, _, RuntimeApi, FullClient>(client.clone(), client)?; + + let (block_import, link_half) = + grandpa::block_import::<_, _, _, RuntimeApi, FullClient>( + client.clone(), client + )?; let block_import = Arc::new(block_import); config.custom.grandpa_import_setup = Some((block_import.clone(), link_half)); - Ok(import_queue( + import_queue( slot_duration, block_import, NothingExtra, - ::consensus::make_basic_inherent as _, - )) + config.custom.inherent_data_providers.clone(), + ).map_err(Into::into) }}, LightImportQueue = AuraImportQueue< Self::Block, LightClient, NothingExtra, - ::consensus::InherentProducingFn, > - { |ref mut config, client: Arc>| - Ok(import_queue( - SlotDuration::get_or_compute(&*client)?, - client, - NothingExtra, - ::consensus::make_basic_inherent as _, - )) + { |config: &FactoryFullConfiguration, client: Arc>| { + import_queue( + SlotDuration::get_or_compute(&*client)?, + client, + NothingExtra, + config.custom.inherent_data_providers.clone(), + ).map_err(Into::into) + } }, } } diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 504ac5db953dc..a114c653b7311 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -33,8 +33,6 @@ extern crate substrate_primitives as primitives; use runtime_primitives::generic; use runtime_primitives::{OpaqueExtrinsic, traits::BlakeTwo256}; -pub use runtime_primitives::BasicInherentData as InherentData; - /// An index to a block. pub type BlockNumber = u64; diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index ed8bae6968ab8..d7599c2c7f9d0 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -64,14 +64,14 @@ use node_primitives::{ }; use grandpa::fg_primitives::{self, ScheduledChange}; use client::{ - block_builder::api as block_builder_api, runtime_api as client_api + block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, + runtime_api as client_api, }; -use runtime_primitives::{ApplyResult, CheckInherentError, BasicInherentData}; +use runtime_primitives::ApplyResult; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::generic; use runtime_primitives::traits::{ - Convert, BlakeTwo256, Block as BlockT, DigestFor, NumberFor, ProvideInherent, - StaticLookup + Convert, BlakeTwo256, Block as BlockT, DigestFor, NumberFor, Extrinsic, StaticLookup, }; use version::RuntimeVersion; use council::{motions as council_motions, voting as council_voting}; @@ -90,9 +90,6 @@ pub use balances::Call as BalancesCall; pub use runtime_primitives::{Permill, Perbill}; pub use srml_support::{StorageValue, RuntimeMetadata}; -const TIMESTAMP_SET_POSITION: u32 = 0; -const NOTE_OFFLINE_POSITION: u32 = 1; - /// Runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), @@ -146,7 +143,6 @@ impl balances::Trait for Runtime { } impl consensus::Trait for Runtime { - const NOTE_OFFLINE_POSITION: u32 = NOTE_OFFLINE_POSITION; type Log = Log; type SessionKey = SessionKey; @@ -156,7 +152,6 @@ impl consensus::Trait for Runtime { } impl timestamp::Trait for Runtime { - const TIMESTAMP_SET_POSITION: u32 = TIMESTAMP_SET_POSITION; type Moment = u64; type OnTimestampSet = Aura; } @@ -228,10 +223,10 @@ construct_runtime!( pub enum Runtime with Log(InternalLog: DigestItem) where Block = Block, NodeBlock = node_primitives::Block, - InherentData = BasicInherentData + UncheckedExtrinsic = UncheckedExtrinsic { System: system::{default, Log(ChangesTrieRoot)}, - Aura: aura::{Module}, + Aura: aura::{Module, Inherent(Timestamp)}, Timestamp: timestamp::{Module, Call, Storage, Config, Inherent}, Consensus: consensus::{Module, Call, Storage, Config, Log(AuthoritiesChange), Inherent}, Indices: indices, @@ -292,7 +287,7 @@ impl_runtime_apis! { } } - impl block_builder_api::BlockBuilder for Runtime { + impl block_builder_api::BlockBuilder for Runtime { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult { Executive::apply_extrinsic(extrinsic) } @@ -301,46 +296,12 @@ impl_runtime_apis! { Executive::finalise_block() } - fn inherent_extrinsics(data: BasicInherentData) -> Vec<::Extrinsic> { - let mut inherent = Vec::new(); - - inherent.extend( - Timestamp::create_inherent_extrinsics(data.timestamp) - .into_iter() - .map(|v| (v.0, UncheckedExtrinsic::new_unsigned(Call::Timestamp(v.1)))) - ); - - inherent.extend( - Consensus::create_inherent_extrinsics(data.consensus) - .into_iter() - .map(|v| (v.0, UncheckedExtrinsic::new_unsigned(Call::Consensus(v.1)))) - ); - - inherent.as_mut_slice().sort_unstable_by_key(|v| v.0); - inherent.into_iter().map(|v| v.1).collect() + fn inherent_extrinsics(data: InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() } - fn check_inherents(block: Block, data: BasicInherentData) -> Result<(), CheckInherentError> { - let expected_slot = data.aura_expected_slot; - - // draw timestamp out from extrinsics. - let set_timestamp = block.extrinsics() - .get(TIMESTAMP_SET_POSITION as usize) - .and_then(|xt: &UncheckedExtrinsic| match xt.function { - Call::Timestamp(TimestampCall::set(ref t)) => Some(t.clone()), - _ => None, - }) - .ok_or_else(|| CheckInherentError::Other("No valid timestamp in block.".into()))?; - - // take the "worse" result of normal verification and the timestamp vs. seal - // check. - CheckInherentError::combine_results( - Runtime::check_inherents(block, data), - || { - Aura::verify_inherent(set_timestamp.into(), expected_slot) - .map_err(|s| CheckInherentError::Other(s.into())) - }, - ) + fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult { + data.check_extrinsics(&block) } fn random_seed() -> ::Hash { diff --git a/node/runtime/wasm/Cargo.lock b/node/runtime/wasm/Cargo.lock index 15e1a533cd625..29511a0dcc1f8 100644 --- a/node/runtime/wasm/Cargo.lock +++ b/node/runtime/wasm/Cargo.lock @@ -468,7 +468,7 @@ name = "node-primitives" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -484,7 +484,7 @@ dependencies = [ "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 0.1.0", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", @@ -600,12 +600,12 @@ dependencies = [ [[package]] name = "parity-codec-derive" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -995,7 +995,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1027,7 +1027,7 @@ version = "0.1.0" dependencies = [ "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -1040,7 +1040,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -1050,6 +1050,7 @@ dependencies = [ "srml-support 0.1.0", "srml-system 0.1.0", "srml-timestamp 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -1059,7 +1060,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1077,13 +1078,14 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (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-support 0.1.0", "srml-system 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -1092,7 +1094,7 @@ name = "srml-contract" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1112,7 +1114,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1131,7 +1133,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1149,7 +1151,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -1164,7 +1166,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1183,7 +1185,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1200,7 +1202,7 @@ name = "srml-metadata" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", @@ -1213,7 +1215,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1232,7 +1234,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1254,7 +1256,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -1280,6 +1282,7 @@ dependencies = [ "sr-std 0.1.0", "srml-metadata 0.1.0", "srml-support-procedural 0.1.0", + "substrate-inherents 0.1.0", ] [[package]] @@ -1318,7 +1321,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.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.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -1334,6 +1337,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -1341,6 +1345,7 @@ dependencies = [ "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", ] @@ -1350,7 +1355,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -1367,7 +1372,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", "sr-primitives 0.1.0", @@ -1410,6 +1415,7 @@ dependencies = [ "sr-version 0.1.0", "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", + "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-state-machine 0.1.0", @@ -1438,10 +1444,11 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-version 0.1.0", + "substrate-inherents 0.1.0", "substrate-primitives 0.1.0", "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1473,13 +1480,24 @@ name = "substrate-finality-grandpa-primitives" version = "0.1.0" dependencies = [ "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "substrate-client 0.1.0", "substrate-primitives 0.1.0", ] +[[package]] +name = "substrate-inherents" +version = "0.1.0" +dependencies = [ + "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 0.1.0", + "sr-std 0.1.0", +] + [[package]] name = "substrate-keyring" version = "0.1.0" @@ -1501,7 +1519,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1562,16 +1580,6 @@ dependencies = [ "trie-root 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.15.22" @@ -1987,7 +1995,7 @@ dependencies = [ "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum parity-codec 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b6a1290fe78aa6bbb5f3338ecede3062687a98b9e40cd1dbcaa47261d44097" -"checksum parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa42c2cb493b60b12c75b26e8c94cb734af4df4d7f2cc229dc04c1953dac189" +"checksum parity-codec-derive 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2632f530f37c8b939c7c194636a82ecbe41ab115e74e88f947ad41e483bbf19" "checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" @@ -2034,7 +2042,6 @@ dependencies = [ "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" diff --git a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index e39414434f6c8c614101f39a5771e9410bec6f1a..f7ce6caae391d283d5f7d6287aa6be69ff69b7c9 100644 GIT binary patch delta 151640 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 result::Result; + /// Replace aura inherent data. + fn aura_replace_inherent_data(&mut self, new: InherentType); +} + +impl AuraInherentData for InherentData { + fn aura_inherent_data(&self) -> result::Result { + self.get_data(&INHERENT_IDENTIFIER) + .and_then(|r| r.ok_or_else(|| "Aura inherent data not found".into())) + } + + fn aura_replace_inherent_data(&mut self, new: InherentType) { + self.replace_data(INHERENT_IDENTIFIER, &new); + } +} + +/// Provides the slot duration inherent data for `Aura`. +#[cfg(feature = "std")] +pub struct InherentDataProvider { + slot_duration: u64, +} + +#[cfg(feature = "std")] +impl InherentDataProvider { + pub fn new(slot_duration: u64) -> Self { + Self { + slot_duration + } + } +} + +#[cfg(feature = "std")] +impl ProvideInherentData for InherentDataProvider { + fn on_register( + &self, + providers: &InherentDataProviders, + ) -> result::Result<(), RuntimeString> { + if !providers.has_provider(×tamp::INHERENT_IDENTIFIER) { + // Add the timestamp inherent data provider, as we require it. + providers.register_provider(timestamp::InherentDataProvider) + } else { + Ok(()) + } + } + + fn inherent_identifier(&self) -> &'static inherents::InherentIdentifier { + &INHERENT_IDENTIFIER + } + + fn provide_inherent_data( + &self, + inherent_data: &mut InherentData, + ) -> result::Result<(), RuntimeString> { + let timestamp = inherent_data.timestamp_inherent_data()?; + let slot_num = timestamp / self.slot_duration; + inherent_data.put_data(INHERENT_IDENTIFIER, &slot_num) + } + + fn error_to_string(&self, error: &[u8]) -> Option { + RuntimeString::decode(&mut &error[..]).map(Into::into) + } +} + /// Something which can handle Aura consensus reports. pub trait HandleReport { fn handle_report(report: AuraReport); @@ -133,20 +210,6 @@ impl Module { >::block_period().as_().saturating_mul(2) } - /// Verify an inherent slot that is used in a block seal against a timestamp - /// extracted from the block. - // TODO: ensure `ProvideInherent` can deal with dependencies like this. - // https://github.com/paritytech/substrate/issues/1228 - pub fn verify_inherent(timestamp: T::Moment, seal_slot: u64) -> Result { - let timestamp_based_slot = timestamp.as_() / Self::slot_duration(); - - if timestamp_based_slot == seal_slot { - Ok(()) - } else { - Err("timestamp set in block doesn't match slot in seal".into()) - } - } - fn on_timestamp_set(now: T::Moment, slot_duration: T::Moment) { let last = Self::last(); ::LastTimestamp::put(now.clone()); @@ -197,3 +260,30 @@ impl HandleReport for StakingSlasher { ); } } + +impl ProvideInherent for Module { + type Call = timestamp::Call; + type Error = MakeFatalError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(_: &InherentData) -> Option { + None + } + + fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> { + let timestamp = match call { + timestamp::Call::set(ref timestamp) => timestamp.clone(), + _ => return Ok(()), + }; + + let timestamp_based_slot = timestamp.as_() / Self::slot_duration(); + + let seal_slot = data.aura_inherent_data()?; + + if timestamp_based_slot == seal_slot { + Ok(()) + } else { + Err(RuntimeString::from("timestamp set in block doesn't match slot in seal").into()) + } + } +} diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 6ff33e6c51ccd..16d2b8128012d 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -32,7 +32,6 @@ impl_outer_origin!{ pub struct Test; impl consensus::Trait for Test { - const NOTE_OFFLINE_POSITION: u32 = 1; type Log = DigestItem; type SessionKey = UintAuthorityId; type InherentOfflineReport = (); @@ -53,8 +52,6 @@ impl system::Trait for Test { } impl timestamp::Trait for Test { - const TIMESTAMP_SET_POSITION: u32 = 0; - type Moment = u64; type OnTimestampSet = Aura; } diff --git a/srml/consensus/Cargo.toml b/srml/consensus/Cargo.toml index 9bc03d85eed47..278482f8168b4 100644 --- a/srml/consensus/Cargo.toml +++ b/srml/consensus/Cargo.toml @@ -9,6 +9,7 @@ serde = { version = "1.0", default-features = false } parity-codec = { version = "2.2", default-features = false } parity-codec-derive = { version = "2.1", default-features = false } substrate-primitives = { path = "../../core/primitives", default-features = false } +substrate-inherents = { path = "../../core/inherents", 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 } @@ -26,4 +27,5 @@ std = [ "srml-support/std", "sr-primitives/std", "srml-system/std", + "substrate-inherents/std", ] diff --git a/srml/consensus/src/lib.rs b/srml/consensus/src/lib.rs index e8ef08e4b9ccb..54da8a5de07d2 100644 --- a/srml/consensus/src/lib.rs +++ b/srml/consensus/src/lib.rs @@ -18,8 +18,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[allow(unused_imports)] -#[macro_use] extern crate sr_std as rstd; #[macro_use] @@ -37,18 +35,19 @@ extern crate substrate_primitives; #[cfg(test)] extern crate sr_io as runtime_io; +extern crate substrate_inherents as inherents; + use rstd::prelude::*; -use rstd::result; use parity_codec::Encode; use runtime_support::{storage, Parameter}; use runtime_support::storage::StorageValue; use runtime_support::storage::unhashed::StorageVec; -use primitives::CheckInherentError; -use primitives::traits::{ - MaybeSerializeDebug, Member, ProvideInherent, Block as BlockT -}; +use primitives::traits::{MaybeSerializeDebug, Member}; use substrate_primitives::storage::well_known_keys; use system::{ensure_signed, ensure_inherent}; +use inherents::{ + ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError +}; #[cfg(any(feature = "std", test))] use substrate_primitives::Ed25519AuthorityId; @@ -56,6 +55,12 @@ use substrate_primitives::Ed25519AuthorityId; mod mock; mod tests; +/// The identifier for consensus inherents. +pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"offlrep0"; + +/// The error type used by this inherent. +pub type InherentError = RuntimeString; + struct AuthorityStorageVec(rstd::marker::PhantomData); impl StorageVec for AuthorityStorageVec { type Item = S; @@ -158,9 +163,6 @@ impl From> for primitives::testing::DigestItem where N: Into> + Into>; @@ -206,12 +208,6 @@ decl_module! { fn note_offline(origin, offline: ::Inherent) { ensure_inherent(origin)?; - assert!( - >::extrinsic_index() == Some(T::NOTE_OFFLINE_POSITION), - "note_offline extrinsic must be at position {} in the block", - T::NOTE_OFFLINE_POSITION - ); - T::InherentOfflineReport::handle_report(offline); } @@ -292,34 +288,38 @@ impl Module { } impl ProvideInherent for Module { - type Inherent = ::Inherent; type Call = Call; - - fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> { - if ::is_empty(&data) { - vec![] + type Error = MakeFatalError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(data: &InherentData) -> Option { + if let Ok(Some(data)) = + data.get_data::<::Inherent>( + &INHERENT_IDENTIFIER + ) + { + if ::is_empty(&data) { + None + } else { + Some(Call::note_offline(data)) + } } else { - vec![(T::NOTE_OFFLINE_POSITION, Call::note_offline(data))] + None } } - fn check_inherent Option<&Self::Call>>( - block: &Block, expected: Self::Inherent, extract_function: &F - ) -> result::Result<(), CheckInherentError> { - let noted_offline = block - .extrinsics() - .get(T::NOTE_OFFLINE_POSITION as usize) - .and_then(|xt| match extract_function(&xt) { - Some(Call::note_offline(ref x)) => Some(x), - _ => None, - }); + fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> { + let offline = match call { + Call::note_offline(ref offline) => offline, + _ => return Ok(()), + }; - // REVIEW: perhaps we should be passing a `None` to check_inherent. - if let Some(noted_offline) = noted_offline { - ::check_inherent(¬ed_offline, &expected) - .map_err(|e| CheckInherentError::Other(e.into()))?; - } + let expected = data + .get_data::<::Inherent>(&INHERENT_IDENTIFIER)? + .ok_or(RuntimeString::from("No `offline_report` found in the inherent data!"))?; - Ok(()) + ::check_inherent( + &offline, &expected + ).map_err(|e| RuntimeString::from(e).into()) } } diff --git a/srml/consensus/src/mock.rs b/srml/consensus/src/mock.rs index 9bf81cd327db5..454aa61c414f4 100644 --- a/srml/consensus/src/mock.rs +++ b/srml/consensus/src/mock.rs @@ -31,7 +31,6 @@ impl_outer_origin!{ #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; impl Trait for Test { - const NOTE_OFFLINE_POSITION: u32 = 1; type Log = DigestItem; type SessionKey = UintAuthorityId; type InherentOfflineReport = ::InstantFinalityReportVec<()>; diff --git a/srml/consensus/src/tests.rs b/srml/consensus/src/tests.rs index 9dc65136fbc28..53d5732173e7c 100644 --- a/srml/consensus/src/tests.rs +++ b/srml/consensus/src/tests.rs @@ -18,9 +18,10 @@ #![cfg(test)] -use primitives::{generic, testing::{self, UintAuthorityId}, traits::{OnFinalise, ProvideInherent}}; +use primitives::{generic, testing::{self, UintAuthorityId}, traits::OnFinalise}; use runtime_io::with_externalities; use mock::{Consensus, System, new_test_ext}; +use inherents::{InherentData, ProvideInherent}; #[test] fn authorities_change_logged() { @@ -31,7 +32,13 @@ fn authorities_change_logged() { let header = System::finalise(); assert_eq!(header.digest, testing::Digest { logs: vec![ - generic::DigestItem::AuthoritiesChange(vec![UintAuthorityId(4).into(), UintAuthorityId(5).into(), UintAuthorityId(6).into()]), + generic::DigestItem::AuthoritiesChange( + vec![ + UintAuthorityId(4).into(), + UintAuthorityId(5).into(), + UintAuthorityId(6).into() + ] + ), ], }); }); @@ -67,7 +74,12 @@ fn authorities_change_is_not_logged_when_changed_back_to_original() { fn offline_report_can_be_excluded() { with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { System::initialise(&1, &Default::default(), &Default::default()); - assert!(Consensus::create_inherent_extrinsics(Vec::new()).is_empty()); - assert_eq!(Consensus::create_inherent_extrinsics(vec![0]).len(), 1); + assert!(Consensus::create_inherent(&InherentData::new()).is_none()); + + let offline_report: Vec = vec![0]; + let mut data = InherentData::new(); + data.put_data(super::INHERENT_IDENTIFIER, &offline_report).unwrap(); + + assert!(Consensus::create_inherent(&data).is_some()); }); } diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index bc316938c0f7f..b758325cea845 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -114,7 +114,6 @@ decl_event!( decl_storage! { trait Store for Module as Session { - /// The current set of validators. pub Validators get(validators) config(): Vec; /// Current length of the session. @@ -246,7 +245,6 @@ mod tests { #[derive(Clone, Eq, PartialEq)] pub struct Test; impl consensus::Trait for Test { - const NOTE_OFFLINE_POSITION: u32 = 1; type Log = DigestItem; type SessionKey = UintAuthorityId; type InherentOfflineReport = (); @@ -265,7 +263,6 @@ mod tests { type Log = DigestItem; } impl timestamp::Trait for Test { - const TIMESTAMP_SET_POSITION: u32 = 0; type Moment = u64; type OnTimestampSet = (); } diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 752922da03dd9..68145a7a70ae3 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -32,7 +32,6 @@ impl_outer_origin!{ #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; impl consensus::Trait for Test { - const NOTE_OFFLINE_POSITION: u32 = 1; type Log = DigestItem; type SessionKey = UintAuthorityId; type InherentOfflineReport = (); @@ -63,7 +62,6 @@ impl session::Trait for Test { type Event = (); } impl timestamp::Trait for Test { - const TIMESTAMP_SET_POSITION: u32 = 0; type Moment = u64; type OnTimestampSet = (); } diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index 6a232215b3874..9210d407d63c0 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -12,6 +12,7 @@ srml-metadata = { path = "../metadata", 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 } +substrate-inherents = { path = "../../core/inherents", default-features = false } srml-support-procedural = { path = "./procedural" } mashup = "0.1.7" once_cell = { version = "0.1.6", default-features = false, optional = true } @@ -32,6 +33,7 @@ std = [ "sr-std/std", "sr-primitives/std", "srml-metadata/std", + "substrate-inherents/std", ] nightly = [] strict = [] diff --git a/srml/support/src/inherent.rs b/srml/support/src/inherent.rs index 925ba91cec532..9c99ba7281150 100644 --- a/srml/support/src/inherent.rs +++ b/srml/support/src/inherent.rs @@ -15,11 +15,11 @@ // along with Substrate. If not, see . #[doc(hidden)] -pub use rstd::{cmp, result::Result, vec::Vec}; +pub use rstd::vec::Vec; #[doc(hidden)] -pub use runtime_primitives::{ - traits::{ProvideInherent, Block as BlockT}, CheckInherentError -}; +pub use runtime_primitives::traits::Block as BlockT; +#[doc(hidden)] +pub use inherents::{InherentData, ProvideInherent, CheckInherentsResult, IsFatalError}; /// Implement the outer inherent. @@ -30,54 +30,72 @@ pub use runtime_primitives::{ /// ```nocompile /// impl_outer_inherent! { /// pub struct InherentData where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic { -/// timestamp: Timestamp export Error as TimestampInherentError, +/// timestamp: Timestamp, /// consensus: Consensus, +/// /// Aura module using the `Timestamp` call. +/// aura: Timestamp, /// } /// } /// ``` -/// -/// Additional parameters after `UncheckedExtrinsic` are `Error` and `Call`. #[macro_export] macro_rules! impl_outer_inherent { ( - for $runtime:ident, - Block = $block:ident, - InherentData = $inherent:ty + impl Inherents where Block = $block:ident, UncheckedExtrinsic = $uncheckedextrinsic:ident { - $( $module:ident: $module_ty:ident,)* + $( $module:ident: $call:ident, )* } ) => { - impl $runtime { - fn check_inherents( - block: $block, - data: $inherent - ) -> $crate::inherent::Result<(), $crate::inherent::CheckInherentError> { - use $crate::inherent::CheckInherentError; + trait InherentDataExt { + fn create_extrinsics(&self) -> + $crate::inherent::Vec<<$block as $crate::inherent::BlockT>::Extrinsic>; + fn check_extrinsics(&self, block: &$block) -> $crate::inherent::CheckInherentsResult; + } - let mut max_valid_after = None; - $( - let res = <$module_ty as $crate::inherent::ProvideInherent>::check_inherent( - &block, - data.$module, - &|xt| match xt.function { - Call::$module_ty(ref data) => Some(data), - _ => None, - }, - ); + impl InherentDataExt for $crate::inherent::InherentData { + fn create_extrinsics(&self) -> + $crate::inherent::Vec<<$block as $crate::inherent::BlockT>::Extrinsic> { + use $crate::inherent::ProvideInherent; + + let mut inherents = Vec::new(); - match res { - Err(CheckInherentError::ValidAtTimestamp(t)) => - max_valid_after = $crate::inherent::cmp::max(max_valid_after, Some(t)), - res => res? + $( + if let Some(inherent) = $module::create_inherent(self) { + inherents.push($uncheckedextrinsic::new_unsigned( + Call::$call(inherent)) + ); } )* - // once everything else has checked out, take the maximum of - // all things which are timestamp-restricted. - match max_valid_after { - Some(t) => Err(CheckInherentError::ValidAtTimestamp(t)), - None => Ok(()) + inherents + } + + fn check_extrinsics(&self, block: &$block) -> $crate::inherent::CheckInherentsResult { + use $crate::inherent::{ProvideInherent, IsFatalError}; + + let mut result = $crate::inherent::CheckInherentsResult::new(); + for xt in block.extrinsics() { + if xt.is_signed().unwrap_or(false) { + break; + } + + $( + match xt.function { + Call::$call(ref call) => { + if let Err(e) = $module::check_inherent(call, self) { + result.put_error( + $module::INHERENT_IDENTIFIER, &e + ).expect("There is only one fatal error; qed"); + if e.is_fatal_error() { + return result; + } + } + } + _ => {}, + } + )* } + + result } } }; diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index ec285590d20d0..5ad29858394b6 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -32,6 +32,7 @@ extern crate srml_metadata; extern crate mashup; #[cfg_attr(test, macro_use)] extern crate srml_support_procedural; +extern crate substrate_inherents as inherents; #[cfg(test)] #[macro_use] diff --git a/srml/support/src/runtime.rs b/srml/support/src/runtime.rs index d658de3426e53..f215e18a833e6 100644 --- a/srml/support/src/runtime.rs +++ b/srml/support/src/runtime.rs @@ -20,11 +20,11 @@ //! mostly for to combine data types and metadata of the included modules. /// Construct a runtime, with the given name and the given modules. -/// +/// /// The parameters here are specific types for Block, NodeBlock and InherentData /// (TODO: describe the difference between Block and NodeBlock) /// and the modules that are used by the runtime. -/// +/// /// # Example: /// /// ```nocompile @@ -32,7 +32,7 @@ /// pub enum Runtime with Log(interalIdent: DigestItem) where /// Block = Block, /// NodeBlock = runtime::Block, -/// InherentData = BasicInherentData +/// UncheckedExtrinsic = UncheckedExtrinsic /// { /// System: system, /// Test: test::{default, Log(Test)}, @@ -44,10 +44,10 @@ /// The module `System: system` will expand to `System: system::{Module, Call, Storage, Event, Config}`. /// The identifier `System` is the name of the module and the lower case identifier `system` is the /// name of the Rust module/crate for this Substrate module. -/// +/// /// The module `Test: test::{default, Log(Test)}` will expand to /// `Test: test::{Module, Call, Storage, Event, Config, Log(Test)}`. -/// +/// /// The module `Test2: test_with_long_module::{Module}` will expand to /// `Test2: test_with_long_module::{Module}`. /// @@ -59,9 +59,9 @@ /// - `Origin` or `Origin` (if the origin is generic) /// - `Config` or `Config` (if the config is generic) /// - `Log( $(IDENT),* )` -/// -/// The -/// +/// - `Inherent $( (CALL) )*` - If the module provides/can check inherents. The optional parameter +/// is for modules that use a `Call` from a different module as +/// inherent. #[macro_export] macro_rules! construct_runtime { @@ -73,7 +73,7 @@ macro_rules! construct_runtime { where Block = $block:ident, NodeBlock = $node_block:ty, - InherentData = $inherent:ty + UncheckedExtrinsic = $uncheckedextrinsic:ident { $( $rest:tt )* } @@ -82,7 +82,7 @@ macro_rules! construct_runtime { $runtime; $block; $node_block; - $inherent; + $uncheckedextrinsic; $log_internal < $( $log_genarg ),* >; ; $( $rest )* @@ -92,7 +92,7 @@ macro_rules! construct_runtime { $runtime:ident; $block:ident; $node_block:ty; - $inherent:ty; + $uncheckedextrinsic:ident; $log_internal:ident <$( $log_genarg:ty ),+>; $( $expanded_name:ident: $expanded_module:ident::{ @@ -120,7 +120,7 @@ macro_rules! construct_runtime { $runtime; $block; $node_block; - $inherent; + $uncheckedextrinsic; $log_internal < $( $log_genarg ),* >; $( $expanded_name: $expanded_module::{ @@ -148,7 +148,7 @@ macro_rules! construct_runtime { $runtime:ident; $block:ident; $node_block:ty; - $inherent:ty; + $uncheckedextrinsic:ident; $log_internal:ident <$( $log_genarg:ty ),+>; $( $expanded_name:ident: $expanded_module:ident::{ @@ -183,7 +183,7 @@ macro_rules! construct_runtime { $runtime; $block; $node_block; - $inherent; + $uncheckedextrinsic; $log_internal < $( $log_genarg ),* >; $( $expanded_name: $expanded_module::{ @@ -217,7 +217,7 @@ macro_rules! construct_runtime { $runtime:ident; $block:ident; $node_block:ty; - $inherent:ty; + $uncheckedextrinsic:ident; $log_internal:ident <$( $log_genarg:ty ),+>; $( $expanded_name:ident: $expanded_module:ident::{ @@ -251,7 +251,7 @@ macro_rules! construct_runtime { $runtime; $block; $node_block; - $inherent; + $uncheckedextrinsic; $log_internal < $( $log_genarg ),* >; $( $expanded_name: $expanded_module::{ @@ -287,7 +287,7 @@ macro_rules! construct_runtime { $runtime:ident; $block:ident; $node_block:ty; - $inherent:ty; + $uncheckedextrinsic:ident; $log_internal:ident <$( $log_genarg:ty ),+>; $( $name:ident: $module:ident::{ @@ -299,9 +299,9 @@ macro_rules! construct_runtime { } ),*; ) => { - // This generates a substrate_generate_ident_name macro that will substitute + // This generates a substrate_generate_ident_name macro that will substitute // "config-ident FooModule" => FooModuleConfig for every module included in the - // runtime. + // runtime. mashup! { $( substrate_generate_ident_name["config-ident" $name] = $name Config; @@ -370,19 +370,19 @@ macro_rules! construct_runtime { __decl_outer_inherent!( $runtime; $block; - $inherent; + $uncheckedextrinsic; ; $( - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } + $name: $module::{ $( $modules $( ( $( $modules_args ),* ) )* ),* } ),*; ); } } /// A macro that generates a "__decl" private macro that transforms parts of the runtime definition -/// to feed them into a public "impl" macro which accepts the format +/// to feed them into a public "impl" macro which accepts the format /// "pub enum $name for $runtime where system = $system". -/// +/// /// Used to define Event and Origin associated types. #[macro_export] #[doc(hidden)] @@ -1109,23 +1109,23 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $inherent:ty; - $( $parsed_modules:ident :: $parsed_name:ident ),*; + $uncheckedextrinsic:ident; + $( $parsed_name:ident :: $parsed_call:ident ),*; $name:ident: $module:ident::{ - Inherent $(, $modules:ident $( <$modules_generic:ident> )* )* + Inherent $(, $modules:ident $( ( $( $modules_call:ident )* ) )* )* } $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* + $( $rest_modules:ident $( ( $( $rest_call:ident )* ) )* ),* })*; ) => { __decl_outer_inherent!( $runtime; $block; - $inherent; - $( $parsed_modules :: $parsed_name, )* $module::$name; + $uncheckedextrinsic; + $( $parsed_name :: $parsed_call, )* $name::$name; $( $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* + $( $rest_modules $( ( $( $rest_call )* ) )* ),* } ),*; ); @@ -1133,24 +1133,49 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $inherent:ty; - $( $parsed_modules:ident :: $parsed_name:ident ),*; + $uncheckedextrinsic:ident; + $( $parsed_name:ident :: $parsed_call:ident ),*; $name:ident: $module:ident::{ - $ingore:ident $( <$ignor:ident> )* $(, $modules:ident $( <$modules_generic:ident> )* )* + Inherent ( $call:ident ) $(, $modules:ident $( ( $( $modules_call:ident )* ) )* )* } $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* + $( $rest_modules:ident $( ( $( $rest_call:ident )* ) )* ),* })*; ) => { __decl_outer_inherent!( $runtime; $block; - $inherent; - $( $parsed_modules :: $parsed_name ),*; - $name: $module::{ $( $modules $( <$modules_generic> )* ),* } + $uncheckedextrinsic; + $( $parsed_name :: $parsed_call, )* $name::$call; + $( + $rest_name: $rest_module::{ + $( $rest_modules $( ( $( $rest_call )* ) )* ),* + } + ),*; + ); + }; + ( + $runtime:ident; + $block:ident; + $uncheckedextrinsic:ident; + $( $parsed_name:ident :: $parsed_call:ident ),*; + $name:ident: $module:ident::{ + $ingore:ident $( ( $( $ignor:ident )* ) )* + $(, $modules:ident $( ( $( $modules_call:ident )* ) )* )* + } + $(, $rest_name:ident : $rest_module:ident::{ + $( $rest_modules:ident $( ( $( $rest_call:ident )* ) )* ),* + })*; + ) => { + __decl_outer_inherent!( + $runtime; + $block; + $uncheckedextrinsic; + $( $parsed_name :: $parsed_call ),*; + $name: $module::{ $( $modules $( ( $( $modules_call )* ) )* ),* } $( , $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* + $( $rest_modules $( ( $( $rest_call )* ) )* ),* } )*; ); @@ -1158,21 +1183,21 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $inherent:ty; - $( $parsed_modules:ident :: $parsed_name:ident ),*; + $uncheckedextrinsic:ident; + $( $parsed_name:ident :: $parsed_call:ident ),*; $name:ident: $module:ident::{} $(, $rest_name:ident : $rest_module:ident::{ - $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* + $( $rest_modules:ident $( ( $( $rest_call:ident )* ) )* ),* })*; ) => { __decl_outer_inherent!( $runtime; $block; - $inherent; - $( $parsed_modules :: $parsed_name ),*; + $uncheckedextrinsic; + $( $parsed_name :: $parsed_call ),*; $( $rest_name: $rest_module::{ - $( $rest_modules $( <$rest_modules_generic> )* ),* + $( $rest_modules $( ( $( $rest_call )* ) )* ),* } ),*; ); @@ -1180,15 +1205,13 @@ macro_rules! __decl_outer_inherent { ( $runtime:ident; $block:ident; - $inherent:ty; - $( $parsed_modules:ident :: $parsed_name:ident ),*; + $uncheckedextrinsic:ident; + $( $parsed_name:ident :: $parsed_call:ident ),*; ; ) => { impl_outer_inherent!( - for $runtime, - Block = $block, - InherentData = $inherent { - $($parsed_modules : $parsed_name,)* + impl Inherents where Block = $block, UncheckedExtrinsic = $uncheckedextrinsic { + $( $parsed_name : $parsed_call, )* } ); }; diff --git a/srml/timestamp/Cargo.toml b/srml/timestamp/Cargo.toml index 4e3ca526ade47..3761719a5269c 100644 --- a/srml/timestamp/Cargo.toml +++ b/srml/timestamp/Cargo.toml @@ -7,10 +7,12 @@ authors = ["Parity Technologies "] hex-literal = "0.1.0" serde = { version = "1.0", default-features = false } parity-codec = { version = "2.2", default-features = false } +parity-codec-derive = { version = "2.2", 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 } +substrate-inherents = { path = "../../core/inherents", default-features = false } srml-support = { path = "../support", default-features = false } srml-system = { path = "../system", default-features = false } srml-consensus = { path = "../consensus", default-features = false } @@ -28,6 +30,8 @@ std = [ "srml-consensus/std", "serde/std", "parity-codec/std", + "parity-codec-derive/std", "substrate-primitives/std", "srml-system/std", + "substrate-inherents/std", ] diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 8f78aabefedfd..6b401b8446b39 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -32,7 +32,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[cfg_attr(not(feature = "std"), macro_use)] extern crate sr_std as rstd; #[macro_use] @@ -46,15 +45,95 @@ extern crate sr_primitives as runtime_primitives; extern crate srml_system as system; extern crate srml_consensus as consensus; extern crate parity_codec as codec; +#[macro_use] +extern crate parity_codec_derive; +extern crate substrate_inherents as inherents; use runtime_support::{StorageValue, Parameter}; -use runtime_primitives::CheckInherentError; -use runtime_primitives::traits::{ - As, SimpleArithmetic, Zero, ProvideInherent, Block as BlockT, Extrinsic -}; +use runtime_primitives::traits::{As, SimpleArithmetic, Zero}; use system::ensure_inherent; -use rstd::{result, ops::{Mul, Div}, vec::Vec}; +use rstd::{result, ops::{Mul, Div}, cmp}; use runtime_support::for_each_tuple; +use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData}; +#[cfg(feature = "std")] +use inherents::ProvideInherentData; + +/// The identifier for the `timestamp` inherent. +pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0"; +/// The type of the inherent. +pub type InherentType = u64; + +/// Errors that can occur while checking the timestamp inherent. +#[derive(Encode)] +#[cfg_attr(feature = "std", derive(Debug, Decode))] +pub enum InherentError { + /// The timestamp is valid in the future. + /// This is a non-fatal-error and will not stop checking the inherents. + ValidAtTimestamp(InherentType), + /// Some other error. + Other(RuntimeString), +} + +impl IsFatalError for InherentError { + fn is_fatal_error(&self) -> bool { + match self { + InherentError::ValidAtTimestamp(_) => false, + InherentError::Other(_) => true, + } + } +} + +impl InherentError { + /// Try to create an instance ouf of the given identifier and data. + #[cfg(feature = "std")] + pub fn try_from(id: &InherentIdentifier, data: &[u8]) -> Option { + if id == &INHERENT_IDENTIFIER { + ::decode(&mut &data[..]) + } else { + None + } + } +} + +/// Auxiliary trait to extract timestamp inherent data. +pub trait TimestampInherentData { + /// Get timestamp inherent data. + fn timestamp_inherent_data(&self) -> Result; +} + +impl TimestampInherentData for InherentData { + fn timestamp_inherent_data(&self) -> Result { + self.get_data(&INHERENT_IDENTIFIER) + .and_then(|r| r.ok_or_else(|| "Timestamp inherent data not found".into())) + } +} + +#[cfg(feature = "std")] +pub struct InherentDataProvider; + +#[cfg(feature = "std")] +impl ProvideInherentData for InherentDataProvider { + fn inherent_identifier(&self) -> &'static InherentIdentifier { + &INHERENT_IDENTIFIER + } + + fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), RuntimeString> { + use std::time::SystemTime; + + let now = SystemTime::now(); + now.duration_since(SystemTime::UNIX_EPOCH) + .map_err(|_| { + "Current time is before unix epoch".into() + }).and_then(|d| { + let duration: InherentType = d.as_secs(); + inherent_data.put_data(INHERENT_IDENTIFIER, &duration) + }) + } + + fn error_to_string(&self, error: &[u8]) -> Option { + InherentError::try_from(&INHERENT_IDENTIFIER, error).map(|e| format!("{:?}", e)) + } +} /// A trait which is called when the timestamp is set. pub trait OnTimestampSet { @@ -80,11 +159,10 @@ macro_rules! impl_timestamp_set { for_each_tuple!(impl_timestamp_set); pub trait Trait: consensus::Trait + system::Trait { - /// The position of the required timestamp-set extrinsic. - const TIMESTAMP_SET_POSITION: u32; - /// Type used for expressing timestamp. - type Moment: Parameter + Default + SimpleArithmetic + Mul + Div; + type Moment: Parameter + Default + SimpleArithmetic + + Mul + + Div; /// Something which can be notified when the timestamp is set. Set this to `()` if not needed. type OnTimestampSet: OnTimestampSet; } @@ -102,11 +180,6 @@ decl_module! { fn set(origin, #[compact] now: T::Moment) { ensure_inherent(origin)?; assert!(!::DidUpdate::exists(), "Timestamp must be updated only once in the block"); - assert!( - >::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 between sequential blocks" @@ -152,33 +225,39 @@ impl Module { } } +fn extract_inherent_data(data: &InherentData) -> Result { + data.get_data::(&INHERENT_IDENTIFIER) + .map_err(|_| RuntimeString::from("Invalid timestamp inherent data encoding."))? + .ok_or_else(|| "Timestamp inherent data is not provided.".into()) +} + impl ProvideInherent for Module { - type Inherent = T::Moment; type Call = Call; + type Error = InherentError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(data: &InherentData) -> Option { + let data = extract_inherent_data(data).expect("Gets and decodes timestamp inherent data"); - fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> { - let next_time = ::rstd::cmp::max(data, Self::now() + Self::block_period()); - vec![(T::TIMESTAMP_SET_POSITION, Call::set(next_time.into()))] + let next_time = cmp::max(As::sa(data), Self::now() + Self::block_period()); + Some(Call::set(next_time.into())) } - fn check_inherent Option<&Self::Call>>( - block: &Block, data: Self::Inherent, extract_function: &F - ) -> result::Result<(), CheckInherentError> { + fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> { const MAX_TIMESTAMP_DRIFT: u64 = 60; - let xt = block.extrinsics().get(T::TIMESTAMP_SET_POSITION as usize) - .ok_or_else(|| CheckInherentError::Other("No valid timestamp inherent in block".into()))?; - - let t = match (xt.is_signed(), extract_function(&xt)) { - (Some(false), Some(Call::set(ref t))) => t.clone(), - _ => return Err(CheckInherentError::Other("No valid timestamp inherent in block".into())), + let t = match call { + Call::set(ref t) => t.clone(), + _ => return Ok(()), }.as_(); + let data = extract_inherent_data(data).map_err(|e| InherentError::Other(e))?; + let minimum = (Self::now() + Self::block_period()).as_(); - if t > data.as_() + MAX_TIMESTAMP_DRIFT { - Err(CheckInherentError::Other("Timestamp too far in future to accept".into())) + if t > data + MAX_TIMESTAMP_DRIFT { + Err(InherentError::Other("Timestamp too far in future to accept".into())) } else if t < minimum { - Err(CheckInherentError::ValidAtTimestamp(minimum)) + Err(InherentError::ValidAtTimestamp(minimum)) } else { Ok(()) } @@ -215,13 +294,11 @@ mod tests { type Log = DigestItem; } impl consensus::Trait for Test { - const NOTE_OFFLINE_POSITION: u32 = 1; type Log = DigestItem; type SessionKey = UintAuthorityId; type InherentOfflineReport = (); } impl Trait for Test { - const TIMESTAMP_SET_POSITION: u32 = 0; type Moment = u64; type OnTimestampSet = (); }