Skip to content

Commit 0c2ad41

Browse files
authored
Merge pull request #636 from opentensor/total_coldkey_migration
Total coldkey migration
2 parents 884a179 + ff23b6f commit 0c2ad41

File tree

8 files changed

+542
-186
lines changed

8 files changed

+542
-186
lines changed

pallets/subtensor/src/benchmarks.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -314,33 +314,33 @@ benchmarks! {
314314
assert_ok!(Subtensor::<T>::register_network(RawOrigin::Signed(coldkey.clone()).into()));
315315
}: dissolve_network(RawOrigin::Signed(coldkey), 1)
316316

317-
swap_hotkey {
318-
let seed: u32 = 1;
319-
let coldkey: T::AccountId = account("Alice", 0, seed);
320-
let old_hotkey: T::AccountId = account("Bob", 0, seed);
321-
let new_hotkey: T::AccountId = account("Charlie", 0, seed);
322-
323-
let netuid = 1u16;
324-
Subtensor::<T>::init_new_network(netuid, 100);
325-
Subtensor::<T>::set_min_burn(netuid, 1);
326-
Subtensor::<T>::set_max_burn(netuid, 1);
327-
Subtensor::<T>::set_target_registrations_per_interval(netuid, 256);
328-
Subtensor::<T>::set_max_registrations_per_block(netuid, 256);
329-
330-
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64);
331-
assert_ok!(Subtensor::<T>::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, old_hotkey.clone()));
332-
assert_ok!(Subtensor::<T>::become_delegate(RawOrigin::Signed(coldkey.clone()).into(), old_hotkey.clone()));
333-
334-
let max_uids = Subtensor::<T>::get_max_allowed_uids(netuid) as u32;
335-
for i in 0..max_uids - 1 {
336-
let coldkey: T::AccountId = account("Axon", 0, i);
337-
let hotkey: T::AccountId = account("Hotkey", 0, i);
338-
339-
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64);
340-
assert_ok!(Subtensor::<T>::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey));
341-
assert_ok!(Subtensor::<T>::add_stake(RawOrigin::Signed(coldkey).into(), old_hotkey.clone(), 1_000_000_000));
342-
}
343-
}: _(RawOrigin::Signed(coldkey), old_hotkey, new_hotkey)
317+
// swap_hotkey {
318+
// let seed: u32 = 1;
319+
// let coldkey: T::AccountId = account("Alice", 0, seed);
320+
// let old_hotkey: T::AccountId = account("Bob", 0, seed);
321+
// let new_hotkey: T::AccountId = account("Charlie", 0, seed);
322+
323+
// let netuid = 1u16;
324+
// Subtensor::<T>::init_new_network(netuid, 100);
325+
// Subtensor::<T>::set_min_burn(netuid, 1);
326+
// Subtensor::<T>::set_max_burn(netuid, 1);
327+
// Subtensor::<T>::set_target_registrations_per_interval(netuid, 256);
328+
// Subtensor::<T>::set_max_registrations_per_block(netuid, 256);
329+
330+
// Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64);
331+
// assert_ok!(Subtensor::<T>::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, old_hotkey.clone()));
332+
// assert_ok!(Subtensor::<T>::become_delegate(RawOrigin::Signed(coldkey.clone()).into(), old_hotkey.clone()));
333+
334+
// let max_uids = Subtensor::<T>::get_max_allowed_uids(netuid) as u32;
335+
// for i in 0..max_uids - 1 {
336+
// let coldkey: T::AccountId = account("Axon", 0, i);
337+
// let hotkey: T::AccountId = account("Hotkey", 0, i);
338+
339+
// Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64);
340+
// assert_ok!(Subtensor::<T>::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey));
341+
// assert_ok!(Subtensor::<T>::add_stake(RawOrigin::Signed(coldkey).into(), old_hotkey.clone(), 1_000_000_000));
342+
// }
343+
// }: _(RawOrigin::Signed(coldkey), old_hotkey, new_hotkey)
344344

