runtime/disputes: slashing (#5535)

* disputes: runtime part of slashing

* disputes: reward winners

* disputes/slashing: validate_unsigned impl

* fmt

* disputes/slashing: report_dispute_lost_unsigned

* disputes/slashing: separate winners from losers and report winners

* disputes/slashing: refactoring

* impl HandleReports

* enable on Wenstend

* fmt

* add slashing pallet to the mock and test runtimes

* fix a bug in report_dispute_lost_unsigned

* fmt

* disputes: remove new_participants from summary

* disputes: remove punish_inconclusive

* impl SlashingHandler for Pallet for type-safety

* do not impl slashing::Config on mainnets yet

* teach spellcheck deduplication

* simplify interfaces and resolve some TODOs

* resolve some more TODOs

* minor typos

* move slashing into a folder

* remove unnecessary clone

* fix validator_set_count calculation

* introduce ValidatorSetCount

* store ValidatorSetCount

* fmt

* add the benchmark

* fmt

* unflatten slashing

* post-rebase fixes

* remove winners eagerly

* use real slashing weights for westend

* remove bench test suite

* zombinet: modify disputes test to check for an offence report

* zombinet: add a timeout

* add slashing pallet to Rococo

* zombienet: revert back to rococo-local

* fmt

* remove TODOs

* revert some accidental changes

* slashing is submodule of disputes

* Change the log target

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* wrap comments with rustfmt, more docs, constants

* use Defensive trait

* cargo update -p sp-io

* merge offence types, remove rewards for now

* cargo update -p sp-io

* benchmark fixes

* fmt

* unused var

* fix block_author impl

* ressurect RewardValidators trait

* remove outdated comment

* more module docs

* introduce BenchmarkingConfig

* typo fix

* teach spellcheck unapplied

* use Weight::new()

* fix mocking rewards

* use RefTimeWeight

* ".git/.scripts/bench-bot.sh" runtime westend-dev runtime_parachains::disputes::slashing

* refactor maybe_identify_validators

* no more ticket in disguise

* remove outdated comments

* lower against valid to 0.1%

* bump zombienet version for debug

* use from_perthousand

* post-merge fixes

* another day, another Weight changes

* Revert "bump zombienet version for debug"

This reverts commit 0d9978711f8ec9a746a5e1c45e8ffbe7c75e7b5c.

* do not reward block authors

* fix outdated comment

* use Pays from frame_support::dispatch::Pays

* add timeout to is up

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: command-bot <>
Co-authored-by: Javier Viola <javier@parity.io>
Co-authored-by: Javier Viola <pepoviola@gmail.com>
This commit is contained in:
Andronik
2022-09-20 12:56:55 +02:00
committed by GitHub
parent b6ed41a464
commit 18c077a818
18 changed files with 1105 additions and 73 deletions
+49 -29
View File
@@ -39,6 +39,7 @@ use sp_std::{cmp::Ordering, prelude::*};
#[allow(unused_imports)]
pub(crate) use self::tests::run_to_block;
pub mod slashing;
#[cfg(test)]
mod tests;
@@ -73,35 +74,55 @@ impl RewardValidators for () {
}
/// Punishment hooks for disputes.
pub trait PunishValidators {
/// Punish a series of validators who were for an invalid parablock. This is expected to be a major
/// punishment.
pub trait SlashingHandler<BlockNumber> {
/// Punish a series of validators who were for an invalid parablock. This is
/// expected to be a major punishment.
fn punish_for_invalid(
session: SessionIndex,
validators: impl IntoIterator<Item = ValidatorIndex>,
candidate_hash: CandidateHash,
losers: impl IntoIterator<Item = ValidatorIndex>,
);
/// Punish a series of validators who were against a valid parablock. This is expected to be a minor
/// punishment.
/// Punish a series of validators who were against a valid parablock. This
/// is expected to be a minor punishment.
fn punish_against_valid(
session: SessionIndex,
validators: impl IntoIterator<Item = ValidatorIndex>,
candidate_hash: CandidateHash,
losers: impl IntoIterator<Item = ValidatorIndex>,
);
/// Punish a series of validators who were part of a dispute which never concluded. This is expected
/// to be a minor punishment.
fn punish_inconclusive(
session: SessionIndex,
validators: impl IntoIterator<Item = ValidatorIndex>,
);
/// Called by the initializer to initialize the slashing pallet.
fn initializer_initialize(now: BlockNumber) -> Weight;
/// Called by the initializer to finalize the slashing pallet.
fn initializer_finalize();
/// Called by the initializer to note that a new session has started.
fn initializer_on_new_session(session_index: SessionIndex);
}
impl PunishValidators for () {
fn punish_for_invalid(_: SessionIndex, _: impl IntoIterator<Item = ValidatorIndex>) {}
impl<BlockNumber> SlashingHandler<BlockNumber> for () {
fn punish_for_invalid(
_: SessionIndex,
_: CandidateHash,
_: impl IntoIterator<Item = ValidatorIndex>,
) {
}
fn punish_against_valid(_: SessionIndex, _: impl IntoIterator<Item = ValidatorIndex>) {}
fn punish_against_valid(
_: SessionIndex,
_: CandidateHash,
_: impl IntoIterator<Item = ValidatorIndex>,
) {
}
fn punish_inconclusive(_: SessionIndex, _: impl IntoIterator<Item = ValidatorIndex>) {}
fn initializer_initialize(_now: BlockNumber) -> Weight {
Weight::zero()
}
fn initializer_finalize() {}
fn initializer_on_new_session(_: SessionIndex) {}
}
/// Binary discriminator to determine if the expensive signature
@@ -412,7 +433,7 @@ pub mod pallet {
pub trait Config: frame_system::Config + configuration::Config + session_info::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type RewardValidators: RewardValidators;
type PunishValidators: PunishValidators;
type SlashingHandler: SlashingHandler<Self::BlockNumber>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
@@ -831,14 +852,7 @@ impl<T: Config> Pallet<T> {
// it would be unexpected for any change here to occur when the dispute has not concluded
// in time, as a dispute guaranteed to have at least one honest participant should
// conclude quickly.
let participating = decrement_spam(spam_slots, &dispute);
// Slight punishment as these validators have failed to make data available to
// others in a timely manner.
T::PunishValidators::punish_inconclusive(
session_index,
participating.iter_ones().map(|i| ValidatorIndex(i as _)),
);
let _participating = decrement_spam(spam_slots, &dispute);
});
weight += T::DbWeight::get().reads_writes(2, 2);
@@ -1187,7 +1201,9 @@ impl<T: Config> Pallet<T> {
Error::<T>::SingleSidedDispute,
);
let DisputeStatementSet { session, candidate_hash, .. } = set.clone();
let DisputeStatementSet { ref session, ref candidate_hash, .. } = set;
let session = *session;
let candidate_hash = *candidate_hash;
// we can omit spam slot checks, `fn filter_disputes_data` is
// always called before calling this `fn`.
@@ -1227,10 +1243,14 @@ impl<T: Config> Pallet<T> {
// Slash participants on a losing side.
{
// a valid candidate, according to 2/3. Punish those on the 'against' side.
T::PunishValidators::punish_against_valid(session, summary.slash_against);
T::SlashingHandler::punish_against_valid(
session,
candidate_hash,
summary.slash_against,
);
// an invalid candidate, according to 2/3. Punish those on the 'for' side.
T::PunishValidators::punish_for_invalid(session, summary.slash_for);
T::SlashingHandler::punish_for_invalid(session, candidate_hash, summary.slash_for);
}
<Disputes<T>>::insert(&session, &candidate_hash, &summary.state);