Skip to content

Commit 3db0cb7

Browse files
authored
Merge pull request #1761 from opentensor/sam-backprop-6-16-2025
backprop hotfixes 6/16/2025
2 parents 40cf4e0 + f2b8ac4 commit 3db0cb7

File tree

8 files changed

+112
-33
lines changed

8 files changed

+112
-33
lines changed

common/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ impl NetUid {
6666
pub fn next(&self) -> NetUid {
6767
Self(self.0.saturating_add(1))
6868
}
69+
70+
pub fn prev(&self) -> NetUid {
71+
Self(self.0.saturating_sub(1))
72+
}
73+
74+
pub fn inner(&self) -> u16 {
75+
self.0
76+
}
6977
}
7078

7179
impl Display for NetUid {
@@ -130,6 +138,7 @@ pub enum ProxyType {
130138
RootWeights,
131139
ChildKeys,
132140
SudoUncheckedSetCode,
141+
SwapHotkey,
133142
}
134143

135144
impl Default for ProxyType {

pallets/subtensor/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,17 @@ pub mod pallet {
16851685
#[pallet::storage] // --- Storage for migration run status
16861686
pub type HasMigrationRun<T: Config> = StorageMap<_, Identity, Vec<u8>, bool, ValueQuery>;
16871687

1688+
#[pallet::type_value]
1689+
/// Default value for pending childkey cooldown (settable by root, default 0)
1690+
pub fn DefaultPendingChildKeyCooldown<T: Config>() -> u64 {
1691+
0
1692+
}
1693+
1694+
#[pallet::storage]
1695+
/// Storage value for pending childkey cooldown, settable by root.
1696+
pub type PendingChildKeyCooldown<T: Config> =
1697+
StorageValue<_, u64, ValueQuery, DefaultPendingChildKeyCooldown<T>>;
1698+
16881699
#[pallet::genesis_config]
16891700
pub struct GenesisConfig<T: Config> {
16901701
/// Stakes record in genesis.

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,5 +2058,17 @@ mod dispatches {
20582058
) -> DispatchResult {
20592059
Self::do_burn_alpha(origin, hotkey, amount, netuid)
20602060
}
2061+
2062+
/// Sets the pending childkey cooldown (in blocks). Root only.
2063+
#[pallet::call_index(109)]
2064+
#[pallet::weight((Weight::from_parts(10_000, 0), DispatchClass::Operational, Pays::No))]
2065+
pub fn set_pending_childkey_cooldown(
2066+
origin: OriginFor<T>,
2067+
cooldown: u64,
2068+
) -> DispatchResult {
2069+
ensure_root(origin)?;
2070+
PendingChildKeyCooldown::<T>::put(cooldown);
2071+
Ok(())
2072+
}
20612073
}
20622074
}

pallets/subtensor/src/staking/set_children.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::*;
2-
use sp_core::Get;
2+
33
use subtensor_runtime_common::NetUid;
44

55
impl<T: Config> Pallet<T> {
@@ -124,7 +124,7 @@ impl<T: Config> Pallet<T> {
124124

125125
// Calculate cool-down block
126126
let cooldown_block =
127-
Self::get_current_block_as_u64().saturating_add(DefaultPendingCooldown::<T>::get());
127+
Self::get_current_block_as_u64().saturating_add(PendingChildKeyCooldown::<T>::get());
128128

129129
// Insert or update PendingChildKeys
130130
PendingChildKeys::<T>::insert(netuid, hotkey.clone(), (children.clone(), cooldown_block));

pallets/subtensor/src/swap/swap_hotkey.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,36 @@ impl<T: Config> Pallet<T> {
5555

5656
weight.saturating_accrue(T::DbWeight::get().reads(2));
5757

58-
// 7. Swap LastTxBlock
58+
// 7. Ensure the new hotkey is not already registered on any network
59+
ensure!(
60+
!Self::is_hotkey_registered_on_any_network(new_hotkey),
61+
Error::<T>::HotKeyAlreadyRegisteredInSubNet
62+
);
63+
64+
// 8. Swap LastTxBlock
5965
// LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey.
6066
let last_tx_block: u64 = LastTxBlock::<T>::get(old_hotkey);
6167
LastTxBlock::<T>::insert(new_hotkey, last_tx_block);
6268
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
6369

64-
// 8. Swap LastTxBlockDelegateTake
70+
// 9. Swap LastTxBlockDelegateTake
6571
// LastTxBlockDelegateTake( hotkey ) --> u64 -- the last transaction block for the hotkey delegate take.
6672
let last_tx_block_delegate_take: u64 = LastTxBlockDelegateTake::<T>::get(old_hotkey);
6773
LastTxBlockDelegateTake::<T>::insert(new_hotkey, last_tx_block_delegate_take);
6874
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
6975

70-
// 9. Swap LastTxBlockChildKeyTake
76+
// 10. Swap LastTxBlockChildKeyTake
7177
// LastTxBlockChildKeyTake( hotkey ) --> u64 -- the last transaction block for the hotkey child key take.
7278
let last_tx_block_child_key_take: u64 = LastTxBlockChildKeyTake::<T>::get(old_hotkey);
7379
LastTxBlockChildKeyTake::<T>::insert(new_hotkey, last_tx_block_child_key_take);
7480
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
7581

76-
// 10. fork for swap hotkey on a specific subnet case after do the common check
82+
// 11. fork for swap hotkey on a specific subnet case after do the common check
7783
if let Some(netuid) = netuid {
7884
return Self::swap_hotkey_on_subnet(&coldkey, old_hotkey, new_hotkey, netuid, weight);
7985
};
8086

8187
// Start to do everything for swap hotkey on all subnets case
82-
// 11. Ensure the new hotkey is not already registered on any network
83-
ensure!(
84-
!Self::is_hotkey_registered_on_any_network(new_hotkey),
85-
Error::<T>::HotKeyAlreadyRegisteredInSubNet
86-
);
87-
8888
// 12. Get the cost for swapping the key
8989
let swap_cost = Self::get_key_swap_cost();
9090
log::debug!("Swap cost: {:?}", swap_cost);

pallets/subtensor/src/tests/children.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3953,14 +3953,14 @@ fn test_dividend_distribution_with_children_same_coldkey_owner() {
39533953
}
39543954

39553955
#[test]
3956-
fn test_pending_cooldown_one_day() {
3956+
fn test_pending_cooldown_as_expected() {
39573957
let curr_block = 1;
3958-
3959-
let expected_cooldown = if cfg!(feature = "fast-blocks") {
3960-
15
3961-
} else {
3962-
7_200
3963-
};
3958+
// TODO: Fix when CHK splitting patched
3959+
// let expected_cooldown = if cfg!(feature = "fast-blocks") {
3960+
// 15
3961+
// } else {
3962+
// 7200
3963+
// };
39643964

39653965
new_test_ext(curr_block).execute_with(|| {
39663966
let coldkey = U256::from(1);
@@ -3970,6 +3970,7 @@ fn test_pending_cooldown_one_day() {
39703970
let netuid = NetUid::from(1);
39713971
let proportion1: u64 = 1000;
39723972
let proportion2: u64 = 2000;
3973+
let expected_cooldown = PendingChildKeyCooldown::<Test>::get();
39733974

39743975
// Add network and register hotkey
39753976
add_network(netuid, 13, 0);

pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,8 @@ fn test_swap_hotkey_with_multiple_subnets() {
497497
new_test_ext(1).execute_with(|| {
498498
let old_hotkey = U256::from(1);
499499
let new_hotkey = U256::from(2);
500-
let coldkey = U256::from(3);
500+
let new_hotkey_2 = U256::from(3);
501+
let coldkey = U256::from(4);
501502

502503
SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX);
503504

@@ -519,12 +520,12 @@ fn test_swap_hotkey_with_multiple_subnets() {
519520
assert_ok!(SubtensorModule::do_swap_hotkey(
520521
RuntimeOrigin::signed(coldkey),
521522
&old_hotkey,
522-
&new_hotkey,
523+
&new_hotkey_2,
523524
Some(netuid2)
524525
));
525526

526527
assert!(IsNetworkMember::<Test>::get(new_hotkey, netuid1));
527-
assert!(IsNetworkMember::<Test>::get(new_hotkey, netuid2));
528+
assert!(IsNetworkMember::<Test>::get(new_hotkey_2, netuid2));
528529
assert!(!IsNetworkMember::<Test>::get(old_hotkey, netuid1));
529530
assert!(!IsNetworkMember::<Test>::get(old_hotkey, netuid2));
530531
});
@@ -628,8 +629,9 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
628629
new_test_ext(1).execute_with(|| {
629630
let old_hotkey = U256::from(1);
630631
let new_hotkey = U256::from(2);
631-
let coldkey1 = U256::from(3);
632-
let coldkey2 = U256::from(4);
632+
let new_hotkey_2 = U256::from(3);
633+
let coldkey1 = U256::from(4);
634+
let coldkey2 = U256::from(5);
633635
let netuid1 = NetUid::from(1);
634636
let netuid2 = NetUid::from(2);
635637
let stake = DefaultMinStake::<Test>::get() * 10;
@@ -687,7 +689,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
687689
assert_ok!(SubtensorModule::do_swap_hotkey(
688690
RuntimeOrigin::signed(coldkey1),
689691
&old_hotkey,
690-
&new_hotkey,
692+
&new_hotkey_2,
691693
Some(netuid2)
692694
));
693695

@@ -697,6 +699,11 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
697699
coldkey1
698700
);
699701
assert!(!SubtensorModule::get_owned_hotkeys(&coldkey2).contains(&new_hotkey));
702+
assert_eq!(
703+
SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey_2),
704+
coldkey1
705+
);
706+
assert!(!SubtensorModule::get_owned_hotkeys(&coldkey2).contains(&new_hotkey_2));
700707

701708
// Check stake transfer
702709
assert_eq!(
@@ -709,7 +716,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
709716
);
710717
assert_eq!(
711718
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
712-
&new_hotkey,
719+
&new_hotkey_2,
713720
&coldkey2,
714721
netuid2
715722
),
@@ -739,7 +746,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
739746
));
740747
assert!(SubtensorModule::is_hotkey_registered_on_network(
741748
netuid2,
742-
&new_hotkey
749+
&new_hotkey_2
743750
));
744751
assert!(!SubtensorModule::is_hotkey_registered_on_network(
745752
netuid1,
@@ -752,7 +759,8 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
752759

753760
// Check total stake transfer
754761
assert_eq!(
755-
SubtensorModule::get_total_stake_for_hotkey(&new_hotkey),
762+
SubtensorModule::get_total_stake_for_hotkey(&new_hotkey)
763+
+ SubtensorModule::get_total_stake_for_hotkey(&new_hotkey_2),
756764
total_hk_stake
757765
);
758766
assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&old_hotkey), 0);
@@ -1143,7 +1151,8 @@ fn test_swap_multiple_subnets() {
11431151
new_test_ext(1).execute_with(|| {
11441152
let old_hotkey = U256::from(1);
11451153
let new_hotkey = U256::from(2);
1146-
let coldkey = U256::from(3);
1154+
let new_hotkey_2 = U256::from(3);
1155+
let coldkey = U256::from(4);
11471156
let netuid1 = add_dynamic_network(&old_hotkey, &coldkey);
11481157
let netuid2 = add_dynamic_network(&old_hotkey, &coldkey);
11491158

@@ -1169,13 +1178,13 @@ fn test_swap_multiple_subnets() {
11691178
assert_ok!(SubtensorModule::do_swap_hotkey(
11701179
RuntimeOrigin::signed(coldkey),
11711180
&old_hotkey,
1172-
&new_hotkey,
1181+
&new_hotkey_2,
11731182
Some(netuid2)
11741183
),);
11751184

11761185
// Verify the swap for both subnets
11771186
assert_eq!(ChildKeys::<Test>::get(new_hotkey, netuid1), children1);
1178-
assert_eq!(ChildKeys::<Test>::get(new_hotkey, netuid2), children2);
1187+
assert_eq!(ChildKeys::<Test>::get(new_hotkey_2, netuid2), children2);
11791188
assert!(ChildKeys::<Test>::get(old_hotkey, netuid1).is_empty());
11801189
assert!(ChildKeys::<Test>::get(old_hotkey, netuid2).is_empty());
11811190
});
@@ -1490,7 +1499,6 @@ fn test_swap_owner_check_swap_record_clean_up() {
14901499
let old_hotkey = U256::from(1);
14911500
let new_hotkey = U256::from(2);
14921501
let coldkey = U256::from(3);
1493-
14941502
let netuid = add_dynamic_network(&old_hotkey, &coldkey);
14951503
SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX);
14961504
Owner::<Test>::insert(old_hotkey, coldkey);
@@ -1514,3 +1522,37 @@ fn test_swap_owner_check_swap_record_clean_up() {
15141522
));
15151523
});
15161524
}
1525+
1526+
// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_hotkey_error_cases --exact --nocapture
1527+
#[test]
1528+
fn test_swap_hotkey_registered_on_other_subnet() {
1529+
new_test_ext(1).execute_with(|| {
1530+
let old_hotkey = U256::from(1);
1531+
let new_hotkey = U256::from(2);
1532+
let coldkey = U256::from(3);
1533+
let wrong_coldkey = U256::from(4);
1534+
let netuid = add_dynamic_network(&old_hotkey, &coldkey);
1535+
let other_netuid = add_dynamic_network(&old_hotkey, &coldkey);
1536+
1537+
// Set up initial state
1538+
Owner::<Test>::insert(old_hotkey, coldkey);
1539+
TotalNetworks::<Test>::put(1);
1540+
LastTxBlock::<Test>::insert(coldkey, 0);
1541+
1542+
let initial_balance = SubtensorModule::get_key_swap_cost() + 1000;
1543+
SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_balance);
1544+
1545+
// Test new hotkey already registered on other subnet
1546+
IsNetworkMember::<Test>::insert(new_hotkey, other_netuid, true);
1547+
System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get());
1548+
assert_noop!(
1549+
SubtensorModule::do_swap_hotkey(
1550+
RuntimeOrigin::signed(coldkey),
1551+
&old_hotkey,
1552+
&new_hotkey,
1553+
Some(netuid)
1554+
),
1555+
Error::<Test>::HotKeyAlreadyRegisteredInSubNet
1556+
);
1557+
});
1558+
}

runtime/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
209209
// `spec_version`, and `authoring_version` are the same between Wasm and native.
210210
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
211211
// the compatible custom types.
212-
spec_version: 276,
212+
spec_version: 278,
213213
impl_version: 1,
214214
apis: RUNTIME_API_VERSIONS,
215215
transaction_version: 1,
@@ -829,6 +829,10 @@ impl InstanceFilter<RuntimeCall> for ProxyType {
829829
}
830830
_ => false,
831831
},
832+
ProxyType::SwapHotkey => matches!(
833+
c,
834+
RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_hotkey { .. })
835+
),
832836
}
833837
}
834838
fn is_superset(&self, o: &Self) -> bool {

0 commit comments

Comments
 (0)