345345
commit_weights {
346346
let tempo: u16 = 1;

pallets/subtensor/src/lib.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,9 @@ pub mod pallet {
14191419
// Populate OwnedHotkeys map for coldkey swap. Doesn't update storage vesion.
14201420
.saturating_add(migration::migrate_populate_owned::<T>())
14211421
// Populate StakingHotkeys map for coldkey swap. Doesn't update storage vesion.
1422-
.saturating_add(migration::migrate_populate_staking_hotkeys::<T>());
1422+
.saturating_add(migration::migrate_populate_staking_hotkeys::<T>())
1423+
// Fix total coldkey stake.
1424+
.saturating_add(migration::migrate_fix_total_coldkey_stake::<T>());
14231425

14241426
weight
14251427
}
@@ -2061,17 +2063,17 @@ pub mod pallet {
20612063
}
20622064

20632065
/// The extrinsic for user to change its hotkey
2064-
#[pallet::call_index(70)]
2065-
#[pallet::weight((Weight::from_parts(1_940_000_000, 0)
2066-
.saturating_add(T::DbWeight::get().reads(272))
2067-
.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))]
2068-
pub fn swap_hotkey(
2069-
origin: OriginFor<T>,
2070-
hotkey: T::AccountId,
2071-
new_hotkey: T::AccountId,
2072-
) -> DispatchResultWithPostInfo {
2073-
Self::do_swap_hotkey(origin, &hotkey, &new_hotkey)
2074-
}
2066+
///#[pallet::call_index(70)]
2067+
///#[pallet::weight((Weight::from_parts(1_940_000_000, 0)
2068+
///.saturating_add(T::DbWeight::get().reads(272))
2069+
///.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))]
2070+
///pub fn swap_hotkey(
2071+
/// origin: OriginFor<T>,
2072+
/// hotkey: T::AccountId,
2073+
/// new_hotkey: T::AccountId,
2074+
///) -> DispatchResultWithPostInfo {
2075+
/// Self::do_swap_hotkey(origin, &hotkey, &new_hotkey)
2076+
///}
20752077
20762078
/// The extrinsic for user to change the coldkey associated with their account.
20772079
///
@@ -2253,6 +2255,17 @@ pub mod pallet {
22532255
pub fn dissolve_network(origin: OriginFor<T>, netuid: u16) -> DispatchResult {
22542256
Self::user_remove_network(origin, netuid)
22552257
}
2258+
2259+
/// Sets values for liquid alpha
2260+
#[pallet::call_index(64)]
2261+
#[pallet::weight((0, DispatchClass::Operational, Pays::No))]
2262+
pub fn sudo_hotfix_swap_coldkey_delegates(
2263+
_origin: OriginFor<T>,
2264+
_old_coldkey: T::AccountId,
2265+
_new_coldkey: T::AccountId,
2266+
) -> DispatchResult {
2267+
Ok(())
2268+
}
22562269
}
22572270

22582271
// ---- Subtensor helper functions.

pallets/subtensor/src/migration.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,62 @@ pub mod deprecated_loaded_emission_format {
2424
StorageMap<Pallet<T>, Identity, u16, Vec<(AccountIdOf<T>, u64)>, OptionQuery>;
2525
}
2626

27+
/// Migrates and fixes the total coldkey stake.
28+
///
29+
/// This function iterates through all staking hotkeys, calculates the total stake for each coldkey,
30+
/// and updates the `TotalColdkeyStake` storage accordingly. The migration is only performed if the
31+
/// on-chain storage version is 6.
32+
///
33+
/// # Returns
34+
/// The weight of the migration process.
35+
pub fn do_migrate_fix_total_coldkey_stake<T: Config>() -> Weight {
36+
// Initialize the weight with one read operation.
37+
let mut weight = T::DbWeight::get().reads(1);
38+
39+
// Iterate through all staking hotkeys.
40+
for (coldkey, hotkey_vec) in StakingHotkeys::<T>::iter() {
41+
// Init the zero value.
42+
let mut coldkey_stake_sum: u64 = 0;
43+
weight = weight.saturating_add(T::DbWeight::get().reads(1));
44+
45+
// Calculate the total stake for the current coldkey.
46+
for hotkey in hotkey_vec {
47+
// Cant fail on retrieval.
48+
coldkey_stake_sum =
49+
coldkey_stake_sum.saturating_add(Stake::<T>::get(hotkey, coldkey.clone()));
50+
weight = weight.saturating_add(T::DbWeight::get().reads(1));
51+
}
52+
// Update the `TotalColdkeyStake` storage with the calculated stake sum.
53+
// Cant fail on insert.
54+
TotalColdkeyStake::<T>::insert(coldkey.clone(), coldkey_stake_sum);
55+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
56+
}
57+
weight
58+
}
59+
// Public migrate function to be called by Lib.rs on upgrade.
60+
pub fn migrate_fix_total_coldkey_stake<T: Config>() -> Weight {
61+
let current_storage_version: u16 = 7;
62+
let next_storage_version: u16 = 8;
63+
64+
// Initialize the weight with one read operation.
65+
let mut weight = T::DbWeight::get().reads(1);
66+
67+
// Grab the current on-chain storage version.
68+
// Cant fail on retrieval.
69+
let onchain_version = Pallet::<T>::on_chain_storage_version();
70+
71+
// Only run this migration on storage version 6.
72+
if onchain_version == current_storage_version {
73+
weight = weight.saturating_add(do_migrate_fix_total_coldkey_stake::<T>());
74+
// Cant fail on insert.
75+
StorageVersion::new(next_storage_version).put::<Pallet<T>>();
76+
weight.saturating_accrue(T::DbWeight::get().writes(1));
77+
}
78+
79+
// Return the migration weight.
80+
weight
81+
}
82+
2783
/// Performs migration to update the total issuance based on the sum of stakes and total balances.
2884
/// This migration is applicable only if the current storage version is 5, after which it updates the storage version to 6.
2985
///

