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
+16 -14
View File
@@ -66,9 +66,7 @@ use frame_support::traits::{
ReservableCurrency, WithdrawReason
};
use sp_runtime::{Permill, ModuleId};
use sp_runtime::traits::{
Zero, EnsureOrigin, StaticLookup, AccountIdConversion, Saturating, ModuleDispatchError,
};
use sp_runtime::traits::{Zero, EnsureOrigin, StaticLookup, AccountIdConversion, Saturating};
use frame_support::weights::SimpleDispatchInfo;
use codec::{Encode, Decode};
use frame_system::{self as system, ensure_signed};
@@ -126,7 +124,7 @@ decl_module! {
/// Percentage of spare funds (if any) that are burnt per spend period.
const Burn: Permill = T::Burn::get();
type Error = Error;
type Error = Error<T>;
fn deposit_event() = default;
@@ -145,12 +143,12 @@ decl_module! {
#[compact] value: BalanceOf<T>,
beneficiary: <T::Lookup as StaticLookup>::Source
) {
let proposer = ensure_signed(origin).map_err(|e| e.as_str())?;
let proposer = ensure_signed(origin)?;
let beneficiary = T::Lookup::lookup(beneficiary)?;
let bond = Self::calculate_bond(value);
T::Currency::reserve(&proposer, bond)
.map_err(|_| Error::InsufficientProposersBalance)?;
.map_err(|_| Error::<T>::InsufficientProposersBalance)?;
let c = Self::proposal_count();
ProposalCount::put(c + 1);
@@ -169,7 +167,7 @@ decl_module! {
#[weight = SimpleDispatchInfo::FixedOperational(100_000)]
fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) {
T::RejectOrigin::ensure_origin(origin).map_err(|e| Into::<&str>::into(e))?;
let proposal = <Proposals<T>>::take(proposal_id).ok_or(Error::InvalidProposalIndex)?;
let proposal = <Proposals<T>>::take(proposal_id).ok_or(Error::<T>::InvalidProposalIndex)?;
let value = proposal.bond;
let imbalance = T::Currency::slash_reserved(&proposal.proposer, value).0;
@@ -188,7 +186,7 @@ decl_module! {
fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) {
T::ApproveOrigin::ensure_origin(origin).map_err(|e| Into::<&str>::into(e))?;
ensure!(<Proposals<T>>::exists(proposal_id), Error::InvalidProposalIndex);
ensure!(<Proposals<T>>::exists(proposal_id), Error::<T>::InvalidProposalIndex);
Approvals::mutate(|v| v.push(proposal_id));
}
@@ -257,7 +255,7 @@ decl_event!(
decl_error! {
/// Error for the treasury module.
pub enum Error {
pub enum Error for Module<T: Trait> {
/// Proposer's balance is too low.
InsufficientProposersBalance,
/// No proposal at that index.
@@ -398,6 +396,7 @@ mod tests {
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
type Version = ();
type ModuleToIndex = ();
}
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
@@ -484,7 +483,10 @@ mod tests {
#[test]
fn spend_proposal_fails_when_proposer_poor() {
new_test_ext().execute_with(|| {
assert_noop!(Treasury::propose_spend(Origin::signed(2), 100, 3), Error::InsufficientProposersBalance);
assert_noop!(
Treasury::propose_spend(Origin::signed(2), 100, 3),
Error::<Test>::InsufficientProposersBalance,
);
});
}
@@ -536,21 +538,21 @@ mod tests {
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0));
assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), Error::InvalidProposalIndex);
assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), Error::<Test>::InvalidProposalIndex);
});
}
#[test]
fn reject_non_existant_spend_proposal_fails() {
new_test_ext().execute_with(|| {
assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), Error::InvalidProposalIndex);
assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), Error::<Test>::InvalidProposalIndex);
});
}
#[test]
fn accept_non_existant_spend_proposal_fails() {
new_test_ext().execute_with(|| {
assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), Error::InvalidProposalIndex);
assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), Error::<Test>::InvalidProposalIndex);
});
}
@@ -561,7 +563,7 @@ mod tests {
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0));
assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), Error::InvalidProposalIndex);
assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), Error::<Test>::InvalidProposalIndex);
});
}