-
Notifications
You must be signed in to change notification settings - Fork 302
Bugfix for: hotkey_swap on a single subnet wipes all root dividend accumulations
#2527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devnet-ready
Are you sure you want to change the base?
Changes from 15 commits
44a39d7
057fa2f
bb59c0c
34d3b61
495e90f
ce1f225
e8d7abe
872fa29
502b531
38f37c5
46e57ae
542b571
04627d6
93a61e7
b9722c7
bc77a99
a538eac
ac35533
f28e120
20a3aba
330d668
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| use super::*; | ||
| use frame_support::pallet_prelude::Weight; | ||
| use frame_system::pallet_prelude::BlockNumberFor; | ||
| use scale_info::prelude::string::String; | ||
| use share_pool::SafeFloat; | ||
| use sp_core::crypto::Ss58Codec; | ||
| use sp_runtime::AccountId32; | ||
| use substrate_fixed::types::U64F64; | ||
|
|
||
| pub fn decode_account_id32<T: Config>(ss58_string: &str) -> Option<T::AccountId> { | ||
| let account_id32: AccountId32 = AccountId32::from_ss58check(ss58_string).ok()?; | ||
| let mut account_id32_slice: &[u8] = account_id32.as_ref(); | ||
| T::AccountId::decode(&mut account_id32_slice).ok() | ||
| } | ||
|
|
||
| /// Fixes the consequences of a bug in `perform_hotkey_swap_on_one_subnet` where | ||
| /// `transfer_root_claimable_for_new_hotkey` unconditionally transferred the **entire** | ||
| /// `RootClaimable` BTreeMap (all subnets) from the old hotkey to the new hotkey, even | ||
| /// during a single-subnet swap. | ||
| /// | ||
| /// This left the old hotkey with: | ||
| /// - `RootClaimable[old_hotkey]` = empty (wiped for ALL subnets) | ||
| /// - `RootClaimed[(subnet, old_hotkey, coldkey)]` = old watermarks (for non-swapped subnets) | ||
| /// | ||
| /// Resulting in `owed = claimable_rate * root_stake - root_claimed = 0 - positive = negative → 0`, | ||
| /// effectively freezing root dividends for the old hotkey. | ||
| /// | ||
| /// Remediation: restore the pre-swap `RootClaimable` and `RootClaimed` storage maps | ||
| pub fn migrate_fix_root_claimed_overclaim<T: Config>() -> Weight { | ||
| let migration_name = b"migrate_fix_root_claimed_overclaim".to_vec(); | ||
| let mut weight = T::DbWeight::get().reads(1); | ||
|
|
||
| if HasMigrationRun::<T>::get(&migration_name) { | ||
| log::info!( | ||
| "Migration '{:?}' has already run. Skipping.", | ||
| String::from_utf8_lossy(&migration_name) | ||
| ); | ||
| return weight; | ||
| } | ||
|
|
||
| log::info!( | ||
| "Running migration '{}'", | ||
| String::from_utf8_lossy(&migration_name) | ||
| ); | ||
|
|
||
| // Only run on mainnet. | ||
| // Mainnet genesis: 0x2f0555cc76fc2840a25a6ea3b9637146806f1f44b090c175ffde2a7e5ab36c03 | ||
| let genesis_hash = frame_system::Pallet::<T>::block_hash(BlockNumberFor::<T>::zero()); | ||
| let genesis_bytes = genesis_hash.as_ref(); | ||
| let mainnet_genesis = | ||
| hex_literal::hex!("2f0555cc76fc2840a25a6ea3b9637146806f1f44b090c175ffde2a7e5ab36c03"); | ||
| if genesis_bytes == mainnet_genesis { | ||
| let old_hotkey_ss58 = "5GmvyePN9aYErXBBhBnxZKGoGk4LKZApE4NkaSzW62CYCYNA"; | ||
| let new_hotkey_ss58 = "5H6BqkzjYvViiqp7rQLXjpnaEmW7U9CoKxXhQ4efMqtX1mQw"; | ||
|
|
||
| if let (Some(old_hotkey), Some(new_hotkey)) = ( | ||
| decode_account_id32::<T>(old_hotkey_ss58), | ||
| decode_account_id32::<T>(new_hotkey_ss58), | ||
| ) { | ||
| let netuid = NetUid::from(27); | ||
|
|
||
| // Reverting the Root Claimable because it only should happen for root subnet | ||
| Pallet::<T>::transfer_root_claimable_for_new_hotkey(&new_hotkey, &old_hotkey); | ||
|
|
||
| let old_alpha_values: Vec<((T::AccountId, NetUid), U64F64)> = | ||
| Alpha::<T>::iter_prefix((&new_hotkey,)).collect(); | ||
| weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values.len() as u64)); | ||
|
|
||
| let old_alpha_values_v2: Vec<((T::AccountId, NetUid), SafeFloat)> = | ||
| AlphaV2::<T>::iter_prefix((&new_hotkey,)).collect(); | ||
| weight.saturating_accrue(T::DbWeight::get().reads(old_alpha_values_v2.len() as u64)); | ||
|
|
||
| // Reverting back root claimable | ||
evgeny-s marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| for ((coldkey, netuid_alpha), alpha) in old_alpha_values { | ||
| if netuid == netuid_alpha && alpha != 0 { | ||
| Pallet::<T>::transfer_root_claimed_for_new_keys( | ||
| netuid, | ||
| &new_hotkey, | ||
| &old_hotkey, | ||
| &coldkey, | ||
| &coldkey, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // Reverting back root claimable | ||
| for ((coldkey, netuid_alpha), alpha) in old_alpha_values_v2 { | ||
| if netuid == netuid_alpha && !alpha.is_zero() { | ||
| Pallet::<T>::transfer_root_claimed_for_new_keys( | ||
| netuid, | ||
| &new_hotkey, | ||
| &old_hotkey, | ||
| &coldkey, | ||
| &coldkey, | ||
| ); | ||
| } | ||
| } | ||
| } else { | ||
| log::error!("Failed to decode hotkeys, skipping"); | ||
| } | ||
| } | ||
|
Comment on lines
+48
to
+103
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be a nice macro @sam0x17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make sure to only clear the RootClaim- able/ed maps if the root stake is still |
||
|
|
||
| // Mark migration as completed | ||
| HasMigrationRun::<T>::insert(&migration_name, true); | ||
| weight.saturating_accrue(T::DbWeight::get().writes(1)); | ||
|
|
||
| log::info!("Migration 'migrate_fix_root_claimed_overclaim' completed."); | ||
|
|
||
| weight | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.