Skip to content

Commit 9d5a44f

Browse files
authored
babe: report equivocations (#6362)
* slots: create primitives crate for consensus slots * offences: add method to check if an offence is unknown * babe: initial equivocation reporting implementation * babe: organize imports * babe: working equivocation reporting * babe: add slot number to equivocation proof * session: move duplicate traits to session primitives * babe: move equivocation stuff to its own file * offences: fix test * session: don't have primitives depend on frame_support * babe: use opaque type for key owner proof * babe: cleanup client equivocation reporting * babe: cleanup equivocation code in pallet * babe: allow sending signed equivocation reports * node: fix compilation * fix test compilation * babe: return bool on check_equivocation_proof * babe: add test for equivocation reporting * babe: add more tests * babe: add test for validate unsigned * babe: take slot number in generate_key_ownership_proof API * babe: add benchmark for equivocation proof checking * session: add benchmark for membership proof checking * offences: fix babe benchmark * babe: add weights based on benchmark results * babe: adjust weights after benchmarking on reference hardware * babe: reorder checks in check_and_report_equivocation
1 parent ad3c0a5 commit 9d5a44f

File tree

3 files changed

+87
-12
lines changed

3 files changed

+87
-12
lines changed

benchmarking/src/lib.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -323,21 +323,16 @@ benchmarks! {
323323
}
324324

325325
report_offence_babe {
326-
let r in 1 .. MAX_REPORTERS;
327326
let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32);
328-
let o = 1;
329327

330-
// Make r reporters
331-
let mut reporters = vec![];
332-
for i in 0 .. r {
333-
let reporter = account("reporter", i, SEED);
334-
reporters.push(reporter);
335-
}
328+
// for babe equivocation reports the number of reporters
329+
// and offenders is always 1
330+
let reporters = vec![account("reporter", 1, SEED)];
336331

337332
// make sure reporters actually get rewarded
338333
Staking::<T>::set_slash_reward_fraction(Perbill::one());
339334

340-
let (mut offenders, raw_offenders) = make_offenders::<T>(o, n)?;
335+
let (mut offenders, raw_offenders) = make_offenders::<T>(1, n)?;
341336
let keys = ImOnline::<T>::keys();
342337

343338
let offence = BabeEquivocationOffence {
@@ -357,9 +352,9 @@ benchmarks! {
357352
assert_eq!(
358353
System::<T>::event_count(), 0
359354
+ 1 // offence
360-
+ 2 * r // reporter (reward + endowment)
361-
+ o // offenders slashed
362-
+ o * n // nominators slashed
355+
+ 2 // reporter (reward + endowment)
356+
+ 1 // offenders slashed
357+
+ n // nominators slashed
363358
);
364359
}
365360

src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,15 @@ where
185185

186186
Ok(())
187187
}
188+
189+
fn is_known_offence(offenders: &[T::IdentificationTuple], time_slot: &O::TimeSlot) -> bool {
190+
let any_unknown = offenders.iter().any(|offender| {
191+
let report_id = Self::report_id::<O>(time_slot, offender);
192+
!<Reports<T>>::contains_key(&report_id)
193+
});
194+
195+
!any_unknown
196+
}
188197
}
189198

190199
impl<T: Trait> Module<T> {

src/tests.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,77 @@ fn doesnt_deposit_event_for_dups() {
174174
});
175175
}
176176

177+
#[test]
178+
fn reports_if_an_offence_is_dup() {
179+
type TestOffence = Offence<u64>;
180+
181+
new_test_ext().execute_with(|| {
182+
let time_slot = 42;
183+
assert_eq!(offence_reports(KIND, time_slot), vec![]);
184+
185+
let offence = |time_slot, offenders| TestOffence {
186+
validator_set_count: 5,
187+
time_slot,
188+
offenders,
189+
};
190+
191+
let mut test_offence = offence(time_slot, vec![0]);
192+
193+
// the report for authority 0 at time slot 42 should not be a known
194+
// offence
195+
assert!(
196+
!<Offences as ReportOffence<_, _, TestOffence>>::is_known_offence(
197+
&test_offence.offenders,
198+
&test_offence.time_slot
199+
)
200+
);
201+
202+
// we report an offence for authority 0 at time slot 42
203+
Offences::report_offence(vec![], test_offence.clone()).unwrap();
204+
205+
// the same report should be a known offence now
206+
assert!(
207+
<Offences as ReportOffence<_, _, TestOffence>>::is_known_offence(
208+
&test_offence.offenders,
209+
&test_offence.time_slot
210+
)
211+
);
212+
213+
// and reporting it again should yield a duplicate report error
214+
assert_eq!(
215+
Offences::report_offence(vec![], test_offence.clone()),
216+
Err(OffenceError::DuplicateReport)
217+
);
218+
219+
// after adding a new offender to the offence report
220+
test_offence.offenders.push(1);
221+
222+
// it should not be a known offence anymore
223+
assert!(
224+
!<Offences as ReportOffence<_, _, TestOffence>>::is_known_offence(
225+
&test_offence.offenders,
226+
&test_offence.time_slot
227+
)
228+
);
229+
230+
// and reporting it again should work without any error
231+
assert_eq!(
232+
Offences::report_offence(vec![], test_offence.clone()),
233+
Ok(())
234+
);
235+
236+
// creating a new offence for the same authorities on the next slot
237+
// should be considered a new offence and thefore not known
238+
let test_offence_next_slot = offence(time_slot + 1, vec![0, 1]);
239+
assert!(
240+
!<Offences as ReportOffence<_, _, TestOffence>>::is_known_offence(
241+
&test_offence_next_slot.offenders,
242+
&test_offence_next_slot.time_slot
243+
)
244+
);
245+
});
246+
}
247+
177248
#[test]
178249
fn should_properly_count_offences() {
179250
// We report two different authorities for the same issue. Ultimately, the 1st authority

0 commit comments

Comments
 (0)