Move inherent implementation into the modules (#924)

* Adds new `ProvideInherent` trait

Also implements the new trait for `srml/consensus` and `srml/timestamp`.

* Adds `impl_outer_inherent!` macro

* Reexport macros from `alloc`

* Introduce `RuntimeString` and fix `ProvideInherent` on `no_std`

* Replace `VersionString` with `RuntimeString`

* Improvements for `impl_outer_inherent!`

* Make `construct_runtime!` support `impl_outer_inherent!`

* Fixes after rebase

* Whitespace
This commit is contained in:
Bastian Köcher
2018-10-18 10:55:52 +02:00
committed by Gav Wood
parent 36625faa9f
commit 4132a49fbb
31 changed files with 498 additions and 166 deletions
+34 -2
View File
@@ -41,11 +41,15 @@ extern crate substrate_primitives;
extern crate sr_io as runtime_io;
use rstd::prelude::*;
use rstd::result;
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};
use primitives::RuntimeString;
use primitives::traits::{
MaybeSerializeDebug, OnFinalise, Member, ProvideInherent, Block as BlockT
};
use substrate_primitives::storage::well_known_keys;
use system::{ensure_signed, ensure_inherent};
@@ -235,6 +239,35 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> ProvideInherent for Module<T> {
type Inherent = Vec<u32>;
type Call = Call<T>;
type Error = RuntimeString;
fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> {
vec![(T::NOTE_OFFLINE_POSITION, Call::note_offline(data))]
}
fn check_inherent<Block: BlockT, F: Fn(&Block::Extrinsic) -> Option<&Self::Call>>(
block: &Block, data: Self::Inherent, extract_function: &F
) -> result::Result<(), Self::Error> {
let noted_offline = block
.extrinsics().get(T::NOTE_OFFLINE_POSITION as usize)
.and_then(|xt| match extract_function(&xt) {
Some(Call::note_offline(ref x)) => Some(&x[..]),
_ => None,
}).unwrap_or(&[]);
noted_offline.iter().try_for_each(|n|
if !data.contains(n) {
Err("Online node marked offline".into())
} else {
Ok(())
}
)
}
}
/// Finalization hook for the consensus module.
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
@@ -246,4 +279,3 @@ impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
}
}
}
+128
View File
@@ -0,0 +1,128 @@
// Copyright 2018 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 <http://www.gnu.org/licenses/>.
#[doc(hidden)]
pub use rstd::{result::Result, vec::Vec};
#[doc(hidden)]
pub use runtime_primitives::traits::ProvideInherent;
/// Implement the outer inherent.
/// All given modules need to implement `ProvideInherent`.
///
/// # Example
///
/// ```nocompile
/// impl_outer_inherent! {
/// pub struct InherentData where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic {
/// timestamp: Timestamp export Error as TimestampInherentError,
/// consensus: Consensus,
/// }
/// }
/// ```
///
/// Additional parameters after `UncheckedExtrinsic` are `Error` and `Call`.
#[macro_export]
macro_rules! impl_outer_inherent {
(
$(#[$attr:meta])*
pub struct $name:ident where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident {
$( $module:ident: $module_ty:ident $(export Error as $error_name:ident)*, )*
}
) => {
impl_outer_inherent!(
$( #[$attr] )*
pub struct $name where Block = $block, UncheckedExtrinsic = $unchecked, Error = InherentError, Call = Call {
$( $module: $module_ty $(export Error as $error_name)*, )*
}
);
};
(
$(#[$attr:meta])*
pub struct $name:ident where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident, Error = $error:ident {
$( $module:ident: $module_ty:ident $(export Error as $error_name:ident)*, )*
}
) => {
impl_outer_inherent!(
$( #[$attr] )*
pub struct $name where Block = $block, UncheckedExtrinsic = $unchecked, Error = $error, Call = Call {
$( $module: $module_ty $(export Error as $error_name)*, )*
}
);
};
(
$(#[$attr:meta])*
pub struct $name:ident where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident, Error = $error:ident, Call = $call:ident {
$( $module:ident: $module_ty:ident $(export Error as $error_name:ident)*, )*
}
) => {
$( #[$attr] )*
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Encode, Decode)]
/// Inherent data to include in a block.
pub struct $name {
$( $module: <$module_ty as $crate::inherent::ProvideInherent>::Inherent, )*
}
$(
$(
pub type $error_name =<$module_ty as $crate::inherent::ProvideInherent>::Error;
)*
)*
impl $name {
/// Create a new instance.
pub fn new( $( $module: <$module_ty as $crate::inherent::ProvideInherent>::Inherent ),* ) -> Self {
Self {
$( $module, )*
}
}
fn create_inherent_extrinsics(self) -> Vec<$unchecked> {
let mut inherent = $crate::inherent::Vec::new();
$(
inherent.extend(
<$module_ty as $crate::inherent::ProvideInherent>::create_inherent_extrinsics(self.$module)
.into_iter()
.map(|v| (v.0, $unchecked::new_unsigned($call::$module_ty(v.1))))
);
)*
inherent.as_mut_slice().sort_unstable_by_key(|v| v.0);
inherent.into_iter().map(|v| v.1).collect()
}
fn check_inherents(self, block: $block) -> $crate::inherent::Result<(), $error> {
$(
<$module_ty as $crate::inherent::ProvideInherent>::check_inherent(
&block, self.$module, &|xt| match xt.function {
Call::$module_ty(ref data) => Some(data),
_ => None,
}).map_err($error::$module_ty)?;
)*
Ok(())
}
}
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Encode)]
#[cfg_attr(feature = "std", derive(Decode))]
pub enum $error {
$( $module_ty(<$module_ty as $crate::inherent::ProvideInherent>::Error), )*
}
};
}
+3 -10
View File
@@ -21,15 +21,12 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate serde;
extern crate sr_std as rstd;
extern crate sr_io as runtime_io;
#[cfg(feature = "std")]
#[doc(hidden)]
pub extern crate sr_primitives as runtime_primitives;
extern crate substrate_metadata;
@@ -49,12 +46,6 @@ extern crate parity_codec_derive;
pub extern crate parity_codec as codec;
pub use self::storage::generator::Storage as GenericStorage;
#[cfg(feature = "std")]
pub mod alloc {
pub use std::boxed;
pub use std::vec;
}
#[macro_use]
pub mod dispatch;
#[macro_use]
@@ -68,6 +59,8 @@ mod origin;
pub mod metadata;
#[macro_use]
mod runtime;
#[macro_use]
pub mod inherent;
pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap};
pub use self::hashable::Hashable;
+130 -9
View File
@@ -47,12 +47,16 @@
#[macro_export]
macro_rules! construct_runtime {
(
pub enum $runtime:ident with Log ($log_internal:ident: DigestItem<$( $log_genarg:ty ),+>) {
pub enum $runtime:ident with Log ($log_internal:ident: DigestItem<$( $log_genarg:ty ),+>)
where Block = $block:ident, UncheckedExtrinsic = $unchecked:ident
{
$( $rest:tt )*
}
) => {
construct_runtime!(
$runtime;
$block;
$unchecked;
$log_internal < $( $log_genarg ),* >;
;
$( $rest )*
@@ -60,6 +64,8 @@ macro_rules! construct_runtime {
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$log_internal:ident <$( $log_genarg:ty ),+>;
$(
$expanded_name:ident: $expanded_module:ident::{
@@ -85,6 +91,8 @@ macro_rules! construct_runtime {
) => {
construct_runtime!(
$runtime;
$block;
$unchecked;
$log_internal < $( $log_genarg ),* >;
$(
$expanded_name: $expanded_module::{
@@ -110,6 +118,8 @@ macro_rules! construct_runtime {
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$log_internal:ident <$( $log_genarg:ty ),+>;
$(
$expanded_name:ident: $expanded_module:ident::{
@@ -142,6 +152,8 @@ macro_rules! construct_runtime {
) => {
construct_runtime!(
$runtime;
$block;
$unchecked;
$log_internal < $( $log_genarg ),* >;
$(
$expanded_name: $expanded_module::{
@@ -173,6 +185,8 @@ macro_rules! construct_runtime {
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$log_internal:ident <$( $log_genarg:ty ),+>;
$(
$expanded_name:ident: $expanded_module:ident::{
@@ -204,6 +218,8 @@ macro_rules! construct_runtime {
) => {
construct_runtime!(
$runtime;
$block;
$unchecked;
$log_internal < $( $log_genarg ),* >;
$(
$expanded_name: $expanded_module::{
@@ -234,6 +250,8 @@ macro_rules! construct_runtime {
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$log_internal:ident <$( $log_genarg:ty ),+>;
$(
$name:ident: $module:ident::{
@@ -245,6 +263,13 @@ macro_rules! construct_runtime {
}
),*;
) => {
mashup! {
$(
substrate_generate_ident_name["config-ident" $name] = $name Config;
substrate_generate_ident_name["inherent-error-ident" $name] = $name InherentError;
)*
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct $runtime;
@@ -298,6 +323,15 @@ macro_rules! construct_runtime {
$name: $module::{ $( $modules $( <$modules_generic> )* ),* }
),*;
);
__decl_outer_inherent!(
$runtime;
$block;
$unchecked;
;
$(
$name: $module::{ $( $modules $( <$modules_generic> )* ),* }
),*;
);
}
}
@@ -980,17 +1014,104 @@ macro_rules! __decl_outer_config {
$( $parsed_modules:ident :: $parsed_name:ident ),*;
;
) => {
mashup! {
$(
substrate_generate_config_name["config-name" $parsed_name] = $parsed_name Config;
)*
}
substrate_generate_config_name! {
substrate_generate_ident_name! {
impl_outer_config!(
pub struct GenesisConfig for $runtime {
$(
"config-name" $parsed_name => $parsed_modules,
"config-ident" $parsed_name => $parsed_modules,
)*
}
);
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __decl_outer_inherent {
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$( $parsed_modules:ident :: $parsed_name:ident ),*;
$name:ident: $module:ident::{
Inherent $(, $modules:ident $( <$modules_generic:ident> )* )*
}
$(, $rest_name:ident : $rest_module:ident::{
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_outer_inherent!(
$runtime;
$block;
$unchecked;
$( $parsed_modules :: $parsed_name, )* $module::$name;
$(
$rest_name: $rest_module::{
$( $rest_modules $( <$rest_modules_generic> )* ),*
}
),*;
);
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$( $parsed_modules:ident :: $parsed_name:ident ),*;
$name:ident: $module:ident::{
$ingore:ident $( <$ignor:ident> )* $(, $modules:ident $( <$modules_generic:ident> )* )*
}
$(, $rest_name:ident : $rest_module:ident::{
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_outer_inherent!(
$runtime;
$block;
$unchecked;
$( $parsed_modules :: $parsed_name ),*;
$name: $module::{ $( $modules $( <$modules_generic> )* ),* }
$(
, $rest_name: $rest_module::{
$( $rest_modules $( <$rest_modules_generic> )* ),*
}
)*;
);
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$( $parsed_modules:ident :: $parsed_name:ident ),*;
$name:ident: $module:ident::{}
$(, $rest_name:ident : $rest_module:ident::{
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_outer_inherent!(
$runtime;
$block;
$unchecked;
$( $parsed_modules :: $parsed_name ),*;
$(
$rest_name: $rest_module::{
$( $rest_modules $( <$rest_modules_generic> )* ),*
}
),*;
);
};
(
$runtime:ident;
$block:ident;
$unchecked:ident;
$( $parsed_modules:ident :: $parsed_name:ident ),*;
;
) => {
substrate_generate_ident_name! {
impl_outer_inherent!(
pub struct InherentData where Block = $block, UncheckedExtrinsic = $unchecked {
$(
$parsed_modules: $parsed_name export Error as "inherent-error-ident" $parsed_name,
)*
}
);
+2
View File
@@ -7,6 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
hex-literal = "0.1.0"
serde = { version = "1.0", default-features = false }
serde_derive = { version = "1.0", optional = true }
parity-codec-derive = { version = "2.1", default-features = false }
parity-codec = { version = "2.1", default-features = false }
substrate-primitives = { path = "../../core/primitives", default-features = false }
sr-std = { path = "../../core/sr-std", default-features = false }
@@ -29,6 +30,7 @@ std = [
"srml-consensus/std",
"serde/std",
"serde_derive",
"parity-codec-derive/std",
"parity-codec/std",
"substrate-primitives/std",
"srml-system/std",
+47 -5
View File
@@ -33,6 +33,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate sr_std as rstd;
#[macro_use]
@@ -50,14 +51,18 @@ extern crate sr_primitives as runtime_primitives;
extern crate srml_system as system;
extern crate srml_consensus as consensus;
extern crate parity_codec as codec;
#[macro_use]
extern crate parity_codec_derive;
use codec::HasCompact;
use runtime_support::{StorageValue, Parameter};
use runtime_support::dispatch::Result;
use runtime_primitives::traits::{As, OnFinalise, SimpleArithmetic, Zero};
use runtime_primitives::RuntimeString;
use runtime_primitives::traits::{
As, OnFinalise, SimpleArithmetic, Zero, ProvideInherent, Block as BlockT, Extrinsic
};
use system::ensure_inherent;
use rstd::ops::{Mul, Div};
use rstd::{result, ops::{Mul, Div}, vec::Vec};
pub trait Trait: consensus::Trait + system::Trait {
/// The position of the required timestamp-set extrinsic.
@@ -106,7 +111,7 @@ impl<T: Trait> Module<T> {
fn set(origin: T::Origin, now: <T::Moment as HasCompact>::Type) -> Result {
ensure_inherent(origin)?;
let now = now.into();
assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block");
assert!(
<system::Module<T>>::extrinsic_index() == Some(T::TIMESTAMP_SET_POSITION),
@@ -123,12 +128,49 @@ impl<T: Trait> Module<T> {
}
/// Set the timestamp to something in particular. Only used for tests.
#[cfg(any(feature = "std", test))]
#[cfg(feature = "std")]
pub fn set_timestamp(now: T::Moment) {
<Self as Store>::Now::put(now);
}
}
#[derive(Encode)]
#[cfg_attr(feature = "std", derive(Decode))]
pub enum InherentError {
Other(RuntimeString),
TimestampInFuture(u64),
}
impl<T: Trait> ProvideInherent for Module<T> {
type Inherent = T::Moment;
type Call = Call<T>;
type Error = InherentError;
fn create_inherent_extrinsics(data: Self::Inherent) -> Vec<(u32, Self::Call)> {
vec![(T::TIMESTAMP_SET_POSITION, Call::set(data.into()))]
}
fn check_inherent<Block: BlockT, F: Fn(&Block::Extrinsic) -> Option<&Self::Call>>(
block: &Block, data: Self::Inherent, extract_function: &F
) -> result::Result<(), Self::Error> {
const MAX_TIMESTAMP_DRIFT: u64 = 60;
let xt = block.extrinsics().get(T::TIMESTAMP_SET_POSITION as usize)
.ok_or_else(|| InherentError::Other("No valid timestamp inherent in block".into()))?;
let t = match (xt.is_signed(), extract_function(&xt)) {
(Some(false), Some(Call::set(ref t))) => t.clone(),
_ => return Err(InherentError::Other("No valid timestamp inherent in block".into())),
}.into().as_();
if t > data.as_() + MAX_TIMESTAMP_DRIFT {
Err(InherentError::TimestampInFuture(t))
} else {
Ok(())
}
}
}
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
assert!(<Self as Store>::DidUpdate::take(), "Timestamp must be updated once in the block");