Skip to content

RPC to get validators #1614

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

Merged
merged 12 commits into from
Jun 4, 2025
4 changes: 3 additions & 1 deletion pallets/subtensor/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub trait SubtensorCustomApi<BlockHash> {
&self,
netuid: u16,
metagraph_index: Vec<u16>,
validator_only: bool,
at: Option<BlockHash>,
) -> RpcResult<Vec<u8>>;
}
Expand Down Expand Up @@ -402,12 +403,13 @@ where
&self,
netuid: u16,
metagraph_index: Vec<u16>,
validator_only: bool,
at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Vec<u8>> {
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

match api.get_selective_metagraph(at, netuid, metagraph_index) {
match api.get_selective_metagraph(at, netuid, metagraph_index, validator_only) {
Ok(result) => Ok(result.encode()),
Err(e) => Err(Error::RuntimeError(format!(
"Unable to get selective metagraph: {:?}",
Expand Down
2 changes: 1 addition & 1 deletion pallets/subtensor/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ sp_api::decl_runtime_apis! {
fn get_metagraph(netuid: u16) -> Option<Metagraph<AccountId32>>;
fn get_dynamic_info(netuid: u16) -> Option<DynamicInfo<AccountId32>>;
fn get_subnet_state(netuid: u16) -> Option<SubnetState<AccountId32>>;
fn get_selective_metagraph(netuid: u16, metagraph_indexes: Vec<u16>) -> Option<SelectiveMetagraph<AccountId32>>;
fn get_selective_metagraph(netuid: u16, metagraph_indexes: Vec<u16>, validator_only: bool) -> Option<SelectiveMetagraph<AccountId32>>;
}

pub trait StakeInfoRuntimeApi {
Expand Down
57 changes: 55 additions & 2 deletions pallets/subtensor/src/rpc_info/metagraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::*;
extern crate alloc;
use crate::epoch::math::*;
use codec::Compact;
use frame_support::IterableStorageDoubleMap;
use frame_support::pallet_prelude::{Decode, Encode};
use substrate_fixed::types::I64F64;
use substrate_fixed::types::I96F32;
Expand Down Expand Up @@ -107,7 +108,7 @@ pub struct Metagraph<AccountId: TypeInfo + Encode + Decode> {
alpha_dividends_per_hotkey: Vec<(AccountId, Compact<u64>)>, // List of dividend payout in alpha via subnet.
}

#[freeze_struct("182c7375fee9db7b")]
#[freeze_struct("2eca518cf84390fa")]
#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)]
pub struct SelectiveMetagraph<AccountId: TypeInfo + Encode + Decode + Clone> {
// Subnet index
Expand Down Expand Up @@ -205,6 +206,9 @@ pub struct SelectiveMetagraph<AccountId: TypeInfo + Encode + Decode + Clone> {
// Dividend break down.
tao_dividends_per_hotkey: Option<Vec<(AccountId, Compact<u64>)>>, // List of dividend payouts in tao via root.
alpha_dividends_per_hotkey: Option<Vec<(AccountId, Compact<u64>)>>, // List of dividend payout in alpha via subnet.

// validators
validators: Option<Vec<Compact<u16>>>, // List of validators
}

impl<AccountId> SelectiveMetagraph<AccountId>
Expand Down Expand Up @@ -362,6 +366,8 @@ where
self.alpha_dividends_per_hotkey = other.alpha_dividends_per_hotkey.clone()
}

Some(SelectiveMetagraphIndex::Validators) => self.validators = other.validators.clone(),

None => {}
};
}
Expand Down Expand Up @@ -445,6 +451,7 @@ where
total_stake: None,
tao_dividends_per_hotkey: None,
alpha_dividends_per_hotkey: None,
validators: None,
}
}
}
Expand Down Expand Up @@ -522,6 +529,7 @@ pub enum SelectiveMetagraphIndex {
TotalStake,
TaoDividendsPerHotkey,
AlphaDividendsPerHotkey,
Validators,
}

impl SelectiveMetagraphIndex {
Expand Down Expand Up @@ -599,6 +607,7 @@ impl SelectiveMetagraphIndex {
69 => Some(SelectiveMetagraphIndex::TotalStake),
70 => Some(SelectiveMetagraphIndex::TaoDividendsPerHotkey),
71 => Some(SelectiveMetagraphIndex::AlphaDividendsPerHotkey),
72 => Some(SelectiveMetagraphIndex::Validators),
_ => None,
}
}
Expand Down Expand Up @@ -791,10 +800,14 @@ impl<T: Config> Pallet<T> {
pub fn get_selective_metagraph(
netuid: u16,
metagraph_indexes: Vec<u16>,
validator_only: bool,
) -> Option<SelectiveMetagraph<T::AccountId>> {
if !Self::if_subnet_exist(netuid) {
None
} else {
if validator_only {
return Some(Self::get_valiators(netuid));
}
let mut result = SelectiveMetagraph::default();
for index in metagraph_indexes.iter() {
let value = Self::get_single_selective_metagraph(netuid, *index);
Expand Down Expand Up @@ -1356,13 +1369,52 @@ impl<T: Config> Pallet<T> {
..Default::default()
}
}
None => SelectiveMetagraph {
_ => SelectiveMetagraph {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means if the SelectiveMetagraphIndex is Validators, we'd still be going to this match arm. Is this correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is correct. get validators is a separate branch. that's the validator_only parameter means.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is there a case where the validators_only parameter is false, and yet the SelectedMetagraphIndex is Validators?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if validators_only is false, we don't return validators in the result. The index is wield, let me check how to change it. thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the validators index.

Copy link
Contributor

@camfairchild camfairchild May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we not use the index of ValidatorsOnly to do this and not add a boolean to the api?

e.g. remove the only_validators param. Then, if ValidatorsOnly is present just keys that are validators.

This requires we add a uids field to the struct also

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say this impl can be like this:

  • we add SelectedMetagraphIndex::Validators. Then it gonna handled the same way as other SelectedMetagraphIndex indices.
  • we add validators field into Metagraph struct.

Result:

  • get_metagraph_info always has filed Metagraph::validators field
  • SelectiveMetagraph returns object with filed validators as Vec with related HK indexes if SelectedMetagraphIndex::Validators passed in params as item in field_indices
  • SDK MetagraphInfo class will get a new field validators

This is gonnabe clearest way for this and SDK implementation as far as I see.
Pleas feel free to correct me if I'm wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we can handle the validators the same as other items in metagraph. user can get any data according to passed index list.

// Subnet index
netuid: netuid.into(),
..Default::default()
},
}
}

fn get_valiators(netuid: u16) -> SelectiveMetagraph<T::AccountId> {
let stake_threshold = Self::get_stake_threshold();
let hotkeys: Vec<(u16, T::AccountId)> =
<Keys<T> as IterableStorageDoubleMap<u16, u16, T::AccountId>>::iter_prefix(netuid)
.collect();
let validator_permits: Vec<bool> = Self::get_validator_permit(netuid);

// filter according to validator_permits
let hotkeys: Vec<&(u16, T::AccountId)> = hotkeys
.iter()
.filter(|(uid, _)| *validator_permits.get(*uid as usize).unwrap_or(&false))
.collect::<Vec<_>>();

// map hotkeys to validators with stake
let mut validators: Vec<(u16, I64F64)> = hotkeys
.iter()
.map(|(uid, hotkey)| {
let stake = Self::get_stake_weights_for_hotkey_on_subnet(hotkey, netuid);
(*uid, stake.0)
})
.collect();

// sort validators by stake
validators.sort_by(|a, b| a.1.cmp(&b.1));

let validators: Vec<Compact<u16>> = validators
.iter()
.filter(|(_uid, stake)| *stake > stake_threshold)
.map(|(uid, _)| Compact::from(*uid))
.collect::<Vec<_>>();

SelectiveMetagraph {
// Subnet index
netuid: netuid.into(),
validators: Some(validators),
..Default::default()
}
}
}

#[test]
Expand Down Expand Up @@ -1441,6 +1493,7 @@ fn test_selective_metagraph() {
total_stake: None,
tao_dividends_per_hotkey: None,
alpha_dividends_per_hotkey: None,
validators: None,
};

// test init value
Expand Down
4 changes: 2 additions & 2 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2197,8 +2197,8 @@ impl_runtime_apis! {
SubtensorModule::get_all_dynamic_info()
}

fn get_selective_metagraph(netuid: u16, metagraph_indexes: Vec<u16>) -> Option<SelectiveMetagraph<AccountId32>> {
SubtensorModule::get_selective_metagraph(netuid, metagraph_indexes)
fn get_selective_metagraph(netuid: u16, metagraph_indexes: Vec<u16>, validator_only: bool) -> Option<SelectiveMetagraph<AccountId32>> {
SubtensorModule::get_selective_metagraph(netuid, metagraph_indexes, validator_only)
}

}
Expand Down
Loading