code/pallets/subtensor/src/migrations/migrate_clear_orphan_subnet_identities_v3.rs

migrate_clear_orphan_subnet_identities_v3.rs

71 lines · 2,897 bytes · 19a6485969RawGitHub
use crate::{Config, Event, HasMigrationRun, NetworksAdded, Pallet, SubnetIdentitiesV3, Weight};
use frame_support::traits::Get;
use scale_info::prelude::string::String;
use sp_std::vec::Vec;
use subtensor_runtime_common::NetUid;

/// Remove `SubnetIdentitiesV3` entries that belong to netuids which are no
/// longer registered networks (`!NetworksAdded`).
///
/// Such orphan identities accumulate when a subnet slot is recycled: a new
/// owner registers a subnet in a previously-used netuid without supplying an
/// identity, and the stale identity from the prior owner is left in place,
/// misleading participants about what the subnet is. The registration path
/// (`set_new_network_state`) only writes on `Some(identity)` and never clears a
/// pre-existing entry, and the historical `migrate_subnet_identities_to_v3`
/// migration copied V2 entries unconditionally.
///
/// This mirrors the identity-clear in `do_dissolve_network` as a one-shot
/// upgrade migration: orphan entries are removed and a `SubnetIdentityRemoved`
/// event is emitted for each; identities of live subnets are untouched.
pub fn migrate_clear_orphan_subnet_identities_v3<T: Config>() -> Weight {
    let migration_name = b"migrate_clear_orphan_subnet_identities_v3".to_vec();
    let mut weight = T::DbWeight::get().reads(1);

    if HasMigrationRun::<T>::get(&migration_name) {
        log::info!(
            target: "runtime",
            "Migration '{}' already run - skipping.",
            String::from_utf8_lossy(&migration_name)
        );
        return weight;
    }

    log::info!(
        target: "runtime",
        "Running migration '{}'",
        String::from_utf8_lossy(&migration_name),
    );

    // Collect identity netuids that no longer correspond to a registered subnet.
    // Every scanned key costs an identity-map read plus a NetworksAdded lookup,
    // even when the identity is kept for a live subnet.
    let mut scanned = 0u64;
    let orphan_netuids: Vec<NetUid> = SubnetIdentitiesV3::<T>::iter_keys()
        .filter(|netuid| {
            scanned = scanned.saturating_add(1);
            !NetworksAdded::<T>::get(netuid)
        })
        .collect();
    let removed = orphan_netuids.len() as u64;
    weight = weight.saturating_add(T::DbWeight::get().reads(scanned.saturating_mul(2)));

    for netuid in orphan_netuids {
        SubnetIdentitiesV3::<T>::remove(netuid);
        Pallet::<T>::deposit_event(Event::SubnetIdentityRemoved(netuid));
    }
    weight = weight.saturating_add(T::DbWeight::get().writes(removed));

    HasMigrationRun::<T>::insert(&migration_name, true);
    weight = weight.saturating_add(T::DbWeight::get().writes(1));

    log::info!(
        target: "runtime",
        "Migration '{}' completed. scanned_identities={}, removed_orphans={}",
        String::from_utf8_lossy(&migration_name),
        scanned,
        removed,
    );

    weight
}