Skip to content

Commit 7364b18

Browse files
authored
Merge pull request #1037 from opentensor/hotfix/set-children-rate-limit
[hotfix] Fix set children rate limit
2 parents 44d6859 + 7fdb692 commit 7364b18

File tree

6 files changed

+50924
-50813
lines changed

6 files changed

+50924
-50813
lines changed

pallets/subtensor/src/utils/rate_limiting.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use super::*;
2-
use sp_core::Get;
32

43
/// Enum representing different types of transactions
54
#[derive(Copy, Clone)]
@@ -35,9 +34,9 @@ impl<T: Config> Pallet<T> {
3534
// ==== Rate Limiting =====
3635
// ========================
3736
/// Get the rate limit for a specific transaction type
38-
pub fn get_rate_limit(tx_type: &TransactionType) -> u64 {
37+
pub fn get_rate_limit(tx_type: &TransactionType, _netuid: u16) -> u64 {
3938
match tx_type {
40-
TransactionType::SetChildren => (DefaultTempo::<T>::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period.
39+
TransactionType::SetChildren => 7200, // Cannot set children twice within a day
4140
TransactionType::SetChildkeyTake => TxChildkeyTakeRateLimit::<T>::get(),
4241
TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit)
4342
}
@@ -50,7 +49,7 @@ impl<T: Config> Pallet<T> {
5049
netuid: u16,
5150
) -> bool {
5251
let block: u64 = Self::get_current_block_as_u64();
53-
let limit: u64 = Self::get_rate_limit(tx_type);
52+
let limit: u64 = Self::get_rate_limit(tx_type, netuid);
5453
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
5554

5655
// Allow the first transaction (when last_block is 0) or if the rate limit has passed
@@ -61,7 +60,7 @@ impl<T: Config> Pallet<T> {
6160
pub fn passes_rate_limit_globally(tx_type: &TransactionType, hotkey: &T::AccountId) -> bool {
6261
let netuid: u16 = u16::MAX;
6362
let block: u64 = Self::get_current_block_as_u64();
64-
let limit: u64 = Self::get_rate_limit(tx_type);
63+
let limit: u64 = Self::get_rate_limit(tx_type, 0);
6564
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
6665
block.saturating_sub(last_block) >= limit
6766
}

pallets/subtensor/tests/children.rs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ fn test_do_set_child_singular_old_children_cleanup() {
172172
vec![(proportion, old_child)]
173173
));
174174

175+
step_rate_limit(&TransactionType::SetChildren, netuid);
176+
175177
// Set new child
176178
assert_ok!(SubtensorModule::do_set_children(
177179
RuntimeOrigin::signed(coldkey),
@@ -260,6 +262,8 @@ fn test_do_set_child_singular_proportion_edge_cases() {
260262
let children = SubtensorModule::get_children(&hotkey, netuid);
261263
assert_eq!(children, vec![(min_proportion, child)]);
262264

265+
step_rate_limit(&TransactionType::SetChildren, netuid);
266+
263267
// Set child with maximum proportion
264268
let max_proportion: u64 = u64::MAX;
265269
assert_ok!(SubtensorModule::do_set_children(
@@ -306,6 +310,8 @@ fn test_do_set_child_singular_multiple_children() {
306310
vec![(proportion1, child1)]
307311
));
308312

313+
step_rate_limit(&TransactionType::SetChildren, netuid);
314+
309315
// Set second child
310316
assert_ok!(SubtensorModule::do_set_children(
311317
RuntimeOrigin::signed(coldkey),
@@ -351,6 +357,7 @@ fn test_add_singular_child() {
351357
Err(Error::<Test>::SubNetworkDoesNotExist.into())
352358
);
353359
add_network(netuid, 0, 0);
360+
step_rate_limit(&TransactionType::SetChildren, netuid);
354361
assert_eq!(
355362
SubtensorModule::do_set_children(
356363
RuntimeOrigin::signed(coldkey),
@@ -361,6 +368,7 @@ fn test_add_singular_child() {
361368
Err(Error::<Test>::NonAssociatedColdKey.into())
362369
);
363370
SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
371+
step_rate_limit(&TransactionType::SetChildren, netuid);
364372
assert_eq!(
365373
SubtensorModule::do_set_children(
366374
RuntimeOrigin::signed(coldkey),
@@ -371,6 +379,7 @@ fn test_add_singular_child() {
371379
Err(Error::<Test>::InvalidChild.into())
372380
);
373381
let child = U256::from(3);
382+
step_rate_limit(&TransactionType::SetChildren, netuid);
374383
assert_ok!(SubtensorModule::do_set_children(
375384
RuntimeOrigin::signed(coldkey),
376385
hotkey,
@@ -467,6 +476,8 @@ fn test_do_revoke_child_singular_success() {
467476
let children = SubtensorModule::get_children(&hotkey, netuid);
468477
assert_eq!(children, vec![(proportion, child)]);
469478

479+
step_rate_limit(&TransactionType::SetChildren, netuid);
480+
470481
// Revoke child
471482
assert_ok!(SubtensorModule::do_set_children(
472483
RuntimeOrigin::signed(coldkey),
@@ -764,6 +775,8 @@ fn test_do_set_children_multiple_old_children_cleanup() {
764775
vec![(proportion, old_child)]
765776
));
766777

778+
step_rate_limit(&TransactionType::SetChildren, netuid);
779+
767780
// Set new children
768781
assert_ok!(SubtensorModule::do_set_children(
769782
RuntimeOrigin::signed(coldkey),
@@ -854,6 +867,8 @@ fn test_do_set_children_multiple_overwrite_existing() {
854867
vec![(proportion, child1), (proportion, child2)]
855868
));
856869

870+
step_rate_limit(&TransactionType::SetChildren, netuid);
871+
857872
// Overwrite with new children
858873
assert_ok!(SubtensorModule::do_set_children(
859874
RuntimeOrigin::signed(coldkey),
@@ -999,7 +1014,7 @@ fn test_childkey_take_rate_limiting() {
9991014
&hotkey,
10001015
netuid,
10011016
);
1002-
let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildkeyTake);
1017+
let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildkeyTake, 0);
10031018
log::info!(
10041019
"Rate limit info: current_block: {}, last_block: {}, limit: {}, passes: {}, diff: {}",
10051020
current_block,
@@ -1199,6 +1214,8 @@ fn test_do_revoke_children_multiple_success() {
11991214
vec![(proportion1, child1), (proportion2, child2)]
12001215
));
12011216

1217+
step_rate_limit(&TransactionType::SetChildren, netuid);
1218+
12021219
// Revoke multiple children
12031220
assert_ok!(SubtensorModule::do_set_children(
12041221
RuntimeOrigin::signed(coldkey),
@@ -1313,6 +1330,8 @@ fn test_do_revoke_children_multiple_partial_revocation() {
13131330
]
13141331
));
13151332

1333+
step_rate_limit(&TransactionType::SetChildren, netuid);
1334+
13161335
// Revoke only child3
13171336
assert_ok!(SubtensorModule::do_set_children(
13181337
RuntimeOrigin::signed(coldkey),
@@ -1364,6 +1383,8 @@ fn test_do_revoke_children_multiple_non_existent_children() {
13641383
vec![(proportion, child1)]
13651384
));
13661385

1386+
step_rate_limit(&TransactionType::SetChildren, netuid);
1387+
13671388
// Attempt to revoke existing and non-existent children
13681389
assert_ok!(SubtensorModule::do_set_children(
13691390
RuntimeOrigin::signed(coldkey),
@@ -1450,6 +1471,8 @@ fn test_do_revoke_children_multiple_complex_scenario() {
14501471
]
14511472
));
14521473

1474+
step_rate_limit(&TransactionType::SetChildren, netuid);
1475+
14531476
// Revoke child2
14541477
assert_ok!(SubtensorModule::do_set_children(
14551478
RuntimeOrigin::signed(coldkey),
@@ -1466,6 +1489,8 @@ fn test_do_revoke_children_multiple_complex_scenario() {
14661489
let parents2 = SubtensorModule::get_parents(&child2, netuid);
14671490
assert!(parents2.is_empty());
14681491

1492+
step_rate_limit(&TransactionType::SetChildren, netuid);
1493+
14691494
// Revoke remaining children
14701495
assert_ok!(SubtensorModule::do_set_children(
14711496
RuntimeOrigin::signed(coldkey),
@@ -2374,6 +2399,7 @@ fn test_dynamic_parent_child_relationships() {
23742399
step_block(11);
23752400

23762401
// Change parent-child relationships
2402+
step_rate_limit(&TransactionType::SetChildren, netuid);
23772403
assert_ok!(SubtensorModule::do_set_children(
23782404
RuntimeOrigin::signed(coldkey_parent),
23792405
parent,
@@ -3702,3 +3728,78 @@ fn test_childkey_take_drain_validator_take() {
37023728
));
37033729
});
37043730
}
3731+
3732+
// 60: Test set_children rate limiting - Fail then succeed
3733+
// This test ensures that an immediate second `set_children` transaction fails due to rate limiting:
3734+
// - Sets up a network and registers a hotkey
3735+
// - Performs a `set_children` transaction
3736+
// - Attempts a second `set_children` transaction immediately
3737+
// - Verifies that the second transaction fails with `TxRateLimitExceeded`
3738+
// Then the rate limit period passes and the second transaction succeeds
3739+
// - Steps blocks for the rate limit period
3740+
// - Attempts the second transaction again and verifies it succeeds
3741+
// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_children_rate_limit_fail_then_succeed --exact --nocapture
3742+
#[test]
3743+
fn test_set_children_rate_limit_fail_then_succeed() {
3744+
new_test_ext(1).execute_with(|| {
3745+
let coldkey = U256::from(1);
3746+
let hotkey = U256::from(2);
3747+
let child = U256::from(3);
3748+
let child2 = U256::from(4);
3749+
let netuid: u16 = 1;
3750+
let tempo = 13;
3751+
3752+
// Add network and register hotkey
3753+
add_network(netuid, tempo, 0);
3754+
register_ok_neuron(netuid, hotkey, coldkey, 0);
3755+
3756+
// First set_children transaction
3757+
assert_ok!(SubtensorModule::do_set_children(
3758+
RuntimeOrigin::signed(coldkey),
3759+
hotkey,
3760+
netuid,
3761+
vec![(100, child)]
3762+
));
3763+
3764+
// Immediate second transaction should fail due to rate limit
3765+
assert_noop!(
3766+
SubtensorModule::do_set_children(
3767+
RuntimeOrigin::signed(coldkey),
3768+
hotkey,
3769+
netuid,
3770+
vec![(100, child2)]
3771+
),
3772+
Error::<Test>::TxRateLimitExceeded
3773+
);
3774+
3775+
// Verify first children assignment remains
3776+
let children = SubtensorModule::get_children(&hotkey, netuid);
3777+
assert_eq!(children, vec![(100, child)]);
3778+
3779+
// Try again after rate limit period has passed
3780+
// Check rate limit
3781+
let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildren, netuid);
3782+
3783+
// Step that many blocks
3784+
step_block(limit as u16);
3785+
3786+
// Verify rate limit passes
3787+
assert!(SubtensorModule::passes_rate_limit_on_subnet(
3788+
&TransactionType::SetChildren,
3789+
&hotkey,
3790+
netuid
3791+
));
3792+
3793+
// Try again
3794+
assert_ok!(SubtensorModule::do_set_children(
3795+
RuntimeOrigin::signed(coldkey),
3796+
hotkey,
3797+
netuid,
3798+
vec![(100, child2)]
3799+
));
3800+
3801+
// Verify children assignment has changed
3802+
let children = SubtensorModule::get_children(&hotkey, netuid);
3803+
assert_eq!(children, vec![(100, child2)]);
3804+
});
3805+
}

pallets/subtensor/tests/mock.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use frame_support::{
1010
use frame_system as system;
1111
use frame_system::{limits, EnsureNever, EnsureRoot, RawOrigin};
1212
use pallet_collective::MemberCount;
13+
use pallet_subtensor::utils::rate_limiting::TransactionType;
1314
use sp_core::{Get, H256, U256};
1415
use sp_runtime::Perbill;
1516
use sp_runtime::{
@@ -601,3 +602,13 @@ pub fn is_within_tolerance(actual: u64, expected: u64, tolerance: u64) -> bool {
601602
};
602603
difference <= tolerance
603604
}
605+
606+
// Helper function to wait for the rate limit
607+
#[allow(dead_code)]
608+
pub fn step_rate_limit(transaction_type: &TransactionType, netuid: u16) {
609+
// Check rate limit
610+
let limit = SubtensorModule::get_rate_limit(transaction_type, netuid);
611+
612+
// Step that many blocks
613+
step_block(limit as u16);
614+
}

plain_spec_finney.json

Lines changed: 50805 additions & 50805 deletions
Large diffs are not rendered by default.

plain_spec_testfinney.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
160160
// `spec_version`, and `authoring_version` are the same between Wasm and native.
161161
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
162162
// the compatible custom types.
163-
spec_version: 211,
163+
spec_version: 212,
164164
impl_version: 1,
165165
apis: RUNTIME_API_VERSIONS,
166166
transaction_version: 1,

0 commit comments

Comments
 (0)