diff --git a/Cargo.lock b/Cargo.lock index dc5a35c2e8e1e..08803e885aa91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2729,6 +2729,7 @@ dependencies = [ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", + "substrate-codec-derive 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-io 0.1.0", "substrate-runtime-primitives 0.1.0", diff --git a/demo/runtime/src/lib.rs b/demo/runtime/src/lib.rs index 69cf3536335b0..feee8626adb5f 100644 --- a/demo/runtime/src/lib.rs +++ b/demo/runtime/src/lib.rs @@ -53,10 +53,9 @@ extern crate substrate_runtime_timestamp as timestamp; extern crate substrate_runtime_version as version; extern crate demo_primitives; -use rstd::prelude::*; use demo_primitives::{AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature}; use runtime_primitives::generic; -use runtime_primitives::traits::{Convert, BlakeTwo256}; +use runtime_primitives::traits::{Convert, BlakeTwo256, DigestItem}; use version::RuntimeVersion; #[cfg(any(feature = "std", test))] @@ -90,9 +89,9 @@ impl system::Trait for Runtime { type BlockNumber = BlockNumber; type Hash = Hash; type Hashing = BlakeTwo256; - type Digest = generic::Digest>; + type Digest = generic::Digest; type AccountId = AccountId; - type Header = generic::Header>; + type Header = generic::Header; type Event = Event; } @@ -112,6 +111,7 @@ pub type Balances = balances::Module; impl consensus::Trait for Runtime { const NOTE_OFFLINE_POSITION: u32 = 1; + type Log = Log; type SessionKey = SessionKey; type OnOfflineValidator = Staking; } @@ -173,6 +173,22 @@ impl_outer_event! { } } +impl_outer_log! { + pub enum Log for Runtime { + consensus + } +} + +impl DigestItem for Log { + type AuthoritiesChange = consensus::AuthoritiesChange; + + fn as_authorities_change(&self) -> Option<&Self::AuthoritiesChange> { + match *self { + Log::consensus(ref item) => item.as_authorities_change(), + } + } +} + impl_outer_dispatch! { #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] @@ -203,7 +219,7 @@ impl_outer_dispatch! { /// The address format for describing accounts. pub type Address = balances::Address; /// Block header type as expected by this runtime. -pub type Header = generic::Header>; +pub type Header = generic::Header; /// Block type as expected by this runtime. pub type Block = generic::Block; /// BlockId type as expected by this runtime. diff --git a/demo/runtime/wasm/Cargo.lock b/demo/runtime/wasm/Cargo.lock index 38caaf9e7c531..5a7006c298ada 100644 --- a/demo/runtime/wasm/Cargo.lock +++ b/demo/runtime/wasm/Cargo.lock @@ -629,6 +629,7 @@ dependencies = [ "serde 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", + "substrate-codec-derive 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-io 0.1.0", "substrate-runtime-primitives 0.1.0", diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index 9537c10de5fc7..1e64ab9760537 100644 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index 7f99674df3237..a7ed5f219890e 100755 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ diff --git a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm index 0ff8c1db3e8e2..75c6ebda9e7f2 100644 Binary files a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm and b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm differ diff --git a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm index 15717f1d28d82..34d64bb11aca2 100755 Binary files a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm and b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm differ diff --git a/substrate/runtime-support/src/lib.rs b/substrate/runtime-support/src/lib.rs index ed22c6413e90d..54985efa25031 100644 --- a/substrate/runtime-support/src/lib.rs +++ b/substrate/runtime-support/src/lib.rs @@ -121,3 +121,27 @@ macro_rules! impl_outer_event { )* } } + +#[macro_export] +macro_rules! impl_outer_log { + + ($(#[$attr:meta])* pub enum $name:ident for $trait:ident { $( $module:ident ),* }) => { + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. + #[derive(Clone, PartialEq, Eq, Encode, Decode)] + #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] + $(#[$attr])* + #[allow(non_camel_case_types)] + pub enum $name { + $( + $module($module::Log<$trait>), + )* + } + $( + impl From<$module::Log<$trait>> for $name { + fn from(x: $module::Log<$trait>) -> Self { + $name::$module(x) + } + } + )* + }; +} diff --git a/substrate/runtime/consensus/Cargo.toml b/substrate/runtime/consensus/Cargo.toml index c9af11fc19683..dfdebbddc118f 100644 --- a/substrate/runtime/consensus/Cargo.toml +++ b/substrate/runtime/consensus/Cargo.toml @@ -8,6 +8,7 @@ hex-literal = "0.1.0" serde = { version = "1.0", default_features = false } serde_derive = { version = "1.0", optional = true } substrate-codec = { path = "../../codec", default_features = false } +substrate-codec-derive = { path = "../../codec/derive", default_features = false } substrate-primitives = { path = "../../primitives", default_features = false } substrate-runtime-std = { path = "../../runtime-std", default_features = false } substrate-runtime-io = { path = "../../runtime-io", default_features = false } @@ -21,6 +22,7 @@ std = [ "serde/std", "serde_derive", "substrate-codec/std", + "substrate-codec-derive/std", "substrate-primitives/std", "substrate-runtime-std/std", "substrate-runtime-io/std", diff --git a/substrate/runtime/consensus/src/lib.rs b/substrate/runtime/consensus/src/lib.rs index df6d034c8f555..5aee25a71afac 100644 --- a/substrate/runtime/consensus/src/lib.rs +++ b/substrate/runtime/consensus/src/lib.rs @@ -32,6 +32,9 @@ extern crate serde; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate substrate_codec_derive; + extern crate substrate_runtime_io as runtime_io; extern crate substrate_runtime_primitives as primitives; extern crate substrate_codec as codec; @@ -41,8 +44,9 @@ extern crate substrate_primitives; use rstd::prelude::*; use runtime_support::{storage, Parameter}; use runtime_support::dispatch::Result; +use runtime_support::storage::StorageValue; use runtime_support::storage::unhashed::StorageVec; -use primitives::traits::{MaybeSerializeDebug, MaybeEmpty}; +use primitives::traits::{MaybeSerializeDebug, MaybeEmpty, OnFinalise, Member, AuthoritiesChangeDigest}; use primitives::bft::MisbehaviorReport; #[cfg(any(feature = "std", test))] @@ -71,14 +75,71 @@ impl OnOfflineValidator for () { fn on_offline_validator(_validator_index: usize) {} } +pub type Log = RawLog< + ::SessionKey, +>; + +/// An logs in this module. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, PartialEq, Eq, Clone)] +pub enum RawLog { + /// Authorities set has been changed. Contains the new set of authorities. + AuthoritiesChange(AuthoritiesChange), +} + +impl RawLog { + /// Try to cast the log entry as AuthoritiesChange log entry. + pub fn as_authorities_change(&self) -> Option<&AuthoritiesChange> { + match *self { + RawLog::AuthoritiesChange(ref item) => Some(item), + } + } +} + +/// Authorities change log entry. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, PartialEq, Eq, Clone)] +pub struct AuthoritiesChange { + /// New set of authorities. + pub new_authorities: Vec, +} + +// Implementation for tests outside of this crate. +impl From> for u64 { + fn from(log: RawLog) -> u64 { + match log { + RawLog::AuthoritiesChange(_) => 1, + } + } +} + +impl AuthoritiesChangeDigest for AuthoritiesChange { + type AuthorityId = SessionKey; + + fn authorities(&self) -> &[Self::AuthorityId] { + &self.new_authorities + } +} + pub trait Trait: system::Trait { /// The allowed extrinsic position for `note_offline` inherent. const NOTE_OFFLINE_POSITION: u32; + /// Type for all log entries of this module. + type Log: From> + Into>; + type SessionKey: Parameter + Default + MaybeSerializeDebug; type OnOfflineValidator: OnOfflineValidator; } +decl_storage! { + trait Store for Module as Consensus { + // Authorities set actual at the block execution start. IsSome only if + // the set has been changed. + OriginalAuthorities: Vec; + } +} + decl_module! { pub struct Module; @@ -149,12 +210,40 @@ impl Module { /// /// Called by `next_session` only. pub fn set_authorities(authorities: &[T::SessionKey]) { - AuthorityStorageVec::::set_items(authorities); + let current_authorities = AuthorityStorageVec::::items(); + if current_authorities != authorities { + Self::save_original_authorities(Some(current_authorities)); + AuthorityStorageVec::::set_items(authorities); + } } /// Set a single authority by index. pub fn set_authority(index: u32, key: &T::SessionKey) { - AuthorityStorageVec::::set_item(index, key); + let current_authority = AuthorityStorageVec::::item(index); + if current_authority != *key { + Self::save_original_authorities(None); + AuthorityStorageVec::::set_item(index, key); + } + } + + /// Save original authorities set. + fn save_original_authorities(current_authorities: Option>) { + if OriginalAuthorities::::get().is_some() { + // if we have already saved original set before, do not overwrite + return; + } + + >::put(current_authorities.unwrap_or_else(|| + AuthorityStorageVec::::items())); + } +} + +/// Finalization hook for the consensus module. +impl OnFinalise for Module { + fn on_finalise(_n: T::BlockNumber) { + if let Some(_) = >::take() { + // TODO: call Self::deposit_log + } } } diff --git a/substrate/runtime/executive/src/lib.rs b/substrate/runtime/executive/src/lib.rs index caaf91a75617d..9e0db49391fa2 100644 --- a/substrate/runtime/executive/src/lib.rs +++ b/substrate/runtime/executive/src/lib.rs @@ -255,6 +255,7 @@ mod tests { pub struct Test; impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; + type Log = u64; type SessionKey = u64; type OnOfflineValidator = staking::Module; } diff --git a/substrate/runtime/primitives/src/generic.rs b/substrate/runtime/primitives/src/generic.rs index efcc52fbecb49..6305bac8d6c99 100644 --- a/substrate/runtime/primitives/src/generic.rs +++ b/substrate/runtime/primitives/src/generic.rs @@ -26,7 +26,7 @@ use rstd::prelude::*; use codec::{Decode, Encode, Codec, Input, Output}; use runtime_support::AuxDispatchable; use traits::{self, Member, SimpleArithmetic, SimpleBitOps, MaybeDisplay, Block as BlockT, - Header as HeaderT, Hash as HashT}; + Header as HeaderT, Hash as HashT, DigestItem as DigestItemT}; use rstd::ops; use bft::Justification; @@ -208,16 +208,27 @@ where } } -#[derive(Default, PartialEq, Eq, Clone, Encode, Decode)] +#[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] pub struct Digest { pub logs: Vec, } +impl Default for Digest { + fn default() -> Self { + Digest { logs: Vec::new(), } + } +} + impl traits::Digest for Digest where - Item: Member + Default + Codec + Item: DigestItemT + Codec { type Item = Item; + + fn logs(&self) -> &[Self::Item] { + &self.logs + } + fn push(&mut self, item: Self::Item) { self.logs.push(item); } @@ -317,7 +328,7 @@ impl Encode for Header where impl traits::Header for Header where Number: Member + ::rstd::hash::Hash + Copy + Codec + MaybeDisplay + SimpleArithmetic + Codec, Hash: HashT, - DigestItem: Member + Default + Codec, + DigestItem: DigestItemT + Codec, Hash::Output: Default + ::rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, { type Number = Number; @@ -356,7 +367,7 @@ impl traits::Header for Header Header where Number: Member + ::rstd::hash::Hash + Copy + Codec + MaybeDisplay + SimpleArithmetic + Codec, Hash: HashT, - DigestItem: Member + Default + Codec, + DigestItem: DigestItemT + Codec, Hash::Output: Default + ::rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, { /// Convenience helper for computing the hash of the header without having diff --git a/substrate/runtime/primitives/src/testing.rs b/substrate/runtime/primitives/src/testing.rs index b1dcef2eadbef..9ac86d7747c82 100644 --- a/substrate/runtime/primitives/src/testing.rs +++ b/substrate/runtime/primitives/src/testing.rs @@ -31,11 +31,20 @@ pub struct Digest { impl traits::Digest for Digest { type Item = u64; + + fn logs(&self) -> &[Self::Item] { + &self.logs + } + fn push(&mut self, item: Self::Item) { self.logs.push(item); } } +impl traits::DigestItem for u64 { + type AuthoritiesChange = (); +} + #[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug, Encode, Decode)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] diff --git a/substrate/runtime/primitives/src/traits.rs b/substrate/runtime/primitives/src/traits.rs index 848d7bcc35293..fbfdfa8a8d74a 100644 --- a/substrate/runtime/primitives/src/traits.rs +++ b/substrate/runtime/primitives/src/traits.rs @@ -317,13 +317,6 @@ impl MaybeDisplay for T {} pub trait Member: Send + Sync + Sized + MaybeSerializeDebug + Eq + PartialEq + Clone + 'static {} impl Member for T {} -/// Something that acts like a `Digest` - it can have `Log`s `push`ed onto it and these `Log`s are -/// each `Codec`. -pub trait Digest { - type Item: Member; - fn push(&mut self, item: Self::Item); -} - /// Something which fulfills the abstract idea of a Substrate header. It has types for a `Number`, /// a `Hash` and a `Digest`. It provides access to an `extrinsics_root`, `state_root` and /// `parent_hash`, as well as a `digest` and a block `number`. @@ -333,7 +326,7 @@ pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebug + 'stat type Number: Member + ::rstd::hash::Hash + Copy + MaybeDisplay + SimpleArithmetic + Codec; type Hash: Member + ::rstd::hash::Hash + Copy + MaybeDisplay + Default + SimpleBitOps + Codec + AsRef<[u8]>; type Hashing: Hash; - type Digest: Member + Default; + type Digest: Digest; fn new( number: Self::Number, @@ -429,3 +422,49 @@ pub trait Applyable: Sized + Send + Sync { fn sender(&self) -> &Self::AccountId; fn apply(self) -> Result<(), &'static str>; } + +/// Something that acts like a `Digest` - it can have `Log`s `push`ed onto it and these `Log`s are +/// each `Codec`. +pub trait Digest: Member + Default { + type Item: DigestItem; + fn logs(&self) -> &[Self::Item]; + fn push(&mut self, item: Self::Item); +} + +/// Single digest item. Could be any type that implements `Member` and provides methods +/// for casting member to 'system' log items, known to substrate. +/// +/// If the runtime does not supports some 'system' items, use `()` as a stub. +pub trait DigestItem: Member { + /// Events of this type is raised by the runtime when set of authorities is changed. + /// Provides access to the new set of authorities. + type AuthoritiesChange: AuthoritiesChangeDigest; // TODO: = () when associated type defaults are stabilized + + /// Returns Some if the entry is the `AuthoritiesChange` entry. + fn as_authorities_change(&self) -> Option<&Self::AuthoritiesChange> { + None + } +} + +/// Authorities change digest item. Created when the set of authorities is changed +/// within the runtime. +pub trait AuthoritiesChangeDigest { + /// Type of authority Id. + type AuthorityId: Member; + + /// Get reference to the new authorities set. + fn authorities(&self) -> &[Self::AuthorityId]; +} + +/// Stub implementations for the digest item that is never created and used. +/// +/// Should be used as a stub for items that are not supported by runtimes. +impl DigestItem for () { + type AuthoritiesChange = (); +} + +impl AuthoritiesChangeDigest for () { + type AuthorityId = (); + + fn authorities(&self) -> &[Self::AuthorityId] { unreachable!("() is never created") } +} diff --git a/substrate/runtime/session/src/lib.rs b/substrate/runtime/session/src/lib.rs index 1e4ac22e78197..fc5bb0438f564 100644 --- a/substrate/runtime/session/src/lib.rs +++ b/substrate/runtime/session/src/lib.rs @@ -295,6 +295,7 @@ mod tests { pub struct Test; impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; + type Log = u64; type SessionKey = u64; type OnOfflineValidator = (); } diff --git a/substrate/runtime/staking/src/mock.rs b/substrate/runtime/staking/src/mock.rs index 1f8cc8e02129f..b8ae013b38dfc 100644 --- a/substrate/runtime/staking/src/mock.rs +++ b/substrate/runtime/staking/src/mock.rs @@ -30,6 +30,7 @@ use {GenesisConfig, Module, Trait, consensus, session, system, timestamp, balanc pub struct Test; impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; + type Log = u64; type SessionKey = u64; type OnOfflineValidator = (); } diff --git a/substrate/runtime/system/src/lib.rs b/substrate/runtime/system/src/lib.rs index 02c937b190fe0..617852b35d313 100644 --- a/substrate/runtime/system/src/lib.rs +++ b/substrate/runtime/system/src/lib.rs @@ -86,6 +86,8 @@ pub trait Trait: Eq + Clone { type Event: Parameter + Member + From; } +pub type DigestItemOf = <::Digest as traits::Digest>::Item; + decl_module! { pub struct Module; } diff --git a/substrate/runtime/timestamp/src/lib.rs b/substrate/runtime/timestamp/src/lib.rs index 5d9fdad118eb5..e7ea230a76f4c 100644 --- a/substrate/runtime/timestamp/src/lib.rs +++ b/substrate/runtime/timestamp/src/lib.rs @@ -161,6 +161,7 @@ mod tests { } impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; + type Log = u64; type SessionKey = u64; type OnOfflineValidator = (); } diff --git a/substrate/test-runtime/src/lib.rs b/substrate/test-runtime/src/lib.rs index 9f0d1be93da83..0bf753a9443a4 100644 --- a/substrate/test-runtime/src/lib.rs +++ b/substrate/test-runtime/src/lib.rs @@ -112,11 +112,11 @@ pub type BlockNumber = u64; /// Index of a transaction. pub type Index = u64; /// The digest of a block. -pub type Digest = runtime_primitives::generic::Digest>; +pub type Digest = runtime_primitives::generic::Digest<()>; /// A test block. pub type Block = runtime_primitives::generic::Block; /// A test block's header. -pub type Header = runtime_primitives::generic::Header>; +pub type Header = runtime_primitives::generic::Header; /// Run whatever tests we have. pub fn run_tests(mut input: &[u8]) -> Vec { diff --git a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 77804d43d0eb7..0afb7c9f18416 100644 Binary files a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm index ca4435aba5534..674df04b2bdbf 100755 Binary files a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm and b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm differ