@@ -2,26 +2,28 @@ use frame_support::pallet_prelude::Get;
2
2
use log:: info;
3
3
use parity_scale_codec:: Encode ;
4
4
use primitives:: {
5
- BanHandler , BanInfo , BanReason , BannedValidators , CommitteeSeats , EraValidators ,
6
- SessionCommittee , SessionValidatorError , SessionValidators , ValidatorProvider ,
5
+ AbftScoresProvider , BanHandler , BanInfo , BanReason , BannedValidators , CommitteeSeats ,
6
+ EraValidators , SessionCommittee , SessionValidatorError , SessionValidators , ValidatorProvider ,
7
7
} ;
8
8
use rand:: { seq:: SliceRandom , SeedableRng } ;
9
9
use rand_pcg:: Pcg32 ;
10
10
use sp_runtime:: { Perbill , Perquintill } ;
11
11
use sp_staking:: { EraIndex , SessionIndex } ;
12
12
use sp_std:: {
13
13
collections:: { btree_map:: BTreeMap , btree_set:: BTreeSet } ,
14
+ vec,
14
15
vec:: Vec ,
15
16
} ;
16
17
17
18
use crate :: {
18
19
pallet:: {
19
20
BanConfig , Banned , Config , CurrentAndNextSessionValidatorsStorage , Event , Pallet ,
20
- SessionValidatorBlockCount , UnderperformedValidatorSessionCount , ValidatorEraTotalReward ,
21
+ SessionValidatorBlockCount , UnderperformedFinalizerSessionCount ,
22
+ UnderperformedValidatorSessionCount , ValidatorEraTotalReward ,
21
23
} ,
22
24
traits:: { EraInfoProvider , ValidatorRewardsHandler } ,
23
- BanConfigStruct , CurrentAndNextSessionValidators , LenientThreshold , ValidatorExtractor ,
24
- ValidatorTotalRewards , LOG_TARGET ,
25
+ BanConfigStruct , CurrentAndNextSessionValidators , FinalityBanConfig , LenientThreshold ,
26
+ ValidatorExtractor , ValidatorTotalRewards , LOG_TARGET ,
25
27
} ;
26
28
27
29
const MAX_REWARD : u32 = 1_000_000_000 ;
@@ -104,30 +106,26 @@ fn select_committee_inner<AccountId: Clone + PartialEq>(
104
106
let non_reserved_committee =
105
107
choose_for_session ( non_reserved, non_reserved_seats, current_session as usize ) ;
106
108
107
- let mut finality_committee = choose_finality_committee (
109
+ let mut finalizers = choose_finality_committee (
108
110
& reserved_committee,
109
111
& non_reserved_committee,
110
112
non_reserved_finality_seats,
111
113
current_session as usize ,
112
114
) ;
113
115
114
- let mut block_producers = match ( reserved_committee, non_reserved_committee) {
116
+ let mut producers = match ( reserved_committee, non_reserved_committee) {
115
117
( Some ( rc) , Some ( nrc) ) => Some ( rc. into_iter ( ) . chain ( nrc. into_iter ( ) ) . collect ( ) ) ,
116
118
( Some ( rc) , _) => Some ( rc) ,
117
119
( _, Some ( nrc) ) => Some ( nrc) ,
118
120
_ => None ,
119
121
} ?;
120
122
121
123
// randomize order of the producers and committee
122
- shuffle_order_for_session (
123
- & mut block_producers,
124
- & mut finality_committee,
125
- current_session,
126
- ) ;
124
+ shuffle_order_for_session ( & mut producers, & mut finalizers, current_session) ;
127
125
128
126
Some ( SessionCommittee {
129
- block_producers ,
130
- finality_committee ,
127
+ producers ,
128
+ finalizers ,
131
129
} )
132
130
}
133
131
@@ -241,8 +239,9 @@ impl<T: Config> Pallet<T> {
241
239
let CurrentAndNextSessionValidators {
242
240
current :
243
241
SessionValidators {
244
- committee ,
242
+ producers ,
245
243
non_committee,
244
+ ..
246
245
} ,
247
246
..
248
247
} = CurrentAndNextSessionValidatorsStorage :: < T > :: get ( ) ;
@@ -263,7 +262,7 @@ impl<T: Config> Pallet<T> {
263
262
)
264
263
. into_iter ( )
265
264
. chain ( Self :: reward_for_session_committee (
266
- committee ,
265
+ producers ,
267
266
nr_of_sessions,
268
267
blocks_per_session,
269
268
& validator_total_rewards,
@@ -274,23 +273,25 @@ impl<T: Config> Pallet<T> {
274
273
}
275
274
276
275
fn store_session_validators (
277
- committee : & [ T :: AccountId ] ,
276
+ producers : & [ T :: AccountId ] ,
277
+ finalizers : & [ T :: AccountId ] ,
278
278
reserved : Vec < T :: AccountId > ,
279
279
non_reserved : Vec < T :: AccountId > ,
280
280
) {
281
- let committee : BTreeSet < T :: AccountId > = committee . iter ( ) . cloned ( ) . collect ( ) ;
281
+ let producers_set : BTreeSet < T :: AccountId > = producers . iter ( ) . cloned ( ) . collect ( ) ;
282
282
283
283
let non_committee = non_reserved
284
284
. into_iter ( )
285
285
. chain ( reserved)
286
- . filter ( |a| !committee . contains ( a) )
286
+ . filter ( |a| !producers_set . contains ( a) )
287
287
. collect ( ) ;
288
288
289
289
let mut session_validators = CurrentAndNextSessionValidatorsStorage :: < T > :: get ( ) ;
290
290
291
291
session_validators. current = session_validators. next ;
292
292
session_validators. next = SessionValidators {
293
- committee : committee. into_iter ( ) . collect ( ) ,
293
+ producers : producers. to_vec ( ) ,
294
+ finalizers : finalizers. to_vec ( ) ,
294
295
non_committee,
295
296
} ;
296
297
@@ -336,7 +337,8 @@ impl<T: Config> Pallet<T> {
336
337
337
338
if let Some ( c) = & committee {
338
339
Self :: store_session_validators (
339
- & c. block_producers ,
340
+ & c. producers ,
341
+ & c. finalizers ,
340
342
era_validators. reserved ,
341
343
era_validators. non_reserved ,
342
344
) ;
@@ -345,18 +347,48 @@ impl<T: Config> Pallet<T> {
345
347
committee
346
348
}
347
349
350
+ pub ( crate ) fn calculate_underperforming_finalizers ( session_id : SessionIndex ) {
351
+ let CurrentAndNextSessionValidators {
352
+ current : SessionValidators { finalizers, .. } ,
353
+ ..
354
+ } = CurrentAndNextSessionValidatorsStorage :: < T > :: get ( ) ;
355
+
356
+ let underperformed_session_count_threshold =
357
+ FinalityBanConfig :: < T > :: get ( ) . underperformed_session_count_threshold ;
358
+ let minimal_expected_performance =
359
+ FinalityBanConfig :: < T > :: get ( ) . minimal_expected_performance ;
360
+
361
+ let is_underperforming = |score| score > minimal_expected_performance;
362
+
363
+ let finalizers_perf = T :: AbftScoresProvider :: scores_for_session ( session_id)
364
+ . map ( |score| score. points )
365
+ . unwrap_or ( vec ! [ minimal_expected_performance; finalizers. len( ) ] )
366
+ . into_iter ( )
367
+ . map ( is_underperforming) ;
368
+
369
+ for ( underperf, validator) in finalizers_perf. zip ( finalizers. iter ( ) ) {
370
+ if underperf {
371
+ let counter =
372
+ UnderperformedFinalizerSessionCount :: < T > :: mutate ( validator, |count| {
373
+ * count += 1 ;
374
+ * count
375
+ } ) ;
376
+ if counter >= underperformed_session_count_threshold {
377
+ // In future, additionally ban underperforming validator
378
+ Self :: deposit_event ( Event :: ValidatorUnderperforming ( validator. clone ( ) ) ) ;
379
+ }
380
+ }
381
+ }
382
+ }
383
+
348
384
pub ( crate ) fn calculate_underperforming_validators ( ) {
349
385
let thresholds = BanConfig :: < T > :: get ( ) ;
350
386
let CurrentAndNextSessionValidators {
351
- current :
352
- SessionValidators {
353
- committee : current_committee,
354
- ..
355
- } ,
387
+ current : SessionValidators { producers, .. } ,
356
388
..
357
389
} = CurrentAndNextSessionValidatorsStorage :: < T > :: get ( ) ;
358
390
let expected_blocks_per_validator = Self :: blocks_to_produce_per_session ( ) ;
359
- for validator in current_committee {
391
+ for validator in producers {
360
392
let underperformance = match SessionValidatorBlockCount :: < T > :: try_get ( & validator) {
361
393
Ok ( block_count) => {
362
394
Perbill :: from_rational ( block_count, expected_blocks_per_validator)
@@ -390,6 +422,8 @@ impl<T: Config> Pallet<T> {
390
422
"Clearing UnderperformedValidatorSessionCount"
391
423
) ;
392
424
let _result = UnderperformedValidatorSessionCount :: < T > :: clear ( u32:: MAX , None ) ;
425
+ let _result = UnderperformedFinalizerSessionCount :: < T > :: clear ( u32:: MAX , None ) ;
426
+ T :: AbftScoresProvider :: clear_scores ( ) ;
393
427
}
394
428
}
395
429
@@ -610,7 +644,7 @@ mod tests {
610
644
& non_reserved,
611
645
)
612
646
. expect ( "Expected non-empty rotated committee!" )
613
- . block_producers ,
647
+ . producers ,
614
648
) ;
615
649
616
650
assert_eq ! ( expected_committee, committee, ) ;
0 commit comments