Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Free standing elections-phragmen and tips Gov V1 unlock/unreserve migrations #14779

Merged
merged 3 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,75 @@
//! A migration that unreserves all deposit and unlocks all stake held in the context of this
//! pallet.

use crate::BalanceOf;
use core::iter::Sum;
use frame_support::traits::{LockableCurrency, OnRuntimeUpgrade, ReservableCurrency};
use frame_support::{
pallet_prelude::ValueQuery,
storage_alias,
traits::{Currency, LockIdentifier, LockableCurrency, OnRuntimeUpgrade, ReservableCurrency},
weights::RuntimeDbWeight,
Parameter, Twox64Concat,
};
use sp_core::Get;
use sp_runtime::traits::Zero;
use sp_std::collections::btree_map::BTreeMap;

#[cfg(feature = "try-runtime")]
use sp_std::vec::Vec;
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

const LOG_TARGET: &str = "elections_phragmen::migrations::unlock_and_unreserve_all_funds";

type BalanceOf<T> =
<<T as UnlockConfig>::Currency as Currency<<T as UnlockConfig>::AccountId>>::Balance;

/// The configuration for [`UnlockAndUnreserveAllFunds`].
pub trait UnlockConfig: 'static {
/// The account ID used in the runtime.
type AccountId: Parameter + Ord;
/// The currency type used in the runtime.
///
/// Should match the currency type previously used for the pallet, if applicable.
type Currency: LockableCurrency<Self::AccountId> + ReservableCurrency<Self::AccountId>;
/// The name of the pallet as previously configured in
/// [`construct_runtime!`](frame_support::construct_runtime).
type PalletName: Get<&'static str>;
/// The maximum number of votes per voter as configured previously in the previous runtime.
type MaxVotesPerVoter: Get<u32>;
/// Identifier for the elections-phragmen pallet's lock, as previously configured in the
/// runtime.
type PalletId: Get<LockIdentifier>;
/// The DB weight as configured in the runtime to calculate the correct weight.
type DbWeight: Get<RuntimeDbWeight>;
/// The block number as configured in the runtime.
type BlockNumber: Parameter + Zero + Copy + Ord;
liamaharon marked this conversation as resolved.
Show resolved Hide resolved
}

#[storage_alias(dynamic)]
type Members<T: UnlockConfig> = StorageValue<
<T as UnlockConfig>::PalletName,
Vec<crate::SeatHolder<<T as UnlockConfig>::AccountId, BalanceOf<T>>>,
ValueQuery,
>;

#[storage_alias(dynamic)]
type RunnersUp<T: UnlockConfig> = StorageValue<
<T as UnlockConfig>::PalletName,
Vec<crate::SeatHolder<<T as UnlockConfig>::AccountId, BalanceOf<T>>>,
ValueQuery,
>;

#[storage_alias(dynamic)]
type Candidates<T: UnlockConfig> = StorageValue<
<T as UnlockConfig>::PalletName,
Vec<(<T as UnlockConfig>::AccountId, BalanceOf<T>)>,
ValueQuery,
>;

#[storage_alias(dynamic)]
type Voting<T: UnlockConfig> = StorageMap<
<T as UnlockConfig>::PalletName,
Twox64Concat,
<T as UnlockConfig>::AccountId,
crate::Voter<<T as UnlockConfig>::AccountId, BalanceOf<T>>,
ValueQuery,
>;

/// A migration that unreserves all deposit and unlocks all stake held in the context of this
/// pallet.
///
Expand All @@ -38,9 +95,9 @@ const LOG_TARGET: &str = "elections_phragmen::migrations::unlock_and_unreserve_a
/// The pallet should be made inoperable before this migration is run.
///
/// (See also [`RemovePallet`][frame_support::migrations::RemovePallet])
pub struct UnlockAndUnreserveAllFunds<T: crate::Config>(sp_std::marker::PhantomData<T>);
pub struct UnlockAndUnreserveAllFunds<T: UnlockConfig>(sp_std::marker::PhantomData<T>);

