feat: Rebrand Polkadot/Substrate references to PezkuwiChain

This commit systematically rebrands various references from Parity Technologies'
Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk.

Key changes include:
- Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks.
- Modified internal documentation and code comments to reflect PezkuwiChain naming and structure.
- Replaced direct references to  with  or specific paths within the  for XCM, Pezkuwi, and other modules.
- Cleaned up deprecated  issue and PR references in various  and  files, particularly in  and  modules.
- Adjusted image and logo URLs in documentation to point to PezkuwiChain assets.
- Removed or rephrased comments related to external Polkadot/Substrate PRs and issues.

This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
@@ -0,0 +1,27 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! All migrations of this pallet.
/// Migration to unreserve all pallet funds.
pub mod unlock_and_unreserve_all_funds;
/// Version 3.
pub mod v3;
/// Version 4.
pub mod v4;
/// Version 5.
pub mod v5;
@@ -0,0 +1,513 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A migration that unreserves all deposit and unlocks all stake held in the context of this
//! pallet.
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use core::iter::Sum;
use pezframe_support::{
pezpallet_prelude::ValueQuery,
storage_alias,
traits::{Currency, LockIdentifier, LockableCurrency, OnRuntimeUpgrade, ReservableCurrency},
weights::RuntimeDbWeight,
Parameter, Twox64Concat,
};
use pezsp_core::Get;
use pezsp_runtime::traits::Zero;
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!`](pezframe_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>;
}
#[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.
///
/// Useful to prevent funds from being locked up when the pallet is being deprecated.
///
/// The pallet should be made inoperable before this migration is run.
///
/// (See also [`RemovePallet`][pezframe_support::migrations::RemovePallet])
pub struct UnlockAndUnreserveAllFunds<T: UnlockConfig>(core::marker::PhantomData<T>);
impl<T: UnlockConfig> UnlockAndUnreserveAllFunds<T> {
/// Calculates and returns the total amounts deposited and staked by each account in the context
/// of this pallet.
///
/// The deposited and staked amounts are returned in two separate `BTreeMap` collections.
///
/// The first `BTreeMap`, `account_deposited_sums`, contains each account's total amount
/// deposited. This includes deposits made by Members, RunnerUps, Candidates, and Voters.
///
/// The second `BTreeMap`, `account_staked_sums`, contains each account's total amount staked.
/// This includes stakes made by Voters.
///
/// # Returns
///
/// This function returns a tuple of two `BTreeMap` collections and the weight of the reads:
///
/// * `BTreeMap<T::AccountId, BalanceOf<T>>`: Map of account IDs to their respective total
/// deposit sums.
/// * `BTreeMap<T::AccountId, BalanceOf<T>>`: Map of account IDs to their respective total
/// staked sums.
/// * `pezframe_support::weights::Weight`: The weight of reading the storage.
fn get_account_deposited_and_staked_sums() -> (
BTreeMap<T::AccountId, BalanceOf<T>>,
BTreeMap<T::AccountId, BalanceOf<T>>,
pezframe_support::weights::Weight,
) {
use pezsp_runtime::Saturating;
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).
let account_deposited_sums: BTreeMap<T::AccountId, BalanceOf<T>> = members
// Massage all data structures into (account_id, deposit) tuples.
.iter()
.chain(runner_ups.iter())
.map(|member| (member.who.clone(), member.deposit))
.chain(candidates.iter().map(|(candidate, amount)| (candidate.clone(), *amount)))
.chain(
Voting::<T>::iter().map(|(account_id, voter)| (account_id.clone(), voter.deposit)),
)
// Finally, aggregate the tuples into a Map.
.fold(BTreeMap::new(), |mut acc, (id, deposit)| {
acc.entry(id.clone()).or_insert(Zero::zero()).saturating_accrue(deposit);
acc
});
// Get the total amount staked (only Voters stake) and count the number of voters.
let mut voters_len = 0;
let account_staked_sums: BTreeMap<T::AccountId, BalanceOf<T>> = Voting::<T>::iter()
.map(|(account_id, voter)| (account_id.clone(), voter.stake))
.fold(BTreeMap::new(), |mut acc, (id, stake)| {
voters_len.saturating_accrue(1);
acc.entry(id.clone()).or_insert(Zero::zero()).saturating_accrue(stake);
acc
});
(
account_deposited_sums,
account_staked_sums,
T::DbWeight::get().reads(
members
.len()
.saturating_add(runner_ups.len())
.saturating_add(candidates.len())
.saturating_add(voters_len.saturating_mul(T::MaxVotesPerVoter::get() as usize))
as u64,
),
)
}
}
impl<T: UnlockConfig> OnRuntimeUpgrade for UnlockAndUnreserveAllFunds<T>
where
BalanceOf<T>: Sum,
{
/// Collects pre-migration data useful for validating the migration was successful, and also
/// checks the integrity of deposited and reserved balances.
///
/// Steps:
/// 1. Gets the deposited and staked balances for each account stored in this pallet.
/// 2. Collects actual pre-migration locked and reserved balances for each account.
/// 3. Checks the integrity of the deposited and reserved balances.
/// 4. Prints summary statistics about the state to be migrated.
/// 5. Encodes and returns pre-migration data to be used in post_upgrade.
///
/// Fails with a `TryRuntimeError` if there's a discrepancy between the amount
/// reported as staked by the pallet and the amount actually locked in `Balances`.
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, pezsp_runtime::TryRuntimeError> {
use alloc::collections::btree_set::BTreeSet;
use codec::Encode;
// Get staked and deposited balances as reported by this pallet.
let (account_deposited_sums, account_staked_sums, _) =
Self::get_account_deposited_and_staked_sums();
let all_accounts: BTreeSet<T::AccountId> = account_staked_sums
.keys()
.chain(account_deposited_sums.keys())
.cloned()
.collect();
let account_reserved_before: BTreeMap<T::AccountId, BalanceOf<T>> = all_accounts
.iter()
.map(|account| (account.clone(), T::Currency::reserved_balance(&account)))
.collect();
// Total deposited for each account *should* be less than or equal to the total reserved,
// however this does not hold for all cases due to bugs in the reserve logic of this pallet.
let bugged_deposits = all_accounts
.iter()
.filter(|account| {
account_deposited_sums.get(&account).unwrap_or(&Zero::zero()) >
account_reserved_before.get(&account).unwrap_or(&Zero::zero())
})
.count();
// Print some summary stats.
let total_stake_to_unlock = account_staked_sums.clone().into_values().sum::<BalanceOf<T>>();
let total_deposits_to_unreserve =
account_deposited_sums.clone().into_values().sum::<BalanceOf<T>>();
log::info!(target: LOG_TARGET, "Total accounts: {:?}", all_accounts.len());
log::info!(target: LOG_TARGET, "Total stake to unlock: {:?}", total_stake_to_unlock);
log::info!(
target: LOG_TARGET,
"Total deposit to unreserve: {:?}",
total_deposits_to_unreserve
);
if bugged_deposits > 0 {
log::warn!(
target: LOG_TARGET,
"Bugged deposits: {}/{}",
bugged_deposits,
all_accounts.len()
);
}
Ok(account_reserved_before.encode())
}
/// Executes the migration.
///
/// Steps:
/// 1. Retrieves the deposit and stake amounts from the pallet.
/// 2. Unreserves the deposited funds for each account.
/// 3. Unlocks the staked funds for each account.
fn on_runtime_upgrade() -> pezframe_support::weights::Weight {
// Get staked and deposited balances as reported by this pallet.
let (account_deposited_sums, account_staked_sums, initial_reads) =
Self::get_account_deposited_and_staked_sums();
// Deposited funds need to be unreserved.
for (account, unreserve_amount) in account_deposited_sums.iter() {
if unreserve_amount.is_zero() {
log::warn!(target: LOG_TARGET, "Unexpected zero amount to unreserve");
continue;
}
T::Currency::unreserve(&account, *unreserve_amount);
}
// Staked funds need to be unlocked.
for (account, amount) in account_staked_sums.iter() {
if amount.is_zero() {
log::warn!(target: LOG_TARGET, "Unexpected zero amount to unlock");
continue;
}
T::Currency::remove_lock(T::PalletId::get(), account);
}
T::DbWeight::get()
.reads_writes(
(account_deposited_sums.len().saturating_add(account_staked_sums.len())) as u64,
(account_deposited_sums.len().saturating_add(account_staked_sums.len())) as u64,
)
.saturating_add(initial_reads)
}
/// Performs post-upgrade sanity checks:
///
/// 1. All expected locks were removed after the migration.
/// 2. The reserved balance for each account has been reduced by the expected amount.
#[cfg(feature = "try-runtime")]
fn post_upgrade(
account_reserved_before_bytes: Vec<u8>,
) -> Result<(), pezsp_runtime::TryRuntimeError> {
use codec::Decode;
use pezsp_runtime::Saturating;
let account_reserved_before =
BTreeMap::<T::AccountId, BalanceOf<T>>::decode(&mut &account_reserved_before_bytes[..])
.map_err(|_| "Failed to decode account_reserved_before_bytes")?;
// Get deposited balances as reported by this pallet.
let (account_deposited_sums, _, _) = Self::get_account_deposited_and_staked_sums();
// Check that the reserved balance is reduced by the expected deposited amount.
for (account, actual_reserved_before) in account_reserved_before {
let actual_reserved_after = T::Currency::reserved_balance(&account);
let expected_amount_deducted = *account_deposited_sums
.get(&account)
.unwrap_or(&Zero::zero())
// .min here to handle bugged deposits where actual_reserved_before is less than the
// amount the pallet reports is reserved
.min(&actual_reserved_before);
let expected_reserved_after =
actual_reserved_before.saturating_sub(expected_amount_deducted);
assert!(
actual_reserved_after == expected_reserved_after,
"Reserved balance for {:?} is incorrect. actual before: {:?}, actual after, {:?}, expected deducted: {:?}",
account,
actual_reserved_before,
actual_reserved_after,
expected_amount_deducted,
);
}
Ok(())
}
}
#[cfg(all(feature = "try-runtime", test))]
mod test {
use super::*;
use crate::{
tests::{Balances, ElectionsPhragmenPalletId, ExtBuilder, PhragmenMaxVoters, Test},
Candidates, Members, RunnersUp, SeatHolder, Voter, Voting,
};
use pezframe_support::{
assert_ok, parameter_types,
traits::{Currency, OnRuntimeUpgrade, ReservableCurrency, WithdrawReasons},
};
parameter_types! {
const PalletName: &'static str = "Elections";
}
struct UnlockConfigImpl;
impl super::UnlockConfig for UnlockConfigImpl {
type Currency = Balances;
type AccountId = u64;
type DbWeight = ();
type PalletName = PalletName;
type MaxVotesPerVoter = PhragmenMaxVoters;
type PalletId = ElectionsPhragmenPalletId;
}
#[test]
fn unreserve_works_for_candidate() {
let candidate = 10;
let deposit = 100;
let initial_reserved = 15;
let initial_balance = 100_000;
ExtBuilder::default().build_and_execute(|| {
// Set up initial state.
<Test as crate::Config>::Currency::make_free_balance_be(&candidate, initial_balance);
assert_ok!(<Test as crate::Config>::Currency::reserve(&candidate, initial_reserved));
Candidates::<Test>::set(vec![(candidate, deposit)]);
assert_ok!(<Test as crate::Config>::Currency::reserve(&candidate, deposit));
// Sanity check: ensure initial Balance state was set up correctly.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&candidate),
deposit + initial_reserved
);
// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
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!(
<Test as crate::Config>::Currency::reserved_balance(&candidate),
initial_reserved
);
});
}
#[test]
fn unreserve_works_for_runner_up() {
let runner_up = 10;
let deposit = 100;
let initial_reserved = 15;
let initial_balance = 100_000;
ExtBuilder::default().build_and_execute(|| {
// Set up initial state.
<Test as crate::Config>::Currency::make_free_balance_be(&runner_up, initial_balance);
assert_ok!(<Test as crate::Config>::Currency::reserve(&runner_up, initial_reserved));
RunnersUp::<Test>::set(vec![SeatHolder { who: runner_up, deposit, stake: 10 }]);
assert_ok!(<Test as crate::Config>::Currency::reserve(&runner_up, deposit));
// Sanity check: ensure initial Balance state was set up correctly.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&runner_up),
deposit + initial_reserved
);
// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::post_upgrade(bytes));
// Assert the reserved balance was reduced by the expected amount.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&runner_up),
initial_reserved
);
});
}
#[test]
fn unreserve_works_for_member() {
let member = 10;
let deposit = 100;
let initial_reserved = 15;
let initial_balance = 100_000;
ExtBuilder::default().build_and_execute(|| {
// Set up initial state.
<Test as crate::Config>::Currency::make_free_balance_be(&member, initial_balance);
assert_ok!(<Test as crate::Config>::Currency::reserve(&member, initial_reserved));
Members::<Test>::set(vec![SeatHolder { who: member, deposit, stake: 10 }]);
assert_ok!(<Test as crate::Config>::Currency::reserve(&member, deposit));
// Sanity check: ensure initial Balance state was set up correctly.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&member),
deposit + initial_reserved
);
// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::on_runtime_upgrade();
assert_ok!(UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::post_upgrade(bytes));
// Assert the reserved balance was reduced by the expected amount.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&member),
initial_reserved
);
});
}
#[test]
fn unlock_and_unreserve_works_for_voter() {
let voter = 10;
let deposit = 100;
let initial_reserved = 15;
let initial_locks = vec![(b"somethin", 10)];
let stake = 25;
let initial_balance = 100_000;
ExtBuilder::default().build_and_execute(|| {
let pezpallet_id = <Test as crate::Config>::PalletId::get();
// Set up initial state.
<Test as crate::Config>::Currency::make_free_balance_be(&voter, initial_balance);
assert_ok!(<Test as crate::Config>::Currency::reserve(&voter, initial_reserved));
for lock in initial_locks.clone() {
<Test as crate::Config>::Currency::set_lock(
*lock.0,
&voter,
lock.1,
WithdrawReasons::all(),
);
}
Voting::<Test>::insert(voter, Voter { votes: vec![], deposit, stake });
assert_ok!(<Test as crate::Config>::Currency::reserve(&voter, deposit));
<Test as crate::Config>::Currency::set_lock(
<Test as crate::Config>::PalletId::get(),
&voter,
stake,
WithdrawReasons::all(),
);
// Sanity check: ensure initial Balance state was set up correctly.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&voter),
deposit + initial_reserved
);
let mut voter_all_locks = initial_locks.clone();
voter_all_locks.push((&pezpallet_id, stake));
assert_eq!(
<Test as crate::Config>::Currency::locks(&voter)
.iter()
.map(|lock| (&lock.id, lock.amount))
.collect::<Vec<_>>(),
voter_all_locks
);
// Run the migration.
let bytes = UnlockAndUnreserveAllFunds::<UnlockConfigImpl>::pre_upgrade()
.unwrap_or_else(|e| panic!("pre_upgrade failed: {:?}", e));
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.
assert_eq!(
<Test as crate::Config>::Currency::reserved_balance(&voter),
initial_reserved
);
assert_eq!(
<Test as crate::Config>::Currency::locks(&voter)
.iter()
.map(|lock| (&lock.id, lock.amount))
.collect::<Vec<_>>(),
initial_locks
);
});
}
}
@@ -0,0 +1,166 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Migrations to version [`3.0.0`], as denoted by the changelog.
use super::super::LOG_TARGET;
use crate::{Config, Pallet};
use alloc::vec::Vec;
use codec::{Decode, Encode, FullCodec};
use pezframe_support::{
pezpallet_prelude::ValueQuery, traits::StorageVersion, weights::Weight, Twox64Concat,
};
use pezsp_runtime::RuntimeDebug;
#[derive(Encode, Decode, Clone, Default, RuntimeDebug, PartialEq)]
struct SeatHolder<AccountId, Balance> {
who: AccountId,
stake: Balance,
deposit: Balance,
}
#[derive(Encode, Decode, Clone, Default, RuntimeDebug, PartialEq)]
struct Voter<AccountId, Balance> {
votes: Vec<AccountId>,
stake: Balance,
deposit: Balance,
}
/// Trait to implement to give information about types used for migration
pub trait V2ToV3 {
/// System config account id
type AccountId: 'static + FullCodec;
/// Elections-phragmen currency balance.
type Balance: 'static + FullCodec + Copy;
}
#[pezframe_support::storage_alias]
type Candidates<V, T: Config> =
StorageValue<Pallet<T>, Vec<(<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance)>, ValueQuery>;
#[pezframe_support::storage_alias]
type Members<V, T: Config> = StorageValue<
Pallet<T>,
Vec<SeatHolder<<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance>>,
ValueQuery,
>;
#[pezframe_support::storage_alias]
type RunnersUp<V, T: Config> = StorageValue<
Pallet<T>,
Vec<SeatHolder<<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance>>,
ValueQuery,
>;
#[pezframe_support::storage_alias]
type Voting<V, T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
<V as V2ToV3>::AccountId,
Voter<<V as V2ToV3>::AccountId, <V as V2ToV3>::Balance>,
>;
/// Apply all of the migrations from 2 to 3.
///
/// ### Warning
///
/// This code will **ONLY** check that the storage version is less than or equal to 2_0_0.
/// Further check might be needed at the user runtime.
///
/// Be aware that this migration is intended to be used only for the mentioned versions. Use
/// with care and run at your own risk.
pub fn apply<V: V2ToV3, T: Config>(
old_voter_bond: V::Balance,
old_candidacy_bond: V::Balance,
) -> Weight {
let storage_version = StorageVersion::get::<Pallet<T>>();
log::info!(
target: LOG_TARGET,
"Running migration for elections-phragmen with storage version {:?}",
storage_version,
);
if storage_version <= 2 {
migrate_voters_to_recorded_deposit::<V, T>(old_voter_bond);
migrate_candidates_to_recorded_deposit::<V, T>(old_candidacy_bond);
migrate_runners_up_to_recorded_deposit::<V, T>(old_candidacy_bond);
migrate_members_to_recorded_deposit::<V, T>(old_candidacy_bond);
StorageVersion::new(3).put::<Pallet<T>>();
Weight::MAX
} else {
log::warn!(
target: LOG_TARGET,
"Attempted to apply migration to V3 but failed because storage version is {:?}",
storage_version,
);
Weight::zero()
}
}
/// Migrate from the old legacy voting bond (fixed) to the new one (per-vote dynamic).
pub fn migrate_voters_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
Voting::<V, T>::translate::<(V::Balance, Vec<V::AccountId>), _>(|_who, (stake, votes)| {
Some(Voter { votes, stake, deposit: old_deposit })
});
log::info!(target: LOG_TARGET, "migrated {} voter accounts.", Voting::<V, T>::iter().count());
}
/// Migrate all candidates to recorded deposit.
pub fn migrate_candidates_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
let _ = Candidates::<V, T>::translate::<Vec<V::AccountId>, _>(|maybe_old_candidates| {
maybe_old_candidates.map(|old_candidates| {
log::info!(target: LOG_TARGET, "migrated {} candidate accounts.", old_candidates.len());
old_candidates.into_iter().map(|c| (c, old_deposit)).collect::<Vec<_>>()
})
});
}
/// Migrate all members to recorded deposit.
pub fn migrate_members_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
let _ = Members::<V, T>::translate::<Vec<(V::AccountId, V::Balance)>, _>(|maybe_old_members| {
maybe_old_members.map(|old_members| {
log::info!(target: LOG_TARGET, "migrated {} member accounts.", old_members.len());
old_members
.into_iter()
.map(|(who, stake)| SeatHolder { who, stake, deposit: old_deposit })
.collect::<Vec<_>>()
})
});
}
/// Migrate all runners-up to recorded deposit.
pub fn migrate_runners_up_to_recorded_deposit<V: V2ToV3, T: Config>(old_deposit: V::Balance) {
let _ = RunnersUp::<V, T>::translate::<Vec<(V::AccountId, V::Balance)>, _>(
|maybe_old_runners_up| {
maybe_old_runners_up.map(|old_runners_up| {
log::info!(
target: LOG_TARGET,
"migrated {} runner-up accounts.",
old_runners_up.len(),
);
old_runners_up
.into_iter()
.map(|(who, stake)| SeatHolder { who, stake, deposit: old_deposit })
.collect::<Vec<_>>()
})
},
);
}
@@ -0,0 +1,107 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Migrations to version [`4.0.0`], as denoted by the changelog.
use super::super::LOG_TARGET;
use pezframe_support::{
traits::{Get, StorageVersion},
weights::Weight,
};
/// The old prefix.
pub const OLD_PREFIX: &[u8] = b"PhragmenElection";
/// Migrate the entire storage of this pallet to a new prefix.
///
/// This new prefix must be the same as the one set in construct_runtime. For safety, use
/// `PalletInfo` to get it, as:
/// `<Runtime as pezframe_system::Config>::PalletInfo::name::<ElectionsPhragmenPallet>`.
///
/// The old storage prefix, `PhragmenElection` is hardcoded in the migration code.
pub fn migrate<T: crate::Config, N: AsRef<str>>(new_pallet_name: N) -> Weight {
if new_pallet_name.as_ref().as_bytes() == OLD_PREFIX {
log::info!(
target: LOG_TARGET,
"New pallet name is equal to the old prefix. No migration needs to be done.",
);
return Weight::zero();
}
let storage_version = StorageVersion::get::<crate::Pallet<T>>();
log::info!(
target: LOG_TARGET,
"Running migration to v4 for elections-phragmen with storage version {:?}",
storage_version,
);
if storage_version <= 3 {
log::info!("new prefix: {}", new_pallet_name.as_ref());
pezframe_support::storage::migration::move_pallet(
OLD_PREFIX,
new_pallet_name.as_ref().as_bytes(),
);
StorageVersion::new(4).put::<crate::Pallet<T>>();
<T as pezframe_system::Config>::BlockWeights::get().max_block
} else {
log::warn!(
target: LOG_TARGET,
"Attempted to apply migration to v4 but failed because storage version is {:?}",
storage_version,
);
Weight::zero()
}
}
/// Some checks prior to migration. This can be linked to
/// `pezframe_support::traits::OnRuntimeUpgrade::pre_upgrade` for further testing.
///
/// Panics if anything goes wrong.
pub fn pre_migration<T: crate::Config, N: AsRef<str>>(new: N) {
let new = new.as_ref();
log::info!("pre-migration elections-phragmen test with new = {}", new);
// the next key must exist, and start with the hash of `OLD_PREFIX`.
let next_key = pezsp_io::storage::next_key(OLD_PREFIX).unwrap();
assert!(next_key.starts_with(&pezsp_io::hashing::twox_128(OLD_PREFIX)));
// ensure nothing is stored in the new prefix.
assert!(
pezsp_io::storage::next_key(new.as_bytes()).map_or(
// either nothing is there
true,
// or we ensure that it has no common prefix with twox_128(new).
|next_key| !next_key.starts_with(&pezsp_io::hashing::twox_128(new.as_bytes()))
),
"unexpected next_key({}) = {:?}",
new,
pezsp_core::hexdisplay::HexDisplay::from(&pezsp_io::storage::next_key(new.as_bytes()).unwrap())
);
// ensure storage version is 3.
assert_eq!(StorageVersion::get::<crate::Pallet<T>>(), 3);
}
/// Some checks for after migration. This can be linked to
/// `pezframe_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing.
///
/// Panics if anything goes wrong.
pub fn post_migration<T: crate::Config>() {
log::info!("post-migration elections-phragmen");
// ensure we've been updated to v4 by the automatic write of crate version -> storage version.
assert_eq!(StorageVersion::get::<crate::Pallet<T>>(), 4);
}
@@ -0,0 +1,88 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::super::*;
use alloc::{boxed::Box, vec::Vec};
/// Migrate the locks and vote stake on accounts (as specified with param `to_migrate`) that have
/// more than their free balance locked.
///
/// This migration addresses a bug were a voter could lock up to their reserved balance + free
/// balance. Since locks are only designed to operate on free balance, this put those affected in a
/// situation where they could increase their free balance but still not be able to use their funds
/// because they were less than the lock.
pub fn migrate<T: Config>(to_migrate: Vec<T::AccountId>) -> Weight {
let mut weight = Weight::zero();
for who in to_migrate.iter() {
if let Ok(mut voter) = Voting::<T>::try_get(who) {
let free_balance = T::Currency::free_balance(who);
weight = weight.saturating_add(T::DbWeight::get().reads(2));
if voter.stake > free_balance {
voter.stake = free_balance;
Voting::<T>::insert(&who, voter);
let pezpallet_id = T::PalletId::get();
T::Currency::set_lock(pezpallet_id, who, free_balance, WithdrawReasons::all());
weight = weight.saturating_add(T::DbWeight::get().writes(2));
}
}
}
weight
}
/// Given the list of voters to migrate return a function that does some checks and information
/// prior to migration. This can be linked to [`pezframe_support::traits::OnRuntimeUpgrade::
/// pre_upgrade`] for further testing.
pub fn pre_migrate_fn<T: Config>(to_migrate: Vec<T::AccountId>) -> Box<dyn Fn() -> ()> {
Box::new(move || {
for who in to_migrate.iter() {
if let Ok(voter) = Voting::<T>::try_get(who) {
let free_balance = T::Currency::free_balance(who);
if voter.stake > free_balance {
// all good
} else {
log::warn!("pre-migrate elections-phragmen: voter={:?} has less stake then free balance", who);
}
} else {
log::warn!("pre-migrate elections-phragmen: cannot find voter={:?}", who);
}
}
log::info!("pre-migrate elections-phragmen complete");
})
}
/// Some checks for after migration. This can be linked to
/// `pezframe_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing.
///
/// Panics if anything goes wrong.
pub fn post_migrate<T: crate::Config>() {
for (who, voter) in Voting::<T>::iter() {
let free_balance = T::Currency::free_balance(&who);
assert!(voter.stake <= free_balance, "migration should have made locked <= free_balance");
// Ideally we would also check that the locks and AccountData.misc_frozen where correctly
// updated, but since both of those are generic we can't do that without further bounding T.
}
log::info!("post-migrate elections-phragmen complete");
}