Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c42de52
commit Cargo.lock
Aug 29, 2025
bf7478e
cargo clippy
Aug 29, 2025
7e11d96
cargo fmt
Aug 29, 2025
7ae3dc8
Disable Keys::remove check for trim_to_max_allowed_uids
ales-otf Sep 1, 2025
d00cfc1
Add benchmark for trim_to_max_uids
ales-otf Sep 1, 2025
3c0ffb1
Fix wrong way ensure for min burn value, fix outdated comments
gztensor Sep 2, 2025
11c281f
Merge branch 'trim_uids' of github.com:opentensor/subtensor into trim…
gztensor Sep 2, 2025
86cce6f
add test + small refacto
l0r1s Sep 3, 2025
9e98561
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 3, 2025
3c8ff8e
cargo fmt
l0r1s Sep 3, 2025
eb001e3
fix misleading comment
l0r1s Sep 3, 2025
c7230d7
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 3, 2025
b96c60c
fix merge issue
l0r1s Sep 3, 2025
0b5e5b1
trim by emission and compress to the left
l0r1s Sep 3, 2025
15a3925
add sudo set min allowed uids
l0r1s Sep 9, 2025
ecc7f13
commit Cargo.lock
l0r1s Sep 9, 2025
30f3f0d
cargo fmt
l0r1s Sep 9, 2025
aa4c566
commit Cargo.lock
l0r1s Sep 9, 2025
4c9a3e2
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 9, 2025
b7e434c
fix merge
l0r1s Sep 9, 2025
26798bd
fix merge 2
l0r1s Sep 9, 2025
c19b71f
cargo fmt
l0r1s Sep 9, 2025
5dc32fd
added max immune percentage
l0r1s Sep 9, 2025
5a55def
fix imports
l0r1s Sep 9, 2025
0a033b2
cargo clippy
l0r1s Sep 9, 2025
2463441
commit Cargo.lock
l0r1s Sep 9, 2025
9e27dd0
cargo fmt
l0r1s Sep 9, 2025
e6fd948
restore clear_neuron
l0r1s Sep 10, 2025
f0b7188
restore clear_neuron 2
l0r1s Sep 10, 2025
04568f2
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 10, 2025
15ccf67
cargo fmt
l0r1s Sep 10, 2025
bf3c278
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 10, 2025
a027ba7
fix rate limit + call_index
l0r1s Sep 10, 2025
b2b9636
refacto to handle subsubnet when trimming uids
l0r1s Sep 10, 2025
20ef94a
fixed tests
l0r1s Sep 10, 2025
45bf58d
trigger ci
l0r1s Sep 11, 2025
a602599
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 12, 2025
b54ca79
fix get_immune_owner_hotkeys
l0r1s Sep 12, 2025
084407c
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 15, 2025
2ce716b
MinAllowedUids to 64
l0r1s Sep 15, 2025
cca14ab
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 15, 2025
a051137
extract rate limit
l0r1s Sep 15, 2025
ac5d6b3
fix benchmarks
l0r1s Sep 15, 2025
746cc61
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 16, 2025
aa4a23e
fix benchmarks
l0r1s Sep 16, 2025
5da86f1
cargo fmt
l0r1s Sep 16, 2025
261ef5a
auto-update benchmark weights
github-actions[bot] Sep 16, 2025
97efc75
Merge branch 'devnet-ready' into trim_uids
l0r1s Sep 16, 2025
f516593
fix rate limit
l0r1s Sep 16, 2025
d794795
auto-update benchmark weights
github-actions[bot] Sep 17, 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
11 changes: 11 additions & 0 deletions pallets/admin-utils/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,5 +346,16 @@ mod benchmarks {
_(RawOrigin::Root, 5u16/*version*/)/*sudo_set_commit_reveal_version()*/;
}

#[benchmark]
fn sudo_trim_to_max_allowed_uids() {
pallet_subtensor::Pallet::<T>::init_new_network(
1u16.into(), /*netuid*/
1u16, /*sudo_tempo*/
);

#[extrinsic_call]
_(RawOrigin::Root, 1u16.into()/*netuid*/, 4097u16/*max_allowed_uids*/)/*sudo_trim_to_max_allowed_uids()*/;
}

