diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index d3085152eba6c..c4a8456c22c67 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -156,6 +156,7 @@ #[macro_use] mod tests; mod benchmarking; +pub mod migration; mod tests_composite; mod tests_local; #[cfg(test)] @@ -497,6 +498,13 @@ pub mod pallet { #[pallet::whitelist_storage] pub type TotalIssuance, I: 'static = ()> = StorageValue<_, T::Balance, ValueQuery>; + /// The total units of outstanding deactivated balance in the system. + #[pallet::storage] + #[pallet::getter(fn inactive_issuance)] + #[pallet::whitelist_storage] + pub type InactiveIssuance, I: 'static = ()> = + StorageValue<_, T::Balance, ValueQuery>; + /// The Balances pallet example of storing the balance of an account. /// /// # Example @@ -1067,6 +1075,9 @@ impl, I: 'static> fungible::Inspect for Pallet fn total_issuance() -> Self::Balance { TotalIssuance::::get() } + fn active_issuance() -> Self::Balance { + TotalIssuance::::get().saturating_sub(InactiveIssuance::::get()) + } fn minimum_balance() -> Self::Balance { T::ExistentialDeposit::get() } @@ -1145,6 +1156,14 @@ impl, I: 'static> fungible::Transfer for Pallet let er = if keep_alive { KeepAlive } else { AllowDeath }; >::transfer(source, dest, amount, er).map(|_| amount) } + + fn deactivate(amount: Self::Balance) { + InactiveIssuance::::mutate(|b| b.saturating_accrue(amount)); + } + + fn reactivate(amount: Self::Balance) { + InactiveIssuance::::mutate(|b| b.saturating_reduce(amount)); + } } impl, I: 'static> fungible::Unbalanced for Pallet { @@ -1418,7 +1437,19 @@ where } fn total_issuance() -> Self::Balance { - >::get() + TotalIssuance::::get() + } + + fn active_issuance() -> Self::Balance { + >::active_issuance() + } + + fn deactivate(amount: Self::Balance) { + >::deactivate(amount); + } + + fn reactivate(amount: Self::Balance) { + >::reactivate(amount); } fn minimum_balance() -> Self::Balance { diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs new file mode 100644 index 0000000000000..e27efc217407a --- /dev/null +++ b/frame/balances/src/migration.rs @@ -0,0 +1,51 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade, weights::Weight}; + +// NOTE: This must be used alongside the account whose balance is expected to be inactive. +// Generally this will be used for the XCM teleport checking account. +pub struct MigrateToTrackInactive>( + sp_std::marker::PhantomData<(T, A)>, +); +impl> OnRuntimeUpgrade for MigrateToTrackInactive { + fn on_runtime_upgrade() -> Weight { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + + if onchain_version == 0 && current_version == 1 { + let b = Pallet::::total_balance(&A::get()); + Pallet::::deactivate(b); + current_version.put::>(); + log::info!(target: "runtime::balances", "Storage to version {:?}", current_version); + T::DbWeight::get().reads_writes(3, 3) + } else { + log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(2) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + Ok(vec![]) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(total: Vec) -> Result<(), &'static str> { + Ok(()) + } +} diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index d0beb66d34923..48247b6021798 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -59,6 +59,18 @@ pub trait Currency { /// The total amount of issuance in the system. fn total_issuance() -> Self::Balance; + /// The total amount of issuance in the system excluding those which are controlled by the + /// system. + fn active_issuance() -> Self::Balance { + Self::total_issuance() + } + + /// Reduce the active issuance by some amount. + fn deactivate(_: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_: Self::Balance) {} + /// The minimum balance any single account may have. This is equivalent to the `Balances` /// module's `ExistentialDeposit`. fn minimum_balance() -> Self::Balance; @@ -212,6 +224,15 @@ impl, A> Get for TotalIssuanceOf { } } +/// A non-const `Get` implementation parameterised by a `Currency` impl which provides the result +/// of `active_issuance`. +pub struct ActiveIssuanceOf, A>(sp_std::marker::PhantomData<(C, A)>); +impl, A> Get for ActiveIssuanceOf { + fn get() -> C::Balance { + C::active_issuance() + } +} + #[cfg(feature = "std")] impl Currency for () { type Balance = u32; diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 90aadb6d8daa6..7b1ec0f434382 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -40,6 +40,12 @@ pub trait Inspect { /// The total amount of issuance in the system. fn total_issuance() -> Self::Balance; + /// The total amount of issuance in the system excluding those which are controlled by the + /// system. + fn active_issuance() -> Self::Balance { + Self::total_issuance() + } + /// The minimum balance any single account may have. fn minimum_balance() -> Self::Balance; @@ -120,6 +126,12 @@ pub trait Transfer: Inspect { amount: Self::Balance, keep_alive: bool, ) -> Result; + + /// Reduce the active issuance by some amount. + fn deactivate(_: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_: Self::Balance) {} } /// Trait for inspecting a fungible asset which can be reserved. @@ -213,6 +225,9 @@ impl< fn total_issuance() -> Self::Balance { >::total_issuance(A::get()) } + fn active_issuance() -> Self::Balance { + >::active_issuance(A::get()) + } fn minimum_balance() -> Self::Balance { >::minimum_balance(A::get()) } @@ -258,6 +273,12 @@ impl< ) -> Result { >::transfer(A::get(), source, dest, amount, keep_alive) } + fn deactivate(amount: Self::Balance) { + >::deactivate(A::get(), amount) + } + fn reactivate(amount: Self::Balance) { + >::reactivate(A::get(), amount) + } } impl< diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index 8c370e9a0d8b5..0743e3031c467 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -46,6 +46,12 @@ pub trait Inspect { /// The total amount of issuance in the system. fn total_issuance(asset: Self::AssetId) -> Self::Balance; + /// The total amount of issuance in the system excluding those which are controlled by the + /// system. + fn active_issuance(asset: Self::AssetId) -> Self::Balance { + Self::total_issuance(asset) + } + /// The minimum balance any single account may have. fn minimum_balance(asset: Self::AssetId) -> Self::Balance; @@ -177,6 +183,12 @@ pub trait Transfer: Inspect { amount: Self::Balance, keep_alive: bool, ) -> Result; + + /// Reduce the active issuance by some amount. + fn deactivate(_: Self::AssetId, _: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_: Self::AssetId, _: Self::Balance) {} } /// Trait for inspecting a set of named fungible assets which can be placed on hold. diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 21b4d2b769c8b..4aa00c348585c 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -223,6 +223,10 @@ pub mod pallet { OptionQuery, >; + /// The amount which has been reported as inactive to Currency. + #[pallet::storage] + pub type Inactive, I: 'static = ()> = StorageValue<_, BalanceOf, ValueQuery>; + /// Proposal indices that have been approved but not yet awarded. #[pallet::storage] #[pallet::getter(fn approvals)] @@ -316,6 +320,16 @@ pub mod pallet { /// - The weight is overestimated if some approvals got missed. /// # fn on_initialize(n: T::BlockNumber) -> Weight { + let pot = Self::pot(); + let deactivated = Inactive::::get(); + if pot != deactivated { + match (pot > deactivated, pot.max(deactivated) - pot.min(deactivated)) { + (true, delta) => T::Currency::deactivate(delta), + (false, delta) => T::Currency::reactivate(delta), + } + Inactive::::put(&pot); + } + // Check to see if we should spend some funds! if (n % T::SpendPeriod::get()).is_zero() { Self::spend_funds()