diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index f70b83f52d..0ab7f3081e 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1063,9 +1063,9 @@ mod dispatches { note = "Please use swap_hotkey_v2 instead. This extrinsic will be removed some time after June 2026." )] #[pallet::call_index(70)] - #[pallet::weight((Weight::from_parts(275_300_000, 0) - .saturating_add(T::DbWeight::get().reads(57_u64)) - .saturating_add(T::DbWeight::get().writes(39_u64)), DispatchClass::Normal, Pays::No))] + #[pallet::weight((Weight::from_parts(263_300_000, 0) + .saturating_add(T::DbWeight::get().reads(45_u64)) + .saturating_add(T::DbWeight::get().writes(31_u64)), DispatchClass::Normal, Pays::No))] pub fn swap_hotkey( origin: OriginFor, hotkey: T::AccountId, diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 1138ed1cde..aaf3f973c5 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -2,6 +2,7 @@ use super::*; use frame_support::weights::Weight; use share_pool::SafeFloat; use sp_core::Get; +use sp_std::collections::btree_set::BTreeSet; use substrate_fixed::types::U64F64; use subtensor_runtime_common::{MechId, NetUid, Token}; @@ -360,37 +361,6 @@ impl Pallet { netuid: NetUid, keep_stake: bool, ) -> DispatchResult { - if !keep_stake { - // 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::::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 ) -> share pool denominator for this hotkey on this subnet. - // Merge v1 and v2 TotalHotkeyShares because TotalHotkeyShares v1 is deprecated - weight.saturating_accrue(T::DbWeight::get().reads(4)); - let old_share_v1 = SafeFloat::from(TotalHotkeyShares::::take(old_hotkey, netuid)); - let old_share_v2 = TotalHotkeySharesV2::::take(old_hotkey, netuid); - let total_old_shares = old_share_v1.add(&old_share_v2).unwrap_or_default(); - - let new_share_v1 = SafeFloat::from(TotalHotkeyShares::::take(new_hotkey, netuid)); - let new_share_v2 = TotalHotkeySharesV2::::take(new_hotkey, netuid); - let total_new_shares = new_share_v1.add(&new_share_v2).unwrap_or_default(); - - TotalHotkeyShares::::remove(old_hotkey, netuid); - TotalHotkeyShares::::remove(new_hotkey, netuid); - - let total_old_plus_new_shares = - total_new_shares.add(&total_old_shares).unwrap_or_default(); - TotalHotkeySharesV2::::insert(new_hotkey, netuid, total_old_plus_new_shares); - weight.saturating_accrue(T::DbWeight::get().writes(3)); - } - // 3. Swap all subnet specific info. // 3.1 Remove the previous hotkey and insert the new hotkey from membership. @@ -549,7 +519,10 @@ impl Pallet { Self::swap_voting_power_for_hotkey(old_hotkey, new_hotkey, netuid); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - // 9. Swap Alpha + // Transfer root claimable + Self::transfer_root_claimable_for_new_hotkey(old_hotkey, new_hotkey); + + // Swap Alpha // Alpha( hotkey, coldkey, netuid ) -> alpha let old_alpha_values: Vec<((T::AccountId, NetUid), U64F64)> = Alpha::::iter_prefix((old_hotkey,)).collect(); @@ -561,63 +534,43 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values_v2.len() as u64)); weight.saturating_accrue(T::DbWeight::get().writes(old_alpha_values_v2.len() as u64)); - // 9.1. Transfer root claimable - Self::transfer_root_claimable_for_new_hotkey(old_hotkey, new_hotkey); - - // 9.2. Insert the new alpha values. - for ((coldkey, netuid_alpha), alpha) in old_alpha_values { - if netuid == netuid_alpha { - Self::transfer_root_claimed_for_new_keys( - netuid, old_hotkey, new_hotkey, &coldkey, &coldkey, - ); - - let new_alpha = Alpha::::take((new_hotkey, &coldkey, netuid)); - Alpha::::remove((old_hotkey, &coldkey, netuid)); - - // Insert into AlphaV2 because Alpha is deprecated - AlphaV2::::insert( - (new_hotkey, &coldkey, netuid), - SafeFloat::from(alpha.saturating_add(new_alpha)), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + // Insert the new alpha values. + // Deduplicate coldkeys staking to old_hotkey from alpha and alpha_v2 + let unique_coldkeys: BTreeSet = old_alpha_values + .into_iter() + .map(|((coldkey, netuid_alpha), _)| (coldkey, netuid_alpha)) + .chain( + old_alpha_values_v2 + .into_iter() + .map(|((coldkey, netuid_alpha), _)| (coldkey, netuid_alpha)), + ) + .filter(|(_, netuid_alpha)| *netuid_alpha == netuid) + .map(|(coldkey, _)| coldkey) + .collect(); + + // For each coldkey remove their stake from old_hotkey and add to new_hotkey + for coldkey in unique_coldkeys { + Self::transfer_root_claimed_for_new_keys( + netuid, old_hotkey, new_hotkey, &coldkey, &coldkey, + ); - // 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)); - } - } - } + let alpha_old = + Self::get_stake_for_hotkey_and_coldkey_on_subnet(old_hotkey, &coldkey, netuid); + Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( + old_hotkey, &coldkey, netuid, alpha_old, + ); + Self::increase_stake_for_hotkey_and_coldkey_on_subnet( + new_hotkey, &coldkey, netuid, alpha_old, + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - for ((coldkey, netuid_alpha), alpha) in old_alpha_values_v2 { - if netuid == netuid_alpha { - Self::transfer_root_claimed_for_new_keys( - netuid, old_hotkey, new_hotkey, &coldkey, &coldkey, - ); - - let new_alpha_v2 = AlphaV2::::take((new_hotkey, &coldkey, netuid)); - AlphaV2::::remove((old_hotkey, &coldkey, netuid)); - AlphaV2::::insert( - (new_hotkey, &coldkey, netuid), - alpha.add(&new_alpha_v2).unwrap_or_default(), - ); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + weight.saturating_accrue(T::DbWeight::get().reads(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)); - } + 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)); } } } diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index d0a1de3526..4c574ebba0 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -889,7 +889,7 @@ fn test_swap_stake_success() { 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 shares = U64F64::from_num(10_000); let mut weight = Weight::zero(); // Initialize staking variables for old_hotkey @@ -974,7 +974,7 @@ fn test_swap_stake_v2_success() { 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 shares = U64F64::from_num(10_000); let mut weight = Weight::zero(); // Initialize staking variables for old_hotkey @@ -1045,7 +1045,7 @@ fn test_swap_stake_v2_success() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey -- test_swap_stake_old_hotkey_not_exist --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_swap_stake_old_hotkey_not_exist --exact --nocapture #[test] fn test_swap_stake_old_hotkey_not_exist() { new_test_ext(1).execute_with(|| { @@ -1056,12 +1056,15 @@ fn test_swap_stake_old_hotkey_not_exist() { let subnet_owner_hotkey = U256::from(1002); let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + let alpha = AlphaBalance::from(1000); let alpha_share = U64F64::from_num(1234); let mut weight = Weight::zero(); let netuid = NetUid::from(1); // Initialize Stake for old_hotkey Alpha::::insert((old_hotkey, coldkey, netuid), alpha_share); + TotalHotkeyAlpha::::insert(old_hotkey, netuid, alpha); + TotalHotkeyShares::::insert(old_hotkey, netuid, alpha_share); // Ensure old_hotkey has a stake assert!(Alpha::::contains_key((old_hotkey, coldkey, netuid))); diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index eb310d1202..5214b1a5f2 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -946,7 +946,7 @@ fn test_swap_stake_success() { let netuid = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); let amount = 10_000; - let shares = U64F64::from_num(123456); + let shares = U64F64::from_num(10_000); // Initialize staking variables for old_hotkey TotalHotkeyAlpha::::insert(old_hotkey, netuid, AlphaBalance::from(amount)); @@ -1033,7 +1033,7 @@ fn test_swap_stake_v2_success() { let netuid = add_dynamic_network(&old_hotkey, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); let amount = 10_000; - let shares = U64F64::from_num(123456); + let shares = U64F64::from_num(10_000); // Initialize staking variables for old_hotkey TotalHotkeyAlpha::::insert(old_hotkey, netuid, AlphaBalance::from(amount)); @@ -2258,7 +2258,7 @@ fn test_revert_hotkey_swap_dividends() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); let amount = 10_000; - let shares = U64F64::from_num(123456); + let shares = U64F64::from_num(10_000); TotalHotkeyAlpha::::insert(hk1, netuid, AlphaBalance::from(amount)); TotalHotkeyAlphaLastEpoch::::insert(hk1, netuid, AlphaBalance::from(amount * 2)); @@ -2546,3 +2546,373 @@ fn test_revert_claim_root_with_swap_hotkey() { ); }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_swap_hotkey_with_existing_stake --exact --show-output +#[test] +fn test_swap_hotkey_with_existing_stake() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(4); + let staker1 = U256::from(5); + let staker2 = U256::from(6); + let subnet_owner_coldkey = U256::from(1000); + let subnet_owner_hotkey = U256::from(1001); + let staked_tao_1 = 100_000_000; + let staked_tao_2 = 200_000_000; + let staked_tao_3 = 300_000_000; + let staked_tao_4 = 500_000_000; + + // Set up initial state + let netuid = add_dynamic_network(&subnet_owner_coldkey, &subnet_owner_hotkey); + register_ok_neuron(netuid, old_hotkey, coldkey, 1234); + register_ok_neuron(netuid, new_hotkey, coldkey, 1234); + + // Add balance to coldkeys + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 10_000_000_000_u64.into()); + SubtensorModule::add_balance_to_coldkey_account(&staker1, 10_000_000_000_u64.into()); + SubtensorModule::add_balance_to_coldkey_account(&staker2, 10_000_000_000_u64.into()); + + // Stake with staker1 coldkey on old_hotkey + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(staker1), + old_hotkey, + netuid, + staked_tao_1.into() + )); + + // Stake with staker2 coldkey on old_hotkey + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(staker2), + old_hotkey, + netuid, + staked_tao_2.into() + )); + + // Stake with staker1 coldkey on new_hotkey + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(staker1), + new_hotkey, + netuid, + staked_tao_3.into() + )); + + // Stake with staker2 coldkey on new_hotkey + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(staker2), + new_hotkey, + netuid, + staked_tao_4.into() + )); + + // Emulate effect of emission into alpha pool - makes numerators and denominators not equal to alpha + let emission = AlphaBalance::from(1_000_000_000); + SubtensorModule::increase_stake_for_hotkey_on_subnet(&old_hotkey, netuid, emission); + SubtensorModule::increase_stake_for_hotkey_on_subnet(&new_hotkey, netuid, emission); + + // Hotkey new_hotkey gets deregistered, stake stays + IsNetworkMember::::remove(new_hotkey, netuid); + + let hk1_stake_1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &staker1, + netuid, + ); + let hk2_stake_1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &staker1, + netuid, + ); + let hk1_stake_2 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &staker2, + netuid, + ); + let hk2_stake_2 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &staker2, + netuid, + ); + + assert!(!hk1_stake_1.is_zero()); + assert!(!hk2_stake_1.is_zero()); + assert!(!hk1_stake_2.is_zero()); + assert!(!hk2_stake_2.is_zero()); + + let total_hk1_stake = SubtensorModule::get_total_stake_for_hotkey(&old_hotkey); + let total_hk2_stake = SubtensorModule::get_total_stake_for_hotkey(&new_hotkey); + assert!(!total_hk1_stake.is_zero()); + assert!(!total_hk2_stake.is_zero()); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid), + false + )); + + // Check correctness of stake transfer + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &staker1, + netuid + ), + 0.into() + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &old_hotkey, + &staker2, + netuid + ), + 0.into() + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &staker1, + netuid + ), + hk2_stake_1 + hk1_stake_1 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &staker2, + netuid + ), + hk2_stake_2 + hk1_stake_2 + ); + + // Check total stake transfer + assert_abs_diff_eq!( + SubtensorModule::get_total_stake_for_hotkey(&old_hotkey), + 0.into(), + epsilon = 1.into() + ); + assert_abs_diff_eq!( + SubtensorModule::get_total_stake_for_hotkey(&new_hotkey), + total_hk1_stake + total_hk2_stake, + epsilon = 1.into() + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_with_revert_stake_the_same --exact --nocapture +#[test] +fn test_revert_hotkey_swap_with_revert_stake_the_same() { + new_test_ext(1).execute_with(|| { + let netuid_1 = NetUid::from(1); + let netuid_2 = NetUid::from(2); + let tempo: u16 = 13; + let hk1 = U256::from(1); + let new_hotkey = U256::from(2); + let random_hotkey = U256::from(3); + let coldkey = U256::from(3); + let coldkey_2 = U256::from(4); + let coldkey_3 = U256::from(5); + let coldkey_4 = U256::from(6); + let random_coldkey = U256::from(7); + let initial_balance = 10_000_000_000u64 * 2; + let stake1 = 500_000_000u64; + let stake2 = 1_000_000_000u64; + let stake_ck2 = 1_500_000_000u64; + let stake_ck3 = 300_000_000u64; + let stake_ck4 = 900_000_000u64; + + assert_ok!(SubtensorModule::try_associate_hotkey( + <::RuntimeOrigin>::signed(random_coldkey), + random_hotkey + )); + + // Setup + super::mock::setup_reserves(netuid_1, (stake_ck4 * 100).into(), (stake_ck4 * 100).into()); + super::mock::setup_reserves(netuid_2, (stake_ck4 * 100).into(), (stake_ck4 * 100).into()); + + add_network(netuid_1, tempo, 0); + add_network(netuid_2, tempo, 0); + + SubnetMechanism::::insert(netuid_1, 1); + SubnetMechanism::::insert(netuid_2, 1); + + register_ok_neuron(netuid_1, hk1, coldkey, 0); + register_ok_neuron(netuid_2, hk1, coldkey, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_balance.into()); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_4, initial_balance.into()); + SubtensorModule::add_balance_to_coldkey_account(&random_coldkey, initial_balance.into()); + step_block(20); // Waiting interval to be able to swap later + + // Checking stake for hk1 on both networks + let hk1_stake_before_increase_sn_1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid_1); + assert!( + hk1_stake_before_increase_sn_1 == 0.into(), + "hk1 should have empty stake" + ); + + let hk1_stake_before_increase_sn_2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid_2); + assert!( + hk1_stake_before_increase_sn_2 == 0.into(), + "hk1 should have empty stake" + ); + + // Adding stake to hk1 on both networks + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + netuid_1, + stake1.into(), + ); + // Adding another stake for different coldkey + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey_2, + netuid_1, + stake_ck2.into(), + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey_3, + netuid_1, + stake_ck3.into(), + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + netuid_2, + stake2.into(), + ); + + // The stake for validator + let hk1_stake_before_swap_sn_1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid_1); + assert!( + hk1_stake_before_swap_sn_1 == stake1.into(), + "hk1 should have stake before swap on sn_1" + ); + + // Let's check individual stake + let hk1_stake_before_swap_sn_1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey_2, netuid_1); + assert_eq!( + hk1_stake_before_swap_sn_1, + (stake_ck2).into(), + "stake for ck2 should be only his stake" + ); + + let hk1_stake_before_swap_sn_2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid_2); + assert!( + hk1_stake_before_swap_sn_2 == stake2.into(), + "hk1 should have stake before swap on sn_2" + ); + + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &hk1, + &new_hotkey, + Some(netuid_1), + false + )); + + assert_eq!(Owner::::get(hk1), coldkey); + + SubtensorModule::do_add_stake( + RawOrigin::Signed(random_coldkey).into(), + hk1, + netuid_1, + stake_ck4.into(), + ) + .unwrap(); + + // Check stake moved to new hotkey on subnet1 + let new_hotkey_stake_after_swap_ck = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey, + netuid_1, + ); + assert_eq!(new_hotkey_stake_after_swap_ck, stake1.into()); + + // Check stake moved for ck2 + let new_hotkey_stake_after_swap_ck_1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey_2, + netuid_1, + ); + assert_eq!(new_hotkey_stake_after_swap_ck_1, stake_ck2.into()); + + // Check stake moved for ck3 + let new_hotkey_stake_after_swap_ck_3 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey_3, + netuid_1, + ); + assert_eq!(new_hotkey_stake_after_swap_ck_3, stake_ck3.into()); + + step_block(20); + + // Let's check individual stakes; they changed because of emissions + let new_hotkey_stake_before_revert_ck = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey, + netuid_1, + ); + assert!(new_hotkey_stake_before_revert_ck > stake1.into()); + + let new_hotkey_stake_before_revert_ck_2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey_2, + netuid_1, + ); + assert!(new_hotkey_stake_before_revert_ck_2 > stake_ck2.into()); + + let new_hotkey_stake_before_revert_ck_3 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &new_hotkey, + &coldkey_3, + netuid_1, + ); + assert!(new_hotkey_stake_before_revert_ck_3 > stake_ck3.into()); + + // Reverting back: hk2 -> hk1 + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey, + &hk1, + Some(netuid_1), + false + )); + + // Let's check individual stakes; they changed because of emissions + let old_hotkey_stake_after_revert_ck = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid_1); + assert_eq!( + old_hotkey_stake_after_revert_ck, + new_hotkey_stake_before_revert_ck + ); + + let old_hotkey_stake_after_revert_ck_2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey_2, netuid_1); + assert_eq!( + old_hotkey_stake_after_revert_ck_2, + new_hotkey_stake_before_revert_ck_2 + ); + + let old_hotkey_stake_after_revert_ck_3 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey_3, netuid_1); + assert_eq!( + old_hotkey_stake_after_revert_ck_3, + new_hotkey_stake_before_revert_ck_3 + ); + }); +}