Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
bbc035f
Basic framing for sub-subnets
gztensor Aug 22, 2025
2c447fd
Refactored epoch, tests failing
gztensor Aug 26, 2025
27ddaff
Simplify bonds calculation (no subsubnet logic for ema)
gztensor Aug 26, 2025
9646bfc
Fix hotkey emission tuples
gztensor Aug 27, 2025
cc186bd
Merge branch 'devnet-ready' into feat/subsubnets
gztensor Aug 27, 2025
1a06146
Epoch refactored, all tests pass
gztensor Aug 27, 2025
842dda4
happy clippy
gztensor Aug 27, 2025
4e1e7bf
Add state cleanup on subsubnet reduction, cleanup
gztensor Aug 27, 2025
fff6f0b
auto-update benchmark weights
github-actions[bot] Aug 27, 2025
f251b01
Add test plan
gztensor Aug 27, 2025
c4d5f98
Merge branch 'feat/subsubnets' of github.com:opentensor/subtensor int…
gztensor Aug 27, 2025
df6e32b
Convert TimelockedWeightCommits to be per-subnet and use NetUidStorag…
gztensor Aug 28, 2025
5dec426
Add netuid index math tests
gztensor Aug 28, 2025
9ddf6dc
Add tests for subsubnets
gztensor Aug 29, 2025
163c3f7
Fix Bonds cleanup on subnet removal
gztensor Aug 29, 2025
db2aa8c
Add more tests for subsubnets. Merge test plan with bit
gztensor Aug 29, 2025
20e0cc2
Merge branch 'devnet-ready' into feat/subsubnets
gztensor Aug 30, 2025
07a2f70
auto-update benchmark weights
github-actions[bot] Aug 30, 2025
8b244eb
Merge branch 'devnet-ready' into feat/subsubnets
gztensor Sep 2, 2025
241c33c
auto-update benchmark weights
github-actions[bot] Sep 2, 2025
0d8234f
Add weight setting/removing tests
gztensor Sep 3, 2025
6eff7f6
Merge branch 'feat/subsubnets' of github.com:opentensor/subtensor int…
gztensor Sep 3, 2025
100f6e2
Add rate limit test for committing timelocked weights
gztensor Sep 3, 2025
88dd86c
Add admin-until call to set desired subsubnet count and test
gztensor Sep 3, 2025
4b3d2d3
Add settable emission split between subsubnets
gztensor Sep 3, 2025
afa8129
Add per-subsubnet RPC for metagraph
gztensor Sep 3, 2025
452390d
Use epoch index for super-block calculation
gztensor Sep 4, 2025
2353767
Fix super-block decrease test, add super-block increase test
gztensor Sep 4, 2025
0eaf230
Add testing of SubsubnetEmissionSplit reset
gztensor Sep 4, 2025
412a247
Add emission tests
gztensor Sep 4, 2025
af8161a
Merge branch 'devnet-ready' into feat/subsubnets
gztensor Sep 4, 2025
700a882
Format
gztensor Sep 4, 2025
b919b5d
Fix merge
gztensor Sep 4, 2025
56453e9
Fix clippy
gztensor Sep 4, 2025
5811d0f
Fix clippy
gztensor Sep 4, 2025
2cd3f5e
Fix emission aggregation
gztensor Sep 4, 2025
f991eca
Spec bump
gztensor Sep 4, 2025
04c8ce1
Merge branch 'devnet-ready' into feat/subsubnets
gztensor Sep 4, 2025
75ea596
auto-update benchmark weights
github-actions[bot] Sep 5, 2025
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
156 changes: 156 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,162 @@ pub mod time {
pub const DAYS: BlockNumber = HOURS * 24;
}

#[freeze_struct("8e576b32bb1bb664")]
#[repr(transparent)]
#[derive(
Deserialize,
Serialize,
Clone,
Copy,
Decode,
DecodeWithMemTracking,
Default,
Encode,
Eq,
Hash,
MaxEncodedLen,
Ord,
PartialEq,
PartialOrd,
RuntimeDebug,
)]
#[serde(transparent)]
pub struct SubId(u8);

