pallet_permission0/ext/
namespace_impl.rs

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
163/// Maximum allowed delegation depth for namespaces
164const MAX_DELEGATION_DEPTH: u32 = 5;
165
166/// Check the delegation depth of a namespace by traversing up the permission chain
167fn 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}