polkadot_runtime_parachains/on_demand/
migration.rs1use super::*;
19use frame_support::{
20 migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias,
21 traits::UncheckedOnRuntimeUpgrade, weights::Weight,
22};
23
24mod v0 {
25 use super::*;
26 use alloc::collections::vec_deque::VecDeque;
27
28 #[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone)]
29 pub(super) struct EnqueuedOrder {
30 pub para_id: ParaId,
31 }
32
33 #[storage_alias]
37 pub(super) type SpotTraffic<T: Config> = StorageValue<Pallet<T>, FixedU128, ValueQuery>;
38
39 #[storage_alias]
43 pub(super) type OnDemandQueue<T: Config> =
44 StorageValue<Pallet<T>, VecDeque<EnqueuedOrder>, ValueQuery>;
45}
46
47mod v1 {
48 use super::*;
49
50 use crate::on_demand::LOG_TARGET;
51
52 pub struct UncheckedMigrateToV1<T>(core::marker::PhantomData<T>);
54 impl<T: Config> UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1<T> {
55 fn on_runtime_upgrade() -> Weight {
56 let mut weight: Weight = Weight::zero();
57
58 let config = configuration::ActiveConfig::<T>::get();
60 QueueStatus::<T>::mutate(|mut queue_status| {
61 Pallet::<T>::update_spot_traffic(&config, &mut queue_status);
62
63 let v0_queue = v0::OnDemandQueue::<T>::take();
64 v0_queue.into_iter().for_each(|enqueued_order| {
66 Pallet::<T>::add_on_demand_order(
68 queue_status,
69 enqueued_order.para_id,
70 QueuePushDirection::Back,
71 );
72 });
73 });
74
75 v0::OnDemandQueue::<T>::kill(); v0::SpotTraffic::<T>::kill(); weight.saturating_accrue(T::DbWeight::get().reads(1));
81 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
83 weight.saturating_accrue(T::DbWeight::get().writes(2));
85
86 log::info!(target: LOG_TARGET, "Migrated on demand assigner storage to v1");
87 weight
88 }
89
90 #[cfg(feature = "try-runtime")]
91 fn pre_upgrade() -> Result<alloc::vec::Vec<u8>, sp_runtime::TryRuntimeError> {
92 let n: u32 = v0::OnDemandQueue::<T>::get().len() as u32;
93
94 log::info!(
95 target: LOG_TARGET,
96 "Number of orders waiting in the queue before: {n}",
97 );
98
99 Ok(n.encode())
100 }
101
102 #[cfg(feature = "try-runtime")]
103 fn post_upgrade(state: alloc::vec::Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
104 log::info!(target: LOG_TARGET, "Running post_upgrade()");
105
106 ensure!(
107 v0::OnDemandQueue::<T>::get().is_empty(),
108 "OnDemandQueue should be empty after the migration"
109 );
110
111 let expected_len = u32::decode(&mut &state[..]).unwrap();
112 let queue_status_size = QueueStatus::<T>::get().size();
113 ensure!(
114 expected_len == queue_status_size,
115 "Number of orders should be the same before and after migration"
116 );
117
118 let n_affinity_entries: u32 =
119 AffinityEntries::<T>::iter().map(|(_index, heap)| heap.len() as u32).sum();
120 let n_para_id_affinity: u32 = ParaIdAffinity::<T>::iter()
121 .map(|(_para_id, affinity)| affinity.count as u32)
122 .sum();
123 ensure!(
124 n_para_id_affinity == n_affinity_entries,
125 "Number of affinity entries should be the same as the counts in ParaIdAffinity"
126 );
127
128 Ok(())
129 }
130 }
131}
132
133pub type MigrateV0ToV1<T> = VersionedMigration<
135 0,
136 1,
137 v1::UncheckedMigrateToV1<T>,
138 Pallet<T>,
139 <T as frame_system::Config>::DbWeight,
140>;
141
142#[cfg(test)]
143mod tests {
144 use super::{v0, v1, UncheckedOnRuntimeUpgrade, Weight};
145 use crate::mock::{new_test_ext, MockGenesisConfig, OnDemand, Test};
146 use polkadot_primitives::Id as ParaId;
147
148 #[test]
149 fn migration_to_v1_preserves_queue_ordering() {
150 new_test_ext(MockGenesisConfig::default()).execute_with(|| {
151 for i in 1..=5 {
153 v0::OnDemandQueue::<Test>::mutate(|queue| {
154 queue.push_back(v0::EnqueuedOrder { para_id: ParaId::new(i) })
155 });
156 }
157
158 let old_queue = v0::OnDemandQueue::<Test>::get();
160 assert_eq!(old_queue.len(), 5);
161 assert_eq!(OnDemand::get_queue_status().size(), 0);
163
164 assert_eq!(
166 <v1::UncheckedMigrateToV1<Test> as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(),
167 Weight::zero()
168 );
169
170 assert_eq!(OnDemand::get_queue_status().size(), 5);
172
173 old_queue.iter().zip(OnDemand::get_free_entries().iter()).for_each(
175 |(old_enq, new_enq)| {
176 assert_eq!(old_enq.para_id, new_enq.para_id);
177 },
178 );
179 });
180 }
181}