Add OnInitialise handler. (#1690)

* Add OnInitialise handler.

Closes #1686

* Fix typo

* Fix wasm build

* Add tests for initialise and finalise.
This commit is contained in:
Gav Wood
2019-02-06 10:01:28 +01:00
committed by Bastian Köcher
parent 0eeef28382
commit fa2e323478
6 changed files with 197 additions and 64 deletions
@@ -251,6 +251,15 @@ pub trait OnFinalise<BlockNumber> {
impl<N> OnFinalise<N> for () {}
/// The block initialisation trait. Implementing this lets you express what should happen
/// for your module when the block is beginning (right before the first extrinsic is executed).
pub trait OnInitialise<BlockNumber> {
/// The block is being initialised. Implement to have something happen.
fn on_initialise(_n: BlockNumber) {}
}
impl<N> OnInitialise<N> for () {}
macro_rules! tuple_impl {
($one:ident,) => {
impl<Number: Copy, $one: OnFinalise<Number>> OnFinalise<Number> for ($one,) {
@@ -258,6 +267,11 @@ macro_rules! tuple_impl {
$one::on_finalise(n);
}
}
impl<Number: Copy, $one: OnInitialise<Number>> OnInitialise<Number> for ($one,) {
fn on_initialise(n: Number) {
$one::on_initialise(n);
}
}
};
($first:ident, $($rest:ident,)+) => {
impl<
@@ -270,6 +284,16 @@ macro_rules! tuple_impl {
$($rest::on_finalise(n);)+
}
}
impl<
Number: Copy,
$first: OnInitialise<Number>,
$($rest: OnInitialise<Number>),+
> OnInitialise<Number> for ($first, $($rest),+) {
fn on_initialise(n: Number) {
$first::on_initialise(n);
$($rest::on_initialise(n);)+
}
}
tuple_impl!($($rest,)+);
}
}
+2 -2
View File
@@ -66,8 +66,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 19,
impl_version: 19,
spec_version: 20,
impl_version: 20,
apis: RUNTIME_API_VERSIONS,
};
+57 -48
View File
@@ -31,7 +31,8 @@ extern crate sr_io;
#[cfg(test)]
extern crate substrate_primitives;
// Needed for various traits. In our case, `OnFinalise`.
// Needed for various traits. In our case, `OnInitialise` and `OnFinalise` in our
// tests.
extern crate sr_primitives;
// Needed for deriving `Encode` and `Decode` for `RawEvent`.
@@ -63,6 +64,52 @@ pub trait Trait: balances::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
decl_storage! {
// A macro for the Storage trait, and its implementation, for this module.
// This allows for type-safe usage of the Substrate storage database, so you can
// keep things around between blocks.
trait Store for Module<T: Trait> as Example {
// Any storage declarations of the form:
// `pub? Name get(getter_name)? [config()|config(myname)] [build(|_| {...})] : <type> (= <new_default_value>)?;`
// where `<type>` is either:
// - `Type` (a basic value item); or
// - `map KeyType => ValueType` (a map item).
//
// Note that there are two optional modifiers for the storage type declaration.
// - `Foo: Option<u32>`:
// - `Foo::put(1); Foo::get()` returns `Some(1)`;
// - `Foo::kill(); Foo::get()` returns `None`.
// - `Foo: u32`:
// - `Foo::put(1); Foo::get()` returns `1`;
// - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
// e.g. Foo: u32;
// e.g. pub Bar get(bar): map T::AccountId => Vec<(T::Balance, u64)>;
//
// For basic value items, you'll get a type which implements
// `support::StorageValue`. For map items, you'll get a type which
// implements `support::StorageMap`.
//
// If they have a getter (`get(getter_name)`), then your module will come
// equipped with `fn getter_name() -> Type` for basic value items or
// `fn getter_name(key: KeyType) -> ValueType` for map items.
Dummy get(dummy) config(): Option<T::Balance>;
// this one uses the default, we'll demonstrate the usage of 'mutate' API.
Foo get(foo) config(): T::Balance;
}
}
/// An event in this module. Events are simple means of reporting specific conditions and
/// circumstances that have happened that users, Dapps and/or chain explorers would find
/// interesting and otherwise difficult to detect.
decl_event!(
pub enum Event<T> where B = <T as balances::Trait>::Balance {
// Just a normal `enum`, here's a dummy event to ensure it compiles.
/// Dummy event, just here so there's a generic type that's used.
Dummy(B),
}
);
// The module declaration. This states the entry points that we handle. The
// macro takes care of the marshalling of arguments and dispatch.
//
@@ -182,6 +229,12 @@ decl_module! {
<Dummy<T>>::put(new_value);
}
// The signature could also look like: `fn on_initialise()`
fn on_initialise(_n: T::BlockNumber) {
// Anything that needs to be done at the start of the block.
// We don't do anything here.
}
// The signature could also look like: `fn on_finalise()`
fn on_finalise(_n: T::BlockNumber) {
// Anything that needs to be done at the end of the block.
@@ -191,52 +244,6 @@ decl_module! {
}
}
/// An event in this module. Events are simple means of reporting specific conditions and
/// circumstances that have happened that users, Dapps and/or chain explorers would find
/// interesting and otherwise difficult to detect.
decl_event!(
pub enum Event<T> where B = <T as balances::Trait>::Balance {
// Just a normal `enum`, here's a dummy event to ensure it compiles.
/// Dummy event, just here so there's a generic type that's used.
Dummy(B),
}
);
decl_storage! {
// A macro for the Storage trait, and its implementation, for this module.
// This allows for type-safe usage of the Substrate storage database, so you can
// keep things around between blocks.
trait Store for Module<T: Trait> as Example {
// Any storage declarations of the form:
// `pub? Name get(getter_name)? [config()|config(myname)] [build(|_| {...})] : <type> (= <new_default_value>)?;`
// where `<type>` is either:
// - `Type` (a basic value item); or
// - `map KeyType => ValueType` (a map item).
//
// Note that there are two optional modifiers for the storage type declaration.
// - `Foo: Option<u32>`:
// - `Foo::put(1); Foo::get()` returns `Some(1)`;
// - `Foo::kill(); Foo::get()` returns `None`.
// - `Foo: u32`:
// - `Foo::put(1); Foo::get()` returns `1`;
// - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
// e.g. Foo: u32;
// e.g. pub Bar get(bar): map T::AccountId => Vec<(T::Balance, u64)>;
//
// For basic value items, you'll get a type which implements
// `support::StorageValue`. For map items, you'll get a type which
// implements `support::StorageMap`.
//
// If they have a getter (`get(getter_name)`), then your module will come
// equipped with `fn getter_name() -> Type` for basic value items or
// `fn getter_name(key: KeyType) -> ValueType` for map items.
Dummy get(dummy) config(): Option<T::Balance>;
// this one uses the default, we'll demonstrate the usage of 'mutate' API.
Foo get(foo) config(): T::Balance;
}
}
// The main implementation block for the module. Functions here fall into three broad
// categories:
// - Public interface. These are functions that are `pub` and generally fall into inspector
@@ -269,7 +276,8 @@ mod tests {
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried.
use sr_primitives::{
BuildStorage, traits::{BlakeTwo256, OnFinalise, IdentityLookup}, testing::{Digest, DigestItem, Header}
BuildStorage, traits::{BlakeTwo256, OnInitialise, OnFinalise, IdentityLookup},
testing::{Digest, DigestItem, Header}
};
impl_outer_origin! {
@@ -334,6 +342,7 @@ mod tests {
assert_eq!(Example::dummy(), None);
// Check that accumulate works when we Dummy has None in it.
<Example as OnInitialise<u64>>::on_initialise(2);
assert_ok!(Example::accumulate_dummy(Origin::signed(1), 42));
assert_eq!(Example::dummy(), Some(42));
});
+8 -7
View File
@@ -45,7 +45,7 @@ use rstd::prelude::*;
use rstd::marker::PhantomData;
use rstd::result;
use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalise,
MakePayment, Hash, As, Digest};
OnInitialise, MakePayment, Hash, As, Digest};
use runtime_support::Dispatchable;
use codec::{Codec, Encode};
use system::extrinsics_root;
@@ -74,16 +74,16 @@ pub struct Executive<
Block,
Context,
Payment,
Finalisation,
>(PhantomData<(System, Block, Context, Payment, Finalisation)>);
AllModules,
>(PhantomData<(System, Block, Context, Payment, AllModules)>);
impl<
Context: Default,
System: system::Trait,
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
Payment: MakePayment<System::AccountId>,
Finalisation: OnFinalise<System::BlockNumber>,
> Executive<System, Block, Context, Payment, Finalisation> where
AllModules: OnInitialise<System::BlockNumber> + OnFinalise<System::BlockNumber>,
> Executive<System, Block, Context, Payment, AllModules> where
Block::Extrinsic: Checkable<Context> + Codec,
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
@@ -92,6 +92,7 @@ impl<
/// Start the execution of a particular block.
pub fn initialise_block(header: &System::Header) {
<system::Module<System>>::initialise(header.number(), header.parent_hash(), header.extrinsics_root());
<AllModules as OnInitialise<System::BlockNumber>>::on_initialise(*header.number());
}
fn initial_checks(block: &Block) {
@@ -123,7 +124,7 @@ impl<
// post-transactional book-keeping.
<system::Module<System>>::note_finished_extrinsics();
Finalisation::on_finalise(*header.number());
<AllModules as OnFinalise<System::BlockNumber>>::on_finalise(*header.number());
// any final checks
Self::final_checks(&header);
@@ -133,7 +134,7 @@ impl<
/// except state-root.
pub fn finalise_block() -> System::Header {
<system::Module<System>>::note_finished_extrinsics();
Finalisation::on_finalise(<system::Module<System>>::block_number());
<AllModules as OnFinalise<System::BlockNumber>>::on_finalise(<system::Module<System>>::block_number());
// setup extrinsics
<system::Module<System>>::derive_extrinsics();
+106 -7
View File
@@ -86,8 +86,8 @@ impl<T> Parameter for T where T: Codec + Clone + Eq {}
/// corresponding to a function of the module. This enum implements Callable and thus its values
/// can be used as an extrinsic's payload.
///
/// The `on_finalise` function is special, since it can either take no parameters,
/// or one parameter, which has the runtime's block number type.
/// The `on_initialise` and `on_finalise` functions are special, since it can either take no
/// parameters, or one parameter, which has the runtime's block number type.
#[macro_export]
macro_rules! decl_module {
// Macro transformations (to convert invocations with incomplete parameters to the canonical
@@ -105,6 +105,7 @@ macro_rules! decl_module {
for enum $call_type where origin: $origin_type, system = system
{}
{}
{}
[]
$($t)*
);
@@ -122,6 +123,7 @@ macro_rules! decl_module {
for enum $call_type where origin: $origin_type, system = $system
{}
{}
{}
[]
$($t)*
);
@@ -132,6 +134,7 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{}
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -143,6 +146,7 @@ macro_rules! decl_module {
pub struct $mod_type<$trait_instance: $trait_name>
for enum $call_type where origin: $origin_type, system = $system
{ $vis fn deposit_event $(<$dpeg>)* () = default; }
{ $( $on_initialise )* }
{ $( $on_finalise )* }
[ $($t)* ]
$($rest)*
@@ -153,6 +157,7 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{}
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -166,6 +171,7 @@ macro_rules! decl_module {
pub struct $mod_type<$trait_instance: $trait_name>
for enum $call_type where origin: $origin_type, system = $system
{ $vis fn deposit_event $(<$dpeg>)* ($( $param_name: $param ),* ) { $( $impl )* } }
{ $( $on_initialise )* }
{ $( $on_finalise )* }
[ $($t)* ]
$($rest)*
@@ -175,7 +181,8 @@ macro_rules! decl_module {
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{}
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -187,6 +194,7 @@ macro_rules! decl_module {
pub struct $mod_type<$trait_instance: $trait_name>
for enum $call_type where origin: $origin_type, system = $system
{ $( $deposit_event )* }
{ $( $on_initialise )* }
{ fn on_finalise( $( $param_name : $param ),* ) { $( $impl )* } }
[ $($t)* ]
$($rest)*
@@ -197,6 +205,30 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{}
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
fn on_initialise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
$($rest:tt)*
) => {
decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<$trait_instance: $trait_name>
for enum $call_type where origin: $origin_type, system = $system
{ $( $deposit_event )* }
{ fn on_initialise( $( $param_name : $param ),* ) { $( $impl )* } }
{ $( $on_finalise )* }
[ $($t)* ]
$($rest)*
);
};
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -210,6 +242,7 @@ macro_rules! decl_module {
pub struct $mod_type<$trait_instance: $trait_name>
for enum $call_type where origin: $origin_type, system = $system
{ $( $deposit_event )* }
{ $( $on_initialise )* }
{ $( $on_finalise )* }
[
$($t)*
@@ -226,6 +259,7 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -245,6 +279,7 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -264,6 +299,7 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
@@ -277,6 +313,7 @@ macro_rules! decl_module {
pub struct $mod_type<$trait_instance: $trait_name>
for enum $call_type where origin: $origin_type, system = $system
{ $( $deposit_event )* }
{ $( $on_initialise )* }
{ $( $on_finalise )* }
[
$($t)*
@@ -293,6 +330,7 @@ macro_rules! decl_module {
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
[ $($t:tt)* ]
) => {
@@ -303,6 +341,7 @@ macro_rules! decl_module {
$($t)*
}
{ $( $deposit_event )* }
{ $( $on_initialise )* }
{ $( $on_finalise )* }
);
};
@@ -374,13 +413,47 @@ macro_rules! decl_module {
}
};
(@impl_on_initialise
$module:ident<$trait_instance:ident: $trait_name:ident>;
fn on_initialise() { $( $impl:tt )* }
) => {
impl<$trait_instance: $trait_name>
$crate::runtime_primitives::traits::OnInitialise<$trait_instance::BlockNumber>
for $module<$trait_instance>
{
fn on_initialise(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* }
}
};
(@impl_on_initialise
$module:ident<$trait_instance:ident: $trait_name:ident>;
fn on_initialise($param:ident : $param_ty:ty) { $( $impl:tt )* }
) => {
impl<$trait_instance: $trait_name>
$crate::runtime_primitives::traits::OnInitialise<$trait_instance::BlockNumber>
for $module<$trait_instance>
{
fn on_initialise($param: $param_ty) { $( $impl )* }
}
};
(@impl_on_initialise
$module:ident<$trait_instance:ident: $trait_name:ident>;
) => {
impl<$trait_instance: $trait_name>
$crate::runtime_primitives::traits::OnInitialise<$trait_instance::BlockNumber>
for $module<$trait_instance>
{}
};
(@impl_on_finalise
$module:ident<$trait_instance:ident: $trait_name:ident>;
fn on_finalise() { $( $impl:tt )* }
) => {
impl<$trait_instance: $trait_name>
$crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber>
for $module<$trait_instance> {
for $module<$trait_instance>
{
fn on_finalise(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* }
}
};
@@ -391,7 +464,8 @@ macro_rules! decl_module {
) => {
impl<$trait_instance: $trait_name>
$crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber>
for $module<$trait_instance> {
for $module<$trait_instance>
{
fn on_finalise($param: $param_ty) { $( $impl )* }
}
};
@@ -401,7 +475,9 @@ macro_rules! decl_module {
) => {
impl<$trait_instance: $trait_name>
$crate::runtime_primitives::traits::OnFinalise<$trait_instance::BlockNumber>
for $module<$trait_instance> {}
for $module<$trait_instance>
{
}
};
(@impl_function
@@ -480,6 +556,7 @@ macro_rules! decl_module {
)*
}
{ $( $deposit_event:tt )* }
{ $( $on_initialise:tt )* }
{ $( $on_finalise:tt )* }
) => {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
@@ -497,6 +574,12 @@ macro_rules! decl_module {
#[cfg(not(feature = "std"))]
pub struct $mod_type<$trait_instance: $trait_name>(::core::marker::PhantomData<$trait_instance>);
decl_module! {
@impl_on_initialise
$mod_type<$trait_instance: $trait_name>;
$( $on_initialise )*
}
decl_module! {
@impl_on_finalise
$mod_type<$trait_instance: $trait_name>;
@@ -972,10 +1055,11 @@ macro_rules! __function_to_metadata {
#[allow(dead_code)]
mod tests {
use super::*;
use crate::runtime_primitives::traits::{OnInitialise, OnFinalise};
pub trait Trait {
type Origin;
type BlockNumber;
type BlockNumber: Into<u32>;
}
pub mod system {
@@ -994,6 +1078,9 @@ mod tests {
fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() }
fn aux_3() -> Result { unreachable!() }
fn aux_4(_data: i32) -> Result { unreachable!() }
fn on_initialise(n: T::BlockNumber) { if n.into() == 42 { panic!("on_initialise") } }
fn on_finalise(n: T::BlockNumber) { if n.into() == 42 { panic!("on_finalise") } }
}
}
@@ -1065,4 +1152,16 @@ mod tests {
let encoded = call.encode();
assert_eq!(encoded.len(), 2);
}
#[test]
#[should_panic(expected = "on_initialise")]
fn on_initialise_should_work() {
<Module<TraitImpl> as OnInitialise<u32>>::on_initialise(42);
}
#[test]
#[should_panic(expected = "on_finalise")]
fn on_finalise_should_work() {
<Module<TraitImpl> as OnFinalise<u32>>::on_finalise(42);
}
}