Skip to content

Commit

Permalink
Migrate vesting (#1637)
Browse files Browse the repository at this point in the history
* Migrate vesting

* Fix clippy

---------

Co-authored-by: Edwin <[email protected]>
  • Loading branch information
hqwangningbo and ark930 authored Jan 27, 2025
1 parent 53d464d commit d3d5881
Show file tree
Hide file tree
Showing 11 changed files with 549 additions and 291 deletions.
593 changes: 306 additions & 287 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ pallet-identity = { git = "https://github.com/parityt
pallet-indices = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
pallet-migrations = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
pallet-multisig = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
pallet-preimage = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
pallet-proxy = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2407", default-features = false }
Expand Down
105 changes: 105 additions & 0 deletions pallets/vesting/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,108 @@ pub(crate) mod v1 {
Ok(())
}
}

pub mod v2 {
use super::*;
use frame_support::migrations::{MigrationId, SteppedMigration, SteppedMigrationError};
use frame_support::weights::WeightMeter;
use sp_runtime::{Percent, SaturatedConversion};

const LOG_TARGET: &str = "bifrost-vesting";
const PALLET_MIGRATIONS_ID: &[u8; 18] = b"pallet-vesting-mbm";

pub struct LazyMigration<T, W: WeightInfo>(core::marker::PhantomData<(T, W)>);

impl<T: crate::Config, W: weights::WeightInfo> SteppedMigration for LazyMigration<T, W> {
type Cursor = <T as frame_system::Config>::AccountId;
// Without the explicit length here the construction of the ID would not be infallible.
type Identifier = MigrationId<18>;

/// The identifier of this migration. Which should be globally unique.
fn id() -> Self::Identifier {
MigrationId {
pallet_id: *PALLET_MIGRATIONS_ID,
version_from: 1,
version_to: 2,
}
}

fn step(
mut cursor: Option<Self::Cursor>,
meter: &mut WeightMeter,
) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
let required = W::step(T::MAX_VESTING_SCHEDULES);
// If there is not enough weight for a single step, return an error. This case can be
// problematic if it is the first migration that ran in this block. But there is nothing
// that we can do about it here.
if meter.remaining().any_lt(required) {
return Err(SteppedMigrationError::InsufficientWeight { required });
}

let mut count = 0u32;
let para_block_number = frame_system::Pallet::<T>::block_number();
let current_block_number = T::BlockNumberProvider::current_block_number();

// We loop here to do as much progress as possible per step.
loop {
// stop when remaining weight is lower than step max weight
if meter.remaining().any_lt(required) {
break;
}

let mut iter = if let Some(last_key) = cursor {
// If a cursor is provided, start iterating from the stored value
// corresponding to the last key processed in the previous step.
// Note that this only works if the old and the new map use the same way to hash
// storage keys.
Vesting::<T>::iter_from(Vesting::<T>::hashed_key_for(last_key))
} else {
// If no cursor is provided, start iterating from the beginning.
Vesting::<T>::iter()
};

// If there's a next item in the iterator, perform the migration.
if let Some((ref last_key, mut schedules)) = iter.next() {
for schedule in schedules.iter_mut() {
// remaining locked balance
let start_block = schedule.starting_block();
let locked = schedule.locked_at::<T::BlockNumberToBalance>(
para_block_number,
Some(start_block),
);
log::debug!(target: LOG_TARGET, "account: {:?}, start block: {:?}, remaining locked balance: {:?}", last_key, start_block, locked);
// reduce unlock `per_block` into half
let per_block = Percent::from_percent(50) * schedule.per_block();
// remaining blocks to start vesting if vesting hasn't started yet
// remaining blocks will be doubled
let remaining_blocks = schedule
.starting_block()
.saturating_sub(para_block_number)
.saturating_mul(2u32.into());
let start_block = current_block_number.saturating_add(remaining_blocks);

*schedule = VestingInfo::new(locked, per_block, start_block);
}

// consume the exact weight
meter.consume(W::step(schedules.len().saturated_into()));

// Override vesting schedules
Vesting::<T>::insert(last_key, schedules);

// inc counter
count.saturating_inc();

// Return the processed key as the new cursor.
cursor = Some(last_key.clone())
} else {
// Signal that the migration is complete (no more items to process).
cursor = None;
break;
}
}
log::debug!(target: LOG_TARGET, "migrated {count:?} entries");
Ok(cursor)
}
}
}
15 changes: 15 additions & 0 deletions pallets/vesting/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub trait WeightInfo {
fn force_vested_transfer(l: u32, s: u32, ) -> Weight;
fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight;
fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight;
fn step(x: u32, ) -> Weight;
}

