From 7a04af977ae57ac0099854eb51fa3b4d63edc3a0 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 7 Apr 2025 10:56:54 -0400 Subject: [PATCH 01/10] Add admin extrinsic for sn owner and root to set the subnet owner hotkey --- pallets/admin-utils/src/lib.rs | 35 +++++++++++++++++ pallets/admin-utils/src/tests/mod.rs | 42 +++++++++++++++++++++ pallets/subtensor/src/subnets/subnet.rs | 50 +++++++++++++++++++++++++ 3 files changed, 127 insertions(+) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 19bbbee73b..803c4b64e1 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1476,6 +1476,41 @@ pub mod pallet { ); Ok(()) } + + /// Sets or updates the hotkey account associated with the owner of a specific subnet. + /// + /// This function allows either the root origin or the current subnet owner to set or update + /// the hotkey for a given subnet. The hotkey must either not be registered yet or must be + /// associated with the caller's coldkey. The subnet must already exist. + /// + /// # Parameters + /// - `origin`: The dispatch origin of the call. Must be either root or the current owner of the subnet. + /// - `netuid`: The unique identifier of the subnet whose owner hotkey is being set. + /// - `hotkey`: The new hotkey account to be associated with the subnet owner. + /// + /// # Returns + /// - `DispatchResult`: Returns `Ok(())` if the hotkey was successfully set, or an appropriate error otherwise. + /// + /// # Errors + /// - `Error::NonAssociatedColdKey`: If the provided hotkey is already associated with a different coldkey. + /// - `Error::SubnetNotExists`: If the specified subnet does not exist. + /// + /// # Access Control + /// Only callable by: + /// - Root origin, or + /// - The coldkey account that owns the subnet. + /// + /// # Storage + /// - Updates [`SubnetOwnerHotkey`] for the given `netuid`. + #[pallet::call_index(66)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_sn_owner_hotkey( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + ) -> DispatchResult { + pallet_subtensor::Pallet::::do_set_sn_owner_hotkey(origin, netuid, &hotkey) + } } } diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 2f4c3f2b51..7ccfccfe03 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -1711,3 +1711,45 @@ fn test_sudo_set_ema_halving() { assert_eq!(value_after_2, to_be_set); }); } + +// cargo test --package pallet-admin-utils --lib -- tests::test_set_sn_owner_hotkey --exact --show-output +#[test] +fn test_set_sn_owner_hotkey() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let hotkey: U256 = U256::from(3); + let bad_origin_coldkey: U256 = U256::from(4); + add_network(netuid, 10); + + let owner = U256::from(10); + pallet_subtensor::SubnetOwner::::insert(netuid, owner); + + // Non-owner and non-root cannot set the sn owner hotkey + assert_eq!( + AdminUtils::sudo_set_sn_owner_hotkey( + <::RuntimeOrigin>::signed(bad_origin_coldkey), + netuid, + hotkey + ), + Err(DispatchError::BadOrigin) + ); + + // SN owner can set the hotkey + assert_ok!(AdminUtils::sudo_set_sn_owner_hotkey( + <::RuntimeOrigin>::signed(owner), + netuid, + hotkey + )); + + // Check the value + let actual_hotkey = pallet_subtensor::SubnetOwnerHotkey::::get(netuid); + assert_eq!(actual_hotkey, hotkey); + + // Root can set the hotkey + assert_ok!(AdminUtils::sudo_set_sn_owner_hotkey( + <::RuntimeOrigin>::root(), + netuid, + hotkey + )); + }); +} diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index e4721c03f5..0de83d35f4 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -370,6 +370,56 @@ impl Pallet { Ok(()) } + /// Sets or updates the hotkey account associated with the owner of a specific subnet. + /// + /// This function allows either the root origin or the current subnet owner to set or update + /// the hotkey for a given subnet. The hotkey must either not be registered yet or must be + /// associated with the caller's coldkey. The subnet must already exist. + /// + /// # Parameters + /// - `origin`: The dispatch origin of the call. Must be either root or the current owner of the subnet. + /// - `netuid`: The unique identifier of the subnet whose owner hotkey is being set. + /// - `hotkey`: The new hotkey account to be associated with the subnet owner. + /// + /// # Returns + /// - `DispatchResult`: Returns `Ok(())` if the hotkey was successfully set, or an appropriate error otherwise. + /// + /// # Errors + /// - `Error::NonAssociatedColdKey`: If the provided hotkey is already associated with a different coldkey. + /// - `Error::SubnetNotExists`: If the specified subnet does not exist. + /// + /// # Access Control + /// Only callable by: + /// - Root origin, or + /// - The coldkey account that owns the subnet. + /// + /// # Storage + /// - Updates [`SubnetOwnerHotkey`] for the given `netuid`. + pub fn do_set_sn_owner_hotkey( + origin: T::RuntimeOrigin, + netuid: u16, + hotkey: &T::AccountId, + ) -> DispatchResult { + // Ensure the caller is either root or subnet owner. + Self::ensure_subnet_owner_or_root(origin, netuid)?; + + // Ensure that the subnet exists and get owner. + ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); + let owner = SubnetOwner::::get(netuid); + + // Ensure the hotkey does not exist or is owned by the coldkey. + ensure!( + !Self::hotkey_account_exists(hotkey) || Self::coldkey_owns_hotkey(&owner, hotkey), + Error::::NonAssociatedColdKey + ); + + // Insert/update the hotkey + SubnetOwnerHotkey::::insert(netuid, hotkey); + + // Return success. + Ok(()) + } + pub fn is_valid_subnet_for_emission(netuid: u16) -> bool { FirstEmissionBlockNumber::::get(netuid).is_some() } From 1c18e63e99833bab45044df0fe2876398511c0be Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 7 Apr 2025 11:42:53 -0400 Subject: [PATCH 02/10] Allow any hotkeys, introduce rate limiting --- pallets/admin-utils/src/tests/mod.rs | 36 ++++++++++++++++++++++++- pallets/subtensor/src/lib.rs | 24 +++++++++++++++++ pallets/subtensor/src/subnets/subnet.rs | 20 +++++++++----- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 7ccfccfe03..eb9e8feafc 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -1714,7 +1714,7 @@ fn test_sudo_set_ema_halving() { // cargo test --package pallet-admin-utils --lib -- tests::test_set_sn_owner_hotkey --exact --show-output #[test] -fn test_set_sn_owner_hotkey() { +fn test_set_sn_owner_hotkey_owner() { new_test_ext().execute_with(|| { let netuid: u16 = 1; let hotkey: U256 = U256::from(3); @@ -1745,11 +1745,45 @@ fn test_set_sn_owner_hotkey() { let actual_hotkey = pallet_subtensor::SubnetOwnerHotkey::::get(netuid); assert_eq!(actual_hotkey, hotkey); + // Cannot set again (rate limited) + assert_err!( + AdminUtils::sudo_set_sn_owner_hotkey( + <::RuntimeOrigin>::signed(owner), + netuid, + hotkey + ), + pallet_subtensor::Error::::TxRateLimitExceeded + ); + + // Root can set the hotkey + // assert_ok!(AdminUtils::sudo_set_sn_owner_hotkey( + // <::RuntimeOrigin>::root(), + // netuid, + // hotkey + // )); + }); +} + +// cargo test --package pallet-admin-utils --lib -- tests::test_set_sn_owner_hotkey_root --exact --show-output +#[test] +fn test_set_sn_owner_hotkey_root() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let hotkey: U256 = U256::from(3); + add_network(netuid, 10); + + let owner = U256::from(10); + pallet_subtensor::SubnetOwner::::insert(netuid, owner); + // Root can set the hotkey assert_ok!(AdminUtils::sudo_set_sn_owner_hotkey( <::RuntimeOrigin>::root(), netuid, hotkey )); + + // Check the value + let actual_hotkey = pallet_subtensor::SubnetOwnerHotkey::::get(netuid); + assert_eq!(actual_hotkey, hotkey); }); } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index e360c307e1..435cacec88 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -66,6 +66,7 @@ pub const MAX_CRV3_COMMIT_SIZE_BYTES: u32 = 5000; #[import_section(config::config)] #[frame_support::pallet] pub mod pallet { + use crate::RateLimitKey; use crate::migrations; use frame_support::{ BoundedVec, @@ -800,6 +801,12 @@ pub mod pallet { 360 } + #[pallet::type_value] + /// Default value for setting subnet owner hotkey rate limit + pub fn DefaultSetSNOwnerHotkeyRateLimit() -> u64 { + 50400 + } + #[pallet::storage] pub type MinActivityCutoff = StorageValue<_, u16, ValueQuery, DefaultMinActivityCutoff>; @@ -1114,6 +1121,15 @@ pub mod pallet { pub type WeightsVersionKeyRateLimit = StorageValue<_, u64, ValueQuery, DefaultWeightsVersionKeyRateLimit>; + /// ============================ + /// ==== Rate Limiting ===== + /// ============================ + + #[pallet::storage] + /// --- MAP ( RateLimitKey ) --> Block number in which the last rate limited operation occured + pub type LastRateLimitedBlock = + StorageMap<_, Identity, RateLimitKey, u64, ValueQuery, DefaultZeroU64>; + /// ============================ /// ==== Subnet Locks ===== /// ============================ @@ -2432,3 +2448,11 @@ impl CollectiveInterface for () { Ok(true) } } + +/// Enum that defines types of rate limited operations for +/// storing last block when this operation occured +#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo)] +pub enum RateLimitKey { + // The setting sn owner hotkey operation is rate limited per netuid + SetSNOwnerHotkey(u16), +} diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 0de83d35f4..1dfe7334a9 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -403,15 +403,21 @@ impl Pallet { // Ensure the caller is either root or subnet owner. Self::ensure_subnet_owner_or_root(origin, netuid)?; - // Ensure that the subnet exists and get owner. + // Ensure that the subnet exists. ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); - let owner = SubnetOwner::::get(netuid); - // Ensure the hotkey does not exist or is owned by the coldkey. - ensure!( - !Self::hotkey_account_exists(hotkey) || Self::coldkey_owns_hotkey(&owner, hotkey), - Error::::NonAssociatedColdKey - ); + // Rate limit: 1 call per week + let maybe_last_block = + LastRateLimitedBlock::::try_get(RateLimitKey::SetSNOwnerHotkey(netuid)); + let current_block = Self::get_current_block_as_u64(); + if let Ok(last_block) = maybe_last_block { + ensure!( + current_block.saturating_sub(last_block) + > DefaultSetSNOwnerHotkeyRateLimit::::get(), + Error::::TxRateLimitExceeded + ); + } + LastRateLimitedBlock::::insert(RateLimitKey::SetSNOwnerHotkey(netuid), current_block); // Insert/update the hotkey SubnetOwnerHotkey::::insert(netuid, hotkey); From 10376a27f521f213b0a428f28cc169517d0b8599 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 7 Apr 2025 11:48:48 -0400 Subject: [PATCH 03/10] Update comment --- pallets/admin-utils/src/lib.rs | 13 +++++++++---- pallets/subtensor/src/subnets/subnet.rs | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 803c4b64e1..b4dec2d922 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1480,20 +1480,20 @@ pub mod pallet { /// Sets or updates the hotkey account associated with the owner of a specific subnet. /// /// This function allows either the root origin or the current subnet owner to set or update - /// the hotkey for a given subnet. The hotkey must either not be registered yet or must be - /// associated with the caller's coldkey. The subnet must already exist. + /// the hotkey for a given subnet. The subnet must already exist. To prevent abuse, the call is + /// rate-limited to once per configured interval (default: one week) per subnet. /// /// # Parameters /// - `origin`: The dispatch origin of the call. Must be either root or the current owner of the subnet. /// - `netuid`: The unique identifier of the subnet whose owner hotkey is being set. - /// - `hotkey`: The new hotkey account to be associated with the subnet owner. + /// - `hotkey`: The new hotkey account to associate with the subnet owner. /// /// # Returns /// - `DispatchResult`: Returns `Ok(())` if the hotkey was successfully set, or an appropriate error otherwise. /// /// # Errors - /// - `Error::NonAssociatedColdKey`: If the provided hotkey is already associated with a different coldkey. /// - `Error::SubnetNotExists`: If the specified subnet does not exist. + /// - `Error::TxRateLimitExceeded`: If the function is called more frequently than the allowed rate limit. /// /// # Access Control /// Only callable by: @@ -1502,6 +1502,11 @@ pub mod pallet { /// /// # Storage /// - Updates [`SubnetOwnerHotkey`] for the given `netuid`. + /// - Reads and updates [`LastRateLimitedBlock`] for rate-limiting. + /// - Reads [`DefaultSetSNOwnerHotkeyRateLimit`] to determine the interval between allowed updates. + /// + /// # Rate Limiting + /// This function is rate-limited to one call per subnet per interval (e.g., one week). #[pallet::call_index(66)] #[pallet::weight((0, DispatchClass::Operational, Pays::No))] pub fn sudo_set_sn_owner_hotkey( diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 1dfe7334a9..168e66f72c 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -373,20 +373,20 @@ impl Pallet { /// Sets or updates the hotkey account associated with the owner of a specific subnet. /// /// This function allows either the root origin or the current subnet owner to set or update - /// the hotkey for a given subnet. The hotkey must either not be registered yet or must be - /// associated with the caller's coldkey. The subnet must already exist. + /// the hotkey for a given subnet. The subnet must already exist. To prevent abuse, the call is + /// rate-limited to once per configured interval (default: one week) per subnet. /// /// # Parameters /// - `origin`: The dispatch origin of the call. Must be either root or the current owner of the subnet. /// - `netuid`: The unique identifier of the subnet whose owner hotkey is being set. - /// - `hotkey`: The new hotkey account to be associated with the subnet owner. + /// - `hotkey`: The new hotkey account to associate with the subnet owner. /// /// # Returns /// - `DispatchResult`: Returns `Ok(())` if the hotkey was successfully set, or an appropriate error otherwise. /// /// # Errors - /// - `Error::NonAssociatedColdKey`: If the provided hotkey is already associated with a different coldkey. /// - `Error::SubnetNotExists`: If the specified subnet does not exist. + /// - `Error::TxRateLimitExceeded`: If the function is called more frequently than the allowed rate limit. /// /// # Access Control /// Only callable by: @@ -395,6 +395,11 @@ impl Pallet { /// /// # Storage /// - Updates [`SubnetOwnerHotkey`] for the given `netuid`. + /// - Reads and updates [`LastRateLimitedBlock`] for rate-limiting. + /// - Reads [`DefaultSetSNOwnerHotkeyRateLimit`] to determine the interval between allowed updates. + /// + /// # Rate Limiting + /// This function is rate-limited to one call per subnet per interval (e.g., one week). pub fn do_set_sn_owner_hotkey( origin: T::RuntimeOrigin, netuid: u16, From fb11106d11d4b85beb32d6c8448b3f41bf6fda9f Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 7 Apr 2025 12:16:10 -0400 Subject: [PATCH 04/10] Use rate limiting lib for rate limits --- pallets/admin-utils/src/tests/mod.rs | 7 ------ pallets/subtensor/src/coinbase/root.rs | 6 +++++ pallets/subtensor/src/subnets/subnet.rs | 26 ++++++++++++-------- pallets/subtensor/src/utils/rate_limiting.rs | 11 +++++++++ 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index eb9e8feafc..bb813ce117 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -1754,13 +1754,6 @@ fn test_set_sn_owner_hotkey_owner() { ), pallet_subtensor::Error::::TxRateLimitExceeded ); - - // Root can set the hotkey - // assert_ok!(AdminUtils::sudo_set_sn_owner_hotkey( - // <::RuntimeOrigin>::root(), - // netuid, - // hotkey - // )); }); } diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index b2633fa381..1f3a91b339 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -665,4 +665,10 @@ impl Pallet { let halved_interval: I64F64 = interval.saturating_mul(halving); halved_interval.saturating_to_num::() } + pub fn get_rate_limited_last_block(rate_limit_key: &RateLimitKey) -> u64 { + LastRateLimitedBlock::::get(rate_limit_key) + } + pub fn set_rate_limited_last_block(rate_limit_key: &RateLimitKey, block: u64) { + LastRateLimitedBlock::::set(rate_limit_key, block); + } } diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 168e66f72c..515a35da3e 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -412,17 +412,23 @@ impl Pallet { ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); // Rate limit: 1 call per week - let maybe_last_block = - LastRateLimitedBlock::::try_get(RateLimitKey::SetSNOwnerHotkey(netuid)); + ensure!( + Self::passes_rate_limit_on_subnet( + &TransactionType::SetSNOwnerHotkey, + hotkey, // ignored + netuid, // Specific to a subnet. + ), + Error::::TxRateLimitExceeded + ); + + // Set last transaction block let current_block = Self::get_current_block_as_u64(); - if let Ok(last_block) = maybe_last_block { - ensure!( - current_block.saturating_sub(last_block) - > DefaultSetSNOwnerHotkeyRateLimit::::get(), - Error::::TxRateLimitExceeded - ); - } - LastRateLimitedBlock::::insert(RateLimitKey::SetSNOwnerHotkey(netuid), current_block); + Self::set_last_transaction_block_on_subnet( + &hotkey, + netuid, + &TransactionType::SetSNOwnerHotkey, + current_block, + ); // Insert/update the hotkey SubnetOwnerHotkey::::insert(netuid, hotkey); diff --git a/pallets/subtensor/src/utils/rate_limiting.rs b/pallets/subtensor/src/utils/rate_limiting.rs index c37a78d2e4..7edaebc98a 100644 --- a/pallets/subtensor/src/utils/rate_limiting.rs +++ b/pallets/subtensor/src/utils/rate_limiting.rs @@ -8,6 +8,7 @@ pub enum TransactionType { Unknown, RegisterNetwork, SetWeightsVersionKey, + SetSNOwnerHotkey, } /// Implement conversion from TransactionType to u16 @@ -19,6 +20,7 @@ impl From for u16 { TransactionType::Unknown => 2, TransactionType::RegisterNetwork => 3, TransactionType::SetWeightsVersionKey => 4, + TransactionType::SetSNOwnerHotkey => 5, } } } @@ -31,6 +33,7 @@ impl From for TransactionType { 1 => TransactionType::SetChildkeyTake, 3 => TransactionType::RegisterNetwork, 4 => TransactionType::SetWeightsVersionKey, + 5 => TransactionType::SetSNOwnerHotkey, _ => TransactionType::Unknown, } } @@ -56,6 +59,8 @@ impl Pallet { match tx_type { TransactionType::SetWeightsVersionKey => (Tempo::::get(netuid) as u64) .saturating_mul(WeightsVersionKeyRateLimit::::get()), + TransactionType::SetSNOwnerHotkey => DefaultSetSNOwnerHotkeyRateLimit::::get(), + _ => Self::get_rate_limit(tx_type), } } @@ -102,6 +107,9 @@ impl Pallet { ) -> u64 { match tx_type { TransactionType::RegisterNetwork => Self::get_network_last_lock_block(), + TransactionType::SetSNOwnerHotkey => { + Self::get_rate_limited_last_block(&RateLimitKey::SetSNOwnerHotkey(netuid)) + } _ => { let tx_as_u16: u16 = (*tx_type).into(); TransactionKeyLastBlock::::get((hotkey, netuid, tx_as_u16)) @@ -126,6 +134,9 @@ impl Pallet { ) { match tx_type { TransactionType::RegisterNetwork => Self::set_network_last_lock_block(block), + TransactionType::SetSNOwnerHotkey => { + Self::set_rate_limited_last_block(&RateLimitKey::SetSNOwnerHotkey(netuid), block) + } _ => { let tx_as_u16: u16 = (*tx_type).into(); TransactionKeyLastBlock::::insert((key, netuid, tx_as_u16), block); From 50b723f6471d004716e2e3baf25bdb6d136bd249 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 7 Apr 2025 12:39:49 -0400 Subject: [PATCH 05/10] Fix clippy --- pallets/subtensor/src/subnets/subnet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 515a35da3e..8acf93b0ae 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -424,7 +424,7 @@ impl Pallet { // Set last transaction block let current_block = Self::get_current_block_as_u64(); Self::set_last_transaction_block_on_subnet( - &hotkey, + hotkey, netuid, &TransactionType::SetSNOwnerHotkey, current_block, From 4e63cff678744312d8cd73ca3f31fb44822a879c Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Thu, 17 Apr 2025 17:43:01 -0400 Subject: [PATCH 06/10] restrict Owner proxy from setting OwnerHK --- runtime/src/lib.rs | 10 +++++++++- runtime/tests/pallet_proxy.rs | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 41117a6c5d..2c6eaf6848 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -710,7 +710,15 @@ impl InstanceFilter for ProxyType { }) => *alpha_amount < SMALL_TRANSFER_LIMIT, _ => false, }, - ProxyType::Owner => matches!(c, RuntimeCall::AdminUtils(..)), + ProxyType::Owner => { + matches!(c, RuntimeCall::AdminUtils(..)) + && !matches!( + c, + RuntimeCall::AdminUtils( + pallet_admin_utils::Call::sudo_set_sn_owner_hotkey { .. } + ) + ) + } ProxyType::NonCritical => !matches!( c, RuntimeCall::SubtensorModule(pallet_subtensor::Call::dissolve_network { .. }) diff --git a/runtime/tests/pallet_proxy.rs b/runtime/tests/pallet_proxy.rs index 563c274bb9..1fcb36dec5 100644 --- a/runtime/tests/pallet_proxy.rs +++ b/runtime/tests/pallet_proxy.rs @@ -68,6 +68,15 @@ fn call_owner_util() -> RuntimeCall { }) } +// sn owner hotkey call +fn call_sn_owner_hotkey() -> RuntimeCall { + let netuid = 1; + RuntimeCall::AdminUtils(pallet_admin_utils::Call::sudo_set_sn_owner_hotkey { + netuid, + hotkey: AccountId::from(ACCOUNT).into(), + }) +} + // critical call for Subtensor fn call_propose() -> RuntimeCall { let proposal = call_remark(); @@ -230,3 +239,30 @@ fn test_non_transfer_cannot_transfer() { ); }); } + +#[test] +fn test_owner_type_cannot_set_sn_owner_hotkey() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(AccountId::from(ACCOUNT)), + AccountId::from(DELEGATE).into(), + ProxyType::Owner, + 0 + )); + + let call = call_sn_owner_hotkey(); + assert_ok!(Proxy::proxy( + RuntimeOrigin::signed(AccountId::from(DELEGATE)), + AccountId::from(ACCOUNT).into(), + None, + Box::new(call.clone()), + )); + + System::assert_last_event( + pallet_proxy::Event::ProxyExecuted { + result: Err(SystemError::CallFiltered.into()), + } + .into(), + ); + }); +} From 3c0a0f5b8b923e869b9b5a72da0432fef11514ea Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 21 Apr 2025 15:09:54 -0400 Subject: [PATCH 07/10] cargo fmt --- pallets/admin-utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 3ee558988d..1a2b4ef8c5 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1515,7 +1515,7 @@ pub mod pallet { hotkey: T::AccountId, ) -> DispatchResult { pallet_subtensor::Pallet::::do_set_sn_owner_hotkey(origin, netuid, &hotkey) - } + } /// Enables or disables subtoken trading for a given subnet. /// From 03650bb3056bf84a9cc25de4befa47058e5b0276 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 21 Apr 2025 16:00:07 -0400 Subject: [PATCH 08/10] cargo fmt --- pallets/admin-utils/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 3ee558988d..1a2b4ef8c5 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1515,7 +1515,7 @@ pub mod pallet { hotkey: T::AccountId, ) -> DispatchResult { pallet_subtensor::Pallet::::do_set_sn_owner_hotkey(origin, netuid, &hotkey) - } + } /// Enables or disables subtoken trading for a given subnet. /// From bdbe770d59fedbb9569145d04a0bc80ab222664d Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 21 Apr 2025 18:07:18 -0400 Subject: [PATCH 09/10] Bump spec version --- 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 d77a678744..948cff085c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -207,7 +207,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: 262, + spec_version: 263, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 454b90ebc1de02abfdee1e2c88186ed521e48e3d Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sun, 27 Apr 2025 09:32:51 -0700 Subject: [PATCH 10/10] update write values --- pallets/subtensor/src/macros/dispatches.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index de22d64c88..98b83791e8 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1195,7 +1195,7 @@ mod dispatches { #[pallet::call_index(59)] #[pallet::weight((Weight::from_parts(260_500_000, 0) .saturating_add(T::DbWeight::get().reads(33)) - .saturating_add(T::DbWeight::get().writes(52)), DispatchClass::Operational, Pays::No))] + .saturating_add(T::DbWeight::get().writes(51)), DispatchClass::Operational, Pays::No))] pub fn register_network(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { Self::do_register_network(origin, &hotkey, 1, None) } @@ -1533,7 +1533,7 @@ mod dispatches { #[pallet::call_index(79)] #[pallet::weight((Weight::from_parts(239_700_000, 0) .saturating_add(T::DbWeight::get().reads(32)) - .saturating_add(T::DbWeight::get().writes(51)), DispatchClass::Operational, Pays::No))] + .saturating_add(T::DbWeight::get().writes(50)), DispatchClass::Operational, Pays::No))] pub fn register_network_with_identity( origin: OriginFor, hotkey: T::AccountId,