Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ mod hooks {
// Fix lock state left behind by subnet-scoped hotkey swaps.
.saturating_add(migrations::migrate_fix_subnet_hotkey_lock_swaps::migrate_fix_subnet_hotkey_lock_swaps::<T>())
// Populate reverse lookup index for EVM address associations.
.saturating_add(migrations::migrate_associated_evm_address_index::migrate_associated_evm_address_index::<T>());
.saturating_add(migrations::migrate_associated_evm_address_index::migrate_associated_evm_address_index::<T>())
// Remove orphan SubnetIdentitiesV3 entries left for recycled netuids.
.saturating_add(migrations::migrate_clear_orphan_subnet_identities_v3::migrate_clear_orphan_subnet_identities_v3::<T>());
weight
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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.
let orphan_netuids: Vec<NetUid> = SubnetIdentitiesV3::<T>::iter_keys()
.filter(|netuid| !NetworksAdded::<T>::get(netuid))
.collect();
let removed = orphan_netuids.len() as u64;
weight = weight.saturating_add(T::DbWeight::get().reads(removed));

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.",
String::from_utf8_lossy(&migration_name),
);

weight
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod migrate_associated_evm_address_index;
pub mod migrate_auto_stake_destination;
pub mod migrate_cleanup_swap_v3;
pub mod migrate_clear_deprecated_registration_maps;
pub mod migrate_clear_orphan_subnet_identities_v3;
pub mod migrate_coldkey_swap_scheduled;
pub mod migrate_coldkey_swap_scheduled_to_announcements;
pub mod migrate_commit_reveal_settings;
Expand Down
46 changes: 46 additions & 0 deletions pallets/subtensor/src/tests/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,51 @@ fn test_migrate_associated_evm_address_index() {
});
}

#[test]
fn test_migrate_clear_orphan_subnet_identities_v3() {
new_test_ext(1).execute_with(|| {
let migration_name = b"migrate_clear_orphan_subnet_identities_v3".to_vec();
HasMigrationRun::<Test>::remove(&migration_name);

let orphan_netuid = NetUid::from(1);
let live_netuid = NetUid::from(2);

// live_netuid is a registered network; orphan_netuid is not.
NetworksAdded::<Test>::insert(live_netuid, true);

let orphan_identity = SubnetIdentityV3 {
subnet_name: b"orphan".to_vec(),
..Default::default()
};
let live_identity = SubnetIdentityV3 {
subnet_name: b"live".to_vec(),
..Default::default()
};

SubnetIdentitiesV3::<Test>::insert(orphan_netuid, orphan_identity);
SubnetIdentitiesV3::<Test>::insert(live_netuid, live_identity.clone());

crate::migrations::migrate_clear_orphan_subnet_identities_v3::migrate_clear_orphan_subnet_identities_v3::<Test>();

// The orphan identity is removed; the live subnet identity is preserved.
assert!(!SubnetIdentitiesV3::<Test>::contains_key(orphan_netuid));
assert_eq!(
SubnetIdentitiesV3::<Test>::get(live_netuid),
Some(live_identity.clone())
);

// Migration is marked as run.
assert!(HasMigrationRun::<Test>::get(&migration_name));

// Idempotent: re-running is a no-op (live identity still present).
crate::migrations::migrate_clear_orphan_subnet_identities_v3::migrate_clear_orphan_subnet_identities_v3::<Test>();
assert_eq!(
SubnetIdentitiesV3::<Test>::get(live_netuid),
Some(live_identity)
);
});
}

#[test]
fn test_migrate_associated_evm_address_index_reconciles_over_cap_buckets() {
new_test_ext(1).execute_with(|| {
Expand Down Expand Up @@ -1254,6 +1299,7 @@ fn test_per_u16_encodes_identically_to_u16() {
}

#[test]
#[allow(deprecated)]
fn test_migrate_last_tx_block_delegate_take() {
new_test_ext(1).execute_with(|| {
// ------------------------------
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 429,
spec_version: 432,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down