Skip to content

Commit 2cce56e

Browse files
committed
- Applied changes from #2527
- Enable hotkey swap extrinsic - Bumped runtime version
1 parent f0e1faf commit 2cce56e

8 files changed

Lines changed: 690 additions & 142 deletions

File tree

pallets/subtensor/src/macros/hooks.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ mod hooks {
168168
// Migrate coldkey swap scheduled to announcements
169169
.saturating_add(migrations::migrate_coldkey_swap_scheduled_to_announcements::migrate_coldkey_swap_scheduled_to_announcements::<T>())
170170
// Migrate fix bad hk swap
171-
.saturating_add(migrations::migrate_fix_bad_hk_swap::migrate_fix_bad_hk_swap::<T>());
171+
.saturating_add(migrations::migrate_fix_bad_hk_swap::migrate_fix_bad_hk_swap::<T>())
172+
// Fix RootClaimed overclaim caused by single-subnet hotkey swap bug
173+
.saturating_add(migrations::migrate_fix_root_claimed_overclaim::migrate_fix_root_claimed_overclaim::<T>());
172174
weight
173175
}
174176

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use super::*;
2+
use frame_support::pallet_prelude::Weight;
3+
use frame_system::pallet_prelude::BlockNumberFor;
4+
use scale_info::prelude::string::String;
5+
use sp_core::crypto::Ss58Codec;
6+
use sp_runtime::AccountId32;
7+
use substrate_fixed::types::U64F64;
8+
9+
pub fn decode_account_id32<T: Config>(ss58_string: &str) -> Option<T::AccountId> {
10+
let account_id32: AccountId32 = AccountId32::from_ss58check(ss58_string).ok()?;
11+
let mut account_id32_slice: &[u8] = account_id32.as_ref();
12+
T::AccountId::decode(&mut account_id32_slice).ok()
13+
}
14+
15+
/// Fixes the consequences of a bug in `perform_hotkey_swap_on_one_subnet` where
16+
/// `transfer_root_claimable_for_new_hotkey` unconditionally transferred the **entire**
17+
/// `RootClaimable` BTreeMap (all subnets) from the old hotkey to the new hotkey, even
18+
/// during a single-subnet swap.
19+
///
20+
/// This left the old hotkey with:
21+
/// - `RootClaimable[old_hotkey]` = empty (wiped for ALL subnets)
22+
/// - `RootClaimed[(subnet, old_hotkey, coldkey)]` = old watermarks (for non-swapped subnets)
23+
///
24+
/// Resulting in `owed = claimable_rate * root_stake - root_claimed = 0 - positive = negative → 0`,
25+
/// effectively freezing root dividends for the old hotkey.
26+
///
27+
/// Remediation: restore the pre-swap `RootClaimable` and `RootClaimed` storage maps
28+
pub fn migrate_fix_root_claimed_overclaim<T: Config>() -> Weight {
29+
let migration_name = b"migrate_fix_root_claimed_overclaim".to_vec();
30+
let mut weight = T::DbWeight::get().reads(1);
31+
32+
if HasMigrationRun::<T>::get(&migration_name) {
33+
log::info!(
34+
"Migration '{:?}' has already run. Skipping.",
35+
String::from_utf8_lossy(&migration_name)
36+
);
37+
return weight;
38+
}
39+
40+
log::info!(
41+
"Running migration '{}'",
42+
String::from_utf8_lossy(&migration_name)
43+
);
44+
45+
// Only run on mainnet.
46+
// Mainnet genesis: 0x2f0555cc76fc2840a25a6ea3b9637146806f1f44b090c175ffde2a7e5ab36c03
47+
let genesis_hash = frame_system::Pallet::<T>::block_hash(BlockNumberFor::<T>::zero());
48+
let genesis_bytes = genesis_hash.as_ref();
49+
let mainnet_genesis =
50+
hex_literal::hex!("2f0555cc76fc2840a25a6ea3b9637146806f1f44b090c175ffde2a7e5ab36c03");
51+
if genesis_bytes == mainnet_genesis {
52+
let old_hotkey_ss58 = "5GmvyePN9aYErXBBhBnxZKGoGk4LKZApE4NkaSzW62CYCYNA";
53+
let new_hotkey_ss58 = "5H6BqkzjYvViiqp7rQLXjpnaEmW7U9CoKxXhQ4efMqtX1mQw";
54+
let netuid = NetUid::from(27);
55+
56+
if let (Some(old_hotkey), Some(new_hotkey)) = (
57+
decode_account_id32::<T>(old_hotkey_ss58),
58+
decode_account_id32::<T>(new_hotkey_ss58),
59+
) {
60+
// Reverting the Root Claimable because it only should happen for root subnet
61+
Pallet::<T>::transfer_root_claimable_for_new_hotkey(&new_hotkey, &old_hotkey);
62+
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
63+
64+
let alpha_values: Vec<((T::AccountId, NetUid), U64F64)> =
65+
Alpha::<T>::iter_prefix((&new_hotkey,)).collect();
66+
weight.saturating_accrue(T::DbWeight::get().reads(alpha_values.len() as u64));
67+
68+
// Reverting back root claimed
69+
for ((coldkey, _), _) in alpha_values
70+
.into_iter()
71+
.filter(|((_, netuid_alpha), alpha)| *netuid_alpha == netuid && *alpha != 0)
72+
{
73+
Pallet::<T>::transfer_root_claimed_for_new_keys(
74+
netuid,
75+
&new_hotkey,
76+
&old_hotkey,
77+
&coldkey,
78+
&coldkey,
79+
);
80+
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
81+
}
82+
} else {
83+
log::error!("Failed to decode hotkeys, skipping");
84+
}
85+
}
86+
87+
// Mark migration as completed
88+
HasMigrationRun::<T>::insert(&migration_name, true);
89+
weight.saturating_accrue(T::DbWeight::get().writes(1));
90+
91+
log::info!("Migration 'migrate_fix_root_claimed_overclaim' completed.");
92+
93+
weight
94+
}

pallets/subtensor/src/migrations/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub mod migrate_disable_commit_reveal;
1919
pub mod migrate_fix_bad_hk_swap;
2020
pub mod migrate_fix_childkeys;
2121
pub mod migrate_fix_is_network_member;
22+
pub mod migrate_fix_root_claimed_overclaim;
2223
pub mod migrate_fix_root_subnet_tao;
2324
pub mod migrate_fix_root_tao_and_alpha_in;
2425
pub mod migrate_fix_staking_hot_keys;

0 commit comments

Comments
 (0)