pallet_schemas/migration/
v5.rs1use crate::{
2 migration::v4,
3 pallet::{CurrentIntentIdentifierMaximum, IntentInfos, NameToMappedEntityIds, SchemaInfos},
4 Config, IntentInfo, Pallet, SchemaInfo, SchemaVersionId, SCHEMA_NAME_BYTES_MAX,
5 SCHEMA_STORAGE_VERSION,
6};
7use alloc::{format, vec::Vec};
8use common_primitives::schema::{IntentId, MappedEntityIdentifier, SchemaId, SchemaStatus};
9use core::marker::PhantomData;
10#[cfg(feature = "try-runtime")]
11use frame_support::ensure;
12use frame_support::{
13 pallet_prelude::{Get, GetStorageVersion, Weight},
14 traits::{Len, UncheckedOnRuntimeUpgrade},
15 BoundedVec,
16};
17#[cfg(feature = "try-runtime")]
18use parity_scale_codec::{Decode, Encode};
19#[cfg(feature = "try-runtime")]
20use sp_runtime::TryRuntimeError;
21
22const LOG_TARGET: &str = "pallet::schemas::migration::v5";
23
24fn convert_from_old(id: SchemaId, old_info: &v4::SchemaInfo) -> crate::SchemaInfo {
25 SchemaInfo {
26 intent_id: id as IntentId,
27 model_type: old_info.model_type,
28 payload_location: old_info.payload_location,
29 settings: old_info.settings,
30 status: SchemaStatus::Active,
31 }
32}
33
34fn convert_to_intent(old_info: &v4::SchemaInfo) -> IntentInfo {
35 IntentInfo { payload_location: old_info.payload_location, settings: old_info.settings }
36}
37
38fn append_or_overlay<S1: Get<u32>, S2: Get<u32>>(
39 target: &mut BoundedVec<u8, S1>,
40 source: &[u8],
41 protocol: &BoundedVec<u8, S2>,
42) -> Result<(), ()> {
43 let max_len = (SCHEMA_NAME_BYTES_MAX as usize - protocol.len() - 1).min(S1::get() as usize);
44 let additional = source.len();
45 let len = target.len();
46 if len + additional > max_len {
47 target.truncate(max_len - additional);
48 }
49 target.try_append(&mut source.to_vec())
50}
51
52pub struct InnerMigrateV4ToV5<T: Config>(PhantomData<T>);
54
55impl<T: Config> UncheckedOnRuntimeUpgrade for InnerMigrateV4ToV5<T> {
56 fn on_runtime_upgrade() -> Weight {
57 let onchain_version = Pallet::<T>::on_chain_storage_version();
58 let current_version = Pallet::<T>::in_code_storage_version();
59 log::info!(target: LOG_TARGET, "onchain_version={onchain_version:?}, current_version={current_version:?}");
60 if SCHEMA_STORAGE_VERSION != current_version {
61 log::error!(target: LOG_TARGET, "storage version mismatch: expected {SCHEMA_STORAGE_VERSION:?}, found {current_version:?}");
62 return T::DbWeight::get().reads(1)
63 }
64 if onchain_version < current_version {
65 log::info!(target: LOG_TARGET, "Migrating from v4 to v5");
66 let mut reads = 0;
67 let mut writes = 0;
68 let mut schemas_migrated = 0;
69 let mut intents_created = 0;
70 let mut new_names = 0;
71 let mut old_names = 0;
72 let mut max_intent_id = 0u16;
73
74 SchemaInfos::<T>::translate(|schema_id, old_schema_info: v4::SchemaInfo| {
76 reads += 1;
77 writes += 2;
78 max_intent_id = max_intent_id.max(schema_id);
79 IntentInfos::<T>::insert(
80 schema_id as IntentId,
81 convert_to_intent(&old_schema_info),
82 );
83 intents_created += 1;
84 schemas_migrated += 1;
85 Some(convert_from_old(schema_id, &old_schema_info))
86 });
87
88 v4::SchemaNameToIds::<T>::translate(
90 |schema_id, old_schema_name, version_id: SchemaVersionId| {
91 reads += 1;
92 old_names += 1;
93 let max_version = version_id.ids.len();
94 for (index, id) in version_id.ids.iter().enumerate() {
95 let version = index + 1;
96 let mut name = old_schema_name.clone();
97 if version < max_version {
100 let version_str = Vec::<u8>::from(format!("-{version}").as_bytes());
101 match append_or_overlay(&mut name, &version_str, &schema_id) {
102 Ok(_) => (),
103 Err(e) => {
104 log::error!(target: LOG_TARGET, "{e:?} unable to append id {version_str:?} to name: {name:?}");
105 return Some(version_id)
106 },
107 };
108 }
109 NameToMappedEntityIds::<T>::insert(
110 &schema_id,
111 name,
112 MappedEntityIdentifier::Intent(*id as IntentId),
113 );
114 writes += 1;
115 new_names += 1;
116 }
117 writes += 1;
118 None
119 },
120 );
121
122 CurrentIntentIdentifierMaximum::<T>::set(max_intent_id);
123
124 log::info!(target: LOG_TARGET,
125 "Migration complete. \
126 schemas_migrated={schemas_migrated:?}, intents_created={intents_created:?}, \
127 new_names={new_names:?}, old_names={old_names:?}"
128 );
129
130 SCHEMA_STORAGE_VERSION.put::<Pallet<T>>();
132 let weight = T::DbWeight::get().reads_writes(reads, writes);
133 log::info!(target: LOG_TARGET,
134 "Schemas storage migrated to version {current_version:?}. reads={reads:?}, writes={writes:?}, proof_size={:?}, ref_time={:?}",
135 weight.proof_size(), weight.ref_time());
136
137 weight
138 } else {
139 log::info!(target: LOG_TARGET,
140 "Migration did not execute; storage version is already up to date. \
141 onchain_version={onchain_version:?}, current_version={current_version:?}"
142 );
143 T::DbWeight::get().reads(1)
144 }
145 }
146
147 #[cfg(feature = "try-runtime")]
148 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
149 let schemas_count = v4::SchemaInfos::<T>::iter_values().count() as u32;
150 let mut named_schemas_count = 0u32;
151 v4::SchemaNameToIds::<T>::iter_values().for_each(|schema_versions| {
152 named_schemas_count += schema_versions.ids.len() as u32;
153 });
154 Ok((schemas_count, named_schemas_count).encode())
155 }
156
157 #[cfg(feature = "try-runtime")]
158 fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
159 let (old_count, old_named_schemas_count) = <(u32, u32)>::decode(&mut &state[..])
160 .map_err(|_| TryRuntimeError::Other("unable to decode old schema count"))?;
161 let new_schema_count = SchemaInfos::<T>::iter_values().count() as u32;
162 let new_intent_count = IntentInfos::<T>::iter_values().count() as u32;
163 let new_names_count = NameToMappedEntityIds::<T>::iter_values().count() as u32;
164 let remaining_schema_names = v4::SchemaNameToIds::<T>::iter_values().count() as u32;
165
166 ensure!(remaining_schema_names == 0, "named schemas still exist");
167 ensure!(old_count == new_schema_count, "schema count mismatch");
168 ensure!(old_count == new_intent_count, "intent count mismatch");
169 ensure!(old_named_schemas_count == new_names_count, "name count mismatch");
170 Ok(())
171 }
172}
173
174pub type MigrateV4ToV5<T> = frame_support::migrations::VersionedMigration<
180 4, 5, InnerMigrateV4ToV5<T>,
183 crate::pallet::Pallet<T>,
184 <T as frame_system::Config>::DbWeight,
185>;