mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 20:47:56 +00:00
Offences report system rework (#13425)
* Experiments with common equivocation trait * Improved equivocation trait * Fix grandpa equivocation implementation * Remove some cruft * Remove some more cruft * More generic naming * Simplification of offences manipilation * More refactory * Some prograss with the encapsulation of offence report system * Finally unit type works as a universal null report system * Align substrate node code * Further simplification * Fix test utils * Remove not required associated type * Fix benches * Rollback to prev field name * Box big params * Fix typo * Remove new tag computation * Remove default implementations * Better docs * Return 'Result' instead of bool * Change offence report system return types * Some renaming and documentation * Improve documentation * More abstract offence report system * Rename 'consume_evidence' to 'process_evidence' * Further docs refinements * Doc for dummy offence report * Fix rustdoc * Fix after master merge * Apply code review suggestions * Improve docs
This commit is contained in:
@@ -25,29 +25,25 @@ use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
dispatch::{DispatchResultWithPostInfo, Pays},
|
||||
ensure,
|
||||
traits::{
|
||||
ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet,
|
||||
OneSessionHandler,
|
||||
},
|
||||
traits::{ConstU32, DisabledValidators, FindAuthor, Get, OnTimestampSet, OneSessionHandler},
|
||||
weights::Weight,
|
||||
BoundedVec, WeakBoundedVec,
|
||||
};
|
||||
use sp_application_crypto::ByteArray;
|
||||
use sp_runtime::{
|
||||
generic::DigestItem,
|
||||
traits::{IsMember, One, SaturatedConversion, Saturating, Zero},
|
||||
ConsensusEngineId, KeyTypeId, Permill,
|
||||
};
|
||||
use sp_session::{GetSessionNumber, GetValidatorCount};
|
||||
use sp_staking::SessionIndex;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use sp_consensus_babe::{
|
||||
digests::{NextConfigDescriptor, NextEpochDescriptor, PreDigest},
|
||||
AllowedSlots, BabeAuthorityWeight, BabeEpochConfiguration, ConsensusLog, Epoch,
|
||||
EquivocationProof, Slot, BABE_ENGINE_ID,
|
||||
};
|
||||
use sp_consensus_vrf::schnorrkel;
|
||||
use sp_runtime::{
|
||||
generic::DigestItem,
|
||||
traits::{IsMember, One, SaturatedConversion, Saturating, Zero},
|
||||
ConsensusEngineId, Permill,
|
||||
};
|
||||
use sp_session::{GetSessionNumber, GetValidatorCount};
|
||||
use sp_staking::{offence::OffenceReportSystem, SessionIndex};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
pub use sp_consensus_babe::{AuthorityId, PUBLIC_KEY_LENGTH, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH};
|
||||
|
||||
@@ -64,7 +60,7 @@ mod mock;
|
||||
#[cfg(all(feature = "std", test))]
|
||||
mod tests;
|
||||
|
||||
pub use equivocation::{BabeEquivocationOffence, EquivocationHandler, HandleEquivocation};
|
||||
pub use equivocation::{EquivocationOffence, EquivocationReportSystem};
|
||||
#[allow(deprecated)]
|
||||
pub use randomness::CurrentBlockRandomness;
|
||||
pub use randomness::{
|
||||
@@ -150,35 +146,25 @@ pub mod pallet {
|
||||
/// initialization.
|
||||
type DisabledValidators: DisabledValidators;
|
||||
|
||||
/// The proof of key ownership, used for validating equivocation reports.
|
||||
/// The proof must include the session index and validator count of the
|
||||
/// session at which the equivocation occurred.
|
||||
type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount;
|
||||
|
||||
/// The identification of a key owner, used when reporting equivocations.
|
||||
type KeyOwnerIdentification: Parameter;
|
||||
|
||||
/// A system for proving ownership of keys, i.e. that a given key was part
|
||||
/// of a validator set, needed for validating equivocation reports.
|
||||
type KeyOwnerProofSystem: KeyOwnerProofSystem<
|
||||
(KeyTypeId, AuthorityId),
|
||||
Proof = Self::KeyOwnerProof,
|
||||
IdentificationTuple = Self::KeyOwnerIdentification,
|
||||
>;
|
||||
|
||||
/// The equivocation handling subsystem, defines methods to report an
|
||||
/// offence (after the equivocation has been validated) and for submitting a
|
||||
/// transaction to report an equivocation (from an offchain context).
|
||||
/// NOTE: when enabling equivocation handling (i.e. this type isn't set to
|
||||
/// `()`) you must use this pallet's `ValidateUnsigned` in the runtime
|
||||
/// definition.
|
||||
type HandleEquivocation: HandleEquivocation<Self>;
|
||||
|
||||
/// Helper for weights computations
|
||||
type WeightInfo: WeightInfo;
|
||||
|
||||
/// Max number of authorities allowed
|
||||
#[pallet::constant]
|
||||
type MaxAuthorities: Get<u32>;
|
||||
|
||||
/// The proof of key ownership, used for validating equivocation reports.
|
||||
/// The proof must include the session index and validator count of the
|
||||
/// session at which the equivocation occurred.
|
||||
type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount;
|
||||
|
||||
/// The equivocation handling subsystem, defines methods to check/report an
|
||||
/// offence and for submitting a transaction to report an equivocation
|
||||
/// (from an offchain context).
|
||||
type EquivocationReportSystem: OffenceReportSystem<
|
||||
Option<Self::AccountId>,
|
||||
(EquivocationProof<Self::Header>, Self::KeyOwnerProof),
|
||||
>;
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
@@ -429,8 +415,12 @@ pub mod pallet {
|
||||
key_owner_proof: T::KeyOwnerProof,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let reporter = ensure_signed(origin)?;
|
||||
|
||||
Self::do_report_equivocation(Some(reporter), *equivocation_proof, key_owner_proof)
|
||||
T::EquivocationReportSystem::process_evidence(
|
||||
Some(reporter),
|
||||
(*equivocation_proof, key_owner_proof),
|
||||
)?;
|
||||
// Waive the fee since the report is valid and beneficial
|
||||
Ok(Pays::No.into())
|
||||
}
|
||||
|
||||
/// Report authority equivocation/misbehavior. This method will verify
|
||||
@@ -451,12 +441,11 @@ pub mod pallet {
|
||||
key_owner_proof: T::KeyOwnerProof,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
ensure_none(origin)?;
|
||||
|
||||
Self::do_report_equivocation(
|
||||
T::HandleEquivocation::block_author(),
|
||||
*equivocation_proof,
|
||||
key_owner_proof,
|
||||
)
|
||||
T::EquivocationReportSystem::process_evidence(
|
||||
None,
|
||||
(*equivocation_proof, key_owner_proof),
|
||||
)?;
|
||||
Ok(Pays::No.into())
|
||||
}
|
||||
|
||||
/// Plan an epoch config change. The epoch config change is recorded and will be enacted on
|
||||
@@ -866,7 +855,7 @@ impl<T: Config> Pallet<T> {
|
||||
/// This function is only well defined for epochs that actually existed,
|
||||
/// e.g. if we skipped from epoch 10 to 20 then a call for epoch 15 (which
|
||||
/// didn't exist) will return an incorrect session index.
|
||||
fn session_index_for_epoch(epoch_index: u64) -> SessionIndex {
|
||||
pub(crate) fn session_index_for_epoch(epoch_index: u64) -> SessionIndex {
|
||||
let skipped_epochs = SkippedEpochs::<T>::get();
|
||||
match skipped_epochs.binary_search_by_key(&epoch_index, |(epoch_index, _)| *epoch_index) {
|
||||
// we have an exact match so we just return the given session index
|
||||
@@ -890,50 +879,6 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn do_report_equivocation(
|
||||
reporter: Option<T::AccountId>,
|
||||
equivocation_proof: EquivocationProof<T::Header>,
|
||||
key_owner_proof: T::KeyOwnerProof,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let offender = equivocation_proof.offender.clone();
|
||||
let slot = equivocation_proof.slot;
|
||||
|
||||
// validate the equivocation proof
|
||||
if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) {
|
||||
return Err(Error::<T>::InvalidEquivocationProof.into())
|
||||
}
|
||||
|
||||
let validator_set_count = key_owner_proof.validator_count();
|
||||
let session_index = key_owner_proof.session();
|
||||
|
||||
let epoch_index = *slot.saturating_sub(GenesisSlot::<T>::get()) / T::EpochDuration::get();
|
||||
|
||||
// check that the slot number is consistent with the session index
|
||||
// in the key ownership proof (i.e. slot is for that epoch)
|
||||
if Self::session_index_for_epoch(epoch_index) != session_index {
|
||||
return Err(Error::<T>::InvalidKeyOwnershipProof.into())
|
||||
}
|
||||
|
||||
// check the membership proof and extract the offender's id
|
||||
let key = (sp_consensus_babe::KEY_TYPE, offender);
|
||||
let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof)
|
||||
.ok_or(Error::<T>::InvalidKeyOwnershipProof)?;
|
||||
|
||||
let offence =
|
||||
BabeEquivocationOffence { slot, validator_set_count, offender, session_index };
|
||||
|
||||
let reporters = match reporter {
|
||||
Some(id) => vec![id],
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
T::HandleEquivocation::report_offence(reporters, offence)
|
||||
.map_err(|_| Error::<T>::DuplicateOffenceReport)?;
|
||||
|
||||
// waive the fee since the report is valid and beneficial
|
||||
Ok(Pays::No.into())
|
||||
}
|
||||
|
||||
/// Submits an extrinsic to report an equivocation. This method will create
|
||||
/// an unsigned extrinsic with a call to `report_equivocation_unsigned` and
|
||||
/// will push the transaction to the pool. Only useful in an offchain
|
||||
@@ -942,11 +887,7 @@ impl<T: Config> Pallet<T> {
|
||||
equivocation_proof: EquivocationProof<T::Header>,
|
||||
key_owner_proof: T::KeyOwnerProof,
|
||||
) -> Option<()> {
|
||||
T::HandleEquivocation::submit_unsigned_equivocation_report(
|
||||
equivocation_proof,
|
||||
key_owner_proof,
|
||||
)
|
||||
.ok()
|
||||
T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user