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

Bound pallet-offences #11585

Closed
wants to merge 17 commits into from
9 changes: 7 additions & 2 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ impl pallet_session::Config for Runtime {
}

impl pallet_session::historical::Config for Runtime {
type FullIdentification = pallet_staking::Exposure<AccountId, Balance>;
type FullIdentificationOf = pallet_staking::ExposureOf<Runtime>;
type FullIdentification = pallet_staking::Exposure<AccountId, Balance, MaxNominations>;
type FullIdentificationOf = pallet_staking::ActiveExposure<Runtime>;
}

pallet_staking_reward_curve::build! {
Expand Down Expand Up @@ -1243,6 +1243,11 @@ impl pallet_offences::Config for Runtime {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;

type MaxConcurrentReportsPerTime = ConstU32<100>;
type MaxSameKindReports = ConstU32<100>;
type MaxSameKindReportsEncodedLen = ConstU32<5_000>;
type MaxOpaqueTimeSlotEncodedLen = ConstU32<16>;
}

impl pallet_authority_discovery::Config for Runtime {
Expand Down
36 changes: 25 additions & 11 deletions frame/babe/src/equivocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@
//! that the `ValidateUnsigned` for the BABE pallet is used in the runtime
//! definition.

use frame_support::traits::{Get, KeyOwnerProofSystem};
use frame_support::traits::{Defensive, Get, KeyOwnerProofSystem};
use sp_consensus_babe::{EquivocationProof, Slot};
use sp_runtime::{
transaction_validity::{
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
TransactionValidityError, ValidTransaction,
},
DispatchResult, Perbill,
BoundedVec, DispatchResult, Perbill,
};
use sp_staking::{
offence::{Kind, Offence, OffenceError, ReportOffence},
offence::{Kind, MaxOffenders, MaxReporters, Offence, OffenceError, ReportOffence},
SessionIndex,
};
use sp_std::prelude::*;
Expand All @@ -62,12 +62,15 @@ pub trait HandleEquivocation<T: Config> {

/// Report an offence proved by the given reporters.
fn report_offence(
reporters: Vec<T::AccountId>,
reporters: BoundedVec<T::AccountId, MaxReporters>,
offence: BabeEquivocationOffence<T::KeyOwnerIdentification>,
) -> Result<(), OffenceError>;

/// Returns true if all of the offenders at the given time slot have already been reported.
fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &Slot) -> bool;
fn is_known_offence(
offenders: &BoundedVec<T::KeyOwnerIdentification, MaxOffenders>,
time_slot: &Slot,
) -> bool;

/// Create and dispatch an equivocation report extrinsic.
fn submit_unsigned_equivocation_report(
Expand All @@ -83,13 +86,16 @@ impl<T: Config> HandleEquivocation<T> for () {
type ReportLongevity = ();

fn report_offence(
_reporters: Vec<T::AccountId>,
_reporters: BoundedVec<T::AccountId, MaxReporters>,
_offence: BabeEquivocationOffence<T::KeyOwnerIdentification>,
) -> Result<(), OffenceError> {
Ok(())
}

fn is_known_offence(_offenders: &[T::KeyOwnerIdentification], _time_slot: &Slot) -> bool {
fn is_known_offence(
_offenders: &BoundedVec<T::KeyOwnerIdentification, MaxOffenders>,
_time_slot: &Slot,
) -> bool {
true
}

Expand Down Expand Up @@ -139,13 +145,16 @@ where
type ReportLongevity = L;

fn report_offence(
reporters: Vec<T::AccountId>,
reporters: BoundedVec<T::AccountId, MaxReporters>,
offence: BabeEquivocationOffence<T::KeyOwnerIdentification>,
) -> Result<(), OffenceError> {
R::report_offence(reporters, offence)
}

fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &Slot) -> bool {
fn is_known_offence(
offenders: &BoundedVec<T::KeyOwnerIdentification, MaxOffenders>,
time_slot: &Slot,
) -> bool {
R::is_known_offence(offenders, time_slot)
}

Expand Down Expand Up @@ -238,10 +247,12 @@ fn is_known_offence<T: Config>(

let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone())
.ok_or(InvalidTransaction::BadProof)?;
let offenders: BoundedVec<_, MaxOffenders> =
vec![offender].try_into().expect("MaxOffenders must be at least 1");

// check if the offence has already been reported,
// and if so then we can discard the report.
if T::HandleEquivocation::is_known_offence(&[offender], &equivocation_proof.slot) {
if T::HandleEquivocation::is_known_offence(&offenders, &equivocation_proof.slot) {
Err(InvalidTransaction::Stale.into())
} else {
Ok(())
Expand All @@ -268,8 +279,11 @@ impl<FullIdentification: Clone> Offence<FullIdentification>
const ID: Kind = *b"babe:equivocatio";
type TimeSlot = Slot;

fn offenders(&self) -> Vec<FullIdentification> {
fn offenders(&self) -> BoundedVec<FullIdentification, MaxOffenders> {
vec![self.offender.clone()]
.try_into()
.defensive_proof("MaxOffenders must be at least 1;")
.unwrap()
}

fn session_index(&self) -> SessionIndex {
Expand Down
12 changes: 8 additions & 4 deletions frame/babe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use frame_support::{
dispatch::DispatchResultWithPostInfo,
ensure,
traits::{
ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet,
OneSessionHandler,
ConstU32, Defensive, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem,
OnTimestampSet, OneSessionHandler,
},
weights::{Pays, Weight},
BoundedVec, WeakBoundedVec,
Expand All @@ -39,6 +39,7 @@ use sp_runtime::{
ConsensusEngineId, KeyTypeId, Permill,
};
use sp_session::{GetSessionNumber, GetValidatorCount};
use sp_staking::offence::MaxReporters;
use sp_std::prelude::*;

use sp_consensus_babe::{
Expand Down Expand Up @@ -826,10 +827,13 @@ impl<T: Config> Pallet<T> {
let offence =
BabeEquivocationOffence { slot, validator_set_count, offender, session_index };

let reporters = match reporter {
let reporters: BoundedVec<T::AccountId, MaxReporters> = match reporter {
Some(id) => vec![id],
None => vec![],
};
}
.try_into()
.defensive_proof("MaxReporters must be at least 1;")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have defensive_expect? we should :D

.unwrap();

T::HandleEquivocation::report_offence(reporters, offence)
.map_err(|_| Error::<T>::DuplicateOffenceReport)?;
Expand Down
11 changes: 8 additions & 3 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ frame_support::construct_runtime!(
Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
Historical: pallet_session_historical::{Pallet},
Offences: pallet_offences::{Pallet, Storage, Event},
Offences: pallet_offences::{Pallet, Storage, Event<T>},
Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned},
Staking: pallet_staking::{Pallet, Call, Storage, Config<T>, Event<T>},
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Expand Down Expand Up @@ -123,8 +123,8 @@ impl pallet_session::Config for Test {
}

impl pallet_session::historical::Config for Test {
type FullIdentification = pallet_staking::Exposure<u64, u128>;
type FullIdentificationOf = pallet_staking::ExposureOf<Self>;
type FullIdentification = pallet_staking::ExposureOf<Test>;
type FullIdentificationOf = pallet_staking::ActiveExposure<Self>;
}

impl pallet_authorship::Config for Test {
Expand Down Expand Up @@ -212,6 +212,11 @@ impl pallet_offences::Config for Test {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;

type MaxConcurrentReportsPerTime = ConstU32<100>;
type MaxSameKindReports = ConstU32<100>;
type MaxSameKindReportsEncodedLen = ConstU32<5_000>;
type MaxOpaqueTimeSlotEncodedLen = ConstU32<16>;
}

parameter_types! {
Expand Down
8 changes: 4 additions & 4 deletions frame/babe/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ fn report_equivocation_current_session_works() {

assert_eq!(
Staking::eras_stakers(1, validator),
pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] },
pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() },
);
}

Expand Down Expand Up @@ -479,7 +479,7 @@ fn report_equivocation_current_session_works() {
assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0);
assert_eq!(
Staking::eras_stakers(2, offending_validator_id),
pallet_staking::Exposure { total: 0, own: 0, others: vec![] },
pallet_staking::Exposure { total: 0, own: 0, others: Default::default() },
);

// check that the balances of all other validators are left intact.
Expand All @@ -492,7 +492,7 @@ fn report_equivocation_current_session_works() {
assert_eq!(Staking::slashable_balance_of(validator), 10_000);
assert_eq!(
Staking::eras_stakers(2, validator),
pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] },
pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() },
);
}
})
Expand Down Expand Up @@ -551,7 +551,7 @@ fn report_equivocation_old_session_works() {
assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0);
assert_eq!(
Staking::eras_stakers(3, offending_validator_id),
pallet_staking::Exposure { total: 0, own: 0, others: vec![] },
pallet_staking::Exposure { total: 0, own: 0, others: Default::default() },
);
})
}
Expand Down
35 changes: 23 additions & 12 deletions frame/grandpa/src/equivocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@
use sp_std::prelude::*;

use codec::{self as codec, Decode, Encode};
use frame_support::traits::{Get, KeyOwnerProofSystem};
use frame_support::traits::{Defensive, Get, KeyOwnerProofSystem};
use sp_finality_grandpa::{EquivocationProof, RoundNumber, SetId};
use sp_runtime::{
transaction_validity::{
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
TransactionValidityError, ValidTransaction,
},
DispatchResult, Perbill,
BoundedVec, DispatchResult, Perbill,
};
use sp_staking::{
offence::{Kind, Offence, OffenceError, ReportOffence},
offence::{Kind, MaxOffenders, MaxReporters, Offence, OffenceError, ReportOffence},
SessionIndex,
};

Expand All @@ -68,13 +68,13 @@ pub trait HandleEquivocation<T: Config> {

/// Report an offence proved by the given reporters.
fn report_offence(
reporters: Vec<T::AccountId>,
reporters: BoundedVec<T::AccountId, MaxReporters>,
offence: Self::Offence,
) -> Result<(), OffenceError>;

/// Returns true if all of the offenders at the given time slot have already been reported.
fn is_known_offence(
offenders: &[T::KeyOwnerIdentification],
offenders: &BoundedVec<T::KeyOwnerIdentification, MaxOffenders>,
time_slot: &<Self::Offence as Offence<T::KeyOwnerIdentification>>::TimeSlot,
) -> bool;

Expand All @@ -93,14 +93,14 @@ impl<T: Config> HandleEquivocation<T> for () {
type ReportLongevity = ();

fn report_offence(
_reporters: Vec<T::AccountId>,
_reporters: BoundedVec<T::AccountId, MaxReporters>,
_offence: GrandpaEquivocationOffence<T::KeyOwnerIdentification>,
) -> Result<(), OffenceError> {
Ok(())
}

fn is_known_offence(
_offenders: &[T::KeyOwnerIdentification],
_offenders: &BoundedVec<T::KeyOwnerIdentification, MaxOffenders>,
_time_slot: &GrandpaTimeSlot,
) -> bool {
true
Expand Down Expand Up @@ -150,12 +150,18 @@ where
type Offence = O;
type ReportLongevity = L;

fn report_offence(reporters: Vec<T::AccountId>, offence: O) -> Result<(), OffenceError> {
fn report_offence(
reporters: BoundedVec<T::AccountId, MaxReporters>,
offence: O,
) -> Result<(), OffenceError> {
R::report_offence(reporters, offence)
}

fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &O::TimeSlot) -> bool {
R::is_known_offence(offenders, time_slot)
fn is_known_offence(
offenders: &BoundedVec<T::KeyOwnerIdentification, MaxOffenders>,
time_slot: &O::TimeSlot,
) -> bool {
R::is_known_offence(&offenders, time_slot)
}

fn submit_unsigned_equivocation_report(
Expand Down Expand Up @@ -261,6 +267,8 @@ fn is_known_offence<T: Config>(

let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone())
.ok_or(InvalidTransaction::BadProof)?;
let offenders: BoundedVec<_, MaxOffenders> =
vec![offender].try_into().expect("MaxOffenders must be at least 1");

// check if the offence has already been reported,
// and if so then we can discard the report.
Expand All @@ -269,7 +277,7 @@ fn is_known_offence<T: Config>(
equivocation_proof.round(),
);

let is_known_offence = T::HandleEquivocation::is_known_offence(&[offender], &time_slot);
let is_known_offence = T::HandleEquivocation::is_known_offence(&offenders, &time_slot);

if is_known_offence {
Err(InvalidTransaction::Stale.into())
Expand Down Expand Up @@ -337,8 +345,11 @@ impl<FullIdentification: Clone> Offence<FullIdentification>
const ID: Kind = *b"grandpa:equivoca";
type TimeSlot = GrandpaTimeSlot;

fn offenders(&self) -> Vec<FullIdentification> {
fn offenders(&self) -> BoundedVec<FullIdentification, MaxOffenders> {
vec![self.offender.clone()]
.try_into()
.defensive_proof("MaxOffenders must be at least 1;")
.unwrap()
}

fn session_index(&self) -> SessionIndex {
Expand Down
13 changes: 10 additions & 3 deletions frame/grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ use frame_support::{
WeakBoundedVec,
};
use scale_info::TypeInfo;
use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult, KeyTypeId};
use sp_runtime::{generic::DigestItem, traits::Zero, BoundedVec, DispatchResult, KeyTypeId};
use sp_session::{GetSessionNumber, GetValidatorCount};
use sp_staking::SessionIndex;
use sp_staking::{offence::MaxReporters, SessionIndex};

mod default_weights;
mod equivocation;
Expand Down Expand Up @@ -568,9 +568,16 @@ impl<T: Config> Pallet<T> {
return Err(Error::<T>::InvalidEquivocationProof.into())
}

let reporters: BoundedVec<T::AccountId, MaxReporters> = match reporter {
Some(id) => vec![id],
None => vec![],
}
.try_into()
.expect("MaxReporters must be at least 1;");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this ensured? Should be in integrity_checks

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its a constant, not a configuration variable, so we only have to ensure it once.
But yea, could add it to the integrity checks.


// report to the offences module rewarding the sender.
T::HandleEquivocation::report_offence(
reporter.into_iter().collect(),
reporters,
<T::HandleEquivocation as HandleEquivocation<T>>::Offence::new(
session_index,
validator_count,
Expand Down
11 changes: 8 additions & 3 deletions frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ frame_support::construct_runtime!(
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned},
Offences: pallet_offences::{Pallet, Storage, Event},
Offences: pallet_offences::{Pallet, Storage, Event<T>},
Historical: pallet_session_historical::{Pallet},
}
);
Expand Down Expand Up @@ -128,8 +128,8 @@ impl pallet_session::Config for Test {
}

impl pallet_session::historical::Config for Test {
type FullIdentification = pallet_staking::Exposure<u64, u128>;
type FullIdentificationOf = pallet_staking::ExposureOf<Self>;
type FullIdentification = pallet_staking::ExposureOf<Test>;
type FullIdentificationOf = pallet_staking::ActiveExposure<Self>;
}

impl pallet_authorship::Config for Test {
Expand Down Expand Up @@ -216,6 +216,11 @@ impl pallet_offences::Config for Test {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;

type MaxConcurrentReportsPerTime = ConstU32<100>;
type MaxSameKindReports = ConstU32<100>;
type MaxSameKindReportsEncodedLen = ConstU32<5_000>;
type MaxOpaqueTimeSlotEncodedLen = ConstU32<16>;
}

parameter_types! {
Expand Down
Loading