Skip to content

Commit bcb696b

Browse files
authored
Merge pull request #490 from opentensor/fix/add-adjust-senate-call
Fix Senate membership changes
2 parents 3e8afeb + 966eaf3 commit bcb696b

File tree

6 files changed

+395
-30
lines changed

6 files changed

+395
-30
lines changed

pallets/subtensor/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ mod errors {
126126
CommitRevealEnabled,
127127
/// Attemtping to commit/reveal weights when disabled.
128128
CommitRevealDisabled,
129+
/// Not able to join the senate.
130+
CouldNotJoinSenate,
129131
/// Attempting to set alpha high/low while disabled
130132
LiquidAlphaDisabled,
131133
/// Alpha high is too low: alpha_high > 0.8

pallets/subtensor/src/events.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ mod events {
132132
MinDelegateTakeSet(u16),
133133
/// the target stakes per interval is set by sudo/admin transaction
134134
TargetStakesPerIntervalSet(u64),
135+
/// a member of the senate is adjusted
136+
SenateAdjusted {
137+
/// the account ID of the old senate member, if any
138+
old_member: Option<T::AccountId>,
139+
/// the account ID of the new senate member
140+
new_member: T::AccountId,
141+
},
135142
/// A coldkey has been swapped
136143
ColdkeySwapped {
137144
/// the account ID of old coldkey

pallets/subtensor/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,6 +2038,15 @@ pub mod pallet {
20382038
Self::do_root_register(origin, hotkey)
20392039
}
20402040

2041+
/// Attempt to adjust the senate membership to include a hotkey
2042+
#[pallet::call_index(63)]
2043+
#[pallet::weight((Weight::from_parts(0, 0)
2044+
.saturating_add(T::DbWeight::get().reads(0))
2045+
.saturating_add(T::DbWeight::get().writes(0)), DispatchClass::Normal, Pays::Yes))]
2046+
pub fn adjust_senate(origin: OriginFor<T>, hotkey: T::AccountId) -> DispatchResult {
2047+
Self::do_adjust_senate(origin, hotkey)
2048+
}
2049+
20412050
/// User register a new subnetwork via burning token
20422051
#[pallet::call_index(7)]
20432052
#[pallet::weight((Weight::from_parts(177_000_000, 0)

pallets/subtensor/src/root.rs

Lines changed: 131 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -571,9 +571,133 @@ impl<T: Config> Pallet<T> {
571571
);
572572
}
573573