// For backwards compatibility and tests
Expand Down Expand Up @@ -257,4 +258,18 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(4_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: `Vesting::Vesting` (r:2 w:1)
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
/// The range of component `x` is `[1, 28]`.
fn step(x: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `316 + x * (36 ±0)`
// Estimated: `8054`
// Minimum execution time: 13_079_000 picoseconds.
Weight::from_parts(13_513_131, 8054)
// Standard Error: 723
.saturating_add(Weight::from_parts(102_389, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
3 changes: 3 additions & 0 deletions runtime/bifrost-kusama/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pallet-identity = { workspace = true }
pallet-indices = { workspace = true }
pallet-membership = { workspace = true }
pallet-message-queue = { workspace = true }
pallet-migrations = { workspace = true }
pallet-multisig = { workspace = true }
pallet-preimage = { workspace = true }
pallet-proxy = { workspace = true }
Expand Down Expand Up @@ -175,6 +176,7 @@ std = [
"pallet-identity/std",
"pallet-indices/std",
"pallet-membership/std",
"pallet-migrations/std",
"pallet-multisig/std",
"pallet-preimage/std",
"pallet-proxy/std",
Expand Down Expand Up @@ -342,6 +344,7 @@ try-runtime = [
"pallet-collective/try-runtime",
"pallet-conviction-voting/try-runtime",
"pallet-membership/try-runtime",
"pallet-migrations/try-runtime",
"cumulus-pallet-xcmp-queue/try-runtime",
"pallet-xcm/try-runtime",
"cumulus-pallet-xcm/try-runtime",
Expand Down
39 changes: 37 additions & 2 deletions runtime/bifrost-kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ use bifrost_slp::QueryId;
use constants::currency::*;
use cumulus_pallet_parachain_system::{RelayNumberMonotonicallyIncreases, RelaychainDataProvider};
use cumulus_primitives_core::AggregateMessageOrigin;
use frame_support::migrations::{FailedMigrationHandler, FailedMigrationHandling};
use frame_support::{
dispatch::DispatchClass,
genesis_builder_helper::{build_state, get_preset},
Expand Down Expand Up @@ -357,7 +358,7 @@ impl frame_system::Config for Runtime {
type MaxConsumers = ConstU32<16>;
type RuntimeTask = ();
type SingleBlockMigrations = ();
type MultiBlockMigrator = ();
type MultiBlockMigrator = MultiBlockMigrations;
type PreInherents = ();
type PostInherents = ();
type PostTransactions = ();
Expand Down Expand Up @@ -926,7 +927,7 @@ impl bifrost_vesting::Config for Runtime {
type WeightInfo = weights::bifrost_vesting::BifrostWeight<Runtime>;
type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons;
const MAX_VESTING_SCHEDULES: u32 = 28;
type BlockNumberProvider = System;
type BlockNumberProvider = RelaychainDataProvider<Runtime>;
}

// Bifrost modules start
Expand Down Expand Up @@ -1690,6 +1691,39 @@ where

// zenlink runtime end

parameter_types! {
pub MbmServiceWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block;
}

/// Unfreeze chain on failed migration and continue with extrinsic execution.
/// Migration must be tested and make sure it doesn't fail. If it happens, we don't have other
/// choices but unfreeze chain and continue with extrinsic execution.
pub struct UnfreezeChainOnFailedMigration;
impl FailedMigrationHandler for UnfreezeChainOnFailedMigration {
fn failed(migration: Option<u32>) -> FailedMigrationHandling {
log::error!(target: "mbm", "Migration failed at cursor: {migration:?}");
FailedMigrationHandling::ForceUnstuck
}
}

impl pallet_migrations::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
#[cfg(not(feature = "runtime-benchmarks"))]
type Migrations = bifrost_vesting::migrations::v2::LazyMigration<
Runtime,
weights::bifrost_vesting::BifrostWeight<Runtime>,
>;
// Benchmarks need mocked migrations to guarantee that they succeed.
#[cfg(feature = "runtime-benchmarks")]
type Migrations = pallet_migrations::mock_helpers::MockedMigrations;
type CursorMaxLen = ConstU32<65_536>;
type IdentifierMaxLen = ConstU32<256>;
type MigrationStatusHandler = ();
type FailedMigrationHandler = UnfreezeChainOnFailedMigration;
type MaxServiceWeight = MbmServiceWeight;
type WeightInfo = pallet_migrations::weights::SubstrateWeight<Runtime>;
}

construct_runtime! {
pub enum Runtime {
// Basic stuff
Expand All @@ -1699,6 +1733,7 @@ construct_runtime! {
ParachainSystem: cumulus_pallet_parachain_system = 5,
ParachainInfo: parachain_info = 6,
TxPause: pallet_tx_pause = 7,
MultiBlockMigrations: pallet_migrations = 8,

// Monetary stuff
Balances: pallet_balances = 10,
Expand Down
14 changes: 14 additions & 0 deletions runtime/bifrost-kusama/src/weights/bifrost_vesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,18 @@ impl<T: frame_system::Config> bifrost_vesting::WeightInfo for BifrostWeight<T> {
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: `Vesting::Vesting` (r:2 w:1)
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
/// The range of component `x` is `[1, 28]`.
fn step(x: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `316 + x * (36 ±0)`
// Estimated: `8054`
// Minimum execution time: 13_079_000 picoseconds.
Weight::from_parts(13_513_131, 8054)
// Standard Error: 723
.saturating_add(Weight::from_parts(102_389, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
14 changes: 14 additions & 0 deletions runtime/bifrost-paseo/src/weights/bifrost_vesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,18 @@ impl<T: frame_system::Config> bifrost_vesting::WeightInfo for BifrostWeight<T> {
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: `Vesting::Vesting` (r:2 w:1)
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
/// The range of component `x` is `[1, 28]`.
fn step(x: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `316 + x * (36 ±0)`
// Estimated: `8054`
// Minimum execution time: 13_079_000 picoseconds.
Weight::from_parts(13_513_131, 8054)
// Standard Error: 723
.saturating_add(Weight::from_parts(102_389, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
3 changes: 3 additions & 0 deletions runtime/bifrost-polkadot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pallet-identity = { workspace = true }
pallet-indices = { workspace = true }
pallet-membership = { workspace = true }
pallet-message-queue = { workspace = true }
pallet-migrations = { workspace = true }
pallet-multisig = { workspace = true }
pallet-preimage = { workspace = true }
pallet-proxy = { workspace = true }
Expand Down Expand Up @@ -208,6 +209,7 @@ std = [
"pallet-identity/std",
"pallet-indices/std",
"pallet-membership/std",
"pallet-migrations/std",
"pallet-multisig/std",
"pallet-preimage/std",
"pallet-proxy/std",
Expand Down Expand Up @@ -427,6 +429,7 @@ try-runtime = [
"pallet-identity/try-runtime",
"pallet-indices/try-runtime",
"pallet-membership/try-runtime",
"pallet-migrations/try-runtime",
"pallet-multisig/try-runtime",
"pallet-preimage/try-runtime",
"pallet-prices/try-runtime",
Expand Down
39 changes: 37 additions & 2 deletions runtime/bifrost-polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ use constants::currency::*;
use cumulus_primitives_core::AggregateMessageOrigin;
use fp_evm::FeeCalculator;
use fp_rpc::TransactionStatus;
use frame_support::migrations::{FailedMigrationHandler, FailedMigrationHandling};
use frame_support::{
dispatch::DispatchClass,
genesis_builder_helper::{build_state, get_preset},
Expand Down Expand Up @@ -299,7 +300,7 @@ impl frame_system::Config for Runtime {
type MaxConsumers = ConstU32<16>;
type RuntimeTask = ();
type SingleBlockMigrations = ();
type MultiBlockMigrator = ();
type MultiBlockMigrator = MultiBlockMigrations;
type PreInherents = ();
type PostInherents = ();
type PostTransactions = ();
Expand Down Expand Up @@ -788,7 +789,7 @@ impl bifrost_vesting::Config for Runtime {
type WeightInfo = weights::bifrost_vesting::BifrostWeight<Runtime>;
type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons;
const MAX_VESTING_SCHEDULES: u32 = 28;
type BlockNumberProvider = System;
type BlockNumberProvider = RelaychainDataProvider<Runtime>;
}

// Bifrost modules start
Expand Down Expand Up @@ -1474,6 +1475,39 @@ impl bifrost_slp_v2::Config for Runtime {
type MaxValidators = ConstU32<256>;
}

parameter_types! {
pub MbmServiceWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block;
}

/// Unfreeze chain on failed migration and continue with extrinsic execution.
/// Migration must be tested and make sure it doesn't fail. If it happens, we don't have other
/// choices but unfreeze chain and continue with extrinsic execution.
pub struct UnfreezeChainOnFailedMigration;
impl FailedMigrationHandler for UnfreezeChainOnFailedMigration {
fn failed(migration: Option<u32>) -> FailedMigrationHandling {
log::error!(target: "mbm", "Migration failed at cursor: {migration:?}");
FailedMigrationHandling::ForceUnstuck
}
}

impl pallet_migrations::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
#[cfg(not(feature = "runtime-benchmarks"))]
type Migrations = bifrost_vesting::migrations::v2::LazyMigration<
Runtime,
weights::bifrost_vesting::BifrostWeight<Runtime>,
>;
// Benchmarks need mocked migrations to guarantee that they succeed.
#[cfg(feature = "runtime-benchmarks")]
type Migrations = pallet_migrations::mock_helpers::MockedMigrations;
type CursorMaxLen = ConstU32<65_536>;
type IdentifierMaxLen = ConstU32<256>;
type MigrationStatusHandler = ();
type FailedMigrationHandler = UnfreezeChainOnFailedMigration;
type MaxServiceWeight = MbmServiceWeight;
type WeightInfo = pallet_migrations::weights::SubstrateWeight<Runtime>;
}

// Below is the implementation of tokens manipulation functions other than native token.
pub struct LocalAssetAdaptor<Local>(PhantomData<Local>);

Expand Down Expand Up @@ -1577,6 +1611,7 @@ construct_runtime! {
ParachainSystem: cumulus_pallet_parachain_system = 5,
ParachainInfo: parachain_info = 6,
TxPause: pallet_tx_pause = 7,
MultiBlockMigrations: pallet_migrations = 8,

// Monetary stuff
Balances: pallet_balances = 10,
Expand Down
14 changes: 14 additions & 0 deletions runtime/bifrost-polkadot/src/weights/bifrost_vesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,18 @@ impl<T: frame_system::Config> bifrost_vesting::WeightInfo for BifrostWeight<T> {
.saturating_add(T::DbWeight::get().reads(4_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: `Vesting::Vesting` (r:2 w:1)
/// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`)
/// The range of component `x` is `[1, 28]`.
fn step(x: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `316 + x * (36 ±0)`
// Estimated: `8054`
// Minimum execution time: 13_079_000 picoseconds.
Weight::from_parts(13_513_131, 8054)
// Standard Error: 723
.saturating_add(Weight::from_parts(102_389, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}

0 comments on commit d3d5881

Please sign in to comment.