pallets/subtensor/src/swap.rs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,8 @@ impl<T: Config> Pallet<T> {
851851
log::info!("Transferring stake for hotkey {:?}: {}", hotkey, stake);
852852
if stake > 0 {
853853
// Insert the stake for the hotkey and new coldkey
854-
Stake::<T>::insert(hotkey, new_coldkey, stake);
854+
let old_stake = Stake::<T>::get(hotkey, new_coldkey);
855+
Stake::<T>::insert(hotkey, new_coldkey, stake.saturating_add(old_stake));
855856
total_transferred_stake = total_transferred_stake.saturating_add(stake);
856857

857858
// Update the owner of the hotkey to the new coldkey
@@ -861,6 +862,52 @@ impl<T: Config> Pallet<T> {
861862
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
862863
}
863864
}
865+
log::info!(
866+
"Starting transfer of delegated stakes for old coldkey: {:?}",
867+
old_coldkey
868+
);
869+
870+
for staking_hotkey in StakingHotkeys::<T>::get(old_coldkey) {
871+
log::info!("Processing staking hotkey: {:?}", staking_hotkey);
872+
if Stake::<T>::contains_key(staking_hotkey.clone(), old_coldkey) {
873+
let hotkey = &staking_hotkey;
874+
// Retrieve and remove the stake associated with the hotkey and old coldkey
875+
let stake: u64 = Stake::<T>::get(hotkey, old_coldkey);
876+
Stake::<T>::remove(hotkey, old_coldkey);
877+
log::info!(
878+
"Transferring delegated stake for hotkey {:?}: {}",
879+
hotkey,
880+
stake
881+
);
882+
if stake > 0 {
883+
// Insert the stake for the hotkey and new coldkey
884+
let old_stake = Stake::<T>::get(hotkey, new_coldkey);
885+
Stake::<T>::insert(hotkey, new_coldkey, stake.saturating_add(old_stake));
886+
total_transferred_stake = total_transferred_stake.saturating_add(stake);
887+
log::info!(
888+
"Updated stake for hotkey {:?} under new coldkey {:?}: {}",
889+
hotkey,
890+
new_coldkey,
891+
stake.saturating_add(old_stake)
892+
);
893+
894+
// Update the transaction weight
895+
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1));
896+
}
897+
} else {
898+
log::info!(
899+
"No stake found for staking hotkey {:?} under old coldkey {:?}",
900+
staking_hotkey,
901+
old_coldkey
902+
);
903+
weight.saturating_accrue(T::DbWeight::get().reads(1));
904+
}
905+
}
906+
907+
log::info!(
908+
"Completed transfer of delegated stakes for old coldkey: {:?}",
909+
old_coldkey
910+
);
864911

865912
// Log the total transferred stake
866913
log::info!("Total transferred stake: {}", total_transferred_stake);
@@ -888,13 +935,30 @@ impl<T: Config> Pallet<T> {
888935
}
889936

890937
// Update the list of owned hotkeys for both old and new coldkeys
938+
939+
let mut new_owned_hotkeys = OwnedHotkeys::<T>::get(new_coldkey);
940+
for hotkey in old_owned_hotkeys {
941+
if !new_owned_hotkeys.contains(&hotkey) {
942+
new_owned_hotkeys.push(hotkey);
943+
}
944+
}
945+
946+
OwnedHotkeys::<T>::insert(new_coldkey, new_owned_hotkeys);
891947
OwnedHotkeys::<T>::remove(old_coldkey);
892-
OwnedHotkeys::<T>::insert(new_coldkey, old_owned_hotkeys);
893948
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
894949

895950
// Update the staking hotkeys for both old and new coldkeys
896-
let staking_hotkeys: Vec<T::AccountId> = StakingHotkeys::<T>::take(old_coldkey);
897-
StakingHotkeys::<T>::insert(new_coldkey, staking_hotkeys);
951+
let staking_hotkeys: Vec<T::AccountId> = StakingHotkeys::<T>::get(old_coldkey);
952+
953+
let mut existing_staking_hotkeys = StakingHotkeys::<T>::get(new_coldkey);
954+
for hotkey in staking_hotkeys {
955+
if !existing_staking_hotkeys.contains(&hotkey) {
956+
existing_staking_hotkeys.push(hotkey);
957+
}
958+
}
959+
960+
StakingHotkeys::<T>::remove(old_coldkey);
961+
StakingHotkeys::<T>::insert(new_coldkey, existing_staking_hotkeys);
898962
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
899963