//impl_benchmark_test_suite!(AdminUtils, crate::mock::new_test_ext(), crate::mock::Test);
}
37 changes: 31 additions & 6 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,12 +677,12 @@ pub mod pallet {
ensure!(
min_burn < TaoCurrency::from(1_000_000_000),
Error::<T>::ValueNotInBounds
)
);
// Min burn must be less than max burn
ensure!(
min_burn > pallet_subtensor::Pallet::<T>::MaxBurn(netuid),
min_burn > pallet_subtensor::Pallet::<T>::get_max_burn(netuid),
Error::<T>::ValueNotInBounds
)
);
pallet_subtensor::Pallet::<T>::set_min_burn(netuid, min_burn);
log::debug!("MinBurnSet( netuid: {netuid:?} min_burn: {min_burn:?} ) ");
Ok(())
Expand All @@ -709,12 +709,12 @@ pub mod pallet {
ensure!(
max_burn > TaoCurrency::from(100_000_000),
Error::<T>::ValueNotInBounds
)
);
// Max burn must be greater than min burn
ensure!(
max_burn > pallet_subtensor::Pallet::<T>::MinBurn(netuid),
max_burn > pallet_subtensor::Pallet::<T>::get_min_burn(netuid),
Error::<T>::ValueNotInBounds
)
);
pallet_subtensor::Pallet::<T>::set_max_burn(netuid, max_burn);
log::debug!("MaxBurnSet( netuid: {netuid:?} max_burn: {max_burn:?} ) ");
Ok(())
Expand Down Expand Up @@ -1703,6 +1703,31 @@ pub mod pallet {
pallet_subtensor::Pallet::<T>::set_owner_immune_neuron_limit(netuid, immune_neurons)?;
Ok(())
}

/// Sets the number of immune owner neurons
#[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_trim_to_max_allowed_uids(
origin: OriginFor<T>,
netuid: NetUid,
max_n: u16,
) -> DispatchResult {
pallet_subtensor::Pallet::<T>::ensure_subnet_owner_or_root(origin.clone(), netuid)?;
if let Ok(RawOrigin::Signed(who)) = origin.into() {
ensure!(
pallet_subtensor::Pallet::<T>::passes_rate_limit_on_subnet(
&TransactionType::SetMaxAllowedUIDS,
&who,
netuid,
),
pallet_subtensor::Error::<T>::TxRateLimitExceeded
);
}
pallet_subtensor::Pallet::<T>::trim_to_max_allowed_uids(netuid, max_n)?;
Ok(())
}
}
}

Expand Down
148 changes: 137 additions & 11 deletions pallets/subtensor/src/subnets/uids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@ impl<T: Config> Pallet<T> {
}
}

/// Resets the trust, emission, consensus, incentive, dividends of the neuron to default
pub fn clear_neuron(netuid: NetUid, neuron_uid: u16) {
let neuron_index: usize = neuron_uid.into();
Emission::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0.into()));
Trust::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Consensus::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Incentive::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Dividends::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Bonds::<T>::remove(netuid, neuron_uid); // Remove bonds for Validator.
}

/// Replace the neuron under this uid.
pub fn replace_neuron(
netuid: NetUid,
Expand Down Expand Up @@ -107,6 +96,143 @@ impl<T: Config> Pallet<T> {
IsNetworkMember::<T>::insert(new_hotkey.clone(), netuid, true); // Fill network is member.
}

/// Appends the uid to the network.
pub fn clear_neuron(netuid: NetUid, neuron_uid: u16) {
let neuron_index: usize = neuron_uid.into();
Emission::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0.into()));
Trust::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Consensus::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Incentive::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Dividends::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
Bonds::<T>::remove(netuid, neuron_uid); // Remove bonds for Validator.
}

