Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1b665ff
hotkey splitting emergency merge of #1559
sam0x17 Jun 14, 2025
0e914af
bump spec version
sam0x17 Jun 14, 2025
6c8df06
Merge pull request #1754 from opentensor/emergency-hotfix-6-14-2025
sam0x17 Jun 14, 2025
582ac00
move guard check for *any* sn reg
camfairchild Jun 14, 2025
0383198
add test
camfairchild Jun 14, 2025
4835953
move state change to after check
camfairchild Jun 14, 2025
248c579
fix test 1
camfairchild Jun 14, 2025
52a06bc
fix test 2
camfairchild Jun 14, 2025
55b3ea2
fix test 3
camfairchild Jun 14, 2025
f892a9c
Merge pull request #1755 from opentensor/fix/move-reg-check
sam0x17 Jun 14, 2025
5596574
add
camfairchild Jun 14, 2025
d7117b6
bump spec
camfairchild Jun 14, 2025
0e9f293
Merge pull request #1756 from opentensor/feat/add-swap-hk-proxy
sam0x17 Jun 14, 2025
4820fb2
cooldown
sam0x17 Jun 15, 2025
4b232d3
fix
sam0x17 Jun 16, 2025
3edbb98
fix: tests
distributedstatemachine Jun 16, 2025
f3c434b
fix: tests
distributedstatemachine Jun 16, 2025
a35e462
chore: clippy
distributedstatemachine Jun 16, 2025
bfeaf1c
bump spec version
sam0x17 Jun 16, 2025
586eb24
fix benchmark
open-junius Jun 16, 2025
0e99ff6
fix an error
open-junius Jun 16, 2025
17e48b2
fix benchmark
open-junius Jun 16, 2025
651b8be
fix benchmark
sam0x17 Jun 16, 2025
73094c9
Merge remote-tracking branch 'origin/hotfix-cooldown' into hotfix-coo…
sam0x17 Jun 16, 2025
18379a4
Merge pull request #1757 from opentensor/hotfix-cooldown
sam0x17 Jun 16, 2025
d3ef42c
Merge remote-tracking branch 'origin/main' into devnet-ready
sam0x17 Jun 16, 2025
7a9ded8
fix hotkey registration check test
l0r1s Jun 16, 2025
3a2cf28
remove printlns
l0r1s Jun 16, 2025
6b71322
cargo fmt
l0r1s Jun 16, 2025
409eb2e
bump spec version
sam0x17 Jun 16, 2025
7627c0c
fix comment
l0r1s Jun 16, 2025
f2b8ac4
commit suggestions
l0r1s Jun 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ impl NetUid {
pub fn next(&self) -> NetUid {
Self(self.0.saturating_add(1))
}

pub fn prev(&self) -> NetUid {
Self(self.0.saturating_sub(1))
}

pub fn inner(&self) -> u16 {
self.0
}
}

