// Copyright 2017 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 . //! Conensus module for runtime; manages the authority set ready for the native code. #![cfg_attr(not(feature = "std"), no_std)] #[allow(unused_imports)] #[macro_use] extern crate sr_std as rstd; #[macro_use] extern crate srml_support as runtime_support; #[cfg(feature = "std")] extern crate serde; #[cfg(feature = "std")] #[macro_use] extern crate serde_derive; #[macro_use] extern crate parity_codec_derive; extern crate sr_io as runtime_io; extern crate sr_primitives as primitives; extern crate parity_codec as codec; extern crate srml_system as system; 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, OnFinalise, Member, DigestItem}; use primitives::bft::MisbehaviorReport; use system::{ensure_signed, ensure_inherent}; #[cfg(any(feature = "std", test))] use substrate_primitives::Blake2Hasher; #[cfg(any(feature = "std", test))] use std::collections::HashMap; pub const AUTHORITY_AT: &'static [u8] = b":auth:"; pub const AUTHORITY_COUNT: &'static [u8] = b":auth:len"; struct AuthorityStorageVec(rstd::marker::PhantomData); impl StorageVec for AuthorityStorageVec { type Item = S; const PREFIX: &'static [u8] = AUTHORITY_AT; } pub const CODE: &'static [u8] = b":code"; pub type KeyValue = (Vec, Vec); pub trait OnOfflineValidator { fn on_offline_validator(validator_index: usize); } impl OnOfflineValidator for () { fn on_offline_validator(_validator_index: usize) {} } pub type Log = RawLog< ::SessionKey, >; /// A 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(Vec), } impl DigestItem for RawLog { type AuthorityId = SessionKey; /// Try to cast the log entry as AuthoritiesChange log entry. fn as_authorities_change(&self) -> Option<&[SessionKey]> { match *self { RawLog::AuthoritiesChange(ref item) => Some(&item), } } } // Implementation for tests outside of this crate. impl From> for u64 { fn from(log: RawLog) -> u64 { match log { RawLog::AuthoritiesChange(_) => 1, } } } 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 for enum Call where origin: T::Origin { fn report_misbehavior(origin, report: MisbehaviorReport) -> Result; fn note_offline(origin, offline_val_indices: Vec) -> Result; fn remark(origin, remark: Vec) -> Result; fn set_code(new: Vec) -> Result; fn set_storage(items: Vec) -> Result; } } impl Module { /// Get the current set of authorities. These are the session keys. pub fn authorities() -> Vec { AuthorityStorageVec::::items() } /// Set the new code. fn set_code(new: Vec) -> Result { storage::unhashed::put_raw(CODE, &new); Ok(()) } /// Set some items of storage. fn set_storage(items: Vec) -> Result { for i in &items { storage::unhashed::put_raw(&i.0, &i.1); } Ok(()) } /// Report some misbehaviour. fn report_misbehavior(origin: T::Origin, _report: MisbehaviorReport) -> Result { ensure_signed(origin)?; // TODO. Ok(()) } /// Note the previous block's validator missed their opportunity to propose a block. This only comes in /// if 2/3+1 of the validators agree that no proposal was submitted. It's only relevant /// for the previous block. fn note_offline(origin: T::Origin, offline_val_indices: Vec) -> Result { 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 ); for validator_index in offline_val_indices.into_iter() { T::OnOfflineValidator::on_offline_validator(validator_index as usize); } Ok(()) } /// Make some on-chain remark. fn remark(origin: T::Origin, _remark: Vec) -> Result { ensure_signed(origin)?; Ok(()) } /// Set the current set of authorities' session keys. /// /// Called by `next_session` only. pub fn set_authorities(authorities: &[T::SessionKey]) { 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) { 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 } } } #[cfg(any(feature = "std", test))] #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct GenesisConfig { pub authorities: Vec, #[serde(with = "substrate_primitives::bytes")] pub code: Vec, } #[cfg(any(feature = "std", test))] impl Default for GenesisConfig { fn default() -> Self { GenesisConfig { authorities: vec![], code: vec![], } } } #[cfg(any(feature = "std", test))] impl primitives::BuildStorage for GenesisConfig { fn build_storage(self) -> ::std::result::Result, Vec>, String> { use codec::{Encode, KeyedVec}; let auth_count = self.authorities.len() as u32; let mut r: runtime_io::TestExternalities = self.authorities.into_iter().enumerate().map(|(i, v)| ((i as u32).to_keyed_vec(AUTHORITY_AT), v.encode()) ).collect(); r.insert(AUTHORITY_COUNT.to_vec(), auth_count.encode()); r.insert(CODE.to_vec(), self.code); Ok(r.into()) } }