Skip to content

Commit dbea365

Browse files
committed
Add migration to populate StakingHotkeys, unstake delegations in do_unstake_all_and_transfer_to_new_coldkey
1 parent a62975c commit dbea365

File tree

5 files changed

+134
-4
lines changed

5 files changed

+134
-4
lines changed

pallets/subtensor/src/lib.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ pub mod pallet {
380380
ValueQuery,
381381
DefaultAccountTake<T>,
382382
>;
383+
#[pallet::storage] // --- DMAP ( cold ) --> Vec<hot> | Maps coldkey to hotkeys that stake to it
384+
pub type StakingHotkeys<T: Config> =
385+
StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;
383386
/// -- ITEM (switches liquid alpha on)
384387
#[pallet::type_value]
385388
pub fn DefaultLiquidAlpha<T: Config>() -> bool {
@@ -1225,6 +1228,13 @@ pub mod pallet {
12251228

12261229
Stake::<T>::insert(hotkey.clone(), coldkey.clone(), stake);
12271230

1231+
// Update StakingHotkeys map
1232+
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
1233+
if !staking_hotkeys.contains(hotkey) {
1234+
staking_hotkeys.push(hotkey.clone());
1235+
StakingHotkeys::<T>::insert(coldkey, staking_hotkeys);
1236+
}
1237+
12281238
next_uid = next_uid.checked_add(1).expect(
12291239
"should not have total number of hotkey accounts larger than u16::MAX",
12301240
);
@@ -1337,7 +1347,9 @@ pub mod pallet {
13371347
// Doesn't check storage version. TODO: Remove after upgrade
13381348
.saturating_add(migration::migration5_total_issuance::<T>(false))
13391349
// Populate OwnedHotkeys map for coldkey swap. Doesn't update storage vesion.
1340-
.saturating_add(migration::migrate_populate_owned::<T>());
1350+
.saturating_add(migration::migrate_populate_owned::<T>())
1351+
// Populate StakingHotkeys map for coldkey swap. Doesn't update storage vesion.
1352+
.saturating_add(migration::migrate_populate_staking_hotkeys::<T>());
13411353

13421354
weight
13431355
}

pallets/subtensor/src/migration.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,3 +539,66 @@ pub fn migrate_populate_owned<T: Config>() -> Weight {
539539
Weight::zero()
540540
}
541541
}
542+
543+
/// Populate the StakingHotkeys map from Stake map
544+
pub fn migrate_populate_staking_hotkeys<T: Config>() -> Weight {
545+
// Setup migration weight
546+
let mut weight = T::DbWeight::get().reads(1);
547+
let migration_name = "Populate StakingHotkeys map";
548+
549+
// Check if this migration is needed (if StakingHotkeys map is empty)
550+
let migrate = StakingHotkeys::<T>::iter().next().is_none();
551+
552+
// Only runs if the migration is needed
553+
if migrate {
554+
info!(target: LOG_TARGET_1, ">>> Starting Migration: {}", migration_name);
555+
556+
let mut longest_hotkey_vector: usize = 0;
557+
let mut longest_coldkey: Option<T::AccountId> = None;
558+
let mut keys_touched: u64 = 0;
559+
let mut storage_reads: u64 = 0;
560+
let mut storage_writes: u64 = 0;
561+
562+
// Iterate through all Owner entries
563+
Stake::<T>::iter().for_each(|(hotkey, coldkey, _stake)| {
564+
storage_reads = storage_reads.saturating_add(1); // Read from Owner storage
565+
let mut hotkeys = StakingHotkeys::<T>::get(&coldkey);
566+
storage_reads = storage_reads.saturating_add(1); // Read from StakingHotkeys storage
567+
568+
// Add the hotkey if it's not already in the vector
569+
if !hotkeys.contains(&hotkey) {
570+
hotkeys.push(hotkey);
571+
keys_touched = keys_touched.saturating_add(1);
572+
573+
// Update longest hotkey vector info
574+
if longest_hotkey_vector < hotkeys.len() {
575+
longest_hotkey_vector = hotkeys.len();
576+
longest_coldkey = Some(coldkey.clone());
577+
}
578+
579+
// Update the StakingHotkeys storage
580+
StakingHotkeys::<T>::insert(&coldkey, hotkeys);
581+
storage_writes = storage_writes.saturating_add(1); // Write to StakingHotkeys storage
582+
}
583+
584+
// Accrue weight for reads and writes
585+
weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1));
586+
});
587+
588+
// Log migration results
589+
info!(
590+
target: LOG_TARGET_1,
591+
"Migration {} finished. Keys touched: {}, Longest hotkey vector: {}, Storage reads: {}, Storage writes: {}",
592+
migration_name, keys_touched, longest_hotkey_vector, storage_reads, storage_writes
593+
);
594+
if let Some(c) = longest_coldkey {
595+
info!(target: LOG_TARGET_1, "Longest hotkey vector is controlled by: {:?}", c);
596+
}
597+
598+
weight
599+
} else {
600+
info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name);
601+
Weight::zero()
602+
}
603+
}
604+

pallets/subtensor/src/staking.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,13 @@ impl<T: Config> Pallet<T> {
569569
hotkeys.push(hotkey.clone());
570570
OwnedHotkeys::<T>::insert(coldkey, hotkeys);
571571
}
572+
573+
// Update StakingHotkeys map
574+
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
575+
if !staking_hotkeys.contains(hotkey) {
576+
staking_hotkeys.push(hotkey.clone());
577+
StakingHotkeys::<T>::insert(coldkey, staking_hotkeys);
578+
}
572579
}
573580
}
574581

