1use core::marker::PhantomData;
20use frame_support::migrations::SteppedMigration;
21use frame_support::migrations::SteppedMigrationError;
22use frame_support::parameter_types;
23use frame_support::traits::PalletInfoAccess;
24use frame_support::weights::WeightMeter;
25use pallet_migrations::WeightInfo;
26use parity_scale_codec::Encode;
27use sp_core::{twox_128, Get};
28use sp_io::{storage::clear_prefix, KillStorageResult};
29use sp_runtime::SaturatedConversion;
30
31pub struct RemovePallet<T, P>(PhantomData<(T, P)>);
46
47impl<T, P> RemovePallet<T, P>
48where
49 P: Get<&'static str>,
50{
51 #[cfg(feature = "try-runtime")]
52 fn num_keys() -> u64 {
53 let prefix = twox_128(P::get().as_bytes()).to_vec();
54 frame_support::storage::KeyPrefixIterator::new(prefix.clone(), prefix, |_| Ok(())).count()
55 as _
56 }
57}
58
59impl<T, P> SteppedMigration for RemovePallet<T, P>
60where
61 T: pallet_migrations::Config,
62 P: Get<&'static str>,
63{
64 type Cursor = bool;
65 type Identifier = [u8; 16];
66
67 fn id() -> Self::Identifier {
68 ("RemovePallet::", P::get()).using_encoded(twox_128)
69 }
70
71 fn step(
72 cursor: Option<Self::Cursor>,
73 meter: &mut WeightMeter,
74 ) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
75 if cursor.unwrap_or(false) {
77 let required = T::DbWeight::get().writes(1);
78 meter
79 .try_consume(required)
80 .map_err(|_| SteppedMigrationError::InsufficientWeight { required })?;
81 return Ok(None);
82 }
83
84 let base_weight = T::WeightInfo::reset_pallet_migration(0);
85 let weight_per_key = T::WeightInfo::reset_pallet_migration(1).saturating_sub(base_weight);
86 let key_budget = meter
87 .remaining()
88 .saturating_sub(base_weight)
89 .checked_div_per_component(&weight_per_key)
90 .unwrap_or_default()
91 .saturated_into();
92
93 if key_budget == 0 {
94 return Err(SteppedMigrationError::InsufficientWeight {
95 required: T::WeightInfo::reset_pallet_migration(1),
96 });
97 }
98
99 let (keys_removed, is_done) =
100 match clear_prefix(&twox_128(P::get().as_bytes()), Some(key_budget)) {
101 KillStorageResult::AllRemoved(value) => (value, true),
102 KillStorageResult::SomeRemaining(value) => (value, false),
103 };
104
105 meter.consume(T::WeightInfo::reset_pallet_migration(keys_removed));
106
107 Ok(Some(is_done))
108 }
109
110 #[cfg(feature = "try-runtime")]
111 fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
112 let num_keys: u64 = Self::num_keys();
113 log::info!(
114 "RemovePallet<{}>: Trying to remove {num_keys} keys.",
115 P::get()
116 );
117 Ok(num_keys.encode())
118 }
119
120 #[cfg(feature = "try-runtime")]
121 fn post_upgrade(state: sp_std::vec::Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
122 use parity_scale_codec::Decode;
123 let keys_before = u64::decode(&mut state.as_ref()).expect("We encoded as u64 above; qed");
124 let keys_now = Self::num_keys();
125 log::info!(
126 "RemovePallet<{}>: Keys remaining after migration: {keys_now}",
127 P::get()
128 );
129
130 if keys_before <= keys_now {
131 log::error!("RemovePallet<{}>: Did not remove any keys.", P::get());
132 Err("RemovePallet failed")?;
133 }
134
135 if keys_now != 1 {
136 log::error!("RemovePallet<{}>: Should have a single key after", P::get());
137 Err("RemovePallet failed")?;
138 }
139
140 Ok(())
141 }
142}
143
144pub struct ResetStorage<T, Pallet, Storage>(PhantomData<(T, Pallet, Storage)>);
155
156impl<T, Pallet, Storage> ResetStorage<T, Pallet, Storage>
157where
158 Pallet: PalletInfoAccess,
159 Storage: Get<&'static str>,
160{
161 #[cfg(feature = "try-runtime")]
162 fn num_keys() -> u64 {
163 let storage_prefix = frame_support::storage::storage_prefix(
164 Pallet::name().as_bytes(),
165 Storage::get().as_bytes(),
166 )
167 .to_vec();
168 frame_support::storage::KeyPrefixIterator::new(
169 storage_prefix.clone(),
170 storage_prefix,
171 |_| Ok(()),
172 )
173 .count() as _
174 }
175}
176
177impl<T, Pallet, Storage> SteppedMigration for ResetStorage<T, Pallet, Storage>
178where
179 T: pallet_migrations::Config,
180 Pallet: PalletInfoAccess,
181 Storage: Get<&'static str>,
182{
183 type Cursor = bool;
184 type Identifier = [u8; 16];
185
186 fn id() -> Self::Identifier {
187 ("ResetStorage", Pallet::name(), Storage::get()).using_encoded(twox_128)
188 }
189
190 fn step(
191 cursor: Option<Self::Cursor>,
192 meter: &mut WeightMeter,
193 ) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
194 if cursor.unwrap_or(false) {
196 let required = T::DbWeight::get().writes(1);
197 meter
198 .try_consume(required)
199 .map_err(|_| SteppedMigrationError::InsufficientWeight { required })?;
200 return Ok(None);
201 }
202
203 let base_weight = T::WeightInfo::reset_pallet_migration(0);
204 let weight_per_key = T::WeightInfo::reset_pallet_migration(1).saturating_sub(base_weight);
205 let key_budget = meter
206 .remaining()
207 .saturating_sub(base_weight)
208 .checked_div_per_component(&weight_per_key)
209 .unwrap_or_default()
210 .saturated_into();
211
212 if key_budget == 0 {
213 return Err(SteppedMigrationError::InsufficientWeight {
214 required: T::WeightInfo::reset_pallet_migration(1),
215 });
216 }
217
218 let storage_prefix = frame_support::storage::storage_prefix(
219 Pallet::name().as_bytes(),
220 Storage::get().as_bytes(),
221 );
222 let (keys_removed, is_done) = match clear_prefix(&storage_prefix, Some(key_budget)) {
223 KillStorageResult::AllRemoved(value) => (value, true),
224 KillStorageResult::SomeRemaining(value) => (value, false),
225 };
226
227 meter.consume(T::WeightInfo::reset_pallet_migration(keys_removed));
228
229 Ok(Some(is_done))
230 }
231
232 #[cfg(feature = "try-runtime")]
233 fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
234 let num_keys: u64 = Self::num_keys();
235 log::info!(
236 "ResetStorage<{}, {}>: Trying to remove {num_keys} keys.",
237 Pallet::name(),
238 Storage::get()
239 );
240 Ok(num_keys.encode())
241 }
242
243 #[cfg(feature = "try-runtime")]
244 fn post_upgrade(state: sp_std::vec::Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
245 use parity_scale_codec::Decode;
246 let keys_before = u64::decode(&mut state.as_ref()).expect("We encoded as u64 above; qed");
247 let keys_now = Self::num_keys();
248 log::info!(
249 "ResetStorage<{}, {}>: Keys remaining after migration: {keys_now}",
250 Pallet::name(),
251 Storage::get()
252 );
253
254 if keys_before <= keys_now {
255 log::error!(
256 "ResetStorage<{}, {}>: Did not remove any keys.",
257 Pallet::name(),
258 Storage::get()
259 );
260 Err("ResetStorage failed")?;
261 }
262
263 if keys_now != 1 {
264 log::error!(
265 "ResetStorage<{}, {}>: Should have a single key after reset",
266 Pallet::name(),
267 Storage::get()
268 );
269 Err("ResetStorage failed")?;
270 }
271
272 Ok(())
273 }
274}
275
276pub type UnreleasedSingleBlockMigrations = ();
278
279pub type PermanentSingleBlockMigrations<Runtime> =
281 (pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,);
282
283pub type SingleBlockMigrations<Runtime> = (
285 UnreleasedSingleBlockMigrations,
286 PermanentSingleBlockMigrations<Runtime>,
287);
288
289parameter_types! {
290 pub const MigratedCandidatesStorageName: &'static str = "MigratedCandidates";
291 pub const MigratedDelegatorsStorageName: &'static str = "MigratedDelegators";
292}
293
294pub type MultiBlockMigrations<Runtime> = (
297 ResetStorage<Runtime, pallet_parachain_staking::Pallet<Runtime>, MigratedCandidatesStorageName>,
298 ResetStorage<Runtime, pallet_parachain_staking::Pallet<Runtime>, MigratedDelegatorsStorageName>,
299 pallet_parachain_staking::migrations::MigrateDelegationScheduledRequestsToDoubleMap<Runtime>,
300);