diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 01ebde206e438..8f3361186ff5b 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -653,8 +653,14 @@ impl Offence for UnresponsivenessOffence { } fn slash_fraction(offenders: u32, validator_set_count: u32) -> Perbill { - // the formula is min((3 * (k - 1)) / n, 1) * 0.05 - let x = Perbill::from_rational_approximation(3 * (offenders - 1), validator_set_count); - x.saturating_mul(Perbill::from_percent(5)) + // the formula is min((3 * (k - (n / 10 + 1))) / n, 1) * 0.07 + // basically, 10% can be offline with no slash, but after that, it linearly climbs up to 7% + // when 13/30 are offline (around 5% when 1/3 are offline). + if let Some(threshold) = offenders.checked_sub(validator_set_count / 10 + 1) { + let x = Perbill::from_rational_approximation(3 * threshold, validator_set_count); + x.saturating_mul(Perbill::from_percent(7)) + } else { + Perbill::default() + } } } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index edfdc34bc00d2..788956ba6e070 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -38,14 +38,19 @@ fn test_unresponsiveness_slash_fraction() { ); assert_eq!( - UnresponsivenessOffence::<()>::slash_fraction(3, 50), - Perbill::from_parts(6000000), // 0.6% + UnresponsivenessOffence::<()>::slash_fraction(5, 50), + Perbill::zero(), // 0% + ); + + assert_eq!( + UnresponsivenessOffence::<()>::slash_fraction(7, 50), + Perbill::from_parts(4200000), // 0.42% ); // One third offline should be punished around 5%. assert_eq!( UnresponsivenessOffence::<()>::slash_fraction(17, 50), - Perbill::from_parts(48000000), // 4.8% + Perbill::from_parts(46200000), // 4.62% ); }