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 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
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
26 changes: 19 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 @@ -45,20 +45,23 @@ pub struct OnOffenceHandler;
thread_local! {
pub static ON_OFFENCE_PERBILL: RefCell<Vec<Perbill>> = RefCell::new(Default::default());
pub static CAN_REPORT: RefCell<bool> = RefCell::new(true);
pub static OFFENCE_WEIGHT: RefCell<Weight> = RefCell::new(Default::default());
}

impl<Reporter, Offender> offence::OnOffenceHandler<Reporter, Offender> for OnOffenceHandler {
impl<Reporter, Offender>
offence::OnOffenceHandler<Reporter, Offender, Weight> 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<Weight, ()> {
if <Self as offence::OnOffenceHandler<Reporter, Offender, Weight>>::can_report() {
ON_OFFENCE_PERBILL.with(|f| {
*f.borrow_mut() = slash_fraction.to_vec();
});

Ok(())
Ok(OFFENCE_WEIGHT.with(|w| *w.borrow()))
} else {
Err(())
}
Expand All @@ -79,12 +82,16 @@ pub fn with_on_offence_fractions<R, F: FnOnce(&mut Vec<Perbill>) -> R>(f: F) ->
})
}

pub fn set_offence_weight(new: Weight) {
OFFENCE_WEIGHT.with(|w| *w.borrow_mut() = new);
}

// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Debug)]
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 +108,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 +120,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
47 changes: 46 additions & 1 deletion frame/offences/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use super::*;
use crate::mock::{
Offences, System, Offence, TestEvent, KIND, new_test_ext, with_on_offence_fractions,
offence_reports, set_can_report,
offence_reports, set_can_report, set_offence_weight,
};
use sp_runtime::Perbill;
use frame_support::traits::OnInitialize;
Expand Down Expand Up @@ -265,3 +265,48 @@ fn should_queue_and_resubmit_rejected_offence() {
assert_eq!(Offences::deferred_offences().len(), 0);
})
}

#[test]
fn weight_soft_limit_is_used() {
new_test_ext().execute_with(|| {
set_can_report(false);
// Only 2 can fit in one block
set_offence_weight(<mock::Runtime as Trait>::WeightSoftLimit::get() / 2);

// Queue 3 offences
// #1
let offence = Offence {
validator_set_count: 5,
time_slot: 42,
offenders: vec![5],
};
Offences::report_offence(vec![], offence).unwrap();
// #2
let offence = Offence {
validator_set_count: 5,
time_slot: 62,
offenders: vec![5],
};
Offences::report_offence(vec![], offence).unwrap();
// #3
let offence = Offence {
validator_set_count: 5,
time_slot: 72,
offenders: vec![5],
};
Offences::report_offence(vec![], offence).unwrap();
// 3 are queued
assert_eq!(Offences::deferred_offences().len(), 3);

// Allow reporting
set_can_report(true);

Offences::on_initialize(3);
// Two are completed, one is left in the queue
assert_eq!(Offences::deferred_offences().len(), 1);

Offences::on_initialize(4);
// All are done now
assert_eq!(Offences::deferred_offences().len(), 0);
})
}
Loading