diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 4532d3d09b497..733ac79d6577c 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -51,6 +51,7 @@ impl system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_template::Config for Test { diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 4eaa0aa00d0b6..335b36fe2f5c4 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -26,7 +26,7 @@ use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, parameter_types, - traits::{KeyOwnerProofSystem, Randomness, StorageInfo}, + traits::{ConstU32, KeyOwnerProofSystem, Randomness, StorageInfo}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, IdentityFee, Weight, @@ -191,6 +191,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; /// The set code logic, just the default since we're not a parachain. type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Runtime {} diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 44d39a870efcc..3134f25cfb265 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -26,8 +26,9 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, - KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + ConstU128, ConstU32, Currency, EnsureOneOf, EqualPrivilegeOnly, Everything, Imbalance, + InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, + U128CurrencyToVote, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -219,6 +220,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = frame_system::weights::SubstrateWeight; type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Runtime {} @@ -1195,6 +1197,7 @@ impl pallet_assets::Config for Runtime { type Currency = Balances; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = ConstU128; type MetadataDepositBase = MetadataDepositBase; type MetadataDepositPerByte = MetadataDepositPerByte; type ApprovalDeposit = ApprovalDeposit; diff --git a/frame/assets/src/extra_mutator.rs b/frame/assets/src/extra_mutator.rs index 8c601b746346c..5ebfc3e547132 100644 --- a/frame/assets/src/extra_mutator.rs +++ b/frame/assets/src/extra_mutator.rs @@ -62,11 +62,11 @@ impl, I: 'static> ExtraMutator { id: T::AssetId, who: impl sp_std::borrow::Borrow, ) -> Option> { - if Account::::contains_key(id, who.borrow()) { + if let Some(a) = Account::::get(id, who.borrow()) { Some(ExtraMutator:: { id, who: who.borrow().clone(), - original: Account::::get(id, who.borrow()).extra, + original: a.extra, pending: None, }) } else { @@ -77,13 +77,8 @@ impl, I: 'static> ExtraMutator { /// Commit any changes to storage. pub fn commit(&mut self) -> Result<(), ()> { if let Some(extra) = self.pending.take() { - Account::::try_mutate_exists(self.id, self.who.borrow(), |maybe_account| { - if let Some(ref mut account) = maybe_account { - account.extra = extra; - Ok(()) - } else { - Err(()) - } + Account::::try_mutate(self.id, self.who.borrow(), |maybe_account| { + maybe_account.as_mut().ok_or(()).map(|account| account.extra = extra) }) } else { Ok(()) @@ -93,13 +88,11 @@ impl, I: 'static> ExtraMutator { /// Revert any changes, even those already committed by `self` and drop self. pub fn revert(mut self) -> Result<(), ()> { self.pending = None; - Account::::try_mutate_exists(self.id, self.who.borrow(), |maybe_account| { - if let Some(ref mut account) = maybe_account { - account.extra = self.original.clone(); - Ok(()) - } else { - Err(()) - } + Account::::try_mutate(self.id, self.who.borrow(), |maybe_account| { + maybe_account + .as_mut() + .ok_or(()) + .map(|account| account.extra = self.original.clone()) }) } } diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index f01954cb970ee..a34900e74bbbd 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -20,6 +20,14 @@ use super::*; use frame_support::{traits::Get, BoundedVec}; +#[must_use] +pub(super) enum DeadConsequence { + Remove, + Keep, +} + +use DeadConsequence::*; + // The main implementation block for the module. impl, I: 'static> Pallet { // Public immutables @@ -32,9 +40,17 @@ impl, I: 'static> Pallet { ExtraMutator::maybe_new(id, who) } - /// Get the asset `id` balance of `who`. + /// Get the asset `id` balance of `who`, or zero if the asset-account doesn't exist. pub fn balance(id: T::AssetId, who: impl sp_std::borrow::Borrow) -> T::Balance { - Account::::get(id, who.borrow()).balance + Self::maybe_balance(id, who).unwrap_or_default() + } + + /// Get the asset `id` balance of `who` if the asset-account exists. + pub fn maybe_balance( + id: T::AssetId, + who: impl sp_std::borrow::Borrow, + ) -> Option { + Account::::get(id, who.borrow()).map(|a| a.balance) } /// Get the total supply of an asset `id`. @@ -45,34 +61,44 @@ impl, I: 'static> Pallet { pub(super) fn new_account( who: &T::AccountId, d: &mut AssetDetails>, - ) -> Result { + maybe_deposit: Option>, + ) -> Result>, DispatchError> { let accounts = d.accounts.checked_add(1).ok_or(ArithmeticError::Overflow)?; - let is_sufficient = if d.is_sufficient { + let reason = if let Some(deposit) = maybe_deposit { + ExistenceReason::DepositHeld(deposit) + } else if d.is_sufficient { frame_system::Pallet::::inc_sufficients(who); d.sufficients += 1; - true + ExistenceReason::Sufficient } else { frame_system::Pallet::::inc_consumers(who).map_err(|_| Error::::NoProvider)?; - false + ExistenceReason::Consumer }; d.accounts = accounts; - Ok(is_sufficient) + Ok(reason) } pub(super) fn dead_account( what: T::AssetId, who: &T::AccountId, d: &mut AssetDetails>, - sufficient: bool, - ) { - if sufficient { - d.sufficients = d.sufficients.saturating_sub(1); - frame_system::Pallet::::dec_sufficients(who); - } else { - frame_system::Pallet::::dec_consumers(who); + reason: &ExistenceReason>, + force: bool, + ) -> DeadConsequence { + let mut result = Remove; + match *reason { + ExistenceReason::Consumer => frame_system::Pallet::::dec_consumers(who), + ExistenceReason::Sufficient => { + d.sufficients = d.sufficients.saturating_sub(1); + frame_system::Pallet::::dec_sufficients(who); + }, + ExistenceReason::DepositRefunded => {}, + ExistenceReason::DepositHeld(_) if !force => return Keep, + ExistenceReason::DepositHeld(_) => result = Keep, } d.accounts = d.accounts.saturating_sub(1); - T::Freezer::died(what, who) + T::Freezer::died(what, who); + result } pub(super) fn can_increase( @@ -87,15 +113,15 @@ impl, I: 'static> Pallet { if details.supply.checked_add(&amount).is_none() { return DepositConsequence::Overflow } - let account = Account::::get(id, who); - if account.balance.checked_add(&amount).is_none() { - return DepositConsequence::Overflow - } - if account.balance.is_zero() { + if let Some(balance) = Self::maybe_balance(id, who) { + if balance.checked_add(&amount).is_none() { + return DepositConsequence::Overflow + } + } else { if amount < details.min_balance { return DepositConsequence::BelowMinimum } - if !details.is_sufficient && frame_system::Pallet::::providers(who) == 0 { + if !details.is_sufficient && !frame_system::Pallet::::can_inc_consumer(who) { return DepositConsequence::CannotCreate } if details.is_sufficient && details.sufficients.checked_add(1).is_none() { @@ -124,7 +150,13 @@ impl, I: 'static> Pallet { if details.is_frozen { return Frozen } - let account = Account::::get(id, who); + if amount.is_zero() { + return Success + } + let account = match Account::::get(id, who) { + Some(a) => a, + None => return NoFunds, + }; if account.is_frozen { return Frozen } @@ -165,7 +197,7 @@ impl, I: 'static> Pallet { let details = Asset::::get(id).ok_or_else(|| Error::::Unknown)?; ensure!(!details.is_frozen, Error::::Frozen); - let account = Account::::get(id, who); + let account = Account::::get(id, who).ok_or(Error::::NoAccount)?; ensure!(!account.is_frozen, Error::::Frozen); let amount = if let Some(frozen) = T::Freezer::frozen_balance(id, who) { @@ -253,6 +285,48 @@ impl, I: 'static> Pallet { Ok((credit, maybe_burn)) } + /// Creates a account for `who` to hold asset `id` with a zero balance and takes a deposit. + pub(super) fn do_touch(id: T::AssetId, who: T::AccountId) -> DispatchResult { + ensure!(!Account::::contains_key(id, &who), Error::::AlreadyExists); + let deposit = T::AssetAccountDeposit::get(); + let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; + let reason = Self::new_account(&who, &mut details, Some(deposit))?; + T::Currency::reserve(&who, deposit)?; + Asset::::insert(&id, details); + Account::::insert( + id, + &who, + AssetAccountOf:: { + balance: Zero::zero(), + is_frozen: false, + reason, + extra: T::Extra::default(), + }, + ); + Ok(()) + } + + /// Returns a deposit, destroying an asset-account. + pub(super) fn do_refund(id: T::AssetId, who: T::AccountId, allow_burn: bool) -> DispatchResult { + let mut account = Account::::get(id, &who).ok_or(Error::::NoDeposit)?; + let deposit = account.reason.take_deposit().ok_or(Error::::NoDeposit)?; + let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; + + ensure!(account.balance.is_zero() || allow_burn, Error::::WouldBurn); + ensure!(!details.is_frozen, Error::::Frozen); + ensure!(!account.is_frozen, Error::::Frozen); + + T::Currency::unreserve(&who, deposit); + + if let Remove = Self::dead_account(id, &who, &mut details, &account.reason, false) { + Account::::remove(id, &who); + } else { + debug_assert!(false, "refund did not result in dead account?!"); + } + Asset::::insert(&id, details); + Ok(()) + } + /// Increases the asset `id` balance of `beneficiary` by `amount`. /// /// This alters the registered supply of the asset and emits an event. @@ -307,13 +381,22 @@ impl, I: 'static> Pallet { check(details)?; - Account::::try_mutate(id, beneficiary, |t| -> DispatchResult { - let new_balance = t.balance.saturating_add(amount); - ensure!(new_balance >= details.min_balance, TokenError::BelowMinimum); - if t.balance.is_zero() { - t.sufficient = Self::new_account(beneficiary, details)?; + Account::::try_mutate(id, beneficiary, |maybe_account| -> DispatchResult { + match maybe_account { + Some(ref mut account) => { + account.balance.saturating_accrue(amount); + }, + maybe_account @ None => { + // Note this should never fail as it's already checked by `can_increase`. + ensure!(amount >= details.min_balance, TokenError::BelowMinimum); + *maybe_account = Some(AssetAccountOf:: { + balance: amount, + reason: Self::new_account(beneficiary, details, None)?, + is_frozen: false, + extra: T::Extra::default(), + }); + }, } - t.balance = new_balance; Ok(()) })?; Ok(()) @@ -375,23 +458,25 @@ impl, I: 'static> Pallet { let actual = Self::prep_debit(id, target, amount, f)?; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { - let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; + let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; check(actual, details)?; - Account::::try_mutate_exists(id, target, |maybe_account| -> DispatchResult { - let mut account = maybe_account.take().unwrap_or_default(); + Account::::try_mutate(id, target, |maybe_account| -> DispatchResult { + let mut account = maybe_account.take().ok_or(Error::::NoAccount)?; debug_assert!(account.balance >= actual, "checked in prep; qed"); // Make the debit. account.balance = account.balance.saturating_sub(actual); - *maybe_account = if account.balance < details.min_balance { + if account.balance < details.min_balance { debug_assert!(account.balance.is_zero(), "checked in prep; qed"); - Self::dead_account(id, target, details, account.sufficient); - None - } else { - Some(account) + if let Remove = + Self::dead_account(id, target, &mut details, &account.reason, false) + { + return Ok(()) + } }; + *maybe_account = Some(account); Ok(()) })?; @@ -432,7 +517,8 @@ impl, I: 'static> Pallet { let debit = Self::prep_debit(id, &source, amount, f.into())?; let (credit, maybe_burn) = Self::prep_credit(id, &dest, amount, debit, f.burn_dust)?; - let mut source_account = Account::::get(id, &source); + let mut source_account = + Account::::get(id, &source).ok_or(Error::::NoAccount)?; Asset::::try_mutate(id, |maybe_details| -> DispatchResult { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; @@ -459,29 +545,40 @@ impl, I: 'static> Pallet { debug_assert!(source_account.balance >= debit, "checked in prep; qed"); source_account.balance = source_account.balance.saturating_sub(debit); - Account::::try_mutate(id, &dest, |a| -> DispatchResult { - // Calculate new balance; this will not saturate since it's already checked in prep. - debug_assert!(a.balance.checked_add(&credit).is_some(), "checked in prep; qed"); - let new_balance = a.balance.saturating_add(credit); - - // Create a new account if there wasn't one already. - if a.balance.is_zero() { - a.sufficient = Self::new_account(&dest, details)?; + Account::::try_mutate(id, &dest, |maybe_account| -> DispatchResult { + match maybe_account { + Some(ref mut account) => { + // Calculate new balance; this will not saturate since it's already checked + // in prep. + debug_assert!( + account.balance.checked_add(&credit).is_some(), + "checked in prep; qed" + ); + account.balance.saturating_accrue(credit); + }, + maybe_account @ None => { + *maybe_account = Some(AssetAccountOf:: { + balance: credit, + is_frozen: false, + reason: Self::new_account(&dest, details, None)?, + extra: T::Extra::default(), + }); + }, } - - a.balance = new_balance; Ok(()) })?; // Remove source account if it's now dead. if source_account.balance < details.min_balance { debug_assert!(source_account.balance.is_zero(), "checked in prep; qed"); - Self::dead_account(id, &source, details, source_account.sufficient); - Account::::remove(id, &source); - } else { - Account::::insert(id, &source, &source_account) + if let Remove = + Self::dead_account(id, &source, details, &source_account.reason, false) + { + Account::::remove(id, &source); + return Ok(()) + } } - + Account::::insert(id, &source, &source_account); Ok(()) })?; @@ -554,7 +651,10 @@ impl, I: 'static> Pallet { ensure!(details.approvals <= witness.approvals, Error::::BadWitness); for (who, v) in Account::::drain_prefix(id) { - Self::dead_account(id, &who, &mut details, v.sufficient); + // We have to force this as it's destroying the entire asset class. + // This could mean that some accounts now have irreversibly reserved + // funds. + let _ = Self::dead_account(id, &who, &mut details, &v.reason, true); } debug_assert_eq!(details.accounts, 0); debug_assert_eq!(details.sufficients, 0); diff --git a/frame/assets/src/impl_stored_map.rs b/frame/assets/src/impl_stored_map.rs index 4c1ff1a0c6027..88e2203f046b6 100644 --- a/frame/assets/src/impl_stored_map.rs +++ b/frame/assets/src/impl_stored_map.rs @@ -22,11 +22,7 @@ use super::*; impl, I: 'static> StoredMap<(T::AssetId, T::AccountId), T::Extra> for Pallet { fn get(id_who: &(T::AssetId, T::AccountId)) -> T::Extra { let &(id, ref who) = id_who; - if Account::::contains_key(id, who) { - Account::::get(id, who).extra - } else { - Default::default() - } + Account::::get(id, who).map(|a| a.extra).unwrap_or_default() } fn try_mutate_exists>( @@ -34,13 +30,13 @@ impl, I: 'static> StoredMap<(T::AssetId, T::AccountId), T::Extra> f f: impl FnOnce(&mut Option) -> Result, ) -> Result { let &(id, ref who) = id_who; - let mut maybe_extra = Some(Account::::get(id, who).extra); + let mut maybe_extra = Account::::get(id, who).map(|a| a.extra); let r = f(&mut maybe_extra)?; // They want to write some value or delete it. // If the account existed and they want to write a value, then we write. // If the account didn't exist and they want to delete it, then we let it pass. // Otherwise, we fail. - Account::::try_mutate_exists(id, who, |maybe_account| { + Account::::try_mutate(id, who, |maybe_account| { if let Some(extra) = maybe_extra { // They want to write a value. Let this happen only if the account actually exists. if let Some(ref mut account) = maybe_account { diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 940120954f968..b86661d9fa4fd 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -212,6 +212,11 @@ pub mod pallet { #[pallet::constant] type AssetDeposit: Get>; + /// The amount of funds that must be reserved for a non-provider asset account to be + /// maintained. + #[pallet::constant] + type AssetAccountDeposit: Get>; + /// The basic amount of funds that must be reserved when adding metadata to your asset. #[pallet::constant] type MetadataDepositBase: Get>; @@ -250,15 +255,15 @@ pub mod pallet { >; #[pallet::storage] - /// The number of units of assets held by any given account. + /// The holdings of a specific account for a specific asset. pub(super) type Account, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::AssetId, Blake2_128Concat, T::AccountId, - AssetBalance, - ValueQuery, + AssetAccountOf, + OptionQuery, GetDefault, ConstU32<300_000>, >; @@ -448,8 +453,8 @@ pub mod pallet { pub enum Error { /// Account balance must be greater than or equal to the transfer amount. BalanceLow, - /// Balance should be non-zero. - BalanceZero, + /// The account to alter does not exist. + NoAccount, /// The signing account has no permission to do the operation. NoPermission, /// The given asset ID is unknown. @@ -471,6 +476,12 @@ pub mod pallet { Unapproved, /// The source account would not survive the transfer and it needs to stay alive. WouldDie, + /// The asset-account already exists. + AlreadyExists, + /// The asset-account doesn't have an associated deposit. + NoDeposit, + /// The operation would result in funds being burned. + WouldBurn, } #[pallet::call] @@ -633,7 +644,7 @@ pub mod pallet { /// /// Origin must be Signed and the sender should be the Manager of the asset `id`. /// - /// Bails with `BalanceZero` if the `who` is already dead. + /// Bails with `NoAccount` if the `who` is already dead. /// /// - `id`: The identifier of the asset to have some amount burned. /// - `who`: The account to be debited from. @@ -779,9 +790,11 @@ pub mod pallet { let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(&origin == &d.freezer, Error::::NoPermission); let who = T::Lookup::lookup(who)?; - ensure!(Account::::contains_key(id, &who), Error::::BalanceZero); - Account::::mutate(id, &who, |a| a.is_frozen = true); + Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { + maybe_account.as_mut().ok_or(Error::::NoAccount)?.is_frozen = true; + Ok(()) + })?; Self::deposit_event(Event::::Frozen { asset_id: id, who }); Ok(()) @@ -808,9 +821,11 @@ pub mod pallet { let details = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(&origin == &details.admin, Error::::NoPermission); let who = T::Lookup::lookup(who)?; - ensure!(Account::::contains_key(id, &who), Error::::BalanceZero); - Account::::mutate(id, &who, |a| a.is_frozen = false); + Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { + maybe_account.as_mut().ok_or(Error::::NoAccount)?.is_frozen = false; + Ok(()) + })?; Self::deposit_event(Event::::Thawed { asset_id: id, who }); Ok(()) @@ -1274,5 +1289,36 @@ pub mod pallet { let destination = T::Lookup::lookup(destination)?; Self::do_transfer_approved(id, &owner, &delegate, &destination, amount) } + + /// Create an asset account for non-provider assets. + /// + /// A deposit will be taken from the signer account. + /// + /// - `origin`: Must be Signed; the signer account must have sufficient funds for a deposit + /// to be taken. + /// - `id`: The identifier of the asset for the account to be created. + /// + /// Emits `Touched` event when successful. + #[pallet::weight(T::WeightInfo::mint())] + pub fn touch(origin: OriginFor, #[pallet::compact] id: T::AssetId) -> DispatchResult { + Self::do_touch(id, ensure_signed(origin)?) + } + + /// Return the deposit (if any) of an asset account. + /// + /// The origin must be Signed. + /// + /// - `id`: The identifier of the asset for the account to be created. + /// - `allow_burn`: If `true` then assets may be destroyed in order to complete the refund. + /// + /// Emits `Refunded` event when successful. + #[pallet::weight(T::WeightInfo::mint())] + pub fn refund( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + allow_burn: bool, + ) -> DispatchResult { + Self::do_refund(id, ensure_signed(origin)?, allow_burn) + } } } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index aedf437ee8439..1e88421dd5acd 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -20,7 +20,10 @@ use super::*; use crate as pallet_assets; -use frame_support::{construct_runtime, parameter_types, traits::GenesisBuild}; +use frame_support::{ + construct_runtime, + traits::{ConstU32, ConstU64, GenesisBuild}, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -42,9 +45,6 @@ construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -59,7 +59,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type BlockHashCount = BlockHashCount; + type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; @@ -69,17 +69,14 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; + type MaxConsumers = ConstU32<2>; } impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); type Event = Event; - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); @@ -87,25 +84,18 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } -parameter_types! { - pub const AssetDeposit: u64 = 1; - pub const ApprovalDeposit: u64 = 1; - pub const StringLimit: u32 = 50; - pub const MetadataDepositBase: u64 = 1; - pub const MetadataDepositPerByte: u64 = 1; -} - impl Config for Test { type Event = Event; type Balance = u64; type AssetId = u32; type Currency = Balances; type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = AssetDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = StringLimit; + type AssetDeposit = ConstU64<1>; + type AssetAccountDeposit = ConstU64<10>; + type MetadataDepositBase = ConstU64<1>; + type MetadataDepositPerByte = ConstU64<1>; + type ApprovalDeposit = ConstU64<1>; + type StringLimit = ConstU32<50>; type Freezer = TestFreezer; type WeightInfo = (); type Extra = (); diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index e24a1d45215da..a3eacdda4452f 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -34,6 +34,97 @@ fn basic_minting_should_work() { }); } +#[test] +fn minting_too_many_insufficient_assets_fails() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + + Balances::make_free_balance_be(&2, 1); + assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + }); +} + +#[test] +fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + + assert_ok!(Assets::touch(Origin::signed(1), 2)); + assert_eq!(Balances::reserved_balance(&1), 10); + + assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + }); +} + +#[test] +fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_eq!(Balances::reserved_balance(&1), 10); + assert_eq!(System::consumers(&1), 0); + }); +} + +#[test] +fn refunding_asset_deposit_with_burn_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Assets::balance(1, 0), 0); + }); +} + +#[test] +fn refunding_asset_deposit_with_burn_disallowed_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_noop!(Assets::refund(Origin::signed(1), 0, false), Error::::WouldBurn); + }); +} + +#[test] +fn refunding_asset_deposit_without_burn_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::touch(Origin::signed(1), 0)); + assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); + assert_eq!(Assets::balance(0, 2), 100); + assert_eq!(Assets::balance(0, 1), 0); + assert_eq!(Balances::reserved_balance(&1), 10); + assert_ok!(Assets::refund(Origin::signed(1), 0, false)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Assets::balance(1, 0), 0); + }); +} + #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { @@ -299,17 +390,17 @@ fn min_balance_should_work() { // When deducting from an account to below minimum, it should be reaped. assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 91)); - assert!(Assets::balance(0, 1).is_zero()); + assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 2, 1, 91)); - assert!(Assets::balance(0, 2).is_zero()); + assert!(Assets::maybe_balance(0, 2).is_none()); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_ok!(Assets::burn(Origin::signed(1), 0, 1, 91)); - assert!(Assets::balance(0, 1).is_zero()); + assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Asset::::get(0).unwrap().accounts, 0); }); } @@ -488,7 +579,7 @@ fn transferring_amount_more_than_available_balance_should_not_work() { assert_eq!(Assets::balance(0, 2), 50); assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::MAX)); assert_eq!(Assets::balance(0, 1), 0); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 1, 50), Error::::BalanceLow); + assert_noop!(Assets::transfer(Origin::signed(1), 0, 1, 50), Error::::NoAccount); assert_noop!(Assets::transfer(Origin::signed(2), 0, 1, 51), Error::::BalanceLow); }); } @@ -536,7 +627,7 @@ fn burning_asset_balance_with_zero_balance_does_nothing() { assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 2), 0); - assert_ok!(Assets::burn(Origin::signed(1), 0, 2, u64::MAX)); + assert_noop!(Assets::burn(Origin::signed(1), 0, 2, u64::MAX), Error::::NoAccount); assert_eq!(Assets::balance(0, 2), 0); assert_eq!(Assets::total_supply(0), 100); }); @@ -688,7 +779,7 @@ fn force_metadata_should_work() { ); // string length limit check - let limit = StringLimit::get() as usize; + let limit = 50usize; assert_noop!( Assets::force_set_metadata( Origin::root(), diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 16f7368f12b74..ecf5f5edf4179 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -26,6 +26,8 @@ use sp_runtime::{traits::Convert, FixedPointNumber, FixedPointOperand, FixedU128 pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; +pub(super) type AssetAccountOf = + AssetAccount<>::Balance, DepositBalanceOf, >::Extra>; #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct AssetDetails { @@ -76,14 +78,47 @@ pub struct Approval { pub(super) deposit: DepositBalance, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, MaxEncodedLen, TypeInfo)] -pub struct AssetBalance { +#[test] +fn ensure_bool_decodes_to_consumer_or_sufficient() { + assert_eq!(false.encode(), ExistenceReason::<()>::Consumer.encode()); + assert_eq!(true.encode(), ExistenceReason::<()>::Sufficient.encode()); +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub enum ExistenceReason { + #[codec(index = 0)] + Consumer, + #[codec(index = 1)] + Sufficient, + #[codec(index = 2)] + DepositHeld(Balance), + #[codec(index = 3)] + DepositRefunded, +} + +impl ExistenceReason { + pub(crate) fn take_deposit(&mut self) -> Option { + if !matches!(self, ExistenceReason::DepositHeld(_)) { + return None + } + if let ExistenceReason::DepositHeld(deposit) = + sp_std::mem::replace(self, ExistenceReason::DepositRefunded) + { + return Some(deposit) + } else { + return None + } + } +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct AssetAccount { /// The balance. pub(super) balance: Balance, /// Whether the account is frozen. pub(super) is_frozen: bool, - /// `true` if this balance gave the account a self-sufficient reference. - pub(super) sufficient: bool, + /// The reason for the existence of the account. + pub(super) reason: ExistenceReason, /// Additional "sidecar" data, in case some other pallet wants to use this storage item. pub(super) extra: Extra, } @@ -124,12 +159,15 @@ pub struct DestroyWitness { pub trait FrozenBalance { /// Return the frozen balance. /// + /// Generally, the balance of every account must be at least the sum of this (if `Some`) and + /// the asset's `minimum_balance` (the latter since there may be complications to destroying an + /// asset's account completely). + /// /// Under normal behaviour, the account balance should not go below the sum of this (if `Some`) - /// and the asset's minimum balance. - /// But the account balance can be below this sum (e.g. if less than the sum has been - /// transfered to the account). + /// and the asset's minimum balance. However, the account balance may reasonably begin below + /// this sum (e.g. if less than the sum had ever been transfered into the account). /// - /// In special case (privileged intervention) the account balance can go below the sum. + /// In special cases (privileged intervention) the account balance may also go below the sum. /// /// If `None` is returned, then nothing special is enforced. fn frozen_balance(asset: AssetId, who: &AccountId) -> Option; diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index a76d0f20ffa3b..47e33252e0943 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -54,6 +54,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 4418d9e85ae24..12748bd212d37 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -78,6 +78,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Test { diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index a6609860d7cf1..c867f98af3e17 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -260,6 +260,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } pub struct TestSessionHandler; diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 5d36adabe888f..cd91957475a1e 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -458,6 +458,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index f62e73aa43917..f3325d0c65a08 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -96,6 +96,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 6545e563a3efe..90d5347b1242f 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -68,6 +68,7 @@ impl frame_system::Config for Runtime { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 60feedb326d8a..b1a7f2417df84 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -73,6 +73,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const TransactionByteFee: u64 = 1; diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index a861df4746a11..ff08e63562011 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const TransactionByteFee: u64 = 1; diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 43edd16baf3b3..01b02943484bf 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -77,6 +77,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const TransactionByteFee: u64 = 1; diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 95b87c360510a..f1195dcc9c028 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -86,6 +86,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index a1fbeda4ab35c..3ce582b29d22d 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -84,6 +84,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_beefy::Config for Test { diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 87cdf80409b89..e2f9f1f2975fd 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -195,6 +195,7 @@ pub mod mock { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl super::Config for Test {} diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index a2cf381e6ecf8..e27b3e09dbedb 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -108,6 +108,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 0ad156ce5a88d..09d11eb6c58d2 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -110,6 +110,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index bbcf9d6d9e72d..ac1f104119dfe 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -84,6 +84,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index ada13e968c4d4..8e2569738b1f2 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -86,6 +86,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index cbd2f68ac73e8..466cdb3eeeb5b 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -115,6 +115,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Test { type Origin = Origin; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f19f5a3159557..1554d1230089e 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -206,6 +206,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Test {} impl pallet_balances::Config for Test { diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 06c4ac666cfba..3c223172987e8 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -105,6 +105,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index f90c64b75ccb0..3ac14b89e7953 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -218,6 +218,7 @@ impl frame_system::Config for Runtime { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 6379adae4206b..a2eb53edcf84c 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -145,6 +145,7 @@ mod tests { type OnKilledAccount = (); type SystemWeightInfo = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Runtime { diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 116c0937bf983..8daa4e7fe13c1 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1150,6 +1150,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index 91318e1e07bcc..bce60534a3522 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -60,6 +60,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index e069cccf8d800..b97083f27d5ee 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -79,6 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 1dde8a1df60c8..9fb965784f186 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -77,6 +77,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } type Extrinsic = TestXt; diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 4c36f0d6eb858..5de9af878723a 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -68,6 +68,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 9b81527fadb35..7ff5584879cea 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -767,6 +767,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } type Balance = u64; diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index ac3f4df1b71dd..9ea33a6d6b68d 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -74,6 +74,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index fe7a530ffe0c8..aed13ec3717a9 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -98,6 +98,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 31b93e70fd3dc..2faf65f560a88 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 1e4d4b43d5789..1d985b9007ea9 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -139,6 +139,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index f4c87016141b5..3e3aed2986b9f 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -69,6 +69,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index d1f090aa26dcb..df86e063c477f 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -79,6 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 6cd8c13f39aff..4bcc28c0ef46a 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -560,6 +560,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } ord_parameter_types! { pub const One: u64 = 1; diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 3616a8d1d5242..392ae5050a96c 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -69,6 +69,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Test { diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 523aefd1e753c..f050ac9d72001 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -74,6 +74,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index bfc23187fc5b5..ea58ea693d3fb 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -297,6 +297,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index 6c79f601c197d..8e2bc7cfd2a6d 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -71,6 +71,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } ord_parameter_types! { diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 26a53c7f8a048..ab2b3569228c6 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -63,6 +63,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: Balance = 10; diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index bce51f527abc6..c2db42ec72fac 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -112,6 +112,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl Config for Runtime { diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index d3565525910fb..538527d47ecd0 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -78,6 +78,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 345b8072c5e47..eee70984f2576 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -219,6 +219,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_randomness_collective_flip::Config for Test {} diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index f6d4a6b159431..1bd7507436b7a 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 260ef90b05372..02bcb5eb3109f 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -932,6 +932,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl logger::Config for Test { type Event = Event; diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 5c5425ae2bdd8..992aecba38e82 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -81,6 +81,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index e000255b84b87..3f3b103905b58 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -68,6 +68,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: Balance = 10; diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 6db7727fa5391..d0511d3936822 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -264,6 +264,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Test { diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 9356c083f2331..4348f2378c425 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -89,6 +89,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 8a8ab1f1e4d04..89ab86259b95f 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -150,6 +150,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_balances::Config for Test { type MaxLocks = MaxLocks; diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index bfbed0d38ab34..88379d0e5fda8 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -144,6 +144,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } // Implement the logger module's `Config` on the Test runtime. diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 9b5453c0a01ae..3c1f268ade073 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -50,9 +50,10 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter mod misc; pub use misc::{ - Backing, ConstU32, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, - ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, - OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, + Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, + ConstU32, ConstU64, ConstU8, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, + ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, + Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 153c3804bd599..165a83b4be2a0 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -60,20 +60,33 @@ impl Get for GetDefault { } } -/// Implement `Get` and `Get>` using the given const. -pub struct ConstU32; - -impl Get for ConstU32 { - fn get() -> u32 { - T - } -} - -impl Get> for ConstU32 { - fn get() -> Option { - Some(T) - } -} +macro_rules! impl_const_get { + ($name:ident, $t:ty) => { + pub struct $name; + impl Get<$t> for $name { + fn get() -> $t { + T + } + } + impl Get> for $name { + fn get() -> Option<$t> { + Some(T) + } + } + }; +} + +impl_const_get!(ConstBool, bool); +impl_const_get!(ConstU8, u8); +impl_const_get!(ConstU16, u16); +impl_const_get!(ConstU32, u32); +impl_const_get!(ConstU64, u64); +impl_const_get!(ConstU128, u128); +impl_const_get!(ConstI8, i8); +impl_const_get!(ConstI16, i16); +impl_const_get!(ConstI32, i32); +impl_const_get!(ConstI64, i64); +impl_const_get!(ConstI128, i128); /// A type for which some values make sense to be able to drop without further consideration. pub trait TryDrop: Sized { diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index 62472a8957ce3..aa53f7ad358dd 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -17,14 +17,17 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"] sp-core = { version = "4.0.0", default-features = false, path = "../../../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" } sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" } -support = { package = "frame-support", version = "4.0.0-dev", default-features = false, path = "../../" } -system = { package = "frame-system", version = "4.0.0-dev", default-features = false, path = "../../../system" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../system" } [features] default = ["std"] std = [ "codec/std", "scale-info/std", - "support/std", - "system/std", + "sp-core/std", + "sp-runtime/std", + "sp-version/std", + "frame-support/std", + "frame-system/std", ] diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 17ba40574adf7..06fb6345d3c8d 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -22,13 +22,13 @@ //! This crate tests that `construct_runtime!` expands the pallet parts //! correctly even when frame-support is renamed in Cargo.toml +use frame_support::{construct_runtime, parameter_types}; use sp_core::{sr25519, H256}; use sp_runtime::{ create_runtime_str, generic, traits::{BlakeTwo256, IdentityLookup, Verify}, }; use sp_version::RuntimeVersion; -use support::{construct_runtime, parameter_types}; pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("frame-support-test-compile-pass"), @@ -51,8 +51,8 @@ parameter_types! { pub const SS58Prefix: u8 = 0; } -impl system::Config for Runtime { - type BaseCallFilter = support::traits::Everything; +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); type Index = u128; @@ -73,6 +73,7 @@ impl system::Config for Runtime { type OnNewAccount = (); type OnKilledAccount = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; } @@ -87,6 +88,6 @@ construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system, + System: frame_system, } ); diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 509e3217ddf96..e9c6fe8be5601 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -566,6 +566,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 4523063252ab9..0cd6a6e59cffc 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -246,6 +246,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 768b9f28d35f3..16f5e16cb873e 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -226,6 +226,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index de70b0e7e404e..9fd748eb332c3 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -274,6 +274,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet::Config for Runtime { type Event = Event; diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 1c47d13a619f2..170e515740b3c 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -152,6 +152,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_test::Trait for Runtime { diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index c8a9d4eadfea0..0d513ff599d53 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -92,6 +92,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl module::Config for Runtime { diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index d828fb22ff5ff..ff00b76c45fdf 100644 --- a/frame/system/benchmarking/src/mock.rs +++ b/frame/system/benchmarking/src/mock.rs @@ -62,6 +62,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl crate::Config for Test {} diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 7825c9ec07802..8823aa37c19c5 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -309,6 +309,10 @@ pub mod pallet { /// It's unlikely that this needs to be customized, unless you are writing a parachain using /// `Cumulus`, where the actual code change is deferred. type OnSetCode: SetCode; + + /// The maximum number of consumers allowed on a single account. + #[pallet::constant] + type MaxConsumers: Get; } #[pallet::pallet] @@ -1107,8 +1111,12 @@ impl Pallet { pub fn inc_consumers(who: &T::AccountId) -> Result<(), DispatchError> { Account::::try_mutate(who, |a| { if a.providers > 0 { - a.consumers = a.consumers.saturating_add(1); - Ok(()) + if a.consumers < T::MaxConsumers::get() { + a.consumers = a.consumers.saturating_add(1); + Ok(()) + } else { + Err(DispatchError::TooManyConsumers) + } } else { Err(DispatchError::NoProviders) } @@ -1148,7 +1156,8 @@ impl Pallet { /// True if the account has at least one provider reference. pub fn can_inc_consumer(who: &T::AccountId) -> bool { - Account::::get(who).providers > 0 + let a = Account::::get(who); + a.providers > 0 && a.consumers < T::MaxConsumers::get() } /// Deposits an event into this block's event record. diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 9dd35691cab84..de89324ec9fb4 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -111,6 +111,7 @@ impl Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } pub type SysEvent = frame_system::Event; diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index eeb840715f817..ae9a3b5f69ad9 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -372,6 +372,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const MinimumPeriod: u64 = 5; diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index 2aac22ffe18ca..7d6a717347310 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -83,6 +83,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index bd5dc57239a28..106b361aff8f3 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -112,6 +112,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { @@ -169,6 +170,7 @@ impl pallet_assets::Config for Runtime { type Currency = Balances; type ForceOrigin = EnsureRoot; type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = frame_support::traits::ConstU64<2>; type MetadataDepositBase = MetadataDeposit; type MetadataDepositPerByte = MetadataDeposit; type ApprovalDeposit = MetadataDeposit; diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 02ba9621c175d..a5bcc6d12dec8 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -865,6 +865,7 @@ mod tests { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 38d14129d76e2..49b81348e7d4f 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -77,6 +77,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 534661b2773bb..c2b41e7165234 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -79,6 +79,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 658e82a5143e2..f65f69209b9ed 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -69,6 +69,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 32582fae82116..169ac6cfff897 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -127,6 +127,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index cb8961150003b..1e04875a7e077 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -64,6 +64,7 @@ impl frame_system::Config for Test { type OnKilledAccount = (); type OnNewAccount = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; type Origin = Origin; type PalletInfo = PalletInfo; type SS58Prefix = (); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 8cd15b51a32c3..10fd39d38f4cc 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -494,6 +494,8 @@ pub enum DispatchError { ConsumerRemaining, /// There are no providers so the account cannot be created. NoProviders, + /// There are too many consumers so the account cannot be created. + TooManyConsumers, /// An error to do with tokens. Token(TokenError), /// An arithmetic error. @@ -629,6 +631,7 @@ impl From for &'static str { DispatchError::Module { message, .. } => message.unwrap_or("Unknown module error"), DispatchError::ConsumerRemaining => "Consumer remaining", DispatchError::NoProviders => "No providers", + DispatchError::TooManyConsumers => "Too many consumers", DispatchError::Token(e) => e.into(), DispatchError::Arithmetic(e) => e.into(), } @@ -660,6 +663,7 @@ impl traits::Printable for DispatchError { }, Self::ConsumerRemaining => "Consumer remaining".print(), Self::NoProviders => "No providers".print(), + Self::TooManyConsumers => "Too many consumers".print(), Self::Token(e) => { "Token error: ".print(); <&'static str>::from(*e).print(); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 08863de510d09..7b78880c2c3bf 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -591,6 +591,7 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_timestamp::Config for Runtime {