Skip to content

Commit

Permalink
Runtime Migration: Move from LockableCurrency to fungible::Hold (#140)
Browse files Browse the repository at this point in the history
* Move sp-core from dev.deps to deps

* Add Lock -> Hold balance migration

* Add runtime upgrade for pallet_parachain_staking

* Add Migration History

* Add few comments

* feat: filter out staking calls
  • Loading branch information
lrazovic committed Jan 3, 2024
1 parent 886c527 commit 300bd20
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 41 deletions.
2 changes: 1 addition & 1 deletion pallets/parachain-staking/Cargo.toml
Expand Up @@ -28,6 +28,7 @@ frame-support.workspace = true
frame-system.workspace = true
sp-runtime.workspace = true
sp-std.workspace = true
sp-core.workspace = true
substrate-fixed.workspace = true
sp-staking.workspace = true
pallet-authorship.workspace = true
Expand All @@ -38,7 +39,6 @@ pallet-balances.workspace = true
pallet-aura.workspace = true
pallet-timestamp.workspace = true
similar-asserts = "1.1.0"
sp-core.workspace = true
sp-io.workspace = true
sp-consensus-aura.workspace = true

Expand Down
42 changes: 3 additions & 39 deletions pallets/parachain-staking/migrations.md
@@ -1,42 +1,6 @@
# Migration History

## Calculate outgoing rewards based on pending revoke and decrease changes
## Move from LockableCurrency to fungible::Hold

- [Migration PR `#1408`](https://github.com/PureStake/moonbeam/pull/1408)

## Patch delegations total mismatch

- [Migration PR `#1291`](https://github.com/PureStake/moonbeam/pull/1291)

## Split candidate state for PoV optimization

- [Migration PR `#1117`](https://github.com/PureStake/moonbeam/pull/1117)

## Increase max delegations per candidate

- [Migration PR `#1096`](https://github.com/PureStake/moonbeam/pull/1096)
- [Migratio bugfix `#1112`](https://github.com/PureStake/moonbeam/pull/1112)

## Manual Exits and Patch Lack of Delay for bond\_{more, less}

- [Migration PR `#810`](https://github.com/PureStake/moonbeam/pull/810)
- [Migration Removal PR `#?`]()

## Purge Stale Storage

- [Migration PR `#970`](https://github.com/PureStake/moonbeam/pull/970)

## Delay nominator exits by changing NominatorState and ExitQueue

- [Migration PR `#610`](https://github.com/PureStake/moonbeam/pull/610)
- [Migration Removal PR `#662`](https://github.com/PureStake/moonbeam/pull/662)

## Patch nomination DOS attack vector by changing CollatorState

- [Migration PR `#505`](https://github.com/PureStake/moonbeam/pull/505)
- [Migration Removal PR `#553`](https://github.com/PureStake/moonbeam/pull/553)

## Patch underflow bug and correct Total storage item

- [Migration PR `#502`](https://github.com/PureStake/moonbeam/pull/502)
- [Migration Removal PR `#553`](https://github.com/PureStake/moonbeam/pull/553)
- [Migration PR `#132`](https://github.com/Polimec/polimec-node/pull/132)
- [Migration Removal PR `#TBD`]()
144 changes: 144 additions & 0 deletions pallets/parachain-staking/src/migrations.rs
Expand Up @@ -15,3 +15,147 @@
// along with Moonbeam. If not, see <http://www.gnu.org/licenses/>.

//! # Migrations
//!
#[allow(unused_imports)]
use crate::*;

// Substrate
use frame_support::traits::{
fungible::{InspectHold, MutateHold},
Currency, Get, LockIdentifier, LockableCurrency, ReservableCurrency,
};
#[allow(unused_imports)]
use frame_support::{dispatch::DispatchError, log, migration, storage::unhashed};
use parity_scale_codec::Encode;
use sp_core::hexdisplay::HexDisplay;
#[allow(unused_imports)]
use sp_std::vec::Vec;

// Lock Identifiers used in the old version of the pallet.
const COLLATOR_LOCK_ID: LockIdentifier = *b"stkngcol";
const DELEGATOR_LOCK_ID: LockIdentifier = *b"stkngdel";

pub struct CustomOnRuntimeUpgrade<T, OldCurrency>
where
T: Config,
OldCurrency: 'static
+ LockableCurrency<<T as frame_system::Config>::AccountId>
+ Currency<<T as frame_system::Config>::AccountId>
+ ReservableCurrency<<T as frame_system::Config>::AccountId>,
{
_phantom: sp_std::marker::PhantomData<(T, OldCurrency)>,
}

impl<T, OldCurrency> frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade<T, OldCurrency>
where
T: Config,
OldCurrency: 'static
+ LockableCurrency<<T as frame_system::Config>::AccountId>
+ Currency<<T as frame_system::Config>::AccountId>
+ ReservableCurrency<<T as frame_system::Config>::AccountId>,
BalanceOf<T>: From<OldCurrency::Balance>,
{
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, DispatchError> {
let active_collators = CandidatePool::<T>::get().0;

for bond_info in active_collators {
let owner = bond_info.owner;
let balance = OldCurrency::free_balance(&owner);
log::info!(
"Collator: {:?} OldCurrency::free_balance pre_upgrade {:?}",
HexDisplay::from(&owner.encode()),
balance
);
}

Ok(Vec::new())
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), DispatchError> {
let active_collators = CandidatePool::<T>::get().0;

for bond_info in active_collators {
let owner = bond_info.owner;
let balance = OldCurrency::free_balance(&owner);
log::info!(
"Collator: {:?} OldCurrency::free_balance post_upgrade {:?}",
HexDisplay::from(&owner.encode()),
balance
);
}

Ok(())
}

fn on_runtime_upgrade() -> frame_support::weights::Weight {
log::info!("Parachain Staking: on_runtime_upgrade");
let mut read_ops = 0u64;
let mut write_ops = 0u64;

// Get all the active collators
let active_collators = CandidatePool::<T>::get().0;
read_ops += 1;

for bond_info in active_collators {
let owner = bond_info.owner;
log::info!("Parachain Staking: migrating collator {:?}", HexDisplay::from(&owner.encode()));

let candidate_info = CandidateInfo::<T>::get(&owner).unwrap();
let bond_amount = candidate_info.bond;
read_ops += 1;
log::info!("Parachain Staking: bond_amount {:?}", bond_amount);

let already_held: <T as Config>::Balance =
T::Currency::balance_on_hold(&HoldReason::StakingCollator.into(), &owner);
read_ops += 1;

// Check if the lock is already held, to make migration idempotent
if already_held == bond_amount {
log::info!("Parachain Staking: already held {:?}", already_held);
} else {
// Remove the lock from the old currency
OldCurrency::remove_lock(COLLATOR_LOCK_ID, &owner);
write_ops += 1;

// Hold the new currency
T::Currency::hold(&HoldReason::StakingCollator.into(), &owner, bond_amount).unwrap_or_else(|err| {
log::error!("Failed to add lock to parachain staking currency: {:?}", err);
});
write_ops += 1;

// Get all the delegations for the collator
if let Some(delegations) = TopDelegations::<T>::get(&owner) {
read_ops += 1;
for delegation in delegations.delegations {
// Process each delegation
log::info!(
"Delegator: {:?}, Amount: {:?}",
HexDisplay::from(&delegation.owner.encode()),
delegation.amount
);

// Remove the lock from the old currency
OldCurrency::remove_lock(DELEGATOR_LOCK_ID, &delegation.owner);
write_ops += 1;

// Hold the new currency
T::Currency::hold(&HoldReason::StakingDelegator.into(), &delegation.owner, delegation.amount)
.unwrap_or_else(|err| {
log::error!("Failed to add lock to parachain staking currency: {:?}", err);
});
write_ops += 1;
}
} else {
// Handle the case where there are no delegations for the account
log::info!("No delegations found for the given account.");
}
}
}

log::info!("Parachain Staking: read_ops {:?} | write_ops: {:?}", read_ops, write_ops);

<T as frame_system::Config>::DbWeight::get().reads_writes(read_ops, write_ops)
}
}
8 changes: 7 additions & 1 deletion runtimes/base/src/lib.rs
Expand Up @@ -128,6 +128,7 @@ pub mod migrations {
cumulus_pallet_xcmp_queue::migration::Migration<Runtime>,
cumulus_pallet_dmp_queue::migration::Migration<Runtime>,
custom_migrations::CustomOnRuntimeUpgrade,
pallet_parachain_staking::migrations::CustomOnRuntimeUpgrade<Runtime, Balances>,
);
}

Expand Down Expand Up @@ -197,13 +198,18 @@ impl Contains<RuntimeCall> for BaseCallFilter {
fn contains(c: &RuntimeCall) -> bool {
use pallet_balances::Call::*;
match c {
// Transferability lock.
RuntimeCall::Balances(inner_call) => match inner_call {
transfer { .. } => false,
transfer_all { .. } => false,
transfer_keep_alive { .. } => false,
transfer_allow_death { .. } => false,
_ => true,
},
// Staking "disabled" @ TGE.
RuntimeCall::ParachainStaking(inner_call) => match inner_call {
_ => false,
},
_ => true,
}
}
Expand Down Expand Up @@ -293,7 +299,7 @@ impl pallet_balances::Config for Runtime {
type Balance = Balance;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type FreezeIdentifier = ();
type FreezeIdentifier = RuntimeFreezeReason;
type MaxFreezes = MaxReserves;
type MaxHolds = MaxLocks;
type MaxLocks = MaxLocks;
Expand Down

0 comments on commit 300bd20

Please sign in to comment.