From da23e439e1a8d0d4b20c64d1c97012f068fcef4b Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 5 Nov 2025 13:06:23 -0500 Subject: [PATCH 1/8] Make max number of subnet mechanisms configurable --- pallets/admin-utils/src/lib.rs | 14 ++++++++++++++ pallets/subtensor/src/lib.rs | 6 +++++- pallets/subtensor/src/subnets/mechanism.rs | 18 +++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 01e9e7b33e..a96824bfbf 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -2186,6 +2186,20 @@ pub mod pallet { log::debug!("set_tao_flow_smoothing_factor( {smoothing_factor:?} ) "); Ok(()) } + + /// Sets the global maximum number of mechanisms in a subnet + #[pallet::call_index(84)] + #[pallet::weight(Weight::from_parts(15_000_000, 0) + .saturating_add(::DbWeight::get().reads(1_u64)) + .saturating_add(::DbWeight::get().writes(1_u64)))] + pub fn sudo_set_max_mechanism_count( + origin: OriginFor, + max_mechanism_count: MechId, + ) -> DispatchResult { + ensure_root(origin)?; + pallet_subtensor::Pallet::::do_set_max_mechanism_count(max_mechanism_count)?; + Ok(()) + } } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 5df8a9c429..5fbdd1e971 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2041,9 +2041,13 @@ pub mod pallet { } #[pallet::type_value] /// -- ITEM (Maximum number of sub-subnets) - pub fn MaxMechanismCount() -> MechId { + pub fn DefaultMaxMechanismCount() -> MechId { MechId::from(2) } + #[pallet::storage] + /// ITEM( max_mechanism_count ) + pub type MaxMechanismCount = + StorageValue<_, MechId, ValueQuery, DefaultMaxMechanismCount>; #[pallet::type_value] /// -- ITEM (Rate limit for mechanism count updates) pub fn MechanismCountSetRateLimit() -> u64 { diff --git a/pallets/subtensor/src/subnets/mechanism.rs b/pallets/subtensor/src/subnets/mechanism.rs index 6598c308f2..727c0bd3a6 100644 --- a/pallets/subtensor/src/subnets/mechanism.rs +++ b/pallets/subtensor/src/subnets/mechanism.rs @@ -95,7 +95,7 @@ impl Pallet { Ok(()) } - /// Set the desired valus of sub-subnet count for a subnet identified + /// Set the desired value of sub-subnet count for a subnet identified /// by netuid pub fn do_set_mechanism_count(netuid: NetUid, mechanism_count: MechId) -> DispatchResult { // Make sure the subnet exists @@ -124,6 +124,22 @@ impl Pallet { Ok(()) } + /// Set the global maximum number of mechanisms per subnet + pub fn do_set_max_mechanism_count(max_mechanism_count: MechId) -> DispatchResult { + // Max count cannot be zero + ensure!(max_mechanism_count > 0.into(), Error::::InvalidValue); + + // Make sure we are not allowing numbers that will break the math + ensure!( + max_mechanism_count <= MechId::from(MAX_MECHANISM_COUNT_PER_SUBNET), + Error::::InvalidValue + ); + + MaxMechanismCount::::set(max_mechanism_count); + + Ok(()) + } + /// Update current count for a subnet identified by netuid /// - Cleans up all sub-subnet maps if count is reduced /// From 7f1a809de806dce9e1d64114f88e724ec5f1db09 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 5 Nov 2025 13:08:49 -0500 Subject: [PATCH 2/8] Spec bump --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 266a755708..d95eb45ee9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 338, + spec_version: 339, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From a6da90ebaa6cdae64878df74a95a5bad81d773a4 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 12 Nov 2025 13:06:04 -0500 Subject: [PATCH 3/8] Add enforcing the mechanism count vs. max uids limit --- pallets/admin-utils/src/lib.rs | 6 ++++++ pallets/admin-utils/src/tests/mod.rs | 23 ++++++++++++++++++++++ pallets/subtensor/src/macros/errors.rs | 2 ++ pallets/subtensor/src/subnets/mechanism.rs | 18 +++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 08e4c1e58a..7bdf12ec3f 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -536,6 +536,12 @@ pub mod pallet { max_allowed_uids <= DefaultMaxAllowedUids::::get(), Error::::MaxAllowedUidsGreaterThanDefaultMaxAllowedUids ); + // Prevent chain bloat: Require max UIDs to be limited + let mechanism_count = pallet_subtensor::MechanismCountCurrent::::get(netuid); + pallet_subtensor::Pallet::::check_max_uids_vs_mechanism_count( + max_allowed_uids, + mechanism_count.into(), + )?; pallet_subtensor::Pallet::::set_max_allowed_uids(netuid, max_allowed_uids); pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 1aaefc8f8d..d03b184f84 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -540,6 +540,20 @@ fn test_sudo_set_max_allowed_uids() { Error::::MaxAllowedUidsGreaterThanDefaultMaxAllowedUids ); + // Chain bloat check against mechanism count + // Set MechanismCountCurrent to exceed 256 / DefaultMaxAllowedUids (16) + MechanismCountCurrent::::insert(netuid, MechId::from(32)); + let large_max_uids = 16_u16; + assert_noop!( + AdminUtils::sudo_set_max_allowed_uids( + <::RuntimeOrigin>::root(), + netuid, + large_max_uids + ), + SubtensorError::::TooManyUIDsPerMechanism + ); + MechanismCountCurrent::::insert(netuid, MechId::from(1)); + // Normal case assert_ok!(AdminUtils::sudo_set_max_allowed_uids( <::RuntimeOrigin>::root(), @@ -2341,6 +2355,7 @@ fn test_sudo_set_mechanism_count() { add_network(netuid, 10); // Set the Subnet Owner SubnetOwner::::insert(netuid, sn_owner); + MaxAllowedUids::::insert(netuid, 256_u16); assert_eq!( AdminUtils::sudo_set_mechanism_count( @@ -2354,7 +2369,13 @@ fn test_sudo_set_mechanism_count() { AdminUtils::sudo_set_mechanism_count(RuntimeOrigin::root(), netuid, ss_count_bad), pallet_subtensor::Error::::InvalidValue ); + assert_noop!( + AdminUtils::sudo_set_mechanism_count(RuntimeOrigin::root(), netuid, ss_count_ok), + pallet_subtensor::Error::::TooManyUIDsPerMechanism + ); + // Reduce max UIDs to 128 + MaxAllowedUids::::insert(netuid, 128_u16); assert_ok!(AdminUtils::sudo_set_mechanism_count( <::RuntimeOrigin>::root(), netuid, @@ -2380,6 +2401,8 @@ fn test_sudo_set_mechanism_count_and_emissions() { add_network(netuid, 10); // Set the Subnet Owner SubnetOwner::::insert(netuid, sn_owner); + MaxMechanismCount::::set(MechId::from(2)); + MaxAllowedUids::::set(netuid, 128_u16); assert_ok!(AdminUtils::sudo_set_mechanism_count( <::RuntimeOrigin>::signed(sn_owner), diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 5a15330075..7470fdb3fb 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -266,5 +266,7 @@ mod errors { InvalidRootClaimThreshold, /// Exceeded subnet limit number or zero. InvalidSubnetNumber, + /// The maximum allowed UIDs times mechanism count should not exceed 256. + TooManyUIDsPerMechanism, } } diff --git a/pallets/subtensor/src/subnets/mechanism.rs b/pallets/subtensor/src/subnets/mechanism.rs index 727c0bd3a6..4b7a284870 100644 --- a/pallets/subtensor/src/subnets/mechanism.rs +++ b/pallets/subtensor/src/subnets/mechanism.rs @@ -95,6 +95,20 @@ impl Pallet { Ok(()) } + pub fn check_max_uids_vs_mechanism_count( + max_uids: u16, + mechanism_count: MechId, + ) -> DispatchResult { + let max_uids_for_one_mechanism = 256_u16; + let max_uids_for_mechanism_count = + max_uids_for_one_mechanism.safe_div(u8::from(mechanism_count) as u16); + ensure!( + max_uids_for_mechanism_count >= max_uids, + Error::::TooManyUIDsPerMechanism + ); + Ok(()) + } + /// Set the desired value of sub-subnet count for a subnet identified /// by netuid pub fn do_set_mechanism_count(netuid: NetUid, mechanism_count: MechId) -> DispatchResult { @@ -113,6 +127,10 @@ impl Pallet { Error::::InvalidValue ); + // Prevent chain bloat: Require max UIDs to be limited + let max_uids = MaxAllowedUids::::get(netuid); + Self::check_max_uids_vs_mechanism_count(max_uids, mechanism_count)?; + // Make sure we are not allowing numbers that will break the math ensure!( mechanism_count <= MechId::from(MAX_MECHANISM_COUNT_PER_SUBNET), From d17f6f6ef6635ec9ffb5c7476cd7130e0dee3417 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 12 Nov 2025 13:14:27 -0500 Subject: [PATCH 4/8] Fix merge issues --- pallets/subtensor/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 858ecd6e2a..c8155d3c16 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2310,6 +2310,7 @@ pub mod pallet { MechId::from(1) } + #[pallet::type_value] /// -- ITEM (Maximum number of sub-subnets) pub fn DefaultMaxMechanismCount() -> MechId { MechId::from(2) @@ -2318,7 +2319,6 @@ pub mod pallet { /// ITEM( max_mechanism_count ) pub type MaxMechanismCount = StorageValue<_, MechId, ValueQuery, DefaultMaxMechanismCount>; - #[pallet::type_value] /// -- ITEM (Rate limit for mechanism count updates) #[pallet::type_value] pub fn MechanismCountSetRateLimit() -> u64 { From 33cbc8be0b00688af3048502aee66047e9770c69 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Mon, 17 Nov 2025 17:03:09 -0300 Subject: [PATCH 5/8] fix + tests --- pallets/admin-utils/src/lib.rs | 2 +- pallets/admin-utils/src/tests/mod.rs | 40 +++++++++++++++++++--- pallets/subtensor/src/lib.rs | 6 ++-- pallets/subtensor/src/subnets/mechanism.rs | 11 +++--- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index e3e53d5e2a..d6f547fe11 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -538,7 +538,7 @@ pub mod pallet { ); // Prevent chain bloat: Require max UIDs to be limited let mechanism_count = pallet_subtensor::MechanismCountCurrent::::get(netuid); - pallet_subtensor::Pallet::::check_max_uids_vs_mechanism_count( + pallet_subtensor::Pallet::::ensure_max_uids_over_all_mechanisms( max_allowed_uids, mechanism_count.into(), )?; diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index d03b184f84..c72932ab11 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -10,7 +10,10 @@ use pallet_subtensor::{ TargetRegistrationsPerInterval, Tempo, WeightsVersionKeyRateLimit, *, }; // use pallet_subtensor::{migrations, Event}; -use pallet_subtensor::{Event, utils::rate_limiting::TransactionType}; +use pallet_subtensor::{ + Event, subnets::mechanism::MAX_MECHANISM_COUNT_PER_SUBNET, + utils::rate_limiting::TransactionType, +}; use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{Get, Pair, U256, ed25519}; use substrate_fixed::types::I96F32; @@ -540,10 +543,10 @@ fn test_sudo_set_max_allowed_uids() { Error::::MaxAllowedUidsGreaterThanDefaultMaxAllowedUids ); - // Chain bloat check against mechanism count - // Set MechanismCountCurrent to exceed 256 / DefaultMaxAllowedUids (16) + // Trying to set max allowed uids that would cause max_allowed_uids * mechanism_count > 256 + MaxAllowedUids::::insert(netuid, 8); MechanismCountCurrent::::insert(netuid, MechId::from(32)); - let large_max_uids = 16_u16; + let large_max_uids = 16; assert_noop!( AdminUtils::sudo_set_max_allowed_uids( <::RuntimeOrigin>::root(), @@ -2888,3 +2891,32 @@ fn test_sudo_set_min_allowed_uids() { ); }); } + +#[test] +fn test_sudo_set_max_mechanism_count() { + new_test_ext().execute_with(|| { + // Normal case + assert_ok!(AdminUtils::sudo_set_max_mechanism_count( + <::RuntimeOrigin>::root(), + MechId::from(10) + )); + + // Zero fails + assert_noop!( + AdminUtils::sudo_set_max_mechanism_count( + <::RuntimeOrigin>::root(), + MechId::from(0) + ), + pallet_subtensor::Error::::InvalidValue + ); + + // Over max bound fails + assert_noop!( + AdminUtils::sudo_set_max_mechanism_count( + <::RuntimeOrigin>::root(), + MechId::from(MAX_MECHANISM_COUNT_PER_SUBNET + 1) + ), + pallet_subtensor::Error::::InvalidValue + ); + }); +} diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index c8155d3c16..5cc2cf77e3 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2310,15 +2310,17 @@ pub mod pallet { MechId::from(1) } + /// -- ITEM (Maximum number of mechanisms) #[pallet::type_value] - /// -- ITEM (Maximum number of sub-subnets) pub fn DefaultMaxMechanismCount() -> MechId { MechId::from(2) } - #[pallet::storage] + /// ITEM( max_mechanism_count ) + #[pallet::storage] pub type MaxMechanismCount = StorageValue<_, MechId, ValueQuery, DefaultMaxMechanismCount>; + /// -- ITEM (Rate limit for mechanism count updates) #[pallet::type_value] pub fn MechanismCountSetRateLimit() -> u64 { diff --git a/pallets/subtensor/src/subnets/mechanism.rs b/pallets/subtensor/src/subnets/mechanism.rs index 4b7a284870..8551e2908f 100644 --- a/pallets/subtensor/src/subnets/mechanism.rs +++ b/pallets/subtensor/src/subnets/mechanism.rs @@ -95,21 +95,18 @@ impl Pallet { Ok(()) } - pub fn check_max_uids_vs_mechanism_count( + pub fn ensure_max_uids_over_all_mechanisms( max_uids: u16, mechanism_count: MechId, ) -> DispatchResult { - let max_uids_for_one_mechanism = 256_u16; - let max_uids_for_mechanism_count = - max_uids_for_one_mechanism.safe_div(u8::from(mechanism_count) as u16); ensure!( - max_uids_for_mechanism_count >= max_uids, + max_uids * u8::from(mechanism_count) as u16 <= 256, Error::::TooManyUIDsPerMechanism ); Ok(()) } - /// Set the desired value of sub-subnet count for a subnet identified + /// Set the desired value of mechanism count for a subnet identified /// by netuid pub fn do_set_mechanism_count(netuid: NetUid, mechanism_count: MechId) -> DispatchResult { // Make sure the subnet exists @@ -129,7 +126,7 @@ impl Pallet { // Prevent chain bloat: Require max UIDs to be limited let max_uids = MaxAllowedUids::::get(netuid); - Self::check_max_uids_vs_mechanism_count(max_uids, mechanism_count)?; + Self::ensure_max_uids_over_all_mechanisms(max_uids, mechanism_count)?; // Make sure we are not allowing numbers that will break the math ensure!( From 045d12332e9644582278b6f3314482c06346137c Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Mon, 17 Nov 2025 17:04:37 -0300 Subject: [PATCH 6/8] DefaultMaxAllowedUids from 4096 to 256 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 9ece1dd025..407e4598cf 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -977,7 +977,7 @@ parameter_types! { pub const SubtensorInitialRho: u16 = 10; pub const SubtensorInitialAlphaSigmoidSteepness: i16 = 1000; pub const SubtensorInitialKappa: u16 = 32_767; // 0.5 = 65535/2 - pub const SubtensorInitialMaxAllowedUids: u16 = 4096; + pub const SubtensorInitialMaxAllowedUids: u16 = 256; pub const SubtensorInitialIssuance: u64 = 0; pub const SubtensorInitialMinAllowedWeights: u16 = 1024; pub const SubtensorInitialEmissionValue: u16 = 0; From 5b54733056c556a2e2312a043e555deb5c51654c Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Mon, 17 Nov 2025 17:32:26 -0300 Subject: [PATCH 7/8] fix clippy --- pallets/subtensor/src/subnets/mechanism.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/subnets/mechanism.rs b/pallets/subtensor/src/subnets/mechanism.rs index 8551e2908f..75baf34eb9 100644 --- a/pallets/subtensor/src/subnets/mechanism.rs +++ b/pallets/subtensor/src/subnets/mechanism.rs @@ -100,7 +100,7 @@ impl Pallet { mechanism_count: MechId, ) -> DispatchResult { ensure!( - max_uids * u8::from(mechanism_count) as u16 <= 256, + max_uids.saturating_mul(u8::from(mechanism_count) as u16) <= 256, Error::::TooManyUIDsPerMechanism ); Ok(()) From 3832d5916dc70cf98023f3b87d473c094f2f5075 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Mon, 17 Nov 2025 18:25:52 -0300 Subject: [PATCH 8/8] remove magic number --- pallets/subtensor/src/subnets/mechanism.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/subnets/mechanism.rs b/pallets/subtensor/src/subnets/mechanism.rs index 75baf34eb9..4780e8a3b7 100644 --- a/pallets/subtensor/src/subnets/mechanism.rs +++ b/pallets/subtensor/src/subnets/mechanism.rs @@ -99,8 +99,10 @@ impl Pallet { max_uids: u16, mechanism_count: MechId, ) -> DispatchResult { + let max_uids_over_all_mechanisms = + max_uids.saturating_mul(u8::from(mechanism_count) as u16); ensure!( - max_uids.saturating_mul(u8::from(mechanism_count) as u16) <= 256, + max_uids_over_all_mechanisms <= T::DefaultMaxAllowedUids::get(), Error::::TooManyUIDsPerMechanism ); Ok(())