Skip to content

Commit c7e88f6

Browse files
committed
add rate limit test and impl for fix
1 parent 44d6859 commit c7e88f6

File tree

2 files changed

+81
-5
lines changed

2 files changed

+81
-5
lines changed

pallets/subtensor/src/utils/rate_limiting.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ impl<T: Config> Pallet<T> {
3535
// ==== Rate Limiting =====
3636
// ========================
3737
/// Get the rate limit for a specific transaction type
38-
pub fn get_rate_limit(tx_type: &TransactionType) -> u64 {
38+
pub fn get_rate_limit(tx_type: &TransactionType, netuid: u16) -> u64 {
39+
let subnet_tempo = Self::get_tempo(netuid);
3940
match tx_type {
40-
TransactionType::SetChildren => (DefaultTempo::<T>::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period.
41+
TransactionType::SetChildren => (subnet_tempo.saturating_mul(2)).into(), // Cannot set children twice within the default tempo period.
4142
TransactionType::SetChildkeyTake => TxChildkeyTakeRateLimit::<T>::get(),
4243
TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit)
4344
}
@@ -50,7 +51,7 @@ impl<T: Config> Pallet<T> {
5051
netuid: u16,
5152
) -> bool {
5253
let block: u64 = Self::get_current_block_as_u64();
53-
let limit: u64 = Self::get_rate_limit(tx_type);
54+
let limit: u64 = Self::get_rate_limit(tx_type, netuid);
5455
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
5556

5657
// Allow the first transaction (when last_block is 0) or if the rate limit has passed
@@ -61,7 +62,7 @@ impl<T: Config> Pallet<T> {
6162
pub fn passes_rate_limit_globally(tx_type: &TransactionType, hotkey: &T::AccountId) -> bool {
6263
let netuid: u16 = u16::MAX;
6364
let block: u64 = Self::get_current_block_as_u64();
64-
let limit: u64 = Self::get_rate_limit(tx_type);
65+
let limit: u64 = Self::get_rate_limit(tx_type, 0);
6566
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
6667
block.saturating_sub(last_block) >= limit
6768
}

pallets/subtensor/tests/children.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ fn test_childkey_take_rate_limiting() {
999999
&hotkey,
10001000
netuid,
10011001
);
1002-
let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildkeyTake);
1002+
let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildkeyTake, 0);
10031003
log::info!(
10041004
"Rate limit info: current_block: {}, last_block: {}, limit: {}, passes: {}, diff: {}",
10051005
current_block,
@@ -3702,3 +3702,78 @@ fn test_childkey_take_drain_validator_take() {
37023702
));
37033703
});
37043704
}
3705+
3706+
// 60: Test set_children rate limiting - Fail then succeed
3707+
// This test ensures that an immediate second `set_children` transaction fails due to rate limiting:
3708+
// - Sets up a network and registers a hotkey
3709+
// - Performs a `set_children` transaction
3710+
// - Attempts a second `set_children` transaction immediately
3711+
// - Verifies that the second transaction fails with `TxRateLimitExceeded`
3712+
// Then the rate limit period passes and the second transaction succeeds
3713+
// - Steps blocks for the rate limit period
3714+
// - Attempts the second transaction again and verifies it succeeds
3715+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_children_rate_limit_fail_then_succeed --exact --nocapture
3716+
#[test]
3717+
fn test_set_children_rate_limit_fail_then_succeed() {
3718+
new_test_ext(1).execute_with(|| {
3719+
let coldkey = U256::from(1);
3720+
let hotkey = U256::from(2);
3721+
let child = U256::from(3);
3722+
let child2 = U256::from(4);
3723+
let netuid: u16 = 1;
3724+
let tempo = 13;
3725+
3726+
// Add network and register hotkey
3727+
add_network(netuid, tempo, 0);
3728+
register_ok_neuron(netuid, hotkey, coldkey, 0);
3729+
3730+
// First set_children transaction
3731+
assert_ok!(SubtensorModule::do_set_children(
3732+
RuntimeOrigin::signed(coldkey),
3733+
hotkey,
3734+
netuid,
3735+
vec![(100, child)]
3736+
));
3737+
3738+
// Immediate second transaction should fail due to rate limit
3739+
assert_noop!(
3740+
SubtensorModule::do_set_children(
3741+
RuntimeOrigin::signed(coldkey),
3742+
hotkey,
3743+
netuid,
3744+
vec![(100, child2)]
3745+
),
3746+
Error::<Test>::TxRateLimitExceeded
3747+
);
3748+
3749+
// Verify first children assignment remains
3750+
let children = SubtensorModule::get_children(&hotkey, netuid);
3751+
assert_eq!(children, vec![(100, child)]);
3752+
3753+
// Try again after rate limit period has passed
3754+
// Check rate limit
3755+
let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildren, netuid);
3756+
3757+
// Step that many blocks
3758+
step_block(limit as u16);
3759+
3760+
// Verify rate limit passes
3761+
assert!(SubtensorModule::passes_rate_limit_on_subnet(
3762+
&TransactionType::SetChildren,
3763+
&hotkey,
3764+
netuid
3765+
));
3766+
3767+
// Try again
3768+
assert_ok!(SubtensorModule::do_set_children(
3769+
RuntimeOrigin::signed(coldkey),
3770+
hotkey,
3771+
netuid,
3772+
vec![(100, child2)]
3773+
));
3774+
3775+
// Verify children assignment has changed
3776+
let children = SubtensorModule::get_children(&hotkey, netuid);
3777+
assert_eq!(children, vec![(100, child2)]);
3778+
});
3779+
}

0 commit comments

Comments
 (0)