mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-02 14:07:23 +00:00
Make decl_error! errors usable (#4449)
* Make `decl_error!` errors usable This pr implements support for returning errors of different pallets in a pallet. These errors need to be declared with `decl_error!`. The pr changes the following: - Each dispatchable function now returns a `DispatchResult` which is an alias for `Result<(), DispatchError>`. - `DispatchError` is an enum that has 4 variants: - `Other`: For storing string error messages - `CannotLookup`: Variant that is returned when something returns a `sp_runtime::LookupError` - `BadOrigin`: Variant that is returned for any kind of bad origin - `Module`: The error of a specific module. Contains the `index`, `error` and the `message`. The index is the index of the module in `construct_runtime!`. `error` is the index of the error in the error enum declared by `decl_error!`. `message` is the message to the error variant (this will not be encoded). - `construct_runtime!` now creates a new struct `ModuleToIndex`. This struct implements the trait `ModuleToIndex`. - `frame_system::Trait` has a new associated type: `ModuleToIndex` that expects the `ModuleToIndex` generated by `construct_runtime!`. - All error strings returned in any module are being converted now to `DispatchError`. - `BadOrigin` is the default error returned by any type that implements `EnsureOrigin`. * Fix frame system benchmarks
This commit is contained in:
committed by
Gavin Wood
parent
0aab5c659e
commit
8e393aa5a8
@@ -24,6 +24,9 @@ use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::quote;
|
||||
use syn::{Ident, Result};
|
||||
|
||||
/// The fixed name of the system module.
|
||||
const SYSTEM_MODULE_NAME: &str = "System";
|
||||
|
||||
pub fn construct_runtime(input: TokenStream) -> TokenStream {
|
||||
let definition = syn::parse_macro_input!(input as RuntimeDefinition);
|
||||
construct_runtime_parsed(definition)
|
||||
@@ -63,7 +66,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
|
||||
let scrate = generate_crate_access(&hidden_crate_name, "frame-support");
|
||||
let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support");
|
||||
|
||||
let all_but_system_modules = modules.iter().filter(|module| module.name != "System");
|
||||
let all_but_system_modules = modules.iter().filter(|module| module.name != SYSTEM_MODULE_NAME);
|
||||
|
||||
let outer_event = decl_outer_event_or_origin(
|
||||
&name,
|
||||
@@ -79,7 +82,8 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
|
||||
&scrate,
|
||||
DeclOuterKind::Origin,
|
||||
)?;
|
||||
let all_modules = decl_all_modules(&name, &system_module, all_but_system_modules);
|
||||
let all_modules = decl_all_modules(&name, modules.iter());
|
||||
let module_to_index = decl_module_to_index(modules.iter(), modules.len(), &scrate);
|
||||
|
||||
let dispatch = decl_outer_dispatch(&name, modules.iter(), &scrate);
|
||||
let metadata = decl_runtime_metadata(&name, modules.iter(), &scrate);
|
||||
@@ -106,6 +110,8 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
|
||||
|
||||
#all_modules
|
||||
|
||||
#module_to_index
|
||||
|
||||
#dispatch
|
||||
|
||||
#metadata
|
||||
@@ -308,7 +314,6 @@ fn decl_outer_event_or_origin<'a>(
|
||||
|
||||
fn decl_all_modules<'a>(
|
||||
runtime: &'a Ident,
|
||||
system_name: &'a Ident,
|
||||
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
|
||||
) -> TokenStream2 {
|
||||
let mut types = TokenStream2::new();
|
||||
@@ -330,22 +335,49 @@ fn decl_all_modules<'a>(
|
||||
names.push(&module_declaration.name);
|
||||
}
|
||||
// Make nested tuple structure like (((Babe, Consensus), Grandpa), ...)
|
||||
let all_modules = names.iter().fold(
|
||||
TokenStream2::default(),
|
||||
|combined, name| quote!((#name, #combined)),
|
||||
);
|
||||
// But ignore the system module.
|
||||
let all_modules = names.iter()
|
||||
.filter(|n| **n != SYSTEM_MODULE_NAME)
|
||||
.fold(TokenStream2::default(), |combined, name| quote!((#name, #combined)));
|
||||
|
||||
quote!(
|
||||
pub type System = #system_name::Module<#runtime>;
|
||||
#types
|
||||
type AllModules = ( #all_modules );
|
||||
)
|
||||
}
|
||||
|
||||
fn decl_module_to_index<'a>(
|
||||
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
|
||||
num_modules: usize,
|
||||
scrate: &TokenStream2,
|
||||
) -> TokenStream2 {
|
||||
let names = module_declarations.map(|d| &d.name);
|
||||
let indices = 0..num_modules;
|
||||
|
||||
quote!(
|
||||
/// Provides an implementation of `ModuleToIndex` to map a module
|
||||
/// to its index in the runtime.
|
||||
pub struct ModuleToIndex;
|
||||
|
||||
impl #scrate::traits::ModuleToIndex for ModuleToIndex {
|
||||
fn module_to_index<M: 'static>() -> Option<usize> {
|
||||
let type_id = #scrate::sp_std::any::TypeId::of::<M>();
|
||||
#(
|
||||
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
|
||||
return Some(#indices)
|
||||
}
|
||||
)*
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn find_system_module<'a>(
|
||||
mut module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
|
||||
) -> Option<&'a Ident> {
|
||||
module_declarations
|
||||
.find(|decl| decl.name == "System")
|
||||
.find(|decl| decl.name == SYSTEM_MODULE_NAME)
|
||||
.map(|decl| &decl.module)
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ pub fn generate_crate_access(unique_id: &str, def_crate: &str) -> TokenStream {
|
||||
|
||||
/// Generates the hidden includes that are required to make the macro independent from its scope.
|
||||
pub fn generate_hidden_includes(unique_id: &str, def_crate: &str) -> TokenStream {
|
||||
if ::std::env::var("CARGO_PKG_NAME").unwrap() == def_crate {
|
||||
if std::env::var("CARGO_PKG_NAME").unwrap() == def_crate {
|
||||
TokenStream::new()
|
||||
} else {
|
||||
let mod_name = generate_hidden_includes_mod_name(unique_id);
|
||||
|
||||
@@ -27,17 +27,11 @@ pub use crate::weights::{
|
||||
SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData, ClassifyDispatch,
|
||||
TransactionPriority, Weight, WeighBlock, PaysFee,
|
||||
};
|
||||
pub use sp_runtime::{
|
||||
traits::{Dispatchable, DispatchResult, ModuleDispatchError},
|
||||
DispatchError,
|
||||
};
|
||||
pub use sp_runtime::{traits::Dispatchable, DispatchError, DispatchResult};
|
||||
|
||||
/// A type that cannot be instantiated.
|
||||
pub enum Never {}
|
||||
|
||||
/// Result with string error message. This exists for backward compatibility purpose.
|
||||
pub type Result = DispatchResult<&'static str>;
|
||||
|
||||
/// Serializable version of Dispatchable.
|
||||
/// This value can be used as a "function" in an extrinsic.
|
||||
pub trait Callable<T> {
|
||||
@@ -68,14 +62,14 @@ impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug {}
|
||||
///
|
||||
/// // Private functions are dispatchable, but not available to other
|
||||
/// // SRML modules.
|
||||
/// fn my_function(origin, var: u64) -> dispatch::Result {
|
||||
/// fn my_function(origin, var: u64) -> dispatch::DispatchResult {
|
||||
/// // Your implementation
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// // Public functions are both dispatchable and available to other
|
||||
/// // SRML modules.
|
||||
/// pub fn my_public_function(origin) -> dispatch::Result {
|
||||
/// pub fn my_public_function(origin) -> dispatch::DispatchResult {
|
||||
/// // Your implementation
|
||||
/// Ok(())
|
||||
/// }
|
||||
@@ -95,8 +89,8 @@ impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug {}
|
||||
///
|
||||
/// ### Shorthand Example
|
||||
///
|
||||
/// The macro automatically expands a shorthand function declaration to return the `Result` type.
|
||||
/// These functions are the same:
|
||||
/// The macro automatically expands a shorthand function declaration to return the
|
||||
/// [`DispatchResult`] type. These functions are the same:
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use]
|
||||
@@ -106,7 +100,7 @@ impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug {}
|
||||
/// decl_module! {
|
||||
/// pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
///
|
||||
/// fn my_long_function(origin) -> dispatch::Result {
|
||||
/// fn my_long_function(origin) -> dispatch::DispatchResult {
|
||||
/// // Your implementation
|
||||
/// Ok(())
|
||||
/// }
|
||||
@@ -130,7 +124,7 @@ impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug {}
|
||||
/// # use frame_system::{self as system, Trait, ensure_signed, ensure_root};
|
||||
/// decl_module! {
|
||||
/// pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
/// fn my_privileged_function(origin) -> dispatch::Result {
|
||||
/// fn my_privileged_function(origin) -> dispatch::DispatchResult {
|
||||
/// ensure_root(origin)?;
|
||||
/// // Your implementation
|
||||
/// Ok(())
|
||||
@@ -1043,9 +1037,8 @@ macro_rules! decl_module {
|
||||
#[allow(unreachable_code)]
|
||||
$vis fn $name(
|
||||
$origin: $origin_ty $(, $param: $param_ty )*
|
||||
) -> $crate::dispatch::DispatchResult<$error_type> {
|
||||
use $crate::sp_std::if_std;
|
||||
if_std! {
|
||||
) -> $crate::dispatch::DispatchResult {
|
||||
$crate::sp_std::if_std! {
|
||||
use $crate::tracing;
|
||||
let span = tracing::span!(tracing::Level::DEBUG, stringify!($name));
|
||||
let _enter = span.enter();
|
||||
@@ -1417,8 +1410,7 @@ macro_rules! decl_module {
|
||||
{
|
||||
type Trait = $trait_instance;
|
||||
type Origin = $origin_type;
|
||||
type Error = $error_type;
|
||||
fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::DispatchResult<Self::Error> {
|
||||
fn dispatch(self, _origin: Self::Origin) -> $crate::sp_runtime::DispatchResult {
|
||||
match self {
|
||||
$(
|
||||
$call_type::$fn_name( $( $param_name ),* ) => {
|
||||
@@ -1446,7 +1438,7 @@ macro_rules! decl_module {
|
||||
pub fn dispatch<D: $crate::dispatch::Dispatchable<Trait = $trait_instance>>(
|
||||
d: D,
|
||||
origin: D::Origin
|
||||
) -> $crate::dispatch::DispatchResult<D::Error> {
|
||||
) -> $crate::sp_runtime::DispatchResult {
|
||||
d.dispatch(origin)
|
||||
}
|
||||
}
|
||||
@@ -1514,11 +1506,10 @@ macro_rules! impl_outer_dispatch {
|
||||
impl $crate::dispatch::Dispatchable for $call_type {
|
||||
type Origin = $origin;
|
||||
type Trait = $call_type;
|
||||
type Error = $crate::dispatch::DispatchError;
|
||||
fn dispatch(
|
||||
self,
|
||||
origin: $origin,
|
||||
) -> $crate::dispatch::DispatchResult<$crate::dispatch::DispatchError> {
|
||||
) -> $crate::sp_runtime::DispatchResult {
|
||||
$crate::impl_outer_dispatch! {
|
||||
@DISPATCH_MATCH
|
||||
self
|
||||
@@ -1565,11 +1556,7 @@ macro_rules! impl_outer_dispatch {
|
||||
$origin
|
||||
{
|
||||
$( $generated )*
|
||||
$call_type::$name(call) => call.dispatch($origin).map_err(|e| {
|
||||
let mut error: $crate::dispatch::DispatchError = e.into();
|
||||
error.module = Some($index);
|
||||
error
|
||||
}),
|
||||
$call_type::$name(call) => call.dispatch($origin),
|
||||
}
|
||||
$index + 1;
|
||||
$( $rest ),*
|
||||
@@ -1895,13 +1882,13 @@ mod tests {
|
||||
}
|
||||
|
||||
pub mod system {
|
||||
use super::Result;
|
||||
use super::*;
|
||||
|
||||
pub trait Trait {
|
||||
type AccountId;
|
||||
}
|
||||
|
||||
pub fn ensure_root<R>(_: R) -> Result {
|
||||
pub fn ensure_root<R>(_: R) -> DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1917,13 +1904,13 @@ mod tests {
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin, T::AccountId: From<u32> {
|
||||
/// 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_0(_origin) -> DispatchResult { unreachable!() }
|
||||
fn aux_1(_origin, #[compact] _data: u32,) -> DispatchResult { unreachable!() }
|
||||
fn aux_2(_origin, _data: i32, _data2: String) -> DispatchResult { unreachable!() }
|
||||
#[weight = SimpleDispatchInfo::FixedNormal(3)]
|
||||
fn aux_3(_origin) -> Result { unreachable!() }
|
||||
fn aux_4(_origin, _data: i32) -> Result { unreachable!() }
|
||||
fn aux_5(_origin, _data: i32, #[compact] _data2: u32,) -> Result { unreachable!() }
|
||||
fn aux_3(_origin) -> DispatchResult { unreachable!() }
|
||||
fn aux_4(_origin, _data: i32) -> DispatchResult { unreachable!() }
|
||||
fn aux_5(_origin, _data: i32, #[compact] _data2: u32,) -> DispatchResult { unreachable!() }
|
||||
|
||||
#[weight = SimpleDispatchInfo::FixedNormal(7)]
|
||||
fn on_initialize(n: T::BlockNumber,) { if n.into() == 42 { panic!("on_initialize") } }
|
||||
|
||||
@@ -17,18 +17,19 @@
|
||||
//! Macro for declaring a module error.
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use sp_runtime::traits::LookupError;
|
||||
pub use sp_runtime::traits::{LookupError, BadOrigin};
|
||||
#[doc(hidden)]
|
||||
pub use frame_metadata::{ModuleErrorMetadata, ErrorMetadata, DecodeDifferent};
|
||||
|
||||
/// Declare an error type for a runtime module.
|
||||
///
|
||||
/// The generated error type inherently has the variants `Other` and `CannotLookup`. `Other` can
|
||||
/// hold any `&'static str` error message and is present for convenience/backward compatibility.
|
||||
/// The `CannotLookup` variant indicates that some lookup could not be done. For both variants the
|
||||
/// error type implements `From<&'static str>` and `From<LookupError>` to make them usable with the
|
||||
/// try operator.
|
||||
/// `decl_error!` supports only variants that do not hold any data. The dispatchable
|
||||
/// functions return [`DispatchResult`](sp_runtime::DispatchResult). The error type
|
||||
/// implements `From<ErrorType> for DispatchResult` to make the error type usable as error
|
||||
/// in the dispatchable functions.
|
||||
///
|
||||
/// `decl_error!` supports only variants that do not hold any data.
|
||||
/// It is required that the error type is registed in `decl_module!` to make the error
|
||||
/// exported in the metadata.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
@@ -36,7 +37,7 @@ pub use frame_metadata::{ModuleErrorMetadata, ErrorMetadata, DecodeDifferent};
|
||||
/// # use frame_support::{decl_error, decl_module};
|
||||
/// decl_error! {
|
||||
/// /// Errors that can occur in my module.
|
||||
/// pub enum MyError {
|
||||
/// pub enum MyError for Module<T: Trait> {
|
||||
/// /// Hey this is an error message that indicates bla.
|
||||
/// MyCoolErrorMessage,
|
||||
/// /// You are just not cool enough for my module!
|
||||
@@ -44,27 +45,36 @@ pub use frame_metadata::{ModuleErrorMetadata, ErrorMetadata, DecodeDifferent};
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # use frame_system::{self as system, Trait, ensure_signed};
|
||||
/// # use frame_system::{self as system, Trait};
|
||||
///
|
||||
/// // You need to register the error type in `decl_module!` as well.
|
||||
/// // You need to register the error type in `decl_module!` as well to make the error
|
||||
/// // exported in the metadata.
|
||||
///
|
||||
/// decl_module! {
|
||||
/// pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
/// type Error = MyError;
|
||||
/// type Error = MyError<T>;
|
||||
///
|
||||
/// fn do_something(origin) -> Result<(), MyError> {
|
||||
/// Err(MyError::YouAreNotCoolEnough)
|
||||
/// fn do_something(origin) -> frame_support::dispatch::DispatchResult {
|
||||
/// Err(MyError::<T>::YouAreNotCoolEnough.into())
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// For instantiable modules you also need to give the instance generic type and bound to the
|
||||
/// error declaration.
|
||||
#[macro_export]
|
||||
macro_rules! decl_error {
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
pub enum $error:ident {
|
||||
pub enum $error:ident
|
||||
for $module:ident<
|
||||
$generic:ident: $trait:path
|
||||
$(, $inst_generic:ident: $instance:path)?
|
||||
>
|
||||
{
|
||||
$(
|
||||
$( #[doc = $doc_attr:tt] )*
|
||||
$name:ident
|
||||
@@ -72,33 +82,42 @@ macro_rules! decl_error {
|
||||
$(,)?
|
||||
}
|
||||
) => {
|
||||
#[derive(Clone, PartialEq, Eq, $crate::RuntimeDebug)]
|
||||
$(#[$attr])*
|
||||
pub enum $error {
|
||||
Other(&'static str),
|
||||
CannotLookup,
|
||||
pub enum $error<$generic: $trait $(, $inst_generic: $instance)?> {
|
||||
#[doc(hidden)]
|
||||
__Ignore(
|
||||
$crate::sp_std::marker::PhantomData<($generic $(, $inst_generic)?)>,
|
||||
$crate::dispatch::Never,
|
||||
),
|
||||
$(
|
||||
$( #[doc = $doc_attr] )*
|
||||
$name
|
||||
),*
|
||||
}
|
||||
|
||||
impl $crate::dispatch::ModuleDispatchError for $error {
|
||||
impl<$generic: $trait $(, $inst_generic: $instance)?> $crate::sp_std::fmt::Debug
|
||||
for $error<$generic $(, $inst_generic)?>
|
||||
{
|
||||
fn fmt(&self, f: &mut $crate::sp_std::fmt::Formatter<'_>) -> $crate::sp_std::fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<$generic: $trait $(, $inst_generic: $instance)?> $error<$generic $(, $inst_generic)?> {
|
||||
fn as_u8(&self) -> u8 {
|
||||
$crate::decl_error! {
|
||||
@GENERATE_AS_U8
|
||||
self
|
||||
$error
|
||||
{}
|
||||
2,
|
||||
0,
|
||||
$( $name ),*
|
||||
}
|
||||
}
|
||||
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
$error::Other(err) => err,
|
||||
$error::CannotLookup => "Can not lookup",
|
||||
Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"),
|
||||
$(
|
||||
$error::$name => stringify!($name),
|
||||
)*
|
||||
@@ -106,33 +125,33 @@ macro_rules! decl_error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for $error {
|
||||
fn from(val: &'static str) -> $error {
|
||||
$error::Other(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$crate::error::LookupError> for $error {
|
||||
fn from(_: $crate::error::LookupError) -> $error {
|
||||
$error::CannotLookup
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$error> for &'static str {
|
||||
fn from(err: $error) -> &'static str {
|
||||
use $crate::dispatch::ModuleDispatchError;
|
||||
impl<$generic: $trait $(, $inst_generic: $instance)?> From<$error<$generic $(, $inst_generic)?>>
|
||||
for &'static str
|
||||
{
|
||||
fn from(err: $error<$generic $(, $inst_generic)?>) -> &'static str {
|
||||
err.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<$crate::dispatch::DispatchError> for $error {
|
||||
fn into(self) -> $crate::dispatch::DispatchError {
|
||||
use $crate::dispatch::ModuleDispatchError;
|
||||
$crate::dispatch::DispatchError::new(None, self.as_u8(), Some(self.as_str()))
|
||||
impl<$generic: $trait $(, $inst_generic: $instance)?> From<$error<$generic $(, $inst_generic)?>>
|
||||
for $crate::sp_runtime::DispatchError
|
||||
{
|
||||
fn from(err: $error<$generic $(, $inst_generic)?>) -> Self {
|
||||
let index = <$generic::ModuleToIndex as $crate::traits::ModuleToIndex>
|
||||
::module_to_index::<$module<$generic $(, $inst_generic)?>>()
|
||||
.expect("Every active module has an index in the runtime; qed") as u8;
|
||||
|
||||
$crate::sp_runtime::DispatchError::Module {
|
||||
index,
|
||||
error: err.as_u8(),
|
||||
message: Some(err.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::error::ModuleErrorMetadata for $error {
|
||||
impl<$generic: $trait $(, $inst_generic: $instance)?> $crate::error::ModuleErrorMetadata
|
||||
for $error<$generic $(, $inst_generic)?>
|
||||
{
|
||||
fn metadata() -> &'static [$crate::error::ErrorMetadata] {
|
||||
&[
|
||||
$(
|
||||
@@ -174,8 +193,7 @@ macro_rules! decl_error {
|
||||
$index:expr,
|
||||
) => {
|
||||
match $self {
|
||||
$error::Other(_) => 0,
|
||||
$error::CannotLookup => 1,
|
||||
$error::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"),
|
||||
$( $generated )*
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ pub use frame_support_procedural::{decl_storage, construct_runtime};
|
||||
#[macro_export]
|
||||
macro_rules! fail {
|
||||
( $y:expr ) => {{
|
||||
return Err($y);
|
||||
return Err($y.into());
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ macro_rules! assert_noop {
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! assert_err {
|
||||
( $x:expr , $y:expr $(,)? ) => {
|
||||
assert_eq!($x, Err($y));
|
||||
assert_eq!($x, Err($y.into()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,13 +240,14 @@ mod tests {
|
||||
mod system {
|
||||
use super::*;
|
||||
|
||||
pub trait Trait {
|
||||
pub trait Trait: 'static {
|
||||
const ASSOCIATED_CONST: u64 = 500;
|
||||
type Origin: Into<Result<RawOrigin<Self::AccountId>, Self::Origin>>
|
||||
+ From<RawOrigin<Self::AccountId>>;
|
||||
type AccountId: From<u32> + Encode;
|
||||
type BlockNumber: From<u32> + Encode;
|
||||
type SomeValue: Get<u32>;
|
||||
type ModuleToIndex: crate::traits::ModuleToIndex;
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
@@ -286,10 +287,8 @@ mod tests {
|
||||
mod event_module {
|
||||
use crate::dispatch::DispatchResult;
|
||||
|
||||
pub trait Trait {
|
||||
type Origin;
|
||||
pub trait Trait: super::system::Trait {
|
||||
type Balance;
|
||||
type BlockNumber;
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
@@ -302,14 +301,14 @@ mod tests {
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
type Error = Error;
|
||||
type Error = Error<T>;
|
||||
|
||||
fn aux_0(_origin) -> DispatchResult<Error> { unreachable!() }
|
||||
fn aux_0(_origin) -> DispatchResult { unreachable!() }
|
||||
}
|
||||
}
|
||||
|
||||
crate::decl_error! {
|
||||
pub enum Error {
|
||||
pub enum Error for Module<T: Trait> {
|
||||
/// Some user input error
|
||||
UserInputError,
|
||||
/// Something bad happened
|
||||
@@ -372,9 +371,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl event_module::Trait for TestRuntime {
|
||||
type Origin = Origin;
|
||||
type Balance = u32;
|
||||
type BlockNumber = u32;
|
||||
}
|
||||
|
||||
impl event_module2::Trait for TestRuntime {
|
||||
@@ -392,6 +389,7 @@ mod tests {
|
||||
type AccountId = u32;
|
||||
type BlockNumber = u32;
|
||||
type SomeValue = SystemValue;
|
||||
type ModuleToIndex = ();
|
||||
}
|
||||
|
||||
impl_runtime_metadata!(
|
||||
|
||||
@@ -22,7 +22,7 @@ use sp_std::{prelude::*, result, marker::PhantomData, ops::Div, fmt::Debug};
|
||||
use codec::{FullCodec, Codec, Encode, Decode};
|
||||
use sp_core::u32_trait::Value as U32;
|
||||
use sp_runtime::{
|
||||
ConsensusEngineId,
|
||||
ConsensusEngineId, DispatchResult, DispatchError,
|
||||
traits::{MaybeSerializeDeserialize, SimpleArithmetic, Saturating},
|
||||
};
|
||||
|
||||
@@ -386,7 +386,7 @@ pub trait Currency<AccountId> {
|
||||
_amount: Self::Balance,
|
||||
reasons: WithdrawReasons,
|
||||
new_balance: Self::Balance,
|
||||
) -> result::Result<(), &'static str>;
|
||||
) -> DispatchResult;
|
||||
|
||||
// PUBLIC MUTABLES (DANGEROUS)
|
||||
|
||||
@@ -399,7 +399,7 @@ pub trait Currency<AccountId> {
|
||||
dest: &AccountId,
|
||||
value: Self::Balance,
|
||||
existence_requirement: ExistenceRequirement,
|
||||
) -> result::Result<(), &'static str>;
|
||||
) -> DispatchResult;
|
||||
|
||||
/// Deducts up to `value` from the combined balance of `who`, preferring to deduct from the
|
||||
/// free balance. This function cannot fail.
|
||||
@@ -419,7 +419,7 @@ pub trait Currency<AccountId> {
|
||||
fn deposit_into_existing(
|
||||
who: &AccountId,
|
||||
value: Self::Balance
|
||||
) -> result::Result<Self::PositiveImbalance, &'static str>;
|
||||
) -> result::Result<Self::PositiveImbalance, DispatchError>;
|
||||
|
||||
/// Similar to deposit_creating, only accepts a `NegativeImbalance` and returns nothing on
|
||||
/// success.
|
||||
@@ -465,7 +465,7 @@ pub trait Currency<AccountId> {
|
||||
value: Self::Balance,
|
||||
reasons: WithdrawReasons,
|
||||
liveness: ExistenceRequirement,
|
||||
) -> result::Result<Self::NegativeImbalance, &'static str>;
|
||||
) -> result::Result<Self::NegativeImbalance, DispatchError>;
|
||||
|
||||
/// Similar to withdraw, only accepts a `PositiveImbalance` and returns nothing on success.
|
||||
fn settle(
|
||||
@@ -528,7 +528,7 @@ pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
|
||||
///
|
||||
/// If the free balance is lower than `value`, then no funds will be moved and an `Err` will
|
||||
/// be returned to notify of this. This is different behavior than `unreserve`.
|
||||
fn reserve(who: &AccountId, value: Self::Balance) -> result::Result<(), &'static str>;
|
||||
fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult;
|
||||
|
||||
/// Moves up to `value` from reserved balance to free balance. This function cannot fail.
|
||||
///
|
||||
@@ -552,7 +552,7 @@ pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
|
||||
slashed: &AccountId,
|
||||
beneficiary: &AccountId,
|
||||
value: Self::Balance
|
||||
) -> result::Result<Self::Balance, &'static str>;
|
||||
) -> result::Result<Self::Balance, DispatchError>;
|
||||
}
|
||||
|
||||
/// An identifier for a lock. Used for disambiguating different locks so that
|
||||
@@ -619,7 +619,7 @@ pub trait VestingCurrency<AccountId>: Currency<AccountId> {
|
||||
locked: Self::Balance,
|
||||
per_block: Self::Balance,
|
||||
starting_block: Self::Moment,
|
||||
) -> result::Result<(), &'static str>;
|
||||
) -> DispatchResult;
|
||||
|
||||
/// Remove a vesting schedule for a given account.
|
||||
fn remove_vesting_schedule(who: &AccountId);
|
||||
@@ -777,3 +777,15 @@ pub trait ValidatorRegistration<ValidatorId> {
|
||||
/// module
|
||||
fn is_registered(id: &ValidatorId) -> bool;
|
||||
}
|
||||
|
||||
/// Something that can convert a given module into the index of the module in the runtime.
|
||||
///
|
||||
/// The index of a module is determined by the position it appears in `construct_runtime!`.
|
||||
pub trait ModuleToIndex {
|
||||
/// Convert the given module `M` into an index.
|
||||
fn module_to_index<M: 'static>() -> Option<usize>;
|
||||
}
|
||||
|
||||
impl ModuleToIndex for () {
|
||||
fn module_to_index<M: 'static>() -> Option<usize> { Some(0) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![recursion_limit="128"]
|
||||
|
||||
use sp_runtime::{generic, traits::{BlakeTwo256, Block as _, Verify}, DispatchError};
|
||||
use sp_core::{H256, sr25519};
|
||||
|
||||
mod system;
|
||||
|
||||
pub trait Currency {}
|
||||
|
||||
mod module1 {
|
||||
use super::*;
|
||||
|
||||
pub trait Trait<I>: system::Trait {}
|
||||
|
||||
frame_support::decl_module! {
|
||||
pub struct Module<T: Trait<I>, I: Instance = DefaultInstance> for enum Call
|
||||
where origin: <T as system::Trait>::Origin
|
||||
{
|
||||
pub fn fail(_origin) -> frame_support::dispatch::DispatchResult {
|
||||
Err(Error::<T, I>::Something.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame_support::decl_error! {
|
||||
pub enum Error for Module<T: Trait<I>, I: Instance> {
|
||||
Something
|
||||
}
|
||||
}
|
||||
|
||||
frame_support::decl_storage! {
|
||||
trait Store for Module<T: Trait<I>, I: Instance=DefaultInstance> as Module {}
|
||||
}
|
||||
}
|
||||
|
||||
mod module2 {
|
||||
use super::*;
|
||||
|
||||
pub trait Trait: system::Trait {}
|
||||
|
||||
frame_support::decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call
|
||||
where origin: <T as system::Trait>::Origin
|
||||
{
|
||||
pub fn fail(_origin) -> frame_support::dispatch::DispatchResult {
|
||||
Err(Error::<T>::Something.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame_support::decl_error! {
|
||||
pub enum Error for Module<T: Trait> {
|
||||
Something
|
||||
}
|
||||
}
|
||||
|
||||
frame_support::decl_storage! {
|
||||
trait Store for Module<T: Trait> as Module {}
|
||||
}
|
||||
}
|
||||
|
||||
impl module1::Trait<module1::Instance1> for Runtime {}
|
||||
impl module1::Trait<module1::Instance2> for Runtime {}
|
||||
impl module2::Trait for Runtime {}
|
||||
|
||||
pub type Signature = sr25519::Signature;
|
||||
pub type AccountId = <Signature as Verify>::Signer;
|
||||
pub type BlockNumber = u64;
|
||||
pub type Index = u64;
|
||||
|
||||
impl system::Trait for Runtime {
|
||||
type Hash = H256;
|
||||
type Origin = Origin;
|
||||
type BlockNumber = BlockNumber;
|
||||
type AccountId = AccountId;
|
||||
type Event = Event;
|
||||
type ModuleToIndex = ModuleToIndex;
|
||||
}
|
||||
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic
|
||||
{
|
||||
System: system::{Module, Call, Event},
|
||||
Module1_1: module1::<Instance1>::{Module, Call, Storage},
|
||||
Module2: module2::{Module, Call, Storage},
|
||||
Module1_2: module1::<Instance2>::{Module, Call, Storage},
|
||||
}
|
||||
);
|
||||
|
||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||
|
||||
#[test]
|
||||
fn check_module1_1_error_type() {
|
||||
assert_eq!(
|
||||
Module1_1::fail(system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module { index: 1, error: 0, message: Some("Something") }),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_module1_2_error_type() {
|
||||
assert_eq!(
|
||||
Module1_2::fail(system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module { index: 3, error: 0, message: Some("Something") }),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_module2_error_type() {
|
||||
assert_eq!(
|
||||
Module2::fail(system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module { index: 2, error: 0, message: Some("Something") }),
|
||||
);
|
||||
}
|
||||
@@ -238,6 +238,7 @@ impl system::Trait for Runtime {
|
||||
type BlockNumber = BlockNumber;
|
||||
type AccountId = AccountId;
|
||||
type Event = Event;
|
||||
type ModuleToIndex = ();
|
||||
}
|
||||
|
||||
frame_support::construct_runtime!(
|
||||
|
||||
@@ -160,6 +160,7 @@ impl system::Trait for Runtime {
|
||||
type BlockNumber = BlockNumber;
|
||||
type AccountId = AccountId;
|
||||
type Event = Event;
|
||||
type ModuleToIndex = ();
|
||||
}
|
||||
|
||||
impl module::Trait for Runtime {}
|
||||
|
||||
@@ -12,14 +12,14 @@ macro_rules! reserved {
|
||||
pub mod system {
|
||||
use frame_support::dispatch;
|
||||
|
||||
pub fn ensure_root<R>(_: R) -> dispatch::Result {
|
||||
pub fn ensure_root<R>(_: R) -> dispatch::DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
frame_support::decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
fn $reserved(_origin) -> dispatch::Result { unreachable!() }
|
||||
fn $reserved(_origin) -> dispatch::DispatchResult { unreachable!() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ pub trait Trait: 'static + Eq + Clone {
|
||||
type Hash;
|
||||
type AccountId: Encode + EncodeLike + Decode;
|
||||
type Event: From<Event>;
|
||||
type ModuleToIndex: frame_support::traits::ModuleToIndex;
|
||||
}
|
||||
|
||||
frame_support::decl_module! {
|
||||
@@ -28,7 +29,7 @@ frame_support::decl_event!(
|
||||
);
|
||||
|
||||
frame_support::decl_error! {
|
||||
pub enum Error {
|
||||
pub enum Error for Module<T: Trait> {
|
||||
/// Test error documentation
|
||||
TestError,
|
||||
/// Error documentation
|
||||
|
||||
Reference in New Issue
Block a user