// 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())
}
}