Custom runtime module errors (#3433)

* srml-system checks

* wip

* more modules compiles

* node-runtime checks

* build.sh passes

* include dispatch error in failed event

* revert some unnecessary changes

* refactor based on comments

* more compile error fixes

* avoid unnecessary into

* reorder code

* fixes some tests

* manually implement encode & decode to avoid i8 workaround

* more test fixes

* more fixes

* more error fixes

* Apply suggestions from code review

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* address comments

* test for DispatchError encoding

* tyep alias for democracy

* make error printable

* line width

* fix balances tests

* fix executive test

* fix system tests

* bump version

* ensure consistent method signature

* Apply suggestions from code review

Co-Authored-By: Gavin Wood <github@gavwood.com>

* changes based on review

* Add issue number for TODOs

* fix

* line width

* fix test

* Update core/sr-primitives/src/lib.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/sr-primitives/src/traits.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/council/src/motions.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update srml/council/src/motions.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* update based on review

* More concrete macro matching

* fix test build issue

* Update hex-literal dependency version. (#3141)

* Update hex-literal dep version.

* Update lock file.

* Start to rework the new error handling

* More work to get it back compiling

* Start to fix after master merge

* The great transaction error handling refactoring

* Make `decl_error` errors convertible to `&'static str`

* Make srml-executive build again

* Fix `sr-primitives` tests

* More fixes

* Last round of fix ups

* Fix build

* Fix build

* Apply suggestions from code review

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Rename some stuff

* Fixes after master merge

* Adds `CheckBlockGasLimit` signed extension

* Remove debug stuff

* Fix srml-balances test

* Rename `InvalidIndex` to `CannotLookup`

* Remove weird generic parameters

* Rename function again

* Fix import

* Document the signed extension

* Change from `Into` to `From`

* Update srml/contracts/src/lib.rs

Co-Authored-By: Sergei Pepyakin <sergei@parity.io>

* Fix compilation

* Update srml/contracts/src/lib.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update core/sr-primitives/src/transaction_validity.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Remove unused code

* Fix compilation

* Some cleanups

* Fix compile errors

* Make `TransactionValidity` a `Result`

* Apply suggestions from code review

Co-Authored-By: Gavin Wood <gavin@parity.io>

* Beautify the code a little bit and fix test

* Make `CannotLookup` an inherent error declared by `decl_error!`

* Adds some documentation

* Make `ApplyOutcome` a result

* Up the spec_version

* Apply suggestions from code review

Co-Authored-By: Gavin Wood <gavin@parity.io>
Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2019-09-04 16:21:42 +02:00
committed by GitHub
parent 5e4bc7c9b6
commit c6f3798078
46 changed files with 1259 additions and 630 deletions
+161 -14
View File
@@ -25,18 +25,18 @@ pub use srml_metadata::{
FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata,
ModuleConstantMetadata, DefaultByte, DefaultByteGetter,
};
pub use sr_primitives::weights::{SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData,
ClassifyDispatch,
TransactionPriority
pub use sr_primitives::{
weights::{
SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData, ClassifyDispatch,
TransactionPriority
}, traits::{Dispatchable, DispatchResult, ModuleDispatchError}, DispatchError
};
pub use sr_primitives::traits::{Dispatchable, DispatchResult};
/// 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 = DispatchResult;
/// 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.
@@ -239,6 +239,7 @@ macro_rules! decl_module {
{}
{}
{}
{}
[]
$($t)*
);
@@ -270,6 +271,7 @@ macro_rules! decl_module {
{}
{}
{}
{}
[]
$($t)*
);
@@ -286,6 +288,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$vis:vis fn deposit_event() = default;
@@ -301,6 +304,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -315,6 +319,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$vis:vis fn deposit_event
@@ -334,6 +339,7 @@ macro_rules! decl_module {
{}
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
fn on_finalize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
@@ -349,6 +355,7 @@ macro_rules! decl_module {
{ fn on_finalize( $( $param_name : $param ),* ) { $( $impl )* } }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -363,6 +370,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
fn on_initialize($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
@@ -378,6 +386,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -395,6 +404,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
fn offchain_worker($($param_name:ident : $param:ty),* ) { $( $impl:tt )* }
@@ -412,6 +422,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ fn offchain_worker( $( $param_name : $param ),* ) { $( $impl )* } }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
@@ -431,6 +442,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$( #[doc = $doc_attr:tt] )*
const $name:ident: $ty:ty = $value:expr;
@@ -453,11 +465,85 @@ macro_rules! decl_module {
$( #[doc = $doc_attr ] )*
$name: $ty = $value;
}
{ $( $error_type )* }
[ $( $dispatchables )* ]
$($rest)*
);
};
// Parse error type
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<
$trait_instance:ident:
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $other_where_bounds:tt )* }
{ $( $deposit_event:tt )* }
{ $( $on_initialize:tt )* }
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
type Error = $error_type:ty;
$($rest:tt)*
) => {
$crate::decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
>
for enum $call_type where origin: $origin_type, system = $system
{ $( $other_where_bounds )* }
{ $( $deposit_event )* }
{ $( $on_initialize )* }
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $error_type }
[ $( $dispatchables )* ]
$($rest)*
);
};
// Add default Error if none supplied
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<
$trait_instance:ident:
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $other_where_bounds:tt )* }
{ $( $deposit_event:tt )* }
{ $( $on_initialize:tt )* }
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ }
[ $($t:tt)* ]
$($rest:tt)*
) => {
$crate::decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
>
for enum $call_type where origin: $origin_type, system = $system
{ $( $other_where_bounds )* }
{ $( $deposit_event )* }
{ $( $on_initialize )* }
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ &'static str }
[ $($t)* ]
$($rest)*
);
};
// This puts the function statement into the [], decreasing `$rest` and moving toward finishing the parse.
(@normalize
$(#[$attr:meta])*
@@ -472,6 +558,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $error_type:ty }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
#[weight = $weight:expr]
@@ -492,6 +579,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $error_type }
[
$( $dispatchables )*
$(#[doc = $doc_attr])*
@@ -518,6 +606,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$fn_vis:vis fn $fn_name:ident(
@@ -537,6 +626,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
[ $( $dispatchables )* ]
$(#[doc = $doc_attr])*
#[weight = $crate::dispatch::SimpleDispatchInfo::default()]
@@ -557,6 +647,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
@@ -581,6 +672,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
@@ -605,6 +697,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
@@ -630,6 +723,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $( $error_type:tt )* }
[ $( $dispatchables:tt )* ]
) => {
$crate::decl_module!(@imp
@@ -644,6 +738,7 @@ macro_rules! decl_module {
{ $( $on_finalize )* }
{ $( $offchain )* }
{ $( $constants )* }
{ $( $error_type )* }
);
};
@@ -794,6 +889,7 @@ macro_rules! decl_module {
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
$error_type:ty;
$ignore:ident;
$(#[doc = $doc_attr:tt])*
$vis:vis fn $name:ident (
@@ -804,7 +900,7 @@ macro_rules! decl_module {
#[allow(unreachable_code)]
$vis fn $name(
$origin: $origin_ty $(, $param: $param_ty )*
) -> $crate::dispatch::Result {
) -> $crate::dispatch::DispatchResult<$error_type> {
{ $( $impl )* }
// May be unreachable.
Ok(())
@@ -815,6 +911,7 @@ macro_rules! decl_module {
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
$error_type:ty;
$ignore:ident;
$(#[doc = $doc_attr:tt])*
$vis:vis fn $name:ident (
@@ -969,6 +1066,7 @@ macro_rules! decl_module {
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
{ $( $constants:tt )* }
{ $error_type:ty }
) => {
$crate::__check_reserved_fn_name! { $( $fn_name )* }
@@ -1020,6 +1118,7 @@ macro_rules! decl_module {
@impl_function
$mod_type<$trait_instance: $trait_name $(<I>, $fn_instance: $fn_instantiable)?>;
$origin_type;
$error_type;
$from;
$(#[doc = $doc_attr])*
$fn_vis fn $fn_name (
@@ -1150,7 +1249,8 @@ macro_rules! decl_module {
{
type Trait = $trait_instance;
type Origin = $origin_type;
fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::Result {
type Error = $error_type;
fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::DispatchResult<Self::Error> {
match self {
$(
$call_type::$fn_name( $( $param_name ),* ) => {
@@ -1177,8 +1277,8 @@ macro_rules! decl_module {
#[doc(hidden)]
pub fn dispatch<D: $crate::dispatch::Dispatchable<Trait = $trait_instance>>(
d: D,
origin: D::Origin,
) -> $crate::dispatch::Result {
origin: D::Origin
) -> $crate::dispatch::DispatchResult<D::Error> {
d.dispatch(origin)
}
}
@@ -1234,9 +1334,19 @@ macro_rules! impl_outer_dispatch {
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), )*
type Error = $crate::dispatch::DispatchError;
fn dispatch(
self,
origin: $origin,
) -> $crate::dispatch::DispatchResult<$crate::dispatch::DispatchError> {
$crate::impl_outer_dispatch! {
@DISPATCH_MATCH
self
$call_type
origin
{}
0;
$( $camelcase ),*
}
}
}
@@ -1258,6 +1368,43 @@ macro_rules! impl_outer_dispatch {
}
}
)*
};
(@DISPATCH_MATCH
$self:ident
$call_type:ident
$origin:ident
{ $( $generated:tt )* }
$index:expr;
$name:ident
$( , $rest:ident )*
) => {
$crate::impl_outer_dispatch! {
@DISPATCH_MATCH
$self
$call_type
$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
}),
}
$index + 1;
$( $rest ),*
}
};
(@DISPATCH_MATCH
$self:ident
$call_type:ident
$origin:ident
{ $( $generated:tt )* }
$index:expr;
) => {
match $self {
$( $generated )*
}
}
}
+151
View File
@@ -0,0 +1,151 @@
// 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/>.
//! Macro for declaring a module error.
#[doc(hidden)]
pub use sr_primitives::traits::LookupError;
/// 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.
///
/// # Usage
///
/// ```
/// # use srml_support::decl_error;
/// decl_error! {
/// /// Errors that can occur in my module.
/// pub enum MyError {
/// /// Hey this is an error message that indicates bla.
/// MyCoolErrorMessage,
/// /// You are just not cool enough for my module!
/// YouAreNotCoolEnough,
/// }
/// }
/// ```
///
/// `decl_error!` supports only variants that do not hold any data.
#[macro_export]
macro_rules! decl_error {
(
$(#[$attr:meta])*
pub enum $error:ident {
$(
$( #[$variant_attr:meta] )*
$name:ident
),*
$(,)?
}
) => {
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
$(#[$attr])*
pub enum $error {
Other(&'static str),
CannotLookup,
$(
$(#[$variant_attr])*
$name
),*
}
impl $crate::dispatch::ModuleDispatchError for $error {
fn as_u8(&self) -> u8 {
$crate::decl_error! {
@GENERATE_AS_U8
self
$error
{}
2,
$( $name ),*
}
}
fn as_str(&self) -> &'static str {
match self {
$error::Other(err) => err,
$error::CannotLookup => "Can not lookup",
$(
$error::$name => stringify!($name),
)*
}
}
}
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;
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()))
}
}
};
(@GENERATE_AS_U8
$self:ident
$error:ident
{ $( $generated:tt )* }
$index:expr,
$name:ident
$( , $rest:ident )*
) => {
$crate::decl_error! {
@GENERATE_AS_U8
$self
$error
{
$( $generated )*
$error::$name => $index,
}
$index + 1,
$( $rest ),*
}
};
(@GENERATE_AS_U8
$self:ident
$error:ident
{ $( $generated:tt )* }
$index:expr,
) => {
match $self {
$error::Other(_) => 0,
$error::CannotLookup => 1,
$( $generated )*
}
}
}
+10 -5
View File
@@ -58,14 +58,16 @@ mod runtime;
pub mod inherent;
#[macro_use]
pub mod unsigned;
#[macro_use]
pub mod error;
mod double_map;
pub mod traits;
pub use self::storage::{StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap};
pub use self::hashable::Hashable;
pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType};
pub use self::dispatch::{Parameter, Callable, IsSubType};
pub use self::double_map::StorageDoubleMapWithHasher;
pub use runtime_io::{print, storage_root};
pub use runtime_io::{print, storage_root, Printable};
pub use sr_primitives::{self, ConsensusEngineId};
/// Macro for easily creating a new implementation of the `Get` trait. Use similarly to
@@ -128,7 +130,7 @@ macro_rules! fail {
/// Used as `ensure!(expression_to_ensure, expression_to_return_on_false)`.
#[macro_export]
macro_rules! ensure {
( $x:expr, $y:expr ) => {{
( $x:expr, $y:expr $(,)? ) => {{
if !$x {
$crate::fail!($y);
}
@@ -142,7 +144,10 @@ macro_rules! ensure {
#[macro_export]
#[cfg(feature = "std")]
macro_rules! assert_noop {
( $x:expr , $y:expr ) => {
(
$x:expr,
$y:expr $(,)?
) => {
let h = $crate::storage_root();
$crate::assert_err!($x, $y);
assert_eq!(h, $crate::storage_root());
@@ -159,7 +164,7 @@ macro_rules! assert_noop {
#[macro_export]
#[cfg(feature = "std")]
macro_rules! assert_err {
( $x:expr , $y:expr ) => {
( $x:expr , $y:expr $(,)? ) => {
assert_eq!($x, Err($y));
}
}
+3 -4
View File
@@ -17,7 +17,7 @@
#[doc(hidden)]
pub use crate::sr_primitives::traits::ValidateUnsigned;
#[doc(hidden)]
pub use crate::sr_primitives::transaction_validity::TransactionValidity;
pub use crate::sr_primitives::transaction_validity::{TransactionValidity, UnknownTransaction};
#[doc(hidden)]
pub use crate::sr_primitives::ApplyError;
@@ -72,7 +72,7 @@ macro_rules! impl_outer_validate_unsigned {
#[allow(unreachable_patterns)]
match call {
$( Call::$module(inner_call) => $module::validate_unsigned(inner_call), )*
_ => $crate::unsigned::TransactionValidity::Invalid($crate::unsigned::ApplyError::BadSignature as i8),
_ => $crate::unsigned::UnknownTransaction::NoUnsignedValidator.into(),
}
}
}
@@ -81,8 +81,7 @@ macro_rules! impl_outer_validate_unsigned {
#[cfg(test)]
mod test_empty_call {
pub enum Call {
}
pub enum Call {}
#[allow(unused)]
pub struct Runtime;