diff --git a/.helix/languages.toml b/.helix/languages.toml index 2de9a69..4dd6c66 100644 --- a/.helix/languages.toml +++ b/.helix/languages.toml @@ -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"] diff --git a/justfile b/justfile index 4dd36d2..bdc35e6 100644 --- a/justfile +++ b/justfile @@ -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 diff --git a/pallets/emission0/src/benchmarking.rs b/pallets/emission0/src/benchmarking.rs index 827f2db..db75711 100644 --- a/pallets/emission0/src/benchmarking.rs +++ b/pallets/emission0/src/benchmarking.rs @@ -30,8 +30,10 @@ mod benchmarks { ::force_set_whitelisted(&module_key2); ::set_allocator(&module_key2); - let _ = - ::deposit_creating(&module_key2, ::min_validator_stake() * 2); + let _ = ::deposit_creating( + &module_key2, + ::min_validator_stake().saturating_mul(2), + ); ::force_set_stake( &module_key2, diff --git a/pallets/emission0/src/weights.rs b/pallets/emission0/src/weights.rs index 9dda381..93d08dd 100644 --- a/pallets/emission0/src/weights.rs +++ b/pallets/emission0/src/weights.rs @@ -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: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -94,7 +94,7 @@ impl WeightInfo for SubstrateWeight { // 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)) @@ -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)) diff --git a/pallets/governance/src/weights.rs b/pallets/governance/src/weights.rs index b6f436b..5da7b88 100644 --- a/pallets/governance/src/weights.rs +++ b/pallets/governance/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_governance` //! //! 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: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -67,7 +67,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6` // Estimated: `3497` - // Minimum execution time: 4_000_000 picoseconds. + // Minimum execution time: 3_000_000 picoseconds. Weight::from_parts(4_000_000, 3497) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -79,12 +79,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `62` // Estimated: `3497` // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_000_000, 3497) + Weight::from_parts(5_000_000, 3497) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -98,14 +98,14 @@ impl WeightInfo for SubstrateWeight { fn add_to_whitelist() -> Weight { // Proof Size summary in bytes: // Measured: `91` - // Estimated: `71354` - // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(25_000_000, 71362) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -119,9 +119,9 @@ impl WeightInfo for SubstrateWeight { fn remove_from_whitelist() -> Weight { // Proof Size summary in bytes: // Measured: `110` - // Estimated: `71354` - // Minimum execution time: 26_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(26_000_000, 71362) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -139,13 +139,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `344` // Estimated: `6196` - // Minimum execution time: 49_000_000 picoseconds. - Weight::from_parts(50_000_000, 6196) + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(49_000_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -163,14 +163,14 @@ impl WeightInfo for SubstrateWeight { fn accept_application() -> Weight { // Proof Size summary in bytes: // Measured: `506` - // Estimated: `71354` - // Minimum execution time: 64_000_000 picoseconds. - Weight::from_parts(65_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(64_000_000, 71362) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -182,14 +182,14 @@ impl WeightInfo for SubstrateWeight { fn deny_application() -> Weight { // Proof Size summary in bytes: // Measured: `175` - // Estimated: `71354` - // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(25_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(25_000_000, 71362) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -201,9 +201,9 @@ impl WeightInfo for SubstrateWeight { fn penalize_agent() -> Weight { // Proof Size summary in bytes: // Measured: `232` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 24_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + Weight::from_parts(25_000_000, 71362) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -219,8 +219,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `205` // Estimated: `6196` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 6196) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -236,7 +236,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `205` // Estimated: `6196` - // Minimum execution time: 44_000_000 picoseconds. + // Minimum execution time: 43_000_000 picoseconds. Weight::from_parts(45_000_000, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -253,8 +253,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `6196` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 6196) + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(44_000_000, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -271,7 +271,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `316` // Estimated: `6100` // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 6100) + Weight::from_parts(18_000_000, 6100) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -320,13 +320,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `6196` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 6196) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -338,14 +338,14 @@ impl WeightInfo for SubstrateWeight { fn toggle_agent_freezing() -> Weight { // Proof Size summary in bytes: // Measured: `48` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 21_000_000 picoseconds. - Weight::from_parts(22_000_000, 71354) + Weight::from_parts(22_000_000, 71362) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -357,9 +357,9 @@ impl WeightInfo for SubstrateWeight { fn toggle_namespace_freezing() -> Weight { // Proof Size summary in bytes: // Measured: `48` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 21_000_000 picoseconds. - Weight::from_parts(22_000_000, 71354) + Weight::from_parts(21_000_000, 71362) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -373,7 +373,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6` // Estimated: `3497` - // Minimum execution time: 4_000_000 picoseconds. + // Minimum execution time: 3_000_000 picoseconds. Weight::from_parts(4_000_000, 3497) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -385,12 +385,12 @@ impl WeightInfo for () { // Measured: `62` // Estimated: `3497` // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_000_000, 3497) + Weight::from_parts(5_000_000, 3497) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -404,14 +404,14 @@ impl WeightInfo for () { fn add_to_whitelist() -> Weight { // Proof Size summary in bytes: // Measured: `91` - // Estimated: `71354` - // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(25_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -425,9 +425,9 @@ impl WeightInfo for () { fn remove_from_whitelist() -> Weight { // Proof Size summary in bytes: // Measured: `110` - // Estimated: `71354` - // Minimum execution time: 26_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(26_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -445,13 +445,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `344` // Estimated: `6196` - // Minimum execution time: 49_000_000 picoseconds. - Weight::from_parts(50_000_000, 6196) + // Minimum execution time: 48_000_000 picoseconds. + Weight::from_parts(49_000_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -469,14 +469,14 @@ impl WeightInfo for () { fn accept_application() -> Weight { // Proof Size summary in bytes: // Measured: `506` - // Estimated: `71354` - // Minimum execution time: 64_000_000 picoseconds. - Weight::from_parts(65_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 63_000_000 picoseconds. + Weight::from_parts(64_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -488,14 +488,14 @@ impl WeightInfo for () { fn deny_application() -> Weight { // Proof Size summary in bytes: // Measured: `175` - // Estimated: `71354` - // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(25_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(25_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -507,9 +507,9 @@ impl WeightInfo for () { fn penalize_agent() -> Weight { // Proof Size summary in bytes: // Measured: `232` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 24_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + Weight::from_parts(25_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -525,8 +525,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `205` // Estimated: `6196` - // Minimum execution time: 44_000_000 picoseconds. - Weight::from_parts(45_000_000, 6196) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -542,7 +542,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `205` // Estimated: `6196` - // Minimum execution time: 44_000_000 picoseconds. + // Minimum execution time: 43_000_000 picoseconds. Weight::from_parts(45_000_000, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -559,8 +559,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `6196` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 6196) + // Minimum execution time: 44_000_000 picoseconds. + Weight::from_parts(44_000_000, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -577,7 +577,7 @@ impl WeightInfo for () { // Measured: `316` // Estimated: `6100` // Minimum execution time: 18_000_000 picoseconds. - Weight::from_parts(19_000_000, 6100) + Weight::from_parts(18_000_000, 6100) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -626,13 +626,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `6196` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(46_000_000, 6196) + // Minimum execution time: 43_000_000 picoseconds. + Weight::from_parts(44_000_000, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -644,14 +644,14 @@ impl WeightInfo for () { fn toggle_agent_freezing() -> Weight { // Proof Size summary in bytes: // Measured: `48` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 21_000_000 picoseconds. - Weight::from_parts(22_000_000, 71354) + Weight::from_parts(22_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -663,9 +663,9 @@ impl WeightInfo for () { fn toggle_namespace_freezing() -> Weight { // Proof Size summary in bytes: // Measured: `48` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 21_000_000 picoseconds. - Weight::from_parts(22_000_000, 71354) + Weight::from_parts(21_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/pallets/permission0/api/src/lib.rs b/pallets/permission0/api/src/lib.rs index b4ab484..da121c0 100644 --- a/pallets/permission0/api/src/lib.rs +++ b/pallets/permission0/api/src/lib.rs @@ -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 ; } } diff --git a/pallets/permission0/src/benchmarking.rs b/pallets/permission0/src/benchmarking.rs index 17dae88..55fa542 100644 --- a/pallets/permission0/src/benchmarking.rs +++ b/pallets/permission0/src/benchmarking.rs @@ -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, }; @@ -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); @@ -310,21 +310,15 @@ mod benchmarks { .expect("failed to register namespace"); } - let mut alice_paths_set: BTreeSet = 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, - BoundedBTreeSet, - T::MaxNamespacesPerPermission, - > = BoundedBTreeMap::new(); + let mut alice_paths = BoundedBTreeMap::new(); alice_paths .try_insert(None, alice_paths_bounded) .expect("failed to insert alice paths"); @@ -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); @@ -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(), @@ -404,20 +419,18 @@ mod benchmarks { .expect("failed to register pollution namespace"); } - let mut alice_bob_set: BTreeSet = 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 = - 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, - BoundedBTreeSet, - T::MaxNamespacesPerPermission, - > = BoundedBTreeMap::new(); + let mut alice_paths = BoundedBTreeMap::new(); alice_paths .try_insert(None, alice_bob_set) .expect("failed to insert alice paths"); @@ -432,19 +445,16 @@ mod benchmarks { ) .expect("failed to create alice->bob permission"); - let mut bob_charlie_set: BTreeSet = 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 = - 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, - BoundedBTreeSet, - 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"); @@ -459,25 +469,45 @@ mod benchmarks { ) .expect("failed to create bob->charlie permission"); - let mut charlie_dave_set: BTreeSet = 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::( + 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 = - 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, - BoundedBTreeSet, - 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"); diff --git a/pallets/permission0/src/ext/namespace_impl.rs b/pallets/permission0/src/ext/namespace_impl.rs index 88662c2..2f99774 100644 --- a/pallets/permission0/src/ext/namespace_impl.rs +++ b/pallets/permission0/src/ext/namespace_impl.rs @@ -93,11 +93,6 @@ pub fn delegate_namespace_permission_impl( Error::::NotPermissionRecipient ); - ensure!( - max_instances <= parent.available_instances().unwrap_or_default(), - Error::::NotEnoughInstances - ); - ensure!( RevocationTerms::::is_weaker(&parent.revocation, &revocation), Error::::RevocationTermsTooStrong @@ -105,9 +100,9 @@ pub fn delegate_namespace_permission_impl( parents.push(pid); - resolve_paths::(&delegator, Some((*pid, namespace)), paths) + resolve_paths::(&delegator, Some((*pid, namespace)), paths, max_instances) } else { - resolve_paths::(&delegator, None, paths) + resolve_paths::(&delegator, None, paths, max_instances) }?; Ok((*pid, namespaces)) @@ -211,49 +206,52 @@ fn check_namespace_delegation_depth( fn resolve_paths( delegator: &T::AccountId, parent: Option<(PermissionId, &NamespaceScope)>, - paths: &BoundedBTreeSet, + new_paths: &BoundedBTreeSet, + instances: u32, ) -> Result, DispatchError> { - let children = paths.iter().map(|path| { + let new_paths = new_paths.iter().map(|path| { NamespacePath::new_agent(path).map_err(|_| Error::::NamespacePathIsInvalid.into()) }); - let paths = if let Some((parent_pid, parent)) = parent { - let children = children.collect::, 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::, 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::::ParentPermissionNotFound ); - for child_path in &children { - check_namespace_delegation_depth::(child_path, Some(parent_pid), 1)?; + for new_path in &new_paths { + check_namespace_delegation_depth::(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) { @@ -266,7 +264,7 @@ fn resolve_paths( .collect::, DispatchError>>()? }; - paths + new_paths .try_into() .map_err(|_| Error::::TooManyNamespaces.into()) } diff --git a/pallets/permission0/src/permission/namespace.rs b/pallets/permission0/src/permission/namespace.rs index cc1132c..f64d6dd 100644 --- a/pallets/permission0/src/permission/namespace.rs +++ b/pallets/permission0/src/permission/namespace.rs @@ -1,14 +1,15 @@ use codec::{Decode, Encode, MaxEncodedLen}; use pallet_torus0_api::NamespacePath; use polkadot_sdk::{ - frame_support::{CloneNoBound, DebugNoBound}, + frame_support::{CloneNoBound, DebugNoBound, dispatch::DispatchResult}, sp_runtime::{BoundedBTreeMap, BoundedBTreeSet}, + sp_std::vec::Vec, }; use scale_info::TypeInfo; -use crate::{Config, Permissions}; +use crate::{Config, Error, Permissions}; -use super::PermissionId; +use super::{PermissionId, PermissionScope}; /// Scope for namespace permissions #[derive(Encode, Decode, CloneNoBound, TypeInfo, MaxEncodedLen, DebugNoBound)] @@ -28,6 +29,99 @@ pub struct NamespaceScope { } impl NamespaceScope { + fn redelegated_paths( + &self, + this_id: PermissionId, + ) -> impl Iterator { + self.children + .iter() + .filter_map(|c| { + if let PermissionScope::Namespace(scope) = Permissions::::get(c)?.scope { + Some(scope) + } else { + None + } + }) + .flat_map(move |scope| { + scope + .paths + .into_iter() + .filter(move |(pid, _)| pid.as_ref().is_some_and(|pid| pid == &this_id)) + .flat_map(|(_, paths)| paths) + .map(move |path| (path, scope.max_instances)) + }) + } + + /// Checks that the provided paths are allowed to be delegated. + /// This is true if enough instances are available and unused by + /// siblings. + /// + /// Given a subpath, an instance is used if any parent or child + /// paths from that subpath were delegated to a sibling permission. + /// sibling subpaths do not consume an instance relative to this + /// subpath. + pub(crate) fn check_available_instances<'a>( + &self, + this_id: PermissionId, + other: impl Iterator, + instances: u32, + ) -> DispatchResult { + let mut redelegated_paths: Vec<_> = self.redelegated_paths(this_id).collect(); + + for other in other { + let mut available_instances = self.max_instances; + + for (redelegated_path, max_instances) in &redelegated_paths { + if redelegated_path == other + || redelegated_path.is_parent_of(other) + || other.is_parent_of(redelegated_path) + { + available_instances = available_instances.saturating_sub(*max_instances); + if available_instances < instances { + return Err(Error::::NotEnoughInstances.into()); + } + } + } + + // This is crucial, do not change. + // When delegating multiple related paths in a single + // call (e.g. .compute and .compute.gpu), we have to + // account for these entries when calculating available + // instances for the next entries (.compute consume + // an instance used by .compute.gpu). To solve this + // in a single call, we add it to the sibling path + // list: the next entry will iterate this path as well. + // + // Earlier paths are siblings to later paths. + redelegated_paths.push((other.clone(), instances)); + + if available_instances < instances { + return Err(Error::::NotEnoughInstances.into()); + } + } + + Ok(()) + } + + /// Count the number of available instances for a given path. + pub fn available_instances(&self, this_id: PermissionId, path: &NamespacePath) -> u32 { + let mut available_instances = self.max_instances; + + for (redelegated_path, max_instances) in self.redelegated_paths(this_id) { + if &redelegated_path == path + || redelegated_path.is_parent_of(path) + || path.is_parent_of(&redelegated_path) + { + available_instances = available_instances.saturating_sub(max_instances); + if available_instances == 0 { + return 0; + } + } + } + + available_instances + } + /// Cleanup operations when permission is revoked or expired pub(super) fn cleanup( &self, diff --git a/pallets/permission0/src/weights.rs b/pallets/permission0/src/weights.rs index 6289ecd..5575b3c 100644 --- a/pallets/permission0/src/weights.rs +++ b/pallets/permission0/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_permission0` //! //! 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: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -57,7 +57,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Permission0::AccumulatedStreamAmounts` (r:1 w:1) /// Proof: `Permission0::AccumulatedStreamAmounts` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -67,14 +67,14 @@ impl WeightInfo for SubstrateWeight { fn delegate_stream_permission() -> Weight { // Proof Size summary in bytes: // Measured: `275` - // Estimated: `71354` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(28_000_000, 71362) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -87,43 +87,43 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Permission0::RevocationTracking` (`max_values`: None, `max_size`: Some(353), added: 2828, mode: `MaxEncodedLen`) fn revoke_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `625` - // Estimated: `71354` + // Measured: `628` + // Estimated: `71362` // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + Weight::from_parts(25_000_000, 71362) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::AccumulatedStreamAmounts` (r:2 w:1) /// Proof: `Permission0::AccumulatedStreamAmounts` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn execute_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `580` - // Estimated: `71354` + // Measured: `583` + // Estimated: `71362` // Minimum execution time: 34_000_000 picoseconds. - Weight::from_parts(35_000_000, 71354) + Weight::from_parts(35_000_000, 71362) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::EnforcementTracking` (r:0 w:1) /// Proof: `Permission0::EnforcementTracking` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn toggle_permission_accumulation() -> Weight { // Proof Size summary in bytes: - // Measured: `427` - // Estimated: `71354` + // Measured: `430` + // Estimated: `71362` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 71354) + Weight::from_parts(13_000_000, 71362) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::EnforcementTracking` (r:1 w:1) /// Proof: `Permission0::EnforcementTracking` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Permission0::AccumulatedStreamAmounts` (r:2 w:1) @@ -132,26 +132,26 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn enforcement_execute_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `617` - // Estimated: `71354` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 71354) + // Measured: `620` + // Estimated: `71362` + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 71362) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) fn set_enforcement_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `427` - // Estimated: `71354` + // Measured: `430` + // Estimated: `71362` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 71354) + Weight::from_parts(14_000_000, 71362) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -161,27 +161,27 @@ impl WeightInfo for SubstrateWeight { fn delegate_curator_permission() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 71354) + Weight::from_parts(15_000_000, 71362) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) fn update_namespace_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `331` - // Estimated: `71354` + // Measured: `339` + // Estimated: `71362` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 71354) + Weight::from_parts(10_000_000, 71362) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Torus0::Agents` (r:4 w:0) + /// Storage: `Torus0::Agents` (r:9 w:0) /// Proof: `Torus0::Agents` (`max_values`: None, `max_size`: Some(857), added: 3332, mode: `MaxEncodedLen`) - /// Storage: `Permission0::Permissions` (r:3 w:2) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Storage: `Permission0::Permissions` (r:18 w:2) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Torus0::Namespaces` (r:2 w:0) /// Proof: `Torus0::Namespaces` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) @@ -192,11 +192,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Permission0::PermissionsByDelegator` (`max_values`: None, `max_size`: Some(3234), added: 5709, mode: `MaxEncodedLen`) fn delegate_namespace_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `1788` - // Estimated: `212082` - // Minimum execution time: 64_000_000 picoseconds. - Weight::from_parts(68_000_000, 212082) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Measured: `7855` + // Estimated: `1267686` + // Minimum execution time: 153_000_000 picoseconds. + Weight::from_parts(155_000_000, 1267686) + .saturating_add(T::DbWeight::get().reads(32_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } } @@ -208,7 +208,7 @@ impl WeightInfo for () { /// Storage: `Permission0::AccumulatedStreamAmounts` (r:1 w:1) /// Proof: `Permission0::AccumulatedStreamAmounts` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -218,14 +218,14 @@ impl WeightInfo for () { fn delegate_stream_permission() -> Weight { // Proof Size summary in bytes: // Measured: `275` - // Estimated: `71354` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 71354) + // Estimated: `71362` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(28_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -238,43 +238,43 @@ impl WeightInfo for () { /// Proof: `Permission0::RevocationTracking` (`max_values`: None, `max_size`: Some(353), added: 2828, mode: `MaxEncodedLen`) fn revoke_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `625` - // Estimated: `71354` + // Measured: `628` + // Estimated: `71362` // Minimum execution time: 25_000_000 picoseconds. - Weight::from_parts(26_000_000, 71354) + Weight::from_parts(25_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::AccumulatedStreamAmounts` (r:2 w:1) /// Proof: `Permission0::AccumulatedStreamAmounts` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn execute_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `580` - // Estimated: `71354` + // Measured: `583` + // Estimated: `71362` // Minimum execution time: 34_000_000 picoseconds. - Weight::from_parts(35_000_000, 71354) + Weight::from_parts(35_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::EnforcementTracking` (r:0 w:1) /// Proof: `Permission0::EnforcementTracking` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn toggle_permission_accumulation() -> Weight { // Proof Size summary in bytes: - // Measured: `427` - // Estimated: `71354` + // Measured: `430` + // Estimated: `71362` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(13_000_000, 71354) + Weight::from_parts(13_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::EnforcementTracking` (r:1 w:1) /// Proof: `Permission0::EnforcementTracking` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Permission0::AccumulatedStreamAmounts` (r:2 w:1) @@ -283,26 +283,26 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn enforcement_execute_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `617` - // Estimated: `71354` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 71354) + // Measured: `620` + // Estimated: `71362` + // Minimum execution time: 39_000_000 picoseconds. + Weight::from_parts(40_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) fn set_enforcement_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `427` - // Estimated: `71354` + // Measured: `430` + // Estimated: `71362` // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 71354) + Weight::from_parts(14_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) /// Proof: `Permission0::PermissionsByParticipants` (`max_values`: None, `max_size`: Some(3266), added: 5741, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByRecipient` (r:1 w:1) @@ -312,27 +312,27 @@ impl WeightInfo for () { fn delegate_curator_permission() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `71354` + // Estimated: `71362` // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 71354) + Weight::from_parts(15_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Permission0::Permissions` (r:1 w:1) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) fn update_namespace_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `331` - // Estimated: `71354` + // Measured: `339` + // Estimated: `71362` // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(10_000_000, 71354) + Weight::from_parts(10_000_000, 71362) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Torus0::Agents` (r:4 w:0) + /// Storage: `Torus0::Agents` (r:9 w:0) /// Proof: `Torus0::Agents` (`max_values`: None, `max_size`: Some(857), added: 3332, mode: `MaxEncodedLen`) - /// Storage: `Permission0::Permissions` (r:3 w:2) - /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67889), added: 70364, mode: `MaxEncodedLen`) + /// Storage: `Permission0::Permissions` (r:18 w:2) + /// Proof: `Permission0::Permissions` (`max_values`: None, `max_size`: Some(67897), added: 70372, mode: `MaxEncodedLen`) /// Storage: `Torus0::Namespaces` (r:2 w:0) /// Proof: `Torus0::Namespaces` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) /// Storage: `Permission0::PermissionsByParticipants` (r:1 w:1) @@ -343,11 +343,11 @@ impl WeightInfo for () { /// Proof: `Permission0::PermissionsByDelegator` (`max_values`: None, `max_size`: Some(3234), added: 5709, mode: `MaxEncodedLen`) fn delegate_namespace_permission() -> Weight { // Proof Size summary in bytes: - // Measured: `1788` - // Estimated: `212082` - // Minimum execution time: 64_000_000 picoseconds. - Weight::from_parts(68_000_000, 212082) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Measured: `7855` + // Estimated: `1267686` + // Minimum execution time: 153_000_000 picoseconds. + Weight::from_parts(155_000_000, 1267686) + .saturating_add(RocksDbWeight::get().reads(32_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } } diff --git a/pallets/permission0/tests/namespace.rs b/pallets/permission0/tests/namespace.rs index 8938230..6dc9c6f 100644 --- a/pallets/permission0/tests/namespace.rs +++ b/pallets/permission0/tests/namespace.rs @@ -7,6 +7,7 @@ use pallet_permission0::{ use pallet_permission0_api::Permission0NamespacesApi; use pallet_torus0_api::{NamespacePath, NamespacePathInner}; use polkadot_sdk::sp_core::{H256, TryCollect}; +use polkadot_sdk::sp_runtime::DispatchError; use polkadot_sdk::{ frame_support::{BoundedBTreeMap, BoundedBTreeSet, assert_err, assert_ok}, frame_system::RawOrigin, @@ -2024,3 +2025,179 @@ fn bulk_delegate_namespace_permission_succeeds_within_parent_instance_limit() { ); }); } + +#[test] +fn namespace_instance_overlap_logic_comprehensive_test() { + new_test_ext().execute_with(|| { + // Register all agents we'll need + let alice = 0; + register_agent(alice); + let bob = 1; + register_agent(bob); + let charlie = 2; + register_agent(charlie); + let dave = 3; + register_agent(dave); + let eve = 4; + register_agent(eve); + let ferdie = 5; + register_agent(ferdie); + + // Register all namespaces we'll need + let compute = register_namespace(alice, b"agent.alice.compute"); + let cpu = register_namespace(alice, b"agent.alice.compute.cpu"); + let epyc4005 = register_namespace(alice, b"agent.alice.compute.cpu.epyc4005"); + let xeon = register_namespace(alice, b"agent.alice.compute.cpu.xeon"); + let gpu = register_namespace(alice, b"agent.alice.compute.gpu"); + let h100 = register_namespace(alice, b"agent.alice.compute.gpu.h100"); + let rtx4090 = register_namespace(alice, b"agent.alice.compute.gpu.rtx4090"); + let cluster1 = register_namespace(alice, b"agent.alice.compute.gpu.h100.cluster1"); + let cluster2 = register_namespace(alice, b"agent.alice.compute.gpu.h100.cluster2"); + let storage = register_namespace(alice, b"agent.alice.compute.storage"); + + // Helper function that implements the overlap-based instance counting logic + fn delegate( + delegator: AccountId, + recipient: AccountId, + parent: Option, + path: &[&NamespacePathInner], + instances: u32, + ) -> Result { + step_block(1); + + let paths = TryCollect::>::try_collect( + vec![( + parent, + TryCollect::>::try_collect( + path.iter().map(|p| (**p).clone()), + ) + .unwrap(), + )] + .into_iter(), + ) + .unwrap(); + + Permission0::delegate_namespace_permission( + get_origin(delegator), + recipient, + paths, + PermissionDuration::Indefinite, + RevocationTerms::RevocableByDelegator, + instances, + )?; + + Ok(get_last_delegated_permission_id(delegator)) + } + + // ========== TEST 1 INSTANCE ========== + // With 1 instance, no overlapping paths can coexist + let parent = delegate(alice, bob, None, &[&compute], 1).unwrap(); + + delegate(bob, charlie, Some(parent), &[&gpu], 2) + .expect_err("more instances than available"); + + // Siblings can coexist (no overlap) + delegate(bob, charlie, Some(parent), &[&cpu, &h100, &gpu], 1) + .expect_err("gpu overlaps with h100"); + + delegate(bob, charlie, Some(parent), &[&cpu], 1).unwrap(); + delegate(bob, charlie, Some(parent), &[&h100], 1).unwrap(); // OK: h100 is under gpu, not cpu + + // Parent-child overlaps are blocked + delegate(bob, charlie, Some(parent), &[&gpu], 1).expect_err("gpu overlaps with h100"); + delegate(bob, dave, Some(parent), &[&epyc4005], 1).expect_err("epyc4005 overlaps with cpu"); + + // But non-overlapping paths work + delegate(bob, dave, Some(parent), &[&rtx4090], 1).unwrap(); // OK: sibling to h100 + + // ========== TEST 2 INSTANCES ========== + // With 2 instances, we can have 2 overlapping chains + let parent = delegate(alice, bob, None, &[&compute], 2).unwrap(); + + delegate(bob, charlie, Some(parent), &[&cpu], 1).unwrap(); + delegate(bob, charlie, Some(parent), &[&h100], 1).unwrap(); + + // Can delegate same path twice (uses 2 instances) + delegate(bob, dave, Some(parent), &[&h100], 1).unwrap(); // 2nd h100 + + // Can delegate overlapping paths + delegate(bob, eve, Some(parent), &[&epyc4005, &rtx4090, &h100], 1) + .expect_err("3rd h100 needs 3 instances"); // Overlaps with cpu + + delegate(bob, eve, Some(parent), &[&epyc4005], 1).unwrap(); // Overlaps with cpu + delegate(bob, eve, Some(parent), &[&rtx4090], 1).unwrap(); // Sibling to h100s + + // But 3rd h100 would fail + delegate(bob, ferdie, Some(parent), &[&h100], 1).expect_err("3rd h100 needs 3 instances"); + + // ========== TEST 3 INSTANCES ========== + // Test 3a: Three identical paths + let parent3a = delegate(alice, bob, None, &[&compute], 3).unwrap(); + + delegate(bob, charlie, Some(parent3a), &[&h100], 1).unwrap(); // h100 #1 + delegate(bob, dave, Some(parent3a), &[&h100], 1).unwrap(); // h100 #2 + delegate(bob, eve, Some(parent3a), &[&h100], 1).unwrap(); // h100 #3 + delegate(bob, ferdie, Some(parent3a), &[&h100], 1).expect_err("4th h100 needs 4 instances"); + + // Test 3b: Complex branching with overlaps + let parent3b = delegate(alice, bob, None, &[&compute], 3).unwrap(); + + delegate(bob, charlie, Some(parent3b), &[&cpu], 1).unwrap(); // CPU branch + delegate(bob, charlie, Some(parent3b), &[&gpu], 1).unwrap(); // GPU branch (sibling) + delegate(bob, dave, Some(parent3b), &[&epyc4005], 1).unwrap(); // Under CPU (1 overlap) + delegate(bob, eve, Some(parent3b), &[&h100], 1).unwrap(); // Under GPU (1 overlap) + delegate(bob, eve, Some(parent3b), &[&rtx4090], 1).unwrap(); // Under GPU (1 overlap) + + // xeon would work (only overlaps with cpu, using 1 instance) + delegate(bob, ferdie, Some(parent3b), &[&xeon], 1).unwrap(); + + // ========== TEST 4 INSTANCES ========== + // Test 4a: Four identical paths + let parent4a = delegate(alice, bob, None, &[&compute], 4).unwrap(); + + delegate(bob, charlie, Some(parent4a), &[&h100], 1).unwrap(); // h100 #1 + delegate(bob, dave, Some(parent4a), &[&h100], 1).unwrap(); // h100 #2 + delegate(bob, eve, Some(parent4a), &[&h100], 1).unwrap(); // h100 #3 + delegate(bob, ferdie, Some(parent4a), &[&h100], 1).unwrap(); // h100 #4 + + // Can't add 5th + let parent4a_new = delegate(alice, charlie, None, &[&compute], 4).unwrap(); + delegate(charlie, alice, Some(parent4a_new), &[&h100], 1).unwrap(); + delegate(charlie, alice, Some(parent4a_new), &[&h100], 1).unwrap(); + delegate(charlie, alice, Some(parent4a_new), &[&h100], 1).unwrap(); + delegate(charlie, alice, Some(parent4a_new), &[&h100], 1).unwrap(); + delegate(charlie, bob, Some(parent4a_new), &[&h100], 1) + .expect_err("5th h100 needs 5 instances"); + + // Test 4b: Deep hierarchy with siblings + let parent4b = delegate(alice, bob, None, &[&compute], 4).unwrap(); + + // Build branches + delegate(bob, charlie, Some(parent4b), &[&gpu], 1).unwrap(); // GPU root + delegate(bob, dave, Some(parent4b), &[&h100], 1).unwrap(); // Under GPU (1 overlap) + delegate(bob, eve, Some(parent4b), &[&cluster1], 1).unwrap(); // Under h100 (2 overlaps) + delegate(bob, ferdie, Some(parent4b), &[&cluster2], 1).unwrap(); // Sibling to cluster1 (2 overlaps) + + delegate(bob, ferdie, Some(parent4b), &[&cluster1], 1).unwrap(); + delegate(bob, ferdie, Some(parent4b), &[&cluster1], 1) + .expect_err("consumed all cluster1 instances"); + + delegate(bob, ferdie, Some(parent4b), &[&cluster2], 1).unwrap(); + delegate(bob, ferdie, Some(parent4b), &[&cluster2], 1) + .expect_err("consumed all cluster2 instances"); + + // Can still add non-overlapping branches + delegate(bob, charlie, Some(parent4b), &[&cpu], 1).unwrap(); // CPU branch (no overlap) + delegate(bob, dave, Some(parent4b), &[&storage], 1).unwrap(); // Storage branch (no overlap) + + // rtx4090 works (only overlaps with gpu root) + delegate(bob, eve, Some(parent4b), &[&rtx4090], 1).unwrap(); + + // With 2 instances, we can have 2 overlapping chains + let parent = delegate(alice, bob, None, &[&gpu, &h100], 2).unwrap(); + + delegate(bob, charlie, Some(parent), &[&rtx4090, &h100], 1).unwrap(); + delegate(bob, charlie, Some(parent), &[&h100], 1).unwrap(); + delegate(bob, charlie, Some(parent), &[&h100], 1).expect_err("h100 instace pool depleted"); + }); +} diff --git a/pallets/torus0/src/weights.rs b/pallets/torus0/src/weights.rs index 52e2470..ef2c913 100644 --- a/pallets/torus0/src/weights.rs +++ b/pallets/torus0/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_torus0` //! //! 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: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -68,11 +68,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `5915` - // Minimum execution time: 26_000_000 picoseconds. - Weight::from_parts(27_000_000, 5915) + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(26_000_000, 5915) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } + /// Storage: `Permission0::PermissionsByDelegator` (r:1 w:0) + /// Proof: `Permission0::PermissionsByDelegator` (`max_values`: None, `max_size`: Some(3234), added: 5709, mode: `MaxEncodedLen`) /// Storage: `Torus0::Agents` (r:1 w:0) /// Proof: `Torus0::Agents` (`max_values`: None, `max_size`: Some(857), added: 3332, mode: `MaxEncodedLen`) /// Storage: `Torus0::StakingTo` (r:1 w:1) @@ -87,13 +89,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Torus0::StakedBy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) fn remove_stake() -> Weight { // Proof Size summary in bytes: - // Measured: `573` - // Estimated: `5915` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 5915) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `615` + // Estimated: `6699` + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(32_000_000, 6699) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } + /// Storage: `Permission0::PermissionsByDelegator` (r:1 w:0) + /// Proof: `Permission0::PermissionsByDelegator` (`max_values`: None, `max_size`: Some(3234), added: 5709, mode: `MaxEncodedLen`) /// Storage: `Torus0::Agents` (r:2 w:0) /// Proof: `Torus0::Agents` (`max_values`: None, `max_size`: Some(857), added: 3332, mode: `MaxEncodedLen`) /// Storage: `Torus0::StakingTo` (r:2 w:2) @@ -108,11 +112,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Torus0::StakedBy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) fn transfer_stake() -> Weight { // Proof Size summary in bytes: - // Measured: `645` + // Measured: `687` // Estimated: `7654` - // Minimum execution time: 48_000_000 picoseconds. - Weight::from_parts(49_000_000, 7654) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(50_000_000, 7654) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Governance::AgentsFrozen` (r:1 w:0) @@ -147,8 +151,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `68` // Estimated: `7654` - // Minimum execution time: 36_000_000 picoseconds. - Weight::from_parts(37_000_000, 7654) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 7654) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -166,8 +170,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `374` // Estimated: `6699` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 6699) + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(27_000_000, 6699) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -220,11 +224,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `335` // Estimated: `5915` - // Minimum execution time: 26_000_000 picoseconds. - Weight::from_parts(27_000_000, 5915) + // Minimum execution time: 25_000_000 picoseconds. + Weight::from_parts(26_000_000, 5915) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } + /// Storage: `Permission0::PermissionsByDelegator` (r:1 w:0) + /// Proof: `Permission0::PermissionsByDelegator` (`max_values`: None, `max_size`: Some(3234), added: 5709, mode: `MaxEncodedLen`) /// Storage: `Torus0::Agents` (r:1 w:0) /// Proof: `Torus0::Agents` (`max_values`: None, `max_size`: Some(857), added: 3332, mode: `MaxEncodedLen`) /// Storage: `Torus0::StakingTo` (r:1 w:1) @@ -239,13 +245,15 @@ impl WeightInfo for () { /// Proof: `Torus0::StakedBy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) fn remove_stake() -> Weight { // Proof Size summary in bytes: - // Measured: `573` - // Estimated: `5915` - // Minimum execution time: 29_000_000 picoseconds. - Weight::from_parts(30_000_000, 5915) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `615` + // Estimated: `6699` + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(32_000_000, 6699) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } + /// Storage: `Permission0::PermissionsByDelegator` (r:1 w:0) + /// Proof: `Permission0::PermissionsByDelegator` (`max_values`: None, `max_size`: Some(3234), added: 5709, mode: `MaxEncodedLen`) /// Storage: `Torus0::Agents` (r:2 w:0) /// Proof: `Torus0::Agents` (`max_values`: None, `max_size`: Some(857), added: 3332, mode: `MaxEncodedLen`) /// Storage: `Torus0::StakingTo` (r:2 w:2) @@ -260,11 +268,11 @@ impl WeightInfo for () { /// Proof: `Torus0::StakedBy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) fn transfer_stake() -> Weight { // Proof Size summary in bytes: - // Measured: `645` + // Measured: `687` // Estimated: `7654` - // Minimum execution time: 48_000_000 picoseconds. - Weight::from_parts(49_000_000, 7654) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 49_000_000 picoseconds. + Weight::from_parts(50_000_000, 7654) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Governance::AgentsFrozen` (r:1 w:0) @@ -299,8 +307,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `68` // Estimated: `7654` - // Minimum execution time: 36_000_000 picoseconds. - Weight::from_parts(37_000_000, 7654) + // Minimum execution time: 35_000_000 picoseconds. + Weight::from_parts(36_000_000, 7654) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -318,8 +326,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `374` // Estimated: `6699` - // Minimum execution time: 27_000_000 picoseconds. - Weight::from_parts(28_000_000, 6699) + // Minimum execution time: 26_000_000 picoseconds. + Weight::from_parts(27_000_000, 6699) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/runtime/src/apis.rs b/runtime/src/apis.rs index bc96bdf..7ee1673 100644 --- a/runtime/src/apis.rs +++ b/runtime/src/apis.rs @@ -470,6 +470,25 @@ impl_runtime_apis! { fn root_stream_id_for_account(account_id: AccountId) -> StreamId { generate_root_stream_id(&account_id) } + + fn available_namespace_instances( + permission_id: pallet_permission0_api::PermissionId, + path: pallet_torus0_api::NamespacePathInner + ) -> Result { + use pallet_permission0::Permissions; + use pallet_torus0_api::NamespacePath; + + let namespace_path = + NamespacePath::new_agent(&path).map_err(|_| pallet_torus0::Error::::InvalidNamespacePath)?; + + let permission = + Permissions::::get(permission_id).ok_or(pallet_permission0::Error::::PermissionNotFound)?; + let pallet_permission0::PermissionScope::Namespace(scope) = &permission.scope else { + return Err(pallet_permission0::Error::::UnsupportedPermissionType.into()); + }; + + Ok(scope.available_instances(permission_id, &namespace_path)) + } } impl pallet_torus0_api::api::Torus0RuntimeApi for Runtime { @@ -480,7 +499,7 @@ impl_runtime_apis! { let namespace_path = NamespacePath::new_agent(&path).map_err(|_| pallet_torus0::Error::::InvalidNamespacePath)?; - let owner = namespace::NamespaceOwnership::Account(account_id); + let owner = namespace::NamespaceOwnership::Account(account_id); let missing_paths = namespace::find_missing_paths::(&owner, &namespace_path); namespace::calculate_cost::(&owner, &missing_paths) }