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
+30 -29
View File
@@ -30,8 +30,10 @@ use frame_support::traits::{Currency, WithdrawReason, ExistenceRequirement};
use frame_system::{self as system, ensure_signed};
use sp_runtime::ModuleId;
use frame_support::weights::SimpleDispatchInfo;
use sp_runtime::traits::{UniqueSaturatedInto, AccountIdConversion, SaturatedConversion, ModuleDispatchError};
use sp_core::{U256, H256, H160, Hasher};
use sp_runtime::{
DispatchResult, traits::{UniqueSaturatedInto, AccountIdConversion, SaturatedConversion},
};
use evm::{ExitReason, ExitSucceed, ExitError};
use evm::executor::StackExecutor;
use evm::backend::ApplyBackend;
@@ -176,7 +178,7 @@ decl_event! {
}
decl_error! {
pub enum Error {
pub enum Error for Module<T: Trait> {
/// Not enough balance to perform action
BalanceLow,
/// Calculating total fee overflowed
@@ -198,14 +200,14 @@ decl_error! {
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error;
type Error = Error<T>;
fn deposit_event() = default;
/// Despoit balance from currency/balances module into EVM.
#[weight = SimpleDispatchInfo::FixedNormal(10_000)]
fn deposit_balance(origin, value: BalanceOf<T>) {
let sender = ensure_signed(origin).map_err(|e| e.as_str())?;
let sender = ensure_signed(origin)?;
let imbalance = T::Currency::withdraw(
&sender,
@@ -225,13 +227,13 @@ decl_module! {
/// Withdraw balance from EVM into currency/balances module.
#[weight = SimpleDispatchInfo::FixedNormal(10_000)]
fn withdraw_balance(origin, value: BalanceOf<T>) {
let sender = ensure_signed(origin).map_err(|e| e.as_str())?;
let sender = ensure_signed(origin)?;
let address = T::ConvertAccountId::convert_account_id(&sender);
let bvalue = U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(value));
let mut account = Accounts::get(&address);
account.balance = account.balance.checked_sub(bvalue)
.ok_or(Error::BalanceLow)?;
.ok_or(Error::<T>::BalanceLow)?;
let imbalance = T::Currency::withdraw(
&Self::account_id(),
@@ -254,10 +256,9 @@ decl_module! {
value: U256,
gas_limit: u32,
gas_price: U256,
) {
let sender = ensure_signed(origin).map_err(|e| e.as_str())?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::GasPriceTooLow);
) -> DispatchResult {
let sender = ensure_signed(origin)?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
let source = T::ConvertAccountId::convert_account_id(&sender);
let vicinity = Vicinity {
@@ -274,13 +275,13 @@ decl_module! {
);
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
.ok_or(Error::FeeOverflow)?;
.ok_or(Error::<T>::FeeOverflow)?;
if Accounts::get(&source).balance <
value.checked_add(total_fee).ok_or(Error::PaymentOverflow)?
value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?
{
return Err(Error::BalanceLow)
Err(Error::<T>::BalanceLow)?
}
executor.withdraw(source, total_fee).map_err(|_| Error::WithdrawFailed)?;
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
let reason = executor.transact_call(
source,
@@ -292,9 +293,9 @@ decl_module! {
let ret = match reason {
ExitReason::Succeed(_) => Ok(()),
ExitReason::Error(_) => Err(Error::ExitReasonFailed),
ExitReason::Revert(_) => Err(Error::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::ExitReasonFatal),
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed),
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal),
};
let actual_fee = executor.fee(gas_price);
executor.deposit(source, total_fee.saturating_sub(actual_fee));
@@ -302,7 +303,7 @@ decl_module! {
let (values, logs) = executor.deconstruct();
backend.apply(values, logs, true);
return ret;
ret.map_err(Into::into)
}
/// Issue an EVM create operation. This is similar to a contract creation transaction in
@@ -314,9 +315,9 @@ decl_module! {
value: U256,
gas_limit: u32,
gas_price: U256,
) {
let sender = ensure_signed(origin).map_err(|e| e.as_str())?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::GasPriceTooLow);
) -> DispatchResult {
let sender = ensure_signed(origin)?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
let source = T::ConvertAccountId::convert_account_id(&sender);
@@ -334,13 +335,13 @@ decl_module! {
);
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
.ok_or(Error::FeeOverflow)?;
.ok_or(Error::<T>::FeeOverflow)?;
if Accounts::get(&source).balance <
value.checked_add(total_fee).ok_or(Error::PaymentOverflow)?
value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?
{
return Err(Error::BalanceLow)
Err(Error::<T>::BalanceLow)?
}
executor.withdraw(source, total_fee).map_err(|_| Error::WithdrawFailed)?;
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
let reason = executor.transact_create(
source,
@@ -351,9 +352,9 @@ decl_module! {
let ret = match reason {
ExitReason::Succeed(_) => Ok(()),
ExitReason::Error(_) => Err(Error::ExitReasonFailed),
ExitReason::Revert(_) => Err(Error::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::ExitReasonFatal),
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed),
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal),
};
let actual_fee = executor.fee(gas_price);
executor.deposit(source, total_fee.saturating_sub(actual_fee));
@@ -361,7 +362,7 @@ decl_module! {
let (values, logs) = executor.deconstruct();
backend.apply(values, logs, true);
return ret;
ret.map_err(Into::into)
}
}
}