impl<T: crate::Config> UnlockAndUnreserveAllFunds<T> {
impl<T: UnlockConfig> UnlockAndUnreserveAllFunds<T> {
/// Calculates and returns the total amounts deposited and staked by each account in the context
/// of this pallet.
///
Expand All @@ -66,12 +123,11 @@ impl<T: crate::Config> UnlockAndUnreserveAllFunds<T> {
BTreeMap<T::AccountId, BalanceOf<T>>,
frame_support::weights::Weight,
) {
use crate::Voting;
use sp_runtime::Saturating;

let members = crate::Members::<T>::get();
let runner_ups = crate::RunnersUp::<T>::get();
let candidates = crate::Candidates::<T>::get();
let members = Members::<T>::get();
let runner_ups = RunnersUp::<T>::get();
let candidates = Candidates::<T>::get();

// Get the total amount deposited (Members, RunnerUps, Candidates and Voters all can have
// deposits).
Expand Down Expand Up @@ -115,7 +171,7 @@ impl<T: crate::Config> UnlockAndUnreserveAllFunds<T> {
}
}

impl<T: crate::Config> OnRuntimeUpgrade for UnlockAndUnreserveAllFunds<T>
impl<T: UnlockConfig> OnRuntimeUpgrade for UnlockAndUnreserveAllFunds<T>
where
BalanceOf<T>: Sum,
{
Expand Down Expand Up @@ -268,13 +324,29 @@ where
mod test {
use super::*;
use crate::{
tests::{ExtBuilder, Test},
tests::{Balances, ElectionsPhragmenPalletId, ExtBuilder, PhragmenMaxVoters, Test},
Candidates, Members, RunnersUp, SeatHolder, Voter, Voting,
};
use frame_support::{
assert_ok,
assert_ok, parameter_types,
traits::{Currency, OnRuntimeUpgrade, ReservableCurrency, WithdrawReasons},
};
use frame_system::pallet_prelude::BlockNumberFor;

parameter_types! {
const PalletName: &'static str = "Elections";
}

struct UnlockConfigImpl;
impl super::UnlockConfig for UnlockConfigImpl {
type Currency = Balances;
type AccountId = u64;
type BlockNumber = BlockNumberFor<Test>;
type DbWeight = ();
type PalletName = PalletName;
type MaxVotesPerVoter = PhragmenMaxVoters;
type PalletId = ElectionsPhragmenPalletId;
}

#[test]
fn unreserve_works_for_candidate() {
Expand All @@ -296,10 +368,10 @@ mod test {
);

// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<Test>::pre_upgrade()
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
UnlockAndUnreserveAllFunds::<Test>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<Test>::post_upgrade(bytes));
UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::post_upgrade(bytes));

// Assert the candidate reserved balance was reduced by the expected amount.
assert_eq!(
Expand Down Expand Up @@ -329,10 +401,10 @@ mod test {
);

// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<Test>::pre_upgrade()
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
UnlockAndUnreserveAllFunds::<Test>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<Test>::post_upgrade(bytes));
UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::post_upgrade(bytes));

// Assert the reserved balance was reduced by the expected amount.
assert_eq!(
Expand Down Expand Up @@ -362,10 +434,10 @@ mod test {
);

// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<Test>::pre_upgrade()
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
UnlockAndUnreserveAllFunds::<Test>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<Test>::post_upgrade(bytes));
UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::post_upgrade(bytes));

// Assert the reserved balance was reduced by the expected amount.
assert_eq!(
Expand Down Expand Up @@ -422,10 +494,10 @@ mod test {
);

// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<Test>::pre_upgrade()
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
UnlockAndUnreserveAllFunds::<Test>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<Test>::post_upgrade(bytes));
UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::post_upgrade(bytes));

// Assert the voter lock was removed and the reserved balance was reduced by the
// expected amount.
Expand Down
106 changes: 88 additions & 18 deletions frame/tips/src/migrations/unreserve_deposits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,64 @@
//! pallet.

use core::iter::Sum;
use frame_support::traits::{OnRuntimeUpgrade, ReservableCurrency};
use pallet_treasury::BalanceOf;
use frame_support::{
pallet_prelude::OptionQuery,
storage_alias,
traits::{Currency, LockableCurrency, OnRuntimeUpgrade, ReservableCurrency},
weights::RuntimeDbWeight,
Parameter, Twox64Concat,
};
use sp_runtime::{traits::Zero, Saturating};
use sp_std::collections::btree_map::BTreeMap;

