BEEFY: introduce offence report system (#13564)

* Trivial adjustments to beefy and grandpa pallets

* Introduce offence report system to beefy pallet

* Minor adjustments

* Fix beefy-mmr mock

* Apply suggestions from code review

Co-authored-by: Anton <anton.kalyaev@gmail.com>

---------

Co-authored-by: Anton <anton.kalyaev@gmail.com>
This commit is contained in:
Davide Galassi
2023-03-11 19:05:55 +01:00
committed by GitHub
parent 7401383252
commit 66f3d9e237
10 changed files with 243 additions and 414 deletions
+16 -17
View File
@@ -57,7 +57,7 @@ use super::{Call, Config, Error, Pallet, LOG_TARGET};
/// A round number and set id which point on the time of an offence.
#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)]
pub struct GrandpaTimeSlot {
pub struct TimeSlot {
// The order of these matters for `derive(Ord)`.
/// Grandpa Set ID.
pub set_id: SetId,
@@ -65,10 +65,10 @@ pub struct GrandpaTimeSlot {
pub round: RoundNumber,
}
/// A GRANDPA equivocation offence report.
/// GRANDPA equivocation offence report.
pub struct EquivocationOffence<Offender> {
/// Time slot at which this incident happened.
pub time_slot: GrandpaTimeSlot,
pub time_slot: TimeSlot,
/// The session index in which the incident happened.
pub session_index: SessionIndex,
/// The size of the validator set at the time of the offence.
@@ -79,7 +79,7 @@ pub struct EquivocationOffence<Offender> {
impl<Offender: Clone> Offence<Offender> for EquivocationOffence<Offender> {
const ID: Kind = *b"grandpa:equivoca";
type TimeSlot = GrandpaTimeSlot;
type TimeSlot = TimeSlot;
fn offenders(&self) -> Vec<Offender> {
vec![self.offender.clone()]
@@ -105,15 +105,16 @@ impl<Offender: Clone> Offence<Offender> for EquivocationOffence<Offender> {
}
}
/// Generic equivocation handler. This type implements `HandleEquivocation`
/// using existing subsystems that are part of frame (type bounds described
/// below) and will dispatch to them directly, it's only purpose is to wire all
/// subsystems together.
/// GRANDPA equivocation offence report system.
///
/// This type implements `OffenceReportSystem` such that:
/// - Equivocation reports are published on-chain as unsigned extrinsic via
/// `offchain::SendTransactioinsTypes`.
/// - On-chain validity checks and processing are mostly delegated to the user provided generic
/// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits.
/// - Offence reporter for unsigned transactions is fetched via the the authorship pallet.
pub struct EquivocationReportSystem<T, R, P, L>(sp_std::marker::PhantomData<(T, R, P, L)>);
// We use the authorship pallet to fetch the current block author and use
// `offchain::SendTransactionTypes` for unsigned extrinsic creation and
// submission.
impl<T, R, P, L>
OffenceReportSystem<
Option<T::AccountId>,
@@ -144,7 +145,7 @@ where
};
let res = SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into());
match res {
Ok(()) => info!(target: LOG_TARGET, "Submitted equivocation report."),
Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report"),
Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e),
}
res
@@ -160,10 +161,8 @@ where
let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?;
// Check if the offence has already been reported, and if so then we can discard the report.
let time_slot = GrandpaTimeSlot {
set_id: equivocation_proof.set_id(),
round: equivocation_proof.round(),
};
let time_slot =
TimeSlot { set_id: equivocation_proof.set_id(), round: equivocation_proof.round() };
if R::is_known_offence(&[offender], &time_slot) {
Err(InvalidTransaction::Stale.into())
} else {
@@ -221,7 +220,7 @@ where
}
let offence = EquivocationOffence {
time_slot: GrandpaTimeSlot { set_id, round },
time_slot: TimeSlot { set_id, round },
session_index,
offender,
validator_set_count,
+2 -1
View File
@@ -63,7 +63,7 @@ mod mock;
#[cfg(all(feature = "std", test))]
mod tests;
pub use equivocation::{EquivocationOffence, EquivocationReportSystem, GrandpaTimeSlot};
pub use equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot};
pub use pallet::*;
@@ -351,6 +351,7 @@ pub mod pallet {
#[pallet::validate_unsigned]
impl<T: Config> ValidateUnsigned for Pallet<T> {
type Call = Call<T>;
fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
Self::validate_unsigned(source, call)
}
-3
View File
@@ -224,13 +224,10 @@ parameter_types! {
impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type MaxAuthorities = ConstU32<100>;
type MaxSetIdSessionEntries = MaxSetIdSessionEntries;
type KeyOwnerProof = <Historical as KeyOwnerProofSystem<(KeyTypeId, AuthorityId)>>::Proof;
type EquivocationReportSystem =
super::EquivocationReportSystem<Self, Offences, Historical, ReportLongevity>;
}
+6 -6
View File
@@ -296,12 +296,12 @@ fn schedule_resume_only_when_paused() {
#[test]
fn time_slot_have_sane_ord() {
// Ensure that `Ord` implementation is sane.
const FIXTURE: &[GrandpaTimeSlot] = &[
GrandpaTimeSlot { set_id: 0, round: 0 },
GrandpaTimeSlot { set_id: 0, round: 1 },
GrandpaTimeSlot { set_id: 1, round: 0 },
GrandpaTimeSlot { set_id: 1, round: 1 },
GrandpaTimeSlot { set_id: 1, round: 2 },
const FIXTURE: &[TimeSlot] = &[
TimeSlot { set_id: 0, round: 0 },
TimeSlot { set_id: 0, round: 1 },
TimeSlot { set_id: 1, round: 0 },
TimeSlot { set_id: 1, round: 1 },
TimeSlot { set_id: 1, round: 2 },
];
assert!(FIXTURE.windows(2).all(|f| f[0] < f[1]));
}