referrerpolicy=no-referrer-when-downgrade

cumulus_pallet_parachain_system/
migration.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use crate::{
18	Config, LastProcessedHrmpMessage, Pallet, ReservedDmpWeightOverride, ReservedXcmpWeightOverride,
19};
20use frame_support::{
21	pallet_prelude::*,
22	traits::{Get, OnRuntimeUpgrade, StorageVersion},
23	weights::Weight,
24};
25
26/// The in-code storage version.
27pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
28
29pub use v4::MigrateV3ToV4;
30
31// V4: Extend the `InboundMessageId` to also contain the sender.
32pub mod v4 {
33	use super::*;
34	use crate::parachain_inherent::{InboundHrmpMessageId, InboundMessageId};
35	use frame_support::traits::UncheckedOnRuntimeUpgrade;
36
37	mod unversioned {
38		use super::*;
39
40		pub struct UncheckedMigrateV3ToV4<T: Config>(PhantomData<T>);
41	}
42
43	impl<T: Config> UncheckedOnRuntimeUpgrade for unversioned::UncheckedMigrateV3ToV4<T> {
44		fn on_runtime_upgrade() -> frame_support::weights::Weight {
45			let result =
46				LastProcessedHrmpMessage::<T>::translate(|maybe_pre: Option<InboundMessageId>| {
47					maybe_pre.map(|pre| InboundHrmpMessageId::Generic(pre))
48				});
49			if result.is_err() {
50				log::error!(
51					target: "parachain_system",
52					"unexpected error when performing translation of the LastProcessedHrmpMessage to the new InboundMessageId type"
53				);
54			}
55
56			T::DbWeight::get().reads_writes(1, 1)
57		}
58	}
59
60	/// [`VersionedMigration`](frame_support::migrations::VersionedMigration), that is performed
61	/// only when the on-chain version is 3.
62	pub type MigrateV3ToV4<T> = frame_support::migrations::VersionedMigration<
63		3,
64		4,
65		unversioned::UncheckedMigrateV3ToV4<T>,
66		Pallet<T>,
67		<T as frame_system::Config>::DbWeight,
68	>;
69}
70
71pub mod v3 {
72	use super::*;
73	use crate::parachain_inherent::InboundMessageId;
74
75	#[frame_support::storage_alias]
76	pub type LastProcessedHrmpMessage<T: Config> = StorageValue<Pallet<T>, InboundMessageId>;
77
78	/// Migrates the pallet storage to the most recent version.
79	pub struct Migration<T: Config>(PhantomData<T>);
80
81	impl<T: Config> OnRuntimeUpgrade for Migration<T> {
82		fn on_runtime_upgrade() -> Weight {
83			let mut weight: Weight = T::DbWeight::get().reads(2);
84
85			if StorageVersion::get::<Pallet<T>>() == 0 {
86				weight = weight
87					.saturating_add(v1::migrate::<T>())
88					.saturating_add(T::DbWeight::get().writes(1));
89				StorageVersion::new(1).put::<Pallet<T>>();
90			}
91
92			if StorageVersion::get::<Pallet<T>>() == 1 {
93				weight = weight
94					.saturating_add(v2::migrate::<T>())
95					.saturating_add(T::DbWeight::get().writes(1));
96				StorageVersion::new(2).put::<Pallet<T>>();
97			}
98
99			if StorageVersion::get::<Pallet<T>>() == 2 {
100				// Runtime upgrades are in their own PoV so there is no issue with killing this.
101				crate::PoVMessagesTracker::<T>::kill();
102				weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));
103				StorageVersion::new(3).put::<Pallet<T>>();
104			}
105
106			weight
107		}
108	}
109}
110
111/// V2: Migrate to 2D weights for ReservedXcmpWeightOverride and ReservedDmpWeightOverride.
112mod v2 {
113	use super::*;
114	const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB
115
116	pub fn migrate<T: Config>() -> Weight {
117		let translate = |pre: u64| -> Weight { Weight::from_parts(pre, DEFAULT_POV_SIZE) };
118
119		if ReservedXcmpWeightOverride::<T>::translate(|pre| pre.map(translate)).is_err() {
120			log::error!(
121				target: "parachain_system",
122				"unexpected error when performing translation of the ReservedXcmpWeightOverride type during storage upgrade to v2"
123			);
124		}
125
126		if ReservedDmpWeightOverride::<T>::translate(|pre| pre.map(translate)).is_err() {
127			log::error!(
128				target: "parachain_system",
129				"unexpected error when performing translation of the ReservedDmpWeightOverride type during storage upgrade to v2"
130			);
131		}
132
133		T::DbWeight::get().reads_writes(2, 2)
134	}
135}
136
137/// V1: `LastUpgrade` block number is removed from the storage since the upgrade
138/// mechanism now uses signals instead of block offsets.
139mod v1 {
140	use crate::{Config, Pallet};
141	use frame_support::{migration::clear_storage_prefix, pallet_prelude::*};
142
143	pub fn migrate<T: Config>() -> Weight {
144		let _ =
145			clear_storage_prefix(<Pallet<T>>::name().as_bytes(), b"LastUpgrade", b"", None, None);
146		T::DbWeight::get().writes(1)
147	}
148}
149
150#[cfg(all(feature = "try-runtime", test))]
151mod tests {
152	use super::*;
153	use crate::{
154		mock::{new_test_ext, Test},
155		parachain_inherent::{InboundHrmpMessageId, InboundMessageId},
156	};
157	use frame_support::traits::OnRuntimeUpgrade;
158
159	#[test]
160	#[allow(deprecated)]
161	fn test_migrate_v3_to_v4() {
162		new_test_ext().execute_with(|| {
163			// None
164			let storage_version = StorageVersion::new(3);
165			storage_version.put::<Pallet<Test>>();
166			frame_support::storage::unhashed::kill(
167				&v3::LastProcessedHrmpMessage::<Test>::hashed_key(),
168			);
169			let bytes = v4::MigrateV3ToV4::<Test>::pre_upgrade();
170			assert!(bytes.is_ok());
171			v4::MigrateV3ToV4::<Test>::on_runtime_upgrade();
172			assert!(v4::MigrateV3ToV4::<Test>::post_upgrade(bytes.unwrap()).is_ok());
173			let post = crate::LastProcessedHrmpMessage::<Test>::get();
174			assert_eq!(post, None);
175
176			// Some
177			let storage_version = StorageVersion::new(3);
178			storage_version.put::<Pallet<Test>>();
179			let pre = InboundMessageId { sent_at: 321, reverse_idx: 123 };
180			frame_support::storage::unhashed::put_raw(
181				&v3::LastProcessedHrmpMessage::<Test>::hashed_key(),
182				&pre.encode(),
183			);
184			let bytes = v4::MigrateV3ToV4::<Test>::pre_upgrade();
185			assert!(bytes.is_ok());
186			v4::MigrateV3ToV4::<Test>::on_runtime_upgrade();
187			assert!(v4::MigrateV3ToV4::<Test>::post_upgrade(bytes.unwrap()).is_ok());
188			let post = crate::LastProcessedHrmpMessage::<Test>::get();
189			assert_eq!(post, Some(InboundHrmpMessageId::Generic(pre)));
190		});
191	}
192}