DigestItem trait (v2) (#650)

* DigestItem trait

* removed autoimpl in impl_outer_log

* StubDigestItem -> ()
This commit is contained in:
Svyatoslav Nikolsky
2018-09-05 14:36:23 +03:00
committed by Gav Wood
parent 101f5ec393
commit be7cb74b06
21 changed files with 221 additions and 23 deletions
+1
View File
@@ -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",
+21 -5
View File
@@ -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<Vec<u8>>;
type Digest = generic::Digest<Log>;
type AccountId = AccountId;
type Header = generic::Header<BlockNumber, BlakeTwo256, Vec<u8>>;
type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
type Event = Event;
}
@@ -112,6 +111,7 @@ pub type Balances = balances::Module<Runtime>;
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<SessionKey>;
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<Runtime>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256, Vec<u8>>;
pub type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// BlockId type as expected by this runtime.
+1
View File
@@ -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",
@@ -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)
}
}
)*
};
}
@@ -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",
@@ -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<T> = RawLog<
<T as Trait>::SessionKey,
>;
/// An logs in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawLog<SessionKey> {
/// Authorities set has been changed. Contains the new set of authorities.
AuthoritiesChange(AuthoritiesChange<SessionKey>),
}
impl<SessionKey> RawLog<SessionKey> {
/// Try to cast the log entry as AuthoritiesChange log entry.
pub fn as_authorities_change(&self) -> Option<&AuthoritiesChange<SessionKey>> {
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<SessionKey> {
/// New set of authorities.
pub new_authorities: Vec<SessionKey>,
}
// Implementation for tests outside of this crate.
impl<N> From<RawLog<N>> for u64 {
fn from(log: RawLog<N>) -> u64 {
match log {
RawLog::AuthoritiesChange(_) => 1,
}
}
}
impl<SessionKey: Member> AuthoritiesChangeDigest for AuthoritiesChange<SessionKey> {
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<Log<Self>> + Into<system::DigestItemOf<Self>>;
type SessionKey: Parameter + Default + MaybeSerializeDebug;
type OnOfflineValidator: OnOfflineValidator;
}
decl_storage! {
trait Store for Module<T: Trait> as Consensus {
// Authorities set actual at the block execution start. IsSome only if
// the set has been changed.
OriginalAuthorities: Vec<T::SessionKey>;
}
}
decl_module! {
pub struct Module<T: Trait>;
@@ -149,12 +210,40 @@ impl<T: Trait> Module<T> {
///
/// Called by `next_session` only.
pub fn set_authorities(authorities: &[T::SessionKey]) {
AuthorityStorageVec::<T::SessionKey>::set_items(authorities);
let current_authorities = AuthorityStorageVec::<T::SessionKey>::items();
if current_authorities != authorities {
Self::save_original_authorities(Some(current_authorities));
AuthorityStorageVec::<T::SessionKey>::set_items(authorities);
}
}
/// Set a single authority by index.
pub fn set_authority(index: u32, key: &T::SessionKey) {
AuthorityStorageVec::<T::SessionKey>::set_item(index, key);
let current_authority = AuthorityStorageVec::<T::SessionKey>::item(index);
if current_authority != *key {
Self::save_original_authorities(None);
AuthorityStorageVec::<T::SessionKey>::set_item(index, key);
}
}
/// Save original authorities set.
fn save_original_authorities(current_authorities: Option<Vec<T::SessionKey>>) {
if OriginalAuthorities::<T>::get().is_some() {
// if we have already saved original set before, do not overwrite
return;
}
<OriginalAuthorities<T>>::put(current_authorities.unwrap_or_else(||
AuthorityStorageVec::<T::SessionKey>::items()));
}
}
/// Finalization hook for the consensus module.
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
if let Some(_) = <OriginalAuthorities<T>>::take() {
// TODO: call Self::deposit_log
}
}
}
@@ -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<Test>;
}
@@ -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<Item> {
pub logs: Vec<Item>,
}
impl<Item> Default for Digest<Item> {
fn default() -> Self {
Digest { logs: Vec::new(), }
}
}
impl<Item> traits::Digest for Digest<Item> 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<Number, Hash, DigestItem> Encode for Header<Number, Hash, DigestItem> where
impl<Number, Hash, DigestItem> traits::Header for Header<Number, Hash, DigestItem> 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<Number, Hash, DigestItem> traits::Header for Header<Number, Hash, DigestIte
impl<Number, Hash, DigestItem> Header<Number, Hash, DigestItem> 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
@@ -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)]
@@ -317,13 +317,6 @@ impl<T> MaybeDisplay for T {}
pub trait Member: Send + Sync + Sized + MaybeSerializeDebug + Eq + PartialEq + Clone + 'static {}
impl<T: Send + Sync + Sized + MaybeSerializeDebug + Eq + PartialEq + Clone + 'static> 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<Output = Self::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") }
}
@@ -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 = ();
}
@@ -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 = ();
}
@@ -86,6 +86,8 @@ pub trait Trait: Eq + Clone {
type Event: Parameter + Member + From<Event>;
}
pub type DigestItemOf<T> = <<T as Trait>::Digest as traits::Digest>::Item;
decl_module! {
pub struct Module<T: Trait>;
}
@@ -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 = ();
}
+2 -2
View File
@@ -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<Vec<u8>>;
pub type Digest = runtime_primitives::generic::Digest<()>;
/// A test block.
pub type Block = runtime_primitives::generic::Block<Header, Extrinsic>;
/// A test block's header.
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, Vec<u8>>;
pub type Header = runtime_primitives::generic::Header<BlockNumber, BlakeTwo256, ()>;
/// Run whatever tests we have.
pub fn run_tests(mut input: &[u8]) -> Vec<u8> {