574-
let current_stake = Self::get_total_stake_for_hotkey(&hotkey);
574+
// --- 13. Join the Senate if eligible.
575+
// Returns the replaced member, if any.
576+
let _ = Self::join_senate_if_eligible(&hotkey)?;
577+
578+
// --- 14. Force all members on root to become a delegate.
579+
if !Self::hotkey_is_delegate(&hotkey) {
580+
Self::delegate_hotkey(&hotkey, 11_796); // 18% cut defaulted.
581+
}
582+
583+
// --- 15. Update the registration counters for both the block and interval.
584+
#[allow(clippy::arithmetic_side_effects)]
585+
// note this RA + clippy false positive is a known substrate issue
586+
RegistrationsThisInterval::<T>::mutate(root_netuid, |val| *val += 1);
587+
#[allow(clippy::arithmetic_side_effects)]
588+
// note this RA + clippy false positive is a known substrate issue
589+
RegistrationsThisBlock::<T>::mutate(root_netuid, |val| *val += 1);
590+
591+
// --- 16. Log and announce the successful registration.
592+
log::info!(
593+
"RootRegistered(netuid:{:?} uid:{:?} hotkey:{:?})",
594+
root_netuid,
595+
subnetwork_uid,
596+
hotkey
597+
);
598+
Self::deposit_event(Event::NeuronRegistered(root_netuid, subnetwork_uid, hotkey));
599+
600+
// --- 17. Finish and return success.
601+
Ok(())
602+
}
603+
604+
// Checks if a hotkey should be a member of the Senate, and if so, adds them.
605+
//
606+
// This function is responsible for adding a hotkey to the Senate if they meet the requirements.
607+
// The root key with the least stake is pruned in the event of a filled membership.
608+
//
609+
// # Arguments:
610+
// * 'origin': Represents the origin of the call.
611+
// * 'hotkey': The hotkey that the user wants to register to the root network.
612+
//
613+
// # Returns:
614+
// * 'DispatchResult': A result type indicating success or failure of the registration.
615+
//
616+
pub fn do_adjust_senate(origin: T::RuntimeOrigin, hotkey: T::AccountId) -> DispatchResult {
617+
// --- 0. Get the unique identifier (UID) for the root network.
618+
let root_netuid: u16 = Self::get_root_netuid();
619+
ensure!(
620+
Self::if_subnet_exist(root_netuid),
621+
Error::<T>::RootNetworkDoesNotExist
622+
);
623+
624+
// --- 1. Ensure that the call originates from a signed source and retrieve the caller's account ID (coldkey).
625+
let coldkey = ensure_signed(origin)?;
626+
log::info!(
627+
"do_root_register( coldkey: {:?}, hotkey: {:?} )",
628+
coldkey,
629+
hotkey
630+
);
631+
632+
// --- 2. Check if the hotkey is already registered to the root network. If not, error out.
633+
ensure!(
634+
Uids::<T>::contains_key(root_netuid, &hotkey),
635+
Error::<T>::HotKeyNotRegisteredInSubNet
636+
);
637+
638+
// --- 3. Create a network account for the user if it doesn't exist.
639+
Self::create_account_if_non_existent(&coldkey, &hotkey);
640+
641+
// --- 4. Join the Senate if eligible.
642+
// Returns the replaced member, if any.
643+
let replaced = Self::join_senate_if_eligible(&hotkey)?;
644+
645+
if replaced.is_none() {
646+
// Not eligible to join the Senate, or no replacement needed.
647+
// Check if the hotkey is *now* a member of the Senate.
648+
// Otherwise, error out.
649+
ensure!(
650+
T::SenateMembers::is_member(&hotkey),
651+
Error::<T>::StakeTooLowForRoot, // Had less stake than the lowest stake incumbent.
652+
);
653+
}
654+
655+
// --- 5. Log and announce the successful Senate adjustment.
656+
log::info!(
657+
"SenateAdjusted(old_hotkey:{:?} hotkey:{:?})",
658+
replaced,
659+
hotkey
660+
);
661+
Self::deposit_event(Event::SenateAdjusted {
662+
old_member: replaced.cloned(),
663+
new_member: hotkey,
664+
});
665+
666+
// --- 6. Finish and return success.
667+
Ok(())
668+
}
669+
670+
// Checks if a hotkey should be a member of the Senate, and if so, adds them.
671+
//
672+
// # Arguments:
673+
// * 'hotkey': The hotkey that the user wants to register to the root network.
674+
//
675+
// # Returns:
676+
// * 'Result<Option<&T::AccountId>, Error<T>>': A result containing the replaced member, if any.
677+
//
678+
fn join_senate_if_eligible(hotkey: &T::AccountId) -> Result<Option<&T::AccountId>, Error<T>> {
679+
// Get the root network UID.
680+
let root_netuid: u16 = Self::get_root_netuid();
681+
682+
// --- 1. Check the hotkey is registered in the root network.
683+
ensure!(
684+
Uids::<T>::contains_key(root_netuid, hotkey),
685+
Error::<T>::HotKeyNotRegisteredInSubNet
686+
);
687+
688+
// --- 2. Verify the hotkey is NOT already a member of the Senate.
689+
ensure!(
690+
!T::SenateMembers::is_member(hotkey),
691+
Error::<T>::HotKeyAlreadyRegisteredInSubNet
692+
);
693+
694+
// --- 3. Grab the hotkey's stake.
695+
let current_stake = Self::get_total_stake_for_hotkey(hotkey);
696+
697+
// Add the hotkey to the Senate.
575698
// If we're full, we'll swap out the lowest stake member.
576699
let members = T::SenateMembers::members();
700+
let last: Option<&T::AccountId> = None;
577701
if (members.len() as u32) == T::SenateMembers::max_members() {
578702
let mut sorted_members = members.clone();
579703
sorted_members.sort_by(|a, b| {
@@ -587,34 +711,17 @@ impl<T: Config> Pallet<T> {
587711
let last_stake = Self::get_total_stake_for_hotkey(last);
588712

589713
if last_stake < current_stake {
590-
T::SenateMembers::swap_member(last, &hotkey).map_err(|e| e.error)?;
591-
T::TriumvirateInterface::remove_votes(last)?;
714+
// Swap the member with the lowest stake.
715+
T::SenateMembers::swap_member(last, hotkey)
716+
.map_err(|_| Error::<T>::CouldNotJoinSenate)?;
592717
}
593718
}
594719
} else {
595-
T::SenateMembers::add_member(&hotkey).map_err(|e| e.error)?;
720+
T::SenateMembers::add_member(hotkey).map_err(|_| Error::<T>::CouldNotJoinSenate)?;
596721
}
597722

598-
// --- 13. Force all members on root to become a delegate.
599-
if !Self::hotkey_is_delegate(&hotkey) {
600-
Self::delegate_hotkey(&hotkey, 11_796); // 18% cut defaulted.
601-
}
602-
603-
// --- 14. Update the registration counters for both the block and interval.
604-
RegistrationsThisInterval::<T>::mutate(root_netuid, |val| val.saturating_inc());
605-
RegistrationsThisBlock::<T>::mutate(root_netuid, |val| val.saturating_inc());
606-
607-
// --- 15. Log and announce the successful registration.
608-
log::info!(
609-
"RootRegistered(netuid:{:?} uid:{:?} hotkey:{:?})",
610-
root_netuid,
611-
subnetwork_uid,
612-
hotkey
613-
);
614-
Self::deposit_event(Event::NeuronRegistered(root_netuid, subnetwork_uid, hotkey));
615-
616-
// --- 16. Finish and return success.
617-
Ok(())
723+
// Return the swapped out member, if any.
724+
Ok(last)
618725
}
619726

620727
pub fn do_set_root_weights(

pallets/subtensor/tests/mock.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,23 +203,29 @@ use pallet_subtensor::{CollectiveInterface, MemberManagement};
203203
pub struct ManageSenateMembers;
204204
impl MemberManagement<AccountId> for ManageSenateMembers {
205205
fn add_member(account: &AccountId) -> DispatchResultWithPostInfo {
206-
SenateMembers::add_member(RawOrigin::Root.into(), *account)
206+
let who = *account;
207+
SenateMembers::add_member(RawOrigin::Root.into(), who)
207208
}
208209

209210
fn remove_member(account: &AccountId) -> DispatchResultWithPostInfo {
210-
SenateMembers::remove_member(RawOrigin::Root.into(), *account)
211+
let who = *account;
212+
SenateMembers::remove_member(RawOrigin::Root.into(), who)
211213
}
212214

213-
fn swap_member(remove: &AccountId, add: &AccountId) -> DispatchResultWithPostInfo {
214-
SenateMembers::swap_member(RawOrigin::Root.into(), *remove, *add)
215+
fn swap_member(rm: &AccountId, add: &AccountId) -> DispatchResultWithPostInfo {
216+
let remove = *rm;
217+
let add = *add;
218+
219+
Triumvirate::remove_votes(rm)?;
220+
SenateMembers::swap_member(RawOrigin::Root.into(), remove, add)
215221
}
216222

217223
fn is_member(account: &AccountId) -> bool {
218-
Senate::is_member(account)
224+
SenateMembers::members().contains(account)
219225
}
220226

221227
fn members() -> Vec<AccountId> {
222-
Senate::members()
228+
SenateMembers::members().into()
223229
}
224230

225231
fn max_members() -> u32 {

0 commit comments

Comments
 (0)