900964
// Log the total stake of old and new coldkeys after the swap
@@ -907,6 +971,7 @@ impl<T: Config> Pallet<T> {
907971
TotalColdkeyStake::<T>::get(new_coldkey)
908972
);
909973
}
974+
910975
/// Swaps the total hotkey-coldkey stakes for the current interval from the old coldkey to the new coldkey.
911976
///
912977
/// # Arguments

pallets/subtensor/tests/migration.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod mock;
44
use frame_support::assert_ok;
55
use frame_system::Config;
66
use mock::*;
7+
use pallet_subtensor::*;
78
use sp_core::U256;
89

910
#[test]
@@ -276,3 +277,73 @@ fn test_migration_delete_subnet_21() {
276277
assert!(!SubtensorModule::if_subnet_exist(21));
277278
})
278279
}
280+
281+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test migration -- test_migrate_fix_total_coldkey_stake --exact --nocapture
282+
#[test]
283+
fn test_migrate_fix_total_coldkey_stake() {
284+
new_test_ext(1).execute_with(|| {
285+
let coldkey = U256::from(0);
286+
TotalColdkeyStake::<Test>::insert(coldkey, 0);
287+
StakingHotkeys::<Test>::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]);
288+
Stake::<Test>::insert(U256::from(1), U256::from(0), 10000);
289+
Stake::<Test>::insert(U256::from(2), U256::from(0), 10000);
290+
Stake::<Test>::insert(U256::from(3), U256::from(0), 10000);
291+
pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::<Test>();
292+
assert_eq!(TotalColdkeyStake::<Test>::get(coldkey), 30000);
293+
})
294+
}
295+
296+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test migration -- test_migrate_fix_total_coldkey_stake_value_already_in_total --exact --nocapture
297+
#[test]
298+
fn test_migrate_fix_total_coldkey_stake_value_already_in_total() {
299+
new_test_ext(1).execute_with(|| {
300+
let coldkey = U256::from(0);
301+
TotalColdkeyStake::<Test>::insert(coldkey, 100000000);
302+
StakingHotkeys::<Test>::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]);
303+
Stake::<Test>::insert(U256::from(1), U256::from(0), 10000);
304+
Stake::<Test>::insert(U256::from(2), U256::from(0), 10000);
305+
Stake::<Test>::insert(U256::from(3), U256::from(0), 10000);
306+
pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::<Test>();
307+
assert_eq!(TotalColdkeyStake::<Test>::get(coldkey), 30000);
308+
})
309+
}
310+
311+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test migration -- test_migrate_fix_total_coldkey_stake_no_entry --exact --nocapture
312+
#[test]
313+
fn test_migrate_fix_total_coldkey_stake_no_entry() {
314+
new_test_ext(1).execute_with(|| {
315+
let coldkey = U256::from(0);
316+
StakingHotkeys::<Test>::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]);
317+
Stake::<Test>::insert(U256::from(1), U256::from(0), 10000);
318+
Stake::<Test>::insert(U256::from(2), U256::from(0), 10000);
319+
Stake::<Test>::insert(U256::from(3), U256::from(0), 10000);
320+
pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::<Test>();
321+
assert_eq!(TotalColdkeyStake::<Test>::get(coldkey), 30000);
322+
})
323+
}
324+
325+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test migration -- test_migrate_fix_total_coldkey_stake_no_entry_in_hotkeys --exact --nocapture
326+
#[test]
327+
fn test_migrate_fix_total_coldkey_stake_no_entry_in_hotkeys() {
328+
new_test_ext(1).execute_with(|| {
329+
let coldkey = U256::from(0);
330+
TotalColdkeyStake::<Test>::insert(coldkey, 100000000);
331+
StakingHotkeys::<Test>::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]);
332+
pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::<Test>();
333+
assert_eq!(TotalColdkeyStake::<Test>::get(coldkey), 0);
334+
})
335+
}
336+
337+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test migration -- test_migrate_fix_total_coldkey_stake_one_hotkey_stake_missing --exact --nocapture
338+
#[test]
339+
fn test_migrate_fix_total_coldkey_stake_one_hotkey_stake_missing() {
340+
new_test_ext(1).execute_with(|| {
341+
let coldkey = U256::from(0);
342+
TotalColdkeyStake::<Test>::insert(coldkey, 100000000);
343+
StakingHotkeys::<Test>::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]);
344+
Stake::<Test>::insert(U256::from(1), U256::from(0), 10000);
345+
Stake::<Test>::insert(U256::from(2), U256::from(0), 10000);
346+
pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::<Test>();
347+
assert_eq!(TotalColdkeyStake::<Test>::get(coldkey), 20000);
348+
})
349+
}

0 commit comments

Comments
 (0)