diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index de6ac5825..d6f547fe1 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::::ensure_max_uids_over_all_mechanisms( + 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, @@ -2213,6 +2219,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/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 1aaefc8f8..c72932ab1 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,6 +543,20 @@ fn test_sudo_set_max_allowed_uids() { Error::::MaxAllowedUidsGreaterThanDefaultMaxAllowedUids ); + // 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; + 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 +2358,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 +2372,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 +2404,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), @@ -2865,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 bbec3ce93..5cc2cf77e 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2310,12 +2310,17 @@ pub mod pallet { MechId::from(1) } - /// -- ITEM (Maximum number of sub-subnets) + /// -- ITEM (Maximum number of mechanisms) #[pallet::type_value] - pub fn MaxMechanismCount() -> MechId { + pub fn DefaultMaxMechanismCount() -> MechId { MechId::from(2) } + /// 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/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 5a1533007..7470fdb3f 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 6598c308f..4780e8a3b 100644 --- a/pallets/subtensor/src/subnets/mechanism.rs +++ b/pallets/subtensor/src/subnets/mechanism.rs @@ -95,7 +95,20 @@ impl Pallet { Ok(()) } - /// Set the desired valus of sub-subnet count for a subnet identified + pub fn ensure_max_uids_over_all_mechanisms( + 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_over_all_mechanisms <= T::DefaultMaxAllowedUids::get(), + Error::::TooManyUIDsPerMechanism + ); + Ok(()) + } + + /// 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 @@ -113,6 +126,10 @@ impl Pallet { Error::::InvalidValue ); + // Prevent chain bloat: Require max UIDs to be limited + let max_uids = MaxAllowedUids::::get(netuid); + Self::ensure_max_uids_over_all_mechanisms(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), @@ -124,6 +141,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 /// diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 9ece1dd02..407e4598c 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;