Skip to content

Commit 383a6d3

Browse files
committed
chore: add rpc
1 parent d042eab commit 383a6d3

File tree

3 files changed

+70
-23
lines changed

3 files changed

+70
-23
lines changed

pallets/permission0/api/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,8 @@ polkadot_sdk::sp_api::decl_runtime_apis! {
192192
/// The root stream ID is assigned by the system when emitting
193193
/// tokens from the STAKE as rewards.
194194
fn root_stream_id_for_account(account_id: AccountId) -> StreamId;
195+
196+
/// Calculates the number of available instances for a given path.
197+
fn available_namespace_instances(permission_id: PermissionId, path: pallet_torus0_api::NamespacePathInner) -> Result<u32, DispatchError> ;
195198
}
196199
}

pallets/permission0/src/permission/namespace.rs

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use pallet_torus0_api::NamespacePath;
33
use polkadot_sdk::{
44
frame_support::{CloneNoBound, DebugNoBound, dispatch::DispatchResult},
55
sp_runtime::{BoundedBTreeMap, BoundedBTreeSet},
6+
sp_std::vec::Vec,
67
};
78
use scale_info::TypeInfo;
89

@@ -28,22 +29,8 @@ pub struct NamespaceScope<T: Config> {
2829
}
2930

3031
impl<T: Config> NamespaceScope<T> {
31-
/// Checks that the provided paths are allowed to be delegated.
32-
/// This is true if enough instances are available and unused by
33-
/// sibilings.
34-
///
35-
/// Given a subpath, an instance is used if any parent or child
36-
/// paths from that subpath were delegated to a sibiling permission.
37-
/// Sibiling subpaths do not consume an instance relative to this
38-
/// subpath.
39-
pub(crate) fn check_available_instances<'a>(
40-
&self,
41-
this_id: PermissionId,
42-
other: impl Iterator<Item = &'a NamespacePath>,
43-
instances: u32,
44-
) -> DispatchResult {
45-
let mut sibiling_paths = self
46-
.children
32+
fn sibiling_paths(&self, this_id: PermissionId) -> impl Iterator<Item = (NamespacePath, u32)> {
33+
self.children
4734
.iter()
4835
.filter_map(|c| {
4936
if let PermissionScope::Namespace(sibiling) = Permissions::<T>::get(c)?.scope {
@@ -52,25 +39,44 @@ impl<T: Config> NamespaceScope<T> {
5239
None
5340
}
5441
})
55-
.flat_map(|sibiling| {
42+
.flat_map(move |sibiling| {
5643
sibiling
5744
.paths
5845
.into_iter()
59-
.filter(|(pid, _)| pid.as_ref().is_some_and(|pid| pid == &this_id))
46+
.filter(move |(pid, _)| pid.as_ref().is_some_and(|pid| pid == &this_id))
6047
.flat_map(|(_, paths)| paths)
6148
.map(move |path| (path, sibiling.max_instances))
6249
})
63-
.collect::<polkadot_sdk::sp_std::vec::Vec<_>>();
50+
}
51+
52+
/// Checks that the provided paths are allowed to be delegated.
53+
/// This is true if enough instances are available and unused by
54+
/// sibilings.
55+
///
56+
/// Given a subpath, an instance is used if any parent or child
57+
/// paths from that subpath were delegated to a sibiling permission.
58+
/// Sibiling subpaths do not consume an instance relative to this
59+
/// subpath.
60+
pub(crate) fn check_available_instances<'a>(
61+
&self,
62+
this_id: PermissionId,
63+
other: impl Iterator<Item = &'a NamespacePath>,
64+
instances: u32,
65+
) -> DispatchResult {
66+
let mut sibiling_paths: Vec<_> = self.sibiling_paths(this_id).collect();
6467

6568
for other in other {
66-
let mut used_instances = 0u32;
69+
let mut available_instances = self.max_instances;
6770

6871
for (sibiling_path, max_instances) in &sibiling_paths {
6972
if sibiling_path == other
7073
|| sibiling_path.is_parent_of(other)
7174
|| other.is_parent_of(sibiling_path)
7275
{
73-
used_instances = used_instances.saturating_add(*max_instances);
76+
available_instances = available_instances.saturating_sub(*max_instances);
77+
if available_instances < instances {
78+
return Err(Error::<T>::NotEnoughInstances.into());
79+
}
7480
}
7581
}
7682

@@ -86,14 +92,33 @@ impl<T: Config> NamespaceScope<T> {
8692
// Earlier paths are sibilings to later paths.
8793
sibiling_paths.push((other.clone(), instances));
8894

89-
if self.max_instances.saturating_sub(used_instances) < instances {
95+
if available_instances < instances {
9096
return Err(Error::<T>::NotEnoughInstances.into());
9197
}
9298
}
9399

94100
Ok(())
95101
}
96102

103+
/// Count the number of available instances for a given path.
104+
pub fn available_instances(&self, this_id: PermissionId, path: &NamespacePath) -> u32 {
105+
let mut available_instances = self.max_instances;
106+
107+
for (sibiling_path, max_instances) in self.sibiling_paths(this_id) {
108+
if &sibiling_path == path
109+
|| sibiling_path.is_parent_of(path)
110+
|| path.is_parent_of(&sibiling_path)
111+
{
112+
available_instances = available_instances.saturating_sub(max_instances);
113+
if available_instances == 0 {
114+
return 0;
115+
}
116+
}
117+
}
118+
119+
available_instances
120+
}
121+
97122
/// Cleanup operations when permission is revoked or expired
98123
pub(super) fn cleanup(
99124
&self,

runtime/src/apis.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,25 @@ impl_runtime_apis! {
470470
fn root_stream_id_for_account(account_id: AccountId) -> StreamId {
471471
generate_root_stream_id(&account_id)
472472
}
473+
474+
fn available_namespace_instances(
475+
permission_id: pallet_permission0_api::PermissionId,
476+
path: pallet_torus0_api::NamespacePathInner
477+
) -> Result<u32, DispatchError> {
478+
use pallet_permission0::Permissions;
479+
use pallet_torus0_api::NamespacePath;
480+
481+
let namespace_path =
482+
NamespacePath::new_agent(&path).map_err(|_| pallet_torus0::Error::<Runtime>::InvalidNamespacePath)?;
483+
484+
let permission =
485+
Permissions::<Runtime>::get(permission_id).ok_or(pallet_permission0::Error::<Runtime>::PermissionNotFound)?;
486+
let pallet_permission0::PermissionScope::Namespace(scope) = &permission.scope else {
487+
return Err(pallet_permission0::Error::<Runtime>::UnsupportedPermissionType.into());
488+
};
489+
490+
Ok(scope.available_instances(permission_id, &namespace_path))
491+
}
473492
}
474493

475494
impl pallet_torus0_api::api::Torus0RuntimeApi<Block, AccountId, Balance> for Runtime {
@@ -480,7 +499,7 @@ impl_runtime_apis! {
480499
let namespace_path =
481500
NamespacePath::new_agent(&path).map_err(|_| pallet_torus0::Error::<Runtime>::InvalidNamespacePath)?;
482501

483-
let owner = namespace::NamespaceOwnership::Account(account_id);
502+
let owner = namespace::NamespaceOwnership::Account(account_id);
484503
let missing_paths = namespace::find_missing_paths::<Runtime>(&owner, &namespace_path);
485504
namespace::calculate_cost::<Runtime>(&owner, &missing_paths)
486505
}

0 commit comments

Comments
 (0)