From de5686509c61370ce097857dd1d68f1fb55a215b Mon Sep 17 00:00:00 2001
From: Gavin Wood <gavin@parity.io>
Date: Wed, 27 Nov 2019 18:57:03 +0000
Subject: [PATCH] Validators don't get slashed for offlineness until 10% at
 once (#4232)

* Validators don't get slashed for offlineness until 10% at once

* Update frame/im-online/src/tests.rs

Co-Authored-By: Marcio Diaz <marcio.diaz@gmail.com>

* Update frame/im-online/src/tests.rs

Co-Authored-By: Marcio Diaz <marcio.diaz@gmail.com>

* Apply suggestions from code review

Co-Authored-By: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
---
 substrate/frame/im-online/src/lib.rs   | 12 +++++++++---
 substrate/frame/im-online/src/tests.rs | 11 ++++++++---
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/substrate/frame/im-online/src/lib.rs b/substrate/frame/im-online/src/lib.rs
index 01ebde206e4..8f3361186ff 100644
--- a/substrate/frame/im-online/src/lib.rs
+++ b/substrate/frame/im-online/src/lib.rs
@@ -653,8 +653,14 @@ impl<Offender: Clone> Offence<Offender> for UnresponsivenessOffence<Offender> {
 	}
 
 	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/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs
index edfdc34bc00..788956ba6e0 100644
--- a/substrate/frame/im-online/src/tests.rs
+++ b/substrate/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%
 	);
 }
 
-- 
GitLab