Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

babe, grandpa: set longevity for equivocation report transactions #8076

Merged
5 commits merged into from
Feb 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// and set impl_version to 0. If only runtime
// implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version.
spec_version: 263,
spec_version: 264,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 2,
Expand Down Expand Up @@ -319,6 +319,8 @@ impl pallet_scheduler::Config for Runtime {
parameter_types! {
pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS;
pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
pub const ReportLongevity: u64 =
BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get();
}

impl pallet_babe::Config for Runtime {
Expand All @@ -339,7 +341,7 @@ impl pallet_babe::Config for Runtime {
)>>::IdentificationTuple;

type HandleEquivocation =
pallet_babe::EquivocationHandler<Self::KeyOwnerIdentification, Offences>;
pallet_babe::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;

type WeightInfo = ();
}
Expand Down Expand Up @@ -866,7 +868,7 @@ impl pallet_grandpa::Config for Runtime {
)>>::IdentificationTuple;

type HandleEquivocation =
pallet_grandpa::EquivocationHandler<Self::KeyOwnerIdentification, Offences>;
pallet_grandpa::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;

type WeightInfo = ();
}
Expand Down
27 changes: 22 additions & 5 deletions frame/babe/src/equivocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@
//! definition.
//!

use frame_support::{debug, traits::KeyOwnerProofSystem};
use frame_support::{
debug,
traits::{Get, KeyOwnerProofSystem},
};
use sp_consensus_babe::{EquivocationProof, Slot};
use sp_runtime::transaction_validity::{
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
Expand All @@ -56,6 +59,10 @@ use crate::{Call, Module, Config};
/// reporter), and also for creating and submitting equivocation report
/// extrinsics (useful only in offchain context).
pub trait HandleEquivocation<T: Config> {
/// The longevity, in blocks, that the equivocation report is valid for. When using the staking
/// pallet this should be equal to the bonding duration (in blocks, not eras).
type ReportLongevity: Get<u64>;

/// Report an offence proved by the given reporters.
fn report_offence(
reporters: Vec<T::AccountId>,
Expand All @@ -76,6 +83,8 @@ pub trait HandleEquivocation<T: Config> {
}

impl<T: Config> HandleEquivocation<T> for () {
type ReportLongevity = ();

fn report_offence(
_reporters: Vec<T::AccountId>,
_offence: BabeEquivocationOffence<T::KeyOwnerIdentification>,
Expand Down Expand Up @@ -103,19 +112,19 @@ impl<T: Config> HandleEquivocation<T> for () {
/// 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.
pub struct EquivocationHandler<I, R> {
_phantom: sp_std::marker::PhantomData<(I, R)>,
pub struct EquivocationHandler<I, R, L> {
_phantom: sp_std::marker::PhantomData<(I, R, L)>,
}

impl<I, R> Default for EquivocationHandler<I, R> {
impl<I, R, L> Default for EquivocationHandler<I, R, L> {
fn default() -> Self {
Self {
_phantom: Default::default(),
}
}
}

impl<T, R> HandleEquivocation<T> for EquivocationHandler<T::KeyOwnerIdentification, R>
impl<T, R, L> HandleEquivocation<T> for EquivocationHandler<T::KeyOwnerIdentification, R, L>
where
// We use the authorship pallet to fetch the current block author and use
// `offchain::SendTransactionTypes` for unsigned extrinsic creation and
Expand All @@ -128,7 +137,12 @@ where
T::KeyOwnerIdentification,
BabeEquivocationOffence<T::KeyOwnerIdentification>,
>,
// The longevity (in blocks) that the equivocation report is valid for. When using the staking
// pallet this should be the bonding duration.
L: Get<u64>,
{
type ReportLongevity = L;

fn report_offence(
reporters: Vec<T::AccountId>,
offence: BabeEquivocationOffence<T::KeyOwnerIdentification>,
Expand Down Expand Up @@ -184,6 +198,8 @@ impl<T: Config> frame_support::unsigned::ValidateUnsigned for Module<T> {
// check report staleness
is_known_offence::<T>(equivocation_proof, key_owner_proof)?;

let longevity = <T::HandleEquivocation as HandleEquivocation<T>>::ReportLongevity::get();

ValidTransaction::with_tag_prefix("BabeEquivocation")
// We assign the maximum priority for any equivocation report.
.priority(TransactionPriority::max_value())
Expand All @@ -192,6 +208,7 @@ impl<T: Config> frame_support::unsigned::ValidateUnsigned for Module<T> {
equivocation_proof.offender.clone(),
*equivocation_proof.slot,
))
.longevity(longevity)
// We don't propagate this. This can never be included on a remote node.
.propagate(false)
.build()
Expand Down
13 changes: 10 additions & 3 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ frame_support::construct_runtime!(

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const EpochDuration: u64 = 3;
pub const ExpectedBlockTime: u64 = 1;
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(16);
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(1024);
Expand Down Expand Up @@ -222,6 +220,13 @@ impl pallet_offences::Config for Test {
type WeightSoftLimit = OffencesWeightSoftLimit;
}

parameter_types! {
pub const EpochDuration: u64 = 3;
pub const ExpectedBlockTime: u64 = 1;
pub const ReportLongevity: u64 =
BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get();
}

impl Config for Test {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
Expand All @@ -237,7 +242,9 @@ impl Config for Test {
AuthorityId,
)>>::IdentificationTuple;

type HandleEquivocation = super::EquivocationHandler<Self::KeyOwnerIdentification, Offences>;
type HandleEquivocation =
super::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;

type WeightInfo = ();
}

Expand Down
6 changes: 3 additions & 3 deletions frame/babe/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,8 @@ fn report_equivocation_invalid_equivocation_proof() {
#[test]
fn report_equivocation_validate_unsigned_prevents_duplicates() {
use sp_runtime::transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionPriority, TransactionSource,
TransactionValidity, ValidTransaction,
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
ValidTransaction,
};

let (pairs, mut ext) = new_test_ext_with_pairs(3);
Expand Down Expand Up @@ -664,7 +664,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() {
priority: TransactionPriority::max_value(),
requires: vec![],
provides: vec![("BabeEquivocation", tx_tag).encode()],
longevity: TransactionLongevity::max_value(),
longevity: ReportLongevity::get(),
propagate: false,
})
);
Expand Down
25 changes: 20 additions & 5 deletions frame/grandpa/src/equivocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
use sp_std::prelude::*;

use codec::{self as codec, Decode, Encode};
use frame_support::{debug, traits::KeyOwnerProofSystem};
use frame_support::{
debug,
traits::{Get, KeyOwnerProofSystem},
};
use sp_finality_grandpa::{EquivocationProof, RoundNumber, SetId};
use sp_runtime::{
transaction_validity::{
Expand All @@ -64,6 +67,10 @@ pub trait HandleEquivocation<T: Config> {
/// The offence type used for reporting offences on valid equivocation reports.
type Offence: GrandpaOffence<T::KeyOwnerIdentification>;

/// The longevity, in blocks, that the equivocation report is valid for. When using the staking
/// pallet this should be equal to the bonding duration (in blocks, not eras).
type ReportLongevity: Get<u64>;

/// Report an offence proved by the given reporters.
fn report_offence(
reporters: Vec<T::AccountId>,
Expand All @@ -88,6 +95,7 @@ pub trait HandleEquivocation<T: Config> {

impl<T: Config> HandleEquivocation<T> for () {
type Offence = GrandpaEquivocationOffence<T::KeyOwnerIdentification>;
type ReportLongevity = ();

fn report_offence(
_reporters: Vec<T::AccountId>,
Expand Down Expand Up @@ -119,19 +127,19 @@ impl<T: Config> HandleEquivocation<T> for () {
/// 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.
pub struct EquivocationHandler<I, R, O = GrandpaEquivocationOffence<I>> {
_phantom: sp_std::marker::PhantomData<(I, R, O)>,
pub struct EquivocationHandler<I, R, L, O = GrandpaEquivocationOffence<I>> {
_phantom: sp_std::marker::PhantomData<(I, R, L, O)>,
}

impl<I, R, O> Default for EquivocationHandler<I, R, O> {
impl<I, R, L, O> Default for EquivocationHandler<I, R, L, O> {
fn default() -> Self {
Self {
_phantom: Default::default(),
}
}
}

impl<T, R, O> HandleEquivocation<T> for EquivocationHandler<T::KeyOwnerIdentification, R, O>
impl<T, R, L, O> HandleEquivocation<T> for EquivocationHandler<T::KeyOwnerIdentification, R, L, O>
where
// We use the authorship pallet to fetch the current block author and use
// `offchain::SendTransactionTypes` for unsigned extrinsic creation and
Expand All @@ -140,10 +148,14 @@ where
// A system for reporting offences after valid equivocation reports are
// processed.
R: ReportOffence<T::AccountId, T::KeyOwnerIdentification, O>,
// The longevity (in blocks) that the equivocation report is valid for. When using the staking
// pallet this should be the bonding duration.
L: Get<u64>,
// The offence type that should be used when reporting.
O: GrandpaOffence<T::KeyOwnerIdentification>,
{
type Offence = O;
type ReportLongevity = L;

fn report_offence(reporters: Vec<T::AccountId>, offence: O) -> Result<(), OffenceError> {
R::report_offence(reporters, offence)
Expand Down Expand Up @@ -207,6 +219,8 @@ impl<T: Config> frame_support::unsigned::ValidateUnsigned for Module<T> {
// check report staleness
is_known_offence::<T>(equivocation_proof, key_owner_proof)?;

let longevity = <T::HandleEquivocation as HandleEquivocation<T>>::ReportLongevity::get();

ValidTransaction::with_tag_prefix("GrandpaEquivocation")
// We assign the maximum priority for any equivocation report.
.priority(TransactionPriority::max_value())
Expand All @@ -216,6 +230,7 @@ impl<T: Config> frame_support::unsigned::ValidateUnsigned for Module<T> {
equivocation_proof.set_id(),
equivocation_proof.round(),
))
.longevity(longevity)
// We don't propagate this. This can never be included on a remote node.
.propagate(false)
.build()
Expand Down
8 changes: 7 additions & 1 deletion frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ impl pallet_offences::Config for Test {
type WeightSoftLimit = OffencesWeightSoftLimit;
}

parameter_types! {
pub const ReportLongevity: u64 =
BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get();
}

impl Config for Test {
type Event = Event;
type Call = Call;
Expand All @@ -240,7 +245,8 @@ impl Config for Test {
AuthorityId,
)>>::IdentificationTuple;

type HandleEquivocation = super::EquivocationHandler<Self::KeyOwnerIdentification, Offences>;
type HandleEquivocation =
super::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;

type WeightInfo = ();
}
Expand Down
6 changes: 3 additions & 3 deletions frame/grandpa/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,8 +706,8 @@ fn report_equivocation_invalid_equivocation_proof() {
#[test]
fn report_equivocation_validate_unsigned_prevents_duplicates() {
use sp_runtime::transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionPriority, TransactionSource,
TransactionValidity, ValidTransaction,
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
ValidTransaction,
};

let authorities = test_authorities();
Expand Down Expand Up @@ -762,7 +762,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() {
priority: TransactionPriority::max_value(),
requires: vec![],
provides: vec![("GrandpaEquivocation", tx_tag).encode()],
longevity: TransactionLongevity::max_value(),
longevity: ReportLongevity::get(),
propagate: false,
})
);
Expand Down