From c6a68e982cd4a36ddf172f39cb46a2405240473d Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 22 Apr 2025 23:48:43 +0800 Subject: [PATCH 01/44] init solution --- pallets/subtensor/src/macros/dispatches.rs | 5 +- pallets/subtensor/src/swap/swap_hotkey.rs | 105 +++++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 4ea03c957b..c216bc469d 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -926,7 +926,7 @@ mod dispatches { Self::do_burned_registration(origin, netuid, hotkey) } - /// The extrinsic for user to change its hotkey + /// The extrinsic for user to change its hotkey in subnet or all subnets. #[pallet::call_index(70)] #[pallet::weight((Weight::from_parts(1_940_000_000, 0) .saturating_add(T::DbWeight::get().reads(272)) @@ -935,8 +935,9 @@ mod dispatches { origin: OriginFor, hotkey: T::AccountId, new_hotkey: T::AccountId, + netuid: Option, ) -> DispatchResultWithPostInfo { - Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) + Self::do_swap_hotkey(origin, &hotkey, &new_hotkey, netuid) } /// The extrinsic for user to change the coldkey associated with their account. diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 54c7c01d8e..10bb3aa6a7 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -11,6 +11,7 @@ impl Pallet { /// * `origin` - The origin of the transaction, and also the coldkey account. /// * `old_hotkey` - The old hotkey to be swapped. /// * `new_hotkey` - The new hotkey to replace the old one. + /// * `netuid` - The hotkey swap in a subnet or all subnets. /// /// # Returns /// @@ -27,6 +28,7 @@ impl Pallet { origin: T::RuntimeOrigin, old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, + netuid: Option, ) -> DispatchResultWithPostInfo { // 1. Ensure the origin is signed and get the coldkey let coldkey = ensure_signed(origin)?; @@ -489,4 +491,107 @@ impl Pallet { } Ok(()) } + + /// Swaps the hotkey of a coldkey account. + /// + /// # Arguments + /// + /// * `origin` - The origin of the transaction, and also the coldkey account. + /// * `old_hotkey` - The old hotkey to be swapped. + /// * `new_hotkey` - The new hotkey to replace the old one. + /// + /// # Returns + /// + /// * `DispatchResultWithPostInfo` - The result of the dispatch. + /// + /// # Errors + /// + /// * `NonAssociatedColdKey` - If the coldkey does not own the old hotkey. + /// * `HotKeySetTxRateLimitExceeded` - If the transaction rate limit is exceeded. + /// * `NewHotKeyIsSameWithOld` - If the new hotkey is the same as the old hotkey. + /// * `HotKeyAlreadyRegisteredInSubNet` - If the new hotkey is already registered in the subnet. + /// * `NotEnoughBalanceToPaySwapHotKey` - If there is not enough balance to pay for the swap. + pub fn do_swap_hotkey_in_subnet( + origin: T::RuntimeOrigin, + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid: Option, + ) -> DispatchResultWithPostInfo { + // 1. Ensure the origin is signed and get the coldkey + let coldkey = ensure_signed(origin)?; + + // 2. Initialize the weight for this operation + let mut weight = T::DbWeight::get().reads(2); + + // 3. Ensure the new hotkey is different from the old one + ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); + + let netuid = netuid.unwrap_or(0); + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); + + // 4. Ensure the new hotkey is not already registered on any network + ensure!( + IsNetworkMember::::get(new_hotkey, netuid), + Error::::HotKeyNotRegisteredInSubNet + ); + + // 5. Update the weight for the checks above + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); + + // 6. Ensure the coldkey owns the old hotkey + ensure!( + Self::coldkey_owns_hotkey(&coldkey, old_hotkey), + Error::::NonAssociatedColdKey + ); + + // 7. Get the current block number + let block: u64 = Self::get_current_block_as_u64(); + + // 8. Ensure the transaction rate limit is not exceeded + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), + Error::::HotKeySetTxRateLimitExceeded + ); + + // 9. Update the weight for reading the total networks + weight.saturating_accrue( + T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), + ); + + // 10. Get the cost for swapping the key + let swap_cost = Self::get_key_swap_cost(); + log::debug!("Swap cost: {:?}", swap_cost); + + // 11. Ensure the coldkey has enough balance to pay for the swap + ensure!( + Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + + // 12. Remove the swap cost from the coldkey's account + let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + + // 13. Burn the tokens + Self::burn_tokens(actual_burn_amount); + + // 14. Perform the hotkey swap + let _ = Self::perform_hotkey_swap(old_hotkey, new_hotkey, &coldkey, &mut weight); + + // 15. Update the last transaction block for the coldkey + Self::set_last_tx_block(&coldkey, block); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + // 16. Emit an event for the hotkey swap + Self::deposit_event(Event::HotkeySwapped { + coldkey, + old_hotkey: old_hotkey.clone(), + new_hotkey: new_hotkey.clone(), + }); + + // 17. Return the weight of the operation + Ok(Some(weight).into()) + } } From d01d1c5dd056c4f7c097b10b89287aa12b1ceb70 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 25 Apr 2025 10:01:33 +0800 Subject: [PATCH 02/44] keep progress --- pallets/subtensor/src/macros/config.rs | 3 + pallets/subtensor/src/subnets/uids.rs | 6 ++ pallets/subtensor/src/swap/swap_hotkey.rs | 105 ++++++---------------- 3 files changed, 37 insertions(+), 77 deletions(-) diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index cf4d97b65b..46ca9dadca 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -213,5 +213,8 @@ mod config { /// Block number after a new subnet accept the start call extrinsic. #[pallet::constant] type DurationOfStartCall: Get; + /// Cost of swapping a hotkey in a subnet. + #[pallet::constant] + type KeySwapOneSubnetCost: Get; } } diff --git a/pallets/subtensor/src/subnets/uids.rs b/pallets/subtensor/src/subnets/uids.rs index c97252677c..008fc03669 100644 --- a/pallets/subtensor/src/subnets/uids.rs +++ b/pallets/subtensor/src/subnets/uids.rs @@ -187,4 +187,10 @@ impl Pallet { } false } + + /// Return true if a hotkey is registered on specific network. + /// + pub fn is_hotkey_registered_on_specific_network(hotkey: &T::AccountId, netuid: u16) -> bool { + IsNetworkMember::::contains_key(hotkey, netuid) + } } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 10bb3aa6a7..e74475959f 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -33,27 +33,21 @@ impl Pallet { // 1. Ensure the origin is signed and get the coldkey let coldkey = ensure_signed(origin)?; + // 6. Ensure the coldkey owns the old hotkey + ensure!( + Self::coldkey_owns_hotkey(&coldkey, old_hotkey), + Error::::NonAssociatedColdKey + ); + // 2. Initialize the weight for this operation let mut weight = T::DbWeight::get().reads(2); // 3. Ensure the new hotkey is different from the old one ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); - // 4. Ensure the new hotkey is not already registered on any network - ensure!( - !Self::is_hotkey_registered_on_any_network(new_hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - // 5. Update the weight for the checks above weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - // 6. Ensure the coldkey owns the old hotkey - ensure!( - Self::coldkey_owns_hotkey(&coldkey, old_hotkey), - Error::::NonAssociatedColdKey - ); - // 7. Get the current block number let block: u64 = Self::get_current_block_as_u64(); @@ -68,6 +62,16 @@ impl Pallet { T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), ); + if let Some(netuid) = netuid { + return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight); + }; + + // 4. Ensure the new hotkey is not already registered on any network + ensure!( + !Self::is_hotkey_registered_on_any_network(new_hotkey), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + // 10. Get the cost for swapping the key let swap_cost = Self::get_key_swap_cost(); log::debug!("Swap cost: {:?}", swap_cost); @@ -492,78 +496,26 @@ impl Pallet { Ok(()) } - /// Swaps the hotkey of a coldkey account. - /// - /// # Arguments - /// - /// * `origin` - The origin of the transaction, and also the coldkey account. - /// * `old_hotkey` - The old hotkey to be swapped. - /// * `new_hotkey` - The new hotkey to replace the old one. - /// - /// # Returns - /// - /// * `DispatchResultWithPostInfo` - The result of the dispatch. - /// - /// # Errors - /// - /// * `NonAssociatedColdKey` - If the coldkey does not own the old hotkey. - /// * `HotKeySetTxRateLimitExceeded` - If the transaction rate limit is exceeded. - /// * `NewHotKeyIsSameWithOld` - If the new hotkey is the same as the old hotkey. - /// * `HotKeyAlreadyRegisteredInSubNet` - If the new hotkey is already registered in the subnet. - /// * `NotEnoughBalanceToPaySwapHotKey` - If there is not enough balance to pay for the swap. - pub fn do_swap_hotkey_in_subnet( - origin: T::RuntimeOrigin, + fn swap_hotkey_on_subnet( + coldkey: &T::AccountId, old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - netuid: Option, + netuid: u16, + init_weight: Weight, ) -> DispatchResultWithPostInfo { - // 1. Ensure the origin is signed and get the coldkey - let coldkey = ensure_signed(origin)?; - - // 2. Initialize the weight for this operation - let mut weight = T::DbWeight::get().reads(2); - - // 3. Ensure the new hotkey is different from the old one - ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); + let mut weight = init_weight; - let netuid = netuid.unwrap_or(0); - ensure!( - Self::if_subnet_exist(netuid), - Error::::SubNetworkDoesNotExist - ); + // Ensure the hotkey not registered on the network before. - // 4. Ensure the new hotkey is not already registered on any network ensure!( - IsNetworkMember::::get(new_hotkey, netuid), - Error::::HotKeyNotRegisteredInSubNet + !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), + Error::::HotKeyAlreadyRegisteredInSubNet ); - - // 5. Update the weight for the checks above weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - // 6. Ensure the coldkey owns the old hotkey - ensure!( - Self::coldkey_owns_hotkey(&coldkey, old_hotkey), - Error::::NonAssociatedColdKey - ); - - // 7. Get the current block number - let block: u64 = Self::get_current_block_as_u64(); - - // 8. Ensure the transaction rate limit is not exceeded - ensure!( - !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), - Error::::HotKeySetTxRateLimitExceeded - ); - - // 9. Update the weight for reading the total networks - weight.saturating_accrue( - T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), - ); - // 10. Get the cost for swapping the key - let swap_cost = Self::get_key_swap_cost(); - log::debug!("Swap cost: {:?}", swap_cost); + let swap_cost = T::KeySwapOneSubnetCost::get(); + log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); // 11. Ensure the coldkey has enough balance to pay for the swap ensure!( @@ -579,19 +531,18 @@ impl Pallet { // 14. Perform the hotkey swap let _ = Self::perform_hotkey_swap(old_hotkey, new_hotkey, &coldkey, &mut weight); - + let block: u64 = Self::get_current_block_as_u64(); // 15. Update the last transaction block for the coldkey Self::set_last_tx_block(&coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); // 16. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwapped { - coldkey, + coldkey: coldkey.clone(), old_hotkey: old_hotkey.clone(), new_hotkey: new_hotkey.clone(), }); - // 17. Return the weight of the operation Ok(Some(weight).into()) } } From 3b2fbcebabe9721cdf4849a7a6b5c62562475f1c Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 28 Apr 2025 21:16:38 +0800 Subject: [PATCH 03/44] most of coding done --- pallets/subtensor/src/macros/events.rs | 12 + pallets/subtensor/src/swap/swap_hotkey.rs | 596 ++++++++++++---------- runtime/src/lib.rs | 2 + 3 files changed, 335 insertions(+), 275 deletions(-) diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index ccbfed9eff..f691ff4760 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -347,5 +347,17 @@ mod events { /// - **netuid**: The network identifier. /// - **Enabled**: Is Commit-Reveal enabled. CommitRevealEnabled(u16, bool), + + /// the hotkey is swapped + HotkeySwappedOnSubnet { + /// the account ID of coldkey + coldkey: T::AccountId, + /// the account ID of old hotkey + old_hotkey: T::AccountId, + /// the account ID of new hotkey + new_hotkey: T::AccountId, + /// the subnet ID + netuid: u16, + }, } } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index e74475959f..451dd86b1a 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -33,7 +33,7 @@ impl Pallet { // 1. Ensure the origin is signed and get the coldkey let coldkey = ensure_signed(origin)?; - // 6. Ensure the coldkey owns the old hotkey + // 2. Ensure the coldkey owns the old hotkey ensure!( Self::coldkey_owns_hotkey(&coldkey, old_hotkey), Error::::NonAssociatedColdKey @@ -57,15 +57,48 @@ impl Pallet { Error::::HotKeySetTxRateLimitExceeded ); - // 9. Update the weight for reading the total networks - weight.saturating_accrue( - T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), - ); - + // fork for swap hotkey on a specific subnet case after do the common check if let Some(netuid) = netuid { return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight); }; + // 5. Swap LastTxBlock + // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. + let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); + LastTxBlock::::remove(old_hotkey); + LastTxBlock::::insert(new_hotkey, last_tx_block); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 6. Swap LastTxBlockDelegateTake + // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. + let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); + LastTxBlockDelegateTake::::remove(old_hotkey); + LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 7. Swap LastTxBlockChildKeyTake + // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. + let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); + LastTxBlockChildKeyTake::::remove(old_hotkey); + LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 8. Swap Senate members. + // Senate( hotkey ) --> ? + if T::SenateMembers::is_member(old_hotkey) { + T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + + // 9. Swap delegates. + // Delegates( hotkey ) -> take value -- the hotkey delegate take value. + if Delegates::::contains_key(old_hotkey) { + let old_delegate_take = Delegates::::get(old_hotkey); + Delegates::::remove(old_hotkey); + Delegates::::insert(new_hotkey, old_delegate_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + // 4. Ensure the new hotkey is not already registered on any network ensure!( !Self::is_hotkey_registered_on_any_network(new_hotkey), @@ -89,7 +122,8 @@ impl Pallet { Self::burn_tokens(actual_burn_amount); // 14. Perform the hotkey swap - let _ = Self::perform_hotkey_swap(old_hotkey, new_hotkey, &coldkey, &mut weight); + let _ = + Self::perform_hotkey_swap_on_all_subnets(old_hotkey, new_hotkey, &coldkey, &mut weight); // 15. Update the last transaction block for the coldkey Self::set_last_tx_block(&coldkey, block); @@ -140,7 +174,7 @@ impl Pallet { /// # Note /// This function performs extensive storage reads and writes, which can be computationally expensive. /// The accumulated weight should be carefully considered in the context of block limits. - pub fn perform_hotkey_swap( + pub fn perform_hotkey_swap_on_all_subnets( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, coldkey: &T::AccountId, @@ -164,33 +198,9 @@ impl Pallet { OwnedHotkeys::::insert(coldkey, hotkeys); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // 3. Swap total hotkey alpha for all subnets it exists on. - // TotalHotkeyAlpha( hotkey, netuid ) -> alpha -- the total alpha that the hotkey has on a specific subnet. - TotalHotkeyAlpha::::iter_prefix(old_hotkey) - .drain() - .for_each(|(netuid, old_alpha)| { - let new_total_hotkey_alpha = TotalHotkeyAlpha::::get(new_hotkey, netuid); - TotalHotkeyAlpha::::insert( - new_hotkey, - netuid, - old_alpha.saturating_add(new_total_hotkey_alpha), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - }); - - // 4. Swap total hotkey shares on all subnets it exists on. - // TotalHotkeyShares( hotkey, netuid ) -> alpha -- the total alpha that the hotkey has on a specific subnet. - TotalHotkeyShares::::iter_prefix(old_hotkey) - .drain() - .for_each(|(netuid, old_shares)| { - let new_total_hotkey_shares = TotalHotkeyShares::::get(new_hotkey, netuid); - TotalHotkeyShares::::insert( - new_hotkey, - netuid, - old_shares.saturating_add(new_total_hotkey_shares), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - }); + for netuid in Self::get_all_subnet_netuids() { + Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, weight, netuid); + } // 5. Swap LastTxBlock // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. @@ -229,92 +239,201 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); } - // 9. swap PendingHotkeyEmissionOnNetuid - // (DEPRECATED.) - - // 10. Swap all subnet specific info. - let all_netuids: Vec = Self::get_all_subnet_netuids(); - all_netuids.iter().for_each(|netuid| { - // 10.1 Remove the previous hotkey and insert the new hotkey from membership. - // IsNetworkMember( hotkey, netuid ) -> bool -- is the hotkey a subnet member. - let is_network_member: bool = IsNetworkMember::::get(old_hotkey, netuid); - IsNetworkMember::::remove(old_hotkey, netuid); - IsNetworkMember::::insert(new_hotkey, netuid, is_network_member); + // Return successful after swapping all the relevant terms. + Ok(()) + } + + pub fn swap_senate_member( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if T::SenateMembers::is_member(old_hotkey) { + T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + Ok(()) + } - // 10.2 Swap Uids + Keys. - // Keys( netuid, hotkey ) -> uid -- the uid the hotkey has in the network if it is a member. - // Uids( netuid, hotkey ) -> uid -- the uids that the hotkey has. - if is_network_member { - // 10.2.1 Swap the UIDS - if let Ok(old_uid) = Uids::::try_get(netuid, old_hotkey) { - Uids::::remove(netuid, old_hotkey); - Uids::::insert(netuid, new_hotkey, old_uid); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - - // 10.2.2 Swap the keys. - Keys::::insert(netuid, old_uid, new_hotkey.clone()); - weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); - } + fn swap_hotkey_on_subnet( + coldkey: &T::AccountId, + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid: u16, + init_weight: Weight, + ) -> DispatchResultWithPostInfo { + let mut weight = init_weight; + + // Ensure the hotkey not registered on the network before. + + ensure!( + !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); + + // 10. Get the cost for swapping the key + let swap_cost = T::KeySwapOneSubnetCost::get(); + log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); + + // 11. Ensure the coldkey has enough balance to pay for the swap + ensure!( + Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + + // 12. Remove the swap cost from the coldkey's account + let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + + // 13. Burn the tokens + Self::burn_tokens(actual_burn_amount); + + // 1. Swap owner. + // Owner( hotkey ) -> coldkey -- the coldkey that owns the hotkey. + // Owner::::remove(old_hotkey); + Owner::::insert(new_hotkey, coldkey.clone()); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // 2. Swap OwnedHotkeys. + // OwnedHotkeys( coldkey ) -> Vec -- the hotkeys that the coldkey owns. + let mut hotkeys = OwnedHotkeys::::get(coldkey); + // Add the new key if needed. + if !hotkeys.contains(new_hotkey) { + hotkeys.push(new_hotkey.clone()); + OwnedHotkeys::::insert(coldkey, hotkeys); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + // Remove the old key. + // hotkeys.retain(|hk| *hk != *old_hotkey); + + // 14. Perform the hotkey swap + Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, &mut weight, netuid); + + let block: u64 = Self::get_current_block_as_u64(); + // 15. Update the last transaction block for the coldkey + Self::set_last_tx_block(&coldkey, block); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + // 16. Emit an event for the hotkey swap + Self::deposit_event(Event::HotkeySwappedOnSubnet { + coldkey: coldkey.clone(), + old_hotkey: old_hotkey.clone(), + new_hotkey: new_hotkey.clone(), + netuid, + }); + + Ok(Some(weight).into()) + } + + // do hotkey swap public part for both swap all subnets and just swap one subnet + pub fn perform_hotkey_swap_on_one_subnet( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + netuid: u16, + ) { + // 1. Swap total hotkey alpha for all subnets it exists on. + // TotalHotkeyAlpha( hotkey, netuid ) -> alpha -- the total alpha that the hotkey has on a specific subnet. + + let alpha = TotalHotkeyAlpha::::take(old_hotkey, netuid); + // TotalHotkeyAlpha::::remove(old_hotkey, netuid); + TotalHotkeyAlpha::::mutate(new_hotkey, netuid, |value| { + *value = value.saturating_add(alpha) + }); + + // 2. Swap total hotkey shares on all subnets it exists on. + // TotalHotkeyShares( hotkey, netuid ) -> alpha -- the total alpha that the hotkey has on a specific subnet. + + let share = TotalHotkeyShares::::take(old_hotkey, netuid); + // TotalHotkeyAlpha::::remove(old_hotkey, netuid); + TotalHotkeyShares::::mutate(new_hotkey, netuid, |value| { + *value = value.saturating_add(share) + }); + + // 3. Swap all subnet specific info. + + // 10.1 Remove the previous hotkey and insert the new hotkey from membership. + // IsNetworkMember( hotkey, netuid ) -> bool -- is the hotkey a subnet member. + let is_network_member: bool = IsNetworkMember::::get(old_hotkey, netuid); + IsNetworkMember::::remove(old_hotkey, netuid); + IsNetworkMember::::insert(new_hotkey, netuid, is_network_member); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 10.2 Swap Uids + Keys. + // Keys( netuid, hotkey ) -> uid -- the uid the hotkey has in the network if it is a member. + // Uids( netuid, hotkey ) -> uid -- the uids that the hotkey has. + if is_network_member { + // 10.2.1 Swap the UIDS + if let Ok(old_uid) = Uids::::try_get(netuid, old_hotkey) { + Uids::::remove(netuid, old_hotkey); + Uids::::insert(netuid, new_hotkey, old_uid); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 10.2.2 Swap the keys. + Keys::::insert(netuid, old_uid, new_hotkey.clone()); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); } + } - // 10.3 Swap Prometheus. - // Prometheus( netuid, hotkey ) -> prometheus -- the prometheus data that a hotkey has in the network. - if is_network_member { - if let Ok(old_prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { - Prometheus::::remove(netuid, old_hotkey); - Prometheus::::insert(netuid, new_hotkey, old_prometheus_info); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } + // 10.3 Swap Prometheus. + // Prometheus( netuid, hotkey ) -> prometheus -- the prometheus data that a hotkey has in the network. + if is_network_member { + if let Ok(old_prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { + Prometheus::::remove(netuid, old_hotkey); + Prometheus::::insert(netuid, new_hotkey, old_prometheus_info); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } + } - // 10.4. Swap axons. - // Axons( netuid, hotkey ) -> axon -- the axon that the hotkey has. - if is_network_member { - if let Ok(old_axon_info) = Axons::::try_get(netuid, old_hotkey) { - Axons::::remove(netuid, old_hotkey); - Axons::::insert(netuid, new_hotkey, old_axon_info); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } + // 10.4. Swap axons. + // Axons( netuid, hotkey ) -> axon -- the axon that the hotkey has. + if is_network_member { + if let Ok(old_axon_info) = Axons::::try_get(netuid, old_hotkey) { + Axons::::remove(netuid, old_hotkey); + Axons::::insert(netuid, new_hotkey, old_axon_info); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } + } - // 10.5 Swap WeightCommits - // WeightCommits( hotkey ) --> Vec -- the weight commits for the hotkey. - if is_network_member { - if let Ok(old_weight_commits) = WeightCommits::::try_get(netuid, old_hotkey) { - WeightCommits::::remove(netuid, old_hotkey); - WeightCommits::::insert(netuid, new_hotkey, old_weight_commits); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } + // 10.5 Swap WeightCommits + // WeightCommits( hotkey ) --> Vec -- the weight commits for the hotkey. + if is_network_member { + if let Ok(old_weight_commits) = WeightCommits::::try_get(netuid, old_hotkey) { + WeightCommits::::remove(netuid, old_hotkey); + WeightCommits::::insert(netuid, new_hotkey, old_weight_commits); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } + } - // 10.6. Swap the subnet loaded emission. - // LoadedEmission( netuid ) --> Vec<(hotkey, u64)> -- the loaded emission for the subnet. - if is_network_member { - if let Some(mut old_loaded_emission) = LoadedEmission::::get(netuid) { - for emission in old_loaded_emission.iter_mut() { - if emission.0 == *old_hotkey { - emission.0 = new_hotkey.clone(); - } + // 10.6. Swap the subnet loaded emission. + // LoadedEmission( netuid ) --> Vec<(hotkey, u64)> -- the loaded emission for the subnet. + if is_network_member { + if let Some(mut old_loaded_emission) = LoadedEmission::::get(netuid) { + for emission in old_loaded_emission.iter_mut() { + if emission.0 == *old_hotkey { + emission.0 = new_hotkey.clone(); } - LoadedEmission::::remove(netuid); - LoadedEmission::::insert(netuid, old_loaded_emission); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } + LoadedEmission::::remove(netuid); + LoadedEmission::::insert(netuid, old_loaded_emission); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } + } - // 10.7. Swap neuron TLS certificates. - // NeuronCertificates( netuid, hotkey ) -> Vec -- the neuron certificate for the hotkey. - if is_network_member { - if let Ok(old_neuron_certificates) = - NeuronCertificates::::try_get(netuid, old_hotkey) - { - NeuronCertificates::::remove(netuid, old_hotkey); - NeuronCertificates::::insert(netuid, new_hotkey, old_neuron_certificates); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } + // 10.7. Swap neuron TLS certificates. + // NeuronCertificates( netuid, hotkey ) -> Vec -- the neuron certificate for the hotkey. + if is_network_member { + if let Ok(old_neuron_certificates) = + NeuronCertificates::::try_get(netuid, old_hotkey) + { + NeuronCertificates::::remove(netuid, old_hotkey); + NeuronCertificates::::insert(netuid, new_hotkey, old_neuron_certificates); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } - }); + } + // }); // 11. Swap Alpha // Alpha( hotkey, coldkey, netuid ) -> alpha @@ -348,201 +467,128 @@ impl Pallet { // 12. Swap ChildKeys. // ChildKeys( parent, netuid ) --> Vec<(proportion,child)> -- the child keys of the parent. - for netuid in Self::get_all_subnet_netuids() { - // Get the children of the old hotkey for this subnet - let my_children: Vec<(u64, T::AccountId)> = ChildKeys::::get(old_hotkey, netuid); - // Remove the old hotkey's child entries - ChildKeys::::remove(old_hotkey, netuid); - // Insert the same child entries for the new hotkey - ChildKeys::::insert(new_hotkey, netuid, my_children.clone()); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - for (_, child_key_i) in my_children { - // For each child, update their parent list - let mut child_parents: Vec<(u64, T::AccountId)> = - ParentKeys::::get(child_key_i.clone(), netuid); - for parent in child_parents.iter_mut() { - // If the parent is the old hotkey, replace it with the new hotkey - if parent.1 == *old_hotkey { - parent.1 = new_hotkey.clone(); - } + // for netuid in Self::get_all_subnet_netuids() { + // Get the children of the old hotkey for this subnet + let my_children: Vec<(u64, T::AccountId)> = ChildKeys::::get(old_hotkey, netuid); + // Remove the old hotkey's child entries + ChildKeys::::remove(old_hotkey, netuid); + // Insert the same child entries for the new hotkey + ChildKeys::::insert(new_hotkey, netuid, my_children.clone()); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + for (_, child_key_i) in my_children { + // For each child, update their parent list + let mut child_parents: Vec<(u64, T::AccountId)> = + ParentKeys::::get(child_key_i.clone(), netuid); + for parent in child_parents.iter_mut() { + // If the parent is the old hotkey, replace it with the new hotkey + if parent.1 == *old_hotkey { + parent.1 = new_hotkey.clone(); } - // Update the child's parent list - ParentKeys::::insert(child_key_i, netuid, child_parents); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } + // Update the child's parent list + ParentKeys::::insert(child_key_i, netuid, child_parents); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } + // } // 13. Swap ParentKeys. // ParentKeys( child, netuid ) --> Vec<(proportion,parent)> -- the parent keys of the child. - for netuid in Self::get_all_subnet_netuids() { - // Get the parents of the old hotkey for this subnet - let parents: Vec<(u64, T::AccountId)> = ParentKeys::::get(old_hotkey, netuid); - // Remove the old hotkey's parent entries - ParentKeys::::remove(old_hotkey, netuid); - // Insert the same parent entries for the new hotkey - ParentKeys::::insert(new_hotkey, netuid, parents.clone()); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - for (_, parent_key_i) in parents { - // For each parent, update their children list - let mut parent_children: Vec<(u64, T::AccountId)> = - ChildKeys::::get(parent_key_i.clone(), netuid); - for child in parent_children.iter_mut() { - // If the child is the old hotkey, replace it with the new hotkey - if child.1 == *old_hotkey { - child.1 = new_hotkey.clone(); - } + // for netuid in Self::get_all_subnet_netuids() { + // Get the parents of the old hotkey for this subnet + let parents: Vec<(u64, T::AccountId)> = ParentKeys::::get(old_hotkey, netuid); + // Remove the old hotkey's parent entries + ParentKeys::::remove(old_hotkey, netuid); + // Insert the same parent entries for the new hotkey + ParentKeys::::insert(new_hotkey, netuid, parents.clone()); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + for (_, parent_key_i) in parents { + // For each parent, update their children list + let mut parent_children: Vec<(u64, T::AccountId)> = + ChildKeys::::get(parent_key_i.clone(), netuid); + for child in parent_children.iter_mut() { + // If the child is the old hotkey, replace it with the new hotkey + if child.1 == *old_hotkey { + child.1 = new_hotkey.clone(); } - // Update the parent's children list - ChildKeys::::insert(parent_key_i, netuid, parent_children); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } + // Update the parent's children list + ChildKeys::::insert(parent_key_i, netuid, parent_children); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } // 14. Swap PendingChildKeys. // PendingChildKeys( netuid, parent ) --> Vec<(proportion,child), cool_down_block> - for netuid in Self::get_all_subnet_netuids() { + // for netuid in Self::get_all_subnet_netuids() { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if PendingChildKeys::::contains_key(netuid, old_hotkey) { + let (children, cool_down_block) = PendingChildKeys::::get(netuid, old_hotkey); + PendingChildKeys::::remove(netuid, old_hotkey); + PendingChildKeys::::insert(netuid, new_hotkey, (children, cool_down_block)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + + // Also check for others with our hotkey as a child + for (hotkey, (children, cool_down_block)) in PendingChildKeys::::iter_prefix(netuid) { weight.saturating_accrue(T::DbWeight::get().reads(1)); - if PendingChildKeys::::contains_key(netuid, old_hotkey) { - let (children, cool_down_block) = PendingChildKeys::::get(netuid, old_hotkey); - PendingChildKeys::::remove(netuid, old_hotkey); - PendingChildKeys::::insert(netuid, new_hotkey, (children, cool_down_block)); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } - // Also check for others with our hotkey as a child - for (hotkey, (children, cool_down_block)) in PendingChildKeys::::iter_prefix(netuid) + if let Some(potential_idx) = + children.iter().position(|(_, child)| *child == *old_hotkey) { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - - if let Some(potential_idx) = - children.iter().position(|(_, child)| *child == *old_hotkey) - { - let mut new_children = children.clone(); - let entry_to_remove = new_children.remove(potential_idx); - new_children.push((entry_to_remove.0, new_hotkey.clone())); // Keep the proportion. - - PendingChildKeys::::remove(netuid, hotkey.clone()); - PendingChildKeys::::insert(netuid, hotkey, (new_children, cool_down_block)); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } + let mut new_children = children.clone(); + let entry_to_remove = new_children.remove(potential_idx); + new_children.push((entry_to_remove.0, new_hotkey.clone())); // Keep the proportion. + + PendingChildKeys::::remove(netuid, hotkey.clone()); + PendingChildKeys::::insert(netuid, hotkey, (new_children, cool_down_block)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } } // 15. Swap SubnetOwnerHotkey // SubnetOwnerHotkey( netuid ) --> hotkey -- the hotkey that is the owner of the subnet. - for netuid in Self::get_all_subnet_netuids() { - if let Ok(old_subnet_owner_hotkey) = SubnetOwnerHotkey::::try_get(netuid) { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if old_subnet_owner_hotkey == *old_hotkey { - SubnetOwnerHotkey::::insert(netuid, new_hotkey); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } + // for netuid in Self::get_all_subnet_netuids() { + if let Ok(old_subnet_owner_hotkey) = SubnetOwnerHotkey::::try_get(netuid) { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if old_subnet_owner_hotkey == *old_hotkey { + SubnetOwnerHotkey::::insert(netuid, new_hotkey); + weight.saturating_accrue(T::DbWeight::get().writes(1)); } } // 16. Swap dividend records - TotalHotkeyAlphaLastEpoch::::iter_prefix(old_hotkey) - .drain() - .for_each(|(netuid, old_alpha)| { - // 16.1 Swap TotalHotkeyAlphaLastEpoch - let new_total_hotkey_alpha = - TotalHotkeyAlphaLastEpoch::::get(new_hotkey, netuid); - TotalHotkeyAlphaLastEpoch::::insert( - new_hotkey, - netuid, - old_alpha.saturating_add(new_total_hotkey_alpha), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - - // 16.2 Swap AlphaDividendsPerSubnet - let old_hotkey_alpha_dividends = - AlphaDividendsPerSubnet::::get(netuid, old_hotkey); - let new_hotkey_alpha_dividends = - AlphaDividendsPerSubnet::::get(netuid, new_hotkey); - AlphaDividendsPerSubnet::::remove(netuid, old_hotkey); - AlphaDividendsPerSubnet::::insert( - netuid, - new_hotkey, - old_hotkey_alpha_dividends.saturating_add(new_hotkey_alpha_dividends), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - - // 16.3 Swap TaoDividendsPerSubnet - let old_hotkey_tao_dividends = TaoDividendsPerSubnet::::get(netuid, old_hotkey); - let new_hotkey_tao_dividends = TaoDividendsPerSubnet::::get(netuid, new_hotkey); - TaoDividendsPerSubnet::::remove(netuid, old_hotkey); - TaoDividendsPerSubnet::::insert( - netuid, - new_hotkey, - old_hotkey_tao_dividends.saturating_add(new_hotkey_tao_dividends), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - }); - - // Return successful after swapping all the relevant terms. - Ok(()) - } - - pub fn swap_senate_member( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) -> DispatchResult { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if T::SenateMembers::is_member(old_hotkey) { - T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } - Ok(()) - } - - fn swap_hotkey_on_subnet( - coldkey: &T::AccountId, - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid: u16, - init_weight: Weight, - ) -> DispatchResultWithPostInfo { - let mut weight = init_weight; - - // Ensure the hotkey not registered on the network before. - - ensure!( - !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), - Error::::HotKeyAlreadyRegisteredInSubNet + // 16.1 Swap TotalHotkeyAlphaLastEpoch + let old_alpha = TotalHotkeyAlphaLastEpoch::::take(old_hotkey, netuid); + let new_total_hotkey_alpha = TotalHotkeyAlphaLastEpoch::::get(new_hotkey, netuid); + TotalHotkeyAlphaLastEpoch::::insert( + new_hotkey, + netuid, + old_alpha.saturating_add(new_total_hotkey_alpha), ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - - // 10. Get the cost for swapping the key - let swap_cost = T::KeySwapOneSubnetCost::get(); - log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); - - // 11. Ensure the coldkey has enough balance to pay for the swap - ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), - Error::::NotEnoughBalanceToPaySwapHotKey + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + // 16.2 Swap AlphaDividendsPerSubnet + let old_hotkey_alpha_dividends = AlphaDividendsPerSubnet::::get(netuid, old_hotkey); + let new_hotkey_alpha_dividends = AlphaDividendsPerSubnet::::get(netuid, new_hotkey); + AlphaDividendsPerSubnet::::remove(netuid, old_hotkey); + AlphaDividendsPerSubnet::::insert( + netuid, + new_hotkey, + old_hotkey_alpha_dividends.saturating_add(new_hotkey_alpha_dividends), ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + // 16.3 Swap TaoDividendsPerSubnet + let old_hotkey_tao_dividends = TaoDividendsPerSubnet::::get(netuid, old_hotkey); + let new_hotkey_tao_dividends = TaoDividendsPerSubnet::::get(netuid, new_hotkey); + TaoDividendsPerSubnet::::remove(netuid, old_hotkey); + TaoDividendsPerSubnet::::insert( + netuid, + new_hotkey, + old_hotkey_tao_dividends.saturating_add(new_hotkey_tao_dividends), + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - // 12. Remove the swap cost from the coldkey's account - let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - - // 13. Burn the tokens - Self::burn_tokens(actual_burn_amount); - - // 14. Perform the hotkey swap - let _ = Self::perform_hotkey_swap(old_hotkey, new_hotkey, &coldkey, &mut weight); - let block: u64 = Self::get_current_block_as_u64(); - // 15. Update the last transaction block for the coldkey - Self::set_last_tx_block(&coldkey, block); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - // 16. Emit an event for the hotkey swap - Self::deposit_event(Event::HotkeySwapped { - coldkey: coldkey.clone(), - old_hotkey: old_hotkey.clone(), - new_hotkey: new_hotkey.clone(), - }); - - Ok(Some(weight).into()) + // Return successful after swapping all the relevant terms. + // Ok(()) } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 55c2d957f8..30b3866615 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1073,6 +1073,7 @@ parameter_types! { } else { 7 * 24 * 60 * 60 / 12 // 7 days }; + pub const SubtensorInitialKeySwapOnSubnetCost: u64 = 1_000_000; // 0.001 TAO } impl pallet_subtensor::Config for Runtime { @@ -1138,6 +1139,7 @@ impl pallet_subtensor::Config for Runtime { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; + type KeySwapOneSubnetCost = SubtensorInitialKeySwapOnSubnetCost; } use sp_runtime::BoundedVec; From 5240483ba9b7bfabb89cad16c3fe94b4dcdfff92 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 28 Apr 2025 21:45:35 +0800 Subject: [PATCH 04/44] commit Cargo.lock --- pallets/subtensor/src/swap/swap_hotkey.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 451dd86b1a..e1d9892ea2 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -39,44 +39,46 @@ impl Pallet { Error::::NonAssociatedColdKey ); - // 2. Initialize the weight for this operation + // 3. Initialize the weight for this operation let mut weight = T::DbWeight::get().reads(2); - // 3. Ensure the new hotkey is different from the old one + // 4. Ensure the new hotkey is different from the old one ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); // 5. Update the weight for the checks above weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - // 7. Get the current block number + // 6. Get the current block number let block: u64 = Self::get_current_block_as_u64(); - // 8. Ensure the transaction rate limit is not exceeded + // 7. Ensure the transaction rate limit is not exceeded ensure!( !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), Error::::HotKeySetTxRateLimitExceeded ); - // fork for swap hotkey on a specific subnet case after do the common check + // 8. fork for swap hotkey on a specific subnet case after do the common check if let Some(netuid) = netuid { return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight); }; - // 5. Swap LastTxBlock + // following update just for swap hotkey in all subnets case + + // 9. Swap LastTxBlock // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); LastTxBlock::::remove(old_hotkey); LastTxBlock::::insert(new_hotkey, last_tx_block); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 6. Swap LastTxBlockDelegateTake + // 10. Swap LastTxBlockDelegateTake // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); LastTxBlockDelegateTake::::remove(old_hotkey); LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 7. Swap LastTxBlockChildKeyTake + // 11. Swap LastTxBlockChildKeyTake // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); LastTxBlockChildKeyTake::::remove(old_hotkey); From 3a991831125dff18aad8a8c0906e568d73977dc8 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 28 Apr 2025 22:12:55 +0800 Subject: [PATCH 05/44] commit Cargo.lock --- pallets/subtensor/src/benchmarks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index b5ff1197e0..bbea816fff 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1270,7 +1270,7 @@ benchmark_swap_hotkey { Owner::::insert(&old, &coldkey); let cost = Subtensor::::get_key_swap_cost(); Subtensor::::add_balance_to_coldkey_account(&coldkey, cost); -}: swap_hotkey(RawOrigin::Signed(coldkey.clone()), old.clone(), new.clone()) +}: swap_hotkey(RawOrigin::Signed(coldkey.clone()), old.clone(), new.clone(), None) benchmark_try_associate_hotkey { let coldkey: T::AccountId = whitelisted_caller::>(); From 8438f1267ad4f266372d7f557e1f33080815d99e Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 28 Apr 2025 22:20:32 +0800 Subject: [PATCH 06/44] fix compilation --- pallets/subtensor/src/swap/swap_hotkey.rs | 6 +- pallets/subtensor/src/tests/swap_hotkey.rs | 126 +++++++++++++++------ 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index e1d9892ea2..a9fc3c23bb 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -282,12 +282,12 @@ impl Pallet { // 11. Ensure the coldkey has enough balance to pay for the swap ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), + Self::can_remove_balance_from_coldkey_account(coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapHotKey ); // 12. Remove the swap cost from the coldkey's account - let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + let actual_burn_amount = Self::remove_balance_from_coldkey_account(coldkey, swap_cost)?; // 13. Burn the tokens Self::burn_tokens(actual_burn_amount); @@ -315,7 +315,7 @@ impl Pallet { let block: u64 = Self::get_current_block_as_u64(); // 15. Update the last transaction block for the coldkey - Self::set_last_tx_block(&coldkey, block); + Self::set_last_tx_block(coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); // 16. Emit an event for the hotkey swap diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index a82972c2f7..41464f35ed 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -22,7 +22,7 @@ fn test_swap_owner() { let mut weight = Weight::zero(); Owner::::insert(old_hotkey, coldkey); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -44,7 +44,7 @@ fn test_swap_owned_hotkeys() { let mut weight = Weight::zero(); OwnedHotkeys::::insert(coldkey, vec![old_hotkey]); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -95,7 +95,7 @@ fn test_swap_total_hotkey_stake() { ); // Swap hotkey - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -127,7 +127,7 @@ fn test_swap_senate_members() { // Assuming there's a way to add a member to the senate // SenateMembers::add_member(&old_hotkey); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -150,7 +150,7 @@ fn test_swap_delegates() { let mut weight = Weight::zero(); Delegates::::insert(old_hotkey, 100); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -174,7 +174,7 @@ fn test_swap_subnet_membership() { add_network(netuid, 1, 1); IsNetworkMember::::insert(old_hotkey, netuid, true); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -202,7 +202,7 @@ fn test_swap_uids_and_keys() { Uids::::insert(netuid, old_hotkey, uid); Keys::::insert(netuid, uid, old_hotkey); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -230,7 +230,7 @@ fn test_swap_prometheus() { IsNetworkMember::::insert(old_hotkey, netuid, true); Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -260,7 +260,7 @@ fn test_swap_axons() { IsNetworkMember::::insert(old_hotkey, netuid, true); Axons::::insert(netuid, old_hotkey, axon_info.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -287,7 +287,7 @@ fn test_swap_certificates() { IsNetworkMember::::insert(old_hotkey, netuid, true); NeuronCertificates::::insert(netuid, old_hotkey, certificate.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -320,7 +320,7 @@ fn test_swap_weight_commits() { IsNetworkMember::::insert(old_hotkey, netuid, true); WeightCommits::::insert(netuid, old_hotkey, weight_commits.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -354,7 +354,7 @@ fn test_swap_loaded_emission() { vec![(old_hotkey, server_emission, validator_emission)], ); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -382,7 +382,7 @@ fn test_swap_staking_hotkeys() { StakingHotkeys::::insert(coldkey, vec![old_hotkey]); Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(100)); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -437,7 +437,7 @@ fn test_swap_hotkey_with_multiple_coldkeys() { let stake1_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey1); let stake2_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey2); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey1, @@ -473,7 +473,7 @@ fn test_swap_hotkey_with_multiple_subnets() { IsNetworkMember::::insert(old_hotkey, netuid1, true); IsNetworkMember::::insert(old_hotkey, netuid2, true); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -529,7 +529,7 @@ fn test_swap_staking_hotkeys_multiple_coldkeys() { stake )); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey1, @@ -564,7 +564,7 @@ fn test_swap_hotkey_with_no_stake() { // Set up initial state with no stake Owner::::insert(old_hotkey, coldkey); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey, @@ -635,7 +635,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { let total_hk_stake = SubtensorModule::get_total_stake_for_hotkey(&old_hotkey); assert!(total_hk_stake > 0); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, &coldkey1, @@ -807,7 +807,12 @@ fn test_swap_owner_success() { Owner::::insert(old_hotkey, coldkey); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap assert_eq!(Owner::::get(new_hotkey), coldkey); @@ -828,7 +833,12 @@ fn test_swap_owner_old_hotkey_not_exist() { assert!(!Owner::::contains_key(old_hotkey)); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap assert_eq!(Owner::::get(new_hotkey), coldkey); @@ -851,7 +861,12 @@ fn test_swap_owner_new_hotkey_already_exists() { Owner::::insert(new_hotkey, another_coldkey); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap assert_eq!(Owner::::get(new_hotkey), coldkey); @@ -873,7 +888,12 @@ fn test_swap_delegates_success() { Delegates::::insert(old_hotkey, delegate_take); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap assert_eq!(Delegates::::get(new_hotkey), delegate_take); @@ -904,7 +924,12 @@ fn test_swap_stake_success() { TaoDividendsPerSubnet::::insert(netuid, old_hotkey, amount); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap assert_eq!(TotalHotkeyAlpha::::get(old_hotkey, netuid), 0); @@ -964,7 +989,12 @@ fn test_swap_stake_old_hotkey_not_exist() { assert!(Alpha::::contains_key((old_hotkey, coldkey, netuid))); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify that new_hotkey has the stake and old_hotkey does not assert!(Alpha::::contains_key((new_hotkey, coldkey, netuid))); @@ -986,7 +1016,7 @@ fn test_swap_stake_old_hotkey_not_exist() { // TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); // // Perform the swap -// SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); +// SubtensorModule::perform_hotkey_swap_on_all_subnets(&old_hotkey, &new_hotkey, &coldkey, &mut weight); // // Verify the swap // assert_eq!( @@ -1087,7 +1117,12 @@ fn test_swap_child_keys() { ChildKeys::::insert(old_hotkey, netuid, children.clone()); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap assert_eq!(ChildKeys::::get(new_hotkey, netuid), children); @@ -1115,7 +1150,12 @@ fn test_swap_parent_keys() { ChildKeys::::insert(U256::from(5), netuid, vec![(200u64, old_hotkey)]); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify ParentKeys swap assert_eq!(ParentKeys::::get(new_hotkey, netuid), parents); @@ -1154,7 +1194,12 @@ fn test_swap_multiple_subnets() { ChildKeys::::insert(old_hotkey, netuid2, children2.clone()); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify the swap for both subnets assert_eq!(ChildKeys::::get(new_hotkey, netuid1), children1); @@ -1199,7 +1244,12 @@ fn test_swap_complex_parent_child_structure() { ); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Verify ParentKeys swap assert_eq!( @@ -1259,7 +1309,7 @@ fn test_swap_parent_hotkey_childkey_maps() { // Swap let mut weight = Weight::zero(); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &parent_old, &parent_new, &coldkey, @@ -1314,7 +1364,7 @@ fn test_swap_child_hotkey_childkey_maps() { // Swap let mut weight = Weight::zero(); - assert_ok!(SubtensorModule::perform_hotkey_swap( + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &child_old, &child_new, &coldkey, @@ -1352,7 +1402,12 @@ fn test_swap_hotkey_is_sn_owner_hotkey() { assert_eq!(SubnetOwnerHotkey::::get(netuid), old_hotkey); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Check for SubnetOwnerHotkey assert_eq!(SubnetOwnerHotkey::::get(netuid), new_hotkey); @@ -1380,7 +1435,12 @@ fn test_swap_hotkey_swap_rate_limits() { LastTxBlockChildKeyTake::::insert(old_hotkey, child_key_take_block); // Perform the swap - SubtensorModule::perform_hotkey_swap(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); // Check for new hotkey assert_eq!(LastTxBlock::::get(new_hotkey), last_tx_block); From e3025577f776254340a32a8bdaa09bf86f1441ce Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 28 Apr 2025 22:57:29 +0800 Subject: [PATCH 07/44] commit Cargo.lock --- pallets/subtensor/src/tests/mock.rs | 3 +++ pallets/subtensor/src/tests/swap_hotkey.rs | 27 ++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index a8ab96be8c..d934d33725 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -186,6 +186,8 @@ parameter_types! { pub const InitialTaoWeight: u64 = 0; // 100% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days + pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; + } // Configure collective pallet for council @@ -410,6 +412,7 @@ impl crate::Config for Test { type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; + type KeySwapOneSubnetCost = InitialKeySwapOnSubnetCost; } pub struct OriginPrivilegeCmp; diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 41464f35ed..be5e8b6b17 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -742,7 +742,8 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { assert_ok!(SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey), &old_hotkey, - &new_hotkey_1 + &new_hotkey_1, + None )); // Attempt to perform another swap immediately, which should fail due to rate limit @@ -750,7 +751,8 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey), &new_hotkey_1, - &new_hotkey_2 + &new_hotkey_2, + None ), Error::::HotKeySetTxRateLimitExceeded ); @@ -760,7 +762,8 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { assert_ok!(SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey), &new_hotkey_1, - &new_hotkey_2 + &new_hotkey_2, + None )); }); } @@ -787,7 +790,8 @@ fn test_do_swap_hotkey_err_not_owner() { SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(not_owner_coldkey), &old_hotkey, - &new_hotkey + &new_hotkey, + None ), Error::::NonAssociatedColdKey ); @@ -1049,7 +1053,8 @@ fn test_swap_hotkey_error_cases() { SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, - &new_hotkey + &new_hotkey, + None ), Error::::NotEnoughBalanceToPaySwapHotKey ); @@ -1062,7 +1067,8 @@ fn test_swap_hotkey_error_cases() { SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, - &old_hotkey + &old_hotkey, + None ), Error::::NewHotKeyIsSameWithOld ); @@ -1073,7 +1079,8 @@ fn test_swap_hotkey_error_cases() { SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, - &new_hotkey + &new_hotkey, + None ), Error::::HotKeyAlreadyRegisteredInSubNet ); @@ -1084,7 +1091,8 @@ fn test_swap_hotkey_error_cases() { SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(wrong_coldkey), &old_hotkey, - &new_hotkey + &new_hotkey, + None ), Error::::NonAssociatedColdKey ); @@ -1093,7 +1101,8 @@ fn test_swap_hotkey_error_cases() { assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, - &new_hotkey + &new_hotkey, + None )); // Check balance after swap From 8b0be6dcb15b8d0df8d569edcaa5e3be4043ced6 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 28 Apr 2025 22:59:53 +0800 Subject: [PATCH 08/44] commit Cargo.lock --- pallets/admin-utils/src/tests/mock.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 99c11b7165..fc80f77c35 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -136,6 +136,7 @@ parameter_types! { pub const InitialTaoWeight: u64 = u64::MAX/10; // 10% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days + pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; } impl pallet_subtensor::Config for Test { @@ -201,6 +202,7 @@ impl pallet_subtensor::Config for Test { type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; + type KeySwapOneSubnetCost = InitialKeySwapOnSubnetCost; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] From f79aef9e703094fb58c7b24f80207ba05a201f11 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 1 May 2025 17:38:50 +0800 Subject: [PATCH 09/44] fix test case --- pallets/subtensor/src/swap/swap_hotkey.rs | 103 ++++++++++++--------- pallets/subtensor/src/tests/swap_hotkey.rs | 11 ++- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index a9fc3c23bb..b16996d5b5 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -1,7 +1,6 @@ use super::*; use frame_support::weights::Weight; use sp_core::Get; -use substrate_fixed::types::U64F64; impl Pallet { /// Swaps the hotkey of a coldkey account. @@ -64,6 +63,25 @@ impl Pallet { // following update just for swap hotkey in all subnets case + // 4. Ensure the new hotkey is not already registered on any network + ensure!( + !Self::is_hotkey_registered_on_any_network(new_hotkey), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + + // 10. Get the cost for swapping the key + let swap_cost = Self::get_key_swap_cost(); + log::debug!("Swap cost: {:?}", swap_cost); + + // 11. Ensure the coldkey has enough balance to pay for the swap + ensure!( + Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + + // 12. Remove the swap cost from the coldkey's account + let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + // 9. Swap LastTxBlock // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); @@ -101,25 +119,6 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); } - // 4. Ensure the new hotkey is not already registered on any network - ensure!( - !Self::is_hotkey_registered_on_any_network(new_hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - - // 10. Get the cost for swapping the key - let swap_cost = Self::get_key_swap_cost(); - log::debug!("Swap cost: {:?}", swap_cost); - - // 11. Ensure the coldkey has enough balance to pay for the swap - ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), - Error::::NotEnoughBalanceToPaySwapHotKey - ); - - // 12. Remove the swap cost from the coldkey's account - let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - // 13. Burn the tokens Self::burn_tokens(actual_burn_amount); @@ -195,13 +194,17 @@ impl Pallet { if !hotkeys.contains(new_hotkey) { hotkeys.push(new_hotkey.clone()); } + // Remove the old key. hotkeys.retain(|hk| *hk != *old_hotkey); OwnedHotkeys::::insert(coldkey, hotkeys); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); for netuid in Self::get_all_subnet_netuids() { - Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, weight, netuid); + Self::perform_hotkey_swap_on_one_subnet( + coldkey, old_hotkey, new_hotkey, weight, netuid, + ); } // 5. Swap LastTxBlock @@ -241,6 +244,17 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); } + // Swap StakingHotkeys. + // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. + let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if staking_hotkeys.contains(old_hotkey) { + staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); + staking_hotkeys.push(new_hotkey.clone()); + StakingHotkeys::::insert(&coldkey, staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + // Return successful after swapping all the relevant terms. Ok(()) } @@ -311,7 +325,13 @@ impl Pallet { // hotkeys.retain(|hk| *hk != *old_hotkey); // 14. Perform the hotkey swap - Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, &mut weight, netuid); + Self::perform_hotkey_swap_on_one_subnet( + coldkey, + old_hotkey, + new_hotkey, + &mut weight, + netuid, + ); let block: u64 = Self::get_current_block_as_u64(); // 15. Update the last transaction block for the coldkey @@ -331,6 +351,7 @@ impl Pallet { // do hotkey swap public part for both swap all subnets and just swap one subnet pub fn perform_hotkey_swap_on_one_subnet( + coldkey: &T::AccountId, old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight, @@ -341,6 +362,7 @@ impl Pallet { let alpha = TotalHotkeyAlpha::::take(old_hotkey, netuid); // TotalHotkeyAlpha::::remove(old_hotkey, netuid); + TotalHotkeyAlpha::::mutate(new_hotkey, netuid, |value| { *value = value.saturating_add(alpha) }); @@ -435,37 +457,28 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } } + // }); // 11. Swap Alpha // Alpha( hotkey, coldkey, netuid ) -> alpha - let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = - Alpha::::iter_prefix((old_hotkey,)).collect(); + // let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = + // Alpha::::iter_prefix((old_hotkey,)).collect(); // Clear the entire old prefix here. - let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); - weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); - weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); + // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); + + let alpha_value = Alpha::::take((old_hotkey, &coldkey, netuid)); + + weight.saturating_accrue(T::DbWeight::get().reads(1_u64)); + weight.saturating_accrue(T::DbWeight::get().writes(1_u64)); // Insert the new alpha values. - for ((coldkey, netuid), alpha) in old_alpha_values { - let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); - Alpha::::insert( - (new_hotkey, &coldkey, netuid), - new_alpha.saturating_add(alpha), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + // for ((coldkey, netuid), alpha) in old_alpha_values { + // let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); + Alpha::::insert((new_hotkey, &coldkey, netuid), alpha_value); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // Swap StakingHotkeys. - // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. - let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if staking_hotkeys.contains(old_hotkey) { - staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); - staking_hotkeys.push(new_hotkey.clone()); - StakingHotkeys::::insert(&coldkey, staking_hotkeys); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - } + // } // 12. Swap ChildKeys. // ChildKeys( parent, netuid ) --> Vec<(proportion,child)> -- the child keys of the parent. diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index be5e8b6b17..27c60cc6b1 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -376,8 +376,12 @@ fn test_swap_staking_hotkeys() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); + + 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 mut weight = Weight::zero(); - let netuid = 1; StakingHotkeys::::insert(coldkey, vec![old_hotkey]); Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(100)); @@ -982,9 +986,12 @@ fn test_swap_stake_old_hotkey_not_exist() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); + 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 alpha_share = U64F64::from_num(1234); let mut weight = Weight::zero(); - let netuid = 1; // Initialize Stake for old_hotkey Alpha::::insert((old_hotkey, coldkey, netuid), alpha_share); From b29e18db1aaaa7580331123b9b8a8e69eaceaaa5 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 1 May 2025 17:40:58 +0800 Subject: [PATCH 10/44] cargo clippy --- pallets/subtensor/src/swap/swap_hotkey.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index b16996d5b5..6ac43656ba 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -246,12 +246,12 @@ impl Pallet { // Swap StakingHotkeys. // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. - let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + let mut staking_hotkeys = StakingHotkeys::::get(coldkey); weight.saturating_accrue(T::DbWeight::get().reads(1)); if staking_hotkeys.contains(old_hotkey) { staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); staking_hotkeys.push(new_hotkey.clone()); - StakingHotkeys::::insert(&coldkey, staking_hotkeys); + StakingHotkeys::::insert(coldkey, staking_hotkeys); weight.saturating_accrue(T::DbWeight::get().writes(1)); } From d93720929f9ffea0d8c439f6ac21c1ca6a08c0be Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 1 May 2025 19:44:01 +0800 Subject: [PATCH 11/44] fix test cases --- pallets/subtensor/src/staking/helpers.rs | 6 ++- pallets/subtensor/src/swap/swap_hotkey.rs | 52 ++++++++++++++--------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 9ee04f36a8..24accfc9ca 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -60,7 +60,7 @@ impl Pallet { // pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { let hotkeys = StakingHotkeys::::get(coldkey); - hotkeys + let result = hotkeys .iter() .map(|hotkey| { let mut total_stake: u64 = 0; @@ -76,7 +76,9 @@ impl Pallet { } total_stake }) - .sum::() + .sum::(); + log::error!("= ======= Total stake for coldkey {}: {}", coldkey, result); + result } // Creates a cold - hot pairing account if the hotkey is not already an active account. diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 6ac43656ba..de5766300f 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -1,7 +1,7 @@ use super::*; use frame_support::weights::Weight; use sp_core::Get; - +use substrate_fixed::types::U64F64; impl Pallet { /// Swaps the hotkey of a coldkey account. /// @@ -255,6 +255,36 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().writes(1)); } + // 11. Swap Alpha + // Alpha( hotkey, coldkey, netuid ) -> alpha + let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = + Alpha::::iter_prefix((old_hotkey,)).collect(); + // Clear the entire old prefix here. + let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); + weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); + weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); + + // Insert the new alpha values. + for ((coldkey, netuid), alpha) in old_alpha_values { + let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); + Alpha::::insert( + (new_hotkey, &coldkey, netuid), + new_alpha.saturating_add(alpha), + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // Swap StakingHotkeys. + // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. + let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if staking_hotkeys.contains(old_hotkey) { + staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); + staking_hotkeys.push(new_hotkey.clone()); + StakingHotkeys::::insert(&coldkey, staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + } + // Return successful after swapping all the relevant terms. Ok(()) } @@ -458,26 +488,6 @@ impl Pallet { } } - // }); - - // 11. Swap Alpha - // Alpha( hotkey, coldkey, netuid ) -> alpha - // let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = - // Alpha::::iter_prefix((old_hotkey,)).collect(); - // Clear the entire old prefix here. - // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); - - let alpha_value = Alpha::::take((old_hotkey, &coldkey, netuid)); - - weight.saturating_accrue(T::DbWeight::get().reads(1_u64)); - weight.saturating_accrue(T::DbWeight::get().writes(1_u64)); - - // Insert the new alpha values. - // for ((coldkey, netuid), alpha) in old_alpha_values { - // let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); - Alpha::::insert((new_hotkey, &coldkey, netuid), alpha_value); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // } // 12. Swap ChildKeys. From c1903a2b025c968b660203e10f7fd5acf977ac42 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 1 May 2025 20:03:41 +0800 Subject: [PATCH 12/44] fix compile error --- pallets/subtensor/src/staking/helpers.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 24accfc9ca..9ee04f36a8 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -60,7 +60,7 @@ impl Pallet { // pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { let hotkeys = StakingHotkeys::::get(coldkey); - let result = hotkeys + hotkeys .iter() .map(|hotkey| { let mut total_stake: u64 = 0; @@ -76,9 +76,7 @@ impl Pallet { } total_stake }) - .sum::(); - log::error!("= ======= Total stake for coldkey {}: {}", coldkey, result); - result + .sum::() } // Creates a cold - hot pairing account if the hotkey is not already an active account. From ee036f99e3333b722b8b0ca35f315b1d74643ea2 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 1 May 2025 20:04:34 +0800 Subject: [PATCH 13/44] cargo clippy --- pallets/subtensor/src/swap/swap_hotkey.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index de5766300f..aa31b7f508 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -381,7 +381,6 @@ impl Pallet { // do hotkey swap public part for both swap all subnets and just swap one subnet pub fn perform_hotkey_swap_on_one_subnet( - coldkey: &T::AccountId, old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight, From 9baf4a0f5c6ca13fd39c36895010a2f9465ae5f5 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 1 May 2025 20:06:30 +0800 Subject: [PATCH 14/44] commit Cargo.lock --- pallets/subtensor/src/swap/swap_hotkey.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index aa31b7f508..5e51e86503 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -202,9 +202,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); for netuid in Self::get_all_subnet_netuids() { - Self::perform_hotkey_swap_on_one_subnet( - coldkey, old_hotkey, new_hotkey, weight, netuid, - ); + Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, weight, netuid); } // 5. Swap LastTxBlock @@ -355,13 +353,7 @@ impl Pallet { // hotkeys.retain(|hk| *hk != *old_hotkey); // 14. Perform the hotkey swap - Self::perform_hotkey_swap_on_one_subnet( - coldkey, - old_hotkey, - new_hotkey, - &mut weight, - netuid, - ); + Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, &mut weight, netuid); let block: u64 = Self::get_current_block_as_u64(); // 15. Update the last transaction block for the coldkey From 3ab6fc10ccc7b7c5f6fd334cce1adf10a5369b7f Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 17:13:57 +0800 Subject: [PATCH 15/44] add new test file --- pallets/subtensor/src/tests/mod.rs | 1 + .../src/tests/swap_hotkey_with_subnet.rs | 1509 +++++++++++++++++ 2 files changed, 1510 insertions(+) create mode 100644 pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs diff --git a/pallets/subtensor/src/tests/mod.rs b/pallets/subtensor/src/tests/mod.rs index ce891e5615..857666f822 100644 --- a/pallets/subtensor/src/tests/mod.rs +++ b/pallets/subtensor/src/tests/mod.rs @@ -21,5 +21,6 @@ mod staking2; mod subnet; mod swap_coldkey; mod swap_hotkey; +mod swap_hotkey_with_subnet; mod uids; mod weights; diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs new file mode 100644 index 0000000000..96d902e0da --- /dev/null +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -0,0 +1,1509 @@ +#![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] + +use approx::assert_abs_diff_eq; +use codec::Encode; +use frame_support::weights::Weight; +use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_system::{Config, RawOrigin}; + +use super::mock::*; +use crate::*; +use sp_core::{Get, H256, U256}; +use sp_runtime::SaturatedConversion; +use substrate_fixed::types::U64F64; +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner --exact --nocapture +#[test] +fn test_swap_owner() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + Owner::::insert(old_hotkey, coldkey); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + assert_eq!(Owner::::get(old_hotkey), coldkey); + assert_eq!(Owner::::get(new_hotkey), coldkey); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owned_hotkeys --exact --nocapture +#[test] +fn test_swap_owned_hotkeys() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + OwnedHotkeys::::insert(coldkey, vec![old_hotkey]); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + let hotkeys = OwnedHotkeys::::get(coldkey); + assert!(hotkeys.contains(&old_hotkey)); + assert!(hotkeys.contains(&new_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_total_hotkey_stake --exact --nocapture +#[test] +fn test_swap_total_hotkey_stake() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let amount = DefaultMinStake::::get() * 10; + let mut weight = Weight::zero(); + let fee = DefaultStakingFee::::get(); + + //add network + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + // Add stake + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey), + old_hotkey, + netuid, + amount + )); + + // Check if stake has increased + assert_abs_diff_eq!( + SubtensorModule::get_total_stake_for_hotkey(&old_hotkey), + amount - fee, + epsilon = amount / 1000, + ); + assert_abs_diff_eq!( + SubtensorModule::get_total_stake_for_hotkey(&new_hotkey), + 0, + epsilon = 1, + ); + + // Swap hotkey + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + // Verify that total hotkey stake swapped + assert_abs_diff_eq!( + SubtensorModule::get_total_stake_for_hotkey(&old_hotkey), + 0, + epsilon = 1, + ); + assert_abs_diff_eq!( + SubtensorModule::get_total_stake_for_hotkey(&new_hotkey), + amount - fee, + epsilon = amount / 1000, + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_senate_members --exact --nocapture +#[test] +fn test_swap_senate_members() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + assert_ok!(SenateMembers::add_member( + RuntimeOrigin::root(), + old_hotkey.clone() + )); + + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + let members = SenateMembers::members(); + assert!(members.contains(&old_hotkey)); + assert!(!members.contains(&new_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_delegates --exact --nocapture +#[test] +fn test_swap_delegates() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + Delegates::::insert(old_hotkey, 100); + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(!Delegates::::contains_key(old_hotkey)); + assert_eq!(Delegates::::get(new_hotkey), 100); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_subnet_membership --exact --nocapture +#[test] +fn test_swap_subnet_membership() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(!IsNetworkMember::::contains_key(old_hotkey, netuid)); + assert!(IsNetworkMember::::get(new_hotkey, netuid)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_uids_and_keys --exact --nocapture +#[test] +fn test_swap_uids_and_keys() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let uid = 5u16; + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + Uids::::insert(netuid, old_hotkey, uid); + Keys::::insert(netuid, uid, old_hotkey); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert_eq!(Uids::::get(netuid, old_hotkey), None); + assert_eq!(Uids::::get(netuid, new_hotkey), Some(uid)); + assert_eq!(Keys::::get(netuid, uid), new_hotkey); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_prometheus --exact --nocapture +#[test] +fn test_swap_prometheus() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let prometheus_info = PrometheusInfo::default(); + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(!Prometheus::::contains_key(netuid, old_hotkey)); + assert_eq!( + Prometheus::::get(netuid, new_hotkey), + Some(prometheus_info) + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_axons --exact --nocapture +#[test] +fn test_swap_axons() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let axon_info = AxonInfo::default(); + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + Axons::::insert(netuid, old_hotkey, axon_info.clone()); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(!Axons::::contains_key(netuid, old_hotkey)); + assert_eq!(Axons::::get(netuid, new_hotkey), Some(axon_info)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_certificates --exact --nocapture +#[test] +fn test_swap_certificates() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let certificate = NeuronCertificate::try_from(vec![1, 2, 3]).unwrap(); + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + NeuronCertificates::::insert(netuid, old_hotkey, certificate.clone()); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(!NeuronCertificates::::contains_key( + netuid, old_hotkey + )); + assert_eq!( + NeuronCertificates::::get(netuid, new_hotkey), + Some(certificate) + ); + }); +} +use sp_std::collections::vec_deque::VecDeque; +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_weight_commits --exact --nocapture +#[test] +fn test_swap_weight_commits() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let mut weight_commits: VecDeque<(H256, u64, u64, u64)> = VecDeque::new(); + weight_commits.push_back((H256::from_low_u64_be(100), 200, 1, 1)); + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + WeightCommits::::insert(netuid, old_hotkey, weight_commits.clone()); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(!WeightCommits::::contains_key(netuid, old_hotkey)); + assert_eq!( + WeightCommits::::get(netuid, new_hotkey), + Some(weight_commits) + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_loaded_emission --exact --nocapture +#[test] +fn test_swap_loaded_emission() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let server_emission = 1000u64; + let validator_emission = 1000u64; + let mut weight = Weight::zero(); + + add_network(netuid, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid, true); + LoadedEmission::::insert( + netuid, + vec![(old_hotkey, server_emission, validator_emission)], + ); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + let new_loaded_emission = LoadedEmission::::get(netuid); + assert_eq!( + new_loaded_emission, + Some(vec![(new_hotkey, server_emission, validator_emission)]) + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_staking_hotkeys --exact --nocapture +#[test] +fn test_swap_staking_hotkeys() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + + 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 mut weight = Weight::zero(); + + StakingHotkeys::::insert(coldkey, vec![old_hotkey]); + Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(100)); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + let staking_hotkeys = StakingHotkeys::::get(coldkey); + assert!(!staking_hotkeys.contains(&old_hotkey)); + assert!(staking_hotkeys.contains(&new_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_swap_hotkey_with_multiple_coldkeys --exact --show-output --nocapture +#[test] +fn test_swap_hotkey_with_multiple_coldkeys() { + 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 old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey1 = U256::from(3); + let coldkey2 = U256::from(4); + let mut weight = Weight::zero(); + let stake = 1_000_000_000; + + StakingHotkeys::::insert(coldkey1, vec![old_hotkey]); + StakingHotkeys::::insert(coldkey2, vec![old_hotkey]); + SubtensorModule::create_account_if_non_existent(&coldkey1, &old_hotkey); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey1, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey2, + stake + ExistentialDeposit::get(), + ); + + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey1), + old_hotkey, + netuid, + stake + )); + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey2), + old_hotkey, + netuid, + stake / 2 + )); + let stake1_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey1); + let stake2_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey2); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey1, + &mut weight + )); + + assert_eq!( + SubtensorModule::get_total_stake_for_coldkey(&coldkey1), + stake1_before + ); + assert_eq!( + SubtensorModule::get_total_stake_for_coldkey(&coldkey2), + stake2_before + ); + assert!(StakingHotkeys::::get(coldkey1).contains(&new_hotkey)); + assert!(StakingHotkeys::::get(coldkey2).contains(&new_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_with_multiple_subnets --exact --nocapture +#[test] +fn test_swap_hotkey_with_multiple_subnets() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid1 = 0; + let netuid2 = 1; + let mut weight = Weight::zero(); + + add_network(netuid1, 1, 1); + add_network(netuid2, 1, 1); + IsNetworkMember::::insert(old_hotkey, netuid1, true); + IsNetworkMember::::insert(old_hotkey, netuid2, true); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + assert!(IsNetworkMember::::get(new_hotkey, netuid1)); + assert!(IsNetworkMember::::get(new_hotkey, netuid2)); + assert!(!IsNetworkMember::::get(old_hotkey, netuid1)); + assert!(!IsNetworkMember::::get(old_hotkey, netuid2)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_staking_hotkeys_multiple_coldkeys --exact --nocapture +#[test] +fn test_swap_staking_hotkeys_multiple_coldkeys() { + 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 old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey1 = U256::from(3); + let coldkey2 = U256::from(4); + let staker5 = U256::from(5); + let mut weight = Weight::zero(); + let stake = 1_000_000_000; + + // Set up initial state + StakingHotkeys::::insert(coldkey1, vec![old_hotkey]); + StakingHotkeys::::insert(coldkey2, vec![old_hotkey, staker5]); + + SubtensorModule::create_account_if_non_existent(&coldkey1, &old_hotkey); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey1, + stake + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey2, + stake + ExistentialDeposit::get(), + ); + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey1), + old_hotkey, + netuid, + stake + )); + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey2), + old_hotkey, + netuid, + stake + )); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey1, + &mut weight + )); + + // Check if new_hotkey replaced old_hotkey in StakingHotkeys + assert!(StakingHotkeys::::get(coldkey1).contains(&new_hotkey)); + assert!(!StakingHotkeys::::get(coldkey1).contains(&old_hotkey)); + + // Check if new_hotkey replaced old_hotkey for coldkey2 as well + assert!(StakingHotkeys::::get(coldkey2).contains(&new_hotkey)); + assert!(!StakingHotkeys::::get(coldkey2).contains(&old_hotkey)); + assert!(StakingHotkeys::::get(coldkey2).contains(&staker5)); + // Other hotkeys should remain + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_with_no_stake --exact --nocapture +#[test] +fn test_swap_hotkey_with_no_stake() { + 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 old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Set up initial state with no stake + Owner::::insert(old_hotkey, coldkey); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + // Check if ownership transferred + assert!(!Owner::::contains_key(old_hotkey)); + assert_eq!(Owner::::get(new_hotkey), coldkey); + + // Ensure no unexpected changes in Stake + assert!(!Alpha::::contains_key((old_hotkey, coldkey, netuid))); + assert!(!Alpha::::contains_key((new_hotkey, coldkey, netuid))); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_swap_hotkey_with_multiple_coldkeys_and_subnets --exact --show-output +#[test] +fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey1 = U256::from(3); + let coldkey2 = U256::from(4); + let netuid1 = 1; + let netuid2 = 2; + let stake = DefaultMinStake::::get() * 10; + let mut weight = Weight::zero(); + + // Set up initial state + add_network(netuid1, 1, 1); + add_network(netuid2, 1, 1); + register_ok_neuron(netuid1, old_hotkey, coldkey1, 1234); + register_ok_neuron(netuid2, old_hotkey, coldkey1, 1234); + + // Add balance to both coldkeys + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, stake + 1_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake + 1_000); + + // Stake with coldkey1 + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey1), + old_hotkey, + netuid1, + stake + )); + + // Stake with coldkey2 also + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey2), + old_hotkey, + netuid2, + stake + )); + + let ck1_stake = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &coldkey1, + netuid1, + ); + let ck2_stake = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &coldkey2, + netuid2, + ); + assert!(ck1_stake > 0); + assert!(ck2_stake > 0); + let total_hk_stake = SubtensorModule::get_total_stake_for_hotkey(&old_hotkey); + assert!(total_hk_stake > 0); + + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey1, + &mut weight + )); + + // Check ownership transfer + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey), + coldkey1 + ); + assert!(!SubtensorModule::get_owned_hotkeys(&coldkey2).contains(&new_hotkey)); + + // Check stake transfer + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey1, + netuid1 + ), + ck1_stake + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey2, + netuid2 + ), + ck2_stake + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &coldkey1, + netuid1 + ), + 0 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &coldkey2, + netuid2 + ), + 0 + ); + + // Check subnet membership transfer + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid1, + &new_hotkey + )); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid2, + &new_hotkey + )); + assert!(!SubtensorModule::is_hotkey_registered_on_network( + netuid1, + &old_hotkey + )); + assert!(!SubtensorModule::is_hotkey_registered_on_network( + netuid2, + &old_hotkey + )); + + // Check total stake transfer + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&new_hotkey), + total_hk_stake + ); + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&old_hotkey), 0); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_tx_rate_limit_exceeded --exact --nocapture +#[test] +fn test_swap_hotkey_tx_rate_limit_exceeded() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey_1 = U256::from(2); + let new_hotkey_2 = U256::from(4); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64 * 2; + + let tx_rate_limit = 1; + + // Get the current transaction rate limit + let current_tx_rate_limit = SubtensorModule::get_tx_rate_limit(); + log::info!("current_tx_rate_limit: {:?}", current_tx_rate_limit); + + // Set the transaction rate limit + SubtensorModule::set_tx_rate_limit(tx_rate_limit); + // assert the rate limit is set to 1000 blocks + assert_eq!(SubtensorModule::get_tx_rate_limit(), tx_rate_limit); + + // Setup initial state + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + + // Perform the first swap + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &old_hotkey, + &new_hotkey_1, + None + )); + + // Attempt to perform another swap immediately, which should fail due to rate limit + assert_err!( + SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey_1, + &new_hotkey_2, + None + ), + Error::::HotKeySetTxRateLimitExceeded + ); + + // move in time past the rate limit + step_block(1001); + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey_1, + &new_hotkey_2, + None + )); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_do_swap_hotkey_err_not_owner --exact --nocapture +#[test] +fn test_do_swap_hotkey_err_not_owner() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let not_owner_coldkey = U256::from(4); + let swap_cost = 1_000_000_000u64; + + // Setup initial state + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(¬_owner_coldkey, swap_cost); + + // Attempt the swap with a non-owner coldkey + assert_err!( + SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(not_owner_coldkey), + &old_hotkey, + &new_hotkey, + None + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner_success --exact --nocapture +#[test] +fn test_swap_owner_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Initialize Owner for old_hotkey + Owner::::insert(old_hotkey, coldkey); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap + assert_eq!(Owner::::get(new_hotkey), coldkey); + assert!(!Owner::::contains_key(old_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner_old_hotkey_not_exist --exact --nocapture +#[test] +fn test_swap_owner_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Ensure old_hotkey does not exist + assert!(!Owner::::contains_key(old_hotkey)); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap + assert_eq!(Owner::::get(new_hotkey), coldkey); + assert!(!Owner::::contains_key(old_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner_new_hotkey_already_exists --exact --nocapture +#[test] +fn test_swap_owner_new_hotkey_already_exists() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let another_coldkey = U256::from(4); + let mut weight = Weight::zero(); + + // Initialize Owner for old_hotkey and new_hotkey + Owner::::insert(old_hotkey, coldkey); + Owner::::insert(new_hotkey, another_coldkey); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap + assert_eq!(Owner::::get(new_hotkey), coldkey); + assert!(!Owner::::contains_key(old_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_swap_delegates_success --exact --show-output +#[test] +fn test_swap_delegates_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let delegate_take = 10u16; + let mut weight = Weight::zero(); + + // Initialize Delegates for old_hotkey + Delegates::::insert(old_hotkey, delegate_take); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap + assert_eq!(Delegates::::get(new_hotkey), delegate_take); + assert!(!Delegates::::contains_key(old_hotkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_stake_success --exact --nocapture +#[test] +fn test_swap_stake_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + 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 amount = 10_000; + let shares = U64F64::from_num(123456); + let mut weight = Weight::zero(); + + // Initialize staking variables for old_hotkey + TotalHotkeyAlpha::::insert(old_hotkey, netuid, amount); + TotalHotkeyAlphaLastEpoch::::insert(old_hotkey, netuid, amount * 2); + TotalHotkeyShares::::insert(old_hotkey, netuid, U64F64::from_num(shares)); + Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(amount)); + AlphaDividendsPerSubnet::::insert(netuid, old_hotkey, amount); + TaoDividendsPerSubnet::::insert(netuid, old_hotkey, amount); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap + assert_eq!(TotalHotkeyAlpha::::get(old_hotkey, netuid), 0); + assert_eq!(TotalHotkeyAlpha::::get(new_hotkey, netuid), amount); + assert_eq!( + TotalHotkeyAlphaLastEpoch::::get(old_hotkey, netuid), + 0 + ); + assert_eq!( + TotalHotkeyAlphaLastEpoch::::get(new_hotkey, netuid), + amount * 2 + ); + assert_eq!( + TotalHotkeyShares::::get(old_hotkey, netuid), + U64F64::from_num(0) + ); + assert_eq!( + TotalHotkeyShares::::get(new_hotkey, netuid), + U64F64::from_num(shares) + ); + assert_eq!( + Alpha::::get((old_hotkey, coldkey, netuid)), + U64F64::from_num(0) + ); + assert_eq!( + Alpha::::get((new_hotkey, coldkey, netuid)), + U64F64::from_num(amount) + ); + assert_eq!(AlphaDividendsPerSubnet::::get(netuid, old_hotkey), 0); + assert_eq!( + AlphaDividendsPerSubnet::::get(netuid, new_hotkey), + amount + ); + assert_eq!(TaoDividendsPerSubnet::::get(netuid, old_hotkey), 0); + assert_eq!( + TaoDividendsPerSubnet::::get(netuid, new_hotkey), + amount + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_stake_old_hotkey_not_exist --exact --nocapture +#[test] +fn test_swap_stake_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + 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 alpha_share = U64F64::from_num(1234); + let mut weight = Weight::zero(); + + // Initialize Stake for old_hotkey + Alpha::::insert((old_hotkey, coldkey, netuid), alpha_share); + + // Ensure old_hotkey has a stake + assert!(Alpha::::contains_key((old_hotkey, coldkey, netuid))); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify that new_hotkey has the stake and old_hotkey does not + assert!(Alpha::::contains_key((new_hotkey, coldkey, netuid))); + assert!(!Alpha::::contains_key((old_hotkey, coldkey, netuid))); + }); +} + +// // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_total_hotkey_coldkey_stakes_this_interval_success --exact --nocapture +// #[test] +// fn test_swap_total_hotkey_coldkey_stakes_this_interval_success() { +// new_test_ext(1).execute_with(|| { +// let old_hotkey = U256::from(1); +// let new_hotkey = U256::from(2); +// let coldkey = U256::from(3); +// let stake = (1000u64, 42u64); // Example tuple value +// let mut weight = Weight::zero(); + +// // Initialize TotalHotkeyColdkeyStakesThisInterval for old_hotkey +// TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); + +// // Perform the swap +// SubtensorModule::perform_hotkey_swap_on_all_subnets(&old_hotkey, &new_hotkey, &coldkey, &mut weight); + +// // Verify the swap +// assert_eq!( +// TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), +// stake +// ); +// assert!(!TotalHotkeyColdkeyStakesThisInterval::::contains_key( +// old_hotkey, coldkey +// )); +// }); +// } + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_error_cases --exact --nocapture +#[test] +fn test_swap_hotkey_error_cases() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let wrong_coldkey = U256::from(4); + + // Set up initial state + Owner::::insert(old_hotkey, coldkey); + TotalNetworks::::put(1); + LastTxBlock::::insert(coldkey, 0); + + // Test not enough balance + let swap_cost = SubtensorModule::get_key_swap_cost(); + assert_noop!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + None + ), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + + let initial_balance = SubtensorModule::get_key_swap_cost() + 1000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_balance); + + // Test new hotkey same as old + assert_noop!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &old_hotkey, + None + ), + Error::::NewHotKeyIsSameWithOld + ); + + // Test new hotkey already registered + IsNetworkMember::::insert(new_hotkey, 0, true); + assert_noop!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + None + ), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + IsNetworkMember::::remove(new_hotkey, 0); + + // Test non-associated coldkey + assert_noop!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(wrong_coldkey), + &old_hotkey, + &new_hotkey, + None + ), + Error::::NonAssociatedColdKey + ); + + // Run the successful swap + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + None + )); + + // Check balance after swap + assert_eq!(Balances::free_balance(coldkey), initial_balance - swap_cost); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_child_keys --exact --nocapture +#[test] +fn test_swap_child_keys() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let children = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; + let mut weight = Weight::zero(); + + // Initialize ChildKeys for old_hotkey + add_network(netuid, 1, 0); + ChildKeys::::insert(old_hotkey, netuid, children.clone()); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap + assert_eq!(ChildKeys::::get(new_hotkey, netuid), children); + assert!(ChildKeys::::get(old_hotkey, netuid).is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_parent_keys --exact --nocapture +#[test] +fn test_swap_parent_keys() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let parents = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; + let mut weight = Weight::zero(); + + // Initialize ParentKeys for old_hotkey + add_network(netuid, 1, 0); + ParentKeys::::insert(old_hotkey, netuid, parents.clone()); + + // Initialize ChildKeys for parent + ChildKeys::::insert(U256::from(4), netuid, vec![(100u64, old_hotkey)]); + ChildKeys::::insert(U256::from(5), netuid, vec![(200u64, old_hotkey)]); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify ParentKeys swap + assert_eq!(ParentKeys::::get(new_hotkey, netuid), parents); + assert!(ParentKeys::::get(old_hotkey, netuid).is_empty()); + + // Verify ChildKeys update for parents + assert_eq!( + ChildKeys::::get(U256::from(4), netuid), + vec![(100u64, new_hotkey)] + ); + assert_eq!( + ChildKeys::::get(U256::from(5), netuid), + vec![(200u64, new_hotkey)] + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_multiple_subnets --exact --nocapture +#[test] +fn test_swap_multiple_subnets() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid1 = 0u16; + let netuid2 = 1u16; + let children1 = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; + let children2 = vec![(300u64, U256::from(6))]; + let mut weight = Weight::zero(); + + add_network(netuid1, 1, 0); + add_network(netuid2, 1, 0); + + // Initialize ChildKeys for old_hotkey in multiple subnets + ChildKeys::::insert(old_hotkey, netuid1, children1.clone()); + ChildKeys::::insert(old_hotkey, netuid2, children2.clone()); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify the swap for both subnets + assert_eq!(ChildKeys::::get(new_hotkey, netuid1), children1); + assert_eq!(ChildKeys::::get(new_hotkey, netuid2), children2); + assert!(ChildKeys::::get(old_hotkey, netuid1).is_empty()); + assert!(ChildKeys::::get(old_hotkey, netuid2).is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_complex_parent_child_structure --exact --nocapture +#[test] +fn test_swap_complex_parent_child_structure() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let netuid = 0u16; + let parent1 = U256::from(4); + let parent2 = U256::from(5); + let child1 = U256::from(6); + let child2 = U256::from(7); + let mut weight = Weight::zero(); + + add_network(netuid, 1, 0); + + // Set up complex parent-child structure + ParentKeys::::insert( + old_hotkey, + netuid, + vec![(100u64, parent1), (200u64, parent2)], + ); + ChildKeys::::insert(old_hotkey, netuid, vec![(300u64, child1), (400u64, child2)]); + ChildKeys::::insert( + parent1, + netuid, + vec![(100u64, old_hotkey), (500u64, U256::from(8))], + ); + ChildKeys::::insert( + parent2, + netuid, + vec![(200u64, old_hotkey), (600u64, U256::from(9))], + ); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Verify ParentKeys swap + assert_eq!( + ParentKeys::::get(new_hotkey, netuid), + vec![(100u64, parent1), (200u64, parent2)] + ); + assert!(ParentKeys::::get(old_hotkey, netuid).is_empty()); + + // Verify ChildKeys swap + assert_eq!( + ChildKeys::::get(new_hotkey, netuid), + vec![(300u64, child1), (400u64, child2)] + ); + assert!(ChildKeys::::get(old_hotkey, netuid).is_empty()); + + // Verify parent's ChildKeys update + assert_eq!( + ChildKeys::::get(parent1, netuid), + vec![(100u64, new_hotkey), (500u64, U256::from(8))] + ); + assert_eq!( + ChildKeys::::get(parent2, netuid), + vec![(200u64, new_hotkey), (600u64, U256::from(9))] + ); + }); +} + +#[test] +fn test_swap_parent_hotkey_childkey_maps() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent_old = U256::from(1); + let coldkey = U256::from(2); + let child = U256::from(3); + let child_other = U256::from(4); + let parent_new = U256::from(4); + add_network(netuid, 1, 0); + SubtensorModule::create_account_if_non_existent(&coldkey, &parent_old); + + // Set child and verify state maps + mock_set_children(&coldkey, &parent_old, netuid, &[(u64::MAX, child)]); + // Wait rate limit + step_rate_limit(&TransactionType::SetChildren, netuid); + // Schedule some pending child keys. + mock_schedule_children(&coldkey, &parent_old, netuid, &[(u64::MAX, child_other)]); + + assert_eq!( + ParentKeys::::get(child, netuid), + vec![(u64::MAX, parent_old)] + ); + assert_eq!( + ChildKeys::::get(parent_old, netuid), + vec![(u64::MAX, child)] + ); + let existing_pending_child_keys = PendingChildKeys::::get(netuid, parent_old); + assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_other)]); + + // Swap + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &parent_old, + &parent_new, + &coldkey, + &mut weight + )); + + // Verify parent and child keys updates + assert_eq!( + ParentKeys::::get(child, netuid), + vec![(u64::MAX, parent_new)] + ); + assert_eq!( + ChildKeys::::get(parent_new, netuid), + vec![(u64::MAX, child)] + ); + assert_eq!( + PendingChildKeys::::get(netuid, parent_new), + existing_pending_child_keys // Entry under new hotkey. + ); + }) +} + +#[test] +fn test_swap_child_hotkey_childkey_maps() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent = U256::from(1); + let coldkey = U256::from(2); + let child_old = U256::from(3); + let child_new = U256::from(4); + add_network(netuid, 1, 0); + SubtensorModule::create_account_if_non_existent(&coldkey, &child_old); + SubtensorModule::create_account_if_non_existent(&coldkey, &parent); + + // Set child and verify state maps + mock_set_children(&coldkey, &parent, netuid, &[(u64::MAX, child_old)]); + // Wait rate limit + step_rate_limit(&TransactionType::SetChildren, netuid); + // Schedule some pending child keys. + mock_schedule_children(&coldkey, &parent, netuid, &[(u64::MAX, child_old)]); + + assert_eq!( + ParentKeys::::get(child_old, netuid), + vec![(u64::MAX, parent)] + ); + assert_eq!( + ChildKeys::::get(parent, netuid), + vec![(u64::MAX, child_old)] + ); + let existing_pending_child_keys = PendingChildKeys::::get(netuid, parent); + assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_old)]); + + // Swap + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + &child_old, + &child_new, + &coldkey, + &mut weight + )); + + // Verify parent and child keys updates + assert_eq!( + ParentKeys::::get(child_new, netuid), + vec![(u64::MAX, parent)] + ); + assert_eq!( + ChildKeys::::get(parent, netuid), + vec![(u64::MAX, child_new)] + ); + assert_eq!( + PendingChildKeys::::get(netuid, parent), + (vec![(u64::MAX, child_new)], existing_pending_child_keys.1) // Same cooldown block. + ); + }) +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_is_sn_owner_hotkey --exact --nocapture +#[test] +fn test_swap_hotkey_is_sn_owner_hotkey() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Create dynamic network + let netuid = add_dynamic_network(&old_hotkey, &coldkey); + // Check for SubnetOwnerHotkey + assert_eq!(SubnetOwnerHotkey::::get(netuid), old_hotkey); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Check for SubnetOwnerHotkey + assert_eq!(SubnetOwnerHotkey::::get(netuid), new_hotkey); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_swap_rate_limits --exact --nocapture +#[test] +fn test_swap_hotkey_swap_rate_limits() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + let last_tx_block = 123; + let delegate_take_block = 4567; + let child_key_take_block = 8910; + + // Set the last tx block for the old hotkey + LastTxBlock::::insert(old_hotkey, last_tx_block); + // Set the last delegate take block for the old hotkey + LastTxBlockDelegateTake::::insert(old_hotkey, delegate_take_block); + // Set last childkey take block for the old hotkey + LastTxBlockChildKeyTake::::insert(old_hotkey, child_key_take_block); + + // Perform the swap + SubtensorModule::perform_hotkey_swap_on_all_subnets( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight, + ); + + // Check for new hotkey + assert_eq!(LastTxBlock::::get(new_hotkey), last_tx_block); + assert_eq!( + LastTxBlockDelegateTake::::get(new_hotkey), + delegate_take_block + ); + assert_eq!( + LastTxBlockChildKeyTake::::get(new_hotkey), + child_key_take_block + ); + }); +} + +#[test] +fn test_swap_hotkey_on_specific_subnet_successful() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + + 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 mut weight = Weight::zero(); + + Owner::::insert(old_hotkey, coldkey); + SubtensorModule::perform_hotkey_swap_on_one_subnet( + &old_hotkey, + &new_hotkey, + &mut weight, + netuid, + ); + + assert!(!Owner::::contains_key(old_hotkey)); + assert!(!Owner::::contains_key(new_hotkey)); + // assert_eq!(Owner::::get(new_hotkey), coldkey); + }); +} From e10c37cd018bdd50b948a762d9513d997ab9e1e8 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 17:21:08 +0800 Subject: [PATCH 16/44] fix an old test --- pallets/subtensor/src/tests/swap_hotkey.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 27c60cc6b1..1587976bbf 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -125,8 +125,14 @@ fn test_swap_senate_members() { let coldkey = U256::from(3); let mut weight = Weight::zero(); - // Assuming there's a way to add a member to the senate - // SenateMembers::add_member(&old_hotkey); + assert_ok!(SenateMembers::add_member( + RuntimeOrigin::root(), + old_hotkey.clone() + )); + let members = SenateMembers::members(); + assert!(members.contains(&old_hotkey)); + assert!(!members.contains(&new_hotkey)); + assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( &old_hotkey, &new_hotkey, @@ -135,8 +141,9 @@ fn test_swap_senate_members() { )); // Assert that the old_hotkey is no longer a member and new_hotkey is now a member - // assert!(!SenateMembers::is_member(&old_hotkey)); - // assert!(SenateMembers::is_member(&new_hotkey)); + let members = SenateMembers::members(); + assert!(!members.contains(&old_hotkey)); + assert!(members.contains(&new_hotkey)); }); } From 41dd31382fd6d808eda223749f57a4c669da2e3f Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 19:45:57 +0800 Subject: [PATCH 17/44] fix more test case --- pallets/subtensor/src/staking/helpers.rs | 10 +- pallets/subtensor/src/swap/swap_hotkey.rs | 100 ++++++--- .../src/tests/swap_hotkey_with_subnet.rs | 200 ++++++++++-------- 3 files changed, 190 insertions(+), 120 deletions(-) diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 9ee04f36a8..fc0088c771 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -60,7 +60,7 @@ impl Pallet { // pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { let hotkeys = StakingHotkeys::::get(coldkey); - hotkeys + let result = hotkeys .iter() .map(|hotkey| { let mut total_stake: u64 = 0; @@ -76,7 +76,13 @@ impl Pallet { } total_stake }) - .sum::() + .sum::(); + log::error!( + "======== get_total_stake_for_coldkey: coldkey: {:?}, total_stake: {:?}", + coldkey, + result + ); + result } // Creates a cold - hot pairing account if the hotkey is not already an active account. diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 5e51e86503..3266ce031f 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -253,35 +253,37 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().writes(1)); } - // 11. Swap Alpha - // Alpha( hotkey, coldkey, netuid ) -> alpha - let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = - Alpha::::iter_prefix((old_hotkey,)).collect(); - // Clear the entire old prefix here. - let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); - weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); - weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); - - // Insert the new alpha values. - for ((coldkey, netuid), alpha) in old_alpha_values { - let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); - Alpha::::insert( - (new_hotkey, &coldkey, netuid), - new_alpha.saturating_add(alpha), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - // Swap StakingHotkeys. - // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. - let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if staking_hotkeys.contains(old_hotkey) { - staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); - staking_hotkeys.push(new_hotkey.clone()); - StakingHotkeys::::insert(&coldkey, staking_hotkeys); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - } + // // 11. Swap Alpha + // // Alpha( hotkey, coldkey, netuid ) -> alpha + // let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = + // Alpha::::iter_prefix((old_hotkey,)).collect(); + // // Clear the entire old prefix here. + // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); + // weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); + // weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); + + // // Insert the new alpha values. + // for ((coldkey, netuid), alpha) in old_alpha_values { + // let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); + // Alpha::::insert( + // (new_hotkey, &coldkey, netuid), + // new_alpha.saturating_add(alpha), + // ); + // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // // Swap StakingHotkeys. + // // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. + // let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + // weight.saturating_accrue(T::DbWeight::get().reads(1)); + // if staking_hotkeys.contains(old_hotkey) { + // staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); + // if !staking_hotkeys.contains(new_hotkey) { + // staking_hotkeys.push(new_hotkey.clone()); + // } + // StakingHotkeys::::insert(&coldkey, staking_hotkeys); + // weight.saturating_accrue(T::DbWeight::get().writes(1)); + // } + // } // Return successful after swapping all the relevant terms. Ok(()) @@ -360,6 +362,14 @@ impl Pallet { Self::set_last_tx_block(coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); + let mut staking_hotkeys = StakingHotkeys::::get(coldkey); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { + staking_hotkeys.push(new_hotkey.clone()); + StakingHotkeys::::insert(coldkey, staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + // 16. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwappedOnSubnet { coldkey: coldkey.clone(), @@ -604,6 +614,38 @@ impl Pallet { ); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + // 11. Swap Alpha + // Alpha( hotkey, coldkey, netuid ) -> alpha + let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = + Alpha::::iter_prefix((old_hotkey,)).collect(); + // Clear the entire old prefix here. + // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); + weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); + weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); + + // Insert the new alpha values. + for ((coldkey, netuid_alpha), alpha) in old_alpha_values { + if netuid == netuid_alpha { + let new_alpha = Alpha::::take((new_hotkey, &coldkey, netuid)); + Alpha::::insert( + (new_hotkey, &coldkey, netuid), + new_alpha.saturating_add(alpha), + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // Swap StakingHotkeys. + // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. + let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { + staking_hotkeys.push(new_hotkey.clone()); + + StakingHotkeys::::insert(&coldkey, staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + } + } + // Return successful after swapping all the relevant terms. // Ok(()) } diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 96d902e0da..2afe09426e 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1,5 +1,7 @@ #![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] +use core::u64; + use approx::assert_abs_diff_eq; use codec::Encode; use frame_support::weights::Weight; @@ -159,16 +161,19 @@ fn test_swap_delegates() { let coldkey = U256::from(3); let mut weight = Weight::zero(); + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + Delegates::::insert(old_hotkey, 100); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); - assert!(!Delegates::::contains_key(old_hotkey)); - assert_eq!(Delegates::::get(new_hotkey), 100); + assert!(Delegates::::contains_key(old_hotkey)); + assert!(!Delegates::::contains_key(new_hotkey)); }); } @@ -179,16 +184,17 @@ fn test_swap_subnet_membership() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; let mut weight = Weight::zero(); - add_network(netuid, 1, 1); + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + IsNetworkMember::::insert(old_hotkey, netuid, true); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); assert!(!IsNetworkMember::::contains_key(old_hotkey, netuid)); @@ -200,23 +206,24 @@ fn test_swap_subnet_membership() { #[test] fn test_swap_uids_and_keys() { new_test_ext(1).execute_with(|| { + let uid = 5u16; let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; - let uid = 5u16; let mut weight = Weight::zero(); - add_network(netuid, 1, 1); + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + IsNetworkMember::::insert(old_hotkey, netuid, true); Uids::::insert(netuid, old_hotkey, uid); Keys::::insert(netuid, uid, old_hotkey); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); assert_eq!(Uids::::get(netuid, old_hotkey), None); @@ -229,22 +236,24 @@ fn test_swap_uids_and_keys() { #[test] fn test_swap_prometheus() { new_test_ext(1).execute_with(|| { + let uid = 5u16; let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; - let prometheus_info = PrometheusInfo::default(); let mut weight = Weight::zero(); + let prometheus_info = PrometheusInfo::default(); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); - add_network(netuid, 1, 1); IsNetworkMember::::insert(old_hotkey, netuid, true); Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); assert!(!Prometheus::::contains_key(netuid, old_hotkey)); @@ -259,22 +268,24 @@ fn test_swap_prometheus() { #[test] fn test_swap_axons() { new_test_ext(1).execute_with(|| { + let uid = 5u16; let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; - let axon_info = AxonInfo::default(); let mut weight = Weight::zero(); + let axon_info = AxonInfo::default(); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); - add_network(netuid, 1, 1); IsNetworkMember::::insert(old_hotkey, netuid, true); Axons::::insert(netuid, old_hotkey, axon_info.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); assert!(!Axons::::contains_key(netuid, old_hotkey)); @@ -286,22 +297,24 @@ fn test_swap_axons() { #[test] fn test_swap_certificates() { new_test_ext(1).execute_with(|| { + let uid = 5u16; let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; - let certificate = NeuronCertificate::try_from(vec![1, 2, 3]).unwrap(); let mut weight = Weight::zero(); + let certificate = NeuronCertificate::try_from(vec![1, 2, 3]).unwrap(); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); - add_network(netuid, 1, 1); IsNetworkMember::::insert(old_hotkey, netuid, true); NeuronCertificates::::insert(netuid, old_hotkey, certificate.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); assert!(!NeuronCertificates::::contains_key( @@ -318,23 +331,25 @@ use sp_std::collections::vec_deque::VecDeque; #[test] fn test_swap_weight_commits() { new_test_ext(1).execute_with(|| { + let uid = 5u16; let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; + let mut weight = Weight::zero(); let mut weight_commits: VecDeque<(H256, u64, u64, u64)> = VecDeque::new(); weight_commits.push_back((H256::from_low_u64_be(100), 200, 1, 1)); - let mut weight = Weight::zero(); - add_network(netuid, 1, 1); + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + IsNetworkMember::::insert(old_hotkey, netuid, true); WeightCommits::::insert(netuid, old_hotkey, weight_commits.clone()); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); assert!(!WeightCommits::::contains_key(netuid, old_hotkey)); @@ -349,26 +364,28 @@ fn test_swap_weight_commits() { #[test] fn test_swap_loaded_emission() { new_test_ext(1).execute_with(|| { + let uid = 5u16; let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; + let mut weight = Weight::zero(); let server_emission = 1000u64; let validator_emission = 1000u64; - let mut weight = Weight::zero(); - add_network(netuid, 1, 1); + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + IsNetworkMember::::insert(old_hotkey, netuid, true); LoadedEmission::::insert( netuid, vec![(old_hotkey, server_emission, validator_emission)], ); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); let new_loaded_emission = LoadedEmission::::get(netuid); @@ -386,25 +403,23 @@ fn test_swap_staking_hotkeys() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - - 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 netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let mut weight = Weight::zero(); StakingHotkeys::::insert(coldkey, vec![old_hotkey]); Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(100)); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); let staking_hotkeys = StakingHotkeys::::get(coldkey); - assert!(!staking_hotkeys.contains(&old_hotkey)); + assert!(staking_hotkeys.contains(&old_hotkey)); assert!(staking_hotkeys.contains(&new_hotkey)); }); } @@ -427,14 +442,8 @@ fn test_swap_hotkey_with_multiple_coldkeys() { StakingHotkeys::::insert(coldkey1, vec![old_hotkey]); StakingHotkeys::::insert(coldkey2, vec![old_hotkey]); SubtensorModule::create_account_if_non_existent(&coldkey1, &old_hotkey); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey1, - stake + ExistentialDeposit::get(), - ); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey2, - stake + ExistentialDeposit::get(), - ); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, u64::MAX); assert_ok!(SubtensorModule::add_stake( RuntimeOrigin::signed(coldkey1), @@ -451,13 +460,22 @@ fn test_swap_hotkey_with_multiple_coldkeys() { let stake1_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey1); let stake2_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey2); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey1), &old_hotkey, &new_hotkey, - &coldkey1, - &mut weight + Some(netuid) )); + assert_eq!( + SubtensorModule::get_total_stake_for_coldkey(&coldkey1), + SubtensorModule::get_total_stake_for_coldkey(&coldkey1), + ); + assert_eq!( + SubtensorModule::get_total_stake_for_coldkey(&coldkey2), + SubtensorModule::get_total_stake_for_coldkey(&coldkey2), + ); + assert_eq!( SubtensorModule::get_total_stake_for_coldkey(&coldkey1), stake1_before @@ -466,6 +484,7 @@ fn test_swap_hotkey_with_multiple_coldkeys() { SubtensorModule::get_total_stake_for_coldkey(&coldkey2), stake2_before ); + assert!(StakingHotkeys::::get(coldkey1).contains(&new_hotkey)); assert!(StakingHotkeys::::get(coldkey2).contains(&new_hotkey)); }); @@ -478,20 +497,27 @@ fn test_swap_hotkey_with_multiple_subnets() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid1 = 0; - let netuid2 = 1; let mut weight = Weight::zero(); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + let netuid1 = add_dynamic_network(&old_hotkey, &coldkey); + let netuid2 = add_dynamic_network(&old_hotkey, &coldkey); - add_network(netuid1, 1, 1); - add_network(netuid2, 1, 1); IsNetworkMember::::insert(old_hotkey, netuid1, true); IsNetworkMember::::insert(old_hotkey, netuid2, true); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid1) + )); + + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid2) )); assert!(IsNetworkMember::::get(new_hotkey, netuid1)); @@ -516,20 +542,15 @@ fn test_swap_staking_hotkeys_multiple_coldkeys() { let staker5 = U256::from(5); let mut weight = Weight::zero(); let stake = 1_000_000_000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, u64::MAX); // Set up initial state StakingHotkeys::::insert(coldkey1, vec![old_hotkey]); StakingHotkeys::::insert(coldkey2, vec![old_hotkey, staker5]); SubtensorModule::create_account_if_non_existent(&coldkey1, &old_hotkey); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey1, - stake + ExistentialDeposit::get(), - ); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey2, - stake + ExistentialDeposit::get(), - ); + assert_ok!(SubtensorModule::add_stake( RuntimeOrigin::signed(coldkey1), old_hotkey, @@ -543,20 +564,20 @@ fn test_swap_staking_hotkeys_multiple_coldkeys() { stake )); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey1), &old_hotkey, &new_hotkey, - &coldkey1, - &mut weight + Some(netuid) )); // Check if new_hotkey replaced old_hotkey in StakingHotkeys assert!(StakingHotkeys::::get(coldkey1).contains(&new_hotkey)); - assert!(!StakingHotkeys::::get(coldkey1).contains(&old_hotkey)); + assert!(StakingHotkeys::::get(coldkey1).contains(&old_hotkey)); // Check if new_hotkey replaced old_hotkey for coldkey2 as well assert!(StakingHotkeys::::get(coldkey2).contains(&new_hotkey)); - assert!(!StakingHotkeys::::get(coldkey2).contains(&old_hotkey)); + assert!(StakingHotkeys::::get(coldkey2).contains(&old_hotkey)); assert!(StakingHotkeys::::get(coldkey2).contains(&staker5)); // Other hotkeys should remain }); @@ -574,19 +595,20 @@ fn test_swap_hotkey_with_no_stake() { let new_hotkey = U256::from(2); let coldkey = U256::from(3); let mut weight = Weight::zero(); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); // Set up initial state with no stake Owner::::insert(old_hotkey, coldkey); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight + Some(netuid) )); // Check if ownership transferred - assert!(!Owner::::contains_key(old_hotkey)); + assert!(Owner::::contains_key(old_hotkey)); assert_eq!(Owner::::get(new_hotkey), coldkey); // Ensure no unexpected changes in Stake From 8b335e8d732f9d93b2ee0dbac18d73173a96ac4a Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 20:08:25 +0800 Subject: [PATCH 18/44] commit Cargo.lock --- pallets/subtensor/src/benchmarks.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 9201a73fc5..787a761675 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1433,7 +1433,12 @@ mod pallet_benchmarks { Subtensor::::add_balance_to_coldkey_account(&coldkey, cost); #[extrinsic_call] - _(RawOrigin::Signed(coldkey.clone()), old.clone(), new.clone()); + _( + RawOrigin::Signed(coldkey.clone()), + old.clone(), + new.clone(), + None, + ); } #[benchmark] From 70f768fcb9134fcc22002833b2b0c896847abbbc Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 20:09:19 +0800 Subject: [PATCH 19/44] cargo clippy --- pallets/subtensor/src/tests/swap_hotkey.rs | 2 +- pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 1587976bbf..fac64431fb 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -127,7 +127,7 @@ fn test_swap_senate_members() { assert_ok!(SenateMembers::add_member( RuntimeOrigin::root(), - old_hotkey.clone() + old_hotkey )); let members = SenateMembers::members(); assert!(members.contains(&old_hotkey)); diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 2afe09426e..34e04d3766 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -136,7 +136,7 @@ fn test_swap_senate_members() { assert_ok!(SenateMembers::add_member( RuntimeOrigin::root(), - old_hotkey.clone() + old_hotkey )); assert_ok!(SubtensorModule::do_swap_hotkey( From 51360f8a6dcfa75c9bcd1942228d70cffa07c63d Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 20:09:51 +0800 Subject: [PATCH 20/44] cargo fmt --- pallets/subtensor/src/tests/swap_hotkey.rs | 5 +---- pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index fac64431fb..9b2b9d2197 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -125,10 +125,7 @@ fn test_swap_senate_members() { let coldkey = U256::from(3); let mut weight = Weight::zero(); - assert_ok!(SenateMembers::add_member( - RuntimeOrigin::root(), - old_hotkey - )); + assert_ok!(SenateMembers::add_member(RuntimeOrigin::root(), old_hotkey)); let members = SenateMembers::members(); assert!(members.contains(&old_hotkey)); assert!(!members.contains(&new_hotkey)); diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 34e04d3766..e5a0037537 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -134,10 +134,7 @@ fn test_swap_senate_members() { let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); - assert_ok!(SenateMembers::add_member( - RuntimeOrigin::root(), - old_hotkey - )); + assert_ok!(SenateMembers::add_member(RuntimeOrigin::root(), old_hotkey)); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), From fa7c9df4930dfdf252d439361534ceccf190bbc4 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 2 May 2025 20:44:00 +0800 Subject: [PATCH 21/44] commit Cargo.lock --- pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index e5a0037537..490950c174 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1,7 +1,5 @@ #![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] -use core::u64; - use approx::assert_abs_diff_eq; use codec::Encode; use frame_support::weights::Weight; From a37245b31e2014040461969aea400b063e214301 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 3 May 2025 11:53:06 +0800 Subject: [PATCH 22/44] fix test case --- .../src/tests/swap_hotkey_with_subnet.rs | 132 +++++++----------- 1 file changed, 49 insertions(+), 83 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 490950c174..6330f59c40 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -632,8 +632,8 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { register_ok_neuron(netuid2, old_hotkey, coldkey1, 1234); // Add balance to both coldkeys - SubtensorModule::add_balance_to_coldkey_account(&coldkey1, stake + 1_000); - SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake + 1_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, u64::MAX); // Stake with coldkey1 assert_ok!(SubtensorModule::add_stake( @@ -666,11 +666,18 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { let total_hk_stake = SubtensorModule::get_total_stake_for_hotkey(&old_hotkey); assert!(total_hk_stake > 0); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey1), &old_hotkey, &new_hotkey, - &coldkey1, - &mut weight + Some(netuid1) + )); + + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey1), + &old_hotkey, + &new_hotkey, + Some(netuid2) )); // Check ownership transfer @@ -771,19 +778,19 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { // Perform the first swap assert_ok!(SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey), + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey_1, - None - )); + Some(netuid) + ),); // Attempt to perform another swap immediately, which should fail due to rate limit assert_err!( SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey), + RuntimeOrigin::signed(coldkey), + &old_hotkey, &new_hotkey_1, - &new_hotkey_2, - None + Some(netuid) ), Error::::HotKeySetTxRateLimitExceeded ); @@ -819,42 +826,16 @@ fn test_do_swap_hotkey_err_not_owner() { // Attempt the swap with a non-owner coldkey assert_err!( SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(not_owner_coldkey), + RuntimeOrigin::signed(not_owner_coldkey), &old_hotkey, &new_hotkey, - None + Some(netuid) ), Error::::NonAssociatedColdKey ); }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner_success --exact --nocapture -#[test] -fn test_swap_owner_success() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - let mut weight = Weight::zero(); - - // Initialize Owner for old_hotkey - Owner::::insert(old_hotkey, coldkey); - - // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, - ); - - // Verify the swap - assert_eq!(Owner::::get(new_hotkey), coldkey); - assert!(!Owner::::contains_key(old_hotkey)); - }); -} - // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner_old_hotkey_not_exist --exact --nocapture #[test] fn test_swap_owner_old_hotkey_not_exist() { @@ -864,15 +845,21 @@ fn test_swap_owner_old_hotkey_not_exist() { let coldkey = U256::from(3); let mut weight = Weight::zero(); + let netuid = add_dynamic_network(&new_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + // Ensure old_hotkey does not exist assert!(!Owner::::contains_key(old_hotkey)); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, + assert_err!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + ), + Error::::NonAssociatedColdKey ); // Verify the swap @@ -890,49 +877,27 @@ fn test_swap_owner_new_hotkey_already_exists() { let coldkey = U256::from(3); let another_coldkey = U256::from(4); let mut weight = Weight::zero(); + let netuid = add_dynamic_network(&new_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); // Initialize Owner for old_hotkey and new_hotkey Owner::::insert(old_hotkey, coldkey); Owner::::insert(new_hotkey, another_coldkey); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, - ); - - // Verify the swap - assert_eq!(Owner::::get(new_hotkey), coldkey); - assert!(!Owner::::contains_key(old_hotkey)); - }); -} - -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_swap_delegates_success --exact --show-output -#[test] -fn test_swap_delegates_success() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - let delegate_take = 10u16; - let mut weight = Weight::zero(); - - // Initialize Delegates for old_hotkey - Delegates::::insert(old_hotkey, delegate_take); - - // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, + assert_err!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + ), + Error::::HotKeyAlreadyRegisteredInSubNet ); // Verify the swap - assert_eq!(Delegates::::get(new_hotkey), delegate_take); - assert!(!Delegates::::contains_key(old_hotkey)); + assert_eq!(Owner::::get(old_hotkey), coldkey); + assert!(Owner::::contains_key(old_hotkey)); }); } @@ -945,7 +910,8 @@ fn test_swap_stake_success() { let coldkey = U256::from(3); 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 netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let amount = 10_000; let shares = U64F64::from_num(123456); let mut weight = Weight::zero(); @@ -959,12 +925,12 @@ fn test_swap_stake_success() { TaoDividendsPerSubnet::::insert(netuid, old_hotkey, amount); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid) + ),); // Verify the swap assert_eq!(TotalHotkeyAlpha::::get(old_hotkey, netuid), 0); From 18e4bc447d0dd585ae39cc6f4f35c022c9dcd206 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 3 May 2025 13:05:27 +0800 Subject: [PATCH 23/44] all test case done --- pallets/subtensor/src/swap/swap_hotkey.rs | 51 ++-- pallets/subtensor/src/tests/swap_hotkey.rs | 53 ----- .../src/tests/swap_hotkey_with_subnet.rs | 219 ++++++------------ 3 files changed, 101 insertions(+), 222 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 3266ce031f..116a521d60 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -56,10 +56,31 @@ impl Pallet { Error::::HotKeySetTxRateLimitExceeded ); + // 9. Swap LastTxBlock + // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. + let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); + LastTxBlock::::insert(new_hotkey, last_tx_block); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 10. Swap LastTxBlockDelegateTake + // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. + let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); + LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // 11. Swap LastTxBlockChildKeyTake + // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. + let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); + LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + // 8. fork for swap hotkey on a specific subnet case after do the common check if let Some(netuid) = netuid { return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight); }; + LastTxBlock::::remove(old_hotkey); + LastTxBlockDelegateTake::::remove(old_hotkey); + LastTxBlockChildKeyTake::::remove(old_hotkey); // following update just for swap hotkey in all subnets case @@ -82,27 +103,6 @@ impl Pallet { // 12. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - // 9. Swap LastTxBlock - // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. - let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); - LastTxBlock::::remove(old_hotkey); - LastTxBlock::::insert(new_hotkey, last_tx_block); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - - // 10. Swap LastTxBlockDelegateTake - // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. - let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); - LastTxBlockDelegateTake::::remove(old_hotkey); - LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - - // 11. Swap LastTxBlockChildKeyTake - // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. - let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); - LastTxBlockChildKeyTake::::remove(old_hotkey); - LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 8. Swap Senate members. // Senate( hotkey ) --> ? if T::SenateMembers::is_member(old_hotkey) { @@ -625,11 +625,17 @@ impl Pallet { // Insert the new alpha values. for ((coldkey, netuid_alpha), alpha) in old_alpha_values { + log::error!("Alpha: {:?}", alpha); + log::error!("Coldkey: {:?}", coldkey); + log::error!("Netuid: {:?}", netuid_alpha); if netuid == netuid_alpha { + // let new_alpha = Alpha::::take((old_hotkey, &coldkey, netuid)); let new_alpha = Alpha::::take((new_hotkey, &coldkey, netuid)); + Alpha::::remove((old_hotkey, &coldkey, netuid)); + log::error!("New Alpha: {:?}", new_alpha); Alpha::::insert( (new_hotkey, &coldkey, netuid), - new_alpha.saturating_add(alpha), + alpha.saturating_add(new_alpha), ); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); @@ -638,6 +644,7 @@ impl Pallet { let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); weight.saturating_accrue(T::DbWeight::get().reads(1)); if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { + log::error!("Staking hotkeys: {:?}", staking_hotkeys); staking_hotkeys.push(new_hotkey.clone()); StakingHotkeys::::insert(&coldkey, staking_hotkeys); diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 9b2b9d2197..f6b1db9ec6 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -806,32 +806,6 @@ fn test_do_swap_hotkey_err_not_owner() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey -- test_swap_owner_success --exact --nocapture -#[test] -fn test_swap_owner_success() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - let mut weight = Weight::zero(); - - // Initialize Owner for old_hotkey - Owner::::insert(old_hotkey, coldkey); - - // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, - ); - - // Verify the swap - assert_eq!(Owner::::get(new_hotkey), coldkey); - assert!(!Owner::::contains_key(old_hotkey)); - }); -} - // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey -- test_swap_owner_old_hotkey_not_exist --exact --nocapture #[test] fn test_swap_owner_old_hotkey_not_exist() { @@ -886,33 +860,6 @@ fn test_swap_owner_new_hotkey_already_exists() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_swap_delegates_success --exact --show-output -#[test] -fn test_swap_delegates_success() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - let delegate_take = 10u16; - let mut weight = Weight::zero(); - - // Initialize Delegates for old_hotkey - Delegates::::insert(old_hotkey, delegate_take); - - // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, - ); - - // Verify the swap - assert_eq!(Delegates::::get(new_hotkey), delegate_take); - assert!(!Delegates::::contains_key(old_hotkey)); - }); -} - // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey -- test_swap_stake_success --exact --nocapture #[test] fn test_swap_stake_success() { diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 6330f59c40..74cda8a144 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -972,67 +972,6 @@ fn test_swap_stake_success() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_stake_old_hotkey_not_exist --exact --nocapture -#[test] -fn test_swap_stake_old_hotkey_not_exist() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - 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 alpha_share = U64F64::from_num(1234); - let mut weight = Weight::zero(); - - // Initialize Stake for old_hotkey - Alpha::::insert((old_hotkey, coldkey, netuid), alpha_share); - - // Ensure old_hotkey has a stake - assert!(Alpha::::contains_key((old_hotkey, coldkey, netuid))); - - // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight, - ); - - // Verify that new_hotkey has the stake and old_hotkey does not - assert!(Alpha::::contains_key((new_hotkey, coldkey, netuid))); - assert!(!Alpha::::contains_key((old_hotkey, coldkey, netuid))); - }); -} - -// // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_total_hotkey_coldkey_stakes_this_interval_success --exact --nocapture -// #[test] -// fn test_swap_total_hotkey_coldkey_stakes_this_interval_success() { -// new_test_ext(1).execute_with(|| { -// let old_hotkey = U256::from(1); -// let new_hotkey = U256::from(2); -// let coldkey = U256::from(3); -// let stake = (1000u64, 42u64); // Example tuple value -// let mut weight = Weight::zero(); - -// // Initialize TotalHotkeyColdkeyStakesThisInterval for old_hotkey -// TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); - -// // Perform the swap -// SubtensorModule::perform_hotkey_swap_on_all_subnets(&old_hotkey, &new_hotkey, &coldkey, &mut weight); - -// // Verify the swap -// assert_eq!( -// TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), -// stake -// ); -// assert!(!TotalHotkeyColdkeyStakesThisInterval::::contains_key( -// old_hotkey, coldkey -// )); -// }); -// } - // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_error_cases --exact --nocapture #[test] fn test_swap_hotkey_error_cases() { @@ -1041,6 +980,7 @@ fn test_swap_hotkey_error_cases() { let new_hotkey = U256::from(2); let coldkey = U256::from(3); let wrong_coldkey = U256::from(4); + let netuid = add_dynamic_network(&old_hotkey, &coldkey); // Set up initial state Owner::::insert(old_hotkey, coldkey); @@ -1054,7 +994,7 @@ fn test_swap_hotkey_error_cases() { RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - None + Some(netuid) ), Error::::NotEnoughBalanceToPaySwapHotKey ); @@ -1068,23 +1008,23 @@ fn test_swap_hotkey_error_cases() { RuntimeOrigin::signed(coldkey), &old_hotkey, &old_hotkey, - None + Some(netuid) ), Error::::NewHotKeyIsSameWithOld ); // Test new hotkey already registered - IsNetworkMember::::insert(new_hotkey, 0, true); + IsNetworkMember::::insert(new_hotkey, netuid, true); assert_noop!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - None + Some(netuid) ), Error::::HotKeyAlreadyRegisteredInSubNet ); - IsNetworkMember::::remove(new_hotkey, 0); + IsNetworkMember::::remove(new_hotkey, netuid); // Test non-associated coldkey assert_noop!( @@ -1092,7 +1032,7 @@ fn test_swap_hotkey_error_cases() { RuntimeOrigin::signed(wrong_coldkey), &old_hotkey, &new_hotkey, - None + Some(netuid) ), Error::::NonAssociatedColdKey ); @@ -1102,11 +1042,8 @@ fn test_swap_hotkey_error_cases() { RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - None - )); - - // Check balance after swap - assert_eq!(Balances::free_balance(coldkey), initial_balance - swap_cost); + Some(netuid) + ),); }); } @@ -1117,21 +1054,22 @@ fn test_swap_child_keys() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; + let netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + let children = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; let mut weight = Weight::zero(); // Initialize ChildKeys for old_hotkey - add_network(netuid, 1, 0); ChildKeys::::insert(old_hotkey, netuid, children.clone()); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid) + ),); // Verify the swap assert_eq!(ChildKeys::::get(new_hotkey, netuid), children); @@ -1146,12 +1084,12 @@ fn test_swap_parent_keys() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; + let netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let parents = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; let mut weight = Weight::zero(); // Initialize ParentKeys for old_hotkey - add_network(netuid, 1, 0); ParentKeys::::insert(old_hotkey, netuid, parents.clone()); // Initialize ChildKeys for parent @@ -1159,12 +1097,12 @@ fn test_swap_parent_keys() { ChildKeys::::insert(U256::from(5), netuid, vec![(200u64, old_hotkey)]); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid) + ),); // Verify ParentKeys swap assert_eq!(ParentKeys::::get(new_hotkey, netuid), parents); @@ -1189,26 +1127,33 @@ fn test_swap_multiple_subnets() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid1 = 0u16; - let netuid2 = 1u16; + let netuid1 = add_dynamic_network(&old_hotkey, &coldkey); + let netuid2 = add_dynamic_network(&old_hotkey, &coldkey); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + let children1 = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; let children2 = vec![(300u64, U256::from(6))]; let mut weight = Weight::zero(); - add_network(netuid1, 1, 0); - add_network(netuid2, 1, 0); - // Initialize ChildKeys for old_hotkey in multiple subnets ChildKeys::::insert(old_hotkey, netuid1, children1.clone()); ChildKeys::::insert(old_hotkey, netuid2, children2.clone()); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid1) + ),); + + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid2) + ),); // Verify the swap for both subnets assert_eq!(ChildKeys::::get(new_hotkey, netuid1), children1); @@ -1225,15 +1170,14 @@ fn test_swap_complex_parent_child_structure() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let netuid = 0u16; + let netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let parent1 = U256::from(4); let parent2 = U256::from(5); let child1 = U256::from(6); let child2 = U256::from(7); let mut weight = Weight::zero(); - add_network(netuid, 1, 0); - // Set up complex parent-child structure ParentKeys::::insert( old_hotkey, @@ -1253,12 +1197,12 @@ fn test_swap_complex_parent_child_structure() { ); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid) + ),); // Verify ParentKeys swap assert_eq!( @@ -1289,13 +1233,15 @@ fn test_swap_complex_parent_child_structure() { #[test] fn test_swap_parent_hotkey_childkey_maps() { new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; let parent_old = U256::from(1); let coldkey = U256::from(2); let child = U256::from(3); let child_other = U256::from(4); let parent_new = U256::from(4); - add_network(netuid, 1, 0); + + let netuid = add_dynamic_network(&parent_old, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::create_account_if_non_existent(&coldkey, &parent_old); // Set child and verify state maps @@ -1318,12 +1264,12 @@ fn test_swap_parent_hotkey_childkey_maps() { // Swap let mut weight = Weight::zero(); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &parent_old, &parent_new, - &coldkey, - &mut weight - )); + Some(netuid) + ),); // Verify parent and child keys updates assert_eq!( @@ -1344,12 +1290,13 @@ fn test_swap_parent_hotkey_childkey_maps() { #[test] fn test_swap_child_hotkey_childkey_maps() { new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; let parent = U256::from(1); let coldkey = U256::from(2); let child_old = U256::from(3); let child_new = U256::from(4); - add_network(netuid, 1, 0); + let netuid = add_dynamic_network(&child_old, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::create_account_if_non_existent(&coldkey, &child_old); SubtensorModule::create_account_if_non_existent(&coldkey, &parent); @@ -1373,12 +1320,12 @@ fn test_swap_child_hotkey_childkey_maps() { // Swap let mut weight = Weight::zero(); - assert_ok!(SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &child_old, &child_new, - &coldkey, - &mut weight - )); + Some(netuid) + ),); // Verify parent and child keys updates assert_eq!( @@ -1407,16 +1354,18 @@ fn test_swap_hotkey_is_sn_owner_hotkey() { // Create dynamic network let netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + // Check for SubnetOwnerHotkey assert_eq!(SubnetOwnerHotkey::::get(netuid), old_hotkey); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid) + ),); // Check for SubnetOwnerHotkey assert_eq!(SubnetOwnerHotkey::::get(netuid), new_hotkey); @@ -1436,6 +1385,9 @@ fn test_swap_hotkey_swap_rate_limits() { let delegate_take_block = 4567; let child_key_take_block = 8910; + let netuid = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + // Set the last tx block for the old hotkey LastTxBlock::::insert(old_hotkey, last_tx_block); // Set the last delegate take block for the old hotkey @@ -1444,12 +1396,12 @@ fn test_swap_hotkey_swap_rate_limits() { LastTxBlockChildKeyTake::::insert(old_hotkey, child_key_take_block); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + Some(netuid) + ),); // Check for new hotkey assert_eq!(LastTxBlock::::get(new_hotkey), last_tx_block); @@ -1463,30 +1415,3 @@ fn test_swap_hotkey_swap_rate_limits() { ); }); } - -#[test] -fn test_swap_hotkey_on_specific_subnet_successful() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - - 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 mut weight = Weight::zero(); - - Owner::::insert(old_hotkey, coldkey); - SubtensorModule::perform_hotkey_swap_on_one_subnet( - &old_hotkey, - &new_hotkey, - &mut weight, - netuid, - ); - - assert!(!Owner::::contains_key(old_hotkey)); - assert!(!Owner::::contains_key(new_hotkey)); - // assert_eq!(Owner::::get(new_hotkey), coldkey); - }); -} From 6e37a4c980036fbe781d581b4c216a98c79c5520 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 3 May 2025 13:06:14 +0800 Subject: [PATCH 24/44] clean up code --- pallets/subtensor/src/swap/swap_hotkey.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 116a521d60..04e42e8b16 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -625,14 +625,10 @@ impl Pallet { // Insert the new alpha values. for ((coldkey, netuid_alpha), alpha) in old_alpha_values { - log::error!("Alpha: {:?}", alpha); - log::error!("Coldkey: {:?}", coldkey); - log::error!("Netuid: {:?}", netuid_alpha); if netuid == netuid_alpha { // let new_alpha = Alpha::::take((old_hotkey, &coldkey, netuid)); let new_alpha = Alpha::::take((new_hotkey, &coldkey, netuid)); Alpha::::remove((old_hotkey, &coldkey, netuid)); - log::error!("New Alpha: {:?}", new_alpha); Alpha::::insert( (new_hotkey, &coldkey, netuid), alpha.saturating_add(new_alpha), @@ -644,9 +640,7 @@ impl Pallet { let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); weight.saturating_accrue(T::DbWeight::get().reads(1)); if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { - log::error!("Staking hotkeys: {:?}", staking_hotkeys); staking_hotkeys.push(new_hotkey.clone()); - StakingHotkeys::::insert(&coldkey, staking_hotkeys); weight.saturating_accrue(T::DbWeight::get().writes(1)); } From 5fe01d8847a10a2218db950b4710cec17da03dea Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 3 May 2025 15:46:40 +0800 Subject: [PATCH 25/44] fix failed test cases --- pallets/subtensor/src/swap/swap_hotkey.rs | 89 ++++++++++--------- pallets/subtensor/src/tests/swap_hotkey.rs | 4 +- .../src/tests/swap_hotkey_with_subnet.rs | 2 +- 3 files changed, 52 insertions(+), 43 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 04e42e8b16..f5208f2cd4 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -78,9 +78,6 @@ impl Pallet { if let Some(netuid) = netuid { return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight); }; - LastTxBlock::::remove(old_hotkey); - LastTxBlockDelegateTake::::remove(old_hotkey); - LastTxBlockChildKeyTake::::remove(old_hotkey); // following update just for swap hotkey in all subnets case @@ -103,6 +100,10 @@ impl Pallet { // 12. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + LastTxBlock::::remove(old_hotkey); + LastTxBlockDelegateTake::::remove(old_hotkey); + LastTxBlockChildKeyTake::::remove(old_hotkey); + // 8. Swap Senate members. // Senate( hotkey ) --> ? if T::SenateMembers::is_member(old_hotkey) { @@ -181,6 +182,8 @@ impl Pallet { coldkey: &T::AccountId, weight: &mut Weight, ) -> DispatchResult { + let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = + Alpha::::iter_prefix((old_hotkey,)).collect(); // 1. Swap owner. // Owner( hotkey ) -> coldkey -- the coldkey that owns the hotkey. Owner::::remove(old_hotkey); @@ -244,46 +247,45 @@ impl Pallet { // Swap StakingHotkeys. // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. - let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if staking_hotkeys.contains(old_hotkey) { - staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); - staking_hotkeys.push(new_hotkey.clone()); - StakingHotkeys::::insert(coldkey, staking_hotkeys); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } + // let mut staking_hotkeys = StakingHotkeys::::get(coldkey); + // weight.saturating_accrue(T::DbWeight::get().reads(1)); + // if staking_hotkeys.contains(old_hotkey) { + // staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); + // staking_hotkeys.push(new_hotkey.clone()); + // StakingHotkeys::::insert(coldkey, staking_hotkeys); + // weight.saturating_accrue(T::DbWeight::get().writes(1)); + // } // // 11. Swap Alpha // // Alpha( hotkey, coldkey, netuid ) -> alpha - // let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = - // Alpha::::iter_prefix((old_hotkey,)).collect(); + // // Clear the entire old prefix here. // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); // weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); // weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); // // Insert the new alpha values. - // for ((coldkey, netuid), alpha) in old_alpha_values { - // let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); - // Alpha::::insert( - // (new_hotkey, &coldkey, netuid), - // new_alpha.saturating_add(alpha), - // ); - // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - // // Swap StakingHotkeys. - // // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. - // let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); - // weight.saturating_accrue(T::DbWeight::get().reads(1)); - // if staking_hotkeys.contains(old_hotkey) { - // staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); - // if !staking_hotkeys.contains(new_hotkey) { - // staking_hotkeys.push(new_hotkey.clone()); - // } - // StakingHotkeys::::insert(&coldkey, staking_hotkeys); - // weight.saturating_accrue(T::DbWeight::get().writes(1)); - // } - // } + for ((coldkey, _netuid), _alpha) in old_alpha_values { + // let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); + // Alpha::::insert( + // (new_hotkey, &coldkey, netuid), + // new_alpha.saturating_add(alpha), + // ); + // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // Swap StakingHotkeys. + // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. + let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if staking_hotkeys.contains(old_hotkey) { + staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); + if !staking_hotkeys.contains(new_hotkey) { + staking_hotkeys.push(new_hotkey.clone()); + } + StakingHotkeys::::insert(&coldkey, staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + } // Return successful after swapping all the relevant terms. Ok(()) @@ -362,13 +364,13 @@ impl Pallet { Self::set_last_tx_block(coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); - let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { - staking_hotkeys.push(new_hotkey.clone()); - StakingHotkeys::::insert(coldkey, staking_hotkeys); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } + // let mut staking_hotkeys = StakingHotkeys::::get(coldkey); + // weight.saturating_accrue(T::DbWeight::get().reads(1)); + // if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { + // staking_hotkeys.push(new_hotkey.clone()); + // StakingHotkeys::::insert(coldkey, staking_hotkeys); + // weight.saturating_accrue(T::DbWeight::get().writes(1)); + // } // 16. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwappedOnSubnet { @@ -625,7 +627,12 @@ impl Pallet { // Insert the new alpha values. for ((coldkey, netuid_alpha), alpha) in old_alpha_values { + log::error!("======== Alpha: {:?}", alpha); + log::error!("Coldkey: {:?}", coldkey); + log::error!("Netuid: {:?}", netuid_alpha); if netuid == netuid_alpha { + log::error!("Netuid: {:?}", netuid); + log::error!("netuid_alpha: {:?}", netuid_alpha); // let new_alpha = Alpha::::take((old_hotkey, &coldkey, netuid)); let new_alpha = Alpha::::take((new_hotkey, &coldkey, netuid)); Alpha::::remove((old_hotkey, &coldkey, netuid)); diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index f6b1db9ec6..9220eef94b 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -514,6 +514,8 @@ fn test_swap_staking_hotkeys_multiple_coldkeys() { // Set up initial state StakingHotkeys::::insert(coldkey1, vec![old_hotkey]); StakingHotkeys::::insert(coldkey2, vec![old_hotkey, staker5]); + Alpha::::insert((old_hotkey, coldkey1, netuid), U64F64::from_num(100)); + Alpha::::insert((old_hotkey, coldkey2, netuid), U64F64::from_num(100)); SubtensorModule::create_account_if_non_existent(&coldkey1, &old_hotkey); SubtensorModule::add_balance_to_coldkey_account( @@ -1007,7 +1009,7 @@ fn test_swap_hotkey_error_cases() { // Test not enough balance let swap_cost = SubtensorModule::get_key_swap_cost(); - assert_noop!( + assert_err!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 74cda8a144..62785fe409 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -989,7 +989,7 @@ fn test_swap_hotkey_error_cases() { // Test not enough balance let swap_cost = SubtensorModule::get_key_swap_cost(); - assert_noop!( + assert_err!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, From 197b68b21afb86360c8adecb94ff6e443ab8e23b Mon Sep 17 00:00:00 2001 From: open-junius Date: Sun, 4 May 2025 12:11:29 +0800 Subject: [PATCH 26/44] fix test cases --- pallets/subtensor/src/swap/swap_hotkey.rs | 143 ++++++++------------- pallets/subtensor/src/tests/swap_hotkey.rs | 10 +- 2 files changed, 63 insertions(+), 90 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index f5208f2cd4..c2e75e7d2e 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -44,101 +44,99 @@ impl Pallet { // 4. Ensure the new hotkey is different from the old one ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); - // 5. Update the weight for the checks above - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - - // 6. Get the current block number + // 5. Get the current block number let block: u64 = Self::get_current_block_as_u64(); - // 7. Ensure the transaction rate limit is not exceeded + // 6. Ensure the transaction rate limit is not exceeded ensure!( !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), Error::::HotKeySetTxRateLimitExceeded ); - // 9. Swap LastTxBlock + weight.saturating_accrue(T::DbWeight::get().reads(2)); + + // 7. Swap LastTxBlock // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); LastTxBlock::::insert(new_hotkey, last_tx_block); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 10. Swap LastTxBlockDelegateTake + // 8. Swap LastTxBlockDelegateTake // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 11. Swap LastTxBlockChildKeyTake + // 9. Swap LastTxBlockChildKeyTake // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 8. fork for swap hotkey on a specific subnet case after do the common check + // 10. fork for swap hotkey on a specific subnet case after do the common check if let Some(netuid) = netuid { return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight); }; - // following update just for swap hotkey in all subnets case - - // 4. Ensure the new hotkey is not already registered on any network + // Start to do everything for swap hotkey on all subnets case + // 11. Ensure the new hotkey is not already registered on any network ensure!( !Self::is_hotkey_registered_on_any_network(new_hotkey), Error::::HotKeyAlreadyRegisteredInSubNet ); - // 10. Get the cost for swapping the key + // 12. Get the cost for swapping the key let swap_cost = Self::get_key_swap_cost(); log::debug!("Swap cost: {:?}", swap_cost); - // 11. Ensure the coldkey has enough balance to pay for the swap + // 13. Ensure the coldkey has enough balance to pay for the swap ensure!( Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapHotKey ); - // 12. Remove the swap cost from the coldkey's account + // 14. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - LastTxBlock::::remove(old_hotkey); - LastTxBlockDelegateTake::::remove(old_hotkey); - LastTxBlockChildKeyTake::::remove(old_hotkey); + // 15. Remove block related info for the old hotkey in swap all subnets case + // LastTxBlock::::remove(old_hotkey); + // LastTxBlockDelegateTake::::remove(old_hotkey); + // LastTxBlockChildKeyTake::::remove(old_hotkey); - // 8. Swap Senate members. + // 16. Swap Senate members. // Senate( hotkey ) --> ? - if T::SenateMembers::is_member(old_hotkey) { - T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } + // if T::SenateMembers::is_member(old_hotkey) { + // T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; + // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + // } - // 9. Swap delegates. - // Delegates( hotkey ) -> take value -- the hotkey delegate take value. - if Delegates::::contains_key(old_hotkey) { - let old_delegate_take = Delegates::::get(old_hotkey); - Delegates::::remove(old_hotkey); - Delegates::::insert(new_hotkey, old_delegate_take); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } + // // 17. Swap delegates. + // // Delegates( hotkey ) -> take value -- the hotkey delegate take value. + // if Delegates::::contains_key(old_hotkey) { + // let old_delegate_take = Delegates::::get(old_hotkey); + // Delegates::::remove(old_hotkey); + // Delegates::::insert(new_hotkey, old_delegate_take); + // weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + // } - // 13. Burn the tokens + // 18. Burn the tokens Self::burn_tokens(actual_burn_amount); - // 14. Perform the hotkey swap - let _ = - Self::perform_hotkey_swap_on_all_subnets(old_hotkey, new_hotkey, &coldkey, &mut weight); + // 19. Perform the hotkey swap + Self::perform_hotkey_swap_on_all_subnets(old_hotkey, new_hotkey, &coldkey, &mut weight)?; - // 15. Update the last transaction block for the coldkey + // 20. Update the last transaction block for the coldkey Self::set_last_tx_block(&coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); - // 16. Emit an event for the hotkey swap + // 21. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwapped { coldkey, old_hotkey: old_hotkey.clone(), new_hotkey: new_hotkey.clone(), }); - // 17. Return the weight of the operation + // 22. Return the weight of the operation Ok(Some(weight).into()) } @@ -182,15 +180,17 @@ impl Pallet { coldkey: &T::AccountId, weight: &mut Weight, ) -> DispatchResult { + // 1. keep the old hotkey alpha values for the case where hotkey staked by multiple coldkeys. let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = Alpha::::iter_prefix((old_hotkey,)).collect(); - // 1. Swap owner. + + // 2. Swap owner. // Owner( hotkey ) -> coldkey -- the coldkey that owns the hotkey. Owner::::remove(old_hotkey); Owner::::insert(new_hotkey, coldkey.clone()); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // 2. Swap OwnedHotkeys. + // 3. Swap OwnedHotkeys. // OwnedHotkeys( coldkey ) -> Vec -- the hotkeys that the coldkey owns. let mut hotkeys = OwnedHotkeys::::get(coldkey); // Add the new key if needed. @@ -198,45 +198,46 @@ impl Pallet { hotkeys.push(new_hotkey.clone()); } - // Remove the old key. + // 4. Remove the old key. hotkeys.retain(|hk| *hk != *old_hotkey); OwnedHotkeys::::insert(coldkey, hotkeys); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + // 5. execute the hotkey swap on all subnets for netuid in Self::get_all_subnet_netuids() { Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, weight, netuid); } - // 5. Swap LastTxBlock + // 6. Swap LastTxBlock // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. - let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); + // let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); LastTxBlock::::remove(old_hotkey); - LastTxBlock::::insert(new_hotkey, last_tx_block); + // LastTxBlock::::insert(new_hotkey, last_tx_block); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 6. Swap LastTxBlockDelegateTake + // 7. Swap LastTxBlockDelegateTake // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. - let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); + // let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); LastTxBlockDelegateTake::::remove(old_hotkey); - LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); + // LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 7. Swap LastTxBlockChildKeyTake + // 8. Swap LastTxBlockChildKeyTake // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. - let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); + // let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); LastTxBlockChildKeyTake::::remove(old_hotkey); - LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); + // LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 8. Swap Senate members. + // 9. Swap Senate members. // Senate( hotkey ) --> ? if T::SenateMembers::is_member(old_hotkey) { T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } - // 9. Swap delegates. + // 10. Swap delegates. // Delegates( hotkey ) -> take value -- the hotkey delegate take value. if Delegates::::contains_key(old_hotkey) { let old_delegate_take = Delegates::::get(old_hotkey); @@ -245,34 +246,9 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); } - // Swap StakingHotkeys. - // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. - // let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - // weight.saturating_accrue(T::DbWeight::get().reads(1)); - // if staking_hotkeys.contains(old_hotkey) { - // staking_hotkeys.retain(|hk| *hk != *old_hotkey && *hk != *new_hotkey); - // staking_hotkeys.push(new_hotkey.clone()); - // StakingHotkeys::::insert(coldkey, staking_hotkeys); - // weight.saturating_accrue(T::DbWeight::get().writes(1)); - // } - - // // 11. Swap Alpha - // // Alpha( hotkey, coldkey, netuid ) -> alpha - - // // Clear the entire old prefix here. - // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); - // weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); - // weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); - - // // Insert the new alpha values. + // 11. Alpha already update in perform_hotkey_swap_on_one_subnet + // Update the StakingHotkeys for the case where hotkey staked by multiple coldkeys. for ((coldkey, _netuid), _alpha) in old_alpha_values { - // let new_alpha = Alpha::::get((new_hotkey, &coldkey, netuid)); - // Alpha::::insert( - // (new_hotkey, &coldkey, netuid), - // new_alpha.saturating_add(alpha), - // ); - // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // Swap StakingHotkeys. // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); @@ -311,18 +287,16 @@ impl Pallet { netuid: u16, init_weight: Weight, ) -> DispatchResultWithPostInfo { - let mut weight = init_weight; - // Ensure the hotkey not registered on the network before. - ensure!( !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), Error::::HotKeyAlreadyRegisteredInSubNet ); + let mut weight: Weight = init_weight; weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - // 10. Get the cost for swapping the key + // 10. Get the cost for swapping the key on the subnet let swap_cost = T::KeySwapOneSubnetCost::get(); log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); @@ -653,8 +627,5 @@ impl Pallet { } } } - - // Return successful after swapping all the relevant terms. - // Ok(()) } } diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 9220eef94b..ffd212b093 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -1391,6 +1391,8 @@ fn test_swap_hotkey_swap_rate_limits() { let new_hotkey = U256::from(2); let coldkey = U256::from(3); let mut weight = Weight::zero(); + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let last_tx_block = 123; let delegate_take_block = 4567; @@ -1404,12 +1406,12 @@ fn test_swap_hotkey_swap_rate_limits() { LastTxBlockChildKeyTake::::insert(old_hotkey, child_key_take_block); // Perform the swap - SubtensorModule::perform_hotkey_swap_on_all_subnets( + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), &old_hotkey, &new_hotkey, - &coldkey, - &mut weight, - ); + None + )); // Check for new hotkey assert_eq!(LastTxBlock::::get(new_hotkey), last_tx_block); From 75f56ec852bda54369ae7b255055f2fac3aedf64 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sun, 4 May 2025 18:55:25 +0800 Subject: [PATCH 27/44] update weights --- pallets/subtensor/src/swap/swap_hotkey.rs | 79 +++++------------------ 1 file changed, 16 insertions(+), 63 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index c2e75e7d2e..bf5e6f0b2d 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -59,19 +59,19 @@ impl Pallet { // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); LastTxBlock::::insert(new_hotkey, last_tx_block); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 8. Swap LastTxBlockDelegateTake // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 9. Swap LastTxBlockChildKeyTake // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 10. fork for swap hotkey on a specific subnet case after do the common check if let Some(netuid) = netuid { @@ -95,32 +95,14 @@ impl Pallet { Error::::NotEnoughBalanceToPaySwapHotKey ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(3, 0)); + // 14. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - // 15. Remove block related info for the old hotkey in swap all subnets case - // LastTxBlock::::remove(old_hotkey); - // LastTxBlockDelegateTake::::remove(old_hotkey); - // LastTxBlockChildKeyTake::::remove(old_hotkey); - - // 16. Swap Senate members. - // Senate( hotkey ) --> ? - // if T::SenateMembers::is_member(old_hotkey) { - // T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; - // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // } - - // // 17. Swap delegates. - // // Delegates( hotkey ) -> take value -- the hotkey delegate take value. - // if Delegates::::contains_key(old_hotkey) { - // let old_delegate_take = Delegates::::get(old_hotkey); - // Delegates::::remove(old_hotkey); - // Delegates::::insert(new_hotkey, old_delegate_take); - // weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - // } - // 18. Burn the tokens Self::burn_tokens(actual_burn_amount); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 2)); // 19. Perform the hotkey swap Self::perform_hotkey_swap_on_all_subnets(old_hotkey, new_hotkey, &coldkey, &mut weight)?; @@ -183,6 +165,7 @@ impl Pallet { // 1. keep the old hotkey alpha values for the case where hotkey staked by multiple coldkeys. let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = Alpha::::iter_prefix((old_hotkey,)).collect(); + weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); // 2. Swap owner. // Owner( hotkey ) -> coldkey -- the coldkey that owns the hotkey. @@ -211,23 +194,17 @@ impl Pallet { // 6. Swap LastTxBlock // LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey. - // let last_tx_block: u64 = LastTxBlock::::get(old_hotkey); LastTxBlock::::remove(old_hotkey); - // LastTxBlock::::insert(new_hotkey, last_tx_block); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); // 7. Swap LastTxBlockDelegateTake // LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take. - // let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::::get(old_hotkey); LastTxBlockDelegateTake::::remove(old_hotkey); - // LastTxBlockDelegateTake::::insert(new_hotkey, last_tx_block_delegate_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); // 8. Swap LastTxBlockChildKeyTake // LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take. - // let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::::get(old_hotkey); LastTxBlockChildKeyTake::::remove(old_hotkey); - // LastTxBlockChildKeyTake::::insert(new_hotkey, last_tx_block_child_key_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); // 9. Swap Senate members. @@ -294,11 +271,12 @@ impl Pallet { ); let mut weight: Weight = init_weight; - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); // 10. Get the cost for swapping the key on the subnet let swap_cost = T::KeySwapOneSubnetCost::get(); log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); // 11. Ensure the coldkey has enough balance to pay for the swap ensure!( @@ -308,9 +286,11 @@ impl Pallet { // 12. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(coldkey, swap_cost)?; + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); // 13. Burn the tokens Self::burn_tokens(actual_burn_amount); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 1. Swap owner. // Owner( hotkey ) -> coldkey -- the coldkey that owns the hotkey. @@ -327,8 +307,6 @@ impl Pallet { OwnedHotkeys::::insert(coldkey, hotkeys); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } - // Remove the old key. - // hotkeys.retain(|hk| *hk != *old_hotkey); // 14. Perform the hotkey swap Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, &mut weight, netuid); @@ -338,14 +316,6 @@ impl Pallet { Self::set_last_tx_block(coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); - // let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - // weight.saturating_accrue(T::DbWeight::get().reads(1)); - // if staking_hotkeys.contains(old_hotkey) && !staking_hotkeys.contains(new_hotkey) { - // staking_hotkeys.push(new_hotkey.clone()); - // StakingHotkeys::::insert(coldkey, staking_hotkeys); - // weight.saturating_accrue(T::DbWeight::get().writes(1)); - // } - // 16. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwappedOnSubnet { coldkey: coldkey.clone(), @@ -366,22 +336,21 @@ impl Pallet { ) { // 1. Swap total hotkey alpha for all subnets it exists on. // TotalHotkeyAlpha( hotkey, netuid ) -> alpha -- the total alpha that the hotkey has on a specific subnet. - let alpha = TotalHotkeyAlpha::::take(old_hotkey, netuid); - // TotalHotkeyAlpha::::remove(old_hotkey, netuid); TotalHotkeyAlpha::::mutate(new_hotkey, netuid, |value| { *value = value.saturating_add(alpha) }); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 2. Swap total hotkey shares on all subnets it exists on. // TotalHotkeyShares( hotkey, netuid ) -> alpha -- the total alpha that the hotkey has on a specific subnet. - let share = TotalHotkeyShares::::take(old_hotkey, netuid); // TotalHotkeyAlpha::::remove(old_hotkey, netuid); TotalHotkeyShares::::mutate(new_hotkey, netuid, |value| { *value = value.saturating_add(share) }); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 3. Swap all subnet specific info. @@ -464,19 +433,15 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } } - - // } - // 12. Swap ChildKeys. // ChildKeys( parent, netuid ) --> Vec<(proportion,child)> -- the child keys of the parent. - // for netuid in Self::get_all_subnet_netuids() { - // Get the children of the old hotkey for this subnet let my_children: Vec<(u64, T::AccountId)> = ChildKeys::::get(old_hotkey, netuid); // Remove the old hotkey's child entries ChildKeys::::remove(old_hotkey, netuid); // Insert the same child entries for the new hotkey ChildKeys::::insert(new_hotkey, netuid, my_children.clone()); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + for (_, child_key_i) in my_children { // For each child, update their parent list let mut child_parents: Vec<(u64, T::AccountId)> = @@ -495,14 +460,13 @@ impl Pallet { // 13. Swap ParentKeys. // ParentKeys( child, netuid ) --> Vec<(proportion,parent)> -- the parent keys of the child. - // for netuid in Self::get_all_subnet_netuids() { - // Get the parents of the old hotkey for this subnet let parents: Vec<(u64, T::AccountId)> = ParentKeys::::get(old_hotkey, netuid); // Remove the old hotkey's parent entries ParentKeys::::remove(old_hotkey, netuid); // Insert the same parent entries for the new hotkey ParentKeys::::insert(new_hotkey, netuid, parents.clone()); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + for (_, parent_key_i) in parents { // For each parent, update their children list let mut parent_children: Vec<(u64, T::AccountId)> = @@ -520,8 +484,6 @@ impl Pallet { // 14. Swap PendingChildKeys. // PendingChildKeys( netuid, parent ) --> Vec<(proportion,child), cool_down_block> - // for netuid in Self::get_all_subnet_netuids() { - weight.saturating_accrue(T::DbWeight::get().reads(1)); if PendingChildKeys::::contains_key(netuid, old_hotkey) { let (children, cool_down_block) = PendingChildKeys::::get(netuid, old_hotkey); PendingChildKeys::::remove(netuid, old_hotkey); @@ -548,7 +510,6 @@ impl Pallet { // 15. Swap SubnetOwnerHotkey // SubnetOwnerHotkey( netuid ) --> hotkey -- the hotkey that is the owner of the subnet. - // for netuid in Self::get_all_subnet_netuids() { if let Ok(old_subnet_owner_hotkey) = SubnetOwnerHotkey::::try_get(netuid) { weight.saturating_accrue(T::DbWeight::get().reads(1)); if old_subnet_owner_hotkey == *old_hotkey { @@ -594,27 +555,19 @@ impl Pallet { // Alpha( hotkey, coldkey, netuid ) -> alpha let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = Alpha::::iter_prefix((old_hotkey,)).collect(); - // Clear the entire old prefix here. - // let _ = Alpha::::clear_prefix((old_hotkey,), old_alpha_values.len() as u32, None); weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values.len() as u64)); // Insert the new alpha values. for ((coldkey, netuid_alpha), alpha) in old_alpha_values { - log::error!("======== Alpha: {:?}", alpha); - log::error!("Coldkey: {:?}", coldkey); - log::error!("Netuid: {:?}", netuid_alpha); if netuid == netuid_alpha { - log::error!("Netuid: {:?}", netuid); - log::error!("netuid_alpha: {:?}", netuid_alpha); - // let new_alpha = Alpha::::take((old_hotkey, &coldkey, netuid)); let new_alpha = Alpha::::take((new_hotkey, &coldkey, netuid)); Alpha::::remove((old_hotkey, &coldkey, netuid)); Alpha::::insert( (new_hotkey, &coldkey, netuid), alpha.saturating_add(new_alpha), ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); // Swap StakingHotkeys. // StakingHotkeys( coldkey ) --> Vec -- the hotkeys that the coldkey stakes. From c0bd9ecfb685c3c1e0465978d17e6058abdcad3f Mon Sep 17 00:00:00 2001 From: open-junius Date: Sun, 4 May 2025 19:15:07 +0800 Subject: [PATCH 28/44] commit Cargo.lock --- pallets/subtensor/src/staking/helpers.rs | 10 +---- .../src/tests/swap_hotkey_with_subnet.rs | 43 ++++++------------- 2 files changed, 15 insertions(+), 38 deletions(-) diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index fc0088c771..9ee04f36a8 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -60,7 +60,7 @@ impl Pallet { // pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { let hotkeys = StakingHotkeys::::get(coldkey); - let result = hotkeys + hotkeys .iter() .map(|hotkey| { let mut total_stake: u64 = 0; @@ -76,13 +76,7 @@ impl Pallet { } total_stake }) - .sum::(); - log::error!( - "======== get_total_stake_for_coldkey: coldkey: {:?}, total_stake: {:?}", - coldkey, - result - ); - result + .sum::() } // Creates a cold - hot pairing account if the hotkey is not already an active account. diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 62785fe409..df8366a49b 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -18,7 +18,6 @@ fn test_swap_owner() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -42,7 +41,6 @@ fn test_swap_owned_hotkeys() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -69,7 +67,7 @@ fn test_swap_total_hotkey_stake() { let new_hotkey = U256::from(2); let coldkey = U256::from(3); let amount = DefaultMinStake::::get() * 10; - let mut weight = Weight::zero(); + let fee = DefaultStakingFee::::get(); //add network @@ -127,7 +125,6 @@ fn test_swap_senate_members() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -154,7 +151,6 @@ fn test_swap_delegates() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -179,7 +175,6 @@ fn test_swap_subnet_membership() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -205,7 +200,6 @@ fn test_swap_uids_and_keys() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -235,7 +229,7 @@ fn test_swap_prometheus() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + let prometheus_info = PrometheusInfo::default(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); @@ -267,7 +261,7 @@ fn test_swap_axons() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + let axon_info = AxonInfo::default(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); @@ -296,7 +290,7 @@ fn test_swap_certificates() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + let certificate = NeuronCertificate::try_from(vec![1, 2, 3]).unwrap(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); @@ -330,7 +324,7 @@ fn test_swap_weight_commits() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + let mut weight_commits: VecDeque<(H256, u64, u64, u64)> = VecDeque::new(); weight_commits.push_back((H256::from_low_u64_be(100), 200, 1, 1)); @@ -363,7 +357,7 @@ fn test_swap_loaded_emission() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + let server_emission = 1000u64; let validator_emission = 1000u64; @@ -401,8 +395,6 @@ fn test_swap_staking_hotkeys() { let netuid = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); - let mut weight = Weight::zero(); - StakingHotkeys::::insert(coldkey, vec![old_hotkey]); Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(100)); @@ -431,7 +423,7 @@ fn test_swap_hotkey_with_multiple_coldkeys() { let new_hotkey = U256::from(2); let coldkey1 = U256::from(3); let coldkey2 = U256::from(4); - let mut weight = Weight::zero(); + let stake = 1_000_000_000; StakingHotkeys::::insert(coldkey1, vec![old_hotkey]); @@ -492,7 +484,7 @@ fn test_swap_hotkey_with_multiple_subnets() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let netuid1 = add_dynamic_network(&old_hotkey, &coldkey); @@ -535,7 +527,7 @@ fn test_swap_staking_hotkeys_multiple_coldkeys() { let coldkey1 = U256::from(3); let coldkey2 = U256::from(4); let staker5 = U256::from(5); - let mut weight = Weight::zero(); + let stake = 1_000_000_000; SubtensorModule::add_balance_to_coldkey_account(&coldkey1, u64::MAX); SubtensorModule::add_balance_to_coldkey_account(&coldkey2, u64::MAX); @@ -589,7 +581,7 @@ fn test_swap_hotkey_with_no_stake() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); // Set up initial state with no stake @@ -623,7 +615,6 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { let netuid1 = 1; let netuid2 = 2; let stake = DefaultMinStake::::get() * 10; - let mut weight = Weight::zero(); // Set up initial state add_network(netuid1, 1, 1); @@ -843,7 +834,6 @@ fn test_swap_owner_old_hotkey_not_exist() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid = add_dynamic_network(&new_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -876,7 +866,7 @@ fn test_swap_owner_new_hotkey_already_exists() { let new_hotkey = U256::from(2); let coldkey = U256::from(3); let another_coldkey = U256::from(4); - let mut weight = Weight::zero(); + let netuid = add_dynamic_network(&new_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); @@ -914,7 +904,6 @@ fn test_swap_stake_success() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let amount = 10_000; let shares = U64F64::from_num(123456); - let mut weight = Weight::zero(); // Initialize staking variables for old_hotkey TotalHotkeyAlpha::::insert(old_hotkey, netuid, amount); @@ -1058,7 +1047,6 @@ fn test_swap_child_keys() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let children = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; - let mut weight = Weight::zero(); // Initialize ChildKeys for old_hotkey ChildKeys::::insert(old_hotkey, netuid, children.clone()); @@ -1087,7 +1075,6 @@ fn test_swap_parent_keys() { let netuid = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); let parents = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; - let mut weight = Weight::zero(); // Initialize ParentKeys for old_hotkey ParentKeys::::insert(old_hotkey, netuid, parents.clone()); @@ -1134,7 +1121,6 @@ fn test_swap_multiple_subnets() { let children1 = vec![(100u64, U256::from(4)), (200u64, U256::from(5))]; let children2 = vec![(300u64, U256::from(6))]; - let mut weight = Weight::zero(); // Initialize ChildKeys for old_hotkey in multiple subnets ChildKeys::::insert(old_hotkey, netuid1, children1.clone()); @@ -1176,7 +1162,6 @@ fn test_swap_complex_parent_child_structure() { let parent2 = U256::from(5); let child1 = U256::from(6); let child2 = U256::from(7); - let mut weight = Weight::zero(); // Set up complex parent-child structure ParentKeys::::insert( @@ -1263,7 +1248,7 @@ fn test_swap_parent_hotkey_childkey_maps() { assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_other)]); // Swap - let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &parent_old, @@ -1319,7 +1304,7 @@ fn test_swap_child_hotkey_childkey_maps() { assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_old)]); // Swap - let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &child_old, @@ -1350,7 +1335,6 @@ fn test_swap_hotkey_is_sn_owner_hotkey() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); // Create dynamic network let netuid = add_dynamic_network(&old_hotkey, &coldkey); @@ -1379,7 +1363,6 @@ fn test_swap_hotkey_swap_rate_limits() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let last_tx_block = 123; let delegate_take_block = 4567; From 4da3b4ee1c04ce88cbaf7d7fc974c00da6620b32 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sun, 4 May 2025 19:15:45 +0800 Subject: [PATCH 29/44] cargo clippy --- pallets/subtensor/src/tests/swap_hotkey.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index ffd212b093..0d6b24d7c0 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -1390,7 +1390,6 @@ fn test_swap_hotkey_swap_rate_limits() { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); - let mut weight = Weight::zero(); let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); From 24d9c5515c96a16fbb0b86ddb1b49892e5b9a208 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 09:22:43 +0800 Subject: [PATCH 30/44] add swap records --- pallets/subtensor/src/lib.rs | 13 +++++++++++++ pallets/subtensor/src/macros/config.rs | 3 +++ pallets/subtensor/src/macros/errors.rs | 2 ++ pallets/subtensor/src/macros/hooks.rs | 23 +++++++++++++++++++++++ pallets/subtensor/src/swap/swap_hotkey.rs | 17 ++++++++++++++--- pallets/subtensor/src/tests/mock.rs | 2 ++ runtime/src/lib.rs | 2 ++ 7 files changed, 59 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 2e0b479c0f..f5cd1c316c 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -908,6 +908,19 @@ pub mod pallet { OptionQuery, >; + #[pallet::storage] + /// --- DMap ( netuid, coldkey ) --> blocknumber | last hotkey swap on network. + pub type LastHotkeySwapOnNetuid = StorageDoubleMap< + _, + Identity, + u16, + Blake2_128Concat, + T::AccountId, + u64, + ValueQuery, + DefaultZeroU64, + >; + #[pallet::storage] /// Ensures unique IDs for StakeJobs storage map pub type NextStakeJobId = StorageValue<_, u64, ValueQuery, DefaultZeroU64>; diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index 46ca9dadca..9373444df8 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -216,5 +216,8 @@ mod config { /// Cost of swapping a hotkey in a subnet. #[pallet::constant] type KeySwapOneSubnetCost: Get; + /// Block number for a coldkey swap the hotkey in specific subnet. + #[pallet::constant] + type HotkeySwapOnSubnetInterval: Get; } } diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 089c741c33..b4a2ca699c 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -209,5 +209,7 @@ mod errors { InvalidRecoveredPublicKey, /// SubToken disabled now SubtokenDisabled, + /// Too frequent hotkey swap on subnet + HotKeySwapOnSubnetIntervalNotPassed, } } diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 4d26994f05..a80b94f6b2 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -41,6 +41,7 @@ mod hooks { // - The number of the block we are finalizing. fn on_finalize(block_number: BlockNumberFor) { Self::do_on_finalize(block_number); + Self::clean_up_hotkey_swap_records(block_number); } fn on_runtime_upgrade() -> frame_support::weights::Weight { @@ -122,4 +123,26 @@ mod hooks { Ok(()) } } + + impl Pallet { + fn clean_up_hotkey_swap_records(block_number: BlockNumberFor) { + let hotkey_swap_on_subnet_interval = T::HotkeySwapOnSubnetInterval::get(); + let block_number: u64 = TryInto::try_into(block_number) + .ok() + .expect("blockchain will not exceed 2^64 blocks; QED."); + let netuids = Self::get_all_subnet_netuids(); + + let slot = block_number % hotkey_swap_on_subnet_interval; + + if slot < (u16::MAX as u64) && netuids.contains(&(slot as u16)) { + for (coldkey, swap_block_number) in + LastHotkeySwapOnNetuid::::iter_prefix(slot as u16) + { + if swap_block_number + hotkey_swap_on_subnet_interval < block_number { + LastHotkeySwapOnNetuid::::remove(slot as u16, coldkey); + } + } + } + } + } } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index bf5e6f0b2d..ff3580923f 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -264,12 +264,23 @@ impl Pallet { netuid: u16, init_weight: Weight, ) -> DispatchResultWithPostInfo { + // 1. Ensure coldkey not swap hotkey too frequently + let mut weight: Weight = init_weight; + let block: u64 = Self::get_current_block_as_u64(); + let hotkey_swap_interval = T::HotkeySwapOnSubnetInterval::get(); + let last_hotkey_swap_block = LastHotkeySwapOnNetuid::::get(netuid, coldkey); + + ensure!( + last_hotkey_swap_block + hotkey_swap_interval < block, + Error::::HotKeySwapOnSubnetIntervalNotPassed + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(3, 0)); + // Ensure the hotkey not registered on the network before. ensure!( !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), Error::::HotKeyAlreadyRegisteredInSubNet ); - let mut weight: Weight = init_weight; weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); @@ -311,10 +322,10 @@ impl Pallet { // 14. Perform the hotkey swap Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, &mut weight, netuid); - let block: u64 = Self::get_current_block_as_u64(); // 15. Update the last transaction block for the coldkey Self::set_last_tx_block(coldkey, block); - weight.saturating_accrue(T::DbWeight::get().writes(1)); + LastHotkeySwapOnNetuid::::insert(netuid, coldkey, block); + weight.saturating_accrue(T::DbWeight::get().writes(2)); // 16. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwappedOnSubnet { diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index d934d33725..bb43015b87 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -187,6 +187,7 @@ parameter_types! { pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; + pub const HotkeySwapOnSubnetInterval: u64 = 1; // 1 block } @@ -413,6 +414,7 @@ impl crate::Config for Test { type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; type KeySwapOneSubnetCost = InitialKeySwapOnSubnetCost; + type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; } pub struct OriginPrivilegeCmp; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index ffb4d0722c..4b33eebf5c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1083,6 +1083,7 @@ parameter_types! { 7 * 24 * 60 * 60 / 12 // 7 days }; pub const SubtensorInitialKeySwapOnSubnetCost: u64 = 1_000_000; // 0.001 TAO + pub const HotkeySwapOnSubnetInterval : BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days } impl pallet_subtensor::Config for Runtime { @@ -1149,6 +1150,7 @@ impl pallet_subtensor::Config for Runtime { type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; type KeySwapOneSubnetCost = SubtensorInitialKeySwapOnSubnetCost; + type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; } use sp_runtime::BoundedVec; From bbf8337c5165b73907ee1dfb618fc15fe01f5112 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 09:24:42 +0800 Subject: [PATCH 31/44] add hook for clean up records --- pallets/subtensor/src/macros/hooks.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index a80b94f6b2..c552cf1db1 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -125,6 +125,8 @@ mod hooks { } impl Pallet { + // This function is to clean up the old hotkey swap records + // It just clean up for one subnet at a time, according to the block number fn clean_up_hotkey_swap_records(block_number: BlockNumberFor) { let hotkey_swap_on_subnet_interval = T::HotkeySwapOnSubnetInterval::get(); let block_number: u64 = TryInto::try_into(block_number) From 3cbe465742c1a594f0f1da6ac47f05b3b78dd2dc Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 09:28:54 +0800 Subject: [PATCH 32/44] commit Cargo.lock --- pallets/admin-utils/src/tests/mock.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index fc80f77c35..f37b8e2537 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -137,6 +137,7 @@ parameter_types! { pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; + pub const HotkeySwapOnSubnetInterval: u64 = 10_000_7 * 24 * 60 * 60 / 12; // 7 days } impl pallet_subtensor::Config for Test { @@ -203,6 +204,7 @@ impl pallet_subtensor::Config for Test { type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; type KeySwapOneSubnetCost = InitialKeySwapOnSubnetCost; + type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] From 1055f851ca0a3e1fbbf21b57e3977bc1641487f8 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 09:29:44 +0800 Subject: [PATCH 33/44] fix mock, missed parameter --- pallets/admin-utils/src/tests/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index f37b8e2537..dcc583fe2f 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -137,7 +137,7 @@ parameter_types! { pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; - pub const HotkeySwapOnSubnetInterval: u64 = 10_000_7 * 24 * 60 * 60 / 12; // 7 days + pub const HotkeySwapOnSubnetInterval: u64 = 7 * 24 * 60 * 60 / 12; // 7 days } impl pallet_subtensor::Config for Test { From f63424ebf2acc604c71cdcd0fecd71c7642042c5 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 09:42:29 +0800 Subject: [PATCH 34/44] fix clippy --- pallets/subtensor/src/macros/hooks.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index c552cf1db1..e7d4b76353 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -134,14 +134,14 @@ mod hooks { .expect("blockchain will not exceed 2^64 blocks; QED."); let netuids = Self::get_all_subnet_netuids(); - let slot = block_number % hotkey_swap_on_subnet_interval; - - if slot < (u16::MAX as u64) && netuids.contains(&(slot as u16)) { - for (coldkey, swap_block_number) in - LastHotkeySwapOnNetuid::::iter_prefix(slot as u16) - { - if swap_block_number + hotkey_swap_on_subnet_interval < block_number { - LastHotkeySwapOnNetuid::::remove(slot as u16, coldkey); + if let Some(slot) = block_number.checked_rem(hotkey_swap_on_subnet_interval) { + if slot < (u16::MAX as u64) && netuids.contains(&(slot as u16)) { + for (coldkey, swap_block_number) in + LastHotkeySwapOnNetuid::::iter_prefix(slot as u16) + { + if swap_block_number + hotkey_swap_on_subnet_interval < block_number { + LastHotkeySwapOnNetuid::::remove(slot as u16, coldkey); + } } } } From 566b24b05b63ab67a804d97bd12118ff1d26f00f Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 10:13:07 +0800 Subject: [PATCH 35/44] fix clippy --- pallets/subtensor/src/macros/hooks.rs | 4 +++- pallets/subtensor/src/swap/swap_hotkey.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index e7d4b76353..f95819d064 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -139,7 +139,9 @@ mod hooks { for (coldkey, swap_block_number) in LastHotkeySwapOnNetuid::::iter_prefix(slot as u16) { - if swap_block_number + hotkey_swap_on_subnet_interval < block_number { + if swap_block_number.saturating_add(hotkey_swap_on_subnet_interval) + < block_number + { LastHotkeySwapOnNetuid::::remove(slot as u16, coldkey); } } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index ff3580923f..67d9c417d5 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -271,7 +271,7 @@ impl Pallet { let last_hotkey_swap_block = LastHotkeySwapOnNetuid::::get(netuid, coldkey); ensure!( - last_hotkey_swap_block + hotkey_swap_interval < block, + last_hotkey_swap_block.saturating_add(hotkey_swap_interval) < block, Error::::HotKeySwapOnSubnetIntervalNotPassed ); weight.saturating_accrue(T::DbWeight::get().reads_writes(3, 0)); From 0b0856bc7cf1ea29ea767b3e3d5521cdafa478aa Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 10:41:21 +0800 Subject: [PATCH 36/44] fix test case --- .../src/tests/swap_hotkey_with_subnet.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index df8366a49b..efe4790f0a 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -22,6 +22,7 @@ fn test_swap_owner() { let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); Owner::::insert(old_hotkey, coldkey); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -46,6 +47,7 @@ fn test_swap_owned_hotkeys() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); OwnedHotkeys::::insert(coldkey, vec![old_hotkey]); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -97,6 +99,7 @@ fn test_swap_total_hotkey_stake() { ); // Swap hotkey + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -131,6 +134,7 @@ fn test_swap_senate_members() { assert_ok!(SenateMembers::add_member(RuntimeOrigin::root(), old_hotkey)); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -156,6 +160,7 @@ fn test_swap_delegates() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); Delegates::::insert(old_hotkey, 100); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -180,6 +185,7 @@ fn test_swap_subnet_membership() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); IsNetworkMember::::insert(old_hotkey, netuid, true); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -208,6 +214,7 @@ fn test_swap_uids_and_keys() { Uids::::insert(netuid, old_hotkey, uid); Keys::::insert(netuid, uid, old_hotkey); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -238,6 +245,7 @@ fn test_swap_prometheus() { IsNetworkMember::::insert(old_hotkey, netuid, true); Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -270,6 +278,7 @@ fn test_swap_axons() { IsNetworkMember::::insert(old_hotkey, netuid, true); Axons::::insert(netuid, old_hotkey, axon_info.clone()); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -299,6 +308,7 @@ fn test_swap_certificates() { IsNetworkMember::::insert(old_hotkey, netuid, true); NeuronCertificates::::insert(netuid, old_hotkey, certificate.clone()); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -334,6 +344,7 @@ fn test_swap_weight_commits() { IsNetworkMember::::insert(old_hotkey, netuid, true); WeightCommits::::insert(netuid, old_hotkey, weight_commits.clone()); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -370,6 +381,7 @@ fn test_swap_loaded_emission() { vec![(old_hotkey, server_emission, validator_emission)], ); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -398,6 +410,7 @@ fn test_swap_staking_hotkeys() { StakingHotkeys::::insert(coldkey, vec![old_hotkey]); Alpha::::insert((old_hotkey, coldkey, netuid), U64F64::from_num(100)); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -447,6 +460,7 @@ fn test_swap_hotkey_with_multiple_coldkeys() { let stake1_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey1); let stake2_before = SubtensorModule::get_total_stake_for_coldkey(&coldkey2); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey1), &old_hotkey, @@ -493,6 +507,7 @@ fn test_swap_hotkey_with_multiple_subnets() { IsNetworkMember::::insert(old_hotkey, netuid1, true); IsNetworkMember::::insert(old_hotkey, netuid2, true); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -500,6 +515,7 @@ fn test_swap_hotkey_with_multiple_subnets() { Some(netuid1) )); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -551,6 +567,7 @@ fn test_swap_staking_hotkeys_multiple_coldkeys() { stake )); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey1), &old_hotkey, @@ -587,6 +604,7 @@ fn test_swap_hotkey_with_no_stake() { // Set up initial state with no stake Owner::::insert(old_hotkey, coldkey); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -656,6 +674,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { assert!(ck2_stake > 0); let total_hk_stake = SubtensorModule::get_total_stake_for_hotkey(&old_hotkey); assert!(total_hk_stake > 0); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey1), @@ -664,6 +683,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() { Some(netuid1) )); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey1), &old_hotkey, @@ -768,6 +788,7 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); // Perform the first swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -788,6 +809,7 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { // move in time past the rate limit step_block(1001); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey), &new_hotkey_1, @@ -875,6 +897,7 @@ fn test_swap_owner_new_hotkey_already_exists() { Owner::::insert(new_hotkey, another_coldkey); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_err!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), @@ -914,6 +937,7 @@ fn test_swap_stake_success() { TaoDividendsPerSubnet::::insert(netuid, old_hotkey, amount); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -978,6 +1002,7 @@ fn test_swap_hotkey_error_cases() { // Test not enough balance let swap_cost = SubtensorModule::get_key_swap_cost(); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_err!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), @@ -992,6 +1017,7 @@ fn test_swap_hotkey_error_cases() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_balance); // Test new hotkey same as old + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_noop!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), @@ -1004,6 +1030,7 @@ fn test_swap_hotkey_error_cases() { // Test new hotkey already registered IsNetworkMember::::insert(new_hotkey, netuid, true); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_noop!( SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), @@ -1027,6 +1054,7 @@ fn test_swap_hotkey_error_cases() { ); // Run the successful swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1052,6 +1080,7 @@ fn test_swap_child_keys() { ChildKeys::::insert(old_hotkey, netuid, children.clone()); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1084,6 +1113,7 @@ fn test_swap_parent_keys() { ChildKeys::::insert(U256::from(5), netuid, vec![(200u64, old_hotkey)]); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1127,6 +1157,7 @@ fn test_swap_multiple_subnets() { ChildKeys::::insert(old_hotkey, netuid2, children2.clone()); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1134,6 +1165,7 @@ fn test_swap_multiple_subnets() { Some(netuid1) ),); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1182,6 +1214,7 @@ fn test_swap_complex_parent_child_structure() { ); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1249,6 +1282,7 @@ fn test_swap_parent_hotkey_childkey_maps() { // Swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &parent_old, @@ -1305,6 +1339,7 @@ fn test_swap_child_hotkey_childkey_maps() { // Swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &child_old, @@ -1344,6 +1379,7 @@ fn test_swap_hotkey_is_sn_owner_hotkey() { assert_eq!(SubnetOwnerHotkey::::get(netuid), old_hotkey); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, @@ -1379,6 +1415,7 @@ fn test_swap_hotkey_swap_rate_limits() { LastTxBlockChildKeyTake::::insert(old_hotkey, child_key_take_block); // Perform the swap + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), &old_hotkey, From 054222d38f55d7eeaeaef67f31a08b56097008e6 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 5 May 2025 11:26:00 +0800 Subject: [PATCH 37/44] test case for records --- pallets/subtensor/src/tests/mock.rs | 2 +- .../src/tests/swap_hotkey_with_subnet.rs | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index bb43015b87..1757bc3605 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -187,7 +187,7 @@ parameter_types! { pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; - pub const HotkeySwapOnSubnetInterval: u64 = 1; // 1 block + pub const HotkeySwapOnSubnetInterval: u64 = 15; // 15 block, should be bigger than subnet number, then trigger clean up for all subnets } diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index efe4790f0a..583a8cf448 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1435,3 +1435,82 @@ fn test_swap_hotkey_swap_rate_limits() { ); }); } + +#[test] +fn test_swap_owner_failed_interval_not_passed() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + Owner::::insert(old_hotkey, coldkey); + assert_err!( + SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + ), + Error::::HotKeySwapOnSubnetIntervalNotPassed, + ); + }); +} + +#[test] +fn test_swap_owner_check_swap_block_set() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + Owner::::insert(old_hotkey, coldkey); + let new_block_number = System::block_number() + HotkeySwapOnSubnetInterval::get(); + System::set_block_number(new_block_number); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + assert_eq!( + LastHotkeySwapOnNetuid::::get(netuid, coldkey), + new_block_number + ); + }); +} + +#[test] +fn test_swap_owner_check_swap_record_clean_up() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + + let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + Owner::::insert(old_hotkey, coldkey); + let new_block_number = System::block_number() + HotkeySwapOnSubnetInterval::get(); + System::set_block_number(new_block_number); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + assert_eq!( + LastHotkeySwapOnNetuid::::get(netuid, coldkey), + new_block_number + ); + + step_block((HotkeySwapOnSubnetInterval::get() as u16 + netuid) * 2); + assert!(!LastHotkeySwapOnNetuid::::contains_key( + netuid, coldkey + )); + }); +} From 57f109764d9b5d8f4459cc9333c1fdd31c5e9c0b Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 6 May 2025 08:12:34 +0800 Subject: [PATCH 38/44] update execution index --- pallets/subtensor/src/swap/swap_hotkey.rs | 56 +++++++++++------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 67d9c417d5..f9b5cb9ebc 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -276,7 +276,7 @@ impl Pallet { ); weight.saturating_accrue(T::DbWeight::get().reads_writes(3, 0)); - // Ensure the hotkey not registered on the network before. + // 2. Ensure the hotkey not registered on the network before. ensure!( !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), Error::::HotKeyAlreadyRegisteredInSubNet @@ -284,32 +284,32 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); - // 10. Get the cost for swapping the key on the subnet + // 3. Get the cost for swapping the key on the subnet let swap_cost = T::KeySwapOneSubnetCost::get(); log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); - // 11. Ensure the coldkey has enough balance to pay for the swap + // 4. Ensure the coldkey has enough balance to pay for the swap ensure!( Self::can_remove_balance_from_coldkey_account(coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapHotKey ); - // 12. Remove the swap cost from the coldkey's account + // 5. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(coldkey, swap_cost)?; weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); - // 13. Burn the tokens + // 6. Burn the tokens Self::burn_tokens(actual_burn_amount); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // 1. Swap owner. + // 7. Swap owner. // Owner( hotkey ) -> coldkey -- the coldkey that owns the hotkey. // Owner::::remove(old_hotkey); Owner::::insert(new_hotkey, coldkey.clone()); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // 2. Swap OwnedHotkeys. + // 8. Swap OwnedHotkeys. // OwnedHotkeys( coldkey ) -> Vec -- the hotkeys that the coldkey owns. let mut hotkeys = OwnedHotkeys::::get(coldkey); // Add the new key if needed. @@ -319,15 +319,15 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } - // 14. Perform the hotkey swap + // 9. Perform the hotkey swap Self::perform_hotkey_swap_on_one_subnet(old_hotkey, new_hotkey, &mut weight, netuid); - // 15. Update the last transaction block for the coldkey + // 10. Update the last transaction block for the coldkey Self::set_last_tx_block(coldkey, block); LastHotkeySwapOnNetuid::::insert(netuid, coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(2)); - // 16. Emit an event for the hotkey swap + // 11. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwappedOnSubnet { coldkey: coldkey.clone(), old_hotkey: old_hotkey.clone(), @@ -365,30 +365,30 @@ impl Pallet { // 3. Swap all subnet specific info. - // 10.1 Remove the previous hotkey and insert the new hotkey from membership. + // 3.1 Remove the previous hotkey and insert the new hotkey from membership. // IsNetworkMember( hotkey, netuid ) -> bool -- is the hotkey a subnet member. let is_network_member: bool = IsNetworkMember::::get(old_hotkey, netuid); IsNetworkMember::::remove(old_hotkey, netuid); IsNetworkMember::::insert(new_hotkey, netuid, is_network_member); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 10.2 Swap Uids + Keys. + // 3.2 Swap Uids + Keys. // Keys( netuid, hotkey ) -> uid -- the uid the hotkey has in the network if it is a member. // Uids( netuid, hotkey ) -> uid -- the uids that the hotkey has. if is_network_member { - // 10.2.1 Swap the UIDS + // 3.2.1 Swap the UIDS if let Ok(old_uid) = Uids::::try_get(netuid, old_hotkey) { Uids::::remove(netuid, old_hotkey); Uids::::insert(netuid, new_hotkey, old_uid); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 10.2.2 Swap the keys. + // 3.2.2 Swap the keys. Keys::::insert(netuid, old_uid, new_hotkey.clone()); weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); } } - // 10.3 Swap Prometheus. + // 3.3 Swap Prometheus. // Prometheus( netuid, hotkey ) -> prometheus -- the prometheus data that a hotkey has in the network. if is_network_member { if let Ok(old_prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { @@ -398,7 +398,7 @@ impl Pallet { } } - // 10.4. Swap axons. + // 3.4. Swap axons. // Axons( netuid, hotkey ) -> axon -- the axon that the hotkey has. if is_network_member { if let Ok(old_axon_info) = Axons::::try_get(netuid, old_hotkey) { @@ -408,7 +408,7 @@ impl Pallet { } } - // 10.5 Swap WeightCommits + // 3.5 Swap WeightCommits // WeightCommits( hotkey ) --> Vec -- the weight commits for the hotkey. if is_network_member { if let Ok(old_weight_commits) = WeightCommits::::try_get(netuid, old_hotkey) { @@ -418,7 +418,7 @@ impl Pallet { } } - // 10.6. Swap the subnet loaded emission. + // 3.6. Swap the subnet loaded emission. // LoadedEmission( netuid ) --> Vec<(hotkey, u64)> -- the loaded emission for the subnet. if is_network_member { if let Some(mut old_loaded_emission) = LoadedEmission::::get(netuid) { @@ -433,7 +433,7 @@ impl Pallet { } } - // 10.7. Swap neuron TLS certificates. + // 3.7. Swap neuron TLS certificates. // NeuronCertificates( netuid, hotkey ) -> Vec -- the neuron certificate for the hotkey. if is_network_member { if let Ok(old_neuron_certificates) = @@ -444,7 +444,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); } } - // 12. Swap ChildKeys. + // 4. Swap ChildKeys. // ChildKeys( parent, netuid ) --> Vec<(proportion,child)> -- the child keys of the parent. let my_children: Vec<(u64, T::AccountId)> = ChildKeys::::get(old_hotkey, netuid); // Remove the old hotkey's child entries @@ -469,7 +469,7 @@ impl Pallet { } // } - // 13. Swap ParentKeys. + // 5. Swap ParentKeys. // ParentKeys( child, netuid ) --> Vec<(proportion,parent)> -- the parent keys of the child. let parents: Vec<(u64, T::AccountId)> = ParentKeys::::get(old_hotkey, netuid); // Remove the old hotkey's parent entries @@ -493,7 +493,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } - // 14. Swap PendingChildKeys. + // 6. Swap PendingChildKeys. // PendingChildKeys( netuid, parent ) --> Vec<(proportion,child), cool_down_block> if PendingChildKeys::::contains_key(netuid, old_hotkey) { let (children, cool_down_block) = PendingChildKeys::::get(netuid, old_hotkey); @@ -519,7 +519,7 @@ impl Pallet { } } - // 15. Swap SubnetOwnerHotkey + // 7. Swap SubnetOwnerHotkey // SubnetOwnerHotkey( netuid ) --> hotkey -- the hotkey that is the owner of the subnet. if let Ok(old_subnet_owner_hotkey) = SubnetOwnerHotkey::::try_get(netuid) { weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -529,8 +529,8 @@ impl Pallet { } } - // 16. Swap dividend records - // 16.1 Swap TotalHotkeyAlphaLastEpoch + // 8. Swap dividend records + // 8.1 Swap TotalHotkeyAlphaLastEpoch let old_alpha = TotalHotkeyAlphaLastEpoch::::take(old_hotkey, netuid); let new_total_hotkey_alpha = TotalHotkeyAlphaLastEpoch::::get(new_hotkey, netuid); TotalHotkeyAlphaLastEpoch::::insert( @@ -540,7 +540,7 @@ impl Pallet { ); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - // 16.2 Swap AlphaDividendsPerSubnet + // 8.2 Swap AlphaDividendsPerSubnet let old_hotkey_alpha_dividends = AlphaDividendsPerSubnet::::get(netuid, old_hotkey); let new_hotkey_alpha_dividends = AlphaDividendsPerSubnet::::get(netuid, new_hotkey); AlphaDividendsPerSubnet::::remove(netuid, old_hotkey); @@ -551,7 +551,7 @@ impl Pallet { ); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - // 16.3 Swap TaoDividendsPerSubnet + // 8.3 Swap TaoDividendsPerSubnet let old_hotkey_tao_dividends = TaoDividendsPerSubnet::::get(netuid, old_hotkey); let new_hotkey_tao_dividends = TaoDividendsPerSubnet::::get(netuid, new_hotkey); TaoDividendsPerSubnet::::remove(netuid, old_hotkey); @@ -562,7 +562,7 @@ impl Pallet { ); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - // 11. Swap Alpha + // 9. Swap Alpha // Alpha( hotkey, coldkey, netuid ) -> alpha let old_alpha_values: Vec<((T::AccountId, u16), U64F64)> = Alpha::::iter_prefix((old_hotkey,)).collect(); From c6ee5d61c0176cc4267ed0a92b3547858fa86d4a Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 8 May 2025 16:26:32 +0800 Subject: [PATCH 39/44] fix comments in PR --- pallets/admin-utils/src/tests/mock.rs | 2 +- pallets/subtensor/src/macros/config.rs | 2 +- pallets/subtensor/src/macros/hooks.rs | 23 +++++++++++++++++------ pallets/subtensor/src/swap/swap_hotkey.rs | 2 +- pallets/subtensor/src/tests/mock.rs | 2 +- runtime/src/lib.rs | 2 +- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 3e5afc3df4..916065081e 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -205,7 +205,7 @@ impl pallet_subtensor::Config for Test { type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; - type KeySwapOneSubnetCost = InitialKeySwapOnSubnetCost; + type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; } diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index a32862e988..32e10dde55 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -218,7 +218,7 @@ mod config { type DurationOfStartCall: Get; /// Cost of swapping a hotkey in a subnet. #[pallet::constant] - type KeySwapOneSubnetCost: Get; + type KeySwapOnSubnetCost: Get; /// Block number for a coldkey swap the hotkey in specific subnet. #[pallet::constant] type HotkeySwapOnSubnetInterval: Get; diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 48898b97b6..e7e1323a7d 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -14,7 +14,9 @@ mod hooks { // # Args: // * 'n': (BlockNumberFor): // - The number of the block we are initializing. - fn on_initialize(_block_number: BlockNumberFor) -> Weight { + fn on_initialize(block_number: BlockNumberFor) -> Weight { + let hotkey_swap_clean_up_weight = Self::clean_up_hotkey_swap_records(block_number); + let block_step_result = Self::block_step(); match block_step_result { Ok(_) => { @@ -23,6 +25,7 @@ mod hooks { Weight::from_parts(110_634_229_000_u64, 0) .saturating_add(T::DbWeight::get().reads(8304_u64)) .saturating_add(T::DbWeight::get().writes(110_u64)) + .saturating_add(hotkey_swap_clean_up_weight) } Err(e) => { // --- If the block step was unsuccessful, return the weight anyway. @@ -30,6 +33,7 @@ mod hooks { Weight::from_parts(110_634_229_000_u64, 0) .saturating_add(T::DbWeight::get().reads(8304_u64)) .saturating_add(T::DbWeight::get().writes(110_u64)) + .saturating_add(hotkey_swap_clean_up_weight) } } } @@ -41,7 +45,6 @@ mod hooks { // - The number of the block we are finalizing. fn on_finalize(block_number: BlockNumberFor) { Self::do_on_finalize(block_number); - Self::clean_up_hotkey_swap_records(block_number); } fn on_runtime_upgrade() -> frame_support::weights::Weight { @@ -132,26 +135,34 @@ mod hooks { impl Pallet { // This function is to clean up the old hotkey swap records // It just clean up for one subnet at a time, according to the block number - fn clean_up_hotkey_swap_records(block_number: BlockNumberFor) { + fn clean_up_hotkey_swap_records(block_number: BlockNumberFor) -> Weight { + let mut weight = Weight::from_parts(0, 0); let hotkey_swap_on_subnet_interval = T::HotkeySwapOnSubnetInterval::get(); let block_number: u64 = TryInto::try_into(block_number) .ok() .expect("blockchain will not exceed 2^64 blocks; QED."); let netuids = Self::get_all_subnet_netuids(); + weight.saturating_accrue(T::DbWeight::get().reads(2_u64 + netuids.len() as u64)); + if let Some(slot) = block_number.checked_rem(hotkey_swap_on_subnet_interval) { - if slot < (u16::MAX as u64) && netuids.contains(&(slot as u16)) { + for netuid in netuids.iter().filter(|netuid| { + (**netuid as u64).checked_rem(hotkey_swap_on_subnet_interval) == Some(slot) + }) { for (coldkey, swap_block_number) in - LastHotkeySwapOnNetuid::::iter_prefix(slot as u16) + LastHotkeySwapOnNetuid::::iter_prefix(netuid) { if swap_block_number.saturating_add(hotkey_swap_on_subnet_interval) < block_number { - LastHotkeySwapOnNetuid::::remove(slot as u16, coldkey); + LastHotkeySwapOnNetuid::::remove(netuid, coldkey); + weight.saturating_accrue(T::DbWeight::get().writes(1_u64)); } + weight.saturating_accrue(T::DbWeight::get().reads(1_u64)); } } } + weight } } } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index f9b5cb9ebc..733535c2ad 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -285,7 +285,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); // 3. Get the cost for swapping the key on the subnet - let swap_cost = T::KeySwapOneSubnetCost::get(); + let swap_cost = T::KeySwapOnSubnetCost::get(); log::debug!("Swap cost in subnet {:?}: {:?}", netuid, swap_cost); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 8fe386aa1a..4bd22f85c1 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -415,7 +415,7 @@ impl crate::Config for Test { type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; - type KeySwapOneSubnetCost = InitialKeySwapOnSubnetCost; + type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 987deb9cab..20a9e73ea9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1148,7 +1148,7 @@ impl pallet_subtensor::Config for Runtime { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; type DurationOfStartCall = DurationOfStartCall; - type KeySwapOneSubnetCost = SubtensorInitialKeySwapOnSubnetCost; + type KeySwapOnSubnetCost = SubtensorInitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; } From 70b1ec07e447c1a68cd1f22df8efc01076d5509b Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 8 May 2025 16:41:13 +0800 Subject: [PATCH 40/44] fix clippy --- pallets/subtensor/src/macros/hooks.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index e7e1323a7d..c09bf43d40 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -141,17 +141,21 @@ mod hooks { let block_number: u64 = TryInto::try_into(block_number) .ok() .expect("blockchain will not exceed 2^64 blocks; QED."); - let netuids = Self::get_all_subnet_netuids(); + weight.saturating_accrue(T::DbWeight::get().reads(2_u64)); - weight.saturating_accrue(T::DbWeight::get().reads(2_u64 + netuids.len() as u64)); + let netuids = Self::get_all_subnet_netuids(); + weight.saturating_accrue(T::DbWeight::get().reads(netuids.len() as u64)); if let Some(slot) = block_number.checked_rem(hotkey_swap_on_subnet_interval) { + // only handle the subnet with the same residue as current block number by HotkeySwapOnSubnetInterval for netuid in netuids.iter().filter(|netuid| { (**netuid as u64).checked_rem(hotkey_swap_on_subnet_interval) == Some(slot) }) { + // Iterate over all the coldkeys in the subnet for (coldkey, swap_block_number) in LastHotkeySwapOnNetuid::::iter_prefix(netuid) { + // Clean up out of date swap records if swap_block_number.saturating_add(hotkey_swap_on_subnet_interval) < block_number { From 896a1392961e58eb1a9057c02cd668c09b5f668d Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 13 May 2025 21:09:12 +0800 Subject: [PATCH 41/44] bump 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 d348b97fbc..9b644c3b8d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -209,7 +209,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: 267, + spec_version: 268, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 04d07f8c7d25faaf8be611d0843936d075c0115a Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 13 May 2025 21:24:02 +0800 Subject: [PATCH 42/44] bump runtime 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 9b644c3b8d..dfcbeedae7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -209,7 +209,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: 268, + spec_version: 269, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 0d18c16d67983137694c2bbf06cbc77947ca20c6 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 30 May 2025 21:07:07 +0800 Subject: [PATCH 43/44] remove duplicated doc --- pallets/subtensor/src/macros/errors.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index c634a98182..6e701014ae 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -212,7 +212,6 @@ mod errors { SubtokenDisabled, /// Too frequent hotkey swap on subnet HotKeySwapOnSubnetIntervalNotPassed, - /// Estimating the maximum stake for limited staking operations returned zero. /// Zero max stake amount ZeroMaxStakeAmount, /// Invalid netuid duplication From ff01f9e68ddac36f4deb89a66f5fc76829ad647c Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 4 Jun 2025 08:57:54 -0700 Subject: [PATCH 44/44] update weight values --- pallets/subtensor/src/macros/dispatches.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 59777e2399..434291c45d 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -937,9 +937,9 @@ mod dispatches { /// The extrinsic for user to change its hotkey in subnet or all subnets. #[pallet::call_index(70)] - #[pallet::weight((Weight::from_parts(240_600_000, 0) - .saturating_add(T::DbWeight::get().reads(31)) - .saturating_add(T::DbWeight::get().writes(23)), DispatchClass::Operational, Pays::No))] + #[pallet::weight((Weight::from_parts(285_900_000, 0) + .saturating_add(T::DbWeight::get().reads(47)) + .saturating_add(T::DbWeight::get().writes(37)), DispatchClass::Operational, Pays::No))] pub fn swap_hotkey( origin: OriginFor, hotkey: T::AccountId,