pallet_collator_selection/
migration.rs1use super::*;
20#[cfg(feature = "try-runtime")]
21use alloc::vec::Vec;
22use frame_support::traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade};
23use log;
24
25pub mod v2 {
27 use super::*;
28 use frame_support::{
29 pallet_prelude::*,
30 storage_alias,
31 traits::{Currency, ReservableCurrency},
32 };
33 use sp_runtime::traits::{Saturating, Zero};
34
35 pub type MigrationToV2<T> = frame_support::migrations::VersionedMigration<
39 1,
40 2,
41 UncheckedMigrationToV2<T>,
42 Pallet<T>,
43 <T as frame_system::Config>::DbWeight,
44 >;
45
46 #[storage_alias]
47 pub type Candidates<T: Config> = StorageValue<
48 Pallet<T>,
49 BoundedVec<CandidateInfo<<T as frame_system::Config>::AccountId, <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance>, <T as Config>::MaxCandidates>,
50 ValueQuery,
51 >;
52
53 pub struct UncheckedMigrationToV2<T>(PhantomData<T>);
55 impl<T: Config + pallet_balances::Config> UncheckedOnRuntimeUpgrade for UncheckedMigrationToV2<T> {
56 fn on_runtime_upgrade() -> Weight {
57 let mut weight = Weight::zero();
58 let mut count: u64 = 0;
59 let candidates = Candidates::<T>::take();
61
62 let new_candidate_list = CandidateList::<T>::get();
67 if new_candidate_list.len().is_zero() {
68 CandidateList::<T>::put(&candidates);
71 weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1));
73 } else {
74 for candidate in candidates {
78 let err = T::Currency::unreserve(&candidate.who, candidate.deposit);
79 if err > Zero::zero() {
80 log::error!(
81 target: LOG_TARGET,
82 "{:?} balance was unable to be unreserved from {:?}",
83 err, &candidate.who,
84 );
85 }
86 count.saturating_inc();
87 }
88 weight.saturating_accrue(
89 <<T as pallet_balances::Config>::WeightInfo as pallet_balances::WeightInfo>::force_unreserve().saturating_mul(count.into()),
90 );
91 }
92
93 log::info!(
94 target: LOG_TARGET,
95 "Unreserved locked bond of {} candidates, upgraded storage to version 2",
96 count,
97 );
98
99 weight.saturating_accrue(T::DbWeight::get().reads_writes(3, 2));
100 weight
101 }
102
103 #[cfg(feature = "try-runtime")]
104 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::DispatchError> {
105 let number_of_candidates = Candidates::<T>::get().to_vec().len();
106 Ok((number_of_candidates as u32).encode())
107 }
108
109 #[cfg(feature = "try-runtime")]
110 fn post_upgrade(_number_of_candidates: Vec<u8>) -> Result<(), sp_runtime::DispatchError> {
111 let new_number_of_candidates = Candidates::<T>::get().to_vec().len();
112 assert_eq!(
113 new_number_of_candidates, 0 as usize,
114 "after migration, the candidates map should be empty"
115 );
116 Ok(())
117 }
118 }
119}
120
121pub mod v1 {
124 use super::*;
125 use frame_support::pallet_prelude::*;
126
127 pub struct MigrateToV1<T>(PhantomData<T>);
128 impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
129 fn on_runtime_upgrade() -> Weight {
130 let on_chain_version = Pallet::<T>::on_chain_storage_version();
131 if on_chain_version == 0 {
132 let invulnerables_len = Invulnerables::<T>::get().to_vec().len();
133 Invulnerables::<T>::mutate(|invulnerables| {
134 invulnerables.sort();
135 });
136
137 StorageVersion::new(1).put::<Pallet<T>>();
138 log::info!(
139 target: LOG_TARGET,
140 "Sorted {} Invulnerables, upgraded storage to version 1",
141 invulnerables_len,
142 );
143 T::WeightInfo::set_invulnerables(invulnerables_len as u32)
146 .saturating_add(T::DbWeight::get().reads_writes(2, 1))
147 } else {
148 log::info!(
149 target: LOG_TARGET,
150 "Migration did not execute. This probably should be removed"
151 );
152 T::DbWeight::get().reads(1)
153 }
154 }
155
156 #[cfg(feature = "try-runtime")]
157 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::DispatchError> {
158 let number_of_invulnerables = Invulnerables::<T>::get().to_vec().len();
159 Ok((number_of_invulnerables as u32).encode())
160 }
161
162 #[cfg(feature = "try-runtime")]
163 fn post_upgrade(number_of_invulnerables: Vec<u8>) -> Result<(), sp_runtime::DispatchError> {
164 let stored_invulnerables = Invulnerables::<T>::get().to_vec();
165 let mut sorted_invulnerables = stored_invulnerables.clone();
166 sorted_invulnerables.sort();
167 assert_eq!(
168 stored_invulnerables, sorted_invulnerables,
169 "after migration, the stored invulnerables should be sorted"
170 );
171
172 let number_of_invulnerables: u32 = Decode::decode(
173 &mut number_of_invulnerables.as_slice(),
174 )
175 .expect("the state parameter should be something that was generated by pre_upgrade");
176 let stored_invulnerables_len = stored_invulnerables.len() as u32;
177 assert_eq!(
178 number_of_invulnerables, stored_invulnerables_len,
179 "after migration, there should be the same number of invulnerables"
180 );
181
182 let on_chain_version = Pallet::<T>::on_chain_storage_version();
183 frame_support::ensure!(on_chain_version >= 1, "must_upgrade");
184
185 Ok(())
186 }
187 }
188}
189
190#[cfg(all(feature = "try-runtime", test))]
191mod tests {
192 use super::*;
193 use crate::{
194 migration::v2::Candidates,
195 mock::{new_test_ext, Balances, Test},
196 };
197 use frame_support::{
198 traits::{Currency, ReservableCurrency, StorageVersion},
199 BoundedVec,
200 };
201 use sp_runtime::traits::ConstU32;
202
203 #[test]
204 fn migrate_to_v2_with_new_candidates() {
205 new_test_ext().execute_with(|| {
206 let storage_version = StorageVersion::new(1);
207 storage_version.put::<Pallet<Test>>();
208
209 let one = 1u64;
210 let two = 2u64;
211 let three = 3u64;
212 let deposit = 10u64;
213
214 Balances::make_free_balance_be(&one, 100u64);
216 Balances::make_free_balance_be(&two, 100u64);
217 Balances::make_free_balance_be(&three, 100u64);
218
219 Balances::reserve(&one, 10u64).unwrap(); Balances::reserve(&two, 20u64).unwrap(); Balances::reserve(&three, 10u64).unwrap(); let candidate_one = CandidateInfo { who: one, deposit };
226 let candidate_two = CandidateInfo { who: two, deposit };
227 let candidate_three = CandidateInfo { who: three, deposit };
228
229 let bounded_candidates =
231 BoundedVec::<CandidateInfo<u64, u64>, ConstU32<20>>::try_from(vec![
232 candidate_one.clone(),
233 candidate_two.clone(),
234 ])
235 .expect("it works");
236 let bounded_candidate_list =
237 BoundedVec::<CandidateInfo<u64, u64>, ConstU32<20>>::try_from(vec![
238 candidate_two.clone(),
239 candidate_three.clone(),
240 ])
241 .expect("it works");
242
243 Candidates::<Test>::put(bounded_candidates);
245 CandidateList::<Test>::put(bounded_candidate_list.clone());
246
247 assert_eq!(Balances::free_balance(one), 90);
249 assert_eq!(Balances::free_balance(two), 80);
250 assert_eq!(Balances::free_balance(three), 90);
251
252 v2::MigrationToV2::<Test>::on_runtime_upgrade();
254
255 let new_storage_version = StorageVersion::get::<Pallet<Test>>();
256 assert_eq!(new_storage_version, 2);
257
258 assert_eq!(Balances::free_balance(one), 100);
260 assert_eq!(Balances::free_balance(two), 90);
261 assert_eq!(Balances::free_balance(three), 90);
262 assert!(Candidates::<Test>::get().is_empty());
264 assert_eq!(CandidateList::<Test>::get(), bounded_candidate_list);
266 });
267 }
268
269 #[test]
270 fn migrate_to_v2_without_new_candidates() {
271 new_test_ext().execute_with(|| {
272 let storage_version = StorageVersion::new(1);
273 storage_version.put::<Pallet<Test>>();
274
275 let one = 1u64;
276 let two = 2u64;
277 let deposit = 10u64;
278
279 Balances::make_free_balance_be(&one, 100u64);
281 Balances::make_free_balance_be(&two, 100u64);
282
283 Balances::reserve(&one, 10u64).unwrap(); Balances::reserve(&two, 10u64).unwrap(); let candidate_one = CandidateInfo { who: one, deposit };
289 let candidate_two = CandidateInfo { who: two, deposit };
290
291 let bounded_candidates =
293 BoundedVec::<CandidateInfo<u64, u64>, ConstU32<20>>::try_from(vec![
294 candidate_one.clone(),
295 candidate_two.clone(),
296 ])
297 .expect("it works");
298
299 Candidates::<Test>::put(bounded_candidates.clone());
301
302 assert_eq!(Balances::free_balance(one), 90);
304 assert_eq!(Balances::free_balance(two), 90);
305
306 v2::MigrationToV2::<Test>::on_runtime_upgrade();
308
309 let new_storage_version = StorageVersion::get::<Pallet<Test>>();
310 assert_eq!(new_storage_version, 2);
311
312 assert_eq!(Balances::free_balance(one), 90);
314 assert_eq!(Balances::free_balance(two), 90);
315 assert!(Candidates::<Test>::get().is_empty());
317 assert_eq!(CandidateList::<Test>::get(), bounded_candidates);
319 });
320 }
321}