polkadot_runtime_parachains/coretime/
migration.rs1pub use v_coretime::{GetLegacyLease, MigrateToCoretime};
20
21mod v_coretime {
22 use crate::{
23 assigner_coretime, configuration,
24 coretime::{mk_coretime_call, Config, PartsOf57600, WeightInfo},
25 };
26 use alloc::{vec, vec::Vec};
27 #[cfg(feature = "try-runtime")]
28 use codec::Decode;
29 #[cfg(feature = "try-runtime")]
30 use codec::Encode;
31 use core::{iter, result};
32 #[cfg(feature = "try-runtime")]
33 use frame_support::ensure;
34 use frame_support::{
35 traits::{OnRuntimeUpgrade, PalletInfoAccess, StorageVersion},
36 weights::Weight,
37 };
38 use frame_system::pallet_prelude::BlockNumberFor;
39 use pallet_broker::{CoreAssignment, CoreMask, ScheduleItem};
40 use polkadot_parachain_primitives::primitives::IsSystem;
41 use polkadot_primitives::{CoreIndex, Id as ParaId};
42 use sp_arithmetic::traits::SaturatedConversion;
43 use sp_core::Get;
44 use sp_runtime::BoundedVec;
45 use xcm::prelude::{
46 send_xcm, Instruction, Junction, Location, SendError, SendXcm, WeightLimit, Xcm,
47 };
48
49 pub trait GetLegacyLease<N> {
51 fn get_parachain_lease_in_blocks(para: ParaId) -> Option<N>;
53 fn get_all_parachains_with_leases() -> Vec<ParaId>;
55 }
56
57 pub struct MigrateToCoretime<T, SendXcm, LegacyLease, const TIMESLICE_PERIOD: u32>(
62 core::marker::PhantomData<(T, SendXcm, LegacyLease)>,
63 );
64
65 impl<
66 T: Config,
67 XcmSender: SendXcm,
68 LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
69 const TIMESLICE_PERIOD: u32,
70 > MigrateToCoretime<T, XcmSender, LegacyLease, TIMESLICE_PERIOD>
71 {
72 fn already_migrated() -> bool {
73 let name_hash = assigner_coretime::Pallet::<T>::name_hash();
76 let mut next_key = name_hash.to_vec();
77 let storage_version_key = StorageVersion::storage_key::<assigner_coretime::Pallet<T>>();
78
79 loop {
80 match sp_io::storage::next_key(&next_key) {
81 Some(key) if &key == &storage_version_key => {
83 next_key = key;
84 },
85 Some(key) if key.starts_with(&name_hash) => {
88 log::info!("`MigrateToCoretime` already executed!");
89 return true
90 },
91 None | Some(_) => return false,
93 }
94 }
95 }
96 }
97
98 impl<
99 T: Config + crate::dmp::Config,
100 XcmSender: SendXcm,
101 LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
102 const TIMESLICE_PERIOD: u32,
103 > OnRuntimeUpgrade for MigrateToCoretime<T, XcmSender, LegacyLease, TIMESLICE_PERIOD>
104 {
105 fn on_runtime_upgrade() -> Weight {
106 if Self::already_migrated() {
107 return Weight::zero()
108 }
109
110 log::info!("Migrating existing parachains to coretime.");
111 migrate_to_coretime::<T, XcmSender, LegacyLease, TIMESLICE_PERIOD>()
112 }
113
114 #[cfg(feature = "try-runtime")]
115 fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::DispatchError> {
116 if Self::already_migrated() {
117 return Ok(Vec::new())
118 }
119
120 let legacy_paras = LegacyLease::get_all_parachains_with_leases();
121 let config = configuration::ActiveConfig::<T>::get();
122 let total_core_count = config.scheduler_params.num_cores + legacy_paras.len() as u32;
123
124 let dmp_queue_size =
125 crate::dmp::Pallet::<T>::dmq_contents(T::BrokerId::get().into()).len() as u32;
126
127 let total_core_count = total_core_count as u32;
128
129 Ok((total_core_count, dmp_queue_size).encode())
130 }
131
132 #[cfg(feature = "try-runtime")]
133 fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::DispatchError> {
134 if state.is_empty() {
135 return Ok(())
136 }
137
138 log::trace!("Running post_upgrade()");
139
140 let (prev_core_count, prev_dmp_queue_size) =
141 <(u32, u32)>::decode(&mut &state[..]).unwrap();
142
143 let dmp_queue_size =
144 crate::dmp::Pallet::<T>::dmq_contents(T::BrokerId::get().into()).len() as u32;
145 let config = configuration::ActiveConfig::<T>::get();
146 let new_core_count = config.scheduler_params.num_cores;
147 ensure!(new_core_count == prev_core_count, "Total number of cores need to not change.");
148 ensure!(
149 dmp_queue_size > prev_dmp_queue_size,
150 "There should have been enqueued at least one DMP messages."
151 );
152
153 Ok(())
154 }
155 }
156
157 fn migrate_to_coretime<
161 T: Config,
162 XcmSender: SendXcm,
163 LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
164 const TIMESLICE_PERIOD: u32,
165 >() -> Weight {
166 let legacy_paras = LegacyLease::get_all_parachains_with_leases();
167 let legacy_count = legacy_paras.len() as u32;
168 let now = frame_system::Pallet::<T>::block_number();
169 for (core, para_id) in legacy_paras.into_iter().enumerate() {
170 let r = assigner_coretime::Pallet::<T>::assign_core(
171 CoreIndex(core as u32),
172 now,
173 vec![(CoreAssignment::Task(para_id.into()), PartsOf57600::FULL)],
174 None,
175 );
176 if let Err(err) = r {
177 log::error!(
178 "Creating assignment for existing para failed: {:?}, error: {:?}",
179 para_id,
180 err
181 );
182 }
183 }
184
185 let config = configuration::ActiveConfig::<T>::get();
186 for on_demand in 0..config.scheduler_params.num_cores {
187 let core = CoreIndex(legacy_count.saturating_add(on_demand as _));
188 let r = assigner_coretime::Pallet::<T>::assign_core(
189 core,
190 now,
191 vec![(CoreAssignment::Pool, PartsOf57600::FULL)],
192 None,
193 );
194 if let Err(err) = r {
195 log::error!("Creating assignment for existing on-demand core, failed: {:?}", err);
196 }
197 }
198 let total_cores = config.scheduler_params.num_cores + legacy_count;
199 configuration::ActiveConfig::<T>::mutate(|c| {
200 c.scheduler_params.num_cores = total_cores;
201 });
202
203 if let Err(err) = migrate_send_assignments_to_coretime_chain::<
204 T,
205 XcmSender,
206 LegacyLease,
207 TIMESLICE_PERIOD,
208 >() {
209 log::error!("Sending legacy chain data to coretime chain failed: {:?}", err);
210 }
211
212 let single_weight = <T as Config>::WeightInfo::assign_core(1);
213 single_weight
214 .saturating_mul(u64::from(
215 legacy_count.saturating_add(config.scheduler_params.num_cores),
216 ))
217 .saturating_add(T::DbWeight::get().reads_writes(2, 1))
219 }
220
221 fn migrate_send_assignments_to_coretime_chain<
222 T: Config,
223 XcmSender: SendXcm,
224 LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
225 const TIMESLICE_PERIOD: u32,
226 >() -> result::Result<(), SendError> {
227 let legacy_paras = LegacyLease::get_all_parachains_with_leases();
228 let legacy_paras_count = legacy_paras.len();
229 let (system_chains, lease_holding): (Vec<_>, Vec<_>) =
230 legacy_paras.into_iter().partition(IsSystem::is_system);
231
232 let reservations = system_chains.into_iter().map(|p| {
233 let schedule = BoundedVec::truncate_from(vec![ScheduleItem {
234 mask: CoreMask::complete(),
235 assignment: CoreAssignment::Task(p.into()),
236 }]);
237 mk_coretime_call::<T>(crate::coretime::CoretimeCalls::Reserve(schedule))
238 });
239
240 let mut leases = lease_holding.into_iter().filter_map(|p| {
241 log::trace!(target: "coretime-migration", "Preparing sending of lease holding para {:?}", p);
242 let Some(valid_until) = LegacyLease::get_parachain_lease_in_blocks(p) else {
243 log::error!("Lease holding chain with no lease information?!");
244 return None
245 };
246 let valid_until: u32 = match valid_until.try_into() {
247 Ok(val) => val,
248 Err(_) => {
249 log::error!("Converting block number to u32 failed!");
250 return None
251 },
252 };
253 let time_slice = valid_until.div_ceil(TIMESLICE_PERIOD);
254 log::trace!(target: "coretime-migration", "Sending of lease holding para {:?}, valid_until: {:?}, time_slice: {:?}", p, valid_until, time_slice);
255 Some(mk_coretime_call::<T>(crate::coretime::CoretimeCalls::SetLease(p.into(), time_slice)))
256 });
257
258 let core_count: u16 = configuration::ActiveConfig::<T>::get()
259 .scheduler_params
260 .num_cores
261 .saturated_into();
262 let set_core_count = iter::once(mk_coretime_call::<T>(
263 crate::coretime::CoretimeCalls::NotifyCoreCount(core_count),
264 ));
265
266 let pool = (legacy_paras_count..core_count.into()).map(|_| {
267 let schedule = BoundedVec::truncate_from(vec![ScheduleItem {
268 mask: CoreMask::complete(),
269 assignment: CoreAssignment::Pool,
270 }]);
271 mk_coretime_call::<T>(crate::coretime::CoretimeCalls::Reserve(schedule))
274 });
275
276 let message_content = iter::once(Instruction::UnpaidExecution {
277 weight_limit: WeightLimit::Unlimited,
278 check_origin: None,
279 });
280
281 let reservation_content = message_content.clone().chain(reservations).collect();
282 let leases_content_1 = message_content
283 .clone()
284 .chain(leases.by_ref().take(legacy_paras_count / 2)) .collect();
286 let leases_content_2 = message_content.clone().chain(leases).collect();
287 let set_core_count_content = message_content.clone().chain(set_core_count).collect();
288 let messages = if core_count as usize > legacy_paras_count {
290 let pool_content = message_content.clone().chain(pool).collect();
291 vec![
292 Xcm(reservation_content),
293 Xcm(pool_content),
294 Xcm(leases_content_1),
295 Xcm(leases_content_2),
296 Xcm(set_core_count_content),
297 ]
298 } else {
299 vec![
300 Xcm(reservation_content),
301 Xcm(leases_content_1),
302 Xcm(leases_content_2),
303 Xcm(set_core_count_content),
304 ]
305 };
306
307 for message in messages {
308 send_xcm::<XcmSender>(
309 Location::new(0, Junction::Parachain(T::BrokerId::get())),
310 message,
311 )?;
312 }
313
314 Ok(())
315 }
316}