#[cfg(feature = "try-runtime")]
use sp_std::vec::Vec;
const LOG_TARGET: &str = "runtime::tips::migrations::unreserve_deposits";

type BalanceOf<T, I> =
<<T as UnlockConfig<I>>::Currency as Currency<<T as UnlockConfig<I>>::AccountId>>::Balance;

/// The configuration for [`UnreserveDeposits`].
pub trait UnlockConfig<I>: 'static {
/// The hash used in the runtime.
type Hash: Parameter;
/// The account ID used in the runtime.
type AccountId: Parameter + Ord;
/// The currency type used in the runtime.
///
/// Should match the currency type previously used for the pallet, if applicable.
type Currency: LockableCurrency<Self::AccountId> + ReservableCurrency<Self::AccountId>;
/// Base deposit to report a tip.
///
/// Should match the currency type previously used for the pallet, if applicable.
type TipReportDepositBase: sp_core::Get<BalanceOf<Self, I>>;
/// Deposit per byte to report a tip.
///
/// Should match the currency type previously used for the pallet, if applicable.
type DataDepositPerByte: sp_core::Get<BalanceOf<Self, I>>;
/// The name of the pallet as previously configured in
/// [`construct_runtime!`](frame_support::construct_runtime).
type PalletName: sp_core::Get<&'static str>;
/// The DB weight as configured in the runtime to calculate the correct weight.
type DbWeight: sp_core::Get<RuntimeDbWeight>;
/// The block number as configured in the runtime.
type BlockNumber: Parameter + Zero + Copy + Ord;
liamaharon marked this conversation as resolved.
Show resolved Hide resolved
}

/// An open tipping "motion". Retains all details of a tip including information on the finder
/// and the members who have voted.
#[storage_alias(dynamic)]
type Tips<T: UnlockConfig<I>, I: 'static> = StorageMap<
<T as UnlockConfig<I>>::PalletName,
Twox64Concat,
<T as UnlockConfig<I>>::Hash,
crate::OpenTip<
<T as UnlockConfig<I>>::AccountId,
BalanceOf<T, I>,
<T as UnlockConfig<I>>::BlockNumber,
<T as UnlockConfig<I>>::Hash,
>,
OptionQuery,
>;

/// A migration that unreserves all tip deposits.
///
Expand All @@ -34,9 +85,9 @@ use sp_std::vec::Vec;
/// The pallet should be made inoperable before or immediately after this migration is run.
///
/// (See also the `RemovePallet` migration in `frame/support/src/migrations.rs`)
pub struct UnreserveDeposits<T: crate::Config<I>, I: 'static>(sp_std::marker::PhantomData<(T, I)>);
pub struct UnreserveDeposits<T: UnlockConfig<I>, I: 'static>(sp_std::marker::PhantomData<(T, I)>);

