Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RAO/No owner deregistration #1217

Merged
merged 2 commits into from
Feb 6, 2025
Merged
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
8 changes: 8 additions & 0 deletions pallets/subtensor/src/subnets/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,14 @@ impl<T: Config> Pallet<T> {
}

for neuron_uid in 0..neurons_n {
// Do not deregister the owner
if let Ok(hotkey) = Self::get_hotkey_for_net_and_uid(netuid, neuron_uid) {
let coldkey = Self::get_owning_coldkey_for_hotkey(&hotkey);
if Self::get_subnet_owner(netuid) == coldkey {
continue;
}
}

let pruning_score: u16 = Self::get_pruning_score_for_uid(netuid, neuron_uid);
let block_at_registration: u64 =
Self::get_neuron_block_at_registration(netuid, neuron_uid);
Expand Down
14 changes: 14 additions & 0 deletions pallets/subtensor/src/subnets/uids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ impl<T: Config> Pallet<T> {
// 1. Get the old hotkey under this position.
let old_hotkey: T::AccountId = Keys::<T>::get(netuid, uid_to_replace);

// Do not deregister the owner
let coldkey = Self::get_owning_coldkey_for_hotkey(&old_hotkey);
if Self::get_subnet_owner(netuid) == coldkey {
log::warn!(
"replace_neuron: Skipped replacement because neuron belongs to the subnet owner. \
netuid: {:?}, uid_to_replace: {:?}, new_hotkey: {:?}, owner_coldkey: {:?}",
netuid,
uid_to_replace,
new_hotkey,
coldkey
);
return;
}

// 2. Remove previous set memberships.
Uids::<T>::remove(netuid, old_hotkey.clone());
IsNetworkMember::<T>::remove(old_hotkey.clone(), netuid);
Expand Down
4 changes: 4 additions & 0 deletions pallets/subtensor/src/tests/difficulty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ fn test_registration_difficulty_adjustment() {
let tempo: u16 = 1;
let modality: u16 = 1;
add_network(netuid, tempo, modality);

// owners are not deregistered
crate::SubnetOwner::<Test>::insert(netuid, U256::from(99999));

SubtensorModule::set_min_difficulty(netuid, 10000);
assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); // Check initial difficulty.
assert_eq!(SubtensorModule::get_last_adjustment_block(netuid), 0); // Last adjustment block starts at 0.
Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/tests/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,12 @@ fn test_full_pass_through() {
add_network(netuid1, tempo1, 0);
add_network(netuid2, tempo2, 0);

// owners are not deregisterd
let dummy_owner = U256::from(99999);
crate::SubnetOwner::<Test>::insert(netuid0, dummy_owner);
crate::SubnetOwner::<Test>::insert(netuid1, dummy_owner);
crate::SubnetOwner::<Test>::insert(netuid2, dummy_owner);

// Check their tempo.
assert_eq!(SubtensorModule::get_tempo(netuid0), tempo0);
assert_eq!(SubtensorModule::get_tempo(netuid1), tempo1);
Expand Down
85 changes: 85 additions & 0 deletions pallets/subtensor/src/tests/uids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,88 @@ fn test_neuron_certificate() {
assert_err!(NeuronCertificate::try_from(data), ());
});
}

#[test]
fn test_replace_neuron_subnet_owner_not_replaced() {
new_test_ext(1).execute_with(|| {
let owner_hotkey = U256::from(100);
let owner_coldkey = U256::from(999);
let new_hotkey_account_id = U256::from(2);

let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey);
let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey)
.expect("Owner neuron should be registered by add_dynamic_network");

let current_block = SubtensorModule::get_current_block_as_u64();
SubtensorModule::replace_neuron(netuid, neuron_uid, &new_hotkey_account_id, current_block);

let still_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey);
assert_ok!(still_uid);
assert_eq!(
still_uid.unwrap(),
neuron_uid,
"UID should remain unchanged for subnet owner"
);

let new_key_uid =
SubtensorModule::get_uid_for_net_and_hotkey(netuid, &new_hotkey_account_id);
assert_err!(new_key_uid, Error::<Test>::HotKeyNotRegisteredInSubNet,);
});
}

#[test]
fn test_get_neuron_to_prune_owner_not_pruned() {
new_test_ext(1).execute_with(|| {
let owner_hotkey = U256::from(123);
let owner_coldkey = U256::from(999);

let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey);

SubtensorModule::set_max_registrations_per_block(netuid, 100);
SubtensorModule::set_target_registrations_per_interval(netuid, 100);
SubnetOwner::<Test>::insert(netuid, owner_coldkey);

let owner_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey)
.expect("Owner neuron should already be registered by add_dynamic_network");

let additional_hotkey_1 = U256::from(1000);
let additional_coldkey_1 = U256::from(2000);

let additional_hotkey_2 = U256::from(1001);
let additional_coldkey_2 = U256::from(2001);

register_ok_neuron(netuid, additional_hotkey_1, additional_coldkey_1, 0);
let uid_1 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_1)
.expect("Should be registered");

register_ok_neuron(netuid, additional_hotkey_2, additional_coldkey_2, 1);
let uid_2 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_2)
.expect("Should be registered");

SubtensorModule::set_pruning_score_for_uid(netuid, owner_uid, 0);
SubtensorModule::set_pruning_score_for_uid(netuid, uid_1, 1);
SubtensorModule::set_pruning_score_for_uid(netuid, uid_2, 2);

let pruned_uid = SubtensorModule::get_neuron_to_prune(netuid);

// - The pruned UID must be `uid_1` (score=1).
// - The owner's UID remains unpruned.
assert_eq!(
pruned_uid, uid_1,
"Should prune the neuron with pruning score=1, not the owner (score=0)."
);

let pruned_score = SubtensorModule::get_pruning_score_for_uid(netuid, uid_1);
assert_eq!(
pruned_score,
u16::MAX,
"Pruned neuron's score should be set to u16::MAX"
);

let owner_score = SubtensorModule::get_pruning_score_for_uid(netuid, owner_uid);
assert_eq!(
owner_score, 0,
"Owner's pruning score remains 0, indicating it was skipped"
);
});
}
Loading