diff --git a/substrate/core/consensus/aura/primitives/src/lib.rs b/substrate/core/consensus/aura/primitives/src/lib.rs index 9bdf39d293..47b1399a67 100644 --- a/substrate/core/consensus/aura/primitives/src/lib.rs +++ b/substrate/core/consensus/aura/primitives/src/lib.rs @@ -26,11 +26,18 @@ use runtime_primitives::ConsensusEngineId; /// The `ConsensusEngineId` of AuRa. pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a']; +/// The index of an authority. +pub type AuthorityIndex = u64; + /// An consensus log item for Aura. #[derive(Decode, Encode)] pub enum ConsensusLog { /// The authorities have changed. + #[codec(index = "1")] AuthoritiesChange(Vec), + /// Disable the authority with given index. + #[codec(index = "2")] + OnDisabled(AuthorityIndex), } decl_runtime_apis! { diff --git a/substrate/core/consensus/aura/src/lib.rs b/substrate/core/consensus/aura/src/lib.rs index 49b505a7f5..1ac5c2c1b9 100644 --- a/substrate/core/consensus/aura/src/lib.rs +++ b/substrate/core/consensus/aura/src/lib.rs @@ -564,14 +564,19 @@ impl Verifier for AuraVerifier where trace!(target: "aura", "Checked {:?}; importing.", pre_header); telemetry!(CONSENSUS_TRACE; "aura.checked_and_importing"; "pre_header" => ?pre_header); - // `Consensus` is the Aura-specific authorities change log. + // Look for an authorities-change log. let maybe_keys = pre_header.digest() - .convert_first(|l| l.try_to::>>( + .logs() + .iter() + .filter_map(|l| l.try_to::>>( OpaqueDigestItemId::Consensus(&AURA_ENGINE_ID) )) - .map(|ConsensusLog::AuthoritiesChange(a)| - vec![(well_known_cache_keys::AUTHORITIES, a.encode())] - ); + .find_map(|l| match l { + ConsensusLog::AuthoritiesChange(a) => Some( + vec![(well_known_cache_keys::AUTHORITIES, a.encode())] + ), + _ => None, + }); let import_block = ImportBlock { origin, diff --git a/substrate/core/consensus/babe/primitives/src/lib.rs b/substrate/core/consensus/babe/primitives/src/lib.rs index 5691dcf44d..655751b763 100644 --- a/substrate/core/consensus/babe/primitives/src/lib.rs +++ b/substrate/core/consensus/babe/primitives/src/lib.rs @@ -40,6 +40,29 @@ pub const VRF_PROOF_LENGTH: usize = 64; /// The length of the public key pub const PUBLIC_KEY_LENGTH: usize = 32; +/// The index of an authority. +pub type AuthorityIndex = u64; + +/// A slot number. +pub type SlotNumber = u64; + +/// The weight of an authority. +pub type Weight = u64; + +/// An consensus log item for BABE. +#[derive(Decode, Encode)] +pub enum ConsensusLog { + /// The epoch has changed. This provides information about the + /// epoch _after_ next: what slot number it will start at, who are the authorities (and their weights) + /// and the next epoch randomness. The information for the _next_ epoch should already + /// be available. + #[codec(index = "1")] + NextEpochData(SlotNumber, Vec<(AuthorityId, Weight)>, [u8; VRF_OUTPUT_LENGTH]), + /// Disable the authority with given index. + #[codec(index = "2")] + OnDisabled(AuthorityIndex), +} + /// Configuration data used by the BABE consensus engine. #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Encode, Decode)] pub struct BabeConfiguration { diff --git a/substrate/core/consensus/babe/src/digest.rs b/substrate/core/consensus/babe/src/digest.rs index 15ca3448f9..37ba27a309 100644 --- a/substrate/core/consensus/babe/src/digest.rs +++ b/substrate/core/consensus/babe/src/digest.rs @@ -17,7 +17,7 @@ //! Private implementation details of BABE digests. use primitives::sr25519::Signature; -use babe_primitives::{self, BABE_ENGINE_ID}; +use babe_primitives::{self, BABE_ENGINE_ID, SlotNumber}; use runtime_primitives::{DigestItem, generic::OpaqueDigestItemId}; use std::fmt::Debug; use parity_codec::{Decode, Encode, Codec, Input}; @@ -33,8 +33,8 @@ use schnorrkel::{vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH} pub struct BabePreDigest { pub(super) vrf_output: VRFOutput, pub(super) proof: VRFProof, - pub(super) index: u64, - pub(super) slot_num: u64, + pub(super) index: babe_primitives::AuthorityIndex, + pub(super) slot_num: SlotNumber, } /// The prefix used by BABE for its VRF keys. diff --git a/substrate/core/finality-grandpa/primitives/src/lib.rs b/substrate/core/finality-grandpa/primitives/src/lib.rs index aded32efa3..f3721d5dcc 100644 --- a/substrate/core/finality-grandpa/primitives/src/lib.rs +++ b/substrate/core/finality-grandpa/primitives/src/lib.rs @@ -23,7 +23,7 @@ extern crate alloc; #[cfg(feature = "std")] use serde::Serialize; -use parity_codec::{Encode, Decode}; +use parity_codec::{Encode, Decode, Codec}; use sr_primitives::{ConsensusEngineId, traits::{DigestFor, NumberFor}}; use client::decl_runtime_apis; use rstd::vec::Vec; @@ -44,16 +44,75 @@ pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; /// The weight of an authority. pub type AuthorityWeight = u64; +/// The index of an authority. +pub type AuthorityIndex = u64; + /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Debug, Serialize))] #[derive(Clone, Eq, PartialEq, Encode, Decode)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. - pub next_authorities: Vec<(AuthorityId, u64)>, + pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, /// The number of blocks to delay. pub delay: N, } +/// An consensus log item for GRANDPA. +#[cfg_attr(feature = "std", derive(Serialize, Debug))] +#[derive(Decode, Encode, PartialEq, Eq, Clone)] +pub enum ConsensusLog { + /// Schedule an authority set change. + /// + /// Precedence towards earlier or later digest items can be given + /// based on the rules of the chain. + /// + /// No change should be scheduled if one is already and the delay has not + /// passed completely. + /// + /// This should be a pure function: i.e. as long as the runtime can interpret + /// the digest type it should return the same result regardless of the current + /// state. + #[codec(index = "1")] + ScheduledChange(ScheduledChange), + /// Force an authority set change. + /// + /// Forced changes are applied after a delay of _imported_ blocks, + /// while pending changes are applied after a delay of _finalized_ blocks. + /// + /// Precedence towards earlier or later digest items can be given + /// based on the rules of the chain. + /// + /// No change should be scheduled if one is already and the delay has not + /// passed completely. + /// + /// This should be a pure function: i.e. as long as the runtime can interpret + /// the digest type it should return the same result regardless of the current + /// state. + #[codec(index = "2")] + ForcedChange(N, ScheduledChange), + /// Note that the authority with given index is disabled until the next change. + #[codec(index = "3")] + OnDisabled(AuthorityIndex), +} + +impl ConsensusLog { + /// Try to cast the log entry as a contained signal. + pub fn try_into_change(self) -> Option> { + match self { + ConsensusLog::ScheduledChange(change) => Some(change), + ConsensusLog::ForcedChange(_, _) | ConsensusLog::OnDisabled(_) => None, + } + } + + /// Try to cast the log entry as a contained forced signal. + pub fn try_into_forced_change(self) -> Option<(N, ScheduledChange)> { + match self { + ConsensusLog::ForcedChange(median, change) => Some((median, change)), + ConsensusLog::ScheduledChange(_) | ConsensusLog::OnDisabled(_) => None, + } + } +} + /// WASM function call to check for pending changes. pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change"; /// WASM function call to get current GRANDPA authorities. diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index b3e37fe3c0..3ea064cac0 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -71,9 +71,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - - spec_version: 105, - impl_version: 105, + spec_version: 106, + impl_version: 106, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/srml/aura/src/lib.rs b/substrate/srml/aura/src/lib.rs index 56485b04c1..3323d87bb5 100644 --- a/substrate/srml/aura/src/lib.rs +++ b/substrate/srml/aura/src/lib.rs @@ -200,8 +200,13 @@ impl session::OneSessionHandler for Module { } } } - fn on_disabled(_i: usize) { - // ignore? + fn on_disabled(i: usize) { + let log: DigestItem = DigestItem::Consensus( + AURA_ENGINE_ID, + ConsensusLog::::OnDisabled(i as u64).encode(), + ); + + >::deposit_log(log.into()); } } diff --git a/substrate/srml/babe/src/lib.rs b/substrate/srml/babe/src/lib.rs index 32d5271970..14f750f3e2 100644 --- a/substrate/srml/babe/src/lib.rs +++ b/substrate/srml/babe/src/lib.rs @@ -31,7 +31,7 @@ use parity_codec::{Encode, Decode}; use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError}; #[cfg(feature = "std")] use inherents::{InherentDataProviders, ProvideInherentData}; -use babe_primitives::BABE_ENGINE_ID; +use babe_primitives::{BABE_ENGINE_ID, ConsensusLog}; pub use babe_primitives::{AuthorityId, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH, PUBLIC_KEY_LENGTH}; /// The BABE inherent identifier. @@ -128,13 +128,13 @@ decl_storage! { /// (like everything else on-chain) it is public. For example, it can be /// used where a number is needed that cannot have been chosen by an /// adversary, for purposes such as public-coin zero-knowledge proofs. - EpochRandomness get(epoch_randomness): [u8; 32]; + EpochRandomness get(epoch_randomness): [u8; VRF_OUTPUT_LENGTH]; /// The randomness under construction - UnderConstruction: [u8; 32]; + UnderConstruction: [u8; VRF_OUTPUT_LENGTH]; /// The randomness for the next epoch - NextEpochRandomness: [u8; 32]; + NextEpochRandomness: [u8; VRF_OUTPUT_LENGTH]; /// The current epoch EpochIndex get(epoch_index): u64; @@ -162,7 +162,7 @@ decl_module! { } impl RandomnessBeacon for Module { - fn random() -> [u8; 32] { + fn random() -> [u8; VRF_OUTPUT_LENGTH] { Self::epoch_randomness() } } @@ -245,8 +245,13 @@ impl session::OneSessionHandler for Module { s[40..].copy_from_slice(&rho); NextEpochRandomness::put(runtime_io::blake2_256(&s)) } - fn on_disabled(_i: usize) { - // ignore? + + fn on_disabled(i: usize) { + let log: DigestItem = DigestItem::Consensus( + BABE_ENGINE_ID, + ConsensusLog::OnDisabled(i as u64).encode(), + ); + >::deposit_log(log.into()); } } diff --git a/substrate/srml/grandpa/src/lib.rs b/substrate/srml/grandpa/src/lib.rs index 9ed8fa079e..ba60128a89 100644 --- a/substrate/srml/grandpa/src/lib.rs +++ b/substrate/srml/grandpa/src/lib.rs @@ -30,8 +30,6 @@ // re-export since this is necessary for `impl_apis` in runtime. pub use substrate_finality_grandpa_primitives as fg_primitives; -#[cfg(feature = "std")] -use serde::Serialize; use rstd::prelude::*; use parity_codec::{self as codec, Encode, Decode}; use srml_support::{ @@ -40,44 +38,13 @@ use srml_support::{ use primitives::{ generic::{DigestItem, OpaqueDigestItemId}, traits::CurrentHeight }; -use fg_primitives::{ScheduledChange, GRANDPA_ENGINE_ID}; +use fg_primitives::{ScheduledChange, ConsensusLog, GRANDPA_ENGINE_ID}; pub use fg_primitives::{AuthorityId, AuthorityWeight}; use system::{ensure_signed, DigestOf}; mod mock; mod tests; -/// Consensus log type of this module. -#[cfg_attr(feature = "std", derive(Serialize, Debug))] -#[derive(Encode, Decode, PartialEq, Eq, Clone)] -pub enum Signal { - /// Authorities set change has been signaled. Contains the new set of authorities - /// and the delay in blocks _to finalize_ before applying. - AuthoritiesChange(ScheduledChange), - /// A forced authorities set change. Contains in this order: the median last - /// finalized block when the change was signaled, the delay in blocks _to import_ - /// before applying and the new set of authorities. - ForcedAuthoritiesChange(N, ScheduledChange), -} - -impl Signal { - /// Try to cast the log entry as a contained signal. - pub fn try_into_change(self) -> Option> { - match self { - Signal::AuthoritiesChange(change) => Some(change), - Signal::ForcedAuthoritiesChange(_, _) => None, - } - } - - /// Try to cast the log entry as a contained forced signal. - pub fn try_into_forced_change(self) -> Option<(N, ScheduledChange)> { - match self { - Signal::ForcedAuthoritiesChange(median, change) => Some((median, change)), - Signal::AuthoritiesChange(_) => None, - } - } -} - pub trait Trait: system::Trait { /// The event type of this module. type Event: From + Into<::Event>; @@ -161,7 +128,7 @@ decl_module! { if let Some(pending_change) = >::get() { if block_number == pending_change.scheduled_at { if let Some(median) = pending_change.forced { - Self::deposit_log(Signal::ForcedAuthoritiesChange( + Self::deposit_log(ConsensusLog::ForcedChange( median, ScheduledChange{ delay: pending_change.delay, @@ -169,7 +136,7 @@ decl_module! { } )) } else { - Self::deposit_log(Signal::AuthoritiesChange( + Self::deposit_log(ConsensusLog::ScheduledChange( ScheduledChange{ delay: pending_change.delay, next_authorities: pending_change.next_authorities.clone(), @@ -242,16 +209,16 @@ impl Module { } /// Deposit one of this module's logs. - fn deposit_log(log: Signal) { + fn deposit_log(log: ConsensusLog) { let log: DigestItem = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()); >::deposit_log(log.into()); } } impl Module { - pub fn grandpa_log(digest: &DigestOf) -> Option> { + pub fn grandpa_log(digest: &DigestOf) -> Option> { let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID); - digest.convert_first(|l| l.try_to::>(id)) + digest.convert_first(|l| l.try_to::>(id)) } pub fn pending_change(digest: &DigestOf) @@ -287,8 +254,8 @@ impl session::OneSessionHandler for Module { } } } - fn on_disabled(_i: usize) { - // ignore? + fn on_disabled(i: usize) { + Self::deposit_log(ConsensusLog::OnDisabled(i as u64)) } } diff --git a/substrate/srml/grandpa/src/mock.rs b/substrate/srml/grandpa/src/mock.rs index 5f2aeee34f..08847b0929 100644 --- a/substrate/srml/grandpa/src/mock.rs +++ b/substrate/srml/grandpa/src/mock.rs @@ -23,17 +23,15 @@ use runtime_io; use srml_support::{impl_outer_origin, impl_outer_event}; use substrate_primitives::{H256, Blake2Hasher}; use parity_codec::{Encode, Decode}; -use crate::{AuthorityId, GenesisConfig, Trait, Module, Signal}; +use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog}; use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID; impl_outer_origin!{ pub enum Origin for Test {} } -impl From> for DigestItem { - fn from(log: Signal) -> DigestItem { - DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()) - } +pub fn grandpa_log(log: ConsensusLog) -> DigestItem { + DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode()) } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. diff --git a/substrate/srml/grandpa/src/tests.rs b/substrate/srml/grandpa/src/tests.rs index ab923f295b..763c4fce89 100644 --- a/substrate/srml/grandpa/src/tests.rs +++ b/substrate/srml/grandpa/src/tests.rs @@ -39,9 +39,9 @@ fn authorities_change_logged() { let header = System::finalize(); assert_eq!(header.digest, Digest { logs: vec![ - Signal::AuthoritiesChange( + grandpa_log(ConsensusLog::ScheduledChange( ScheduledChange { delay: 0, next_authorities: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) } - ).into(), + )), ], }); @@ -64,9 +64,9 @@ fn authorities_change_logged_after_delay() { let header = System::finalize(); assert_eq!(header.digest, Digest { logs: vec![ - Signal::AuthoritiesChange( + grandpa_log(ConsensusLog::ScheduledChange( ScheduledChange { delay: 1, next_authorities: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) } - ).into(), + )), ], });