impl Display for NetUid {
Expand Down Expand Up @@ -130,6 +138,7 @@ pub enum ProxyType {
RootWeights,
ChildKeys,
SudoUncheckedSetCode,
SwapHotkey,
}

impl Default for ProxyType {
Expand Down
11 changes: 11 additions & 0 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,17 @@ pub mod pallet {
#[pallet::storage] // --- Storage for migration run status
pub type HasMigrationRun<T: Config> = StorageMap<_, Identity, Vec<u8>, bool, ValueQuery>;

#[pallet::type_value]
/// Default value for pending childkey cooldown (settable by root, default 0)
pub fn DefaultPendingChildKeyCooldown<T: Config>() -> u64 {
0
}

#[pallet::storage]
/// Storage value for pending childkey cooldown, settable by root.
pub type PendingChildKeyCooldown<T: Config> =
StorageValue<_, u64, ValueQuery, DefaultPendingChildKeyCooldown<T>>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
/// Stakes record in genesis.
Expand Down
12 changes: 12 additions & 0 deletions pallets/subtensor/src/macros/dispatches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2058,5 +2058,17 @@ mod dispatches {
) -> DispatchResult {
Self::do_burn_alpha(origin, hotkey, amount, netuid)
}

/// Sets the pending childkey cooldown (in blocks). Root only.
#[pallet::call_index(109)]
#[pallet::weight((Weight::from_parts(10_000, 0), DispatchClass::Operational, Pays::No))]
pub fn set_pending_childkey_cooldown(
origin: OriginFor<T>,
cooldown: u64,
) -> DispatchResult {
ensure_root(origin)?;
PendingChildKeyCooldown::<T>::put(cooldown);
Ok(())
}
}
}
4 changes: 2 additions & 2 deletions pallets/subtensor/src/staking/set_children.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use sp_core::Get;

use subtensor_runtime_common::NetUid;

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -124,7 +124,7 @@ impl<T: Config> Pallet<T> {

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

// Insert or update PendingChildKeys
PendingChildKeys::<T>::insert(netuid, hotkey.clone(), (children.clone(), cooldown_block));
Expand Down
20 changes: 10 additions & 10 deletions pallets/subtensor/src/swap/swap_hotkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,36 @@ impl<T: Config> Pallet<T> {

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

// 7. Swap LastTxBlock
// 7. Ensure the new hotkey is not already registered on any network
ensure!(
!Self::is_hotkey_registered_on_any_network(new_hotkey),
Error::<T>::HotKeyAlreadyRegisteredInSubNet
);

// 8. Swap LastTxBlock
// LastTxBlock( hotkey ) --> u64 -- the last transaction block for the hotkey.
let last_tx_block: u64 = LastTxBlock::<T>::get(old_hotkey);
LastTxBlock::<T>::insert(new_hotkey, last_tx_block);
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));

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

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

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

// Start to do everything for swap hotkey on all subnets case
// 11. Ensure the new hotkey is not already registered on any network
ensure!(
!Self::is_hotkey_registered_on_any_network(new_hotkey),
Error::<T>::HotKeyAlreadyRegisteredInSubNet
);

// 12. Get the cost for swapping the key
let swap_cost = Self::get_key_swap_cost();
log::debug!("Swap cost: {:?}", swap_cost);
Expand Down
15 changes: 8 additions & 7 deletions pallets/subtensor/src/tests/children.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3953,14 +3953,14 @@ fn test_dividend_distribution_with_children_same_coldkey_owner() {
}

#[test]
fn test_pending_cooldown_one_day() {
fn test_pending_cooldown_as_expected() {
let curr_block = 1;

let expected_cooldown = if cfg!(feature = "fast-blocks") {
15
} else {
7_200
};
// TODO: Fix when CHK splitting patched
// let expected_cooldown = if cfg!(feature = "fast-blocks") {
// 15
// } else {
// 7200
// };

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

// Add network and register hotkey
add_network(netuid, 13, 0);
Expand Down
68 changes: 55 additions & 13 deletions pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,8 @@ fn test_swap_hotkey_with_multiple_subnets() {
new_test_ext(1).execute_with(|| {
let old_hotkey = U256::from(1);
let new_hotkey = U256::from(2);
let coldkey = U256::from(3);
let new_hotkey_2 = U256::from(3);
let coldkey = U256::from(4);

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

Expand All @@ -519,12 +520,12 @@ fn test_swap_hotkey_with_multiple_subnets() {
assert_ok!(SubtensorModule::do_swap_hotkey(
RuntimeOrigin::signed(coldkey),
&old_hotkey,
&new_hotkey,
&new_hotkey_2,
Some(netuid2)
));

assert!(IsNetworkMember::<Test>::get(new_hotkey, netuid1));
assert!(IsNetworkMember::<Test>::get(new_hotkey, netuid2));
assert!(IsNetworkMember::<Test>::get(new_hotkey_2, netuid2));
assert!(!IsNetworkMember::<Test>::get(old_hotkey, netuid1));
assert!(!IsNetworkMember::<Test>::get(old_hotkey, netuid2));
});
Expand Down Expand Up @@ -628,8 +629,9 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
new_test_ext(1).execute_with(|| {
let old_hotkey = U256::from(1);
let new_hotkey = U256::from(2);
let coldkey1 = U256::from(3);
let coldkey2 = U256::from(4);
let new_hotkey_2 = U256::from(3);
let coldkey1 = U256::from(4);
let coldkey2 = U256::from(5);
let netuid1 = NetUid::from(1);
let netuid2 = NetUid::from(2);
let stake = DefaultMinStake::<Test>::get() * 10;
Expand Down Expand Up @@ -687,7 +689,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
assert_ok!(SubtensorModule::do_swap_hotkey(
RuntimeOrigin::signed(coldkey1),
&old_hotkey,
&new_hotkey,
&new_hotkey_2,
Some(netuid2)
));

Expand All @@ -697,6 +699,11 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
coldkey1
);
assert!(!SubtensorModule::get_owned_hotkeys(&coldkey2).contains(&new_hotkey));
assert_eq!(
SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey_2),
coldkey1
);
assert!(!SubtensorModule::get_owned_hotkeys(&coldkey2).contains(&new_hotkey_2));

// Check stake transfer
assert_eq!(
Expand All @@ -709,7 +716,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
);
assert_eq!(
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
&new_hotkey,
&new_hotkey_2,
&coldkey2,
netuid2
),
Expand Down Expand Up @@ -739,7 +746,7 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
));
assert!(SubtensorModule::is_hotkey_registered_on_network(
netuid2,
&new_hotkey
&new_hotkey_2
));
assert!(!SubtensorModule::is_hotkey_registered_on_network(
netuid1,
Expand All @@ -752,7 +759,8 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {

// Check total stake transfer
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&new_hotkey),
SubtensorModule::get_total_stake_for_hotkey(&new_hotkey)
+ SubtensorModule::get_total_stake_for_hotkey(&new_hotkey_2),
total_hk_stake
);
assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&old_hotkey), 0);
Expand Down Expand Up @@ -1143,7 +1151,8 @@ fn test_swap_multiple_subnets() {
new_test_ext(1).execute_with(|| {
let old_hotkey = U256::from(1);
let new_hotkey = U256::from(2);
let coldkey = U256::from(3);
let new_hotkey_2 = U256::from(3);
let coldkey = U256::from(4);
let netuid1 = add_dynamic_network(&old_hotkey, &coldkey);
let netuid2 = add_dynamic_network(&old_hotkey, &coldkey);

Expand All @@ -1169,13 +1178,13 @@ fn test_swap_multiple_subnets() {
assert_ok!(SubtensorModule::do_swap_hotkey(
RuntimeOrigin::signed(coldkey),
&old_hotkey,
&new_hotkey,
&new_hotkey_2,
Some(netuid2)
),);

// Verify the swap for both subnets
assert_eq!(ChildKeys::<Test>::get(new_hotkey, netuid1), children1);
assert_eq!(ChildKeys::<Test>::get(new_hotkey, netuid2), children2);
assert_eq!(ChildKeys::<Test>::get(new_hotkey_2, netuid2), children2);
assert!(ChildKeys::<Test>::get(old_hotkey, netuid1).is_empty());
assert!(ChildKeys::<Test>::get(old_hotkey, netuid2).is_empty());
});
Expand Down Expand Up @@ -1490,7 +1499,6 @@ fn test_swap_owner_check_swap_record_clean_up() {
let old_hotkey = U256::from(1);
let new_hotkey = U256::from(2);
let coldkey = U256::from(3);

let netuid = add_dynamic_network(&old_hotkey, &coldkey);
SubtensorModule::add_balance_to_coldkey_account(&coldkey, u64::MAX);
Owner::<Test>::insert(old_hotkey, coldkey);
Expand All @@ -1514,3 +1522,37 @@ fn test_swap_owner_check_swap_record_clean_up() {
));
});
}

// 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::<Test>::insert(old_hotkey, coldkey);
TotalNetworks::<Test>::put(1);
LastTxBlock::<Test>::insert(coldkey, 0);

let initial_balance = SubtensorModule::get_key_swap_cost() + 1000;
SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_balance);

// Test new hotkey already registered on other subnet
IsNetworkMember::<Test>::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::<Test>::HotKeyAlreadyRegisteredInSubNet
);
});
}
6 changes: 5 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 276,
spec_version: 278,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down Expand Up @@ -829,6 +829,10 @@ impl InstanceFilter<RuntimeCall> for ProxyType {
}
_ => false,
},
ProxyType::SwapHotkey => matches!(
c,
RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_hotkey { .. })
),
}
}
fn is_superset(&self, o: &Self) -> bool {
Expand Down
Loading