1use super::*;
19use crate::types::RegionRecord;
20use codec::{Decode, Encode};
21use core::marker::PhantomData;
22use frame_support::traits::{Get, UncheckedOnRuntimeUpgrade};
23use sp_runtime::Saturating;
24
25#[cfg(feature = "try-runtime")]
26use alloc::vec::Vec;
27#[cfg(feature = "try-runtime")]
28use frame_support::ensure;
29
30mod v1 {
31 use super::*;
32
33 #[derive(Encode, Decode)]
35 struct RegionRecordV0<AccountId, Balance> {
36 pub end: Timeslice,
38 pub owner: AccountId,
40 pub paid: Option<Balance>,
42 }
43
44 pub struct MigrateToV1Impl<T>(PhantomData<T>);
45
46 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV1Impl<T> {
47 fn on_runtime_upgrade() -> frame_support::weights::Weight {
48 let mut count: u64 = 0;
49
50 <Regions<T>>::translate::<RegionRecordV0<T::AccountId, BalanceOf<T>>, _>(|_, v0| {
51 count.saturating_inc();
52 Some(RegionRecord { end: v0.end, owner: Some(v0.owner), paid: v0.paid })
53 });
54
55 log::info!(
56 target: LOG_TARGET,
57 "Storage migration v1 for pallet-broker finished.",
58 );
59
60 T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)
62 }
63
64 #[cfg(feature = "try-runtime")]
65 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
66 Ok((Regions::<T>::iter_keys().count() as u32).encode())
67 }
68
69 #[cfg(feature = "try-runtime")]
70 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
71 let old_count = u32::decode(&mut &state[..]).expect("Known good");
72 let new_count = Regions::<T>::iter_values().count() as u32;
73
74 ensure!(old_count == new_count, "Regions count should not change");
75 Ok(())
76 }
77 }
78}
79
80mod v2 {
81 use super::*;
82 use frame_support::{
83 pallet_prelude::{OptionQuery, Twox64Concat},
84 storage_alias,
85 };
86
87 #[storage_alias]
88 pub type AllowedRenewals<T: Config> = StorageMap<
89 Pallet<T>,
90 Twox64Concat,
91 PotentialRenewalId,
92 PotentialRenewalRecordOf<T>,
93 OptionQuery,
94 >;
95
96 pub struct MigrateToV2Impl<T>(PhantomData<T>);
97
98 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV2Impl<T> {
99 fn on_runtime_upgrade() -> frame_support::weights::Weight {
100 let mut count = 0;
101 for (renewal_id, renewal) in AllowedRenewals::<T>::drain() {
102 PotentialRenewals::<T>::insert(renewal_id, renewal);
103 count += 1;
104 }
105
106 log::info!(
107 target: LOG_TARGET,
108 "Storage migration v2 for pallet-broker finished.",
109 );
110
111 T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1)
113 }
114
115 #[cfg(feature = "try-runtime")]
116 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
117 Ok((AllowedRenewals::<T>::iter_keys().count() as u32).encode())
118 }
119
120 #[cfg(feature = "try-runtime")]
121 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
122 let old_count = u32::decode(&mut &state[..]).expect("Known good");
123 let new_count = PotentialRenewals::<T>::iter_values().count() as u32;
124
125 ensure!(old_count == new_count, "Renewal count should not change");
126 Ok(())
127 }
128 }
129}
130
131mod v3 {
132 use super::*;
133 use codec::MaxEncodedLen;
134 use frame_support::{
135 pallet_prelude::{Debug, OptionQuery, TypeInfo},
136 storage_alias,
137 };
138 use frame_system::Pallet as System;
139 use sp_arithmetic::Perbill;
140
141 pub struct MigrateToV3Impl<T>(PhantomData<T>);
142
143 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV3Impl<T> {
144 fn on_runtime_upgrade() -> frame_support::weights::Weight {
145 let acc = Pallet::<T>::account_id();
146 System::<T>::inc_providers(&acc);
147 T::DbWeight::get().writes(1)
149 }
150
151 #[cfg(feature = "try-runtime")]
152 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
153 Ok(System::<T>::providers(&Pallet::<T>::account_id()).encode())
154 }
155
156 #[cfg(feature = "try-runtime")]
157 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
158 let old_providers = u32::decode(&mut &state[..]).expect("Known good");
159 let new_providers = System::<T>::providers(&Pallet::<T>::account_id()) as u32;
160
161 ensure!(new_providers == old_providers + 1, "Providers count should increase by one");
162 Ok(())
163 }
164 }
165
166 #[storage_alias]
167 pub type Configuration<T: Config> = StorageValue<Pallet<T>, ConfigRecordOf<T>, OptionQuery>;
168 pub type ConfigRecordOf<T> =
169 ConfigRecord<frame_system::pallet_prelude::BlockNumberFor<T>, RelayBlockNumberOf<T>>;
170
171 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
173 pub struct ConfigRecord<BlockNumber, RelayBlockNumber> {
174 pub advance_notice: RelayBlockNumber,
177 pub interlude_length: BlockNumber,
179 pub leadin_length: BlockNumber,
181 pub region_length: Timeslice,
183 pub ideal_bulk_proportion: Perbill,
186 pub limit_cores_offered: Option<CoreIndex>,
189 pub renewal_bump: Perbill,
191 pub contribution_timeout: Timeslice,
193 }
194
195 #[storage_alias]
196 pub type SaleInfo<T: Config> = StorageValue<Pallet<T>, SaleInfoRecordOf<T>, OptionQuery>;
197 pub type SaleInfoRecordOf<T> =
198 SaleInfoRecord<BalanceOf<T>, frame_system::pallet_prelude::BlockNumberFor<T>>;
199
200 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
202 pub struct SaleInfoRecord<Balance, BlockNumber> {
203 pub sale_start: BlockNumber,
205 pub leadin_length: BlockNumber,
207 pub price: Balance,
209 pub region_begin: Timeslice,
211 pub region_end: Timeslice,
214 pub ideal_cores_sold: CoreIndex,
217 pub cores_offered: CoreIndex,
219 pub first_core: CoreIndex,
222 pub sellout_price: Option<Balance>,
225 pub cores_sold: CoreIndex,
227 }
228}
229
230pub mod v4 {
231 use super::*;
232
233 type BlockNumberFor<T> = frame_system::pallet_prelude::BlockNumberFor<T>;
234
235 pub trait BlockToRelayHeightConversion<T: Config> {
236 fn convert_block_number_to_relay_height(
238 block_number: BlockNumberFor<T>,
239 ) -> RelayBlockNumberOf<T>;
240
241 fn convert_block_length_to_relay_length(
243 block_number: BlockNumberFor<T>,
244 ) -> RelayBlockNumberOf<T>;
245 }
246
247 pub struct MigrateToV4Impl<T, BlockConversion>(PhantomData<T>, PhantomData<BlockConversion>);
248 impl<T: Config, BlockConversion: BlockToRelayHeightConversion<T>> UncheckedOnRuntimeUpgrade
249 for MigrateToV4Impl<T, BlockConversion>
250 {
251 #[cfg(feature = "try-runtime")]
252 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
253 let (interlude_length, configuration_leadin_length) =
254 if let Some(config_record) = v3::Configuration::<T>::get() {
255 (config_record.interlude_length, config_record.leadin_length)
256 } else {
257 ((0 as u32).into(), (0 as u32).into())
258 };
259
260 let updated_interlude_length: RelayBlockNumberOf<T> =
261 BlockConversion::convert_block_length_to_relay_length(interlude_length);
262 let updated_leadin_length: RelayBlockNumberOf<T> =
263 BlockConversion::convert_block_length_to_relay_length(configuration_leadin_length);
264 log::info!(target: LOG_TARGET, "Configuration Pre-Migration: Interlude Length {:?}->{:?} Leadin Length {:?}->{:?}", interlude_length, updated_interlude_length, configuration_leadin_length, updated_leadin_length);
265
266 let (sale_start, sale_info_leadin_length) =
267 if let Some(sale_info_record) = v3::SaleInfo::<T>::get() {
268 (sale_info_record.sale_start, sale_info_record.leadin_length)
269 } else {
270 ((0 as u32).into(), (0 as u32).into())
271 };
272
273 let updated_sale_start: RelayBlockNumberOf<T> =
274 BlockConversion::convert_block_number_to_relay_height(sale_start);
275 let updated_sale_info_leadin_length: RelayBlockNumberOf<T> =
276 BlockConversion::convert_block_length_to_relay_length(sale_info_leadin_length);
277 log::info!(target: LOG_TARGET, "SaleInfo Pre-Migration: Sale Start {:?}->{:?} Interlude Length {:?}->{:?}", sale_start, updated_sale_start, sale_info_leadin_length, updated_sale_info_leadin_length);
278
279 Ok((interlude_length, configuration_leadin_length, sale_start, sale_info_leadin_length)
280 .encode())
281 }
282
283 fn on_runtime_upgrade() -> frame_support::weights::Weight {
284 let mut weight = T::DbWeight::get().reads(1);
285
286 if let Some(config_record) = v3::Configuration::<T>::take() {
287 log::info!(target: LOG_TARGET, "migrating Configuration record");
288
289 let updated_interlude_length: RelayBlockNumberOf<T> =
290 BlockConversion::convert_block_length_to_relay_length(
291 config_record.interlude_length,
292 );
293 let updated_leadin_length: RelayBlockNumberOf<T> =
294 BlockConversion::convert_block_length_to_relay_length(
295 config_record.leadin_length,
296 );
297
298 let updated_config_record = ConfigRecord {
299 interlude_length: updated_interlude_length,
300 leadin_length: updated_leadin_length,
301 advance_notice: config_record.advance_notice,
302 region_length: config_record.region_length,
303 ideal_bulk_proportion: config_record.ideal_bulk_proportion,
304 limit_cores_offered: config_record.limit_cores_offered,
305 renewal_bump: config_record.renewal_bump,
306 contribution_timeout: config_record.contribution_timeout,
307 };
308 Configuration::<T>::put(updated_config_record);
309 }
310 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
311
312 if let Some(sale_info) = v3::SaleInfo::<T>::take() {
313 log::info!(target: LOG_TARGET, "migrating SaleInfo record");
314
315 let updated_sale_start: RelayBlockNumberOf<T> =
316 BlockConversion::convert_block_number_to_relay_height(sale_info.sale_start);
317 let updated_leadin_length: RelayBlockNumberOf<T> =
318 BlockConversion::convert_block_length_to_relay_length(sale_info.leadin_length);
319
320 let updated_sale_info = SaleInfoRecord {
321 sale_start: updated_sale_start,
322 leadin_length: updated_leadin_length,
323 end_price: sale_info.price,
324 region_begin: sale_info.region_begin,
325 region_end: sale_info.region_end,
326 ideal_cores_sold: sale_info.ideal_cores_sold,
327 cores_offered: sale_info.cores_offered,
328 first_core: sale_info.first_core,
329 sellout_price: sale_info.sellout_price,
330 cores_sold: sale_info.cores_sold,
331 sale_index: 0,
332 };
333 SaleInfo::<T>::put(updated_sale_info);
334 }
335
336 weight.saturating_add(T::DbWeight::get().reads_writes(1, 2))
337 }
338
339 #[cfg(feature = "try-runtime")]
340 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
341 let (
342 old_interlude_length,
343 old_configuration_leadin_length,
344 old_sale_start,
345 old_sale_info_leadin_length,
346 ): (BlockNumberFor<T>, BlockNumberFor<T>, BlockNumberFor<T>, BlockNumberFor<T>) =
347 Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
348
349 if let Some(config_record) = Configuration::<T>::get() {
350 ensure!(
351 Self::verify_updated_block_length(
352 old_configuration_leadin_length,
353 config_record.leadin_length
354 ),
355 "must migrate configuration leadin_length"
356 );
357
358 ensure!(
359 Self::verify_updated_block_length(
360 old_interlude_length,
361 config_record.interlude_length
362 ),
363 "must migrate configuration interlude_length"
364 );
365 }
366
367 if let Some(sale_info) = SaleInfo::<T>::get() {
368 ensure!(
369 Self::verify_updated_block_time(old_sale_start, sale_info.sale_start),
370 "must migrate sale info sale_start"
371 );
372
373 ensure!(
374 Self::verify_updated_block_length(
375 old_sale_info_leadin_length,
376 sale_info.leadin_length
377 ),
378 "must migrate sale info leadin_length"
379 );
380 }
381
382 Ok(())
383 }
384 }
385
386 #[cfg(feature = "try-runtime")]
387 impl<T: Config, BlockConversion: BlockToRelayHeightConversion<T>>
388 MigrateToV4Impl<T, BlockConversion>
389 {
390 fn verify_updated_block_time(
391 old_value: BlockNumberFor<T>,
392 new_value: RelayBlockNumberOf<T>,
393 ) -> bool {
394 BlockConversion::convert_block_number_to_relay_height(old_value) == new_value
395 }
396
397 fn verify_updated_block_length(
398 old_value: BlockNumberFor<T>,
399 new_value: RelayBlockNumberOf<T>,
400 ) -> bool {
401 BlockConversion::convert_block_length_to_relay_length(old_value) == new_value
402 }
403 }
404}
405
406pub mod v5 {
407 use super::*;
408 use frame_support::traits::Get;
409
410 pub(crate) mod old {
412 use super::*;
413 use codec::MaxEncodedLen;
414 use frame_support::{
415 pallet_prelude::{Debug, OptionQuery, TypeInfo},
416 storage_alias,
417 };
418
419 #[storage_alias]
420 pub type SaleInfo<T: Config> = StorageValue<Pallet<T>, SaleInfoRecordOf<T>, OptionQuery>;
421 pub type SaleInfoRecordOf<T> = SaleInfoRecord<BalanceOf<T>, RelayBlockNumberOf<T>>;
422
423 #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
425 pub struct SaleInfoRecord<Balance, RelayBlockNumber> {
426 pub sale_start: RelayBlockNumber,
427 pub leadin_length: RelayBlockNumber,
428 pub end_price: Balance,
429 pub region_begin: Timeslice,
430 pub region_end: Timeslice,
431 pub ideal_cores_sold: CoreIndex,
432 pub cores_offered: CoreIndex,
433 pub first_core: CoreIndex,
434 pub sellout_price: Option<Balance>,
435 pub cores_sold: CoreIndex,
436 }
437 }
438
439 pub trait FirstSaleRegion {
442 fn region_begin() -> Timeslice;
443 }
444
445 pub struct MigrateToV5Impl<T, F>(PhantomData<T>, PhantomData<F>);
447
448 impl<T: Config, F: FirstSaleRegion> UncheckedOnRuntimeUpgrade for MigrateToV5Impl<T, F> {
449 #[cfg(feature = "try-runtime")]
450 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
451 let sale_info_state = old::SaleInfo::<T>::get()
452 .map(|sale| (sale.sale_start, sale.region_begin, sale.region_end));
453 Ok(sale_info_state.encode())
454 }
455
456 fn on_runtime_upgrade() -> frame_support::weights::Weight {
457 let mut weight = T::DbWeight::get().reads(1);
458
459 if let Some(old_sale) = old::SaleInfo::<T>::get() {
460 let first_region_begin = F::region_begin();
461
462 let region_length = if let Some(config) = Configuration::<T>::get() {
465 config.region_length
466 } else {
467 log::error!(
468 target: LOG_TARGET,
469 "Migrating SaleInfo: Configuration missing while SaleInfo exists; \
470 defaulting region_length to 0 and sale_index to 1",
471 );
472 0
473 };
474 weight.saturating_accrue(T::DbWeight::get().reads(1));
475
476 let completed_regions = if region_length > 0 {
482 old_sale.region_begin.saturating_sub(first_region_begin) / region_length
483 } else {
484 0
485 };
486 let sale_index: SaleIndex = completed_regions.saturating_add(1);
487
488 log::info!(
489 target: LOG_TARGET,
490 "Migrating SaleInfo: first_region_begin={:?}, current_region_begin={:?}, \
491 region_length={:?}, sale_index={}",
492 first_region_begin,
493 old_sale.region_begin,
494 region_length,
495 sale_index,
496 );
497
498 let updated_sale = SaleInfoRecord {
499 sale_start: old_sale.sale_start,
500 leadin_length: old_sale.leadin_length,
501 end_price: old_sale.end_price,
502 region_begin: old_sale.region_begin,
503 region_end: old_sale.region_end,
504 ideal_cores_sold: old_sale.ideal_cores_sold,
505 cores_offered: old_sale.cores_offered,
506 first_core: old_sale.first_core,
507 sellout_price: old_sale.sellout_price,
508 cores_sold: old_sale.cores_sold,
509 sale_index,
510 };
511 SaleInfo::<T>::put(updated_sale);
512 weight.saturating_accrue(T::DbWeight::get().writes(1));
513
514 log::info!(
515 target: LOG_TARGET,
516 "Storage migration v5 for pallet-broker completed: added sale_index = {}",
517 sale_index,
518 );
519 } else {
520 log::info!(
521 target: LOG_TARGET,
522 "No SaleInfo found, skipping v5 migration",
523 );
524 }
525
526 weight
527 }
528
529 #[cfg(feature = "try-runtime")]
530 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
531 let old_state: Option<(RelayBlockNumberOf<T>, Timeslice, Timeslice)> =
532 Decode::decode(&mut &state[..])
533 .map_err(|_| "Failed to decode pre_upgrade state")?;
534
535 if let Some((old_sale_start, old_region_begin, old_region_end)) = old_state {
537 let new_sale =
538 SaleInfo::<T>::get().ok_or("SaleInfo should still exist after migration")?;
539
540 ensure!(
541 old_sale_start == new_sale.sale_start &&
542 old_region_begin == new_sale.region_begin &&
543 old_region_end == new_sale.region_end,
544 "Core SaleInfo fields should not have changed during migration"
545 );
546 ensure!(
547 new_sale.sale_index >= 1,
548 "An existing sale must have a sale_index of at least 1"
549 );
550 }
551
552 Ok(())
553 }
554 }
555}
556
557pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
559 0,
560 1,
561 v1::MigrateToV1Impl<T>,
562 Pallet<T>,
563 <T as frame_system::Config>::DbWeight,
564>;
565
566pub type MigrateV1ToV2<T> = frame_support::migrations::VersionedMigration<
567 1,
568 2,
569 v2::MigrateToV2Impl<T>,
570 Pallet<T>,
571 <T as frame_system::Config>::DbWeight,
572>;
573
574pub type MigrateV2ToV3<T> = frame_support::migrations::VersionedMigration<
575 2,
576 3,
577 v3::MigrateToV3Impl<T>,
578 Pallet<T>,
579 <T as frame_system::Config>::DbWeight,
580>;
581
582pub type MigrateV3ToV4<T, BlockConversion> = frame_support::migrations::VersionedMigration<
583 3,
584 4,
585 v4::MigrateToV4Impl<T, BlockConversion>,
586 Pallet<T>,
587 <T as frame_system::Config>::DbWeight,
588>;
589
590pub type MigrateV4ToV5<T, FirstSaleRegion> = frame_support::migrations::VersionedMigration<
591 4,
592 5,
593 v5::MigrateToV5Impl<T, FirstSaleRegion>,
594 Pallet<T>,
595 <T as frame_system::Config>::DbWeight,
596>;