diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 7bc9e986e0..fe2f102a7b 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1399,6 +1399,36 @@ pub mod pallet { log::debug!("SubnetMovingAlphaSet( alpha: {:?} )", alpha); Ok(()) } + + /// Change the SubnetOwnerHotkey for a given subnet. + /// + /// # Arguments + /// * `origin` - The origin of the call, which must be the subnet owner. + /// * `netuid` - The unique identifier for the subnet. + /// * `hotkey` - The new hotkey for the subnet owner. + /// + /// # Errors + /// * `BadOrigin` - If the caller is not the subnet owner or root account. + /// + /// # Weight + /// Weight is handled by the `#[pallet::weight]` attribute. + #[pallet::call_index(64)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_subnet_owner_hotkey( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + ) -> DispatchResult { + pallet_subtensor::Pallet::::ensure_subnet_owner(origin.clone(), netuid)?; + pallet_subtensor::Pallet::::set_subnet_owner_hotkey(netuid, &hotkey); + + log::debug!( + "SubnetOwnerHotkeySet( netuid: {:?}, hotkey: {:?} )", + netuid, + hotkey + ); + Ok(()) + } } } diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 6c879635e3..6f6cdad976 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -1466,3 +1466,46 @@ fn test_sudo_root_sets_subnet_moving_alpha() { assert_eq!(pallet_subtensor::SubnetMovingAlpha::::get(), alpha); }); } + +#[test] +fn test_sudo_set_subnet_owner_hotkey() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + + let coldkey: U256 = U256::from(1); + let hotkey: U256 = U256::from(2); + let new_hotkey: U256 = U256::from(3); + + let coldkey_origin = <::RuntimeOrigin>::signed(coldkey); + let root = RuntimeOrigin::root(); + let random_account = RuntimeOrigin::signed(U256::from(123456)); + + pallet_subtensor::SubnetOwner::::insert(netuid, coldkey); + pallet_subtensor::SubnetOwnerHotkey::::insert(netuid, hotkey); + assert_eq!( + pallet_subtensor::SubnetOwnerHotkey::::get(netuid), + hotkey + ); + + assert_ok!(AdminUtils::sudo_set_subnet_owner_hotkey( + coldkey_origin, + netuid, + new_hotkey + )); + + assert_eq!( + pallet_subtensor::SubnetOwnerHotkey::::get(netuid), + new_hotkey + ); + + assert_noop!( + AdminUtils::sudo_set_subnet_owner_hotkey(random_account, netuid, new_hotkey), + DispatchError::BadOrigin + ); + + assert_noop!( + AdminUtils::sudo_set_subnet_owner_hotkey(root, netuid, new_hotkey), + DispatchError::BadOrigin + ); + }); +} diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 40890b018a..3290c343c3 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -271,5 +271,11 @@ mod events { /// Parameters: /// (netuid, bool) TransferToggle(u16, bool), + + /// The owner hotkey for a subnet has been set. + /// + /// Parameters: + /// (netuid, new_hotkey) + SubnetOwnerHotkeySet(u16, T::AccountId), } } diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index bd093a76b5..bca9a456bb 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -1,7 +1,7 @@ use super::*; use crate::{ Error, - system::{ensure_root, ensure_signed_or_root, pallet_prelude::BlockNumberFor}, + system::{ensure_root, ensure_signed, ensure_signed_or_root, pallet_prelude::BlockNumberFor}, }; use safe_math::*; use sp_core::Get; @@ -23,6 +23,15 @@ impl Pallet { } } + pub fn ensure_subnet_owner(o: T::RuntimeOrigin, netuid: u16) -> Result<(), DispatchError> { + let coldkey = ensure_signed(o); + match coldkey { + Ok(who) if SubnetOwner::::get(netuid) == who => Ok(()), + Ok(_) => Err(DispatchError::BadOrigin), + Err(x) => Err(x.into()), + } + } + // ======================== // ==== Global Setters ==== // ======================== @@ -743,4 +752,20 @@ impl Pallet { DissolveNetworkScheduleDuration::::set(duration); Self::deposit_event(Event::DissolveNetworkScheduleDurationSet(duration)); } + + /// Set the owner hotkey for a subnet. + /// + /// # Arguments + /// + /// * `netuid` - The unique identifier for the subnet. + /// * `hotkey` - The new hotkey for the subnet owner. + /// + /// # Effects + /// + /// * Update the SubnetOwnerHotkey storage. + /// * Emits a SubnetOwnerHotkeySet event. + pub fn set_subnet_owner_hotkey(netuid: u16, hotkey: &T::AccountId) { + SubnetOwnerHotkey::::insert(netuid, hotkey.clone()); + Self::deposit_event(Event::SubnetOwnerHotkeySet(netuid, hotkey.clone())); + } }