diff --git a/Cargo.lock b/Cargo.lock index a5c5c71174..6b5204cb2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6316,11 +6316,11 @@ dependencies = [ [[package]] name = "is_executable" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2" +checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4" dependencies = [ - "winapi", + "windows-sys 0.60.2", ] [[package]] diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index b6cafb71b7..b83604b69a 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -2498,6 +2498,28 @@ fn test_trim_to_max_allowed_uids() { Keys::::insert(netuid, 14, sn_owner_hotkey2); Uids::::insert(netuid, sn_owner_hotkey2, 14); + // Set some evm addresses + AssociatedEvmAddress::::insert( + netuid, + 6, + (sp_core::H160::from_slice(b"12345678901234567891"), now), + ); + AssociatedEvmAddress::::insert( + netuid, + 10, + (sp_core::H160::from_slice(b"12345678901234567892"), now), + ); + AssociatedEvmAddress::::insert( + netuid, + 12, + (sp_core::H160::from_slice(b"12345678901234567893"), now), + ); + AssociatedEvmAddress::::insert( + netuid, + 14, + (sp_core::H160::from_slice(b"12345678901234567894"), now), + ); + // Populate Weights and Bonds storage items to test trimming // Create weights and bonds that span across the range that will be trimmed for uid in 0..max_n { @@ -2574,6 +2596,7 @@ fn test_trim_to_max_allowed_uids() { for uid in new_max_n..max_n { assert!(!Keys::::contains_key(netuid, uid)); assert!(!BlockAtRegistration::::contains_key(netuid, uid)); + assert!(!AssociatedEvmAddress::::contains_key(netuid, uid)); for mecid in 0..mechanism_count.into() { let netuid_index = SubtensorModule::get_mechanism_storage_index(netuid, MechId::from(mecid)); @@ -2631,6 +2654,23 @@ fn test_trim_to_max_allowed_uids() { // Actual number of neurons on the network updated after trimming assert_eq!(SubnetworkN::::get(netuid), new_max_n); + // Uids match enumeration order + for i in 0..new_max_n.into() { + let hotkey = Keys::::get(netuid, i); + let uid = Uids::::get(netuid, hotkey); + assert_eq!(uid, Some(i)); + } + + // EVM association have been remapped correctly (uids: 7 -> 2, 14 -> 7) + assert_eq!( + AssociatedEvmAddress::::get(netuid, 2), + Some((sp_core::H160::from_slice(b"12345678901234567891"), now)) + ); + assert_eq!( + AssociatedEvmAddress::::get(netuid, 7), + Some((sp_core::H160::from_slice(b"12345678901234567894"), now)) + ); + // Non existent subnet assert_err!( AdminUtils::sudo_trim_to_max_allowed_uids( @@ -2673,7 +2713,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { MaxRegistrationsPerBlock::::insert(netuid, 256); TargetRegistrationsPerInterval::::insert(netuid, 256); ImmuneOwnerUidsLimit::::insert(netuid, 2); - MinAllowedUids::::set(netuid, 4); + MinAllowedUids::::set(netuid, 2); // Add 5 neurons let max_n = 5; @@ -2711,7 +2751,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { netuid, 4 ), - pallet_subtensor::Error::::InvalidValue + pallet_subtensor::Error::::TrimmingWouldExceedMaxImmunePercentage ); // Try to trim to 3 UIDs - this should also fail because 4/3 > 80% immune (>= 80%) @@ -2721,7 +2761,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { netuid, 3 ), - pallet_subtensor::Error::::InvalidValue + pallet_subtensor::Error::::TrimmingWouldExceedMaxImmunePercentage ); // Now test a scenario where trimming should succeed @@ -2733,10 +2773,6 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { Uids::::remove(netuid, hotkey_to_remove); BlockAtRegistration::::remove(netuid, uid_to_remove); - // Now we have 3 immune out of 4 total UIDs - // Try to trim to 3 UIDs - this should succeed because 3/3 = 100% immune, but that's exactly 80% - // Wait, 100% is > 80%, so this should fail. Let me test with a scenario where we have fewer immune UIDs - // Remove another immune UID to make it 2 immune out of 3 total let uid_to_remove2 = 2; let hotkey_to_remove2 = U256::from(uid_to_remove2 * 1000 + 1000); diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 98c1742e9a..fbae1e1075 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -256,5 +256,9 @@ mod errors { CannotAffordLockCost, /// exceeded the rate limit for associating an EVM key. EvmKeyAssociateRateLimitExceeded, + /// The UID map for the subnet could not be cleared + UidMapCouldNotBeCleared, + /// Trimming would exceed the max immune neurons percentage + TrimmingWouldExceedMaxImmunePercentage, } } diff --git a/pallets/subtensor/src/subnets/uids.rs b/pallets/subtensor/src/subnets/uids.rs index b68fabfbd5..4b33a5e737 100644 --- a/pallets/subtensor/src/subnets/uids.rs +++ b/pallets/subtensor/src/subnets/uids.rs @@ -162,7 +162,7 @@ impl Pallet { let immune_percentage = Percent::from_rational(immune_count, max_n); ensure!( immune_percentage < T::MaxImmuneUidsPercentage::get(), - Error::::InvalidValue + Error::::TrimmingWouldExceedMaxImmunePercentage ); // Get all emissions with their UIDs and sort by emission (descending) @@ -209,6 +209,7 @@ impl Pallet { #[allow(unknown_lints)] Keys::::remove(netuid, neuron_uid); BlockAtRegistration::::remove(netuid, neuron_uid); + AssociatedEvmAddress::::remove(netuid, neuron_uid); for mecid in 0..mechanisms_count { let netuid_index = Self::get_mechanism_storage_index(netuid, mecid.into()); Weights::::remove(netuid_index, neuron_uid); @@ -315,6 +316,7 @@ impl Pallet { // Swap uid specific storage items to new compressed positions Keys::::swap(netuid, old_neuron_uid, netuid, new_neuron_uid); + AssociatedEvmAddress::::swap(netuid, old_neuron_uid, netuid, new_neuron_uid); BlockAtRegistration::::swap(netuid, old_neuron_uid, netuid, new_neuron_uid); for mecid in 0..mechanisms_count { @@ -352,6 +354,21 @@ impl Pallet { } } + // Clear the UID map for the subnet + let clear_result = Uids::::clear_prefix(netuid, u32::MAX, None); + // Shouldn't happen, but possible. + ensure!( + clear_result.maybe_cursor.is_none(), + Error::::UidMapCouldNotBeCleared + ); + + // Insert the new UIDs + for new_uid in old_to_new_uid.values() { + // Get the hotkey using Keys map and new UID. + let hotkey = Keys::::get(netuid, *new_uid as u16); + Uids::::insert(netuid, hotkey, *new_uid as u16); + } + // Update the subnet's uid count to reflect the new maximum SubnetworkN::::insert(netuid, max_n); } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a1629cdafb..e597728a60 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -223,7 +223,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: 322, + spec_version: 323, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,