pallet_torus0/
migrations.rs

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,   // 15tors
105                max_burn: 1000000000000000000000, // 1000tors
106                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}