Skip to content

Commit 26267f5

Browse files
authored
Merge pull request #1655 from opentensor/devnet
testnet deploy 5/20/2025
2 parents ee7bad9 + 70a77f5 commit 26267f5

File tree

12 files changed

+531
-61
lines changed

12 files changed

+531
-61
lines changed

pallets/subtensor/src/epoch/math.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,22 @@ pub fn is_topk(vector: &[I32F32], k: usize) -> Vec<bool> {
246246
result
247247
}
248248

249+
// Returns a bool vector where an item is true if the vector item is in topk values and is non-zero.
250+
#[allow(dead_code, clippy::indexing_slicing)]
251+
pub fn is_topk_nonzero(vector: &[I32F32], k: usize) -> Vec<bool> {
252+
let n: usize = vector.len();
253+
let mut result: Vec<bool> = vector.iter().map(|&elem| elem != I32F32::from(0)).collect();
254+
if n < k {
255+
return result;
256+
}
257+
let mut idxs: Vec<usize> = (0..n).collect();
258+
idxs.sort_by_key(|&idx| &vector[idx]); // ascending stable sort
259+
for &idx in idxs.iter().take(n.saturating_sub(k)) {
260+
result[idx] = false;
261+
}
262+
result
263+
}
264+
249265
// Returns a normalized (sum to 1 except 0) copy of the input vector.
250266
#[allow(dead_code)]
251267
pub fn normalize(x: &[I32F32]) -> Vec<I32F32> {

pallets/subtensor/src/epoch/run_epoch.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,26 @@ impl<T: Config> Pallet<T> {
8080
log::trace!("hotkeys: {:?}", &hotkeys);
8181

8282
// Access network stake as normalized vector.
83-
let (mut total_stake, _alpha_stake, _tao_stake): (Vec<I64F64>, Vec<I64F64>, Vec<I64F64>) =
83+
let (total_stake, _alpha_stake, _tao_stake): (Vec<I64F64>, Vec<I64F64>, Vec<I64F64>) =
8484
Self::get_stake_weights_for_network(netuid);
85-
inplace_normalize_64(&mut total_stake);
86-
let stake: Vec<I32F32> = vec_fixed64_to_fixed32(total_stake);
85+
86+
// Get the minimum stake required.
87+
let min_stake = Self::get_stake_threshold();
88+
89+
// Set stake of validators that doesn't meet the staking threshold to 0 as filter.
90+
let mut filtered_stake: Vec<I64F64> = total_stake
91+
.iter()
92+
.map(|&s| {
93+
if fixed64_to_u64(s) < min_stake {
94+
return I64F64::from(0);
95+
}
96+
s
97+
})
98+
.collect();
99+
log::debug!("Filtered stake: {:?}", &filtered_stake);
100+
101+
inplace_normalize_64(&mut filtered_stake);
102+
let stake: Vec<I32F32> = vec_fixed64_to_fixed32(filtered_stake);
87103
log::trace!("S: {:?}", &stake);
88104

89105
// =======================
@@ -102,7 +118,8 @@ impl<T: Config> Pallet<T> {
102118
log::trace!("max_allowed_validators: {:?}", max_allowed_validators);
103119

104120
// Get new validator permits.
105-
let new_validator_permits: Vec<bool> = is_topk(&stake, max_allowed_validators as usize);
121+
let new_validator_permits: Vec<bool> =
122+
is_topk_nonzero(&stake, max_allowed_validators as usize);
106123
log::trace!("new_validator_permits: {:?}", new_validator_permits);
107124

108125
// ==================
@@ -470,10 +487,26 @@ impl<T: Config> Pallet<T> {
470487
log::debug!("hotkeys: {:?}", &hotkeys);
471488

472489
// Access network stake as normalized vector.
473-
let (mut total_stake, _alpha_stake, _tao_stake): (Vec<I64F64>, Vec<I64F64>, Vec<I64F64>) =
490+
let (total_stake, _alpha_stake, _tao_stake): (Vec<I64F64>, Vec<I64F64>, Vec<I64F64>) =
474491
Self::get_stake_weights_for_network(netuid);
475-
inplace_normalize_64(&mut total_stake);
476-
let stake: Vec<I32F32> = vec_fixed64_to_fixed32(total_stake);
492+
493+
// Get the minimum stake required.
494+
let min_stake = Self::get_stake_threshold();
495+
496+
// Set stake of validators that doesn't meet the staking threshold to 0 as filter.
497+
let mut filtered_stake: Vec<I64F64> = total_stake
498+
.iter()
499+
.map(|&s| {
500+
if fixed64_to_u64(s) < min_stake {
501+
return I64F64::from(0);
502+
}
503+
s
504+
})
505+
.collect();
506+
log::debug!("Filtered stake: {:?}", &filtered_stake);
507+
508+
inplace_normalize_64(&mut filtered_stake);
509+
let stake: Vec<I32F32> = vec_fixed64_to_fixed32(filtered_stake);
477510
log::debug!("Normalised Stake: {:?}", &stake);
478511

479512
// =======================
@@ -492,7 +525,8 @@ impl<T: Config> Pallet<T> {
492525
log::trace!("max_allowed_validators: {:?}", max_allowed_validators);
493526

494527
// Get new validator permits.
495-
let new_validator_permits: Vec<bool> = is_topk(&stake, max_allowed_validators as usize);
528+
let new_validator_permits: Vec<bool> =
529+
is_topk_nonzero(&stake, max_allowed_validators as usize);
496530
log::trace!("new_validator_permits: {:?}", new_validator_permits);
497531

498532
// ==================

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ mod dispatches {
925925
/// User register a new subnetwork via burning token
926926
#[pallet::call_index(7)]
927927
#[pallet::weight((Weight::from_parts(219_400_000, 0)
928-
.saturating_add(T::DbWeight::get().reads(34))
928+
.saturating_add(T::DbWeight::get().reads(33))
929929
.saturating_add(T::DbWeight::get().writes(29)), DispatchClass::Normal, Pays::No))]
930930
pub fn burned_register(
931931
origin: OriginFor<T>,
@@ -1012,7 +1012,7 @@ mod dispatches {
10121012
#[pallet::call_index(75)]
10131013
#[pallet::weight((
10141014
Weight::from_parts(49_470_000, 0)
1015-
.saturating_add(T::DbWeight::get().reads(4))
1015+
.saturating_add(T::DbWeight::get().reads(5))
10161016
.saturating_add(T::DbWeight::get().writes(2)),
10171017
DispatchClass::Normal,
10181018
Pays::Yes

pallets/subtensor/src/staking/remove_stake.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ impl<T: Config> Pallet<T> {
617617
pub fn get_max_amount_remove(netuid: u16, limit_price: u64) -> Result<u64, Error<T>> {
618618
// Corner case: root and stao
619619
// There's no slippage for root or stable subnets, so if limit price is 1e9 rao or
620-
// higher, then max_amount equals u64::MAX, otherwise it is 0.
620+
// lower, then max_amount equals u64::MAX, otherwise it is 0.
621621
if (netuid == Self::get_root_netuid()) || (SubnetMechanism::<T>::get(netuid)) == 0 {
622622
if limit_price <= 1_000_000_000 {
623623
return Ok(u64::MAX);

pallets/subtensor/src/staking/set_children.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,19 @@ impl<T: Config> Pallet<T> {
317317
Error::<T>::InvalidChildkeyTake
318318
);
319319

320-
// Ensure the hotkey passes the rate limit.
321-
ensure!(
322-
Self::passes_rate_limit_on_subnet(
323-
&TransactionType::SetChildkeyTake, // Set childkey take.
324-
&hotkey, // Specific to a hotkey.
325-
netuid, // Specific to a subnet.
326-
),
327-
Error::<T>::TxChildkeyTakeRateLimitExceeded
328-
);
320+
let current_take = Self::get_childkey_take(&hotkey, netuid);
321+
// Check the rate limit for increasing childkey take case
322+
if take > current_take {
323+
// Ensure the hotkey passes the rate limit.
324+
ensure!(
325+
Self::passes_rate_limit_on_subnet(
326+
&TransactionType::SetChildkeyTake, // Set childkey take.
327+
&hotkey, // Specific to a hotkey.
328+
netuid, // Specific to a subnet.
329+
),
330+
Error::<T>::TxChildkeyTakeRateLimitExceeded
331+
);
332+
}
329333

330334
// Set last transaction block
331335
let current_block = Self::get_current_block_as_u64();

pallets/subtensor/src/subnets/registration.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ impl<T: Config> Pallet<T> {
8686
Error::<T>::SubNetworkDoesNotExist
8787
);
8888

89-
Self::ensure_subtoken_enabled(netuid)?;
90-
9189
// --- 3. Ensure the passed network allows registrations.
9290
ensure!(
9391
Self::get_network_registration_allowed(netuid),

pallets/subtensor/src/tests/children.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3988,3 +3988,109 @@ fn test_pending_cooldown_one_day() {
39883988
assert_eq!(pending_children.1, curr_block + expected_cooldown);
39893989
});
39903990
}
3991+
3992+
#[test]
3993+
fn test_do_set_childkey_take_success() {
3994+
new_test_ext(1).execute_with(|| {
3995+
// Setup
3996+
let coldkey = U256::from(1);
3997+
let hotkey = U256::from(2);
3998+
let netuid: u16 = 1;
3999+
let take = 5000;
4000+
4001+
// Add network and register hotkey
4002+
add_network(netuid, 13, 0);
4003+
register_ok_neuron(netuid, hotkey, coldkey, 0);
4004+
4005+
// Set childkey take
4006+
assert_ok!(SubtensorModule::do_set_childkey_take(
4007+
coldkey, hotkey, netuid, take
4008+
));
4009+
4010+
// Verify the take was set correctly
4011+
assert_eq!(SubtensorModule::get_childkey_take(&hotkey, netuid), take);
4012+
let tx_type: u16 = TransactionType::SetChildkeyTake.into();
4013+
assert_eq!(
4014+
TransactionKeyLastBlock::<Test>::get((hotkey, netuid, tx_type,)),
4015+
System::block_number()
4016+
);
4017+
});
4018+
}
4019+
4020+
#[test]
4021+
fn test_do_set_childkey_take_non_associated_coldkey() {
4022+
new_test_ext(1).execute_with(|| {
4023+
// Setup
4024+
let coldkey = U256::from(1);
4025+
let hotkey = U256::from(2);
4026+
let hotkey2 = U256::from(3);
4027+
let netuid: u16 = 1;
4028+
let take = 5000;
4029+
4030+
// Add network and register hotkey
4031+
add_network(netuid, 13, 0);
4032+
register_ok_neuron(netuid, hotkey, coldkey, 0);
4033+
4034+
// Set childkey take
4035+
assert_noop!(
4036+
SubtensorModule::do_set_childkey_take(coldkey, hotkey2, netuid, take),
4037+
Error::<Test>::NonAssociatedColdKey
4038+
);
4039+
});
4040+
}
4041+
4042+
#[test]
4043+
fn test_do_set_childkey_take_invalid_take_value() {
4044+
new_test_ext(1).execute_with(|| {
4045+
// Setup
4046+
let coldkey = U256::from(1);
4047+
let hotkey = U256::from(2);
4048+
let netuid: u16 = 1;
4049+
let take = SubtensorModule::get_max_childkey_take() + 1;
4050+
4051+
// Add network and register hotkey
4052+
add_network(netuid, 13, 0);
4053+
register_ok_neuron(netuid, hotkey, coldkey, 0);
4054+
4055+
// Set childkey take
4056+
assert_noop!(
4057+
SubtensorModule::do_set_childkey_take(coldkey, hotkey, netuid, take),
4058+
Error::<Test>::InvalidChildkeyTake
4059+
);
4060+
});
4061+
}
4062+
4063+
#[test]
4064+
fn test_do_set_childkey_take_rate_limit_exceeded() {
4065+
new_test_ext(1).execute_with(|| {
4066+
// Setup
4067+
let coldkey = U256::from(1);
4068+
let hotkey = U256::from(2);
4069+
let netuid: u16 = 1;
4070+
let initial_take = 3000;
4071+
let higher_take = 5000;
4072+
let lower_take = 1000;
4073+
4074+
add_network(netuid, 13, 0);
4075+
register_ok_neuron(netuid, hotkey, coldkey, 0);
4076+
4077+
// Set initial childkey take
4078+
assert_ok!(SubtensorModule::do_set_childkey_take(
4079+
coldkey,
4080+
hotkey,
4081+
netuid,
4082+
initial_take
4083+
));
4084+
4085+
// Try to increase the take value, should hit rate limit
4086+
assert_noop!(
4087+
SubtensorModule::do_set_childkey_take(coldkey, hotkey, netuid, higher_take),
4088+
Error::<Test>::TxChildkeyTakeRateLimitExceeded
4089+
);
4090+
4091+
// lower take value should be ok
4092+
assert_ok!(SubtensorModule::do_set_childkey_take(
4093+
coldkey, hotkey, netuid, lower_take
4094+
));
4095+
});
4096+
}

pallets/subtensor/src/tests/epoch.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,13 +2095,14 @@ fn test_deregistered_miner_bonds() {
20952095
});
20962096
}
20972097

2098-
// Test that epoch assigns validator permits to highest stake uids, varies uid interleaving and stake values.
2098+
// Test that epoch assigns validator permits to highest stake uids that are over the stake threshold, varies uid interleaving and stake values.
20992099
#[test]
21002100
fn test_validator_permits() {
21012101
let netuid: u16 = 1;
21022102
let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead
21032103
for interleave in 0..3 {
21042104
for (network_n, validators_n) in [(2, 1), (4, 2), (8, 4)] {
2105+
let min_stake = validators_n as u64;
21052106
for assignment in 0..=1 {
21062107
let (validators, servers) =
21072108
distribute_nodes(validators_n as usize, network_n, interleave as usize);
@@ -2132,6 +2133,7 @@ fn test_validator_permits() {
21322133
netuid,
21332134
network_n as u16,
21342135
);
2136+
SubtensorModule::set_stake_threshold(min_stake);
21352137

21362138
// === Register [validator1, validator2, server1, server2]
21372139
for key in 0..network_n as u64 {
@@ -2173,7 +2175,7 @@ fn test_validator_permits() {
21732175
SubtensorModule::epoch(netuid, 1_000_000_000); // run first epoch to set allowed validators
21742176
for validator in &validators {
21752177
assert_eq!(
2176-
correct,
2178+
stake[*validator as usize] >= min_stake,
21772179
SubtensorModule::get_validator_permit_for_uid(netuid, *validator)
21782180
);
21792181
}
@@ -2211,7 +2213,7 @@ fn test_validator_permits() {
22112213
}
22122214
for server in &servers {
22132215
assert_eq!(
2214-
correct,
2216+
(stake[*server as usize] + (2 * network_n as u64)) >= min_stake,
22152217
SubtensorModule::get_validator_permit_for_uid(netuid, *server)
22162218
);
22172219
}

0 commit comments

Comments
 (0)