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:
Bastian Köcher
2019-12-19 14:01:52 +01:00
committed by Gavin Wood
parent 0aab5c659e
commit 8e393aa5a8
69 changed files with 868 additions and 611 deletions
+19 -16
View File
@@ -75,7 +75,7 @@
//!
//! decl_module! {
//! pub struct Module<T: Trait> for enum Call where origin: T::Origin {
//! pub fn system_module_example(origin) -> dispatch::Result {
//! pub fn system_module_example(origin) -> dispatch::DispatchResult {
//! let _sender = ensure_signed(origin)?;
//! let _extrinsic_count = <system::Module<T>>::extrinsic_count();
//! let _parent_hash = <system::Module<T>>::parent_hash();
@@ -105,7 +105,7 @@ use sp_runtime::{
},
traits::{
self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Lookup, LookupError,
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, SaturatedConversion,
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, BadOrigin, SaturatedConversion,
MaybeSerialize, MaybeSerializeDeserialize, StaticLookup, One, Bounded,
},
};
@@ -113,7 +113,7 @@ use sp_runtime::{
use sp_core::storage::well_known_keys;
use frame_support::{
decl_module, decl_event, decl_storage, decl_error, storage, Parameter,
traits::{Contains, Get},
traits::{Contains, Get, ModuleToIndex},
weights::{Weight, DispatchInfo, DispatchClass, SimpleDispatchInfo},
};
use codec::{Encode, Decode};
@@ -219,6 +219,12 @@ pub trait Trait: 'static + Eq + Clone {
/// Get the chain's current version.
type Version: Get<RuntimeVersion>;
/// Convert a module to its index in the runtime.
///
/// Expects the `ModuleToIndex` type that is being generated by `construct_runtime!` in the
/// runtime. For tests it is okay to use `()` as type (returns `0` for each input).
type ModuleToIndex: ModuleToIndex;
}
pub type DigestOf<T> = generic::Digest<<T as Trait>::Hash>;
@@ -229,7 +235,7 @@ pub type KeyValue = (Vec<u8>, Vec<u8>);
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error;
type Error = Error<T>;
/// A big dispatch that will disallow any other transaction to be included.
// TODO: this must be preferable available for testing really (not possible at the moment).
@@ -319,11 +325,7 @@ decl_event!(
decl_error! {
/// Error for the System module
pub enum Error {
RequireSignedOrigin,
RequireRootOrigin,
RequireNoOrigin,
}
pub enum Error for Module<T: Trait> {}
}
/// Origin for the System module.
@@ -502,32 +504,32 @@ impl<O, T> EnsureOrigin<O> for EnsureNever<T> {
/// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction).
/// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise.
pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, Error>
pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, BadOrigin>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::Signed(t)) => Ok(t),
_ => Err(Error::RequireSignedOrigin),
_ => Err(BadOrigin),
}
}
/// Ensure that the origin `o` represents the root. Returns `Ok` or an `Err` otherwise.
pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), Error>
pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), BadOrigin>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::Root) => Ok(()),
_ => Err(Error::RequireRootOrigin),
_ => Err(BadOrigin),
}
}
/// Ensure that the origin `o` represents an unsigned extrinsic. Returns `Ok` or an `Err` otherwise.
pub fn ensure_none<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), Error>
pub fn ensure_none<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), BadOrigin>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::None) => Ok(()),
_ => Err(Error::RequireNoOrigin),
_ => Err(BadOrigin),
}
}
@@ -1175,6 +1177,7 @@ mod tests {
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
type Version = ();
type ModuleToIndex = ();
}
impl From<Event> for u16 {
@@ -1230,7 +1233,7 @@ mod tests {
System::initialize(&2, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default());
System::deposit_event(42u16);
System::note_applied_extrinsic(&Ok(()), 0, Default::default());
System::note_applied_extrinsic(&Err(DispatchError::new(Some(1), 2, None)), 0, Default::default());
System::note_applied_extrinsic(&Err(DispatchError::BadOrigin), 0, Default::default());
System::note_finished_extrinsics();
System::deposit_event(3u16);
System::finalize();