1use crate::{
2 Config, Error, Event, Pallet, PermissionContract, PermissionDuration, PermissionId,
3 PermissionScope, Permissions, PermissionsByDelegator, RevocationTerms, generate_permission_id,
4 permission::NamespaceScope, permission::add_permission_indices,
5};
6use pallet_permission0_api::Permission0NamespacesApi;
7use pallet_torus0_api::{NamespacePath, NamespacePathInner, Torus0Api};
8use polkadot_sdk::{
9 frame_support::{dispatch::DispatchResult, ensure},
10 frame_system::{self, ensure_signed},
11 polkadot_sdk_frame::prelude::OriginFor,
12 sp_core::Get,
13 sp_runtime::{BoundedBTreeMap, BoundedBTreeSet, DispatchError},
14 sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet},
15};
16
17impl<T: Config> Permission0NamespacesApi<T::AccountId, NamespacePath> for Pallet<T> {
18 fn is_delegating_namespace(delegator: &T::AccountId, path: &NamespacePath) -> bool {
19 PermissionsByDelegator::<T>::get(delegator)
20 .iter()
21 .any(|id| {
22 Permissions::<T>::get(id)
23 .filter(|permission| {
24 if let PermissionScope::Namespace(scope) = &permission.scope {
25 for other in scope.paths.values().flat_map(|k| k.iter()) {
26 if other == path
27 || path.is_parent_of(other)
28 || other.is_parent_of(path)
29 {
30 return true;
31 }
32 }
33 }
34
35 false
36 })
37 .is_some()
38 })
39 }
40}
41
42pub fn delegate_namespace_permission_impl<T: Config>(
43 delegator: OriginFor<T>,
44 recipient: T::AccountId,
45 paths: BoundedBTreeMap<
46 Option<PermissionId>,
47 BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
48 T::MaxNamespacesPerPermission,
49 >,
50 duration: PermissionDuration<T>,
51 revocation: RevocationTerms<T>,
52 max_instances: u32,
53) -> Result<PermissionId, DispatchError> {
54 let delegator = ensure_signed(delegator)?;
55
56 ensure!(
57 T::Torus::is_agent_registered(&delegator),
58 Error::<T>::NotRegisteredAgent
59 );
60 ensure!(
61 T::Torus::is_agent_registered(&recipient),
62 Error::<T>::NotRegisteredAgent
63 );
64
65 ensure!(max_instances > 0, Error::<T>::NotEnoughInstances);
66
67 let total_multi_parent = paths.keys().filter(|p| p.is_some()).count();
68 ensure!(total_multi_parent <= 1, Error::<T>::MultiParentForbidden);
69
70 let mut total_paths = 0usize;
71 let mut parents = polkadot_sdk::sp_std::vec::Vec::with_capacity(paths.len());
72
73 let paths = paths
74 .iter()
75 .map(|(pid, paths)| {
76 total_paths = total_paths.saturating_add(paths.len());
77 ensure!(
78 total_paths as u32 <= T::MaxNamespacesPerPermission::get(),
79 Error::<T>::TooManyNamespaces
80 );
81
82 let namespaces = if let Some(pid) = pid {
83 let Some(parent) = Permissions::<T>::get(pid) else {
84 return Err(Error::<T>::ParentPermissionNotFound.into());
85 };
86
87 let PermissionScope::Namespace(namespace) = &parent.scope else {
88 return Err(Error::<T>::UnsupportedPermissionType.into());
89 };
90
91 ensure!(
92 namespace.recipient == delegator,
93 Error::<T>::NotPermissionRecipient
94 );
95
96 ensure!(
97 max_instances <= parent.available_instances().unwrap_or_default(),
98 Error::<T>::NotEnoughInstances
99 );
100
101 ensure!(
102 RevocationTerms::<T>::is_weaker(&parent.revocation, &revocation),
103 Error::<T>::RevocationTermsTooStrong
104 );
105
106 parents.push(pid);
107
108 resolve_paths::<T>(&delegator, Some((*pid, namespace)), paths)
109 } else {
110 resolve_paths::<T>(&delegator, None, paths)
111 }?;
112
113 Ok((*pid, namespaces))
114 })
115 .collect::<Result<BTreeMap<_, _>, DispatchError>>()?;
116
117 let paths = paths
118 .try_into()
119 .map_err(|_| Error::<T>::TooManyNamespaces)?;
120
121 let scope = PermissionScope::Namespace(NamespaceScope {
122 recipient: recipient.clone(),
123 paths,
124 children: Default::default(),
125 max_instances,
126 });
127 let permission_id = generate_permission_id::<T>(&delegator, &scope)?;
128
129 for parent in parents {
130 Permissions::<T>::mutate_extant(parent, |parent| {
131 if let Some(children) = parent.children_mut() {
132 children.try_insert(permission_id).ok()
133 } else {
134 Some(false)
135 }
136 })
137 .ok_or(Error::<T>::TooManyChildren)?;
138 }
139
140 let contract = PermissionContract::<T>::new(
141 delegator,
142 scope,
143 duration,
144 revocation,
145 crate::EnforcementAuthority::None,
146 );
147
148 Permissions::<T>::insert(permission_id, &contract);
149 add_permission_indices::<T>(
150 &contract.delegator,
151 core::iter::once(&recipient),
152 permission_id,
153 )?;
154
155 <Pallet<T>>::deposit_event(Event::PermissionDelegated {
156 delegator: contract.delegator,
157 permission_id,
158 });
159
160 Ok(permission_id)
161}
162
163const MAX_DELEGATION_DEPTH: u32 = 5;
165
166fn check_namespace_delegation_depth<T: Config>(
168 namespace_path: &NamespacePath,
169 parent_permission_id: Option<PermissionId>,
170 current_depth: u32,
171) -> Result<(), DispatchError> {
172 if current_depth > MAX_DELEGATION_DEPTH {
173 return Err(Error::<T>::DelegationDepthExceeded.into());
174 }
175
176 let Some(parent_id) = parent_permission_id else {
177 return Ok(());
178 };
179
180 let Some(parent_permission) = Permissions::<T>::get(parent_id) else {
181 return Err(Error::<T>::ParentPermissionNotFound.into());
182 };
183
184 let PermissionScope::Namespace(parent_scope) = &parent_permission.scope else {
185 return Err(Error::<T>::UnsupportedPermissionType.into());
186 };
187
188 for (grandparent_id, namespace_set) in parent_scope.paths.iter() {
189 if namespace_set.contains(namespace_path) {
190 return check_namespace_delegation_depth::<T>(
191 namespace_path,
192 *grandparent_id,
193 current_depth.saturating_add(1),
194 );
195 }
196
197 for parent_namespace in namespace_set.iter() {
198 if parent_namespace.is_parent_of(namespace_path) {
199 return check_namespace_delegation_depth::<T>(
200 parent_namespace,
201 *grandparent_id,
202 current_depth.saturating_add(1),
203 );
204 }
205 }
206 }
207
208 Ok(())
209}
210
211fn resolve_paths<T: Config>(
212 delegator: &T::AccountId,
213 parent: Option<(PermissionId, &NamespaceScope<T>)>,
214 paths: &BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
215) -> Result<BoundedBTreeSet<NamespacePath, T::MaxNamespacesPerPermission>, DispatchError> {
216 let children = paths.iter().map(|path| {
217 NamespacePath::new_agent(path).map_err(|_| Error::<T>::NamespacePathIsInvalid.into())
218 });
219
220 let paths = if let Some((parent_pid, parent)) = parent {
221 let children = children.collect::<Result<BTreeSet<_>, DispatchError>>()?;
222 let matched_paths = parent
223 .paths
224 .values()
225 .flat_map(|p_path| p_path.iter())
226 .filter_map(|parent_path| {
227 if children.contains(parent_path) {
228 Some(())
229 } else {
230 let agent_name = parent_path.agent_name()?;
231 let child_path = children
232 .iter()
233 .find(|child| parent_path.is_parent_of(child))?;
234
235 let agent = T::Torus::find_agent_by_name(agent_name)?;
236 if !T::Torus::namespace_exists(&agent, child_path) {
237 return None;
238 }
239
240 Some(())
241 }
242 })
243 .count();
244
245 ensure!(
246 matched_paths == children.len(),
247 Error::<T>::ParentPermissionNotFound
248 );
249
250 for child_path in &children {
251 check_namespace_delegation_depth::<T>(child_path, Some(parent_pid), 1)?;
252 }
253
254 children
255 } else {
256 children
257 .map(|path| {
258 path.and_then(|path| {
259 if T::Torus::namespace_exists(delegator, &path) {
260 Ok(path)
261 } else {
262 Err(Error::<T>::NamespaceDoesNotExist.into())
263 }
264 })
265 })
266 .collect::<Result<BTreeSet<_>, DispatchError>>()?
267 };
268
269 paths
270 .try_into()
271 .map_err(|_| Error::<T>::TooManyNamespaces.into())
272}
273
274pub(crate) fn update_namespace_permission<T: Config>(
275 origin: OriginFor<T>,
276 permission_id: PermissionId,
277 max_instances: u32,
278) -> DispatchResult {
279 let who = ensure_signed(origin)?;
280
281 let permission = Permissions::<T>::get(permission_id);
282
283 let Some(mut permission) = permission else {
284 return Err(Error::<T>::PermissionNotFound.into());
285 };
286
287 ensure!(permission.delegator == who, Error::<T>::NotAuthorizedToEdit);
288
289 let PermissionScope::Namespace(mut namespace) = permission.scope.clone() else {
290 return Err(Error::<T>::NotEditable.into());
291 };
292
293 if max_instances == namespace.max_instances {
294 return Ok(());
295 } else if max_instances > namespace.max_instances {
296 for parent in namespace.paths.keys().copied().flatten() {
297 let Some(parent) = Permissions::<T>::get(parent) else {
298 continue;
299 };
300
301 ensure!(
302 max_instances <= parent.available_instances().unwrap_or_default(),
303 Error::<T>::NotEnoughInstances
304 );
305 }
306 } else {
307 ensure!(permission.is_updatable(), Error::<T>::NotAuthorizedToEdit);
308 ensure!(
309 max_instances >= permission.used_instances(),
310 Error::<T>::NotEnoughInstances
311 );
312 }
313
314 namespace.max_instances = max_instances;
315
316 permission.scope = PermissionScope::Namespace(namespace);
317 permission.last_update = frame_system::Pallet::<T>::block_number();
318
319 Permissions::<T>::set(permission_id, Some(permission));
320
321 Ok(())
322}