Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 13 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
5 changes: 5 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,15 @@ impl pallet_im_online::Trait for Runtime {
type UnsignedPriority = ImOnlineUnsignedPriority;
}

parameter_types! {
pub const OffencesWeightSoftLimit: Weight = Perbill::from_percent(60) * MaximumBlockWeight::get();
}

impl pallet_offences::Trait for Runtime {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;
type WeightSoftLimit = OffencesWeightSoftLimit;
}

impl pallet_authority_discovery::Trait for Runtime {}
Expand Down
5 changes: 5 additions & 0 deletions frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,15 @@ impl staking::Trait for Test {
type MaxIterations = ();
}

parameter_types! {
pub const OffencesWeightSoftLimit: Weight = Perbill::from_percent(60) * MaximumBlockWeight::get();
}

impl offences::Trait for Test {
type Event = TestEvent;
type IdentificationTuple = session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;
type WeightSoftLimit = OffencesWeightSoftLimit;
}

impl Trait for Test {
Expand Down
16 changes: 14 additions & 2 deletions frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
#![cfg(test)]

use super::*;
use frame_support::parameter_types;
use frame_support::{
parameter_types,
weights::{Weight, constants::WEIGHT_PER_SECOND},
};
use frame_system as system;
use sp_runtime::{
SaturatedConversion,
Expand All @@ -34,6 +37,10 @@ type AccountIndex = u32;
type BlockNumber = u64;
type Balance = u64;

parameter_types! {
pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND;
}

impl frame_system::Trait for Test {
type Origin = Origin;
type Index = AccountIndex;
Expand All @@ -46,7 +53,7 @@ impl frame_system::Trait for Test {
type Header = sp_runtime::testing::Header;
type Event = Event;
type BlockHashCount = ();
type MaximumBlockWeight = ();
type MaximumBlockWeight = MaximumBlockWeight;
type DbWeight = ();
type AvailableBlockRatio = ();
type MaximumBlockLength = ();
Expand Down Expand Up @@ -178,10 +185,15 @@ impl pallet_im_online::Trait for Test {
type UnsignedPriority = ();
}

parameter_types! {
pub const OffencesWeightSoftLimit: Weight = Perbill::from_percent(60) * MaximumBlockWeight::get();
}

impl pallet_offences::Trait for Test {
type Event = Event;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;
type WeightSoftLimit = OffencesWeightSoftLimit;
}

impl<T> frame_system::offchain::SendTransactionTypes<T> for Test where Call: From<T> {
Expand Down
55 changes: 38 additions & 17 deletions frame/offences/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ mod tests;
use sp_std::vec::Vec;
use frame_support::{
decl_module, decl_event, decl_storage, Parameter, debug,
traits::Get,
weights::Weight,
};
use sp_runtime::{traits::Hash, Perbill};
use sp_runtime::{traits::{Hash, Zero}, Perbill};
use sp_staking::{
SessionIndex,
offence::{Offence, ReportOffence, Kind, OnOffenceHandler, OffenceDetails, OffenceError},
Expand Down Expand Up @@ -58,7 +59,11 @@ pub trait Trait: frame_system::Trait {
/// Full identification of the validator.
type IdentificationTuple: Parameter + Ord;
/// A handler called for every offence report.
type OnOffenceHandler: OnOffenceHandler<Self::AccountId, Self::IdentificationTuple>;
type OnOffenceHandler: OnOffenceHandler<Self::AccountId, Self::IdentificationTuple, Weight>;
/// The a soft limit on maximum weight that may be consumed while dispatching deferred offences in
/// `on_initialize`.
/// Note it's going to be exceeded before we stop adding to it, so it has to be set conservatively.
type WeightSoftLimit: Get<Weight>;
}

decl_storage! {
Expand Down Expand Up @@ -102,23 +107,39 @@ decl_module! {

fn on_initialize(now: T::BlockNumber) -> Weight {
// only decode storage if we can actually submit anything again.
if T::OnOffenceHandler::can_report() {
<DeferredOffences<T>>::mutate(|deferred| {
// keep those that fail to be reported again. An error log is emitted here; this
// should not happen if staking's `can_report` is implemented properly.
deferred.retain(|(o, p, s)| {
T::OnOffenceHandler::on_offence(&o, &p, *s).map_err(|_| {
debug::native::error!(
target: "pallet-offences",
"re-submitting a deferred slash returned Err at {}. This should not happen with pallet-staking",
now,
);
}).is_err()
})
})
if !T::OnOffenceHandler::can_report() {
return 0;
}

0
let limit = T::WeightSoftLimit::get();
let mut consumed = Weight::zero();

<DeferredOffences<T>>::mutate(|deferred| {
deferred.retain(|(offences, perbill, session)| {
if consumed >= limit {
true
} else {
// keep those that fail to be reported again. An error log is emitted here; this
// should not happen if staking's `can_report` is implemented properly.
match T::OnOffenceHandler::on_offence(&offences, &perbill, *session) {
Ok(weight) => {
consumed += weight;
false
},
Err(_) => {
debug::native::error!(
target: "pallet-offences",
"re-submitting a deferred slash returned Err at {}. This should not happen with pallet-staking",
now,
);
true
},
}
}
})
});

consumed
}
}
}
Expand Down
21 changes: 14 additions & 7 deletions frame/offences/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use sp_runtime::traits::{IdentityLookup, BlakeTwo256};
use sp_core::H256;
use frame_support::{
impl_outer_origin, impl_outer_event, parameter_types, StorageMap, StorageDoubleMap,
weights::Weight,
weights::{Weight, constants::{WEIGHT_PER_SECOND, RocksDbWeight}},
};
use frame_system as system;

Expand All @@ -47,18 +47,20 @@ thread_local! {
pub static CAN_REPORT: RefCell<bool> = RefCell::new(true);
}

impl<Reporter, Offender> offence::OnOffenceHandler<Reporter, Offender> for OnOffenceHandler {
impl<Reporter, Offender, Res: Default>
offence::OnOffenceHandler<Reporter, Offender, Res> for OnOffenceHandler
{
fn on_offence(
_offenders: &[OffenceDetails<Reporter, Offender>],
slash_fraction: &[Perbill],
_offence_session: SessionIndex,
) -> Result<(), ()> {
if <Self as offence::OnOffenceHandler<Reporter, Offender>>::can_report() {
) -> Result<Res, ()> {
if <Self as offence::OnOffenceHandler<Reporter, Offender, Res>>::can_report() {
ON_OFFENCE_PERBILL.with(|f| {
*f.borrow_mut() = slash_fraction.to_vec();
});

Ok(())
Ok(Default::default())
} else {
Err(())
}
Expand All @@ -84,7 +86,7 @@ pub fn with_on_offence_fractions<R, F: FnOnce(&mut Vec<Perbill>) -> R>(f: F) ->
pub struct Runtime;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = 1024;
pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
Expand All @@ -101,7 +103,7 @@ impl frame_system::Trait for Runtime {
type Event = TestEvent;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type DbWeight = ();
type DbWeight = RocksDbWeight;
type BlockExecutionWeight = ();
type ExtrinsicBaseWeight = ();
type MaximumBlockLength = MaximumBlockLength;
Expand All @@ -113,10 +115,15 @@ impl frame_system::Trait for Runtime {
type OnKilledAccount = ();
}

parameter_types! {
pub const OffencesWeightSoftLimit: Weight = Perbill::from_percent(60) * MaximumBlockWeight::get();
}

impl Trait for Runtime {
type Event = TestEvent;
type IdentificationTuple = u64;
type OnOffenceHandler = OnOffenceHandler;
type WeightSoftLimit = OffencesWeightSoftLimit;
}

mod offences {
Expand Down
50 changes: 43 additions & 7 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3218,32 +3218,42 @@ impl<T: Trait> Convert<T::AccountId, Option<Exposure<T::AccountId, BalanceOf<T>>
}

/// This is intended to be used with `FilterHistoricalOffences`.
impl <T: Trait> OnOffenceHandler<T::AccountId, pallet_session::historical::IdentificationTuple<T>> for Module<T> where
impl <T: Trait>
OnOffenceHandler<T::AccountId, pallet_session::historical::IdentificationTuple<T>, Weight>
for Module<T> where
T: pallet_session::Trait<ValidatorId = <T as frame_system::Trait>::AccountId>,
T: pallet_session::historical::Trait<
FullIdentification = Exposure<<T as frame_system::Trait>::AccountId, BalanceOf<T>>,
FullIdentificationOf = ExposureOf<T>,
>,
T::SessionHandler: pallet_session::SessionHandler<<T as frame_system::Trait>::AccountId>,
T::SessionManager: pallet_session::SessionManager<<T as frame_system::Trait>::AccountId>,
T::ValidatorIdOf: Convert<<T as frame_system::Trait>::AccountId, Option<<T as frame_system::Trait>::AccountId>>
T::ValidatorIdOf: Convert<
<T as frame_system::Trait>::AccountId,
Option<<T as frame_system::Trait>::AccountId>
>,
{
fn on_offence(
offenders: &[OffenceDetails<T::AccountId, pallet_session::historical::IdentificationTuple<T>>],
slash_fraction: &[Perbill],
slash_session: SessionIndex,
) -> Result<(), ()> {
) -> Result<Weight, ()> {
if !Self::can_report() {
return Err(())
}

let reward_proportion = SlashRewardFraction::get();
let mut consumed_weight: Weight = 0;
let mut add_db_reads_writes = |reads, writes| {
consumed_weight += T::DbWeight::get().reads_writes(reads, writes);
};

let active_era = {
let active_era = Self::active_era();
add_db_reads_writes(1, 0);
if active_era.is_none() {
// this offence need not be re-submitted.
return Ok(())
return Ok(consumed_weight)
}
active_era.expect("value checked not to be `None`; qed").index
};
Expand All @@ -3252,6 +3262,7 @@ impl <T: Trait> OnOffenceHandler<T::AccountId, pallet_session::historical::Ident
frame_support::print("Error: start_session_index must be set for current_era");
0
});
add_db_reads_writes(1, 0);

let window_start = active_era.saturating_sub(T::BondingDuration::get());

Expand All @@ -3261,11 +3272,13 @@ impl <T: Trait> OnOffenceHandler<T::AccountId, pallet_session::historical::Ident
active_era
} else {
let eras = BondedEras::get();
add_db_reads_writes(1, 0);

// reverse because it's more likely to find reports from recent eras.
match eras.iter().rev().filter(|&&(_, ref sesh)| sesh <= &slash_session).next() {
None => return Ok(()), // before bonding period. defensive - should be filtered out.
Some(&(ref slash_era, _)) => *slash_era,
// before bonding period. defensive - should be filtered out.
None => return Ok(consumed_weight),
}
};

Expand All @@ -3274,14 +3287,18 @@ impl <T: Trait> OnOffenceHandler<T::AccountId, pallet_session::historical::Ident
*earliest = Some(active_era)
}
});
add_db_reads_writes(1, 1);

let slash_defer_duration = T::SlashDeferDuration::get();

let invulnerables = Self::invulnerables();
add_db_reads_writes(1, 0);

for (details, slash_fraction) in offenders.iter().zip(slash_fraction) {
let (stash, exposure) = &details.offender;

// Skip if the validator is invulnerable.
if Self::invulnerables().contains(stash) {
if invulnerables.contains(stash) {
continue
}

Expand All @@ -3296,21 +3313,40 @@ impl <T: Trait> OnOffenceHandler<T::AccountId, pallet_session::historical::Ident
});

if let Some(mut unapplied) = unapplied {
let nominators_len = unapplied.others.len() as u64;
let reporters_len = details.reporters.len() as u64;

{
let upper_bound = 1 /* Validator/NominatorSlashInEra */ + 2 /* fetch_spans */;
let rw = upper_bound + nominators_len * upper_bound;
add_db_reads_writes(rw, rw);
}
unapplied.reporters = details.reporters.clone();
if slash_defer_duration == 0 {
// apply right away.
slashing::apply_slash::<T>(unapplied);
{
let slash_cost = (6, 5);
let reward_cost = (2, 2);
add_db_reads_writes(
(1 + nominators_len) * slash_cost.0 + reward_cost.0 * reporters_len,
(1 + nominators_len) * slash_cost.1 + reward_cost.1 * reporters_len
);
}
} else {
// defer to end of some `slash_defer_duration` from now.
<Self as Store>::UnappliedSlashes::mutate(
active_era,
move |for_later| for_later.push(unapplied),
);
add_db_reads_writes(1, 1);
}
} else {
add_db_reads_writes(4 /* fetch_spans */, 5 /* kick_out_if_recent */)
}
}

Ok(())
Ok(consumed_weight)
}

fn can_report() -> bool {
Expand Down
Loading