From 5089be8bd87aac0122e6ed92202059680ae5805c Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Sun, 26 Jan 2025 19:04:14 -0500 Subject: [PATCH 1/4] add alpha transfer enabled check --- pallets/admin-utils/src/benchmarking.rs | 13 +++++ pallets/admin-utils/src/lib.rs | 41 ++++++++++++++- pallets/admin-utils/src/weights.rs | 16 ++++++ pallets/subtensor/src/lib.rs | 17 ++++++- pallets/subtensor/src/macros/errors.rs | 2 + pallets/subtensor/src/staking/move_stake.rs | 6 +++ pallets/subtensor/src/staking/stake_utils.rs | 25 ++++++++++ pallets/subtensor/src/tests/move_stake.rs | 52 ++++++++++++++++++++ pallets/subtensor/src/utils/misc.rs | 20 +++++++- 9 files changed, 189 insertions(+), 3 deletions(-) diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index af9b68051f..ac268ef5a7 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -280,5 +280,18 @@ mod benchmarks { _(RawOrigin::Root, 1u16/*netuid*/, 1_000_000_000_000_000u64/*max_stake*/)/*sudo_set_network_max_stake*/; } + #[benchmark] + fn sudo_enable_alpha_transfer() { + pallet_subtensor::Pallet::::init_new_network( + 1u16, /*netuid*/ + 1u16, /*sudo_tempo*/ + ); + let owner: T::AccountId = account("Alice", 0, 1); + SubnetOwner::::insert(1u16, owner.clone()); + + #[extrinsic_call] + _(RawOrigin::Signed(owner.clone()), 1u16/*netuid*/)/*sudo_enable_alpha_transfer*/; + } + //impl_benchmark_test_suite!(AdminUtils, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 7de39aa38a..a7730258dd 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -69,7 +69,10 @@ pub mod pallet { } #[pallet::event] - pub enum Event {} + pub enum Event { + /// Alpha transfer was enabled on a subnet. + AlphaTransferEnabled(u16, bool), + } // Errors inform users that something went wrong. #[pallet::error] @@ -1287,6 +1290,42 @@ pub mod pallet { ensure_root(origin)?; T::Grandpa::schedule_change(next_authorities, in_blocks, forced) } + + /// Enables alpha transfer for a specific subnet. + /// + /// This extrinsic allows the subnet owner to enable alpha transfer for a specific subnet. + /// + /// # Arguments + /// * `origin` - The origin of the call, which must be the subnet owner. + /// * `netuid` - The unique identifier of the subnet for which the periods are being set. + /// + /// # Errors + /// * `BadOrigin` - If the caller is neither the subnet owner nor the root account. + /// * `SubnetDoesNotExist` - If the specified subnet does not exist. + /// + /// # Weight + /// Weight is handled by the `#[pallet::weight]` attribute. + #[pallet::call_index(61)] + #[pallet::weight(::WeightInfo::sudo_enable_alpha_transfer())] + pub fn sudo_enable_alpha_transfer(origin: OriginFor, netuid: u16) -> DispatchResult { + pallet_subtensor::Pallet::::ensure_subnet_owner(origin, netuid)?; + + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); + + if pallet_subtensor::Pallet::::get_alpha_transfer_enabled(netuid) { + return Ok(()); // exit early if already enabled + } + + pallet_subtensor::Pallet::::set_alpha_transfer_enabled(netuid, true); + // Log and emit event + log::debug!("AlphaTransferEnabled( netuid: {:?} ) ", netuid); + Self::deposit_event(Event::AlphaTransferEnabled(netuid, true)); + + Ok(()) + } } } diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index 6ef9523546..a228b15ef7 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -65,6 +65,7 @@ pub trait WeightInfo { fn sudo_set_commit_reveal_weights_enabled() -> Weight; fn sudo_set_evm_chain_id() -> Weight; fn schedule_grandpa_change(a: u32) -> Weight; + fn sudo_set_alpha_transfer_enabled() -> Weight; } /// Weights for `pallet_admin_utils` using the Substrate node and recommended hardware. @@ -456,6 +457,14 @@ impl WeightInfo for SubstrateWeight { // TODO should be replaced by benchmarked weights Weight::default() } + + fn sudo_set_alpha_transfer_enabled() -> Weight { + // TODO benchmark + // 1 read for check subnet owner + // 1 read for check alpha transfer enabled + // 1 write for set alpha transfer enabled + Weight::default().saturating_add(RocksDbWeight::get().reads_writes(2_u64, 1_u64)) + } } // For backwards compatibility and tests. @@ -851,4 +860,11 @@ impl WeightInfo for () { // TODO should be replaced by benchmarked weights Weight::default() } + fn sudo_set_alpha_transfer_enabled() -> Weight { + // TODO benchmark + // 1 read for check subnet owner + // 1 read for check alpha transfer enabled + // 1 write for set alpha transfer enabled + Weight::default().saturating_add(RocksDbWeight::get().reads_writes(2_u64, 1_u64)) + } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index cbe394037f..800387f5d7 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -669,6 +669,11 @@ pub mod pallet { false } #[pallet::type_value] + /// Default value for alpha transfer enabled. + pub fn DefaultAlphaTransferEnabled() -> bool { + false + } + #[pallet::type_value] /// Senate requirements pub fn DefaultSenateRequiredStakePercentage() -> u64 { T::InitialSenateRequiredStakePercentage::get() @@ -1221,6 +1226,10 @@ pub mod pallet { pub type CommitRevealWeightsEnabled = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultCommitRevealWeightsEnabled>; #[pallet::storage] + /// --- MAP ( netuid ) --> alpha transfer enabled if true + pub type AlphaTransferEnabled = + StorageMap<_, Identity, u16, bool, ValueQuery, DefaultAlphaTransferEnabled>; + #[pallet::storage] /// --- MAP ( netuid ) --> Burn pub type Burn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBurn>; #[pallet::storage] @@ -1563,6 +1572,7 @@ pub enum CustomTransactionError { NotEnoughStakeToWithdraw, RateLimitExceeded, BadRequest, + AlphaTransferNotEnabled, } impl From for u8 { @@ -1575,6 +1585,7 @@ impl From for u8 { CustomTransactionError::HotkeyAccountDoesntExist => 4, CustomTransactionError::NotEnoughStakeToWithdraw => 5, CustomTransactionError::RateLimitExceeded => 6, + CustomTransactionError::AlphaTransferNotEnabled => 7, CustomTransactionError::BadRequest => 255, } } @@ -1642,6 +1653,10 @@ where CustomTransactionError::NotEnoughStakeToWithdraw.into(), ) .into()), + Error::::AlphaTransferNotEnabled => Err(InvalidTransaction::Custom( + CustomTransactionError::AlphaTransferNotEnabled.into(), + ) + .into()), _ => Err( InvalidTransaction::Custom(CustomTransactionError::BadRequest.into()).into(), ), @@ -1830,7 +1845,7 @@ where alpha_amount, }) => { // Fully validate the user input - Self::result_to_validity(Pallet::::validate_stake_transition( + Self::result_to_validity(Pallet::::validate_alpha_transfer( who, destination_coldkey, hotkey, diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index dd5e97b78a..588c54eff9 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -185,5 +185,7 @@ mod errors { CommittingWeightsTooFast, /// Stake amount is too low. AmountTooLow, + /// Alpha transfer is not enabled on this subnet. + AlphaTransferNotEnabled, } } diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs index 4644b32134..ff830224e3 100644 --- a/pallets/subtensor/src/staking/move_stake.rs +++ b/pallets/subtensor/src/staking/move_stake.rs @@ -114,6 +114,12 @@ impl Pallet { alpha_amount, )?; + // Ensure alpha transfer is enabled on the origin subnet + ensure!( + Pallet::::get_alpha_transfer_enabled(origin_netuid), + Error::::AlphaTransferNotEnabled + ); + // 9. Emit an event for logging/monitoring. log::info!( "StakeTransferred(origin_coldkey: {:?}, destination_coldkey: {:?}, hotkey: {:?}, origin_netuid: {:?}, destination_netuid: {:?}, amount: {:?})", diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index f34a5ace00..a273e338d2 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -841,6 +841,31 @@ impl Pallet { Ok(()) } + + pub fn validate_alpha_transfer( + origin_coldkey: &T::AccountId, + destination_coldkey: &T::AccountId, + origin_hotkey: &T::AccountId, + destination_hotkey: &T::AccountId, + origin_netuid: u16, + destination_netuid: u16, + alpha_amount: u64, + ) -> Result<(), Error> { + ensure!( + Self::get_alpha_transfer_enabled(origin_netuid), + Error::::AlphaTransferNotEnabled + ); + + Self::validate_stake_transition( + origin_coldkey, + destination_coldkey, + origin_hotkey, + destination_hotkey, + origin_netuid, + destination_netuid, + alpha_amount, + ) + } } /////////////////////////////////////////// diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs index f299832ed2..bcd3c45ab3 100644 --- a/pallets/subtensor/src/tests/move_stake.rs +++ b/pallets/subtensor/src/tests/move_stake.rs @@ -824,6 +824,9 @@ fn test_do_transfer_success() { let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); let fee = DefaultStakingFee::::get(); + // Enable alpha transfer on this subnet + SubtensorModule::set_alpha_transfer_enabled(netuid, true); + // 2. Define the origin coldkey, destination coldkey, and hotkey to be used. let origin_coldkey = U256::from(1); let destination_coldkey = U256::from(2); @@ -901,6 +904,9 @@ fn test_do_transfer_nonexistent_hotkey() { let subnet_owner_hotkey = U256::from(1002); let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + // Enable alpha transfer on this subnet + SubtensorModule::set_alpha_transfer_enabled(netuid, true); + let origin_coldkey = U256::from(1); let destination_coldkey = U256::from(2); let nonexistent_hotkey = U256::from(999); @@ -926,6 +932,9 @@ fn test_do_transfer_insufficient_stake() { let subnet_owner_hotkey = U256::from(1002); let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + // Enable alpha transfer on this subnet + SubtensorModule::set_alpha_transfer_enabled(netuid, true); + let origin_coldkey = U256::from(1); let destination_coldkey = U256::from(2); let hotkey = U256::from(3); @@ -956,6 +965,9 @@ fn test_do_transfer_wrong_origin() { let subnet_owner_hotkey = U256::from(1011); let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + // Enable alpha transfer on this subnet + SubtensorModule::set_alpha_transfer_enabled(netuid, true); + let origin_coldkey = U256::from(1); let wrong_coldkey = U256::from(9999); let destination_coldkey = U256::from(2); @@ -988,6 +1000,9 @@ fn test_do_transfer_minimum_stake_check() { let subnet_owner_hotkey = U256::from(1002); let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + // Enable alpha transfer on this subnet + SubtensorModule::set_alpha_transfer_enabled(netuid, true); + let origin_coldkey = U256::from(1); let destination_coldkey = U256::from(2); let hotkey = U256::from(3); @@ -1019,6 +1034,9 @@ fn test_do_transfer_different_subnets() { let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + // Enable alpha transfer on origin subnet + SubtensorModule::set_alpha_transfer_enabled(origin_netuid, true); + // 2. Define origin/destination coldkeys and hotkey. let origin_coldkey = U256::from(1); let destination_coldkey = U256::from(2); @@ -1083,6 +1101,40 @@ fn test_do_transfer_different_subnets() { }); } +/// RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::move_stake::test_do_transfer_alpha_transfer_not_enabled --show-output +#[test] +fn test_do_transfer_alpha_transfer_not_enabled() { + new_test_ext(1).execute_with(|| { + let subnet_owner_coldkey = U256::from(1001); + let subnet_owner_hotkey = U256::from(1002); + let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + + let origin_coldkey = U256::from(1); + let destination_coldkey = U256::from(2); + let hotkey = U256::from(3); + let stake_amount = DefaultMinStake::::get() * 10; + + SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey); + SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount, 0); + + // Verify alpha transfer is not enabled + assert!(!SubtensorModule::get_alpha_transfer_enabled(netuid)); + + let alpha = stake_amount - 10_000; + assert_err!( + SubtensorModule::do_transfer_stake( + RuntimeOrigin::signed(origin_coldkey), + destination_coldkey, + hotkey, + netuid, + netuid, + alpha + ), + Error::::AlphaTransferNotEnabled + ); + }); +} + #[test] fn test_do_swap_success() { new_test_ext(1).execute_with(|| { diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index f1e0c7eb40..557f9cc10f 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -1,6 +1,6 @@ use super::*; use crate::{ - system::{ensure_root, ensure_signed_or_root, pallet_prelude::BlockNumberFor}, + system::{ensure_root, ensure_signed, ensure_signed_or_root, pallet_prelude::BlockNumberFor}, Error, }; use sp_core::Get; @@ -22,6 +22,17 @@ impl Pallet { } } + /// Ensure that the caller is the owner of the subnet. + /// Note: this is *not* true for the root account. + 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 ==== // ======================== @@ -470,6 +481,13 @@ impl Pallet { CommitRevealWeightsEnabled::::set(netuid, enabled); } + pub fn get_alpha_transfer_enabled(netuid: u16) -> bool { + AlphaTransferEnabled::::get(netuid) + } + pub fn set_alpha_transfer_enabled(netuid: u16, enabled: bool) { + AlphaTransferEnabled::::set(netuid, enabled); + } + pub fn get_rho(netuid: u16) -> u16 { Rho::::get(netuid) } From 50830120107c9ae4cf686df029a0c10d8a2b9572 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Sun, 26 Jan 2025 19:08:41 -0500 Subject: [PATCH 2/4] fix naming --- pallets/admin-utils/src/weights.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index a228b15ef7..6d0852f566 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -65,7 +65,7 @@ pub trait WeightInfo { fn sudo_set_commit_reveal_weights_enabled() -> Weight; fn sudo_set_evm_chain_id() -> Weight; fn schedule_grandpa_change(a: u32) -> Weight; - fn sudo_set_alpha_transfer_enabled() -> Weight; + fn sudo_enable_alpha_transfer() -> Weight; } /// Weights for `pallet_admin_utils` using the Substrate node and recommended hardware. @@ -458,7 +458,7 @@ impl WeightInfo for SubstrateWeight { Weight::default() } - fn sudo_set_alpha_transfer_enabled() -> Weight { + fn sudo_enable_alpha_transfer() -> Weight { // TODO benchmark // 1 read for check subnet owner // 1 read for check alpha transfer enabled @@ -860,7 +860,7 @@ impl WeightInfo for () { // TODO should be replaced by benchmarked weights Weight::default() } - fn sudo_set_alpha_transfer_enabled() -> Weight { + fn sudo_enable_alpha_transfer() -> Weight { // TODO benchmark // 1 read for check subnet owner // 1 read for check alpha transfer enabled From 0128a94bef1312ca0d6daa80b873af4a7a26be8b Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Sun, 26 Jan 2025 19:09:19 -0500 Subject: [PATCH 3/4] add event deposit func --- pallets/admin-utils/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index a7730258dd..91ff72b887 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -69,6 +69,7 @@ pub mod pallet { } #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Alpha transfer was enabled on a subnet. AlphaTransferEnabled(u16, bool), From 6994e9b0aec30aab42f9203c24d26723ce19d549 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Tue, 28 Jan 2025 15:29:35 -0500 Subject: [PATCH 4/4] fix benchmark --- pallets/admin-utils/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index ac268ef5a7..9aeb23ee56 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -287,7 +287,7 @@ mod benchmarks { 1u16, /*sudo_tempo*/ ); let owner: T::AccountId = account("Alice", 0, 1); - SubnetOwner::::insert(1u16, owner.clone()); + pallet_subtensor::SubnetOwner::::insert(1u16, owner.clone()); #[extrinsic_call] _(RawOrigin::Signed(owner.clone()), 1u16/*netuid*/)/*sudo_enable_alpha_transfer*/;