pallet_permission0/
migrations.rs

1pub mod v5 {
2    use num_traits::Zero;
3    use polkadot_sdk::{
4        frame_support::{migrations::VersionedMigration, traits::UncheckedOnRuntimeUpgrade},
5        sp_runtime::BoundedBTreeMap,
6        sp_tracing::warn,
7        sp_weights::Weight,
8    };
9
10    use crate::{
11        Config, EmissionAllocation, Pallet, PermissionId, PermissionScope,
12        permission::CuratorScope, permission::NamespaceScope,
13    };
14
15    pub type Migration<T, W> = VersionedMigration<3, 5, MigrateToV4<T>, Pallet<T>, W>;
16    pub struct MigrateToV4<T>(core::marker::PhantomData<T>);
17
18    mod old_storage {
19        use codec::{Decode, Encode, MaxEncodedLen};
20        use pallet_torus0_api::NamespacePath;
21        use polkadot_sdk::{
22            frame_support::Identity,
23            frame_support_procedural::storage_alias,
24            polkadot_sdk_frame::prelude::BlockNumberFor,
25            sp_runtime::{BoundedBTreeSet, BoundedVec},
26        };
27        use scale_info::TypeInfo;
28
29        use crate::{
30            AccountIdOf, Config, CuratorPermissions, EmissionScope, Pallet, PermissionId,
31            permission::{EnforcementAuthority, PermissionDuration},
32        };
33
34        #[storage_alias]
35        pub type Permissions<T: Config> =
36            StorageMap<Pallet<T>, Identity, PermissionId, PermissionContract<T>>;
37
38        #[storage_alias]
39        pub type PermissionsByGrantor<T: Config> = StorageMap<
40            Pallet<T>,
41            Identity,
42            AccountIdOf<T>,
43            BoundedVec<PermissionId, <T as Config>::MaxTargetsPerPermission>,
44        >;
45
46        #[storage_alias]
47        pub type PermissionsByGrantee<T: Config> = StorageMap<
48            Pallet<T>,
49            Identity,
50            AccountIdOf<T>,
51            BoundedVec<PermissionId, <T as Config>::MaxTargetsPerPermission>,
52        >;
53
54        #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
55        #[scale_info(skip_type_params(T))]
56        pub struct PermissionContract<T: crate::Config> {
57            pub grantor: T::AccountId,
58            pub grantee: T::AccountId,
59            pub scope: PermissionScope<T>,
60            pub duration: PermissionDuration<T>,
61            pub revocation: RevocationTerms<T>,
62            /// Enforcement authority that can toggle the permission
63            pub enforcement: EnforcementAuthority<T>,
64            /// Last execution block
65            pub last_execution: Option<BlockNumberFor<T>>,
66            /// Number of times the permission was executed
67            pub execution_count: u32,
68            /// Parent permission ID (None for root permissions)
69            pub parent: Option<PermissionId>,
70            pub created_at: BlockNumberFor<T>,
71        }
72
73        /// Defines what the permission applies to
74        #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
75        #[scale_info(skip_type_params(T))]
76        pub enum PermissionScope<T: Config> {
77            Emission(EmissionScope<T>),
78            Curator(CuratorScope<T>),
79            Namespace(NamespaceScope<T>),
80        }
81
82        /// Scope for namespace permissions
83        #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
84        #[scale_info(skip_type_params(T))]
85        pub struct NamespaceScope<T: Config> {
86            /// Set of namespace paths this permission delegates access to
87            pub paths: BoundedBTreeSet<NamespacePath, T::MaxNamespacesPerPermission>,
88        }
89
90        #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
91        #[scale_info(skip_type_params(T))]
92        pub struct CuratorScope<T: Config> {
93            pub flags: CuratorPermissions,
94            pub cooldown: Option<BlockNumberFor<T>>,
95        }
96
97        #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
98        #[scale_info(skip_type_params(T))]
99        pub enum RevocationTerms<T: Config> {
100            /// Cannot be revoked
101            Irrevocable,
102            /// Can be revoked by the grantor at any time
103            RevocableByGrantor,
104            /// Can be revoked by third party arbiters
105            RevocableByArbiters {
106                accounts: BoundedVec<T::AccountId, T::MaxRevokersPerPermission>,
107                required_votes: u32,
108            },
109            /// Time-based revocation
110            RevocableAfter(BlockNumberFor<T>),
111        }
112    }
113
114    impl<T: Config> UncheckedOnRuntimeUpgrade for MigrateToV4<T> {
115        fn on_runtime_upgrade() -> Weight {
116            let _ = old_storage::PermissionsByGrantor::<T>::clear(u32::MAX, None);
117            let _ = old_storage::PermissionsByGrantee::<T>::clear(u32::MAX, None);
118
119            for (pid, contract) in old_storage::Permissions::<T>::iter() {
120                if let old_storage::PermissionScope::Emission(scope) = &contract.scope {
121                    if let EmissionAllocation::Streams(streams) = &scope.allocation {
122                        for stream in streams.keys() {
123                            if !crate::AccumulatedStreamAmounts::<T>::contains_key((
124                                &contract.grantor,
125                                &stream,
126                                &pid,
127                            )) {
128                                warn!(
129                                    "inserting accumulated stream value for broken contract: {pid}, stream: {stream}"
130                                );
131                                crate::AccumulatedStreamAmounts::<T>::set(
132                                    (&contract.grantor, &stream, &pid),
133                                    Some(Zero::zero()),
134                                );
135                            }
136                        }
137                    }
138                }
139
140                crate::PermissionsByDelegator::<T>::mutate(&contract.grantor, |pids| {
141                    let _ = pids.try_push(pid);
142                });
143
144                crate::PermissionsByRecipient::<T>::mutate(&contract.grantee, |pids| {
145                    let _ = pids.try_push(pid);
146                });
147
148                let scope = match contract.scope {
149                    old_storage::PermissionScope::Emission(scope) => {
150                        PermissionScope::Emission(scope)
151                    }
152                    old_storage::PermissionScope::Curator(scope) => PermissionScope::Curator({
153                        let mut flags = BoundedBTreeMap::new();
154                        let _ = flags.try_insert(Option::<PermissionId>::None, scope.flags);
155                        CuratorScope {
156                            flags,
157                            cooldown: scope.cooldown,
158                        }
159                    }),
160                    old_storage::PermissionScope::Namespace(scope) => PermissionScope::Namespace({
161                        let mut paths = BoundedBTreeMap::new();
162                        let _ = paths.try_insert(Option::<PermissionId>::None, scope.paths);
163                        NamespaceScope { paths }
164                    }),
165                };
166
167                let revocation = match contract.revocation {
168                    old_storage::RevocationTerms::Irrevocable => {
169                        crate::RevocationTerms::Irrevocable
170                    }
171                    old_storage::RevocationTerms::RevocableByGrantor => {
172                        crate::RevocationTerms::RevocableByDelegator
173                    }
174                    old_storage::RevocationTerms::RevocableByArbiters {
175                        accounts,
176                        required_votes,
177                    } => crate::RevocationTerms::RevocableByArbiters {
178                        accounts,
179                        required_votes,
180                    },
181                    old_storage::RevocationTerms::RevocableAfter(block) => {
182                        crate::RevocationTerms::RevocableAfter(block)
183                    }
184                };
185
186                let mut new = crate::PermissionContract::<T>::new(
187                    contract.grantor,
188                    contract.grantee,
189                    scope,
190                    contract.duration,
191                    revocation,
192                    contract.enforcement,
193                    1,
194                );
195
196                new.created_at = contract.created_at;
197                #[allow(deprecated)]
198                new.set_execution_info(contract.last_execution, contract.execution_count);
199
200                crate::Permissions::<T>::set(pid, Some(new));
201            }
202
203            Weight::zero()
204        }
205    }
206}