4848//! The pallet relies on two resolvers:
4949//!
5050//! - [`Config::LimitScopeResolver`], which determines how limits are stored (for example by
51- //! returning a `netuid`). When this resolver returns `None`, the configuration is stored as a
52- //! global fallback.
51+ //! returning a `netuid`). The resolver can also signal that a call should bypass rate limiting or
52+ //! adjust the effective span at validation time. When it returns `None`, the configuration is
53+ //! stored as a global fallback.
5354//! - [`Config::UsageResolver`], which decides how executions are tracked in
5455//! [`LastSeen`](pallet::LastSeen). This can refine the limit scope (for example by returning a
5556//! tuple of `(netuid, hyperparameter)`).
6364//!
6465//! // Limits are scoped per netuid.
6566//! pub struct ScopeResolver;
66- //! impl pallet_rate_limiting::RateLimitScopeResolver<RuntimeCall, NetUid> for ScopeResolver {
67+ //! impl pallet_rate_limiting::RateLimitScopeResolver<RuntimeCall, NetUid, BlockNumber > for ScopeResolver {
6768//! fn context(call: &RuntimeCall) -> Option<NetUid> {
6869//! match call {
6970//! RuntimeCall::Subtensor(pallet_subtensor::Call::set_weights { netuid, .. }) => {
7273//! _ => None,
7374//! }
7475//! }
76+ //!
77+ //! fn adjust_span(_call: &RuntimeCall, span: BlockNumber) -> BlockNumber {
78+ //! span
79+ //! }
7580//! }
7681//!
7782//! // Usage tracking distinguishes hyperparameter + netuid.
7883//! pub struct UsageResolver;
79- //! impl pallet_rate_limiting::RateLimitUsageResolver<RuntimeCall, (NetUid, HyperParam)>
80- //! for UsageResolver {
84+ //! impl pallet_rate_limiting::RateLimitUsageResolver<RuntimeCall, (NetUid, HyperParam)> for UsageResolver {
8185//! fn context(call: &RuntimeCall) -> Option<(NetUid, HyperParam)> {
8286//! match call {
8387//! RuntimeCall::Subtensor(pallet_subtensor::Call::set_hyperparam {
@@ -156,7 +160,11 @@ pub mod pallet {
156160 type LimitScope : Parameter + Clone + PartialEq + Eq + Ord + MaybeSerializeDeserialize ;
157161
158162 /// Resolves the scope for the given runtime call when configuring limits.
159- type LimitScopeResolver : RateLimitScopeResolver < <Self as Config < I > >:: RuntimeCall , Self :: LimitScope > ;
163+ type LimitScopeResolver : RateLimitScopeResolver <
164+ <Self as Config < I > >:: RuntimeCall ,
165+ Self :: LimitScope ,
166+ BlockNumberFor < Self > ,
167+ > ;
160168
161169 /// Usage key tracked in [`LastSeen`] for rate-limited calls.
162170 type UsageKey : Parameter + Clone + PartialEq + Eq + Ord + MaybeSerializeDeserialize ;
@@ -306,21 +314,17 @@ pub mod pallet {
306314 identifier : & TransactionIdentifier ,
307315 scope : & Option < <T as Config < I > >:: LimitScope > ,
308316 usage_key : & Option < <T as Config < I > >:: UsageKey > ,
317+ call : & <T as Config < I > >:: RuntimeCall ,
309318 ) -> Result < bool , DispatchError > {
310- let Some ( block_span ) = Self :: resolved_limit ( identifier , scope ) else {
319+ if < T as Config < I > > :: LimitScopeResolver :: should_bypass ( call ) {
311320 return Ok ( true ) ;
312- } ;
313-
314- let current = frame_system:: Pallet :: < T > :: block_number ( ) ;
315-
316- if let Some ( last) = LastSeen :: < T , I > :: get ( identifier, usage_key) {
317- let delta = current. saturating_sub ( last) ;
318- if delta < block_span {
319- return Ok ( false ) ;
320- }
321321 }
322322
323- Ok ( true )
323+ let Some ( block_span) = Self :: effective_span ( call, identifier, scope) else {
324+ return Ok ( true ) ;
325+ } ;
326+
327+ Ok ( Self :: within_span ( identifier, usage_key, block_span) )
324328 }
325329
326330 pub ( crate ) fn resolved_limit (
@@ -335,6 +339,37 @@ pub mod pallet {
335339 } )
336340 }
337341
342+ pub ( crate ) fn effective_span (
343+ call : & <T as Config < I > >:: RuntimeCall ,
344+ identifier : & TransactionIdentifier ,
345+ scope : & Option < <T as Config < I > >:: LimitScope > ,
346+ ) -> Option < BlockNumberFor < T > > {
347+ let span = Self :: resolved_limit ( identifier, scope) ?;
348+ Some ( <T as Config < I > >:: LimitScopeResolver :: adjust_span (
349+ call, span,
350+ ) )
351+ }
352+
353+ pub ( crate ) fn within_span (
354+ identifier : & TransactionIdentifier ,
355+ usage_key : & Option < <T as Config < I > >:: UsageKey > ,
356+ block_span : BlockNumberFor < T > ,
357+ ) -> bool {
358+ if block_span. is_zero ( ) {
359+ return true ;
360+ }
361+
362+ if let Some ( last) = LastSeen :: < T , I > :: get ( identifier, usage_key) {
363+ let current = frame_system:: Pallet :: < T > :: block_number ( ) ;
364+ let delta = current. saturating_sub ( last) ;
365+ if delta < block_span {
366+ return false ;
367+ }
368+ }
369+
370+ true
371+ }
372+
338373 /// Returns the configured limit for the specified pallet/extrinsic names, if any.
339374 pub fn limit_for_call_names (
340375 pallet_name : & str ,
0 commit comments