// Copyright 2017-2019 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 . //! Dispatch system. Contains a macro for defining runtime modules and //! generating values representing lazy module function calls. pub use crate::rstd::prelude::{Vec, Clone, Eq, PartialEq}; #[cfg(feature = "std")] pub use std::fmt; pub use crate::rstd::result; pub use crate::codec::{Codec, Decode, Encode, Input, Output, HasCompact, EncodeAsRef}; pub use srml_metadata::{FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata}; /// A type that cannot be instantiated. pub enum Never {} /// Result of a module function call; either nothing (functions are only called for "side effects") /// or an error message. pub type Result = result::Result<(), &'static str>; /// A lazy call (module function and argument values) that can be executed via its `dispatch` /// method. pub trait Dispatchable { /// Every function call from your runtime has an origin, which specifies where the extrinsic was /// generated from. In the case of a signed extrinsic (transaction), the origin contains an /// identifier for the caller. The origin can be empty in the case of an inherent extrinsic. type Origin; type Trait; fn dispatch(self, origin: Self::Origin) -> Result; } /// Serializable version of Dispatchable. /// This value can be used as a "function" in an extrinsic. pub trait Callable { type Call: Dispatchable + Codec + Clone + PartialEq + Eq; } // dirty hack to work around serde_derive issue // https://github.com/rust-lang/rust/issues/51331 pub type CallableCallFor = ::Call; #[cfg(feature = "std")] pub trait Parameter: Codec + Clone + Eq + fmt::Debug {} #[cfg(feature = "std")] impl Parameter for T where T: Codec + Clone + Eq + fmt::Debug {} #[cfg(not(feature = "std"))] pub trait Parameter: Codec + Clone + Eq {} #[cfg(not(feature = "std"))] impl Parameter for T where T: Codec + Clone + Eq {} /// Declares a `Module` struct and a `Call` enum, which implements the dispatch logic. /// /// ## Declaration /// /// ``` /// # #[macro_use] /// # extern crate srml_support; /// # use srml_support::dispatch::Result; /// # use srml_system::{self as system, Trait, ensure_signed}; /// decl_module! { /// pub struct Module for enum Call where origin: T::Origin { /// /// // Private functions are dispatchable, but not available to other /// // SRML modules. /// fn my_function(origin, var: u64) -> Result { /// // Your implementation /// Ok(()) /// } /// /// // Public functions are both dispatchable and available to other /// // SRML modules. /// pub fn my_public_function(origin) -> Result { /// // Your implementation /// Ok(()) /// } /// } /// } /// # fn main() {} /// ``` /// /// The declaration is set with the header where: /// /// * `Module`: The struct generated by the macro, with type `Trait`. /// * `Call`: The enum generated for every module, which implements [`Callable`](./dispatch/trait.Callable.html). /// * `origin`: Alias of `T::Origin`, declared by the [`impl_outer_origin!`](./macro.impl_outer_origin.html) macro. /// * `Result`: The expected return type from module functions. /// /// ### Shorthand Example /// /// The macro automatically expands a shorthand function declaration to return the `Result` type. /// These functions are the same: /// /// ``` /// # #[macro_use] /// # extern crate srml_support; /// # use srml_support::dispatch::Result; /// # use srml_system::{self as system, Trait, ensure_signed}; /// decl_module! { /// pub struct Module for enum Call where origin: T::Origin { /// /// fn my_long_function(origin) -> Result { /// // Your implementation /// Ok(()) /// } /// /// fn my_short_function(origin) { /// // Your implementation /// } /// } /// } /// # fn main() {} /// ``` /// /// ### Privileged Function Example /// /// If the `origin` param is omitted, the macro adds it as the first parameter and adds `ensure_root(origin)` /// as the first line of the function. These functions are the same: /// /// ``` /// # #[macro_use] /// # extern crate srml_support; /// # use srml_support::dispatch::Result; /// # use srml_system::{self as system, Trait, ensure_signed, ensure_root}; /// decl_module! { /// pub struct Module for enum Call where origin: T::Origin { /// /// fn my_privileged_function() -> Result { /// // Your implementation /// Ok(()) /// } /// /// fn my_function(origin) -> Result { /// ensure_root(origin); /// // Your implementation /// Ok(()) /// } /// } /// } /// # fn main() {} /// ``` /// /// ## Multiple Module Instances Example /// /// A Substrate module can be built such that multiple instances of the same module can be used within a single /// runtime. For example, the [Balances module](../srml_balances/index.html) can be added multiple times to your /// runtime in order to support multiple, independent currencies for your blockchain. Here is an example of how /// you would declare such a module using the `decl_module!` macro: /// /// ``` /// # #[macro_use] /// # extern crate srml_support; /// # use srml_support::dispatch::Result; /// # use srml_system::{self as system, ensure_signed}; /// # pub struct DefaultInstance; /// # pub trait Instance {} /// # impl Instance for DefaultInstance {} /// pub trait Trait: system::Trait {} /// /// decl_module! { /// pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { /// // Your implementation /// } /// } /// # fn main() {} /// ``` /// /// ## Reserved Functions /// /// The following are reserved function signatures: /// /// * `deposit_event`: Helper function for depositing an [event](https://docs.substrate.dev/docs/event-enum). /// The default behavior is to call `deposit_event` from the [System module](../srml_system/index.html). /// However, you can write your own implementation for events in your runtime. To use the default behavior, /// add `fn deposit_event() = default;` to your `Module`. /// /// The following reserved functions also take the block number (with type `T::BlockNumber`) as an optional input: /// /// * `on_initialize`: Executes at the beginning of a block. Using this function will /// implement the [`OnInitialize`](../sr_primitives/traits/trait.OnInitialize.html) trait. /// * `on_finalize`: Executes at the end of a block. Using this function will /// implement the [`OnFinalize`](../sr_primitives/traits/trait.OnFinalize.html) trait. /// * `offchain_worker`: Executes at the beginning of a block and produces extrinsics for a future block /// upon completion. Using this function will implement the /// [`OffchainWorker`](../sr_primitives/traits/trait.OffchainWorker.html) trait. #[macro_export] macro_rules! decl_module { // Macro transformations (to convert invocations with incomplete parameters to the canonical // form) ( $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty { $($t:tt)* } ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = system {} {} {} {} [] $($t)* ); }; ( $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $($t:tt)* } ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system {} {} {} {} [] $($t)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident {} { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $vis:vis fn deposit_event $(<$dpeg:ident $(, $dpeg_instance:ident)?>)* () = default; $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $vis fn deposit_event $(<$dpeg $(, $dpeg_instance)?>)* () = default; } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident {} { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $vis:vis fn deposit_event $(<$dpeg:ident $(, $dpeg_instance:ident)?>)* ( $($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $vis fn deposit_event $(<$dpeg $(, $dpeg_instance)?>)* ($( $param_name: $param ),* ) { $( $impl )* } } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } {} { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn on_finalize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $( $deposit_event )* } { $( $on_initialize )* } { fn on_finalize( $( $param_name : $param ),* ) { $( $impl )* } } { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } {} { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn on_finalise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { compile_error!( "`on_finalise` was renamed to `on_finalize`. Please rename your function accordingly." ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } {} { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn on_initialize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $( $deposit_event )* } { fn on_initialize( $( $param_name : $param ),* ) { $( $impl )* } } { $( $on_finalize )* } { $( $offchain )* } [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } {} { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn on_initialise($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { compile_error!( "`on_initialise` was renamed to `on_initialize`. Please rename your function accordingly." ); }; (@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_initialize:tt )* } { $( $on_finalize:tt )* } { } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* fn offchain_worker($($param_name:ident : $param:ty),* ) { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name> for enum $call_type where origin: $origin_type, system = $system { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { fn offchain_worker( $( $param_name : $param ),* ) { $( $impl )* } } [ $($t)* ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( $origin:ident $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)* ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, $instance: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } [ $($t)* $(#[doc = $doc_attr])* $fn_vis fn $fn_name( $origin $( , $(#[$codec_attr])* $param_name : $param )* ) $( -> $result )* { $( $impl )* } { $($instance: $instantiable)? } ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( $origin:ident : T::Origin $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)* ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { compile_error!( "First parameter of dispatch should be marked `origin` only, with no type specified \ (a bit like `self`). (For root-matching dispatches, ensure the first parameter does \ not use the `T::Origin` type.)" ) }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( origin : $origin:ty $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)* ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { compile_error!( "First parameter of dispatch should be marked `origin` only, with no type specified \ (a bit like `self`). (For root-matching dispatches, ensure the first parameter does \ not use the `T::Origin` type.)" ) }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( $( $(#[$codec_attr:ident])* $param_name:ident : $param:ty),* ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { $crate::decl_module!(@normalize $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, $instance: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } [ $($t)* $(#[doc = $doc_attr])* $fn_vis fn $fn_name( root $( , $(#[$codec_attr])* $param_name : $param )* ) $( -> $result )* { $( $impl )* } { $($instance: $instantiable)? } ] $($rest)* ); }; (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } [ $($t:tt)* ] ) => { $crate::decl_module!(@imp $(#[$attr])* pub struct $mod_type<$trait_instance: $trait_name$(, I: $instantiable $(= $module_default_instance)?)?> for enum $call_type where origin: $origin_type, system = $system { $($t)* } { $( $deposit_event )* } { $( $on_initialize )* } { $( $on_finalize )* } { $( $offchain )* } ); }; // Implementation of Call enum's .dispatch() method. // TODO: this probably should be a different macro? (@call root $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] ) => { { $system::ensure_root($origin)?; <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $( $param_name ),* ) } }; (@call $ingore:ident $mod_type:ident<$trait_instance:ident $(, $instance:ident)?> $fn_name:ident $origin:ident $system:ident [ $( $param_name:ident),* ] ) => { <$mod_type<$trait_instance $(, $instance)?>>::$fn_name( $origin $(, $param_name )* ) }; // no `deposit_event` function wanted (@impl_deposit_event $module:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path)?>; $system:ident; ) => {}; (@impl_deposit_event $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $system:ident; $vis:vis fn deposit_event$(<$event_trait_instance:ident $(, $event_instance:ident)?>)?() = default; ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> { $vis fn deposit_event(event: Event$(<$event_trait_instance $(, $event_instance)?>)?) { <$system::Module<$trait_instance>>::deposit_event( <$trait_instance as $trait_name$(<$instance>)?>::Event::from(event).into() ); } } }; (@impl_deposit_event $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $system:ident; $vis:vis fn deposit_event($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $module<$trait_instance $(, $instance)?> { $vis fn deposit_event($param: $param_ty) { $( $impl )* } } }; (@impl_on_initialize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_initialize() { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialize<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { fn on_initialize(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } }; (@impl_on_initialize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_initialize($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialize<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { fn on_initialize($param: $param_ty) { $( $impl )* } } }; (@impl_on_initialize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnInitialize<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> {} }; (@impl_on_finalize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_finalize() { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalize<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { fn on_finalize(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } }; (@impl_on_finalize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn on_finalize($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalize<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { fn on_finalize($param: $param_ty) { $( $impl )* } } }; (@impl_on_finalize $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OnFinalize<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { } }; (@impl_offchain $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn offchain_worker() { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { fn generate_extrinsics(_block_number_not_used: $trait_instance::BlockNumber) { $( $impl )* } } }; (@impl_offchain $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; fn offchain_worker($param:ident : $param_ty:ty) { $( $impl:tt )* } ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> { fn generate_extrinsics($param: $param_ty) { $( $impl )* } } }; (@impl_offchain $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; ) => { impl<$trait_instance: $trait_name$(, $instance: $instantiable)?> $crate::runtime_primitives::traits::OffchainWorker<$trait_instance::BlockNumber> for $module<$trait_instance$(, $instance)?> {} }; (@impl_function $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $origin_ty:ty; root; $(#[doc = $doc_attr:tt])* $vis:vis fn $name:ident ( root $(, $param:ident : $param_ty:ty )* ) { $( $impl:tt )* } ) => { $(#[doc = $doc_attr])* $vis fn $name($( $param: $param_ty ),* ) -> $crate::dispatch::Result { { $( $impl )* } Ok(()) } }; (@impl_function $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $origin_ty:ty; root; $(#[doc = $doc_attr:tt])* $vis:vis fn $name:ident ( root $(, $param:ident : $param_ty:ty )* ) -> $result:ty { $( $impl:tt )* } ) => { $(#[doc = $doc_attr])* $vis fn $name($( $param: $param_ty ),* ) -> $result { $( $impl )* } }; (@impl_function $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $origin_ty:ty; $ignore:ident; $(#[doc = $doc_attr:tt])* $vis:vis fn $name:ident ( $origin:ident $(, $param:ident : $param_ty:ty )* ) { $( $impl:tt )* } ) => { $(#[doc = $doc_attr])* $vis fn $name( $origin: $origin_ty $(, $param: $param_ty )* ) -> $crate::dispatch::Result { { $( $impl )* } Ok(()) } }; (@impl_function $module:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?>; $origin_ty:ty; $ignore:ident; $(#[doc = $doc_attr:tt])* $vis:vis fn $name:ident ( $origin:ident $(, $param:ident : $param_ty:ty )* ) -> $result:ty { $( $impl:tt )* } ) => { $(#[doc = $doc_attr])* $vis fn $name($origin: $origin_ty $(, $param: $param_ty )* ) -> $result { $( $impl )* } }; // Declare a `Call` variant parameter that should be encoded `compact`. (@create_call_enum $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> { $( $generated_variants:tt )* } { $( $current_params:tt )* } variant $fn_name:ident; $( #[doc = $doc_attr:tt] )* #[compact] $type:ty; $( $rest:tt )* ) => { $crate::decl_module! { @create_call_enum $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> { $( $generated_variants )* } { $( $current_params )* #[codec(compact)] $type, } variant $fn_name; $( #[doc = $doc_attr] )* $( $rest )* } }; // Declare a `Call` variant parameter. (@create_call_enum $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> { $( $generated_variants:tt )* } { $( $current_params:tt )* } variant $fn_name:ident; $(#[doc = $doc_attr:tt])* $type:ty; $( $rest:tt )* ) => { $crate::decl_module! { @create_call_enum $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> { $( $generated_variants )* } { $( $current_params )* $type, } variant $fn_name; $( #[doc = $doc_attr] )* $( $rest )* } }; (@create_call_enum $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> { $( $generated_variants:tt )* } { $( $current_params:tt )* } variant $fn_name:ident; $(#[doc = $doc_attr:tt])* $( variant $next_fn_name:ident; $( $rest:tt )* )? ) => { $crate::decl_module! { @create_call_enum $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> { $( $generated_variants )* #[allow(non_camel_case_types)] $(#[doc = $doc_attr])* $fn_name ( $( $current_params )* ), } {} $( variant $next_fn_name; $( $rest )* )? } }; (@create_call_enum $( #[$attr:meta] )* $call_type:ident; <$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> { $( $generated_variants:tt )* } {} ) => { #[derive($crate::codec::Encode, $crate::codec::Decode)] $( #[$attr] )* pub enum $call_type<$trait_instance: $trait_name$(, $instance: $instantiable $( = $module_default_instance)?)?> { #[doc(hidden)] #[codec(skip)] __PhantomItem($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never), $( $generated_variants )* } }; // The main macro expansion that actually renders the module code. (@imp $(#[$attr:meta])* pub struct $mod_type:ident< $trait_instance:ident: $trait_name:ident $(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)? > for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident { $( $(#[doc = $doc_attr:tt])* $fn_vis:vis fn $fn_name:ident( $from:ident $( , $(#[$codec_attr:ident])* $param_name:ident : $param:ty)* ) $( -> $result:ty )* { $( $impl:tt )* } { $($fn_instance:ident: $fn_instantiable:path)? } )* } { $( $deposit_event:tt )* } { $( $on_initialize:tt )* } { $( $on_finalize:tt )* } { $( $offchain:tt )* } ) => { $crate::__check_reserved_fn_name! { $($fn_name)* } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] pub struct $mod_type< $trait_instance: $trait_name $(, $instance: $instantiable $( = $module_default_instance)?)? >($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>); $crate::decl_module! { @impl_on_initialize $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $( $on_initialize )* } $crate::decl_module! { @impl_on_finalize $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $( $on_finalize )* } $crate::decl_module! { @impl_offchain $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $( $offchain )* } $crate::decl_module! { @impl_deposit_event $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; $system; $( $deposit_event )* } /// Can also be called using [`Call`]. /// /// [`Call`]: enum.Call.html impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { $( $crate::decl_module! { @impl_function $mod_type<$trait_instance: $trait_name $(, $fn_instance: $fn_instantiable)?>; $origin_type; $from; $(#[doc = $doc_attr])* $fn_vis fn $fn_name ( $from $(, $param_name : $param )* ) $( -> $result )* { $( $impl )* } } )* } $crate::decl_module! { @create_call_enum $( #[$attr] )* $call_type; <$trait_instance: $trait_name $(, $instance: $instantiable $(= $module_default_instance)? )?> {} {} $( variant $fn_name; $(#[doc = $doc_attr])* $( $(#[$codec_attr])* $param; )* )* } // manual implementation of clone/eq/partialeq because using derive erroneously requires // clone/eq/partialeq from T. impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Clone for $call_type<$trait_instance $(, $instance)?> { fn clone(&self) -> Self { match *self { $( $call_type::$fn_name( $( ref $param_name ),* ) => $call_type::$fn_name( $( (*$param_name).clone() ),* ) ,)* _ => unreachable!(), } } } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::PartialEq for $call_type<$trait_instance $(, $instance)?> { fn eq(&self, _other: &Self) -> bool { match *self { $( $call_type::$fn_name( $( ref $param_name ),* ) => { let self_params = ( $( $param_name, )* ); if let $call_type::$fn_name( $( ref $param_name ),* ) = *_other { self_params == ( $( $param_name, )* ) } else { match *_other { $call_type::__PhantomItem(_, _) => unreachable!(), _ => false, } } } )* _ => unreachable!(), } } } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Eq for $call_type<$trait_instance $(, $instance)?> {} #[cfg(feature = "std")] impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::fmt::Debug for $call_type<$trait_instance $(, $instance)?> { fn fmt(&self, _f: &mut $crate::dispatch::fmt::Formatter) -> $crate::dispatch::result::Result<(), $crate::dispatch::fmt::Error> { match *self { $( $call_type::$fn_name( $( ref $param_name ),* ) => write!(_f, "{}{:?}", stringify!($fn_name), ( $( $param_name.clone(), )* ) ) ,)* _ => unreachable!(), } } } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Dispatchable for $call_type<$trait_instance $(, $instance)?> { type Trait = $trait_instance; type Origin = $origin_type; fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::Result { match self { $( $call_type::$fn_name( $( $param_name ),* ) => { $crate::decl_module!( @call $from $mod_type<$trait_instance $(, $fn_instance)?> $fn_name _origin $system [ $( $param_name ),* ] ) }, )* $call_type::__PhantomItem(_, _) => { unreachable!("__PhantomItem should never be used.") }, } } } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Callable for $mod_type<$trait_instance $(, $instance)?> { type Call = $call_type<$trait_instance $(, $instance)?>; } impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { #[doc(hidden)] pub fn dispatch>(d: D, origin: D::Origin) -> $crate::dispatch::Result { d.dispatch(origin) } } $crate::__dispatch_impl_metadata! { $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> $call_type $origin_type {$( $(#[doc = $doc_attr])* fn $fn_name($from $(, $(#[$codec_attr])* $param_name : $param )*); )*} } } } pub trait IsSubType { fn is_aux_sub_type(&self) -> Option<&::Call>; } /// Implement a meta-dispatch module to dispatch to other dispatchers. #[macro_export] macro_rules! impl_outer_dispatch { ( $(#[$attr:meta])* pub enum $call_type:ident for $runtime:ident where origin: $origin:ty { $( $module:ident::$camelcase:ident, )* } ) => { $(#[$attr])* #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug))] pub enum $call_type { $( $camelcase ( $crate::dispatch::CallableCallFor<$camelcase> ) ,)* } impl $crate::dispatch::Dispatchable for $call_type { type Origin = $origin; type Trait = $call_type; fn dispatch(self, origin: $origin) -> $crate::dispatch::Result { match self { $( $call_type::$camelcase(call) => call.dispatch(origin), )* } } } $( impl $crate::dispatch::IsSubType<$camelcase> for $call_type { fn is_aux_sub_type(&self) -> Option<&<$camelcase as $crate::dispatch::Callable>::Call> { if let $call_type::$camelcase ( ref r ) = *self { Some(r) } else { None } } } )* } } /// Implement metadata for dispatch. #[macro_export] #[doc(hidden)] macro_rules! __dispatch_impl_metadata { ( $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?> $($rest:tt)* ) => { impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> { #[doc(hidden)] pub fn call_functions() -> &'static [$crate::dispatch::FunctionMetadata] { $crate::__call_to_functions!($($rest)*) } } } } /// Convert the list of calls into their JSON representation, joined by ",". #[macro_export] #[doc(hidden)] macro_rules! __call_to_functions { ( $call_type:ident $origin_type:ty {$( $(#[doc = $doc_attr:tt])* fn $fn_name:ident($from:ident $( , $(#[$codec_attr:ident])* $param_name:ident : $param:ty )* ); )*} ) => { $crate::__functions_to_metadata!(0; $origin_type;; $( fn $fn_name( $($(#[$codec_attr])* $param_name: $param ),* ); $( $doc_attr ),*; )*) }; } /// Convert a list of functions into a list of `FunctionMetadata` items. #[macro_export] #[doc(hidden)] macro_rules! __functions_to_metadata{ ( $fn_id:expr; $origin_type:ty; $( $function_metadata:expr ),*; fn $fn_name:ident( $( $(#[$codec_attr:ident])* $param_name:ident : $param:ty ),* ); $( $fn_doc:expr ),*; $( $rest:tt )* ) => { $crate::__functions_to_metadata!( $fn_id + 1; $origin_type; $( $function_metadata, )* $crate::__function_to_metadata!( fn $fn_name($( $(#[$codec_attr])* $param_name : $param ),*); $( $fn_doc ),*; $fn_id; ); $($rest)* ) }; ( $fn_id:expr; $origin_type:ty; $( $function_metadata:expr ),*; ) => { &[ $( $function_metadata ),* ] } } /// Convert a function into its metadata representation. #[macro_export] #[doc(hidden)] macro_rules! __function_to_metadata { ( fn $fn_name:ident( $( $(#[$codec_attr:ident])* $param_name:ident : $param:ty),* ); $( $fn_doc:expr ),*; $fn_id:expr; ) => { $crate::dispatch::FunctionMetadata { name: $crate::dispatch::DecodeDifferent::Encode(stringify!($fn_name)), arguments: $crate::dispatch::DecodeDifferent::Encode(&[ $( $crate::dispatch::FunctionArgumentMetadata { name: $crate::dispatch::DecodeDifferent::Encode(stringify!($param_name)), ty: $crate::dispatch::DecodeDifferent::Encode( $crate::__function_to_metadata!(@stringify_expand_attr $(#[$codec_attr])* $param_name: $param ) ), } ),* ]), documentation: $crate::dispatch::DecodeDifferent::Encode(&[ $( $fn_doc ),* ]), } }; (@stringify_expand_attr #[compact] $param_name:ident : $param:ty) => { concat!("Compact<", stringify!($param), ">") }; (@stringify_expand_attr $param_name:ident : $param:ty) => { stringify!($param) }; (@stringify_expand_attr $(#[codec_attr:ident])* $param_name:ident : $param:ty) => { compile_error!(concat!( "Invalid attribute for parameter `", stringify!($param_name), "`, the following attributes are supported: `#[compact]`" )) } } #[macro_export] #[doc(hidden)] macro_rules! __check_reserved_fn_name { (deposit_event $( $rest:ident )*) => { $crate::__check_reserved_fn_name!(@compile_error deposit_event); }; (on_initialize $( $rest:ident )*) => { $crate::__check_reserved_fn_name!(@compile_error on_initialize); }; (on_initialise $( $rest:ident )*) => { $crate::__check_reserved_fn_name!(@compile_error on_initialise); }; (on_finalize $( $rest:ident )*) => { $crate::__check_reserved_fn_name!(@compile_error on_finalize); }; (on_finalise $( $rest:ident )*) => { $crate::__check_reserved_fn_name!(@compile_error on_finalise); }; (offchain_worker $( $rest:ident )*) => { $crate::__check_reserved_fn_name!(@compile_error offchain_worker); }; ($t:ident $( $rest:ident )*) => { $crate::__check_reserved_fn_name!($( $rest )*); }; () => {}; (@compile_error $ident:ident) => { compile_error!(concat!("Invalid call fn name: `", stringify!($ident), "`, name is reserved and doesn't match expected signature, please refer to `decl_module!`", " documentation to see the appropriate usage, or rename it to an unreserved keyword.")); }; } #[cfg(test)] // Do not complain about unused `dispatch` and `dispatch_aux`. #[allow(dead_code)] mod tests { use super::*; use crate::runtime_primitives::traits::{OnInitialize, OnFinalize}; pub trait Trait { type Origin; type BlockNumber: Into; } pub mod system { use super::Result; pub fn ensure_root(_: R) -> Result { Ok(()) } } decl_module! { pub struct Module for enum Call where origin: T::Origin { /// Hi, this is a comment. fn aux_0(_origin) -> Result { unreachable!() } fn aux_1(_origin, #[compact] _data: u32) -> Result { unreachable!() } fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() } fn aux_3() -> Result { unreachable!() } fn aux_4(_data: i32) -> Result { unreachable!() } fn aux_5(_origin, _data: i32, #[compact] _data2: u32) -> Result { unreachable!() } fn on_initialize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_initialize") } } fn on_finalize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_finalize") } } fn offchain_worker() {} } } const EXPECTED_METADATA: &'static [FunctionMetadata] = &[ FunctionMetadata { name: DecodeDifferent::Encode("aux_0"), arguments: DecodeDifferent::Encode(&[]), documentation: DecodeDifferent::Encode(&[ " Hi, this is a comment." ]) }, FunctionMetadata { name: DecodeDifferent::Encode("aux_1"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("Compact") } ]), documentation: DecodeDifferent::Encode(&[]), }, FunctionMetadata { name: DecodeDifferent::Encode("aux_2"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("i32"), }, FunctionArgumentMetadata { name: DecodeDifferent::Encode("_data2"), ty: DecodeDifferent::Encode("String"), } ]), documentation: DecodeDifferent::Encode(&[]), }, FunctionMetadata { name: DecodeDifferent::Encode("aux_3"), arguments: DecodeDifferent::Encode(&[]), documentation: DecodeDifferent::Encode(&[]), }, FunctionMetadata { name: DecodeDifferent::Encode("aux_4"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("i32"), } ]), documentation: DecodeDifferent::Encode(&[]), }, FunctionMetadata { name: DecodeDifferent::Encode("aux_5"), arguments: DecodeDifferent::Encode(&[ FunctionArgumentMetadata { name: DecodeDifferent::Encode("_data"), ty: DecodeDifferent::Encode("i32"), }, FunctionArgumentMetadata { name: DecodeDifferent::Encode("_data2"), ty: DecodeDifferent::Encode("Compact") } ]), documentation: DecodeDifferent::Encode(&[]), }, ]; struct TraitImpl {} impl Trait for TraitImpl { type Origin = u32; type BlockNumber = u32; } #[test] fn module_json_metadata() { let metadata = Module::::call_functions(); assert_eq!(EXPECTED_METADATA, metadata); } #[test] fn compact_attr() { let call: Call = Call::aux_1(1); let encoded = call.encode(); assert_eq!(2, encoded.len()); assert_eq!(vec![1, 4], encoded); let call: Call = Call::aux_5(1, 2); let encoded = call.encode(); assert_eq!(6, encoded.len()); assert_eq!(vec![5, 1, 0, 0, 0, 8], encoded); } #[test] fn encode_is_correct_and_decode_works() { let call: Call = Call::aux_0(); let encoded = call.encode(); assert_eq!(vec![0], encoded); let decoded = Call::::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded, call); let call: Call = Call::aux_2(32, "hello".into()); let encoded = call.encode(); assert_eq!(vec![2, 32, 0, 0, 0, 20, 104, 101, 108, 108, 111], encoded); let decoded = Call::::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded, call); } #[test] #[should_panic(expected = "on_initialize")] fn on_initialize_should_work() { as OnInitialize>::on_initialize(42); } #[test] #[should_panic(expected = "on_finalize")] fn on_finalize_should_work() { as OnFinalize>::on_finalize(42); } }