use super::*; use frame_support::{traits::Get, weights::Weight}; use scale_info::prelude::string::String; /// Backfill [`ColdkeyCollateralHotkeys`] from existing [`MinerCollateral`] rows. /// /// Collateral rows may exist before this index shipped (testnets / early /// deploys). Without a backfill, lazy indexing can fill the 32-entry cap while /// a legacy unindexed row remains, so a later hotkey swap fails after mutating /// storage. This migration indexes every standing row up to /// [`crate::MAX_COLDKEY_COLLATERAL_HOTKEYS`] per `(netuid, coldkey)`. /// /// Over-cap coldkeys keep their aggregate and MinerCollateral rows; only the /// index stops growing. Coldkey swaps for those coldkeys fail closed with /// [`Error::ColdkeyCollateralIncomplete`] until enough indexed positions drain. /// That branch is unreachable for any realistic mainnet state at first deploy /// (collateral ships with this index), but keeps the maps consistent under the /// pallet's bound. pub fn migrate_coldkey_collateral_hotkeys() -> Weight { let migration_name = b"migrate_coldkey_collateral_hotkeys".to_vec(); let mut weight = T::DbWeight::get().reads(1); if HasMigrationRun::::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) ); let mut indexed = 0_u64; let mut overflowed = 0_u64; for ((netuid, hotkey, coldkey), _state) in MinerCollateral::::iter() { weight.saturating_accrue(T::DbWeight::get().reads(1)); let mut overflow = false; ColdkeyCollateralHotkeys::::mutate(netuid, &coldkey, |hotkeys| { if hotkeys.contains(&hotkey) { return; } if hotkeys.try_push(hotkey.clone()).is_err() { overflow = true; } }); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); if overflow { overflowed = overflowed.saturating_add(1); log::warn!( "migrate_coldkey_collateral_hotkeys: coldkey at cap; left unindexed \ (netuid={netuid:?}, hotkey={hotkey:?}, coldkey={coldkey:?})" ); } else { indexed = indexed.saturating_add(1); } } HasMigrationRun::::insert(&migration_name, true); weight.saturating_accrue(T::DbWeight::get().writes(1)); log::info!( "Migration '{:?}' completed. {} positions indexed, {} over-cap left unindexed.", String::from_utf8_lossy(&migration_name), indexed, overflowed, ); weight }