referrerpolicy=no-referrer-when-downgrade

pallet_broker/
migration.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use 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	/// V0 region record.
34	#[derive(Encode, Decode)]
35	struct RegionRecordV0<AccountId, Balance> {
36		/// The end of the Region.
37		pub end: Timeslice,
38		/// The owner of the Region.
39		pub owner: AccountId,
40		/// The amount paid to Polkadot for this Region, or `None` if renewal is not allowed.
41		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			// calculate and return migration weights
61			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			// calculate and return migration weights
112			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::{OptionQuery, RuntimeDebug, 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			// calculate and return migration weights
148			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	// types added here for v4 migration
172	#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
173	pub struct ConfigRecord<BlockNumber, RelayBlockNumber> {
174		/// The number of Relay-chain blocks in advance which scheduling should be fixed and the
175		/// `Coretime::assign` API used to inform the Relay-chain.
176		pub advance_notice: RelayBlockNumber,
177		/// The length in blocks of the Interlude Period for forthcoming sales.
178		pub interlude_length: BlockNumber,
179		/// The length in blocks of the Leadin Period for forthcoming sales.
180		pub leadin_length: BlockNumber,
181		/// The length in timeslices of Regions which are up for sale in forthcoming sales.
182		pub region_length: Timeslice,
183		/// The proportion of cores available for sale which should be sold in order for the price
184		/// to remain the same in the next sale.
185		pub ideal_bulk_proportion: Perbill,
186		/// An artificial limit to the number of cores which are allowed to be sold. If `Some` then
187		/// no more cores will be sold than this.
188		pub limit_cores_offered: Option<CoreIndex>,
189		/// The amount by which the renewal price increases each sale period.
190		pub renewal_bump: Perbill,
191		/// The duration by which rewards for contributions to the InstaPool must be collected.
192		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	/// The status of a Bulk Coretime Sale.
201	#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
202	pub struct SaleInfoRecord<Balance, BlockNumber> {
203		/// The relay block number at which the sale will/did start.
204		pub sale_start: BlockNumber,
205		/// The length in relay chain blocks of the Leadin Period (where the price is decreasing).
206		pub leadin_length: BlockNumber,
207		/// The price of Bulk Coretime after the Leadin Period.
208		pub price: Balance,
209		/// The first timeslice of the Regions which are being sold in this sale.
210		pub region_begin: Timeslice,
211		/// The timeslice on which the Regions which are being sold in the sale terminate. (i.e.
212		/// One after the last timeslice which the Regions control.)
213		pub region_end: Timeslice,
214		/// The number of cores we want to sell, ideally. Selling this amount would result in no
215		/// change to the price for the next sale.
216		pub ideal_cores_sold: CoreIndex,
217		/// Number of cores which are/have been offered for sale.
218		pub cores_offered: CoreIndex,
219		/// The index of the first core which is for sale. Core of Regions which are sold have
220		/// incrementing indices from this.
221		pub first_core: CoreIndex,
222		/// The latest price at which Bulk Coretime was purchased until surpassing the ideal number
223		/// of cores were sold.
224		pub sellout_price: Option<Balance>,
225		/// Number of cores which have been sold; never more than cores_offered.
226		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		/// Converts absolute value of parachain block number to relay chain block number
237		fn convert_block_number_to_relay_height(
238			block_number: BlockNumberFor<T>,
239		) -> RelayBlockNumberOf<T>;
240
241		/// Converts parachain block length into equivalent relay chain block length
242		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				};
332				SaleInfo::<T>::put(updated_sale_info);
333			}
334
335			weight.saturating_add(T::DbWeight::get().reads_writes(1, 2))
336		}
337
338		#[cfg(feature = "try-runtime")]
339		fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
340			let (
341				old_interlude_length,
342				old_configuration_leadin_length,
343				old_sale_start,
344				old_sale_info_leadin_length,
345			): (BlockNumberFor<T>, BlockNumberFor<T>, BlockNumberFor<T>, BlockNumberFor<T>) =
346				Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
347
348			if let Some(config_record) = Configuration::<T>::get() {
349				ensure!(
350					Self::verify_updated_block_length(
351						old_configuration_leadin_length,
352						config_record.leadin_length
353					),
354					"must migrate configuration leadin_length"
355				);
356
357				ensure!(
358					Self::verify_updated_block_length(
359						old_interlude_length,
360						config_record.interlude_length
361					),
362					"must migrate configuration interlude_length"
363				);
364			}
365
366			if let Some(sale_info) = SaleInfo::<T>::get() {
367				ensure!(
368					Self::verify_updated_block_time(old_sale_start, sale_info.sale_start),
369					"must migrate sale info sale_start"
370				);
371
372				ensure!(
373					Self::verify_updated_block_length(
374						old_sale_info_leadin_length,
375						sale_info.leadin_length
376					),
377					"must migrate sale info leadin_length"
378				);
379			}
380
381			Ok(())
382		}
383	}
384
385	#[cfg(feature = "try-runtime")]
386	impl<T: Config, BlockConversion: BlockToRelayHeightConversion<T>>
387		MigrateToV4Impl<T, BlockConversion>
388	{
389		fn verify_updated_block_time(
390			old_value: BlockNumberFor<T>,
391			new_value: RelayBlockNumberOf<T>,
392		) -> bool {
393			BlockConversion::convert_block_number_to_relay_height(old_value) == new_value
394		}
395
396		fn verify_updated_block_length(
397			old_value: BlockNumberFor<T>,
398			new_value: RelayBlockNumberOf<T>,
399		) -> bool {
400			BlockConversion::convert_block_length_to_relay_length(old_value) == new_value
401		}
402	}
403}
404
405/// Migrate the pallet storage from `0` to `1`.
406pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
407	0,
408	1,
409	v1::MigrateToV1Impl<T>,
410	Pallet<T>,
411	<T as frame_system::Config>::DbWeight,
412>;
413
414pub type MigrateV1ToV2<T> = frame_support::migrations::VersionedMigration<
415	1,
416	2,
417	v2::MigrateToV2Impl<T>,
418	Pallet<T>,
419	<T as frame_system::Config>::DbWeight,
420>;
421
422pub type MigrateV2ToV3<T> = frame_support::migrations::VersionedMigration<
423	2,
424	3,
425	v3::MigrateToV3Impl<T>,
426	Pallet<T>,
427	<T as frame_system::Config>::DbWeight,
428>;
429
430pub type MigrateV3ToV4<T, BlockConversion> = frame_support::migrations::VersionedMigration<
431	3,
432	4,
433	v4::MigrateToV4Impl<T, BlockConversion>,
434	Pallet<T>,
435	<T as frame_system::Config>::DbWeight,
436>;