From 651bf4cb82c446a938864f5ae2cae060eada06b6 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Wed, 4 Mar 2026 16:54:15 +0100 Subject: [PATCH 01/16] - Add a possibility to revert hotkey back after the swap --- pallets/subtensor/src/swap/swap_hotkey.rs | 12 ++++--- pallets/subtensor/src/tests/swap_hotkey.rs | 42 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index a54a02a750..8bc57bc783 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -57,11 +57,13 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads(2)); - // 7. Ensure the new hotkey is not already registered on any network - ensure!( - !Self::is_hotkey_registered_on_any_network(new_hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); + // 7. Ensure the new hotkey is not already registered on any network, only if netuid is none + if netuid.is_none() { + ensure!( + !Self::is_hotkey_registered_on_any_network(new_hotkey), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + } // 8. Swap LastTxBlock let last_tx_block: u64 = Self::get_last_tx_block(old_hotkey); diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 71191d1951..fea8f1b809 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -60,6 +60,48 @@ fn test_swap_owned_hotkeys() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --lib -- tests::swap_hotkey::test_revert_hotkey_swap --exact --nocapture +// This test confirms, that the old hotkey can be reverted after the hotkey swap +#[test] +fn test_revert_hotkey_swap() { + new_test_ext(1).execute_with(|| { + let netuid = NetUid::from(1); + let netuid2 = NetUid::from(2); + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64 * 2; + + // Setup initial state + add_network(netuid, tempo, 0); + add_network(netuid2, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + register_ok_neuron(netuid2, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + step_block(20); + + // Perform the first swap (only on netuid) + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + assert!(SubtensorModule::is_hotkey_registered_on_any_network(&old_hotkey)); + + step_block(20); + + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey, + &old_hotkey, + Some(netuid) + )); + }); +} + // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey -- test_swap_total_hotkey_stake --exact --nocapture #[test] fn test_swap_total_hotkey_stake() { From 6c16a187b11f05288a3749bb2202302ea209b478 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Wed, 4 Mar 2026 17:35:29 +0100 Subject: [PATCH 02/16] - Updated HotkeySwapOnSubnetInterval to 1 day. --- 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 c5fd050fab..ee7272498a 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1109,7 +1109,7 @@ parameter_types! { // 0 days pub const InitialStartCallDelay: u64 = 0; pub const SubtensorInitialKeySwapOnSubnetCost: u64 = 1_000_000; // 0.001 TAO - pub const HotkeySwapOnSubnetInterval : BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days + pub const HotkeySwapOnSubnetInterval : BlockNumber = 1 * 24 * 60 * 60 / 12; // 1 day pub const LeaseDividendsDistributionInterval: BlockNumber = 100; // 100 blocks pub const MaxImmuneUidsPercentage: Percent = Percent::from_percent(80); pub const EvmKeyAssociateRateLimit: u64 = EVM_KEY_ASSOCIATE_RATELIMIT; From 250a881bbe2467246334fc6a58f8ec6e46ee9fcd Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Wed, 4 Mar 2026 18:13:37 +0100 Subject: [PATCH 03/16] - Added test `test_revert_hotkey_swap_stake_is_not_lost` + removed test: `test_swap_hotkey_registered_on_other_subnet` --- pallets/subtensor/src/tests/swap_hotkey.rs | 77 ++++++++++++++++++- .../src/tests/swap_hotkey_with_subnet.rs | 35 +-------- 2 files changed, 77 insertions(+), 35 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index fea8f1b809..26a1ce137f 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -60,7 +60,82 @@ fn test_swap_owned_hotkeys() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --lib -- tests::swap_hotkey::test_revert_hotkey_swap --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap_stake_is_not_lost --exact --nocapture +#[test] +fn test_revert_hotkey_swap_stake_is_not_lost() { + new_test_ext(1).execute_with(|| { + let netuid = NetUid::from(1); + let netuid2 = NetUid::from(2); + let tempo: u16 = 13; + let hk1 = U256::from(1); + let hk2 = U256::from(2); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64 * 2; + + // Setup + add_network(netuid, tempo, 0); + add_network(netuid2, tempo, 0); + register_ok_neuron(netuid, hk1, coldkey, 0); + register_ok_neuron(netuid2, hk1, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + + let hk1_stake_before_increase = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + assert!(hk1_stake_before_increase == 0.into(), "hk1 should have empty stake"); + + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + netuid, + 1_000_000_000u64.into(), + ); + + let hk1_stake_before_swap = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + assert!(hk1_stake_before_swap == 1_000_000_000.into(), "hk1 should have stake before swap"); + + step_block(20); + + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); + + step_block(20); + + let hk2_stake_before_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk2, &coldkey, netuid); + let hk1_stake_before_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + + assert_eq!(hk1_stake_before_revert, 0.into()); + + // Revert: hk2 -> hk1 + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + let hk1_stake_after_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + let hk2_stake_after_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk2, &coldkey, netuid); + + assert_eq!( + hk1_stake_after_revert, + hk2_stake_before_revert, + ); + + // hk2 should be empty + assert_eq!(hk2_stake_after_revert, 0.into(), "hk2 should have no stake after revert"); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap --exact --nocapture // This test confirms, that the old hotkey can be reverted after the hotkey swap #[test] fn test_revert_hotkey_swap() { diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 6e423c1269..14c29dd7d3 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1553,37 +1553,4 @@ fn test_swap_owner_check_swap_record_clean_up() { netuid, 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_registered_on_other_subnet() { - 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); - let netuid = add_dynamic_network(&old_hotkey, &coldkey); - let other_netuid = add_dynamic_network(&old_hotkey, &coldkey); - - // Set up initial state - Owner::::insert(old_hotkey, coldkey); - TotalNetworks::::put(1); - - let initial_balance = SubtensorModule::get_key_swap_cost().to_u64() + 1000; - SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_balance); - - // Test new hotkey already registered on other subnet - IsNetworkMember::::insert(new_hotkey, other_netuid, true); - System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); - assert_noop!( - SubtensorModule::do_swap_hotkey( - RuntimeOrigin::signed(coldkey), - &old_hotkey, - &new_hotkey, - Some(netuid) - ), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - }); -} +} \ No newline at end of file From ccde975cd44906cd85331a968c97cd212acb01ce Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Wed, 4 Mar 2026 19:05:50 +0100 Subject: [PATCH 04/16] - Added stake to hk1 after swap --- pallets/subtensor/src/tests/swap_hotkey.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 26a1ce137f..9fdf866976 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -71,6 +71,7 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { let hk2 = U256::from(2); let coldkey = U256::from(3); let swap_cost = 1_000_000_000u64 * 2; + let stake2 = 1_000_000_000u64; // Setup add_network(netuid, tempo, 0); @@ -103,6 +104,13 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { Some(netuid) )); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + netuid, + stake2.into(), + ); + step_block(20); let hk2_stake_before_revert = @@ -110,7 +118,7 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { let hk1_stake_before_revert = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - assert_eq!(hk1_stake_before_revert, 0.into()); + assert_eq!(hk1_stake_before_revert, stake2.into()); // Revert: hk2 -> hk1 assert_ok!(SubtensorModule::do_swap_hotkey( @@ -127,7 +135,7 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { assert_eq!( hk1_stake_after_revert, - hk2_stake_before_revert, + hk2_stake_before_revert + stake2.into(), ); // hk2 should be empty From 8e63fa0a4170de52b8216be36508108a0d3bd1cc Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Wed, 4 Mar 2026 19:14:16 +0100 Subject: [PATCH 05/16] - Moved tests to the correct file --- pallets/subtensor/src/tests/swap_hotkey.rs | 125 ----------------- .../src/tests/swap_hotkey_with_subnet.rs | 127 +++++++++++++++++- 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs index 9fdf866976..71191d1951 100644 --- a/pallets/subtensor/src/tests/swap_hotkey.rs +++ b/pallets/subtensor/src/tests/swap_hotkey.rs @@ -60,131 +60,6 @@ fn test_swap_owned_hotkeys() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap_stake_is_not_lost --exact --nocapture -#[test] -fn test_revert_hotkey_swap_stake_is_not_lost() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let netuid2 = NetUid::from(2); - let tempo: u16 = 13; - let hk1 = U256::from(1); - let hk2 = U256::from(2); - let coldkey = U256::from(3); - let swap_cost = 1_000_000_000u64 * 2; - let stake2 = 1_000_000_000u64; - - // Setup - add_network(netuid, tempo, 0); - add_network(netuid2, tempo, 0); - register_ok_neuron(netuid, hk1, coldkey, 0); - register_ok_neuron(netuid2, hk1, coldkey, 0); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); - - let hk1_stake_before_increase = - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - assert!(hk1_stake_before_increase == 0.into(), "hk1 should have empty stake"); - - SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( - &hk1, - &coldkey, - netuid, - 1_000_000_000u64.into(), - ); - - let hk1_stake_before_swap = - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - assert!(hk1_stake_before_swap == 1_000_000_000.into(), "hk1 should have stake before swap"); - - step_block(20); - - assert_ok!(SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey), - &hk1, - &hk2, - Some(netuid) - )); - - SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( - &hk1, - &coldkey, - netuid, - stake2.into(), - ); - - step_block(20); - - let hk2_stake_before_revert = - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk2, &coldkey, netuid); - let hk1_stake_before_revert = - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - - assert_eq!(hk1_stake_before_revert, stake2.into()); - - // Revert: hk2 -> hk1 - assert_ok!(SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey), - &hk2, - &hk1, - Some(netuid) - )); - - let hk1_stake_after_revert = - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - let hk2_stake_after_revert = - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk2, &coldkey, netuid); - - assert_eq!( - hk1_stake_after_revert, - hk2_stake_before_revert + stake2.into(), - ); - - // hk2 should be empty - assert_eq!(hk2_stake_after_revert, 0.into(), "hk2 should have no stake after revert"); - }); -} - -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap --exact --nocapture -// This test confirms, that the old hotkey can be reverted after the hotkey swap -#[test] -fn test_revert_hotkey_swap() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let netuid2 = NetUid::from(2); - let tempo: u16 = 13; - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let coldkey = U256::from(3); - let swap_cost = 1_000_000_000u64 * 2; - - // Setup initial state - add_network(netuid, tempo, 0); - add_network(netuid2, tempo, 0); - register_ok_neuron(netuid, old_hotkey, coldkey, 0); - register_ok_neuron(netuid2, old_hotkey, coldkey, 0); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); - step_block(20); - - // Perform the first swap (only on netuid) - assert_ok!(SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey), - &old_hotkey, - &new_hotkey, - Some(netuid) - )); - - assert!(SubtensorModule::is_hotkey_registered_on_any_network(&old_hotkey)); - - step_block(20); - - assert_ok!(SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey), - &new_hotkey, - &old_hotkey, - Some(netuid) - )); - }); -} - // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey -- test_swap_total_hotkey_stake --exact --nocapture #[test] fn test_swap_total_hotkey_stake() { diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 14c29dd7d3..c5b9037e55 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1553,4 +1553,129 @@ fn test_swap_owner_check_swap_record_clean_up() { netuid, coldkey )); }); -} \ No newline at end of file +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap_stake_is_not_lost --exact --nocapture +#[test] +fn test_revert_hotkey_swap_stake_is_not_lost() { + new_test_ext(1).execute_with(|| { + let netuid = NetUid::from(1); + let netuid2 = NetUid::from(2); + let tempo: u16 = 13; + let hk1 = U256::from(1); + let hk2 = U256::from(2); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64 * 2; + let stake2 = 1_000_000_000u64; + + // Setup + add_network(netuid, tempo, 0); + add_network(netuid2, tempo, 0); + register_ok_neuron(netuid, hk1, coldkey, 0); + register_ok_neuron(netuid2, hk1, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + + let hk1_stake_before_increase = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + assert!(hk1_stake_before_increase == 0.into(), "hk1 should have empty stake"); + + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + netuid, + 1_000_000_000u64.into(), + ); + + let hk1_stake_before_swap = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + assert!(hk1_stake_before_swap == 1_000_000_000.into(), "hk1 should have stake before swap"); + + step_block(20); + + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); + + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + netuid, + stake2.into(), + ); + + step_block(20); + + let hk2_stake_before_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk2, &coldkey, netuid); + let hk1_stake_before_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + + assert_eq!(hk1_stake_before_revert, stake2.into()); + + // Revert: hk2 -> hk1 + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + let hk1_stake_after_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); + let hk2_stake_after_revert = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk2, &coldkey, netuid); + + assert_eq!( + hk1_stake_after_revert, + hk2_stake_before_revert + stake2.into(), + ); + + // hk2 should be empty + assert_eq!(hk2_stake_after_revert, 0.into(), "hk2 should have no stake after revert"); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap --exact --nocapture +// This test confirms, that the old hotkey can be reverted after the hotkey swap +#[test] +fn test_revert_hotkey_swap() { + new_test_ext(1).execute_with(|| { + let netuid = NetUid::from(1); + let netuid2 = NetUid::from(2); + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64 * 2; + + // Setup initial state + add_network(netuid, tempo, 0); + add_network(netuid2, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + register_ok_neuron(netuid2, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + step_block(20); + + // Perform the first swap (only on netuid) + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &old_hotkey, + &new_hotkey, + Some(netuid) + )); + + assert!(SubtensorModule::is_hotkey_registered_on_any_network(&old_hotkey)); + + step_block(20); + + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey, + &old_hotkey, + Some(netuid) + )); + }); +} From d29c9e6783c6701325efc0411ca318759a94e2ec Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Wed, 4 Mar 2026 19:27:25 +0100 Subject: [PATCH 06/16] - Added test to check revert hotkey for parent keys and child keys --- .../src/tests/swap_hotkey_with_subnet.rs | 71 ++++++++++++++++++- 1 file changed, 69 insertions(+), 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 c5b9037e55..2c1fe21d50 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1555,7 +1555,7 @@ fn test_swap_owner_check_swap_record_clean_up() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap_stake_is_not_lost --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_stake_is_not_lost --exact --nocapture #[test] fn test_revert_hotkey_swap_stake_is_not_lost() { new_test_ext(1).execute_with(|| { @@ -1638,7 +1638,7 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey::test_revert_hotkey_swap --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap --exact --nocapture // This test confirms, that the old hotkey can be reverted after the hotkey swap #[test] fn test_revert_hotkey_swap() { @@ -1679,3 +1679,70 @@ fn test_revert_hotkey_swap() { )); }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_parent_child_keys --exact --nocapture +#[test] +fn test_revert_hotkey_swap_parent_child_keys() { + new_test_ext(1).execute_with(|| { + let hk1 = U256::from(1); + let hk2 = U256::from(2); + let coldkey = U256::from(3); + let parent1 = U256::from(4); + let parent2 = U256::from(5); + let netuid = add_dynamic_network(&hk1, &coldkey); + let netuid2 = add_dynamic_network(&hk2, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + let parents = vec![(100u64, parent1), (200u64, parent2)]; + + ParentKeys::::insert(hk1, netuid, parents.clone()); + + ChildKeys::::insert(parent1, netuid, vec![(100u64, hk1)]); + ChildKeys::::insert(parent2, netuid, vec![(200u64, hk1)]); + + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); + + // Verify ParentKeys swap + assert_eq!(ParentKeys::::get(hk2, netuid), parents); + assert!(ParentKeys::::get(hk1, netuid).is_empty()); + + // Verify ChildKeys update for parents + assert_eq!(ChildKeys::::get(parent1, netuid), vec![(100u64, hk2)]); + assert_eq!(ChildKeys::::get(parent2, netuid), vec![(200u64, hk2)]); + + step_block(20); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + assert_eq!( + ParentKeys::::get(hk1, netuid), + parents, + "ParentKeys must be restored to hk1 after revert" + ); + assert!( + ParentKeys::::get(hk2, netuid).is_empty(), + "hk2 must have no ParentKeys after revert" + ); + + assert_eq!( + ChildKeys::::get(parent1, netuid), + vec![(100u64, hk1)], + "parent1 ChildKeys must point back to hk1 after revert" + ); + assert_eq!( + ChildKeys::::get(parent2, netuid), + vec![(200u64, hk1)], + "parent2 ChildKeys must point back to hk1 after revert" + ); + }); +} \ No newline at end of file From 72ef608fff8eac852a3971a80cc10f79615a8aa0 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 12:24:35 +0100 Subject: [PATCH 07/16] - tests for: ParentKeys + Uid + AutoStakeDestination + SubnetOwnership --- .../src/tests/swap_hotkey_with_subnet.rs | 253 ++++++++++++++++-- 1 file changed, 226 insertions(+), 27 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 2c1fe21d50..81150e5dc7 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1680,25 +1680,173 @@ fn test_revert_hotkey_swap() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_parent_child_keys --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_parent_hotkey_childkey_maps --exact --nocapture #[test] -fn test_revert_hotkey_swap_parent_child_keys() { +fn test_revert_hotkey_swap_parent_hotkey_childkey_maps() { new_test_ext(1).execute_with(|| { + let hk1 = U256::from(1); + let coldkey = U256::from(2); + let child = U256::from(3); + let child_other = U256::from(4); + let hk2 = U256::from(5); + + let netuid = add_dynamic_network(&hk1, &coldkey); + let netuid2 = add_dynamic_network(&hk1, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::create_account_if_non_existent(&coldkey, &hk1); + + mock_set_children(&coldkey, &hk1, netuid, &[(u64::MAX, child)]); + step_rate_limit(&TransactionType::SetChildren, netuid); + mock_schedule_children(&coldkey, &hk1, netuid, &[(u64::MAX, child_other)]); + + assert_eq!( + ParentKeys::::get(child, netuid), + vec![(u64::MAX, hk1)] + ); + assert_eq!( + ChildKeys::::get(hk1, netuid), + vec![(u64::MAX, child)] + ); + let existing_pending_child_keys = PendingChildKeys::::get(netuid, hk1); + assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_other)]); + + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); + + assert_eq!( + ParentKeys::::get(child, netuid), + vec![(u64::MAX, hk2)] + ); + assert_eq!( + ChildKeys::::get(hk2, netuid), + vec![(u64::MAX, child)] + ); + assert_eq!( + PendingChildKeys::::get(netuid, hk2), + existing_pending_child_keys + ); + assert!(ChildKeys::::get(hk1, netuid).is_empty()); + assert!(PendingChildKeys::::get(netuid, hk1).0.is_empty()); + + // Revert: hk2 -> hk1 + step_block(20); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + assert_eq!( + ParentKeys::::get(child, netuid), + vec![(u64::MAX, hk1)], + "ParentKeys must point back to hk1 after revert" + ); + assert_eq!( + ChildKeys::::get(hk1, netuid), + vec![(u64::MAX, child)], + "ChildKeys must be restored to hk1 after revert" + ); + assert_eq!( + PendingChildKeys::::get(netuid, hk1), + existing_pending_child_keys, + "PendingChildKeys must be restored to hk1 after revert" + ); + + assert!( + ChildKeys::::get(hk2, netuid).is_empty(), + "hk2 must have no ChildKeys after revert" + ); + assert!( + PendingChildKeys::::get(netuid, hk2).0.is_empty(), + "hk2 must have no PendingChildKeys after revert" + ); + }) +} +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_uids_and_keys --exact --nocapture +#[test] +fn test_revert_hotkey_swap_uids_and_keys() { + new_test_ext(1).execute_with(|| { + let uid = 5u16; let hk1 = U256::from(1); let hk2 = U256::from(2); let coldkey = U256::from(3); - let parent1 = U256::from(4); - let parent2 = U256::from(5); + let netuid = add_dynamic_network(&hk1, &coldkey); - let netuid2 = add_dynamic_network(&hk2, &coldkey); + let netuid2 = add_dynamic_network(&hk1, &coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); - let parents = vec![(100u64, parent1), (200u64, parent2)]; + IsNetworkMember::::insert(hk1, netuid, true); + Uids::::insert(netuid, hk1, uid); + Keys::::insert(netuid, uid, hk1); - ParentKeys::::insert(hk1, netuid, parents.clone()); + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); - ChildKeys::::insert(parent1, netuid, vec![(100u64, hk1)]); - ChildKeys::::insert(parent2, netuid, vec![(200u64, hk1)]); + assert_eq!(Uids::::get(netuid, hk1), None); + assert_eq!(Uids::::get(netuid, hk2), Some(uid)); + assert_eq!(Keys::::get(netuid, uid), hk2); + + // Revert: hk2 -> hk1 + step_block(20); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + assert_eq!( + Uids::::get(netuid, hk2), + None, + "hk2 must have no uid after revert" + ); + assert_eq!( + Uids::::get(netuid, hk1), + Some(uid), + "hk1 must have its uid restored after revert" + ); + assert_eq!( + Keys::::get(netuid, uid), + hk1, + "Keys must point back to hk1 after revert" + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_auto_stake_destination --exact --nocapture +#[test] +fn test_revert_hotkey_swap_auto_stake_destination() { + new_test_ext(1).execute_with(|| { + let hk1 = U256::from(1); + let hk2 = U256::from(2); + let coldkey = U256::from(3); + let netuid = NetUid::from(2u16); + let netuid2 = NetUid::from(3u16); + let staker1 = U256::from(4); + let staker2 = U256::from(5); + let coldkeys = vec![staker1, staker2, coldkey]; + + add_network(netuid, 1, 0); + add_network(netuid2, 1, 0); + register_ok_neuron(netuid, hk1, coldkey, 0); + register_ok_neuron(netuid2, hk1, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + AutoStakeDestinationColdkeys::::insert(hk1, netuid, coldkeys.clone()); + AutoStakeDestination::::insert(coldkey, netuid, hk1); + AutoStakeDestination::::insert(staker1, netuid, hk1); + AutoStakeDestination::::insert(staker2, netuid, hk1); System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( @@ -1708,14 +1856,16 @@ fn test_revert_hotkey_swap_parent_child_keys() { Some(netuid) )); - // Verify ParentKeys swap - assert_eq!(ParentKeys::::get(hk2, netuid), parents); - assert!(ParentKeys::::get(hk1, netuid).is_empty()); - - // Verify ChildKeys update for parents - assert_eq!(ChildKeys::::get(parent1, netuid), vec![(100u64, hk2)]); - assert_eq!(ChildKeys::::get(parent2, netuid), vec![(200u64, hk2)]); + assert_eq!( + AutoStakeDestinationColdkeys::::get(hk2, netuid), + coldkeys + ); + assert!(AutoStakeDestinationColdkeys::::get(hk1, netuid).is_empty()); + assert_eq!(AutoStakeDestination::::get(coldkey, netuid), Some(hk2)); + assert_eq!(AutoStakeDestination::::get(staker1, netuid), Some(hk2)); + assert_eq!(AutoStakeDestination::::get(staker2, netuid), Some(hk2)); + // Revert: hk2 -> hk1 step_block(20); assert_ok!(SubtensorModule::do_swap_hotkey( RuntimeOrigin::signed(coldkey), @@ -1725,24 +1875,73 @@ fn test_revert_hotkey_swap_parent_child_keys() { )); assert_eq!( - ParentKeys::::get(hk1, netuid), - parents, - "ParentKeys must be restored to hk1 after revert" + AutoStakeDestinationColdkeys::::get(hk1, netuid), + coldkeys, + "AutoStakeDestinationColdkeys must be restored to hk1 after revert" ); assert!( - ParentKeys::::get(hk2, netuid).is_empty(), - "hk2 must have no ParentKeys after revert" + AutoStakeDestinationColdkeys::::get(hk2, netuid).is_empty(), + "hk2 must have no AutoStakeDestinationColdkeys after revert" + ); + assert_eq!( + AutoStakeDestination::::get(coldkey, netuid), + Some(hk1), + "coldkey AutoStakeDestination must point back to hk1 after revert" + ); + assert_eq!( + AutoStakeDestination::::get(staker1, netuid), + Some(hk1), + "staker1 AutoStakeDestination must point back to hk1 after revert" + ); + assert_eq!( + AutoStakeDestination::::get(staker2, netuid), + Some(hk1), + "staker2 AutoStakeDestination must point back to hk1 after revert" ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_subnet_owner --exact --nocapture +#[test] +fn test_revert_hotkey_swap_subnet_owner() { + new_test_ext(1).execute_with(|| { + let hk1 = U256::from(1); + let hk2 = U256::from(2); + let coldkey = U256::from(3); + + let netuid = add_dynamic_network(&hk1, &coldkey); + let netuid2 = add_dynamic_network(&hk1, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + assert_eq!(SubnetOwnerHotkey::::get(netuid), hk1); + + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); assert_eq!( - ChildKeys::::get(parent1, netuid), - vec![(100u64, hk1)], - "parent1 ChildKeys must point back to hk1 after revert" + SubnetOwnerHotkey::::get(netuid), + hk2, + "hk2 must be subnet owner after swap" ); + + // Revert: hk2 -> hk1 + step_block(20); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + assert_eq!( - ChildKeys::::get(parent2, netuid), - vec![(200u64, hk1)], - "parent2 ChildKeys must point back to hk1 after revert" + SubnetOwnerHotkey::::get(netuid), + hk1, + "hk1 must be restored as subnet owner after revert" ); }); } \ No newline at end of file From 7bd2ca1889cf71ee92a87a21c5b89f29db87eb19 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 12:36:21 +0100 Subject: [PATCH 08/16] - tests for: Dividends --- .../src/tests/swap_hotkey_with_subnet.rs | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 81150e5dc7..5036659dbc 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1944,4 +1944,106 @@ fn test_revert_hotkey_swap_subnet_owner() { "hk1 must be restored as subnet owner after revert" ); }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_hotkey_swap_dividends --exact --nocapture +#[test] +fn test_revert_hotkey_swap_dividends() { + new_test_ext(1).execute_with(|| { + let hk1 = U256::from(1); + let hk2 = U256::from(2); + let coldkey = U256::from(3); + + let netuid = add_dynamic_network(&hk1, &coldkey); + let netuid2 = add_dynamic_network(&hk1, &coldkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + + let amount = 10_000; + let shares = U64F64::from_num(123456); + + TotalHotkeyAlpha::::insert(hk1, netuid, AlphaCurrency::from(amount)); + TotalHotkeyAlphaLastEpoch::::insert(hk1, netuid, AlphaCurrency::from(amount * 2)); + TotalHotkeyShares::::insert(hk1, netuid, U64F64::from_num(shares)); + Alpha::::insert((hk1, coldkey, netuid), U64F64::from_num(amount)); + AlphaDividendsPerSubnet::::insert(netuid, hk1, AlphaCurrency::from(amount)); + + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk1, + &hk2, + Some(netuid) + )); + + assert_eq!(TotalHotkeyAlpha::::get(hk1, netuid), AlphaCurrency::ZERO); + assert_eq!(TotalHotkeyAlpha::::get(hk2, netuid), AlphaCurrency::from(amount)); + assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), AlphaCurrency::ZERO); + assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), AlphaCurrency::from(amount * 2)); + assert_eq!(TotalHotkeyShares::::get(hk1, netuid), U64F64::from_num(0)); + assert_eq!(TotalHotkeyShares::::get(hk2, netuid), U64F64::from_num(shares)); + assert_eq!(Alpha::::get((hk1, coldkey, netuid)), U64F64::from_num(0)); + assert_eq!(Alpha::::get((hk2, coldkey, netuid)), U64F64::from_num(amount)); + assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk1), AlphaCurrency::ZERO); + assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk2), AlphaCurrency::from(amount)); + + // Revert: hk2 -> hk1 + step_block(20); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + assert_eq!( + TotalHotkeyAlpha::::get(hk2, netuid), + AlphaCurrency::ZERO, + "hk2 TotalHotkeyAlpha must be zero after revert" + ); + assert_eq!( + TotalHotkeyAlpha::::get(hk1, netuid), + AlphaCurrency::from(amount), + "hk1 TotalHotkeyAlpha must be restored after revert" + ); + assert_eq!( + TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), + AlphaCurrency::ZERO, + "hk2 TotalHotkeyAlphaLastEpoch must be zero after revert" + ); + assert_eq!( + TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), + AlphaCurrency::from(amount * 2), + "hk1 TotalHotkeyAlphaLastEpoch must be restored after revert" + ); + assert_eq!( + TotalHotkeyShares::::get(hk2, netuid), + U64F64::from_num(0), + "hk2 TotalHotkeyShares must be zero after revert" + ); + assert_eq!( + TotalHotkeyShares::::get(hk1, netuid), + U64F64::from_num(shares), + "hk1 TotalHotkeyShares must be restored after revert" + ); + assert_eq!( + Alpha::::get((hk2, coldkey, netuid)), + U64F64::from_num(0), + "hk2 Alpha must be zero after revert" + ); + assert_eq!( + Alpha::::get((hk1, coldkey, netuid)), + U64F64::from_num(amount), + "hk1 Alpha must be restored after revert" + ); + assert_eq!( + AlphaDividendsPerSubnet::::get(netuid, hk2), + AlphaCurrency::ZERO, + "hk2 AlphaDividendsPerSubnet must be zero after revert" + ); + assert_eq!( + AlphaDividendsPerSubnet::::get(netuid, hk1), + AlphaCurrency::from(amount), + "hk1 AlphaDividendsPerSubnet must be restored after revert" + ); + }); } \ No newline at end of file From df3f2e8b98cd65b1e0971a394dd13b5b37e6cd6b Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 12:50:18 +0100 Subject: [PATCH 09/16] - tests for: VotingPower --- .../src/tests/swap_hotkey_with_subnet.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 5036659dbc..0de65866d9 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -2046,4 +2046,39 @@ fn test_revert_hotkey_swap_dividends() { "hk1 AlphaDividendsPerSubnet must be restored after revert" ); }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_voting_power_transfers_on_hotkey_swap --exact --nocapture +#[test] +fn test_revert_voting_power_transfers_on_hotkey_swap() { + new_test_ext(1).execute_with(|| { + let hk1 = U256::from(1); + let hk2 = U256::from(99); + let coldkey = U256::from(2); + let netuid = add_dynamic_network(&hk1, &coldkey); + let voting_power_value = 5_000_000_000_000_u64; + + VotingPower::::insert(netuid, hk1, voting_power_value); + assert_eq!(SubtensorModule::get_voting_power(netuid, &hk1), voting_power_value); + assert_eq!(SubtensorModule::get_voting_power(netuid, &hk2), 0); + + SubtensorModule::swap_voting_power_for_hotkey(&hk1, &hk2, netuid); + + assert_eq!(SubtensorModule::get_voting_power(netuid, &hk1), 0); + assert_eq!(SubtensorModule::get_voting_power(netuid, &hk2), voting_power_value); + + // Revert: hk2 -> hk1 + SubtensorModule::swap_voting_power_for_hotkey(&hk2, &hk1, netuid); + + assert_eq!( + SubtensorModule::get_voting_power(netuid, &hk1), + voting_power_value, + "hk1 voting power must be fully restored after revert" + ); + assert_eq!( + SubtensorModule::get_voting_power(netuid, &hk2), + 0, + "hk2 must have no voting power after revert" + ); + }); } \ No newline at end of file From 4be737a6ff4c3804520a116751ff2407d902d220 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 13:07:32 +0100 Subject: [PATCH 10/16] - tests for: RootClaimed + RootClaimable --- .../src/tests/swap_hotkey_with_subnet.rs | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 0de65866d9..9c5b7d3eeb 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -11,7 +11,9 @@ use super::mock::*; use crate::*; use sp_core::{Get, H160, H256, U256}; use sp_runtime::SaturatedConversion; +use std::collections::BTreeSet; 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() { @@ -2081,4 +2083,123 @@ fn test_revert_voting_power_transfers_on_hotkey_swap() { "hk2 must have no voting power after revert" ); }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_revert_claim_root_with_swap_hotkey --exact --nocapture +#[test] +fn test_revert_claim_root_with_swap_hotkey() { + new_test_ext(1).execute_with(|| { + let owner_coldkey = U256::from(1001); + let hk1 = U256::from(1002); + let hk2 = U256::from(1003); + let coldkey = U256::from(1004); + + let netuid = add_dynamic_network(&hk1, &owner_coldkey); + let netuid2 = add_dynamic_network(&hk1, &owner_coldkey); + + SubtensorModule::add_balance_to_coldkey_account(&owner_coldkey, u64::MAX); + SubtensorModule::set_tao_weight(u64::MAX); + + let root_stake = 2_000_000u64; + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &coldkey, + NetUid::ROOT, + root_stake.into(), + ); + + let initial_total_hotkey_alpha = 10_000_000u64; + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hk1, + &owner_coldkey, + netuid, + initial_total_hotkey_alpha.into(), + ); + + let pending_root_alpha = 1_000_000u64; + SubtensorModule::distribute_emission( + netuid, + AlphaCurrency::ZERO, + AlphaCurrency::ZERO, + pending_root_alpha.into(), + AlphaCurrency::ZERO, + ); + + assert_ok!(SubtensorModule::set_root_claim_type( + RuntimeOrigin::signed(coldkey), + RootClaimTypeEnum::Keep + )); + assert_ok!(SubtensorModule::claim_root( + RuntimeOrigin::signed(coldkey), + BTreeSet::from([netuid]) + )); + + let stake_after_claim: u64 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid) + .into(); + + let hk1_root_claimed = RootClaimed::::get((netuid, &hk1, &coldkey)); + let hk1_claimable = *RootClaimable::::get(hk1) + .get(&netuid) + .expect("claimable must exist before swap"); + + assert_eq!(u128::from(stake_after_claim), hk1_root_claimed); + assert!(!RootClaimable::::get(hk2).contains_key(&netuid)); + + System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(owner_coldkey), + &hk1, + &hk2, + Some(netuid) + )); + + assert_eq!( + RootClaimed::::get((netuid, &hk1, &coldkey)), + 0u128, + "hk1 RootClaimed must be zero after swap" + ); + assert_eq!( + RootClaimed::::get((netuid, &hk2, &coldkey)), + hk1_root_claimed, + "hk2 must have hk1's RootClaimed after swap" + ); + assert!(!RootClaimable::::get(hk1).contains_key(&netuid)); + assert_eq!( + *RootClaimable::::get(hk2) + .get(&netuid) + .expect("claimable must exist on hk2 after swap"), + hk1_claimable, + "hk2 must have hk1's RootClaimable after swap" + ); + + // Revert: hk2 -> hk1 + step_block(20); + assert_ok!(SubtensorModule::do_swap_hotkey( + RuntimeOrigin::signed(owner_coldkey), + &hk2, + &hk1, + Some(netuid) + )); + + assert_eq!( + RootClaimed::::get((netuid, &hk2, &coldkey)), + 0u128, + "hk2 RootClaimed must be zero after revert" + ); + assert_eq!( + RootClaimed::::get((netuid, &hk1, &coldkey)), + hk1_root_claimed, + "hk1 RootClaimed must be restored after revert" + ); + + assert!(!RootClaimable::::get(hk2).contains_key(&netuid)); + assert_eq!( + *RootClaimable::::get(hk1) + .get(&netuid) + .expect("claimable must exist on hk1 after revert"), + hk1_claimable, + "hk1 RootClaimable must be restored after revert" + ); + }); } \ No newline at end of file From d3cb527b79bd80f00ef3a9f614b0e1c3443388d9 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 18:15:32 +0100 Subject: [PATCH 11/16] commit Cargo.lock --- .../src/tests/swap_hotkey_with_subnet.rs | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index ffcc60ecd4..8b7f51a34a 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1575,7 +1575,7 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { add_network(netuid2, tempo, 0); register_ok_neuron(netuid, hk1, coldkey, 0); register_ok_neuron(netuid2, hk1, coldkey, 0); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost.into()); let hk1_stake_before_increase = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); @@ -1658,7 +1658,7 @@ fn test_revert_hotkey_swap() { add_network(netuid2, tempo, 0); register_ok_neuron(netuid, old_hotkey, coldkey, 0); register_ok_neuron(netuid2, old_hotkey, coldkey, 0); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost.into()); step_block(20); // Perform the first swap (only on netuid) @@ -1694,7 +1694,7 @@ fn test_revert_hotkey_swap_parent_hotkey_childkey_maps() { let netuid = add_dynamic_network(&hk1, &coldkey); let netuid2 = add_dynamic_network(&hk1, &coldkey); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); SubtensorModule::create_account_if_non_existent(&coldkey, &hk1); mock_set_children(&coldkey, &hk1, netuid, &[(u64::MAX, child)]); @@ -1781,7 +1781,7 @@ fn test_revert_hotkey_swap_uids_and_keys() { let netuid = add_dynamic_network(&hk1, &coldkey); let netuid2 = add_dynamic_network(&hk1, &coldkey); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); IsNetworkMember::::insert(hk1, netuid, true); Uids::::insert(netuid, hk1, uid); @@ -1843,7 +1843,7 @@ fn test_revert_hotkey_swap_auto_stake_destination() { add_network(netuid2, 1, 0); register_ok_neuron(netuid, hk1, coldkey, 0); register_ok_neuron(netuid2, hk1, coldkey, 0); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); AutoStakeDestinationColdkeys::::insert(hk1, netuid, coldkeys.clone()); AutoStakeDestination::::insert(coldkey, netuid, hk1); @@ -1913,7 +1913,7 @@ fn test_revert_hotkey_swap_subnet_owner() { let netuid = add_dynamic_network(&hk1, &coldkey); let netuid2 = add_dynamic_network(&hk1, &coldkey); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); assert_eq!(SubnetOwnerHotkey::::get(netuid), hk1); @@ -1958,16 +1958,16 @@ fn test_revert_hotkey_swap_dividends() { let netuid = add_dynamic_network(&hk1, &coldkey); let netuid2 = add_dynamic_network(&hk1, &coldkey); - SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX.into()); let amount = 10_000; let shares = U64F64::from_num(123456); - TotalHotkeyAlpha::::insert(hk1, netuid, AlphaCurrency::from(amount)); - TotalHotkeyAlphaLastEpoch::::insert(hk1, netuid, AlphaCurrency::from(amount * 2)); + TotalHotkeyAlpha::::insert(hk1, netuid, AlphaBalance::from(amount).into()); + TotalHotkeyAlphaLastEpoch::::insert(hk1, netuid, AlphaBalance::from(amount * 2)); TotalHotkeyShares::::insert(hk1, netuid, U64F64::from_num(shares)); Alpha::::insert((hk1, coldkey, netuid), U64F64::from_num(amount)); - AlphaDividendsPerSubnet::::insert(netuid, hk1, AlphaCurrency::from(amount)); + AlphaDividendsPerSubnet::::insert(netuid, hk1, AlphaBalance::from(amount)); System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); assert_ok!(SubtensorModule::do_swap_hotkey( @@ -1977,16 +1977,16 @@ fn test_revert_hotkey_swap_dividends() { Some(netuid) )); - assert_eq!(TotalHotkeyAlpha::::get(hk1, netuid), AlphaCurrency::ZERO); - assert_eq!(TotalHotkeyAlpha::::get(hk2, netuid), AlphaCurrency::from(amount)); - assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), AlphaCurrency::ZERO); - assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), AlphaCurrency::from(amount * 2)); + assert_eq!(TotalHotkeyAlpha::::get(hk1, netuid), AlphaBalance::ZERO); + assert_eq!(TotalHotkeyAlpha::::get(hk2, netuid), AlphaBalance::from(amount)); + assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), AlphaBalance::ZERO); + assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), AlphaBalance::from(amount * 2)); assert_eq!(TotalHotkeyShares::::get(hk1, netuid), U64F64::from_num(0)); assert_eq!(TotalHotkeyShares::::get(hk2, netuid), U64F64::from_num(shares)); assert_eq!(Alpha::::get((hk1, coldkey, netuid)), U64F64::from_num(0)); assert_eq!(Alpha::::get((hk2, coldkey, netuid)), U64F64::from_num(amount)); - assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk1), AlphaCurrency::ZERO); - assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk2), AlphaCurrency::from(amount)); + assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk1), AlphaBalance::ZERO); + assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk2), AlphaBalance::from(amount)); // Revert: hk2 -> hk1 step_block(20); @@ -1999,22 +1999,22 @@ fn test_revert_hotkey_swap_dividends() { assert_eq!( TotalHotkeyAlpha::::get(hk2, netuid), - AlphaCurrency::ZERO, + AlphaBalance::ZERO, "hk2 TotalHotkeyAlpha must be zero after revert" ); assert_eq!( TotalHotkeyAlpha::::get(hk1, netuid), - AlphaCurrency::from(amount), + AlphaBalance::from(amount), "hk1 TotalHotkeyAlpha must be restored after revert" ); assert_eq!( TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), - AlphaCurrency::ZERO, + AlphaBalance::ZERO, "hk2 TotalHotkeyAlphaLastEpoch must be zero after revert" ); assert_eq!( TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), - AlphaCurrency::from(amount * 2), + AlphaBalance::from(amount * 2), "hk1 TotalHotkeyAlphaLastEpoch must be restored after revert" ); assert_eq!( @@ -2039,12 +2039,12 @@ fn test_revert_hotkey_swap_dividends() { ); assert_eq!( AlphaDividendsPerSubnet::::get(netuid, hk2), - AlphaCurrency::ZERO, + AlphaBalance::ZERO, "hk2 AlphaDividendsPerSubnet must be zero after revert" ); assert_eq!( AlphaDividendsPerSubnet::::get(netuid, hk1), - AlphaCurrency::from(amount), + AlphaBalance::from(amount), "hk1 AlphaDividendsPerSubnet must be restored after revert" ); }); @@ -2097,7 +2097,7 @@ fn test_revert_claim_root_with_swap_hotkey() { let netuid = add_dynamic_network(&hk1, &owner_coldkey); let netuid2 = add_dynamic_network(&hk1, &owner_coldkey); - SubtensorModule::add_balance_to_coldkey_account(&owner_coldkey, u64::MAX); + SubtensorModule::add_balance_to_coldkey_account(&owner_coldkey, u64::MAX.into()); SubtensorModule::set_tao_weight(u64::MAX); let root_stake = 2_000_000u64; @@ -2119,10 +2119,10 @@ fn test_revert_claim_root_with_swap_hotkey() { let pending_root_alpha = 1_000_000u64; SubtensorModule::distribute_emission( netuid, - AlphaCurrency::ZERO, - AlphaCurrency::ZERO, + AlphaBalance::ZERO, + AlphaBalance::ZERO, pending_root_alpha.into(), - AlphaCurrency::ZERO, + AlphaBalance::ZERO, ); assert_ok!(SubtensorModule::set_root_claim_type( From 1cc064432613a3f2fb5f7b16fe2d7228f910f318 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 18:16:22 +0100 Subject: [PATCH 12/16] commit Cargo.lock --- pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 8b7f51a34a..f1933adcb8 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1963,7 +1963,7 @@ fn test_revert_hotkey_swap_dividends() { let amount = 10_000; let shares = U64F64::from_num(123456); - TotalHotkeyAlpha::::insert(hk1, netuid, AlphaBalance::from(amount).into()); + TotalHotkeyAlpha::::insert(hk1, netuid, AlphaBalance::from(amount)); TotalHotkeyAlphaLastEpoch::::insert(hk1, netuid, AlphaBalance::from(amount * 2)); TotalHotkeyShares::::insert(hk1, netuid, U64F64::from_num(shares)); Alpha::::insert((hk1, coldkey, netuid), U64F64::from_num(amount)); From a7154538eb71d326f13ea5f2f8da738fb9e06696 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 18:18:22 +0100 Subject: [PATCH 13/16] cargo clippy --- 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 ad13c51ad4..b21af85162 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1116,7 +1116,7 @@ parameter_types! { // 0 days pub const InitialStartCallDelay: u64 = 0; pub const SubtensorInitialKeySwapOnSubnetCost: TaoBalance = TaoBalance::new(1_000_000); // 0.001 TAO - pub const HotkeySwapOnSubnetInterval : BlockNumber = 1 * 24 * 60 * 60 / 12; // 1 day + pub const HotkeySwapOnSubnetInterval : BlockNumber = 24 * 60 * 60 / 12; // 1 day pub const LeaseDividendsDistributionInterval: BlockNumber = 100; // 100 blocks pub const MaxImmuneUidsPercentage: Percent = Percent::from_percent(80); pub const EvmKeyAssociateRateLimit: u64 = EVM_KEY_ASSOCIATE_RATELIMIT; From 5e85bb37f566d44b99c4b12d545e26119830f07a Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Thu, 5 Mar 2026 18:19:44 +0100 Subject: [PATCH 14/16] cargo fmt --- .../src/tests/swap_hotkey_with_subnet.rs | 107 +++++++++++++----- 1 file changed, 79 insertions(+), 28 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index f1933adcb8..48ccfabda7 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -1579,7 +1579,10 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { let hk1_stake_before_increase = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - assert!(hk1_stake_before_increase == 0.into(), "hk1 should have empty stake"); + assert!( + hk1_stake_before_increase == 0.into(), + "hk1 should have empty stake" + ); SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( &hk1, @@ -1590,7 +1593,10 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { let hk1_stake_before_swap = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hk1, &coldkey, netuid); - assert!(hk1_stake_before_swap == 1_000_000_000.into(), "hk1 should have stake before swap"); + assert!( + hk1_stake_before_swap == 1_000_000_000.into(), + "hk1 should have stake before swap" + ); step_block(20); @@ -1636,7 +1642,11 @@ fn test_revert_hotkey_swap_stake_is_not_lost() { ); // hk2 should be empty - assert_eq!(hk2_stake_after_revert, 0.into(), "hk2 should have no stake after revert"); + assert_eq!( + hk2_stake_after_revert, + 0.into(), + "hk2 should have no stake after revert" + ); }); } @@ -1669,7 +1679,9 @@ fn test_revert_hotkey_swap() { Some(netuid) )); - assert!(SubtensorModule::is_hotkey_registered_on_any_network(&old_hotkey)); + assert!(SubtensorModule::is_hotkey_registered_on_any_network( + &old_hotkey + )); step_block(20); @@ -1705,10 +1717,7 @@ fn test_revert_hotkey_swap_parent_hotkey_childkey_maps() { ParentKeys::::get(child, netuid), vec![(u64::MAX, hk1)] ); - assert_eq!( - ChildKeys::::get(hk1, netuid), - vec![(u64::MAX, child)] - ); + assert_eq!(ChildKeys::::get(hk1, netuid), vec![(u64::MAX, child)]); let existing_pending_child_keys = PendingChildKeys::::get(netuid, hk1); assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_other)]); @@ -1724,10 +1733,7 @@ fn test_revert_hotkey_swap_parent_hotkey_childkey_maps() { ParentKeys::::get(child, netuid), vec![(u64::MAX, hk2)] ); - assert_eq!( - ChildKeys::::get(hk2, netuid), - vec![(u64::MAX, child)] - ); + assert_eq!(ChildKeys::::get(hk2, netuid), vec![(u64::MAX, child)]); assert_eq!( PendingChildKeys::::get(netuid, hk2), existing_pending_child_keys @@ -1863,9 +1869,18 @@ fn test_revert_hotkey_swap_auto_stake_destination() { coldkeys ); assert!(AutoStakeDestinationColdkeys::::get(hk1, netuid).is_empty()); - assert_eq!(AutoStakeDestination::::get(coldkey, netuid), Some(hk2)); - assert_eq!(AutoStakeDestination::::get(staker1, netuid), Some(hk2)); - assert_eq!(AutoStakeDestination::::get(staker2, netuid), Some(hk2)); + assert_eq!( + AutoStakeDestination::::get(coldkey, netuid), + Some(hk2) + ); + assert_eq!( + AutoStakeDestination::::get(staker1, netuid), + Some(hk2) + ); + assert_eq!( + AutoStakeDestination::::get(staker2, netuid), + Some(hk2) + ); // Revert: hk2 -> hk1 step_block(20); @@ -1977,16 +1992,46 @@ fn test_revert_hotkey_swap_dividends() { Some(netuid) )); - assert_eq!(TotalHotkeyAlpha::::get(hk1, netuid), AlphaBalance::ZERO); - assert_eq!(TotalHotkeyAlpha::::get(hk2, netuid), AlphaBalance::from(amount)); - assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), AlphaBalance::ZERO); - assert_eq!(TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), AlphaBalance::from(amount * 2)); - assert_eq!(TotalHotkeyShares::::get(hk1, netuid), U64F64::from_num(0)); - assert_eq!(TotalHotkeyShares::::get(hk2, netuid), U64F64::from_num(shares)); - assert_eq!(Alpha::::get((hk1, coldkey, netuid)), U64F64::from_num(0)); - assert_eq!(Alpha::::get((hk2, coldkey, netuid)), U64F64::from_num(amount)); - assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk1), AlphaBalance::ZERO); - assert_eq!(AlphaDividendsPerSubnet::::get(netuid, hk2), AlphaBalance::from(amount)); + assert_eq!( + TotalHotkeyAlpha::::get(hk1, netuid), + AlphaBalance::ZERO + ); + assert_eq!( + TotalHotkeyAlpha::::get(hk2, netuid), + AlphaBalance::from(amount) + ); + assert_eq!( + TotalHotkeyAlphaLastEpoch::::get(hk1, netuid), + AlphaBalance::ZERO + ); + assert_eq!( + TotalHotkeyAlphaLastEpoch::::get(hk2, netuid), + AlphaBalance::from(amount * 2) + ); + assert_eq!( + TotalHotkeyShares::::get(hk1, netuid), + U64F64::from_num(0) + ); + assert_eq!( + TotalHotkeyShares::::get(hk2, netuid), + U64F64::from_num(shares) + ); + assert_eq!( + Alpha::::get((hk1, coldkey, netuid)), + U64F64::from_num(0) + ); + assert_eq!( + Alpha::::get((hk2, coldkey, netuid)), + U64F64::from_num(amount) + ); + assert_eq!( + AlphaDividendsPerSubnet::::get(netuid, hk1), + AlphaBalance::ZERO + ); + assert_eq!( + AlphaDividendsPerSubnet::::get(netuid, hk2), + AlphaBalance::from(amount) + ); // Revert: hk2 -> hk1 step_block(20); @@ -2061,13 +2106,19 @@ fn test_revert_voting_power_transfers_on_hotkey_swap() { let voting_power_value = 5_000_000_000_000_u64; VotingPower::::insert(netuid, hk1, voting_power_value); - assert_eq!(SubtensorModule::get_voting_power(netuid, &hk1), voting_power_value); + assert_eq!( + SubtensorModule::get_voting_power(netuid, &hk1), + voting_power_value + ); assert_eq!(SubtensorModule::get_voting_power(netuid, &hk2), 0); SubtensorModule::swap_voting_power_for_hotkey(&hk1, &hk2, netuid); assert_eq!(SubtensorModule::get_voting_power(netuid, &hk1), 0); - assert_eq!(SubtensorModule::get_voting_power(netuid, &hk2), voting_power_value); + assert_eq!( + SubtensorModule::get_voting_power(netuid, &hk2), + voting_power_value + ); // Revert: hk2 -> hk1 SubtensorModule::swap_voting_power_for_hotkey(&hk2, &hk1, netuid); @@ -2202,4 +2253,4 @@ fn test_revert_claim_root_with_swap_hotkey() { "hk1 RootClaimable must be restored after revert" ); }); -} \ No newline at end of file +} From 893bfb0009d40c2112188da41b52909767008b59 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 6 Mar 2026 10:56:27 +0100 Subject: [PATCH 15/16] Add check for `is_hotkey_registered_on_specific_network` when `netuid` is `Some` --- pallets/subtensor/src/swap/swap_hotkey.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 00008cb439..c2d7c54567 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -65,6 +65,14 @@ impl Pallet { ); } + // 7.1. Ensure the hotkey is not registered on the network before, if netuid is provided + if let Some(netuid) = netuid { + ensure!( + !Self::is_hotkey_registered_on_specific_network(new_hotkey, netuid), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + } + // 8. Swap LastTxBlock let last_tx_block: u64 = Self::get_last_tx_block(old_hotkey); Self::set_last_tx_block(new_hotkey, last_tx_block); From c62a01d008baf29b1ea7f69b8546c0509d01f2e5 Mon Sep 17 00:00:00 2001 From: Evgeny Svirsky Date: Fri, 6 Mar 2026 11:22:04 +0100 Subject: [PATCH 16/16] - Fix for clippy --- pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 48ccfabda7..be2895941c 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -2192,7 +2192,7 @@ fn test_revert_claim_root_with_swap_hotkey() { let hk1_root_claimed = RootClaimed::::get((netuid, &hk1, &coldkey)); let hk1_claimable = *RootClaimable::::get(hk1) .get(&netuid) - .expect("claimable must exist before swap"); + .unwrap(); assert_eq!(u128::from(stake_after_claim), hk1_root_claimed); assert!(!RootClaimable::::get(hk2).contains_key(&netuid)); @@ -2219,7 +2219,7 @@ fn test_revert_claim_root_with_swap_hotkey() { assert_eq!( *RootClaimable::::get(hk2) .get(&netuid) - .expect("claimable must exist on hk2 after swap"), + .unwrap(), hk1_claimable, "hk2 must have hk1's RootClaimable after swap" ); @@ -2248,7 +2248,7 @@ fn test_revert_claim_root_with_swap_hotkey() { assert_eq!( *RootClaimable::::get(hk1) .get(&netuid) - .expect("claimable must exist on hk1 after revert"), + .unwrap(), hk1_claimable, "hk1 RootClaimable must be restored after revert" );