impl<T: crate::Config<I>, I: 'static> UnreserveDeposits<T, I> {
impl<T: UnlockConfig<I>, I: 'static> UnreserveDeposits<T, I> {
/// Calculates and returns the total amount reserved by each account by this pallet from open
/// tips.
///
Expand All @@ -46,14 +97,14 @@ impl<T: crate::Config<I>, I: 'static> UnreserveDeposits<T, I> {
/// reserved balance by this pallet
/// * `frame_support::weights::Weight`: The weight of this operation.
fn get_deposits() -> (BTreeMap<T::AccountId, BalanceOf<T, I>>, frame_support::weights::Weight) {
use frame_support::traits::Get;
use sp_core::Get;

let mut tips_len = 0;
let account_deposits: BTreeMap<T::AccountId, BalanceOf<T, I>> = crate::Tips::<T, I>::iter()
let account_deposits: BTreeMap<T::AccountId, BalanceOf<T, I>> = Tips::<T, I>::iter()
.map(|(_hash, open_tip)| open_tip)
.fold(BTreeMap::new(), |mut acc, tip| {
// Count the total number of tips
tips_len.saturating_accrue(1);
tips_len.saturating_inc();

// Add the balance to the account's existing deposit in the accumulator
acc.entry(tip.finder).or_insert(Zero::zero()).saturating_accrue(tip.deposit);
Expand All @@ -64,7 +115,7 @@ impl<T: crate::Config<I>, I: 'static> UnreserveDeposits<T, I> {
}
}

impl<T: crate::Config<I>, I: 'static> OnRuntimeUpgrade for UnreserveDeposits<T, I>
impl<T: UnlockConfig<I>, I: 'static> OnRuntimeUpgrade for UnreserveDeposits<T, I>
where
BalanceOf<T, I>: Sum,
{
Expand All @@ -82,7 +133,7 @@ where
/// Fails with a `TryRuntimeError` if somehow the amount reserved by this pallet is greater than
/// the actual total reserved amount for any accounts.
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
use codec::Encode;
use frame_support::ensure;

Expand All @@ -107,8 +158,8 @@ where
// Print some summary stats
let total_deposits_to_unreserve =
account_deposits.clone().into_values().sum::<BalanceOf<T, I>>();
log::info!("Total accounts: {}", account_deposits.keys().count());
log::info!("Total amount to unreserve: {:?}", total_deposits_to_unreserve);
log::info!(target: LOG_TARGET, "Total accounts: {}", account_deposits.keys().count());
log::info!(target: LOG_TARGET, "Total amount to unreserve: {:?}", total_deposits_to_unreserve);

// Return the actual amount reserved before the upgrade to verify integrity of the upgrade
// in the post_upgrade hook.
Expand Down Expand Up @@ -138,7 +189,7 @@ where
/// Verifies that the account reserved balances were reduced by the actual expected amounts.
#[cfg(feature = "try-runtime")]
fn post_upgrade(
account_reserved_before_bytes: Vec<u8>,
account_reserved_before_bytes: sp_std::vec::Vec<u8>,
) -> Result<(), sp_runtime::TryRuntimeError> {
use codec::Decode;

Expand All @@ -161,6 +212,7 @@ where

if actual_reserved_after != expected_reserved_after {
log::error!(
target: LOG_TARGET,
"Reserved balance for {:?} is incorrect. actual before: {:?}, actual after, {:?}, expected deducted: {:?}",
account,
actual_reserved_before,
Expand All @@ -180,9 +232,27 @@ mod test {
use super::*;
use crate::{
migrations::unreserve_deposits::UnreserveDeposits,
tests::{new_test_ext, RuntimeOrigin, Test, Tips},
tests::{new_test_ext, Balances, RuntimeOrigin, Test, Tips},
};
use frame_support::{assert_ok, traits::TypedGet};
use frame_support::{assert_ok, parameter_types, traits::TypedGet};
use frame_system::pallet_prelude::BlockNumberFor;
use sp_core::ConstU64;

parameter_types! {
const PalletName: &'static str = "Tips";
}

struct UnlockConfigImpl;
impl super::UnlockConfig<()> for UnlockConfigImpl {
type Currency = Balances;
type TipReportDepositBase = ConstU64<1>;
type DataDepositPerByte = ConstU64<1>;
type Hash = sp_core::H256;
type AccountId = u128;
type BlockNumber = BlockNumberFor<Test>;
type DbWeight = ();
type PalletName = PalletName;
}

#[test]
fn unreserve_all_funds_works() {
Expand Down Expand Up @@ -233,12 +303,12 @@ mod test {
);

// Execute the migration
let bytes = match UnreserveDeposits::<Test, ()>::pre_upgrade() {
let bytes = match UnreserveDeposits::<UnlockConfigImpl, ()>::pre_upgrade() {
Ok(bytes) => bytes,
Err(e) => panic!("pre_upgrade failed: {:?}", e),
};
UnreserveDeposits::<Test, ()>::on_runtime_upgrade();
assert_ok!(UnreserveDeposits::<Test, ()>::post_upgrade(bytes));
UnreserveDeposits::<UnlockConfigImpl, ()>::on_runtime_upgrade();
assert_ok!(UnreserveDeposits::<UnlockConfigImpl, ()>::post_upgrade(bytes));

// Check the deposits were were unreserved
assert_eq!(
Expand Down