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
+37 -37
View File
@@ -147,7 +147,7 @@
//! decl_module! {
//! pub struct Module<T: Trait> for enum Call where origin: T::Origin {
//! /// Reward a validator.
//! pub fn reward_myself(origin) -> dispatch::Result {
//! pub fn reward_myself(origin) -> dispatch::DispatchResult {
//! let reported = ensure_signed(origin)?;
//! <staking::Module<T>>::reward_by_ids(vec![(reported, 10)]);
//! Ok(())
@@ -272,7 +272,7 @@ use sp_runtime::{
curve::PiecewiseLinear,
traits::{
Convert, Zero, One, StaticLookup, CheckedSub, Saturating, Bounded, SaturatedConversion,
SimpleArithmetic, EnsureOrigin, ModuleDispatchError,
SimpleArithmetic, EnsureOrigin,
}
};
use sp_staking::{
@@ -785,7 +785,7 @@ decl_event!(
decl_error! {
/// Error for the stacking module.
pub enum Error {
pub enum Error for Module<T: Trait> {
/// Not a controller account.
NotController,
/// Not a stash account.
@@ -817,7 +817,7 @@ decl_module! {
/// Number of eras that staked funds must remain bonded for.
const BondingDuration: EraIndex = T::BondingDuration::get();
type Error = Error;
type Error = Error<T>;
fn deposit_event() = default;
@@ -853,21 +853,21 @@ decl_module! {
#[compact] value: BalanceOf<T>,
payee: RewardDestination
) {
let stash = ensure_signed(origin).map_err(|e| e.as_str())?;
let stash = ensure_signed(origin)?;
if <Bonded<T>>::exists(&stash) {
return Err(Error::AlreadyBonded)
Err(Error::<T>::AlreadyBonded)?
}
let controller = T::Lookup::lookup(controller)?;
if <Ledger<T>>::exists(&controller) {
return Err(Error::AlreadyPaired)
Err(Error::<T>::AlreadyPaired)?
}
// reject a bond which is considered to be _dust_.
if value < T::Currency::minimum_balance() {
return Err(Error::InsufficientValue)
Err(Error::<T>::InsufficientValue)?
}
// You're auto-bonded forever, here. We might improve this by only bonding when
@@ -897,10 +897,10 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
fn bond_extra(origin, #[compact] max_additional: BalanceOf<T>) {
let stash = ensure_signed(origin).map_err(|e| e.as_str())?;
let stash = ensure_signed(origin)?;
let controller = Self::bonded(&stash).ok_or(Error::NotStash)?;
let mut ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = Self::bonded(&stash).ok_or(Error::<T>::NotStash)?;
let mut ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
let stash_balance = T::Currency::free_balance(&stash);
@@ -937,11 +937,11 @@ decl_module! {
/// </weight>
#[weight = SimpleDispatchInfo::FixedNormal(400_000)]
fn unbond(origin, #[compact] value: BalanceOf<T>) {
let controller = ensure_signed(origin).map_err(|e| e.as_str())?;
let mut ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = ensure_signed(origin)?;
let mut ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
ensure!(
ledger.unlocking.len() < MAX_UNLOCKING_CHUNKS,
Error::NoMoreChunks
Error::<T>::NoMoreChunks,
);
let mut value = value.min(ledger.active);
@@ -979,8 +979,8 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(400_000)]
fn withdraw_unbonded(origin) {
let controller = ensure_signed(origin).map_err(|e| e.as_str())?;
let ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
let ledger = ledger.consolidate_unlocked(Self::current_era());
if ledger.unlocking.is_empty() && ledger.active.is_zero() {
@@ -1013,8 +1013,8 @@ decl_module! {
fn validate(origin, prefs: ValidatorPrefs) {
Self::ensure_storage_upgraded();
let controller = ensure_signed(origin).map_err(|e| e.as_str())?;
let ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
let stash = &ledger.stash;
<Nominators<T>>::remove(stash);
<Validators<T>>::insert(stash, prefs);
@@ -1035,10 +1035,10 @@ decl_module! {
fn nominate(origin, targets: Vec<<T::Lookup as StaticLookup>::Source>) {
Self::ensure_storage_upgraded();
let controller = ensure_signed(origin).map_err(|e| e.as_str())?;
let ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
let stash = &ledger.stash;
ensure!(!targets.is_empty(), Error::EmptyTargets);
ensure!(!targets.is_empty(), Error::<T>::EmptyTargets);
let targets = targets.into_iter()
.take(MAX_NOMINATIONS)
.map(|t| T::Lookup::lookup(t))
@@ -1067,8 +1067,8 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
fn chill(origin) {
let controller = ensure_signed(origin).map_err(|e| e.as_str())?;
let ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
Self::chill_stash(&ledger.stash);
}
@@ -1085,8 +1085,8 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
fn set_payee(origin, payee: RewardDestination) {
let controller = ensure_signed(origin).map_err(|e| e.as_str())?;
let ledger = Self::ledger(&controller).ok_or(Error::NotController)?;
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
let stash = &ledger.stash;
<Payee<T>>::insert(stash, payee);
}
@@ -1104,11 +1104,11 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(750_000)]
fn set_controller(origin, controller: <T::Lookup as StaticLookup>::Source) {
let stash = ensure_signed(origin).map_err(|e| e.as_str())?;
let old_controller = Self::bonded(&stash).ok_or(Error::NotStash)?;
let stash = ensure_signed(origin)?;
let old_controller = Self::bonded(&stash).ok_or(Error::<T>::NotStash)?;
let controller = T::Lookup::lookup(controller)?;
if <Ledger<T>>::exists(&controller) {
return Err(Error::AlreadyPaired)
Err(Error::<T>::AlreadyPaired)?
}
if controller != old_controller {
<Bonded<T>>::insert(&stash, &controller);
@@ -1121,7 +1121,7 @@ decl_module! {
/// The ideal number of validators.
#[weight = SimpleDispatchInfo::FreeOperational]
fn set_validator_count(origin, #[compact] new: u32) {
ensure_root(origin).map_err(|e| e.as_str())?;
ensure_root(origin)?;
ValidatorCount::put(new);
}
@@ -1134,7 +1134,7 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FreeOperational]
fn force_no_eras(origin) {
ensure_root(origin).map_err(|e| e.as_str())?;
ensure_root(origin)?;
ForceEra::put(Forcing::ForceNone);
}
@@ -1146,21 +1146,21 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FreeOperational]
fn force_new_era(origin) {
ensure_root(origin).map_err(|e| e.as_str())?;
ensure_root(origin)?;
ForceEra::put(Forcing::ForceNew);
}
/// Set the validators who cannot be slashed (if any).
#[weight = SimpleDispatchInfo::FreeOperational]
fn set_invulnerables(origin, validators: Vec<T::AccountId>) {
ensure_root(origin).map_err(|e| e.as_str())?;
ensure_root(origin)?;
<Invulnerables<T>>::put(validators);
}
/// Force a current staker to become completely unstaked, immediately.
#[weight = SimpleDispatchInfo::FreeOperational]
fn force_unstake(origin, stash: T::AccountId) {
ensure_root(origin).map_err(|e| e.as_str())?;
ensure_root(origin)?;
// remove the lock.
T::Currency::remove_lock(STAKING_ID, &stash);
@@ -1175,7 +1175,7 @@ decl_module! {
/// # </weight>
#[weight = SimpleDispatchInfo::FreeOperational]
fn force_new_era_always(origin) {
ensure_root(origin).map_err(|e| e.as_str())?;
ensure_root(origin)?;
ForceEra::put(Forcing::ForceAlways);
}
@@ -1191,7 +1191,7 @@ decl_module! {
T::SlashCancelOrigin::try_origin(origin)
.map(|_| ())
.or_else(ensure_root)
.map_err(|_| Error::BadOrigin)?;
.map_err(|_| Error::<T>::BadOrigin)?;
let mut slash_indices = slash_indices;
slash_indices.sort_unstable();
@@ -1201,12 +1201,12 @@ decl_module! {
let index = index as usize;
// if `index` is not duplicate, `removed` must be <= index.
ensure!(removed <= index, Error::DuplicateIndex);
ensure!(removed <= index, Error::<T>::DuplicateIndex);
// all prior removals were from before this index, since the
// list is sorted.
let index = index - removed;
ensure!(index < unapplied.len(), Error::InvalidSlashIndex);
ensure!(index < unapplied.len(), Error::<T>::InvalidSlashIndex);
unapplied.remove(index);
}
+1
View File
@@ -137,6 +137,7 @@ impl frame_system::Trait for Test {
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
type Version = ();
type ModuleToIndex = ();
}
parameter_types! {
pub const TransferFee: Balance = 0;
+9 -9
View File
@@ -18,7 +18,7 @@
use super::*;
use mock::*;
use sp_runtime::{assert_eq_error_rate, traits::OnInitialize};
use sp_runtime::{assert_eq_error_rate, traits::{OnInitialize, BadOrigin}};
use sp_staking::offence::OffenceDetails;
use frame_support::{assert_ok, assert_noop, traits::{Currency, ReservableCurrency}};
use substrate_test_utils::assert_eq_uvec;
@@ -35,7 +35,7 @@ fn force_unstake_works() {
"account liquidity restrictions prevent withdrawal"
);
// Force unstake requires root.
assert_noop!(Staking::force_unstake(Origin::signed(11), 11), "RequireRootOrigin".into());
assert_noop!(Staking::force_unstake(Origin::signed(11), 11), BadOrigin);
// We now force them to unstake
assert_ok!(Staking::force_unstake(Origin::ROOT, 11));
// No longer bonded.
@@ -142,7 +142,7 @@ fn change_controller_works() {
assert_noop!(
Staking::validate(Origin::signed(10), ValidatorPrefs::default()),
Error::NotController,
Error::<Test>::NotController,
);
assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default()));
})
@@ -680,10 +680,10 @@ fn double_staking_should_fail() {
// 4 = not used so far, 1 stashed => not allowed.
assert_noop!(
Staking::bond(Origin::signed(1), 4, arbitrary_value,
RewardDestination::default()), Error::AlreadyBonded,
RewardDestination::default()), Error::<Test>::AlreadyBonded,
);
// 1 = stashed => attempting to nominate should fail.
assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), Error::NotController);
assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), Error::<Test>::NotController);
// 2 = controller => nominating should work.
assert_ok!(Staking::nominate(Origin::signed(2), vec![1]));
});
@@ -705,7 +705,7 @@ fn double_controlling_should_fail() {
// 2 = controller, 3 stashed (Note that 2 is reused.) => no-op
assert_noop!(
Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()),
Error::AlreadyPaired,
Error::<Test>::AlreadyPaired,
);
});
}
@@ -1152,11 +1152,11 @@ fn too_many_unbond_calls_should_not_work() {
// locked at era 1 until 4
assert_ok!(Staking::unbond(Origin::signed(10), 1));
// can't do more.
assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::NoMoreChunks);
assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::<Test>::NoMoreChunks);
start_era(3);
assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::NoMoreChunks);
assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::<Test>::NoMoreChunks);
// free up.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10)));
@@ -1422,7 +1422,7 @@ fn bond_with_no_staked_value() {
// Can't bond with 1
assert_noop!(
Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller),
Error::InsufficientValue,
Error::<Test>::InsufficientValue,
);
// bonded with absolute minimum value possible.
assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller));