Skip to content

Commit a529926

Browse files
committedMar 21, 2025
Linear relaase pallet migration
1 parent 7c4f030 commit a529926

File tree

3 files changed

+222
-80
lines changed

3 files changed

+222
-80
lines changed
 

‎pallets/linear-release/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use frame_support::{
3333
traits::{
3434
fungible::{BalancedHold, Inspect, InspectHold, Mutate, MutateHold},
3535
tokens::{Balance, Precision},
36-
Get, WithdrawReasons,
36+
Get, StorageVersion, WithdrawReasons,
3737
},
3838
};
3939
use frame_system::pallet_prelude::*;
@@ -110,6 +110,9 @@ impl<T: Config> Get<u32> for MaxVestingSchedulesGet<T> {
110110
}
111111
}
112112

113+
/// Current storage version
114+
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(7);
115+
113116
/// Enable `dev_mode` for this pallet.
114117
#[frame_support::pallet(dev_mode)]
115118
pub mod pallet {
@@ -172,6 +175,7 @@ pub mod pallet {
172175
// Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and
173176
// method.
174177
#[pallet::pallet]
178+
#[pallet::storage_version(STORAGE_VERSION)]
175179
pub struct Pallet<T>(_);
176180

177181
#[pallet::event]
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,245 @@
1-
use crate::{Balance, BlockNumber, Runtime, RuntimeHoldReason};
1+
use crate::{Runtime, RuntimeHoldReason};
22
use alloc::vec::Vec;
33
use frame_support::{storage::storage_prefix, traits::OnRuntimeUpgrade, BoundedVec};
4-
use pallet_linear_release::{MaxVestingSchedulesGet, VestingInfo};
4+
use pallet_linear_release::{MaxVestingSchedulesGet, VestingInfo, VestingInfoOf};
55

66
#[cfg(feature = "try-runtime")]
77
use frame_support::{ensure, migrations::VersionedPostUpgradeData, traits::GetStorageVersion};
88
#[cfg(feature = "try-runtime")]
99
use itertools::Itertools;
1010
#[cfg(feature = "try-runtime")]
11-
use parity_scale_codec::{DecodeAll, Encode};
11+
use parity_scale_codec::{Decode, DecodeAll, Encode};
12+
#[cfg(feature = "try-runtime")]
13+
use sp_runtime::DispatchError;
1214

13-
pub type Values = BoundedVec<VestingInfo<Balance, BlockNumber>, MaxVestingSchedulesGet<Runtime>>;
15+
pub type Values<T> = BoundedVec<VestingInfoOf<T>, MaxVestingSchedulesGet<T>>;
1416

15-
pub struct LinearReleaseVestingMigration;
16-
impl OnRuntimeUpgrade for LinearReleaseVestingMigration {
17-
#[cfg(feature = "try-runtime")]
18-
fn pre_upgrade() -> Result<alloc::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
19-
use crate::LinearRelease;
17+
pub mod v1 {
18+
use super::*;
19+
use core::marker::PhantomData;
20+
use frame_support::{migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade};
21+
use frame_system::pallet_prelude::BlockNumberFor;
22+
use pallet_linear_release::{AccountIdOf, ReasonOf};
23+
use sp_core::Get;
24+
use sp_runtime::{traits::BlockNumberProvider, Saturating, Weight};
2025

21-
let funding_on_chain_version = LinearRelease::on_chain_storage_version();
22-
if funding_on_chain_version == 0 {
23-
let storage = pallet_linear_release::Vesting::<Runtime>::iter().collect_vec();
24-
ensure!(storage.len() == 15, "LinearReleaseVestingMigration: Invalid storage length in pre_upgrade");
25-
Ok(VersionedPostUpgradeData::MigrationExecuted(Vec::new()).encode())
26-
} else {
27-
Ok(VersionedPostUpgradeData::Noop.encode())
26+
const LOG: &str = "linear_release::migration::v1";
27+
pub struct LinearReleaseVestingInfoMigration;
28+
29+
pub struct UncheckedMigrationToV1<T: pallet_linear_release::Config + cumulus_pallet_parachain_system::Config>(
30+
PhantomData<T>,
31+
);
32+
33+
impl<T: pallet_linear_release::Config + cumulus_pallet_parachain_system::Config> UncheckedOnRuntimeUpgrade
34+
for UncheckedMigrationToV1<T>
35+
{
36+
#[cfg(feature = "try-runtime")]
37+
fn pre_upgrade() -> Result<Vec<u8>, DispatchError> {
38+
let migration_count = pallet_linear_release::Vesting::<T>::iter().count() as u32;
39+
log::info!(target: LOG, "Pre-upgrade: {} UserMigrations entries", migration_count);
40+
41+
let vestings = pallet_linear_release::Vesting::<T>::iter().collect::<Vec<_>>();
42+
43+
Ok((migration_count, vestings).encode())
2844
}
29-
}
3045

31-
fn on_runtime_upgrade() -> frame_support::weights::Weight {
32-
let db_weight = <Runtime as frame_system::Config>::DbWeight::get();
46+
fn on_runtime_upgrade() -> Weight {
47+
let mut items = 0u64;
48+
let translate_vesting_info =
49+
|_: AccountIdOf<T>, _: ReasonOf<T>, vesting_info: Values<T>| -> Option<Values<T>> {
50+
let migrated: Vec<_> = vesting_info
51+
.iter()
52+
.map(|vesting| {
53+
items = items.saturating_add(1);
54+
55+
// adjust starting block to relay chain block number
56+
let relay_chain_now: BlockNumberFor<T> =
57+
cumulus_pallet_parachain_system::RelaychainDataProvider::<T>::current_block_number()
58+
.try_into()
59+
.ok()
60+
.expect("BlockNumber conversion failed");
61+
62+
let polimec_now = frame_system::Pallet::<T>::current_block_number();
63+
let blocks_passed = polimec_now.saturating_sub(vesting.starting_block);
64+
let relay_chain_starting_block = relay_chain_now.saturating_sub(
65+
blocks_passed.saturating_mul(2_u32.try_into().ok().expect("safe to convert; qed")),
66+
);
67+
68+
let adjusted_per_block =
69+
vesting.per_block.saturating_mul(2_u32.try_into().ok().expect("safe to convert; qed"));
70+
71+
VestingInfo {
72+
locked: vesting.locked,
73+
per_block: adjusted_per_block,
74+
starting_block: relay_chain_starting_block,
75+
}
76+
})
77+
.collect();
78+
79+
let bounded = Values::<T>::try_from(migrated)
80+
.unwrap_or_else(|_| panic!("MaxVestingSchedulesGet exceeded during migration"));
3381

34-
// Step 1: Get account count for weight calculation
35-
let account_count = pallet_linear_release::Vesting::<Runtime>::iter().count();
82+
Some(bounded)
83+
};
3684

37-
// Initial weight: account_count reads + 1 clear_prefix operation
38-
let mut total_weight = db_weight.reads_writes(account_count as u64, 1); // For clear_prefix
85+
log::info!(target: LOG, "Starting linear release vesting time migration to V1");
3986

40-
// Step 2: Collect all accounts and their hold amounts
41-
let mut account_holds = Vec::with_capacity(account_count);
87+
pallet_linear_release::Vesting::<T>::translate(translate_vesting_info);
4288

43-
for (account, reason, vesting_info) in pallet_linear_release::Vesting::<Runtime>::iter() {
44-
if !vesting_info.is_empty() {
45-
log::info!(
46-
"Found vesting for account: {:?}, reason: {:?}, schedule count: {:?}",
47-
account,
48-
reason,
49-
vesting_info.len()
50-
);
51-
account_holds.push((account, reason, vesting_info[0]));
89+
log::info!(target: LOG, "Migrated {} linear release vesting entries", items);
90+
91+
T::DbWeight::get().reads_writes(items, items)
92+
}
93+
94+
#[cfg(feature = "try-runtime")]
95+
fn post_upgrade(pre_state: Vec<u8>) -> Result<(), DispatchError> {
96+
let (pre_migration_count, pre_vestings): (u32, Vec<((AccountIdOf<T>, ReasonOf<T>), Values<T>)>) =
97+
Decode::decode(&mut &pre_state[..]).expect("Failed to decode pre-migration state");
98+
99+
let post_migration_count = pallet_linear_release::Vesting::<T>::iter().count() as u32;
100+
101+
if pre_migration_count != post_migration_count {
102+
return Err("Migration count mismatch".into());
103+
}
104+
105+
for ((account, reason), pre_vesting) in pre_vestings {
106+
let post_vesting = pallet_linear_release::Vesting::<T>::get(&account, &reason).unwrap_or_default();
107+
108+
// check that the starting block has been adjusted
109+
let relay_chain_now =
110+
cumulus_pallet_parachain_system::RelaychainDataProvider::<T>::current_block_number();
111+
112+
for (pre_vesting_info, post_vesting_info) in pre_vesting.iter().zip(post_vesting.iter()) {
113+
assert_ne!(
114+
pre_vesting_info.starting_block, post_vesting_info.starting_block,
115+
"Starting block not adjusted"
116+
);
117+
assert!(
118+
post_vesting_info.starting_block <=
119+
relay_chain_now.try_into().ok().expect("safe to convert; qed"),
120+
"Starting block not adjusted correctly"
121+
);
122+
123+
assert!(
124+
post_vesting_info.per_block ==
125+
pre_vesting_info
126+
.per_block
127+
.saturating_mul(2_u32.try_into().ok().expect("safe to convert; qed")),
128+
"Per block not adjusted"
129+
);
130+
}
131+
}
132+
133+
Ok(())
134+
}
135+
}
136+
137+
pub type LinearReleaseVestingMigrationV1<T> = VersionedMigration<
138+
0,
139+
1,
140+
UncheckedMigrationToV1<T>,
141+
pallet_linear_release::Pallet<T>,
142+
<T as frame_system::Config>::DbWeight,
143+
>;
144+
}
145+
146+
pub mod unversioned {
147+
use super::*;
148+
149+
pub struct LinearReleaseVestingMigration;
150+
impl OnRuntimeUpgrade for LinearReleaseVestingMigration {
151+
#[cfg(feature = "try-runtime")]
152+
fn pre_upgrade() -> Result<alloc::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
153+
use crate::LinearRelease;
154+
155+
let funding_on_chain_version = LinearRelease::on_chain_storage_version();
156+
if funding_on_chain_version == 0 {
157+
let storage = pallet_linear_release::Vesting::<Runtime>::iter().collect_vec();
158+
ensure!(storage.len() == 15, "LinearReleaseVestingMigration: Invalid storage length in pre_upgrade");
159+
Ok(VersionedPostUpgradeData::MigrationExecuted(Vec::new()).encode())
52160
} else {
53-
log::warn!("Empty vesting info found for account: {:?}, reason: {:?}", account, reason);
161+
Ok(VersionedPostUpgradeData::Noop.encode())
54162
}
55163
}
56164

57-
// Step 3: Clear all corrupted vesting entries
58-
let pallet_prefix = storage_prefix(b"LinearRelease", b"Vesting");
59-
let removed_keys = frame_support::storage::unhashed::clear_prefix(&pallet_prefix, None, None);
60-
log::info!("Cleared {:#?} vesting storage keys", removed_keys.deconstruct());
61-
62-
// Step 4: Create fresh vesting entries for all accounts with holds
63-
let mut success_count = 0u64;
64-
let mut failure_count = 0u64;
65-
66-
for (account, _corrupted_reason, vesting_info) in account_holds {
67-
// Create a BoundedVec with this schedule - reuse original VestingInfo value, but set the k2 to the new pallet_funding HoldReason::Participation.
68-
let mut schedules = BoundedVec::<_, MaxVestingSchedulesGet<Runtime>>::default();
69-
70-
match schedules.try_push(vesting_info) {
71-
Ok(_) => {
72-
pallet_linear_release::Vesting::<Runtime>::insert(
73-
&account,
74-
&RuntimeHoldReason::Funding(pallet_funding::HoldReason::Participation),
75-
schedules,
165+
fn on_runtime_upgrade() -> frame_support::weights::Weight {
166+
let db_weight = <Runtime as frame_system::Config>::DbWeight::get();
167+
168+
// Step 1: Get account count for weight calculation
169+
let account_count = pallet_linear_release::Vesting::<Runtime>::iter().count();
170+
171+
// Initial weight: account_count reads + 1 clear_prefix operation
172+
let mut total_weight = db_weight.reads_writes(account_count as u64, 1); // For clear_prefix
173+
174+
// Step 2: Collect all accounts and their hold amounts
175+
let mut account_holds = Vec::with_capacity(account_count);
176+
177+
for (account, reason, vesting_info) in pallet_linear_release::Vesting::<Runtime>::iter() {
178+
if !vesting_info.is_empty() {
179+
log::info!(
180+
"Found vesting for account: {:?}, reason: {:?}, schedule count: {:?}",
181+
account,
182+
reason,
183+
vesting_info.len()
76184
);
77-
success_count += 1;
78-
total_weight = total_weight.saturating_add(db_weight.writes(1));
79-
},
80-
Err(_) => {
81-
log::error!("Failed to add vesting schedule to BoundedVec for account {:?}", account);
82-
failure_count += 1;
83-
},
185+
account_holds.push((account, reason, vesting_info[0]));
186+
} else {
187+
log::warn!("Empty vesting info found for account: {:?}, reason: {:?}", account, reason);
188+
}
84189
}
85-
}
86190

87-
log::info!(
88-
"Migration complete. Successfully created {} new vesting entries. Failed: {}",
89-
success_count,
90-
failure_count
91-
);
191+
// Step 3: Clear all corrupted vesting entries
192+
let pallet_prefix = storage_prefix(b"LinearRelease", b"Vesting");
193+
let removed_keys = frame_support::storage::unhashed::clear_prefix(&pallet_prefix, None, None);
194+
log::info!("Cleared {:#?} vesting storage keys", removed_keys.deconstruct());
195+
196+
// Step 4: Create fresh vesting entries for all accounts with holds
197+
let mut success_count = 0u64;
198+
let mut failure_count = 0u64;
199+
200+
for (account, _corrupted_reason, vesting_info) in account_holds {
201+
// Create a BoundedVec with this schedule - reuse original VestingInfo value, but set the k2 to the new pallet_funding HoldReason::Participation.
202+
let mut schedules = BoundedVec::<_, MaxVestingSchedulesGet<Runtime>>::default();
203+
204+
match schedules.try_push(vesting_info) {
205+
Ok(_) => {
206+
pallet_linear_release::Vesting::<Runtime>::insert(
207+
&account,
208+
&RuntimeHoldReason::Funding(pallet_funding::HoldReason::Participation),
209+
schedules,
210+
);
211+
success_count += 1;
212+
total_weight = total_weight.saturating_add(db_weight.writes(1));
213+
},
214+
Err(_) => {
215+
log::error!("Failed to add vesting schedule to BoundedVec for account {:?}", account);
216+
failure_count += 1;
217+
},
218+
}
219+
}
92220

93-
total_weight
94-
}
221+
log::info!(
222+
"Migration complete. Successfully created {} new vesting entries. Failed: {}",
223+
success_count,
224+
failure_count
225+
);
95226

96-
#[cfg(feature = "try-runtime")]
97-
fn post_upgrade(versioned_post_upgrade_data_bytes: alloc::vec::Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
98-
let storage = pallet_linear_release::Vesting::<Runtime>::iter().collect_vec();
99-
ensure!(storage.len() == 15, "LinearReleaseVestingMigration: Invalid storage length in post_upgrade");
227+
total_weight
228+
}
100229

101-
match <VersionedPostUpgradeData>::decode_all(&mut &versioned_post_upgrade_data_bytes[..])
102-
.map_err(|_| "VersionedMigration post_upgrade failed to decode PreUpgradeData")?
103-
{
104-
VersionedPostUpgradeData::MigrationExecuted(_inner_bytes) => Ok(()),
105-
VersionedPostUpgradeData::Noop => Ok(()),
230+
#[cfg(feature = "try-runtime")]
231+
fn post_upgrade(
232+
versioned_post_upgrade_data_bytes: alloc::vec::Vec<u8>,
233+
) -> Result<(), sp_runtime::TryRuntimeError> {
234+
let storage = pallet_linear_release::Vesting::<Runtime>::iter().collect_vec();
235+
ensure!(storage.len() == 15, "LinearReleaseVestingMigration: Invalid storage length in post_upgrade");
236+
237+
match <VersionedPostUpgradeData>::decode_all(&mut &versioned_post_upgrade_data_bytes[..])
238+
.map_err(|_| "VersionedMigration post_upgrade failed to decode PreUpgradeData")?
239+
{
240+
VersionedPostUpgradeData::MigrationExecuted(_inner_bytes) => Ok(()),
241+
VersionedPostUpgradeData::Noop => Ok(()),
242+
}
106243
}
107244
}
108245
}

‎runtimes/polimec/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,11 @@ pub mod migrations {
188188
#[allow(unused_parens)]
189189
pub type Unreleased = (
190190
super::custom_migrations::asset_id_migration::FromOldAssetIdMigration,
191-
super::custom_migrations::linear_release::LinearReleaseVestingMigration,
191+
super::custom_migrations::linear_release::unversioned::LinearReleaseVestingMigration,
192192
pallet_funding::migrations::storage_migrations::v6::MigrationToV6<Runtime>,
193193
RemovePallet<IdentityPalletName, RuntimeDbWeight>,
194194
pallet_funding::migrations::vesting_info::v7::MigrationToV8<Runtime>,
195+
super::custom_migrations::linear_release::v1::LinearReleaseVestingMigrationV1<Runtime>,
195196
);
196197
}
197198

0 commit comments

Comments
 (0)
Failed to load comments.