@@ -63,6 +63,7 @@ use sp_runtime::{
63
63
traits:: { Saturating , Zero } ,
64
64
DispatchResult , RuntimeDebug ,
65
65
} ;
66
+ use sp_staking:: offence:: DisableStrategy ;
66
67
use sp_std:: vec:: Vec ;
67
68
68
69
/// The proportion of the slashing reward to be paid out on the first slashing detection.
@@ -213,6 +214,8 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> {
213
214
/// The maximum percentage of a slash that ever gets paid out.
214
215
/// This is f_inf in the paper.
215
216
pub ( crate ) reward_proportion : Perbill ,
217
+ /// When to disable offenders.
218
+ pub ( crate ) disable_strategy : DisableStrategy ,
216
219
}
217
220
218
221
/// Computes a slash of a validator and nominators. It returns an unapplied
@@ -224,29 +227,30 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> {
224
227
pub ( crate ) fn compute_slash < T : Config > (
225
228
params : SlashParams < T > ,
226
229
) -> Option < UnappliedSlash < T :: AccountId , BalanceOf < T > > > {
227
- let SlashParams { stash, slash, exposure, slash_era, window_start, now, reward_proportion } =
228
- params. clone ( ) ;
229
-
230
230
let mut reward_payout = Zero :: zero ( ) ;
231
231
let mut val_slashed = Zero :: zero ( ) ;
232
232
233
233
// is the slash amount here a maximum for the era?
234
- let own_slash = slash * exposure. own ;
235
- if slash * exposure. total == Zero :: zero ( ) {
234
+ let own_slash = params . slash * params . exposure . own ;
235
+ if params . slash * params . exposure . total == Zero :: zero ( ) {
236
236
// kick out the validator even if they won't be slashed,
237
237
// as long as the misbehavior is from their most recent slashing span.
238
238
kick_out_if_recent :: < T > ( params) ;
239
239
return None
240
240
}
241
241
242
242
let ( prior_slash_p, _era_slash) =
243
- <Pallet < T > as Store >:: ValidatorSlashInEra :: get ( & slash_era, stash)
243
+ <Pallet < T > as Store >:: ValidatorSlashInEra :: get ( & params . slash_era , params . stash )
244
244
. unwrap_or ( ( Perbill :: zero ( ) , Zero :: zero ( ) ) ) ;
245
245
246
246
// compare slash proportions rather than slash values to avoid issues due to rounding
247
247
// error.
248
- if slash. deconstruct ( ) > prior_slash_p. deconstruct ( ) {
249
- <Pallet < T > as Store >:: ValidatorSlashInEra :: insert ( & slash_era, stash, & ( slash, own_slash) ) ;
248
+ if params. slash . deconstruct ( ) > prior_slash_p. deconstruct ( ) {
249
+ <Pallet < T > as Store >:: ValidatorSlashInEra :: insert (
250
+ & params. slash_era ,
251
+ params. stash ,
252
+ & ( params. slash , own_slash) ,
253
+ ) ;
250
254
} else {
251
255
// we slash based on the max in era - this new event is not the max,
252
256
// so neither the validator or any nominators will need an update.
@@ -261,35 +265,34 @@ pub(crate) fn compute_slash<T: Config>(
261
265
// apply slash to validator.
262
266
{
263
267
let mut spans = fetch_spans :: < T > (
264
- stash,
265
- window_start,
268
+ params . stash ,
269
+ params . window_start ,
266
270
& mut reward_payout,
267
271
& mut val_slashed,
268
- reward_proportion,
272
+ params . reward_proportion ,
269
273
) ;
270
274
271
- let target_span = spans. compare_and_update_span_slash ( slash_era, own_slash) ;
275
+ let target_span = spans. compare_and_update_span_slash ( params . slash_era , own_slash) ;
272
276
273
277
if target_span == Some ( spans. span_index ( ) ) {
274
278
// misbehavior occurred within the current slashing span - take appropriate
275
279
// actions.
276
280
277
281
// chill the validator - it misbehaved in the current span and should
278
282
// not continue in the next election. also end the slashing span.
279
- spans. end_span ( now) ;
280
- <Pallet < T > >:: chill_stash ( stash) ;
283
+ spans. end_span ( params . now ) ;
284
+ <Pallet < T > >:: chill_stash ( params . stash ) ;
281
285
}
282
286
}
283
287
284
- // add the validator to the offenders list and make sure it is disabled for
285
- // the duration of the era
286
- add_offending_validator :: < T > ( params. stash , true ) ;
288
+ let disable_when_slashed = params. disable_strategy != DisableStrategy :: Never ;
289
+ add_offending_validator :: < T > ( params. stash , disable_when_slashed) ;
287
290
288
291
let mut nominators_slashed = Vec :: new ( ) ;
289
- reward_payout += slash_nominators :: < T > ( params, prior_slash_p, & mut nominators_slashed) ;
292
+ reward_payout += slash_nominators :: < T > ( params. clone ( ) , prior_slash_p, & mut nominators_slashed) ;
290
293
291
294
Some ( UnappliedSlash {
292
- validator : stash. clone ( ) ,
295
+ validator : params . stash . clone ( ) ,
293
296
own : val_slashed,
294
297
others : nominators_slashed,
295
298
reporters : Vec :: new ( ) ,
@@ -316,9 +319,8 @@ fn kick_out_if_recent<T: Config>(params: SlashParams<T>) {
316
319
<Pallet < T > >:: chill_stash ( params. stash ) ;
317
320
}
318
321
319
- // add the validator to the offenders list but since there's no slash being
320
- // applied there's no need to disable the validator
321
- add_offending_validator :: < T > ( params. stash , false ) ;
322
+ let disable_without_slash = params. disable_strategy == DisableStrategy :: Always ;
323
+ add_offending_validator :: < T > ( params. stash , disable_without_slash) ;
322
324
}
323
325
324
326
/// Add the given validator to the offenders list and optionally disable it.
@@ -371,29 +373,27 @@ fn slash_nominators<T: Config>(
371
373
prior_slash_p : Perbill ,
372
374
nominators_slashed : & mut Vec < ( T :: AccountId , BalanceOf < T > ) > ,
373
375
) -> BalanceOf < T > {
374
- let SlashParams { stash : _, slash, exposure, slash_era, window_start, now, reward_proportion } =
375
- params;
376
-
377
376
let mut reward_payout = Zero :: zero ( ) ;
378
377
379
- nominators_slashed. reserve ( exposure. others . len ( ) ) ;
380
- for nominator in & exposure. others {
378
+ nominators_slashed. reserve ( params . exposure . others . len ( ) ) ;
379
+ for nominator in & params . exposure . others {
381
380
let stash = & nominator. who ;
382
381
let mut nom_slashed = Zero :: zero ( ) ;
383
382
384
383
// the era slash of a nominator always grows, if the validator
385
384
// had a new max slash for the era.
386
385
let era_slash = {
387
386
let own_slash_prior = prior_slash_p * nominator. value ;
388
- let own_slash_by_validator = slash * nominator. value ;
387
+ let own_slash_by_validator = params . slash * nominator. value ;
389
388
let own_slash_difference = own_slash_by_validator. saturating_sub ( own_slash_prior) ;
390
389
391
- let mut era_slash = <Pallet < T > as Store >:: NominatorSlashInEra :: get ( & slash_era, stash)
392
- . unwrap_or_else ( || Zero :: zero ( ) ) ;
390
+ let mut era_slash =
391
+ <Pallet < T > as Store >:: NominatorSlashInEra :: get ( & params. slash_era , stash)
392
+ . unwrap_or_else ( || Zero :: zero ( ) ) ;
393
393
394
394
era_slash += own_slash_difference;
395
395
396
- <Pallet < T > as Store >:: NominatorSlashInEra :: insert ( & slash_era, stash, & era_slash) ;
396
+ <Pallet < T > as Store >:: NominatorSlashInEra :: insert ( & params . slash_era , stash, & era_slash) ;
397
397
398
398
era_slash
399
399
} ;
@@ -402,18 +402,18 @@ fn slash_nominators<T: Config>(
402
402
{
403
403
let mut spans = fetch_spans :: < T > (
404
404
stash,
405
- window_start,
405
+ params . window_start ,
406
406
& mut reward_payout,
407
407
& mut nom_slashed,
408
- reward_proportion,
408
+ params . reward_proportion ,
409
409
) ;
410
410
411
- let target_span = spans. compare_and_update_span_slash ( slash_era, era_slash) ;
411
+ let target_span = spans. compare_and_update_span_slash ( params . slash_era , era_slash) ;
412
412
413
413
if target_span == Some ( spans. span_index ( ) ) {
414
414
// End the span, but don't chill the nominator. its nomination
415
415
// on this validator will be ignored in the future.
416
- spans. end_span ( now) ;
416
+ spans. end_span ( params . now ) ;
417
417
}
418
418
}
419
419
0 commit comments