pub fn trim_to_max_allowed_uids(netuid: NetUid, max_n: u16) -> DispatchResult {
// Reasonable limits
ensure!(
Self::if_subnet_exist(netuid),
Error::<T>::SubNetworkDoesNotExist
);
ensure!(max_n > 16, Error::<T>::InvalidValue);
ensure!(
max_n <= Self::get_max_allowed_uids(netuid),
Error::<T>::InvalidValue
);

// Set the value.
MaxAllowedUids::<T>::insert(netuid, max_n);

// Check if we need to trim.
let current_n: u16 = Self::get_subnetwork_n(netuid);

// We need to trim, get rid of values between max_n and current_n.
if current_n > max_n {
let ranks: Vec<u16> = Rank::<T>::get(netuid);
let trimmed_ranks: Vec<u16> = ranks.into_iter().take(max_n as usize).collect();
Rank::<T>::insert(netuid, trimmed_ranks);

let trust: Vec<u16> = Trust::<T>::get(netuid);
let trimmed_trust: Vec<u16> = trust.into_iter().take(max_n as usize).collect();
Trust::<T>::insert(netuid, trimmed_trust);

let active: Vec<bool> = Active::<T>::get(netuid);
let trimmed_active: Vec<bool> = active.into_iter().take(max_n as usize).collect();
Active::<T>::insert(netuid, trimmed_active);

let emission: Vec<AlphaCurrency> = Emission::<T>::get(netuid);
let trimmed_emission: Vec<AlphaCurrency> =
emission.into_iter().take(max_n as usize).collect();
Emission::<T>::insert(netuid, trimmed_emission);

let consensus: Vec<u16> = Consensus::<T>::get(netuid);
let trimmed_consensus: Vec<u16> = consensus.into_iter().take(max_n as usize).collect();
Consensus::<T>::insert(netuid, trimmed_consensus);

let incentive: Vec<u16> = Incentive::<T>::get(netuid);
let trimmed_incentive: Vec<u16> = incentive.into_iter().take(max_n as usize).collect();
Incentive::<T>::insert(netuid, trimmed_incentive);

let dividends: Vec<u16> = Dividends::<T>::get(netuid);
let trimmed_dividends: Vec<u16> = dividends.into_iter().take(max_n as usize).collect();
Dividends::<T>::insert(netuid, trimmed_dividends);

let lastupdate: Vec<u64> = LastUpdate::<T>::get(netuid);
let trimmed_lastupdate: Vec<u64> =
lastupdate.into_iter().take(max_n as usize).collect();
LastUpdate::<T>::insert(netuid, trimmed_lastupdate);

let pruning_scores: Vec<u16> = PruningScores::<T>::get(netuid);
let trimmed_pruning_scores: Vec<u16> =
pruning_scores.into_iter().take(max_n as usize).collect();
PruningScores::<T>::insert(netuid, trimmed_pruning_scores);

let vtrust: Vec<u16> = ValidatorTrust::<T>::get(netuid);
let trimmed_vtrust: Vec<u16> = vtrust.into_iter().take(max_n as usize).collect();
ValidatorTrust::<T>::insert(netuid, trimmed_vtrust);

let vpermit: Vec<bool> = ValidatorPermit::<T>::get(netuid);
let trimmed_vpermit: Vec<bool> = vpermit.into_iter().take(max_n as usize).collect();
ValidatorPermit::<T>::insert(netuid, trimmed_vpermit);

let stake_weight: Vec<u16> = StakeWeight::<T>::get(netuid);
let trimmed_stake_weight: Vec<u16> =
stake_weight.into_iter().take(max_n as usize).collect();
StakeWeight::<T>::insert(netuid, trimmed_stake_weight);

// Trim UIDs and Keys by removing entries with UID >= max_n (since UIDs are 0-indexed)
// UIDs range from 0 to current_n-1, so we remove UIDs from max_n to current_n-1
for uid in max_n..current_n {
if let Ok(hotkey) = Keys::<T>::try_get(netuid, uid) {
Uids::<T>::remove(netuid, &hotkey);
// Remove IsNetworkMember association for the hotkey
IsNetworkMember::<T>::remove(&hotkey, netuid);
// Remove last hotkey emission for the hotkey
LastHotkeyEmissionOnNetuid::<T>::remove(&hotkey, netuid);
// Remove alpha dividends for the hotkey
AlphaDividendsPerSubnet::<T>::remove(netuid, &hotkey);
// Remove tao dividends for the hotkey
TaoDividendsPerSubnet::<T>::remove(netuid, &hotkey);
}
#[allow(unknown_lints)]
Keys::<T>::remove(netuid, uid);
// Remove block at registration for the uid
BlockAtRegistration::<T>::remove(netuid, uid);
}

// Trim weights and bonds for removed UIDs
for uid in max_n..current_n {
Weights::<T>::remove(netuid, uid);
Bonds::<T>::remove(netuid, uid);
}

// Trim axons, certificates, and prometheus info for removed hotkeys
for uid in max_n..current_n {
if let Ok(hotkey) = Keys::<T>::try_get(netuid, uid) {
Axons::<T>::remove(netuid, &hotkey);
NeuronCertificates::<T>::remove(netuid, &hotkey);
Prometheus::<T>::remove(netuid, &hotkey);
}
}

// Trim weight and bond connections to removed UIDs for remaining neurons
// UIDs 0 to max_n-1 are kept, so we iterate through these valid UIDs
for uid in 0..max_n {
Weights::<T>::mutate(netuid, uid, |weights| {
weights.retain(|(target_uid, _)| *target_uid < max_n);
});
Bonds::<T>::mutate(netuid, uid, |bonds| {
bonds.retain(|(target_uid, _)| *target_uid < max_n);
});
}

// Update the subnetwork size
SubnetworkN::<T>::insert(netuid, max_n);
}

// --- Ok and done.
Ok(())
}

