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