1use polkadot_sdk::frame_support::{
2 migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade, weights::Weight,
3};
4
5use crate::{Config, Pallet};
6
7pub mod v4 {
8 use super::*;
9 use crate::{Agent, Agents};
10 use scale_info::prelude::vec::Vec;
11
12 pub mod storage {
13 use codec::{Decode, Encode, MaxEncodedLen};
14 use polkadot_sdk::frame_support::{DebugNoBound, Identity, storage_alias};
15 use polkadot_sdk::polkadot_sdk_frame::prelude::BlockNumberFor;
16 use polkadot_sdk::sp_runtime::{BoundedVec, Percent};
17 use scale_info::TypeInfo;
18
19 use crate::AccountIdOf;
20
21 #[derive(DebugNoBound, Encode, Decode, MaxEncodedLen, TypeInfo)]
22 #[scale_info(skip_type_params(T))]
23 pub struct Agent<T: crate::Config> {
24 pub key: AccountIdOf<T>,
25 pub name: BoundedVec<u8, T::MaxAgentNameLengthConstraint>,
26 pub url: BoundedVec<u8, T::MaxAgentUrlLengthConstraint>,
27 pub metadata: BoundedVec<u8, T::MaxAgentMetadataLengthConstraint>,
28 pub weight_penalty_factor: Percent,
29 pub registration_block: BlockNumberFor<T>,
30 pub fees: crate::fee::ValidatorFee<T>,
31 }
32
33 #[storage_alias]
34 pub type Agents<T: crate::Config> =
35 StorageMap<crate::Pallet<T>, Identity, AccountIdOf<T>, Agent<T>>;
36 }
37
38 pub type Migration<T, W> = VersionedMigration<3, 4, MigrateToV4<T>, Pallet<T>, W>;
39 pub struct MigrateToV4<T>(core::marker::PhantomData<T>);
40 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV4<T> {
41 fn on_runtime_upgrade() -> Weight {
42 let old_agents = storage::Agents::<T>::iter().collect::<Vec<_>>();
43 let _ = storage::Agents::<T>::clear(u32::MAX, None);
44
45 for (id, old_agent) in old_agents {
46 Agents::<T>::insert(
47 id,
48 Agent {
49 key: old_agent.key,
50 name: old_agent.name,
51 url: old_agent.url,
52 metadata: old_agent.metadata,
53 registration_block: old_agent.registration_block,
54 weight_penalty_factor: old_agent.weight_penalty_factor,
55 fees: old_agent.fees,
56 last_update_block: old_agent.registration_block,
57 },
58 )
59 }
60
61 Weight::zero()
62 }
63 }
64}
65
66pub mod v5 {
67 use pallet_torus0_api::NamespacePath;
68 use polkadot_sdk::{
69 frame_support::{migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade},
70 sp_tracing::{error, info},
71 sp_weights::Weight,
72 };
73
74 use crate::{
75 Agents, BurnConfig, Config, Pallet, burn::BurnConfiguration, namespace::NamespaceOwnership,
76 };
77
78 pub mod storage {
79 use polkadot_sdk::frame_support::{pallet_prelude::*, storage_alias};
80
81 use crate::AccountIdOf;
82
83 #[storage_alias]
84 pub type Namespaces<T: crate::Config> = StorageDoubleMap<
85 crate::Pallet<T>,
86 Blake2_128Concat,
87 AccountIdOf<T>,
88 Blake2_128Concat,
89 pallet_torus0_api::NamespacePath,
90 crate::namespace::NamespaceMetadata<T>,
91 >;
92
93 #[storage_alias]
94 pub type NamespaceCount<T: crate::Config> =
95 StorageMap<crate::Pallet<T>, Blake2_128Concat, AccountIdOf<T>, u32, ValueQuery>;
96 }
97
98 pub type Migration<T, W> = VersionedMigration<4, 5, MigrateToV5<T>, Pallet<T>, W>;
99 pub struct MigrateToV5<T>(core::marker::PhantomData<T>);
100
101 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV5<T> {
102 fn on_runtime_upgrade() -> Weight {
103 BurnConfig::<T>::set(BurnConfiguration {
104 min_burn: 15000000000000000000, max_burn: 1000000000000000000000, max_registrations_per_interval: 16,
107 ..BurnConfig::<T>::get()
108 });
109
110 let _ = storage::Namespaces::<T>::clear(u32::MAX, None);
111 let _ = storage::NamespaceCount::<T>::clear(u32::MAX, None);
112
113 let path = NamespacePath::agent_root();
114 #[allow(deprecated)]
115 if let Err(err) =
116 crate::namespace::create_namespace0::<T>(NamespaceOwnership::System, path, false)
117 {
118 error!("failed to create root agent namespace: {err:?}");
119 return Weight::default();
120 }
121
122 info!("created root agent namespace");
123
124 for (id, agent) in Agents::<T>::iter() {
125 let old_name = agent.name.clone();
126 let Ok(agent_name) = core::str::from_utf8(&agent.name) else {
127 error!("agent name is not utf-8: {:?}", agent.name);
128 continue;
129 };
130
131 let agent_name = agent_name.trim().to_ascii_lowercase().replace(' ', "-");
132
133 let Ok(bounded_name) = agent_name.as_bytes().to_vec().try_into() else {
134 error!("cannot lower case agent {agent_name:?}");
135 continue;
136 };
137
138 let path = match NamespacePath::new_agent_root(agent_name.as_bytes()) {
139 Ok(path) => path,
140 Err(err) => {
141 error!("cannot create path for agent {agent_name:?}: {err:?}");
142 continue;
143 }
144 };
145
146 Agents::<T>::mutate_extant(id.clone(), |agent| {
147 agent.name = bounded_name;
148 });
149
150 #[allow(deprecated)]
151 if let Err(err) = crate::namespace::create_namespace0::<T>(
152 NamespaceOwnership::Account(id.clone()),
153 path.clone(),
154 false,
155 ) {
156 error!("cannot create namespace for agent {agent_name:?}: {err:?}");
157
158 Agents::<T>::mutate_extant(id.clone(), |agent| {
159 agent.name = old_name;
160 });
161 } else {
162 info!("created namespace entry for agent {agent_name:?}: {path:?}");
163 }
164 }
165
166 Weight::default()
167 }
168 }
169}
170
171pub mod v6 {
172
173 use polkadot_sdk::{
174 frame_support::{
175 migrations::VersionedMigration,
176 traits::{Currency, Imbalance, NamedReservableCurrency, UncheckedOnRuntimeUpgrade},
177 },
178 sp_core::Get,
179 sp_std::collections::btree_set::BTreeSet,
180 sp_tracing::{error, info, warn},
181 sp_weights::Weight,
182 };
183
184 use crate::{Config, Pallet, stake::STAKE_IDENTIFIER};
185
186 pub type Migration<T, W> = VersionedMigration<5, 6, MigrateToV6<T>, Pallet<T>, W>;
187 pub struct MigrateToV6<T>(core::marker::PhantomData<T>);
188
189 impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV6<T> {
190 fn on_runtime_upgrade() -> Weight {
191 let ed = T::ExistentialDeposit::get();
192 let mut minted = 0u128;
193
194 let total_stake_before = crate::TotalStake::<T>::get();
195 let total_issuance_before = T::Currency::total_issuance();
196 let total_tokens_before = total_stake_before.saturating_add(total_issuance_before);
197
198 for (staker, staked, original_stake) in crate::StakingTo::<T>::iter() {
199 let free = T::Currency::free_balance(&staker);
200
201 let mint = original_stake;
202 let stake = if free < ed {
203 original_stake.checked_sub(ed).unwrap_or_default()
204 } else {
205 original_stake
206 };
207
208 let imbalance = T::Currency::deposit_creating(&staker, mint);
209 if imbalance.peek() != mint {
210 error!(
211 "failed to mint {mint} stake tokens for account {staker:?}: actual {}",
212 imbalance.peek()
213 );
214 continue;
215 }
216
217 if stake > 0 {
218 if let Err(err) = T::Currency::reserve_named(STAKE_IDENTIFIER, &staker, stake) {
219 error!(
220 "failed to reserve {stake} stake tokens for account {staker:?}: {err:?}"
221 );
222 }
223 }
224
225 if original_stake != stake {
226 let diff = mint.saturating_sub(stake);
227 warn!(
228 "updating total stake for a difference of {diff} tokens for stake {staker:?} -> {staked:?}",
229 );
230
231 crate::TotalStake::<T>::mutate(|total| {
232 *total = total.saturating_sub(diff);
233 });
234 crate::StakingTo::<T>::mutate(&staker, &staked, |total| {
235 if let Some(total) = total {
236 *total = stake;
237 }
238 });
239 crate::StakedBy::<T>::mutate(&staked, &staker, |total| {
240 if let Some(total) = total {
241 *total = stake;
242 }
243 });
244 }
245
246 minted = minted.saturating_add(mint);
247 }
248
249 let total_staking_to: u128 = crate::StakingTo::<T>::iter_values().sum();
250 let total_staked_by: u128 = crate::StakedBy::<T>::iter_values().sum();
251 let total_reserved: u128 = crate::StakingTo::<T>::iter_keys()
252 .map(|(staker, _)| staker)
253 .collect::<BTreeSet<_>>()
254 .into_iter()
255 .map(|staker| T::Currency::reserved_balance_named(STAKE_IDENTIFIER, &staker))
256 .sum();
257
258 let total_stake_after = crate::TotalStake::<T>::get();
259 let total_issuance_after = T::Currency::total_issuance();
260
261 info!(
262 "total stake minted: {minted}. total issuance: {total_issuance_after}. total issuance before: {total_issuance_before}"
263 );
264
265 if total_issuance_after != total_tokens_before {
266 error!("total issuance does not match total tokens before migration");
267 }
268
269 if total_staking_to != total_staked_by {
270 error!("total staking to does not match total staked by");
271 }
272
273 if total_staking_to != total_stake_after {
274 error!("total staking to does not match total staked after");
275 }
276
277 if total_reserved != total_stake_after {
278 error!(
279 "total reserved balance does not match total tracked state: {total_reserved} != {total_stake_after}"
280 );
281 }
282
283 Weight::default()
284 }
285 }
286}