Skip to content
Open
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
17 changes: 17 additions & 0 deletions pallets/subtensor/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ pub trait SubtensorCustomApi<BlockHash> {
mecid: MechId,
at: Option<BlockHash>,
) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getSubmetagraphs")]
fn get_submetagraphs(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getSubnetState")]
fn get_subnet_state(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getLockCost")]
Expand Down Expand Up @@ -405,6 +407,21 @@ where
}
}

fn get_submetagraphs(
&self,
netuid: NetUid,
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_submetagraphs(at, netuid) {
Ok(result) => Ok(result.encode()),
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get submetagraphs: {e:?}")).into())
}
}
}

fn get_subnet_state(
&self,
netuid: NetUid,
Expand Down
1 change: 1 addition & 0 deletions pallets/subtensor/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ sp_api::decl_runtime_apis! {
fn get_metagraph(netuid: NetUid) -> Option<Metagraph<AccountId32>>;
fn get_all_mechagraphs() -> Vec<Option<Metagraph<AccountId32>>>;
fn get_mechagraph(netuid: NetUid, mecid: MechId) -> Option<Metagraph<AccountId32>>;
fn get_submetagraphs(netuid: NetUid) -> Vec<Option<Metagraph<AccountId32>>>;
fn get_dynamic_info(netuid: NetUid) -> Option<DynamicInfo<AccountId32>>;
fn get_subnet_state(netuid: NetUid) -> Option<SubnetState<AccountId32>>;
fn get_selective_metagraph(netuid: NetUid, metagraph_indexes: Vec<u16>) -> Option<SelectiveMetagraph<AccountId32>>;
Expand Down
12 changes: 12 additions & 0 deletions pallets/subtensor/src/rpc_info/metagraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,18 @@ impl<T: Config> Pallet<T> {
metagraphs
}

pub fn get_submetagraphs(netuid: NetUid) -> Vec<Option<Metagraph<T::AccountId>>> {
if !Self::if_subnet_exist(netuid) {
return Vec::new();
}
let mechanism_count = u8::from(MechanismCountCurrent::<T>::get(netuid));
let mut metagraphs = Vec::<Option<Metagraph<T::AccountId>>>::new();
for mecid in 0..mechanism_count {
metagraphs.push(Self::get_mechagraph(netuid, MechId::from(mecid)));
}
metagraphs
}

pub fn get_selective_metagraph(
netuid: NetUid,
metagraph_indexes: Vec<u16>,
Expand Down
1 change: 1 addition & 0 deletions pallets/subtensor/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod registration;
mod serving;
mod staking;
mod staking2;
mod submetagraph;
mod subnet;
mod subnet_emissions;
mod swap_coldkey;
Expand Down
219 changes: 219 additions & 0 deletions pallets/subtensor/src/tests/submetagraph.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
#![allow(
clippy::arithmetic_side_effects,
clippy::expect_used,
clippy::indexing_slicing,
clippy::unwrap_used
)]

// Run tests with:
// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::submetagraph --show-output

use super::mock::*;
use crate::*;
use sp_core::U256;
use subtensor_runtime_common::{MechId, NetUid};

#[test]
fn test_get_submetagraphs_nonexistent_subnet() {
new_test_ext(1).execute_with(|| {
let netuid = NetUid::from(999u16); // Non-existent subnet

let submetagraphs = SubtensorModule::get_submetagraphs(netuid);
assert_eq!(submetagraphs.len(), 0);
});
}

#[test]
fn test_get_submetagraphs_empty_mechanisms() {
new_test_ext(1).execute_with(|| {
let netuid = NetUid::from(1u16);
let tempo: u16 = 2;
let modality: u16 = 2;

// Add network
add_network(netuid, tempo, modality);

// Explicitly set mechanism count to 0
NetworksAdded::<Test>::insert(netuid, true);
MechanismCountCurrent::<Test>::insert(netuid, MechId::from(0u8));

let submetagraphs = SubtensorModule::get_submetagraphs(netuid);
assert_eq!(submetagraphs.len(), 0);
});
}

#[test]
fn test_get_submetagraphs_single_mechanism() {
new_test_ext(1).execute_with(|| {
let netuid = NetUid::from(1u16);
let tempo: u16 = 2;
let modality: u16 = 2;

add_network(netuid, tempo, modality);

// Set mechanism count to 1
NetworksAdded::<Test>::insert(netuid, true);
MechanismCountCurrent::<Test>::insert(netuid, MechId::from(1u8));

let submetagraphs = SubtensorModule::get_submetagraphs(netuid);
assert_eq!(submetagraphs.len(), 1);

// Verify we can get the mechagraph directly
let mechagraph = SubtensorModule::get_mechagraph(netuid, MechId::from(0u8));
assert!(mechagraph.is_some());
});
}

#[test]
fn test_get_submetagraphs_multiple_mechanisms() {
new_test_ext(1).execute_with(|| {
let netuid = NetUid::from(2u16);
let tempo: u16 = 2;
let modality: u16 = 2;

add_network(netuid, tempo, modality);

// Set mechanism count to 3
NetworksAdded::<Test>::insert(netuid, true);
MechanismCountCurrent::<Test>::insert(netuid, MechId::from(3u8));

let submetagraphs = SubtensorModule::get_submetagraphs(netuid);
assert_eq!(submetagraphs.len(), 3);

// Verify each mechagraph exists
for mecid in 0..3 {
let mechagraph = SubtensorModule::get_mechagraph(netuid, MechId::from(mecid));
assert!(
mechagraph.is_some(),
"Mechagraph for mecid {} should exist",
mecid
);
}
});
}

#[test]
fn test_get_submetagraphs_filters_by_netuid() {
new_test_ext(1).execute_with(|| {
let netuid1 = NetUid::from(10u16);
let netuid2 = NetUid::from(20u16);
let tempo: u16 = 2;
let modality: u16 = 2;

// Add two networks
add_network(netuid1, tempo, modality);
add_network(netuid2, tempo, modality);

// Set different mechanism counts for each
NetworksAdded::<Test>::insert(netuid1, true);
NetworksAdded::<Test>::insert(netuid2, true);
MechanismCountCurrent::<Test>::insert(netuid1, MechId::from(2u8));
MechanismCountCurrent::<Test>::insert(netuid2, MechId::from(4u8));

// Get submetagraphs for each netuid
let submetagraphs1 = SubtensorModule::get_submetagraphs(netuid1);
let submetagraphs2 = SubtensorModule::get_submetagraphs(netuid2);

assert_eq!(submetagraphs1.len(), 2);
assert_eq!(submetagraphs2.len(), 4);

// Verify filtering - netuid1 should only have 2, netuid2 should only have 4
for (idx, metagraph) in submetagraphs1.iter().enumerate() {
assert!(
metagraph.is_some(),
"Mechagraph at index {} should exist",
idx
);
assert!(idx < 2);
}

for (idx, metagraph) in submetagraphs2.iter().enumerate() {
assert!(
metagraph.is_some(),
"Mechagraph at index {} should exist",
idx
);
assert!(idx < 4);
}
});
}

#[test]
fn test_get_submetagraphs_vs_get_all_mechagraphs() {
new_test_ext(1).execute_with(|| {
let netuid1 = NetUid::from(30u16);
let netuid2 = NetUid::from(31u16);
let tempo: u16 = 2;
let modality: u16 = 2;

// Add two networks with different mechanism counts
add_network(netuid1, tempo, modality);
add_network(netuid2, tempo, modality);

NetworksAdded::<Test>::insert(netuid1, true);
NetworksAdded::<Test>::insert(netuid2, true);
MechanismCountCurrent::<Test>::insert(netuid1, MechId::from(2u8));
MechanismCountCurrent::<Test>::insert(netuid2, MechId::from(3u8));

// Get all mechagraphs (should include both netuids)
let all_mechagraphs = SubtensorModule::get_all_mechagraphs();

// Get submetagraphs for each netuid
let submetagraphs1 = SubtensorModule::get_submetagraphs(netuid1);
let submetagraphs2 = SubtensorModule::get_submetagraphs(netuid2);

// Verify that get_submetagraphs returns only the mechagraphs for the specific netuid
assert_eq!(submetagraphs1.len(), 2);
assert_eq!(submetagraphs2.len(), 3);

// The sum should match (or be less if there are other subnets)
// At minimum, our two subnets should be included
assert!(all_mechagraphs.len() >= 5); // 2 + 3 = 5

// Verify that get_submetagraphs for netuid1 returns the same as filtering all_mechagraphs
// by checking that each mechagraph in submetagraphs1 exists in all_mechagraphs
// (This is a simplified check - in practice you'd compare the actual data)
assert_eq!(submetagraphs1.len(), 2);
assert_eq!(submetagraphs2.len(), 3);
});
}

#[test]
fn test_get_submetagraphs_with_registered_neurons() {
new_test_ext(1).execute_with(|| {
let netuid = NetUid::from(40u16);
let tempo: u16 = 2;
let modality: u16 = 2;

add_network(netuid, tempo, modality);
NetworksAdded::<Test>::insert(netuid, true);
MechanismCountCurrent::<Test>::insert(netuid, MechId::from(2u8));

// Register some neurons
let hotkey1 = U256::from(1);
let coldkey1 = U256::from(1);
let hotkey2 = U256::from(2);
let coldkey2 = U256::from(2);

register_ok_neuron(netuid, hotkey1, coldkey1, 39420842);
register_ok_neuron(netuid, hotkey2, coldkey2, 39420843);

let submetagraphs = SubtensorModule::get_submetagraphs(netuid);
assert_eq!(submetagraphs.len(), 2);

// Verify that mechagraphs exist and contain neuron data
// We verify by comparing with direct get_mechagraph calls
for (idx, metagraph_opt) in submetagraphs.iter().enumerate() {
assert!(
metagraph_opt.is_some(),
"Mechagraph at index {} should exist",
idx
);

// Verify it matches the direct call
let direct_mechagraph =
SubtensorModule::get_mechagraph(netuid, MechId::from(idx as u8));
assert_eq!(metagraph_opt.is_some(), direct_mechagraph.is_some());
}
});
}
4 changes: 4 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2394,6 +2394,10 @@ impl_runtime_apis! {
SubtensorModule::get_all_mechagraphs()
}

fn get_submetagraphs(netuid: NetUid) -> Vec<Option<Metagraph<AccountId32>>> {
SubtensorModule::get_submetagraphs(netuid)
}

fn get_all_dynamic_info() -> Vec<Option<DynamicInfo<AccountId32>>> {
SubtensorModule::get_all_dynamic_info()
}
Expand Down