impl SubId {
pub const MAIN: SubId = Self(0);
}

impl From<u8> for SubId {
fn from(value: u8) -> Self {
Self(value)
}
}

impl From<SubId> for u16 {
fn from(val: SubId) -> Self {
u16::from(val.0)
}
}

impl From<SubId> for u64 {
fn from(val: SubId) -> Self {
u64::from(val.0)
}
}

impl From<SubId> for u8 {
fn from(val: SubId) -> Self {
u8::from(val.0)
}
}

impl Display for SubId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}

impl CompactAs for SubId {
type As = u8;

fn encode_as(&self) -> &Self::As {
&self.0
}

fn decode_from(v: Self::As) -> Result<Self, CodecError> {
Ok(Self(v))
}
}

impl From<Compact<SubId>> for SubId {
fn from(c: Compact<SubId>) -> Self {
c.0
}
}

impl TypeInfo for SubId {
type Identity = <u8 as TypeInfo>::Identity;
fn type_info() -> scale_info::Type {
<u8 as TypeInfo>::type_info()
}
}

#[freeze_struct("2d995c5478e16d4d")]
#[repr(transparent)]
#[derive(
Deserialize,
Serialize,
Clone,
Copy,
Decode,
DecodeWithMemTracking,
Default,
Encode,
Eq,
Hash,
MaxEncodedLen,
Ord,
PartialEq,
PartialOrd,
RuntimeDebug,
)]
#[serde(transparent)]
pub struct NetUidStorageIndex(u16);

impl NetUidStorageIndex {
pub const ROOT: NetUidStorageIndex = Self(0);
}

impl Display for NetUidStorageIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}

impl CompactAs for NetUidStorageIndex {
type As = u16;

fn encode_as(&self) -> &Self::As {
&self.0
}

fn decode_from(v: Self::As) -> Result<Self, CodecError> {
Ok(Self(v))
}
}

impl From<Compact<NetUidStorageIndex>> for NetUidStorageIndex {
fn from(c: Compact<NetUidStorageIndex>) -> Self {
c.0
}
}

impl From<NetUid> for NetUidStorageIndex {
fn from(val: NetUid) -> Self {
val.0.into()
}
}

impl From<NetUidStorageIndex> for u16 {
fn from(val: NetUidStorageIndex) -> Self {
val.0
}
}

impl From<u16> for NetUidStorageIndex {
fn from(value: u16) -> Self {
Self(value)
}
}

impl TypeInfo for NetUidStorageIndex {
type Identity = <u16 as TypeInfo>::Identity;
fn type_info() -> scale_info::Type {
<u16 as TypeInfo>::type_info()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
34 changes: 32 additions & 2 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use pallet::*;
// - we could use a type parameter for `AuthorityId`, but there is
// no sense for this as GRANDPA's `AuthorityId` is not a parameter -- it's always the same
use sp_consensus_grandpa::AuthorityList;
use sp_runtime::{DispatchResult, RuntimeAppPublic, traits::Member};
use sp_runtime::{DispatchResult, RuntimeAppPublic, Vec, traits::Member};

mod benchmarking;

Expand All @@ -31,7 +31,7 @@ pub mod pallet {
use pallet_subtensor::utils::rate_limiting::TransactionType;
use sp_runtime::BoundedVec;
use substrate_fixed::types::I96F32;
use subtensor_runtime_common::{NetUid, TaoCurrency};
use subtensor_runtime_common::{NetUid, SubId, TaoCurrency};

/// The main data structure of the module.
#[pallet::pallet]
Expand Down Expand Up @@ -1619,6 +1619,36 @@ pub mod pallet {
log::debug!("CKBurnSet( burn: {burn:?} ) ");
Ok(())
}

/// Sets the desired number of subsubnets in a subnet
#[pallet::call_index(74)]
#[pallet::weight(Weight::from_parts(15_000_000, 0)
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(1_u64))
.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1_u64)))]
pub fn sudo_set_desired_subsubnet_count(
origin: OriginFor<T>,
netuid: NetUid,
subsub_count: SubId,
) -> DispatchResult {
pallet_subtensor::Pallet::<T>::ensure_subnet_owner_or_root(origin, netuid)?;
pallet_subtensor::Pallet::<T>::do_set_desired_subsubnet_count(netuid, subsub_count)?;
Ok(())
}

