File tree Expand file tree Collapse file tree
substrate/frame/broker/src Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ # Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
2+ # See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
3+
4+ title: "[pallet-broker] Fix claim revenue behaviour for zero timeslices"
5+
6+ doc:
7+ - audience: Runtime Dev
8+ description: |
9+ Add a check in the `claim_revenue` broker call to ensure that max_timeslices > 0 and errors if
10+ not. This mitigates an issue where an attacker could call claim_revenue for an existing region
11+ that is owed a revenue, with max_timeslices set to 0 for free indefinitely, which would
12+ represent an unbounded spam attack.
13+
14+ crates:
15+ - name: pallet-broker
16+ bump: patch
Original file line number Diff line number Diff line change @@ -329,6 +329,7 @@ impl<T: Config> Pallet<T> {
329329 mut region : RegionId ,
330330 max_timeslices : Timeslice ,
331331 ) -> DispatchResult {
332+ ensure ! ( max_timeslices > 0 , Error :: <T >:: NoClaimTimeslices ) ;
332333 let mut contribution =
333334 InstaPoolContribution :: < T > :: take ( region) . ok_or ( Error :: < T > :: UnknownContribution ) ?;
334335 let contributed_parts = region. mask . count_ones ( ) ;
Original file line number Diff line number Diff line change @@ -474,6 +474,8 @@ pub mod pallet {
474474 AlreadyExpired ,
475475 /// The configuration could not be applied because it is invalid.
476476 InvalidConfig ,
477+ /// The revenue must be claimed for 1 or more timeslices.
478+ NoClaimTimeslices ,
477479 }
478480
479481 #[ pallet:: hooks]
@@ -680,13 +682,12 @@ pub mod pallet {
680682
681683 /// Claim the revenue owed from inclusion in the Instantaneous Coretime Pool.
682684 ///
683- /// - `origin`: Must be a Signed origin of the account which owns the Region `region_id` .
685+ /// - `origin`: Must be a Signed origin.
684686 /// - `region_id`: The Region which was assigned to the Pool.
685- /// - `max_timeslices`: The maximum number of timeslices which should be processed. This may
686- /// effect the weight of the call but should be ideally made equivalent to the length of
687- /// the Region `region_id`. If it is less than this, then further dispatches will be
688- /// required with the `region_id` which makes up any remainders of the region to be
689- /// collected.
687+ /// - `max_timeslices`: The maximum number of timeslices which should be processed. This
688+ /// must be greater than 0. This may affect the weight of the call but should be ideally
689+ /// made equivalent to the length of the Region `region_id`. If less, further dispatches
690+ /// will be required with the same `region_id` to claim revenue for the remainder.
690691 #[ pallet:: call_index( 12 ) ]
691692 #[ pallet:: weight( T :: WeightInfo :: claim_revenue( * max_timeslices) ) ]
692693 pub fn claim_revenue (
Original file line number Diff line number Diff line change @@ -372,6 +372,11 @@ fn instapool_payouts_work() {
372372 advance_to ( 11 ) ;
373373 assert_eq ! ( pot( ) , 14 ) ;
374374 assert_eq ! ( revenue( ) , 106 ) ;
375+
376+ // Cannot claim for 0 timeslices.
377+ assert_noop ! ( Broker :: do_claim_revenue( region, 0 ) , Error :: <Test >:: NoClaimTimeslices ) ;
378+
379+ // Revenue can be claimed.
375380 assert_ok ! ( Broker :: do_claim_revenue( region, 100 ) ) ;
376381 assert_eq ! ( pot( ) , 10 ) ;
377382 assert_eq ! ( balance( 2 ) , 4 ) ;
You can’t perform that action at this time.
0 commit comments