@@ -648,6 +655,13 @@ impl<T: Config> Pallet<T> {
648655
Stake::<T>::get(hotkey, coldkey).saturating_add(increment),
649656
);
650657
TotalStake::<T>::put(TotalStake::<T>::get().saturating_add(increment));
658+
659+
// Update StakingHotkeys map
660+
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
661+
if !staking_hotkeys.contains(hotkey) {
662+
staking_hotkeys.push(hotkey.clone());
663+
StakingHotkeys::<T>::insert(coldkey, staking_hotkeys);
664+
}
651665
}
652666

653667
// Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters.
@@ -668,6 +682,8 @@ impl<T: Config> Pallet<T> {
668682
Stake::<T>::get(hotkey, coldkey).saturating_sub(decrement),
669683
);
670684
TotalStake::<T>::put(TotalStake::<T>::get().saturating_sub(decrement));
685+
686+
// TODO: Tech debt: Remove StakingHotkeys entry if stake goes to 0
671687
}
672688

673689
/// Empties the stake associated with a given coldkey-hotkey account pairing.
@@ -693,6 +709,11 @@ impl<T: Config> Pallet<T> {
693709
TotalStake::<T>::mutate(|stake| *stake = stake.saturating_sub(current_stake));
694710
TotalIssuance::<T>::mutate(|issuance| *issuance = issuance.saturating_sub(current_stake));
695711

712+
// Update StakingHotkeys map
713+
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
714+
staking_hotkeys.retain(|h| h != hotkey);
715+
StakingHotkeys::<T>::insert(coldkey, staking_hotkeys);
716+
696717
current_stake
697718
}
698719

@@ -897,6 +918,25 @@ impl<T: Config> Pallet<T> {
897918
}
898919
}
899920

921+
// Unstake all delegate stake make by this coldkey to non-owned hotkeys
922+
let staking_hotkeys = StakingHotkeys::<T>::get(&current_coldkey);
923+
924+
// iterate over all staking hotkeys.
925+
for hotkey in staking_hotkeys {
926+
// Get the current stake
927+
let current_stake: u64 =
928+
Self::get_stake_for_coldkey_and_hotkey(&current_coldkey, &hotkey);
929+
930+
// Unstake all balance if there's any stake
931+
if current_stake > 0 {
932+
Self::do_remove_stake(
933+
RawOrigin::Signed(current_coldkey.clone()).into(),
934+
hotkey.clone(),
935+
current_stake,
936+
)?;
937+
}
938+
}
939+
900940
let total_balance = Self::get_coldkey_balance(&current_coldkey);
901941
log::info!("Total Bank Balance: {:?}", total_balance);
902942

pallets/subtensor/src/swap.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,22 @@ impl<T: Config> Pallet<T> {
272272
for (coldkey, stake_amount) in stakes {
273273
Stake::<T>::insert(new_hotkey, &coldkey, stake_amount);
274274
writes = writes.saturating_add(1u64); // One write for insert
275+
276+
// Update StakingHotkeys map
277+
let mut staking_hotkeys = StakingHotkeys::<T>::get(&coldkey);
278+
if !staking_hotkeys.contains(new_hotkey) {
279+
staking_hotkeys.push(new_hotkey.clone());
280+
StakingHotkeys::<T>::insert(coldkey.clone(), staking_hotkeys);
281+
writes = writes.saturating_add(1u64); // One write for insert
282+
}
275283
}
276284

277285
// Clear the prefix for the old hotkey after transferring all stakes
278286
let _ = Stake::<T>::clear_prefix(old_hotkey, stake_count, None);
279287
writes = writes.saturating_add(1); // One write for insert; // One write for clear_prefix
280288

289+
// TODO: Remove all entries for old hotkey from StakingHotkeys map
290+
281291
weight.saturating_accrue(T::DbWeight::get().writes(writes));
282292
}
283293

@@ -521,7 +531,12 @@ impl<T: Config> Pallet<T> {
521531
let stake = Stake::<T>::get(&hotkey, old_coldkey);
522532
Stake::<T>::remove(&hotkey, old_coldkey);
523533
Stake::<T>::insert(&hotkey, new_coldkey, stake);
524-
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
534+
535+
// Update StakingHotkeys map
536+
let staking_hotkeys = StakingHotkeys::<T>::get(old_coldkey);
537+
StakingHotkeys::<T>::insert(new_coldkey.clone(), staking_hotkeys);
538+
539+
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 3));
525540
}
526541
}
527542

pallets/subtensor/tests/swap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ fn test_swap_stake_weight_update() {
625625
SubtensorModule::swap_stake(&old_hotkey, &new_hotkey, &mut weight);
626626

627627
// Verify the weight update
628-
let expected_weight = <Test as frame_system::Config>::DbWeight::get().writes(2);
628+
let expected_weight = <Test as frame_system::Config>::DbWeight::get().writes(3);
629629
assert_eq!(weight, expected_weight);
630630
});
631631
}
@@ -1213,7 +1213,7 @@ fn test_swap_stake_for_coldkey() {
12131213
assert_eq!(TotalIssuance::<Test>::get(), stake_amount1 + stake_amount2);
12141214

12151215
// Verify weight update
1216-
let expected_weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(3, 4);
1216+
let expected_weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(5, 6);
12171217
assert_eq!(weight, expected_weight);
12181218
});
12191219
}

0 commit comments

Comments
 (0)