diff --git a/srml/consensus/src/lib.rs b/srml/consensus/src/lib.rs index dfcc6805dc8de..4c2a57b83c1de 100644 --- a/srml/consensus/src/lib.rs +++ b/srml/consensus/src/lib.rs @@ -14,7 +14,105 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Consensus module for runtime; manages the authority set ready for the native code. +//! # Consensus Module +//! +//! ## Overview +//! +//! The consensus module manages the authority set for the native code. It provides support for reporting offline +//! behavior among validators and logging changes in the validator authority set. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! - `report_misbehavior` - Report some misbehavior. The origin of this call must be signed. +//! - `note_offline` - Note that the previous block's validator missed its opportunity to propose a block. +//! The origin of this call must be an inherent. +//! - `remark` - Make some on-chain remark. The origin of this call must be signed. +//! - `set_heap_pages` - Set the number of pages in the WebAssembly environment's heap. +//! - `set_code` - Set the new code. +//! - `set_storage` - Set some items of storage. +//! +//! Please refer to the [`Call`](./enum.Call.html) enum and its associated variants for documentation on each function. +//! +//! ### Public Functions +//! +//! See the [module](./struct.Module.html) for details on publicly available functions. +//! +//! ## Usage +//! +//! ### Prerequisites +//! +//! To use functionality from the consensus module, implement the specific Trait or function that you are invoking +//! from the module: +//! +//! ```rust,ignore +//! impl for consensus::SomeTrait for Module { +//! /// required functions and types for trait included here +//! /// more comprehensive example included below +//! } +//! ``` +//! +//! Alternatively, to set the authorities: +//! +//! ```rust,ignore +//! consensus::set_authorities(&[]) // example included below +//! ``` +//! +//! ### Simple Code Snippet +//! +//! Set authorities: +//! +//! ```rust,ignore +//! >::set_authorities(&[UintAuthorityId(4), UintAuthorityId(5), UintAuthorityId(6)]) +//! ``` +//! +//! Log changes in the authorities set: +//! +//! ```rust,ignore +//! >::on_finalise(5); // finalize UintAuthorityId(5) +//! ``` +//! +//! ### Example from SRML +//! +//! In the staking module, the `consensus::OnOfflineReport` is implemented to monitor offline +//! reporting among validators: +//! +//! ```rust,ignore +//! impl consensus::OnOfflineReport> for Module { +//! fn handle_report(reported_indices: Vec) { +//! for validator_index in reported_indices { +//! let v = >::validators()[validator_index as usize].clone(); +//! Self::on_offline_validator(v, 1); +//! } +//! } +//! } +//! ``` +//! +//! In the GRANDPA module, we use `srml-consensus` to get the set of `next_authorities` before changing +//! this set according to the consensus algorithm (which does not rotate sessions in the *normal* way): +//! +//! ```rust,ignore +//! let next_authorities = >::authorities() +//! .into_iter() +//! .map(|key| (key, 1)) // evenly-weighted. +//! .collect::::SessionKey, u64)>>(); +//! ``` +//! +//! ## Related Modules +//! +//! - [`staking`](../srml_staking/index.html): This module uses `srml-consensus` to monitor offline +//! reporting among validators. +//! - [`aura`](../srml_aura/index.html): This module does not relate directly to `srml-consensus`, +//! but serves to manage offline reporting for the Aura consensus algorithm with its own `handle_report` method. +//! - [`grandpa`](../srml_grandpa/index.html): Although GRANDPA does its own voter-set management, +//! it has a mode where it can track `consensus`, if desired. +//! +//! ## References +//! +//! If you're interested in hacking on this module, it is useful to understand the interaction with +//! `substrate/core/inherents/src/lib.rs` and, specifically, the required implementation of `ProvideInherent` +//! to create and check inherents. #![cfg_attr(not(feature = "std"), no_std)] @@ -88,9 +186,9 @@ impl InherentOfflineReport for () { } } -/// A variant of the `OfflineReport` which is useful for instant-finality blocks. +/// A variant of the `OfflineReport` that is useful for instant-finality blocks. /// -/// This assumes blocks are only finalized +/// This assumes blocks are only finalized. pub struct InstantFinalityReportVec(::rstd::marker::PhantomData); impl>> InherentOfflineReport for InstantFinalityReportVec { @@ -117,7 +215,7 @@ pub type Log = RawLog< ::SessionKey, >; -/// A logs in this module. +/// Logs in this module. #[cfg_attr(feature = "std", derive(Serialize, Debug))] #[derive(Encode, Decode, PartialEq, Eq, Clone)] pub enum RawLog { @@ -159,7 +257,7 @@ pub trait Trait: system::Trait { decl_storage! { trait Store for Module as Consensus { - // Authorities set actual at the block execution start. IsSome only if + // Actual authorities set at the block execution start. Is `Some` iff // the set has been changed. OriginalAuthorities: Option>; } @@ -188,7 +286,7 @@ decl_module! { ensure_signed(origin)?; } - /// Note the previous block's validator missed their opportunity to propose a block. + /// Note that the previous block's validator missed its opportunity to propose a block. fn note_offline(origin, offline: ::Inherent) { ensure_inherent(origin)?; @@ -243,7 +341,7 @@ impl Module { /// Set the current set of authorities' session keys. /// - /// Called by `next_session` only. + /// Called by `rotate_session` only. pub fn set_authorities(authorities: &[T::SessionKey]) { let current_authorities = AuthorityStorageVec::::items(); if current_authorities != authorities { @@ -284,11 +382,16 @@ impl Module { } } +/// Implementing `ProvideInherent` enables this module to create and check inherents. impl ProvideInherent for Module { + /// The call type of the module. type Call = Call; + /// The error returned by `check_inherent`. type Error = MakeFatalError; + /// The inherent identifier used by this inherent. const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + /// Creates an inherent from the `InherentData`. fn create_inherent(data: &InherentData) -> Option { if let Ok(Some(data)) = data.get_data::<::Inherent>( @@ -305,6 +408,7 @@ impl ProvideInherent for Module { } } + /// Verify the validity of the given inherent. fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> { let offline = match call { Call::note_offline(ref offline) => offline, diff --git a/srml/consensus/src/tests.rs b/srml/consensus/src/tests.rs index ff60660b0a475..4fb5bb614d5f4 100644 --- a/srml/consensus/src/tests.rs +++ b/srml/consensus/src/tests.rs @@ -44,6 +44,27 @@ fn authorities_change_logged() { }); } +#[test] +fn partial_authorities_change_logged() { + with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { + System::initialise(&2, &Default::default(), &Default::default()); + Consensus::set_authorities(&[UintAuthorityId(2), UintAuthorityId(4), UintAuthorityId(5)]); + Consensus::on_finalise(2); + let header = System::finalise(); + assert_eq!(header.digest, testing::Digest { + logs: vec![ + generic::DigestItem::AuthoritiesChange( + vec![ + UintAuthorityId(2).into(), + UintAuthorityId(4).into(), + UintAuthorityId(5).into() + ] + ), + ], + }); + }); +} + #[test] fn authorities_change_is_not_logged_when_not_changed() { with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 3d07b53e2e444..204eaccc1f94b 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -103,7 +103,7 @@ decl_storage! { /// Timestamp when current session started. pub CurrentStart get(current_start) build(|_| T::Moment::zero()): T::Moment; - /// New session is being forced is this entry exists; in which case, the boolean value is whether + /// New session is being forced if this entry exists; in which case, the boolean value is whether /// the new session should be considered a normal rotation (rewardable) or exceptional (slashable). pub ForcingNewSession get(forcing_new_session): Option; /// Block at which the session length last changed. @@ -121,12 +121,12 @@ decl_storage! { } impl Module { - /// The number of validators currently. + /// The current number of validators. pub fn validator_count() -> u32 { >::get().len() as u32 } - /// The last length change, if there was one, zero if not. + /// The last length change if there was one, zero if not. pub fn last_length_change() -> T::BlockNumber { >::get().unwrap_or_else(T::BlockNumber::zero) } @@ -140,7 +140,7 @@ impl Module { /// Set the current set of validators. /// - /// Called by `staking::new_era()` only. `rotate_session` must be called after this in order to + /// Called by `staking::new_era` only. `rotate_session` must be called after this in order to /// update the session keys to the next validator set. pub fn set_validators(new: &[T::AccountId]) { >::put(&new.to_vec()); @@ -148,9 +148,9 @@ impl Module { /// Hook to be called after transaction processing. pub fn check_rotate_session(block_number: T::BlockNumber) { - // do this last, after the staking system has had chance to switch out the authorities for the + // Do this last, after the staking system has had the chance to switch out the authorities for the // new set. - // check block number and call next_session if necessary. + // Check block number and call `rotate_session` if necessary. let is_final_block = ((block_number - Self::last_length_change()) % Self::length()).is_zero(); let (should_end_session, apply_rewards) = >::take() .map_or((is_final_block, is_final_block), |apply_rewards| (true, apply_rewards)); @@ -159,7 +159,7 @@ impl Module { } } - /// Move onto next session: register the new authority set. + /// Move on to next session: register the new authority set. pub fn rotate_session(is_final_block: bool, apply_rewards: bool) { let now = >::get(); let time_elapsed = now.clone() - Self::current_start(); @@ -206,7 +206,7 @@ impl Module { } /// Number of blocks remaining in this session, not counting this one. If the session is - /// due to rotate at the end of this block, then it will return 0. If the just began, then + /// due to rotate at the end of this block, then it will return 0. If the session just began, then /// it will return `Self::length() - 1`. pub fn blocks_remaining() -> T::BlockNumber { let length = Self::length();