Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

Commit

Permalink
Add arithmetic dispatch errors. (paritytech#8726)
Browse files Browse the repository at this point in the history
* Add arithmetic dispatch errors.

* Replace custom overflow errors.

* Replace custom underflow and division by zero errors.

* Replace overflow/underflow in token error.

* Add token and arithmetic errors in dispatch error equality test.

* Trigger CI.
  • Loading branch information
shaunxw authored and nazar-pc committed Aug 8, 2021
1 parent 927cbe8 commit e2949e9
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 60 deletions.
3 changes: 2 additions & 1 deletion frame/assets/README.md
Expand Up @@ -71,6 +71,7 @@ Import the Assets module and types and derive your runtime's configuration trait
use pallet_assets as assets;
use frame_support::{decl_module, dispatch, ensure};
use frame_system::ensure_signed;
use sp_runtime::ArithmeticError;

pub trait Config: assets::Config { }

Expand All @@ -84,7 +85,7 @@ decl_module! {
const COUNT_AIRDROP_RECIPIENTS: u64 = 2;
const TOKENS_FIXED_SUPPLY: u64 = 100;

ensure!(!COUNT_AIRDROP_RECIPIENTS.is_zero(), "Divide by zero error.");
ensure!(!COUNT_AIRDROP_RECIPIENTS.is_zero(), ArithmeticError::DivisionByZero);

let asset_id = Self::next_asset_id();

Expand Down
6 changes: 3 additions & 3 deletions frame/assets/src/functions.rs
Expand Up @@ -47,7 +47,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
who: &T::AccountId,
d: &mut AssetDetails<T::Balance, T::AccountId, DepositBalanceOf<T, I>>,
) -> Result<bool, DispatchError> {
let accounts = d.accounts.checked_add(1).ok_or(Error::<T, I>::Overflow)?;
let accounts = d.accounts.checked_add(1).ok_or(ArithmeticError::Overflow)?;
let is_sufficient = if d.is_sufficient {
frame_system::Pallet::<T>::inc_sufficients(who);
d.sufficients += 1;
Expand Down Expand Up @@ -162,7 +162,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
id: T::AssetId,
who: &T::AccountId,
keep_alive: bool,
) -> Result<T::Balance, Error<T, I>> {
) -> Result<T::Balance, DispatchError> {
let details = Asset::<T, I>::get(id).ok_or_else(|| Error::<T, I>::Unknown)?;
ensure!(!details.is_frozen, Error::<T, I>::Frozen);

Expand All @@ -173,7 +173,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
// Frozen balance: account CANNOT be deleted
let required = frozen
.checked_add(&details.min_balance)
.ok_or(Error::<T, I>::Overflow)?;
.ok_or(ArithmeticError::Overflow)?;
account.balance.saturating_sub(required)
} else {
let is_provider = false;
Expand Down
4 changes: 1 addition & 3 deletions frame/assets/src/lib.rs
Expand Up @@ -140,7 +140,7 @@ pub use types::*;

use sp_std::{prelude::*, borrow::Borrow};
use sp_runtime::{
RuntimeDebug, TokenError, traits::{
RuntimeDebug, TokenError, ArithmeticError, traits::{
AtLeast32BitUnsigned, Zero, StaticLookup, Saturating, CheckedSub, CheckedAdd, Bounded,
StoredMapError,
}
Expand Down Expand Up @@ -326,8 +326,6 @@ pub mod pallet {
BadWitness,
/// Minimum balance should be non-zero.
MinBalanceZero,
/// A mint operation lead to an overflow.
Overflow,
/// No provider reference exists to allow a non-zero balance of a non-self-sufficient asset.
NoProvider,
/// Invalid metadata given.
Expand Down
14 changes: 6 additions & 8 deletions frame/balances/src/lib.rs
Expand Up @@ -171,7 +171,7 @@ use frame_support::{
#[cfg(feature = "std")]
use frame_support::traits::GenesisBuild;
use sp_runtime::{
RuntimeDebug, DispatchResult, DispatchError,
RuntimeDebug, DispatchResult, DispatchError, ArithmeticError,
traits::{
Zero, AtLeast32BitUnsigned, StaticLookup, CheckedAdd, CheckedSub,
MaybeSerializeDeserialize, Saturating, Bounded, StoredMapError,
Expand Down Expand Up @@ -402,8 +402,6 @@ pub mod pallet {
VestingBalance,
/// Account liquidity restrictions prevent withdrawal
LiquidityRestrictions,
/// Got an overflow after adding
Overflow,
/// Balance too low to send value
InsufficientBalance,
/// Value too low to create account due to existential deposit
Expand Down Expand Up @@ -909,10 +907,10 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
match status {
Status::Free => to_account.free = to_account.free
.checked_add(&actual)
.ok_or(Error::<T, I>::Overflow)?,
.ok_or(ArithmeticError::Overflow)?,
Status::Reserved => to_account.reserved = to_account.reserved
.checked_add(&actual)
.ok_or(Error::<T, I>::Overflow)?,
.ok_or(ArithmeticError::Overflow)?,
}
from_account.reserved -= actual;
Ok(actual)
Expand Down Expand Up @@ -1332,7 +1330,7 @@ impl<T: Config<I>, I: 'static> Currency<T::AccountId> for Pallet<T, I> where

// NOTE: total stake being stored in the same type means that this could never overflow
// but better to be safe than sorry.
to_account.free = to_account.free.checked_add(&value).ok_or(Error::<T, I>::Overflow)?;
to_account.free = to_account.free.checked_add(&value).ok_or(ArithmeticError::Overflow)?;

let ed = T::ExistentialDeposit::get();
ensure!(to_account.total() >= ed, Error::<T, I>::ExistentialDeposit);
Expand Down Expand Up @@ -1431,7 +1429,7 @@ impl<T: Config<I>, I: 'static> Currency<T::AccountId> for Pallet<T, I> where

Self::try_mutate_account(who, |account, is_new| -> Result<Self::PositiveImbalance, DispatchError> {
ensure!(!is_new, Error::<T, I>::DeadAccount);
account.free = account.free.checked_add(&value).ok_or(Error::<T, I>::Overflow)?;
account.free = account.free.checked_add(&value).ok_or(ArithmeticError::Overflow)?;
Ok(PositiveImbalance::new(value))
})
}
Expand Down Expand Up @@ -1554,7 +1552,7 @@ impl<T: Config<I>, I: 'static> ReservableCurrency<T::AccountId> for Pallet<T, I>

Self::try_mutate_account(who, |account, _| -> DispatchResult {
account.free = account.free.checked_sub(&value).ok_or(Error::<T, I>::InsufficientBalance)?;
account.reserved = account.reserved.checked_add(&value).ok_or(Error::<T, I>::Overflow)?;
account.reserved = account.reserved.checked_add(&value).ok_or(ArithmeticError::Overflow)?;
Self::ensure_can_withdraw(&who, value.clone(), WithdrawReasons::RESERVE, account.free)
})?;

Expand Down
4 changes: 2 additions & 2 deletions frame/balances/src/tests.rs
Expand Up @@ -24,7 +24,7 @@ macro_rules! decl_tests {
($test:ty, $ext_builder:ty, $existential_deposit:expr) => {

use crate::*;
use sp_runtime::{FixedPointNumber, traits::{SignedExtension, BadOrigin}};
use sp_runtime::{ArithmeticError, FixedPointNumber, traits::{SignedExtension, BadOrigin}};
use frame_support::{
assert_noop, assert_storage_noop, assert_ok, assert_err, StorageValue,
traits::{
Expand Down Expand Up @@ -523,7 +523,7 @@ macro_rules! decl_tests {

assert_err!(
Balances::transfer(Some(1).into(), 2, u64::max_value()),
Error::<$test, _>::Overflow,
ArithmeticError::Overflow,
);

assert_eq!(Balances::free_balance(1), u64::max_value());
Expand Down
12 changes: 4 additions & 8 deletions frame/democracy/src/lib.rs
Expand Up @@ -154,7 +154,7 @@

use sp_std::prelude::*;
use sp_runtime::{
DispatchResult, DispatchError, RuntimeDebug,
DispatchResult, DispatchError, ArithmeticError, RuntimeDebug,
traits::{Zero, Hash, Dispatchable, Saturating, Bounded},
};
use codec::{Encode, Decode, Input};
Expand Down Expand Up @@ -510,10 +510,6 @@ decl_error! {
NoPermission,
/// The account is already delegating.
AlreadyDelegating,
/// An unexpected integer overflow occurred.
Overflow,
/// An unexpected integer underflow occurred.
Underflow,
/// Too high a balance was provided that the account cannot afford.
InsufficientFunds,
/// The account is not currently delegating.
Expand Down Expand Up @@ -1252,7 +1248,7 @@ impl<T: Config> Module<T> {
match votes.binary_search_by_key(&ref_index, |i| i.0) {
Ok(i) => {
// Shouldn't be possible to fail, but we handle it gracefully.
status.tally.remove(votes[i].1).ok_or(Error::<T>::Underflow)?;
status.tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?;
if let Some(approve) = votes[i].1.as_standard() {
status.tally.reduce(approve, *delegations);
}
Expand All @@ -1264,7 +1260,7 @@ impl<T: Config> Module<T> {
}
}
// Shouldn't be possible to fail, but we handle it gracefully.
status.tally.add(vote).ok_or(Error::<T>::Overflow)?;
status.tally.add(vote).ok_or(ArithmeticError::Overflow)?;
if let Some(approve) = vote.as_standard() {
status.tally.increase(approve, *delegations);
}
Expand Down Expand Up @@ -1300,7 +1296,7 @@ impl<T: Config> Module<T> {
Some(ReferendumInfo::Ongoing(mut status)) => {
ensure!(matches!(scope, UnvoteScope::Any), Error::<T>::NoPermission);
// Shouldn't be possible to fail, but we handle it gracefully.
status.tally.remove(votes[i].1).ok_or(Error::<T>::Underflow)?;
status.tally.remove(votes[i].1).ok_or(ArithmeticError::Underflow)?;
if let Some(approve) = votes[i].1.as_standard() {
status.tally.reduce(approve, *delegations);
}
Expand Down
8 changes: 3 additions & 5 deletions frame/lottery/src/lib.rs
Expand Up @@ -56,7 +56,7 @@ pub mod weights;

use sp_std::prelude::*;
use sp_runtime::{
DispatchError,
DispatchError, ArithmeticError,
traits::{AccountIdConversion, Saturating, Zero},
};
use frame_support::{
Expand Down Expand Up @@ -188,8 +188,6 @@ decl_event!(

decl_error! {
pub enum Error for Module<T: Config> {
/// An overflow has occurred.
Overflow,
/// A lottery has not been configured.
NotConfigured,
/// A lottery is already in progress.
Expand Down Expand Up @@ -278,7 +276,7 @@ decl_module! {
Lottery::<T>::try_mutate(|lottery| -> DispatchResult {
ensure!(lottery.is_none(), Error::<T>::InProgress);
let index = LotteryIndex::get();
let new_index = index.checked_add(1).ok_or(Error::<T>::Overflow)?;
let new_index = index.checked_add(1).ok_or(ArithmeticError::Overflow)?;
let start = frame_system::Pallet::<T>::block_number();
// Use new_index to more easily track everything with the current state.
*lottery = Some(LotteryConfig {
Expand Down Expand Up @@ -400,7 +398,7 @@ impl<T: Config> Module<T> {
ensure!(T::ValidateCall::validate_call(call), Error::<T>::InvalidCall);
let call_index = Self::call_to_index(call)?;
let ticket_count = TicketsCount::get();
let new_ticket_count = ticket_count.checked_add(1).ok_or(Error::<T>::Overflow)?;
let new_ticket_count = ticket_count.checked_add(1).ok_or(ArithmeticError::Overflow)?;
// Try to update the participant status
Participants::<T>::try_mutate(&caller, |(lottery_index, participating_calls)| -> DispatchResult {
let index = LotteryIndex::get();
Expand Down
10 changes: 4 additions & 6 deletions frame/recovery/src/lib.rs
Expand Up @@ -154,7 +154,7 @@
use sp_std::prelude::*;
use sp_runtime::{
traits::{Dispatchable, SaturatedConversion, CheckedAdd, CheckedMul},
DispatchResult
DispatchResult, ArithmeticError,
};
use codec::{Encode, Decode};

Expand Down Expand Up @@ -313,8 +313,6 @@ decl_error! {
Threshold,
/// There are still active recovery attempts that need to be closed
StillActive,
/// There was an overflow in a calculation
Overflow,
/// This account is already set up for recovery
AlreadyProxy,
/// Some internal state is broken.
Expand Down Expand Up @@ -443,10 +441,10 @@ decl_module! {
// Total deposit is base fee + number of friends * factor fee
let friend_deposit = T::FriendDepositFactor::get()
.checked_mul(&friends.len().saturated_into())
.ok_or(Error::<T>::Overflow)?;
.ok_or(ArithmeticError::Overflow)?;
let total_deposit = T::ConfigDepositBase::get()
.checked_add(&friend_deposit)
.ok_or(Error::<T>::Overflow)?;
.ok_or(ArithmeticError::Overflow)?;
// Reserve the deposit
T::Currency::reserve(&who, total_deposit)?;
// Create the recovery configuration
Expand Down Expand Up @@ -581,7 +579,7 @@ decl_module! {
let current_block_number = <system::Pallet<T>>::block_number();
let recoverable_block_number = active_recovery.created
.checked_add(&recovery_config.delay_period)
.ok_or(Error::<T>::Overflow)?;
.ok_or(ArithmeticError::Overflow)?;
ensure!(recoverable_block_number <= current_block_number, Error::<T>::DelayPeriod);
// Make sure the threshold is met
ensure!(
Expand Down
4 changes: 2 additions & 2 deletions frame/support/src/traits/tokens/fungible/balanced.rs
Expand Up @@ -20,7 +20,7 @@

use super::*;
use sp_std::marker::PhantomData;
use sp_runtime::{TokenError, traits::{CheckedAdd, Zero}};
use sp_runtime::{TokenError, ArithmeticError, traits::{CheckedAdd, Zero}};
use super::super::Imbalance as ImbalanceT;
use crate::traits::misc::{SameOrOther, TryDrop};
use crate::dispatch::{DispatchResult, DispatchError};
Expand Down Expand Up @@ -221,7 +221,7 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
-> Result<Self::Balance, DispatchError>
{
let old_balance = Self::balance(who);
let new_balance = old_balance.checked_add(&amount).ok_or(TokenError::Overflow)?;
let new_balance = old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
if new_balance < Self::minimum_balance() {
Err(TokenError::BelowMinimum)?
}
Expand Down
4 changes: 2 additions & 2 deletions frame/support/src/traits/tokens/fungibles/balanced.rs
Expand Up @@ -20,7 +20,7 @@

use super::*;
use sp_std::marker::PhantomData;
use sp_runtime::{TokenError, traits::{Zero, CheckedAdd}};
use sp_runtime::{ArithmeticError, TokenError, traits::{Zero, CheckedAdd}};
use sp_arithmetic::traits::Saturating;
use crate::dispatch::{DispatchError, DispatchResult};
use crate::traits::misc::{SameOrOther, TryDrop};
Expand Down Expand Up @@ -236,7 +236,7 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
-> Result<Self::Balance, DispatchError>
{
let old_balance = Self::balance(asset, who);
let new_balance = old_balance.checked_add(&amount).ok_or(TokenError::Overflow)?;
let new_balance = old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
if new_balance < Self::minimum_balance(asset) {
Err(TokenError::BelowMinimum)?
}
Expand Down
28 changes: 14 additions & 14 deletions frame/support/src/traits/tokens/misc.rs
Expand Up @@ -20,7 +20,7 @@
use codec::{Encode, Decode, FullCodec};
use sp_core::RuntimeDebug;
use sp_arithmetic::traits::{Zero, AtLeast32BitUnsigned};
use sp_runtime::TokenError;
use sp_runtime::{DispatchError, ArithmeticError, TokenError};

/// One of a number of consequences of withdrawing a fungible from an account.
#[derive(Copy, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -50,17 +50,17 @@ pub enum WithdrawConsequence<Balance> {
}

impl<Balance: Zero> WithdrawConsequence<Balance> {
/// Convert the type into a `Result` with `TokenError` as the error or the additional `Balance`
/// Convert the type into a `Result` with `DispatchError` as the error or the additional `Balance`
/// by which the account will be reduced.
pub fn into_result(self) -> Result<Balance, TokenError> {
pub fn into_result(self) -> Result<Balance, DispatchError> {
use WithdrawConsequence::*;
match self {
NoFunds => Err(TokenError::NoFunds),
WouldDie => Err(TokenError::WouldDie),
UnknownAsset => Err(TokenError::UnknownAsset),
Underflow => Err(TokenError::Underflow),
Overflow => Err(TokenError::Overflow),
Frozen => Err(TokenError::Frozen),
NoFunds => Err(TokenError::NoFunds.into()),
WouldDie => Err(TokenError::WouldDie.into()),
UnknownAsset => Err(TokenError::UnknownAsset.into()),
Underflow => Err(ArithmeticError::Underflow.into()),
Overflow => Err(ArithmeticError::Overflow.into()),
Frozen => Err(TokenError::Frozen.into()),
ReducedToZero(result) => Ok(result),
Success => Ok(Zero::zero()),
}
Expand Down Expand Up @@ -90,13 +90,13 @@ pub enum DepositConsequence {

impl DepositConsequence {
/// Convert the type into a `Result` with `TokenError` as the error.
pub fn into_result(self) -> Result<(), TokenError> {
pub fn into_result(self) -> Result<(), DispatchError> {
use DepositConsequence::*;
Err(match self {
BelowMinimum => TokenError::BelowMinimum,
CannotCreate => TokenError::CannotCreate,
UnknownAsset => TokenError::UnknownAsset,
Overflow => TokenError::Overflow,
BelowMinimum => TokenError::BelowMinimum.into(),
CannotCreate => TokenError::CannotCreate.into(),
UnknownAsset => TokenError::UnknownAsset.into(),
Overflow => ArithmeticError::Overflow.into(),
Success => return Ok(()),
})
}
Expand Down

0 comments on commit e2949e9

Please sign in to comment.