/// Returns true if the uid is set on the network.
///
pub fn is_uid_exist_on_network(netuid: NetUid, uid: u16) -> bool {
Expand Down
7 changes: 4 additions & 3 deletions pallets/subtensor/src/utils/rate_limiting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum TransactionType {
RegisterNetwork,
SetWeightsVersionKey,
SetSNOwnerHotkey,
SetMaxAllowedUIDS,
}

/// Implement conversion from TransactionType to u16
Expand All @@ -23,6 +24,7 @@ impl From<TransactionType> for u16 {
TransactionType::RegisterNetwork => 3,
TransactionType::SetWeightsVersionKey => 4,
TransactionType::SetSNOwnerHotkey => 5,
TransactionType::SetMaxAllowedUIDS => 6,
}
}
}
Expand All @@ -36,6 +38,7 @@ impl From<u16> for TransactionType {
3 => TransactionType::RegisterNetwork,
4 => TransactionType::SetWeightsVersionKey,
5 => TransactionType::SetSNOwnerHotkey,
6 => TransactionType::SetMaxAllowedUIDS,
_ => TransactionType::Unknown,
}
}
Expand All @@ -50,7 +53,7 @@ impl<T: Config> Pallet<T> {
TransactionType::SetChildren => 150, // 30 minutes
TransactionType::SetChildkeyTake => TxChildkeyTakeRateLimit::<T>::get(),
TransactionType::RegisterNetwork => NetworkRateLimit::<T>::get(),

TransactionType::SetMaxAllowedUIDS => 7200 * 30,
TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit)
_ => 0,
}
Expand All @@ -62,7 +65,6 @@ impl<T: Config> Pallet<T> {
TransactionType::SetWeightsVersionKey => (Tempo::<T>::get(netuid) as u64)
.saturating_mul(WeightsVersionKeyRateLimit::<T>::get()),
TransactionType::SetSNOwnerHotkey => DefaultSetSNOwnerHotkeyRateLimit::<T>::get(),

_ => Self::get_rate_limit(tx_type),
}
}
Expand All @@ -89,7 +91,6 @@ impl<T: Config> Pallet<T> {
let block: u64 = Self::get_current_block_as_u64();
let limit: u64 = Self::get_rate_limit_on_subnet(tx_type, netuid);
let last_block: u64 = Self::get_last_transaction_block_on_subnet(hotkey, netuid, tx_type);

Self::check_passes_rate_limit(limit, block, last_block)
}

Expand Down
Loading