diff --git a/pallets/subtensor/src/migrations/migrate_fix_subnet_hotkey_lock_swaps.rs b/pallets/subtensor/src/migrations/migrate_fix_subnet_hotkey_lock_swaps.rs index 7ff1dea7c8..93af663092 100644 --- a/pallets/subtensor/src/migrations/migrate_fix_subnet_hotkey_lock_swaps.rs +++ b/pallets/subtensor/src/migrations/migrate_fix_subnet_hotkey_lock_swaps.rs @@ -273,30 +273,51 @@ pub fn migrate_fix_subnet_hotkey_lock_swaps() -> Weight { }; let netuid = NetUid::from(fix.netuid); + let index_reads: u64; + let index_writes: u64; + let lock_take_reads: u64; + let lock_take_writes: u64; let locks_to_fix: Vec<(T::AccountId, LockState)> = if let Some(coldkey) = fix.coldkey { let Some(coldkey) = decode_account_id32::(coldkey) else { log::error!("Failed to decode coldkey: {}", coldkey); continue; }; - Lock::::take((coldkey.clone(), netuid, old_hotkey.clone())) - .map(|lock| vec![(coldkey, lock)]) - .unwrap_or_default() + index_reads = 0; + index_writes = 1; + lock_take_reads = 1; + LockingColdkeys::::remove((netuid, old_hotkey.clone(), coldkey.clone())); + if let Some(lock) = Lock::::take((coldkey.clone(), netuid, old_hotkey.clone())) { + lock_take_writes = 1; + vec![(coldkey, lock)] + } else { + lock_take_writes = 0; + Vec::new() + } } else { - let locks: Vec<(T::AccountId, LockState)> = Lock::::iter() - .filter_map(|((coldkey, lock_netuid, hotkey), lock)| { - (lock_netuid == netuid && hotkey == old_hotkey).then_some((coldkey, lock)) + let coldkeys: Vec = + LockingColdkeys::::iter_prefix((netuid, old_hotkey.clone())) + .map(|(coldkey, ())| coldkey) + .collect(); + let indexed_coldkeys = coldkeys.len() as u64; + index_reads = indexed_coldkeys; + index_writes = indexed_coldkeys; + lock_take_reads = indexed_coldkeys; + + let locks: Vec<(T::AccountId, LockState)> = coldkeys + .into_iter() + .filter_map(|coldkey| { + LockingColdkeys::::remove((netuid, old_hotkey.clone(), coldkey.clone())); + Lock::::take((coldkey.clone(), netuid, old_hotkey.clone())) + .map(|lock| (coldkey, lock)) }) .collect(); - for (coldkey, _) in &locks { - Lock::::remove((coldkey.clone(), netuid, old_hotkey.clone())); - } + lock_take_writes = locks.len() as u64; locks }; - let locks_to_fix_count = locks_to_fix.len() as u64; - weight = weight.saturating_add( - T::DbWeight::get() - .reads_writes(locks_to_fix_count.saturating_add(1), locks_to_fix_count), - ); + weight = weight.saturating_add(T::DbWeight::get().reads_writes( + index_reads.saturating_add(lock_take_reads), + index_writes.saturating_add(lock_take_writes), + )); if locks_to_fix.is_empty() { missing_locks = missing_locks.saturating_add(1); @@ -323,7 +344,8 @@ pub fn migrate_fix_subnet_hotkey_lock_swaps() -> Weight { } Lock::::insert((coldkey.clone(), netuid, new_hotkey.clone()), lock.clone()); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); + LockingColdkeys::::insert((netuid, new_hotkey.clone(), coldkey.clone()), ()); + weight = weight.saturating_add(T::DbWeight::get().writes(2)); if !new_hotkey_is_owner { add_to_aggregate::(&coldkey, netuid, &new_hotkey, &lock); diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index 73cdacac7e..84f20da888 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -123,14 +123,17 @@ fn test_migrate_fix_subnet_hotkey_lock_swaps_moves_or_discards_conflicts() { (coldkey_to_move, netuid, old_hotkey), moved_lock.clone(), ); + LockingColdkeys::::insert((netuid, old_hotkey, coldkey_to_move), ()); Lock::::insert( (coldkey_with_conflict, netuid, old_hotkey), discarded_lock.clone(), ); + LockingColdkeys::::insert((netuid, old_hotkey, coldkey_with_conflict), ()); Lock::::insert( (coldkey_with_conflict, netuid, new_hotkey), existing_destination_lock.clone(), ); + LockingColdkeys::::insert((netuid, new_hotkey, coldkey_with_conflict), ()); DecayingLock::::insert(coldkey_to_move, netuid, false); DecayingLock::::insert(coldkey_with_conflict, netuid, false); DecayingLock::::insert(chained_coldkey, chained_netuid, false); @@ -148,6 +151,10 @@ fn test_migrate_fix_subnet_hotkey_lock_swaps_moves_or_discards_conflicts() { (chained_coldkey, chained_netuid, chained_first_hotkey), chained_lock.clone(), ); + LockingColdkeys::::insert( + (chained_netuid, chained_first_hotkey, chained_coldkey), + (), + ); HotkeyLock::::insert(chained_netuid, chained_first_hotkey, chained_lock.clone()); let weight = @@ -157,14 +164,34 @@ fn test_migrate_fix_subnet_hotkey_lock_swaps_moves_or_discards_conflicts() { assert!(HasMigrationRun::::get(&migration_name)); assert!(Lock::::get((coldkey_to_move, netuid, old_hotkey)).is_none()); assert!(Lock::::get((coldkey_with_conflict, netuid, old_hotkey)).is_none()); + assert!(!LockingColdkeys::::contains_key(( + netuid, + old_hotkey, + coldkey_to_move + ))); + assert!(!LockingColdkeys::::contains_key(( + netuid, + old_hotkey, + coldkey_with_conflict + ))); assert_eq!( Lock::::get((coldkey_to_move, netuid, new_hotkey)), Some(moved_lock.clone()) ); + assert!(LockingColdkeys::::contains_key(( + netuid, + new_hotkey, + coldkey_to_move + ))); assert_eq!( Lock::::get((coldkey_with_conflict, netuid, new_hotkey)), Some(existing_destination_lock.clone()) ); + assert!(LockingColdkeys::::contains_key(( + netuid, + new_hotkey, + coldkey_with_conflict + ))); assert!(HotkeyLock::::get(netuid, old_hotkey).is_none()); let new_aggregate = HotkeyLock::::get(netuid, new_hotkey) @@ -193,10 +220,25 @@ fn test_migrate_fix_subnet_hotkey_lock_swaps_moves_or_discards_conflicts() { chained_middle_hotkey )) .is_none()); + assert!(!LockingColdkeys::::contains_key(( + chained_netuid, + chained_first_hotkey, + chained_coldkey + ))); + assert!(!LockingColdkeys::::contains_key(( + chained_netuid, + chained_middle_hotkey, + chained_coldkey + ))); assert_eq!( Lock::::get((chained_coldkey, chained_netuid, chained_final_hotkey)), Some(chained_lock.clone()) ); + assert!(LockingColdkeys::::contains_key(( + chained_netuid, + chained_final_hotkey, + chained_coldkey + ))); assert!(HotkeyLock::::get(chained_netuid, chained_first_hotkey).is_none()); assert!(HotkeyLock::::get(chained_netuid, chained_middle_hotkey).is_none()); assert_eq!( diff --git a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs index 1e200aaedd..beb8ec9a75 100644 --- a/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs +++ b/pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs @@ -900,22 +900,23 @@ fn test_swap_owner_old_hotkey_not_exist() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_hotkey_with_subnet -- test_swap_owner_new_hotkey_already_exists --exact --nocapture +// SKIP_WASM_BUILD=1 cargo test --package pallet-subtensor --lib -- tests::swap_hotkey_with_subnet::test_swap_owner_new_hotkey_already_exists --exact --nocapture #[test] fn test_swap_owner_new_hotkey_already_exists() { new_test_ext(1).execute_with(|| { let old_hotkey = U256::from(1); let new_hotkey = U256::from(2); let coldkey = U256::from(3); + let another_coldkey = U256::from(4); - let netuid = add_dynamic_network(&new_hotkey, &coldkey); + let netuid = add_dynamic_network(&old_hotkey, &coldkey); add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_u64.into()); // old_hotkey is owned by coldkey; new_hotkey was already registered on `netuid` // by add_dynamic_network (the condition under test). Do NOT reassign new_hotkey to // a foreign coldkey — the new_hotkey-ownership check (NonAssociatedColdKey) would // then fire before the already-registered-in-subnet check this test targets. - Owner::::insert(old_hotkey, coldkey); + Owner::::insert(new_hotkey, another_coldkey); // Perform the swap System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get()); @@ -927,7 +928,7 @@ fn test_swap_owner_new_hotkey_already_exists() { Some(netuid), false ), - Error::::HotKeyAlreadyRegisteredInSubNet + Error::::NonAssociatedColdKey ); // Verify the swap diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 5cf4d7aadb..94e25a46fb 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -234,7 +234,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: 419, + spec_version: 420, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,