/// Sets the emission split between subsubnets in a subnet
#[pallet::call_index(75)]
#[pallet::weight(Weight::from_parts(15_000_000, 0)
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(1_u64))
.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1_u64)))]
pub fn sudo_set_subsubnet_emission_split(
origin: OriginFor<T>,
netuid: NetUid,
maybe_split: Option<Vec<u16>>,
) -> DispatchResult {
pallet_subtensor::Pallet::<T>::ensure_subnet_owner_or_root(origin, netuid)?;
pallet_subtensor::Pallet::<T>::do_set_emission_split(netuid, maybe_split)?;
Ok(())
}
}
}

Expand Down
54 changes: 50 additions & 4 deletions pallets/admin-utils/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use pallet_subtensor::Event;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
use sp_core::{Get, Pair, U256, ed25519};
use substrate_fixed::types::I96F32;
use subtensor_runtime_common::{Currency, NetUid, TaoCurrency};
use subtensor_runtime_common::{Currency, NetUid, SubId, TaoCurrency};

use crate::Error;
use crate::pallet::PrecompileEnable;
Expand Down Expand Up @@ -827,7 +827,7 @@ fn test_sudo_set_bonds_moving_average() {
let netuid = NetUid::from(1);
let to_be_set: u64 = 10;
add_network(netuid, 10);
let init_value: u64 = SubtensorModule::get_bonds_moving_average(netuid);
let init_value: u64 = SubtensorModule::get_bonds_moving_average(netuid.into());
assert_eq!(
AdminUtils::sudo_set_bonds_moving_average(
<<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
Expand All @@ -845,15 +845,18 @@ fn test_sudo_set_bonds_moving_average() {
Err(Error::<Test>::SubnetDoesNotExist.into())
);
assert_eq!(
SubtensorModule::get_bonds_moving_average(netuid),
SubtensorModule::get_bonds_moving_average(netuid.into()),
init_value
);
assert_ok!(AdminUtils::sudo_set_bonds_moving_average(
<<Test as Config>::RuntimeOrigin>::root(),
netuid,
to_be_set
));
assert_eq!(SubtensorModule::get_bonds_moving_average(netuid), to_be_set);
assert_eq!(
SubtensorModule::get_bonds_moving_average(netuid.into()),
to_be_set
);
});
}

Expand Down Expand Up @@ -2069,3 +2072,46 @@ fn test_sudo_set_max_burn() {
);
});
}

#[test]
fn test_sudo_set_desired_subsubnet_count() {
new_test_ext().execute_with(|| {
let netuid = NetUid::from(1);
let ss_count_ok = SubId::from(8);
let ss_count_bad = SubId::from(9);

let sn_owner = U256::from(1324);
add_network(netuid, 10);
// Set the Subnet Owner
SubnetOwner::<Test>::insert(netuid, sn_owner);

assert_eq!(
AdminUtils::sudo_set_desired_subsubnet_count(
<<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
netuid,
ss_count_ok
),
Err(DispatchError::BadOrigin)
);
assert_noop!(
AdminUtils::sudo_set_desired_subsubnet_count(
RuntimeOrigin::root(),
netuid,
ss_count_bad
),
pallet_subtensor::Error::<Test>::InvalidValue
);

assert_ok!(AdminUtils::sudo_set_desired_subsubnet_count(
<<Test as Config>::RuntimeOrigin>::root(),
netuid,
ss_count_ok
));

assert_ok!(AdminUtils::sudo_set_desired_subsubnet_count(
<<Test as Config>::RuntimeOrigin>::signed(sn_owner),
netuid,
ss_count_ok
));
});
}
Loading