Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
a37cc79
Initialize pallet-rate-limiting
ales-otf Oct 17, 2025
e903915
Add transaction extension for rate limiting
ales-otf Oct 17, 2025
ea289ef
Implement contextual scope
ales-otf Oct 17, 2025
ebcec75
Add context resolver
ales-otf Oct 17, 2025
56333c9
Add default rate limit
ales-otf Oct 21, 2025
1b6b03c
Add genesis config for pallet-rate-limiting
ales-otf Oct 21, 2025
220c905
Add rpc method to fetch rate limit
ales-otf Oct 21, 2025
69151b1
Add tests to pallet-rate-limiting
ales-otf Oct 27, 2025
13b8774
Add crate-level documentation for pallet-rate-limiting
ales-otf Oct 27, 2025
a4a1c88
Add benchmarks for pallet-rate-limiting
ales-otf Oct 27, 2025
6414907
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Oct 29, 2025
6ccc421
Extend rate limit setting with context
ales-otf Oct 29, 2025
be9d4f7
Make rate limiting pallet instantiable
ales-otf Oct 29, 2025
61eb4d2
Refactor RateLimit type
ales-otf Oct 30, 2025
c84cb92
Separate context between usage key and limit scope
ales-otf Oct 30, 2025
f85320e
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Oct 30, 2025
2df6d4b
Update docs
ales-otf Oct 31, 2025
15c9aa9
Add an extrinsic to clear all scoped rate limits in pallet-rate-limiting
ales-otf Oct 31, 2025
e74d650
Clear LastSeen on clear_rate_limit call
ales-otf Oct 31, 2025
fc60465
Add rate limit bypassing
ales-otf Oct 31, 2025
5c8a8ab
Add rate limit adjuster
ales-otf Oct 31, 2025
1e8db7d
Add api to migrate scope and usage keys
ales-otf Nov 3, 2025
d65baff
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Nov 3, 2025
232de64
Pass origin to rate limit context resolvers
ales-otf Nov 3, 2025
11ba1b6
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Nov 5, 2025
e00342f
Implement rate-limiting resolvers for pallet-subtensor
ales-otf Nov 10, 2025
7705637
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Nov 12, 2025
69715be
Migrate pallet-subtensor's rate limiting to pallet-rate-limiting
ales-otf Nov 12, 2025
f717d4d
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Nov 17, 2025
821f1ff
Add grouped targets for pallet-rate-limiting
ales-otf Nov 19, 2025
8fcb615
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Nov 20, 2025
434f7e3
Add groups to rate-limiting migration
ales-otf Nov 21, 2025
eaca7aa
Configure pallet-rate-limiting for the runtime
ales-otf Nov 24, 2025
4eff5f5
Resolve git conflicts
ales-otf Nov 25, 2025
f7050e1
Clean up
ales-otf Nov 25, 2025
42ea14e
Add more tests for rate-limiting migration
ales-otf Nov 25, 2025
662a5ed
Fix rate limit scope resolver implementation
ales-otf Nov 26, 2025
34d5f26
Remove register-network calls from rate limit usage resolver
ales-otf Dec 1, 2025
41c56e0
Add read-only flag to grouped calls in pallet-rate-limiting
ales-otf Dec 1, 2025
b4fef32
Fix staking ops rate limiting migration
ales-otf Dec 1, 2025
28eb64b
Resolve git conflicts
ales-otf Dec 3, 2025
cd09153
Fix sudo_set_weights_version_key rate-limiting migration
ales-otf Dec 3, 2025
0d3a1d5
Refactor rate-limiting migration
ales-otf Dec 4, 2025
09ba878
Introduce BypassDesicion in pallet-rate-limiting
ales-otf Dec 4, 2025
95720cb
Fix reveal-weights bypassing and transfer stake ops rate-limiting
ales-otf Dec 5, 2025
56c1af9
Refactor rate-limiting migration
ales-otf Dec 8, 2025
953288f
Fix swap-keys rate-limiting migration
ales-otf Dec 10, 2025
b16eff0
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Dec 10, 2025
30d5e32
Decouple rate-limiting migration from legacy types
ales-otf Dec 11, 2025
483be0c
Add rate limiting interface
ales-otf Dec 12, 2025
d805203
Merge branch 'devnet-ready' into feat/rate-limit-pallet
ales-otf Dec 15, 2025
1228b8a
Add rate limiting interface for pallet-subtensor::Config
ales-otf Dec 15, 2025
0c1c6cb
Add limit setting rule to pallet-rate-limiting
ales-otf Dec 15, 2025
ee5bde9
Deprecate serving rate limit
ales-otf Dec 16, 2025
60e1284
Resolve git conflicts
ales-otf Dec 23, 2025
f1504c6
Fix TX-extension type definition
ales-otf Dec 23, 2025
913ee97
Deprecate serving rate limit
ales-otf Dec 23, 2025
cdd90c1
Update contract tests
ales-otf Dec 23, 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
64 changes: 64 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ members = [
"common",
"node",
"pallets/*",
"pallets/rate-limiting/runtime-api",
"pallets/rate-limiting/rpc",
"precompiles",
"primitives/*",
"runtime",
Expand Down Expand Up @@ -59,6 +61,9 @@ pallet-subtensor = { path = "pallets/subtensor", default-features = false }
pallet-subtensor-swap = { path = "pallets/swap", default-features = false }
pallet-subtensor-swap-runtime-api = { path = "pallets/swap/runtime-api", default-features = false }
pallet-subtensor-swap-rpc = { path = "pallets/swap/rpc", default-features = false }
pallet-rate-limiting = { path = "pallets/rate-limiting", default-features = false }
pallet-rate-limiting-runtime-api = { path = "pallets/rate-limiting/runtime-api", default-features = false }
pallet-rate-limiting-rpc = { path = "pallets/rate-limiting/rpc", default-features = false }
procedural-fork = { path = "support/procedural-fork", default-features = false }
safe-math = { path = "primitives/safe-math", default-features = false }
share-pool = { path = "primitives/share-pool", default-features = false }
Expand All @@ -70,6 +75,7 @@ subtensor-runtime-common = { default-features = false, path = "common" }
subtensor-swap-interface = { default-features = false, path = "pallets/swap-interface" }
subtensor-transaction-fee = { default-features = false, path = "pallets/transaction-fee" }
subtensor-chain-extensions = { default-features = false, path = "chain-extensions" }
rate-limiting-interface = { default-features = false, path = "pallets/rate-limiting-interface" }

ed25519-dalek = { version = "2.1.0", default-features = false }
async-trait = "0.1"
Expand Down
3 changes: 3 additions & 0 deletions chain-extensions/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ subtensor-swap-interface.workspace = true
num_enum.workspace = true
substrate-fixed.workspace = true

[dev-dependencies]
rate-limiting-interface.workspace = true

[lints]
workspace = true

Expand Down
35 changes: 32 additions & 3 deletions chain-extensions/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ use pallet_contracts::HoldReason as ContractsHoldReason;
use pallet_subtensor::*;
use pallet_subtensor_proxy as pallet_proxy;
use pallet_subtensor_utility as pallet_utility;
use rate_limiting_interface::{RateLimitingInfo, TryIntoRateLimitTarget};
use sp_core::{ConstU64, H256, U256, offchain::KeyTypeId};
use sp_runtime::Perbill;
use sp_runtime::{
BuildStorage, Percent,
traits::{BlakeTwo256, Convert, IdentityLookup},
};
use sp_std::{cell::RefCell, cmp::Ordering, sync::OnceLock};
use subtensor_runtime_common::{AlphaCurrency, NetUid, TaoCurrency};
use subtensor_runtime_common::{
AlphaCurrency, NetUid, TaoCurrency, rate_limiting::RateLimitUsageKey,
};

type Block = frame_system::mocking::MockBlock<Test>;

Expand Down Expand Up @@ -291,7 +294,6 @@ parameter_types! {
pub const InitialMinChildKeyTake: u16 = 0; // 0 %;
pub const InitialMaxChildKeyTake: u16 = 11_796; // 18 %;
pub const InitialWeightsVersionKey: u16 = 0;
pub const InitialServingRateLimit: u64 = 0; // No limit.
pub const InitialTxRateLimit: u64 = 0; // Disable rate limit for testing
pub const InitialTxDelegateTakeRateLimit: u64 = 1; // 1 block take rate limit for testing
pub const InitialTxChildKeyTakeRateLimit: u64 = 1; // 1 block take rate limit for testing
Expand Down Expand Up @@ -377,7 +379,6 @@ impl pallet_subtensor::Config for Test {
type InitialWeightsVersionKey = InitialWeightsVersionKey;
type InitialMaxDifficulty = InitialMaxDifficulty;
type InitialMinDifficulty = InitialMinDifficulty;
type InitialServingRateLimit = InitialServingRateLimit;
type InitialTxRateLimit = InitialTxRateLimit;
type InitialTxDelegateTakeRateLimit = InitialTxDelegateTakeRateLimit;
type InitialBurn = InitialBurn;
Expand Down Expand Up @@ -411,6 +412,7 @@ impl pallet_subtensor::Config for Test {
type GetCommitments = ();
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
type CommitmentsInterface = CommitmentsI;
type RateLimiting = NoRateLimiting;
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
}

Expand Down Expand Up @@ -449,6 +451,33 @@ impl CommitmentsInterface for CommitmentsI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct NoRateLimiting;

impl RateLimitingInfo for NoRateLimiting {
type GroupId = subtensor_runtime_common::rate_limiting::GroupId;
type CallMetadata = RuntimeCall;
type Limit = BlockNumber;
type Scope = subtensor_runtime_common::NetUid;
type UsageKey = RateLimitUsageKey<AccountId>;

fn rate_limit<TargetArg>(_target: TargetArg, _scope: Option<Self::Scope>) -> Option<Self::Limit>
where
TargetArg: TryIntoRateLimitTarget<Self::GroupId>,
{
None
}

fn last_seen<TargetArg>(
_target: TargetArg,
_usage_key: Option<Self::UsageKey>,
) -> Option<Self::Limit>
where
TargetArg: TryIntoRateLimitTarget<Self::GroupId>,
{
None
}
}

parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
Expand Down
1 change: 1 addition & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use subtensor_macros::freeze_struct;
pub use currency::*;

mod currency;
pub mod rate_limiting;

/// Balance of an account.
pub type Balance = u64;
Expand Down
110 changes: 110 additions & 0 deletions common/src/rate_limiting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! Shared rate-limiting types.
//!
//! Note: `pallet-rate-limiting` supports multiple independent instances, and is intended to be used
//! as “one instance per pallet” with pallet-specific scope/usage-key types and resolvers.
//!
//! The scope/usage-key types in this module are centralized today due to the current state of
//! `pallet-subtensor` (a large, centralized pallet) and its coupling with `pallet-admin-utils`,
//! which share a single `pallet-rate-limiting` instance and resolver implementation in the runtime.
//!
//! For new pallets, it is strongly recommended to:
//! - define their own `LimitScope` and `UsageKey` types (do not extend `RateLimitUsageKey` here),
//! - provide pallet-local scope/usage resolvers,
//! - and use a dedicated `pallet-rate-limiting` instance.
//!
//! Long-term, we should move away from these shared types by refactoring `pallet-subtensor` into
//! smaller pallets with dedicated `pallet-rate-limiting` instances.

use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use frame_support::pallet_prelude::Parameter;
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};

use crate::{MechId, NetUid};

/// Identifier type for rate-limiting groups.
pub type GroupId = u32;

/// Group id for serving-related calls.
pub const GROUP_SERVE: GroupId = 0;
/// Group id for delegate-take related calls.
pub const GROUP_DELEGATE_TAKE: GroupId = 1;
/// Group id for subnet weight-setting calls.
pub const GROUP_WEIGHTS_SUBNET: GroupId = 2;
/// Group id for network registration calls.
pub const GROUP_REGISTER_NETWORK: GroupId = 3;
/// Group id for owner hyperparameter calls.
pub const GROUP_OWNER_HPARAMS: GroupId = 4;
/// Group id for staking operations.
pub const GROUP_STAKING_OPS: GroupId = 5;
/// Group id for key swap calls.
pub const GROUP_SWAP_KEYS: GroupId = 6;

/// Usage-key type currently shared by the centralized `pallet-subtensor` rate-limiting instance.
///
/// Do not add new variants for new pallets. Prefer defining pallet-specific types and using a
/// dedicated `pallet-rate-limiting` instance per pallet.
#[derive(
Serialize,
Deserialize,
Encode,
Decode,
DecodeWithMemTracking,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Debug,
TypeInfo,
MaxEncodedLen,
)]
#[scale_info(skip_type_params(AccountId))]
pub enum RateLimitUsageKey<AccountId: Parameter> {
Account(AccountId),
Subnet(NetUid),
AccountSubnet {
account: AccountId,
netuid: NetUid,
},
ColdkeyHotkeySubnet {
coldkey: AccountId,
hotkey: AccountId,
netuid: NetUid,
},
SubnetNeuron {
netuid: NetUid,
uid: u16,
},
SubnetMechanismNeuron {
netuid: NetUid,
mecid: MechId,
uid: u16,
},
AccountSubnetServing {
account: AccountId,
netuid: NetUid,
endpoint: ServingEndpoint,
},
}

#[derive(
Serialize,
Deserialize,
Encode,
Decode,
DecodeWithMemTracking,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Debug,
TypeInfo,
MaxEncodedLen,
)]
pub enum ServingEndpoint {
Axon,
Prometheus,
}
3 changes: 3 additions & 0 deletions contract-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ npx papi add devnet -w ws://localhost:9944
If the runtime is upgrade, need to get the metadata again.

```bash
cd contract-tests/bittensor
cargo contract build --release
cd ..
sh get-metadata.sh
```

Expand Down
2 changes: 1 addition & 1 deletion contract-tests/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"scripts": {
"test": "mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register test/*test.ts"
"test": "TS_NODE_PREFER_TS_EXTS=1 TS_NODE_TRANSPILE_ONLY=1 mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register --extension ts \"test/**/*.ts\""
},
"keywords": [],
"author": "",
Expand Down
Loading
Loading