Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .helix/languages.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
cargo.extraEnv = { SKIP_WASM_BUILD = "true" }
cargo.features = ["runtime-benchmarks"]
check.extraEnv = { SKIP_WASM_BUILD = "true" }
check.overrideCommand = ["cargo", "check", "--tests", "--all", "--message-format=json"]
check.features = ["runtime-benchmarks"]
check.overrideCommand = ["cargo", "check", "--message-format=json", "--tests", "--examples", "--all"]
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ build-testnet:
# Development

check: fmt
cargo clippy --tests -- -D clippy::all
cargo clippy --tests --features testnet,runtime-benchmarks -- -D clippy::all

test: check
SKIP_WASM_BUILD=1 cargo nextest run
Expand Down
6 changes: 4 additions & 2 deletions pallets/emission0/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ mod benchmarks {
<T::Governance>::force_set_whitelisted(&module_key2);

<T::Governance>::set_allocator(&module_key2);
let _ =
<T::Currency>::deposit_creating(&module_key2, <T::Torus>::min_validator_stake() * 2);
let _ = <T::Currency>::deposit_creating(
&module_key2,
<T::Torus>::min_validator_stake().saturating_mul(2),
);

<T::Torus>::force_set_stake(
&module_key2,
Expand Down
6 changes: 3 additions & 3 deletions pallets/emission0/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! Autogenerated weights for `pallet_emission0`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0
//! DATE: 2025-08-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `Luizs-MacBook-Pro.local`, CPU: `<UNKNOWN>`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
Expand Down Expand Up @@ -94,7 +94,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// Proof Size summary in bytes:
// Measured: `333`
// Estimated: `3529`
// Minimum execution time: 10_000_000 picoseconds.
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(10_000_000, 3529)
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
Expand Down Expand Up @@ -151,7 +151,7 @@ impl WeightInfo for () {
// Proof Size summary in bytes:
// Measured: `333`
// Estimated: `3529`
// Minimum execution time: 10_000_000 picoseconds.
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(10_000_000, 3529)
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
Expand Down
150 changes: 75 additions & 75 deletions pallets/governance/src/weights.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions pallets/permission0/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,8 @@ polkadot_sdk::sp_api::decl_runtime_apis! {
/// The root stream ID is assigned by the system when emitting
/// tokens from the STAKE as rewards.
fn root_stream_id_for_account(account_id: AccountId) -> StreamId;

/// Calculates the number of available instances for a given path.
fn available_namespace_instances(permission_id: PermissionId, path: pallet_torus0_api::NamespacePathInner) -> Result<u32, DispatchError> ;
}
}
134 changes: 82 additions & 52 deletions pallets/permission0/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::*;

#[benchmarks]
mod benchmarks {
use codec::alloc::string::ToString;
use polkadot_sdk::{
sp_core::TryCollect, sp_std::collections::btree_map::BTreeMap, sp_std::vec,
};
Expand Down Expand Up @@ -290,7 +291,6 @@ mod benchmarks {

#[benchmark]
fn update_namespace_permission() {
use pallet_torus0_api::NamespacePathInner;
use polkadot_sdk::sp_std::collections::btree_set::BTreeSet;

let alice: T::AccountId = account("alice", 0, 0);
Expand All @@ -310,21 +310,15 @@ mod benchmarks {
.expect("failed to register namespace");
}

let mut alice_paths_set: BTreeSet<NamespacePathInner> = BTreeSet::new();
alice_paths_set.insert(b"agent.alice.network".to_vec().try_into().unwrap());
alice_paths_set.insert(b"agent.alice.compute".to_vec().try_into().unwrap());
let alice_paths_bounded: BoundedBTreeSet<
NamespacePathInner,
T::MaxNamespacesPerPermission,
> = alice_paths_set
let alice_paths_set = BTreeSet::from([
b"agent.alice.network".to_vec().try_into().unwrap(),
b"agent.alice.compute".to_vec().try_into().unwrap(),
]);
let alice_paths_bounded: BoundedBTreeSet<_, _> = alice_paths_set
.try_into()
.expect("failed to create bounded set");

let mut alice_paths: BoundedBTreeMap<
Option<PermissionId>,
BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
T::MaxNamespacesPerPermission,
> = BoundedBTreeMap::new();
let mut alice_paths = BoundedBTreeMap::new();
alice_paths
.try_insert(None, alice_paths_bounded)
.expect("failed to insert alice paths");
Expand All @@ -345,7 +339,6 @@ mod benchmarks {

#[benchmark]
fn delegate_namespace_permission() {
use pallet_torus0_api::NamespacePathInner;
use polkadot_sdk::sp_std::collections::btree_set::BTreeSet;

let alice: T::AccountId = account("alice", 0, 0);
Expand Down Expand Up @@ -386,6 +379,28 @@ mod benchmarks {
.expect("failed to register pollution namespace");
}

let alice_n = &[
b"agent.alice.n.01",
b"agent.alice.n.02",
b"agent.alice.n.03",
b"agent.alice.n.04",
b"agent.alice.n.05",
b"agent.alice.n.06",
b"agent.alice.n.07",
b"agent.alice.n.08",
b"agent.alice.n.09",
b"agent.alice.n.10",
b"agent.alice.n.11",
b"agent.alice.n.12",
b"agent.alice.n.13",
b"agent.alice.n.14",
b"agent.alice.n.15",
];
for namespace_bytes in alice_n {
T::Torus::force_register_namespace(&alice, namespace_bytes.to_vec())
.expect("failed to register pollution namespace");
}

for namespace_bytes in [
b"agent.bob.compute".to_vec(),
b"agent.bob.compute.cpu".to_vec(),
Expand All @@ -404,20 +419,18 @@ mod benchmarks {
.expect("failed to register pollution namespace");
}

let mut alice_bob_set: BTreeSet<NamespacePathInner> = BTreeSet::new();
alice_bob_set.insert(b"agent.alice.compute".to_vec().try_into().unwrap());
alice_bob_set.insert(b"agent.alice.network".to_vec().try_into().unwrap());
alice_bob_set.insert(b"agent.alice.storage".to_vec().try_into().unwrap());
let alice_bob_set: BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission> =
alice_bob_set
.try_into()
.expect("failed to create bounded set");
let alice_bob_set = BTreeSet::from([
b"agent.alice.compute".to_vec().try_into().unwrap(),
b"agent.alice.network".to_vec().try_into().unwrap(),
b"agent.alice.storage".to_vec().try_into().unwrap(),
b"agent.alice.n".to_vec().try_into().unwrap(),
b"agent.alice.n".to_vec().try_into().unwrap(),
]);
let alice_bob_set: BoundedBTreeSet<_, _> = alice_bob_set
.try_into()
.expect("failed to create bounded set");

let mut alice_paths: BoundedBTreeMap<
Option<PermissionId>,
BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
T::MaxNamespacesPerPermission,
> = BoundedBTreeMap::new();
let mut alice_paths = BoundedBTreeMap::new();
alice_paths
.try_insert(None, alice_bob_set)
.expect("failed to insert alice paths");
Expand All @@ -432,19 +445,16 @@ mod benchmarks {
)
.expect("failed to create alice->bob permission");

let mut bob_charlie_set: BTreeSet<NamespacePathInner> = BTreeSet::new();
bob_charlie_set.insert(b"agent.alice.compute.gpu".to_vec().try_into().unwrap());
bob_charlie_set.insert(b"agent.alice.network.subnet1".to_vec().try_into().unwrap());
let bob_charlie_set: BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission> =
bob_charlie_set
.try_into()
.expect("failed to create bounded set");
let bob_charlie_set = BTreeSet::from([
b"agent.alice.compute.gpu".to_vec().try_into().unwrap(),
b"agent.alice.network.subnet1".to_vec().try_into().unwrap(),
b"agent.alice.n".to_vec().try_into().unwrap(),
]);
let bob_charlie_set: BoundedBTreeSet<_, _> = bob_charlie_set
.try_into()
.expect("failed to create bounded set");

let mut bob_paths: BoundedBTreeMap<
Option<PermissionId>,
BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
T::MaxNamespacesPerPermission,
> = BoundedBTreeMap::new();
let mut bob_paths = BoundedBTreeMap::new();
bob_paths
.try_insert(Some(alice_permission_id), bob_charlie_set)
.expect("failed to insert bob paths");
Expand All @@ -459,25 +469,45 @@ mod benchmarks {
)
.expect("failed to create bob->charlie permission");

let mut charlie_dave_set: BTreeSet<NamespacePathInner> = BTreeSet::new();
charlie_dave_set.insert(b"agent.alice.compute.gpu.h100".to_vec().try_into().unwrap());
charlie_dave_set.insert(
for (i, path) in alice_n.iter().enumerate() {
let acc: T::AccountId = account("acc", 100.saturating_add(i as u32), 0);
let mut acc_name = "acc".to_string();
acc_name.push_str(&i.to_string());

T::Torus::force_register_agent(&acc, acc_name.as_bytes().to_vec(), vec![], vec![])
.expect("failed to register acc");

let set = BTreeSet::from([path.to_vec().try_into().unwrap()]);
let set: BoundedBTreeSet<_, _> = set.try_into().expect("failed to create bounded set");
let mut paths = BoundedBTreeMap::new();
paths
.try_insert(Some(bob_permission_id), set)
.expect("failed to insert bob paths");

ext::namespace_impl::delegate_namespace_permission_impl::<T>(
RawOrigin::Signed(charlie.clone()).into(),
acc.clone(),
paths,
PermissionDuration::Indefinite,
RevocationTerms::RevocableByDelegator,
1,
)
.expect("failed to create bob->charlie permission");
}

let charlie_dave_set = BTreeSet::from([
b"agent.alice.compute.gpu.h100".to_vec().try_into().unwrap(),
b"agent.alice.network.subnet1.fast"
.to_vec()
.try_into()
.unwrap(),
);
]);

let charlie_dave_set: BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission> =
charlie_dave_set
.try_into()
.expect("failed to create bounded set");
let charlie_dave_set: BoundedBTreeSet<_, _> = charlie_dave_set
.try_into()
.expect("failed to create bounded set");

let mut charlie_paths: BoundedBTreeMap<
Option<PermissionId>,
BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
T::MaxNamespacesPerPermission,
> = BoundedBTreeMap::new();
let mut charlie_paths = BoundedBTreeMap::new();
charlie_paths
.try_insert(Some(bob_permission_id), charlie_dave_set)
.expect("failed to insert charlie paths");
Expand Down
70 changes: 34 additions & 36 deletions pallets/permission0/src/ext/namespace_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,16 @@ pub fn delegate_namespace_permission_impl<T: Config>(
Error::<T>::NotPermissionRecipient
);

ensure!(
max_instances <= parent.available_instances().unwrap_or_default(),
Error::<T>::NotEnoughInstances
);

ensure!(
RevocationTerms::<T>::is_weaker(&parent.revocation, &revocation),
Error::<T>::RevocationTermsTooStrong
);

parents.push(pid);

resolve_paths::<T>(&delegator, Some((*pid, namespace)), paths)
resolve_paths::<T>(&delegator, Some((*pid, namespace)), paths, max_instances)
} else {
resolve_paths::<T>(&delegator, None, paths)
resolve_paths::<T>(&delegator, None, paths, max_instances)
}?;

Ok((*pid, namespaces))
Expand Down Expand Up @@ -211,49 +206,52 @@ fn check_namespace_delegation_depth<T: Config>(
fn resolve_paths<T: Config>(
delegator: &T::AccountId,
parent: Option<(PermissionId, &NamespaceScope<T>)>,
paths: &BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
new_paths: &BoundedBTreeSet<NamespacePathInner, T::MaxNamespacesPerPermission>,
instances: u32,
) -> Result<BoundedBTreeSet<NamespacePath, T::MaxNamespacesPerPermission>, DispatchError> {
let children = paths.iter().map(|path| {
let new_paths = new_paths.iter().map(|path| {
NamespacePath::new_agent(path).map_err(|_| Error::<T>::NamespacePathIsInvalid.into())
});

let paths = if let Some((parent_pid, parent)) = parent {
let children = children.collect::<Result<BTreeSet<_>, DispatchError>>()?;
let matched_paths = parent
.paths
.values()
.flat_map(|p_path| p_path.iter())
.filter_map(|parent_path| {
if children.contains(parent_path) {
Some(())
} else {
let agent_name = parent_path.agent_name()?;
let child_path = children
.iter()
.find(|child| parent_path.is_parent_of(child))?;

let agent = T::Torus::find_agent_by_name(agent_name)?;
if !T::Torus::namespace_exists(&agent, child_path) {
return None;
}
let new_paths = if let Some((parent_pid, parent)) = parent {
let new_paths = new_paths.collect::<Result<BTreeSet<_>, DispatchError>>()?;

Some(())
}
let matched_paths = new_paths
.iter()
.filter(|new_path| {
parent
.paths
.values()
.flat_map(|p_path| p_path.iter())
.any(|parent_path| {
if *new_path == parent_path {
true
} else if parent_path.is_parent_of(new_path)
&& let Some(agent_name) = parent_path.agent_name()
&& let Some(agent) = T::Torus::find_agent_by_name(agent_name)
{
T::Torus::namespace_exists(&agent, new_path)
} else {
false
}
})
})
.count();

ensure!(
matched_paths == children.len(),
matched_paths == new_paths.len(),
Error::<T>::ParentPermissionNotFound
);

for child_path in &children {
check_namespace_delegation_depth::<T>(child_path, Some(parent_pid), 1)?;
for new_path in &new_paths {
check_namespace_delegation_depth::<T>(new_path, Some(parent_pid), 1)?;
}

children
parent.check_available_instances(parent_pid, new_paths.iter(), instances)?;

new_paths
} else {
children
new_paths
.map(|path| {
path.and_then(|path| {
if T::Torus::namespace_exists(delegator, &path) {
Expand All @@ -266,7 +264,7 @@ fn resolve_paths<T: Config>(
.collect::<Result<BTreeSet<_>, DispatchError>>()?
};

paths
new_paths
.try_into()
.map_err(|_| Error::<T>::TooManyNamespaces.into())
}
Expand Down
Loading
Loading