mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
Remove commented-out slashing code from serai-validator-sets-pallet
Deferred to https://github.com/serai-dex/serai/issues/657.
This commit is contained in:
@@ -14,31 +14,6 @@ use allocations::*;
|
|||||||
mod sessions;
|
mod sessions;
|
||||||
use sessions::{*, GenesisValidators as GenesisValidatorsContainer};
|
use sessions::{*, GenesisValidators as GenesisValidatorsContainer};
|
||||||
|
|
||||||
/*
|
|
||||||
#[derive(Debug, Encode, Decode, PartialEq, Eq, Clone)]
|
|
||||||
pub struct MembershipProof<T: pallet::Config>(pub Public, pub PhantomData<T>);
|
|
||||||
impl<T: pallet::Config> GetSessionNumber for MembershipProof<T> {
|
|
||||||
fn session(&self) -> u32 {
|
|
||||||
let current = Pallet::<T>::session(NetworkId::Serai).unwrap().0;
|
|
||||||
if Babe::<T>::is_member(&BabeAuthorityId::from(self.0)) {
|
|
||||||
current
|
|
||||||
} else {
|
|
||||||
// if it isn't in the current session, it should have been in the previous one.
|
|
||||||
current - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: pallet::Config> GetValidatorCount for MembershipProof<T> {
|
|
||||||
// We only implement and this interface to satisfy trait requirements
|
|
||||||
// Although this might return the wrong count if the offender was in the previous set, we don't
|
|
||||||
// rely on it and Substrate only relies on it to offer economic calculations we also don't rely
|
|
||||||
// on
|
|
||||||
fn validator_count(&self) -> u32 {
|
|
||||||
u32::try_from(Babe::<T>::authorities().len()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[expect(clippy::cast_possible_truncation)]
|
#[expect(clippy::cast_possible_truncation)]
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
mod pallet {
|
mod pallet {
|
||||||
@@ -157,7 +132,7 @@ mod pallet {
|
|||||||
type DelayedDeallocations = DelayedDeallocations<T>;
|
type DelayedDeallocations = DelayedDeallocations<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* TODO
|
||||||
/// The generated key pair for a given validator set instance.
|
/// The generated key pair for a given validator set instance.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::getter(fn keys)]
|
#[pallet::getter(fn keys)]
|
||||||
@@ -169,10 +144,6 @@ mod pallet {
|
|||||||
pub type PendingSlashReport<T: Config> =
|
pub type PendingSlashReport<T: Config> =
|
||||||
StorageMap<_, Identity, ExternalNetworkId, Public, OptionQuery>;
|
StorageMap<_, Identity, ExternalNetworkId, Public, OptionQuery>;
|
||||||
|
|
||||||
/// Disabled validators.
|
|
||||||
#[pallet::storage]
|
|
||||||
pub type SeraiDisabledIndices<T: Config> = StorageMap<_, Identity, u32, Public, OptionQuery>;
|
|
||||||
|
|
||||||
#[pallet::event]
|
#[pallet::event]
|
||||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||||
pub enum Event<T: Config> {
|
pub enum Event<T: Config> {
|
||||||
@@ -318,21 +289,7 @@ mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* TODO
|
||||||
fn session_to_unlock_on_for_current_set(network: NetworkId) -> Option<Session> {
|
|
||||||
let mut to_unlock_on = Self::session(network)?;
|
|
||||||
// Move to the next session, as deallocating currently in-use stake is obviously invalid
|
|
||||||
to_unlock_on.0 += 1;
|
|
||||||
if network == NetworkId::Serai {
|
|
||||||
// Since the next Serai set will already have been decided, we can only deallocate one
|
|
||||||
// session later
|
|
||||||
to_unlock_on.0 += 1;
|
|
||||||
}
|
|
||||||
// Increase the session by one, creating a cooldown period
|
|
||||||
to_unlock_on.0 += 1;
|
|
||||||
Some(to_unlock_on)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decreases a validator's allocation to a set.
|
/// Decreases a validator's allocation to a set.
|
||||||
///
|
///
|
||||||
/// Errors if the capacity provided by this allocation is in use.
|
/// Errors if the capacity provided by this allocation is in use.
|
||||||
@@ -349,7 +306,6 @@ mod pallet {
|
|||||||
account: T::AccountId,
|
account: T::AccountId,
|
||||||
amount: Amount,
|
amount: Amount,
|
||||||
) -> Result<bool, DispatchError> {
|
) -> Result<bool, DispatchError> {
|
||||||
/* TODO
|
|
||||||
// Check it's safe to decrease this set's stake by this amount
|
// Check it's safe to decrease this set's stake by this amount
|
||||||
if let NetworkId::External(n) = network {
|
if let NetworkId::External(n) = network {
|
||||||
let new_total_staked = Self::total_allocated_stake(NetworkId::from(n))
|
let new_total_staked = Self::total_allocated_stake(NetworkId::from(n))
|
||||||
@@ -378,7 +334,6 @@ mod pallet {
|
|||||||
Err(Error::<T>::DeallocationWouldRemoveFaultTolerance)?;
|
Err(Error::<T>::DeallocationWouldRemoveFaultTolerance)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
Sessions::<T>::decrease_allocation(network, account, amount)
|
Sessions::<T>::decrease_allocation(network, account, amount)
|
||||||
}
|
}
|
||||||
@@ -411,20 +366,6 @@ mod pallet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rotate_session() {
|
|
||||||
Self::retire_set(ValidatorSet { network: NetworkId::Serai, session: prior_serai_session });
|
|
||||||
|
|
||||||
// Clear SeraiDisabledIndices, only preserving keys still present in the new session
|
|
||||||
// First drain so we don't mutate as we iterate
|
|
||||||
let mut disabled = vec![];
|
|
||||||
for (_, validator) in SeraiDisabledIndices::<T>::drain() {
|
|
||||||
disabled.push(validator);
|
|
||||||
}
|
|
||||||
for disabled in disabled {
|
|
||||||
Self::disable_serai_validator(disabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the required stake in terms SRI for a given `Balance`.
|
/// Returns the required stake in terms SRI for a given `Balance`.
|
||||||
pub fn required_stake(balance: &ExternalBalance) -> SubstrateAmount {
|
pub fn required_stake(balance: &ExternalBalance) -> SubstrateAmount {
|
||||||
use dex_pallet::HigherPrecisionBalance;
|
use dex_pallet::HigherPrecisionBalance;
|
||||||
@@ -472,76 +413,6 @@ mod pallet {
|
|||||||
)?;
|
)?;
|
||||||
Self::increase_allocation(network, account, amount, true)
|
Self::increase_allocation(network, account, amount, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_slash_serai_validator(validator: Public) -> bool {
|
|
||||||
// Checks if they're active or actively deallocating (letting us still slash them)
|
|
||||||
// We could check if they're upcoming/still allocating, yet that'd mean the equivocation is
|
|
||||||
// invalid (as they aren't actively signing anything) or severely dated
|
|
||||||
// It's not an edge case worth being comprehensive to due to the complexity of being so
|
|
||||||
Babe::<T>::is_member(&BabeAuthorityId::from(validator)) ||
|
|
||||||
PendingDeallocations::<T>::iter_prefix((NetworkId::Serai, validator)).next().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn slash_serai_validator(validator: Public) {
|
|
||||||
let network = NetworkId::Serai;
|
|
||||||
|
|
||||||
let mut allocation = Abstractions::<T>::get_allocation((network, validator))
|
|
||||||
.unwrap_or(Amount(0));
|
|
||||||
// reduce the current allocation to 0.
|
|
||||||
Abstractions::<T>::set_allocation(network, validator, Amount(0));
|
|
||||||
|
|
||||||
// Take the pending deallocation from the current session
|
|
||||||
allocation.0 += PendingDeallocations::<T>::take(
|
|
||||||
(network, validator),
|
|
||||||
Self::session_to_unlock_on_for_current_set(network).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap_or(Amount(0))
|
|
||||||
.0;
|
|
||||||
|
|
||||||
// Reduce the TotalAllocatedStake for the network, if in set
|
|
||||||
// TotalAllocatedStake is the sum of allocations and pending deallocations from the current
|
|
||||||
// session, since pending deallocations can still be slashed and therefore still contribute
|
|
||||||
// to economic security, hence the allocation calculations above being above and the ones
|
|
||||||
// below being below
|
|
||||||
if InSet::<T>::contains_key(NetworkId::Serai, validator) {
|
|
||||||
let current_staked = Self::total_allocated_stake(network).unwrap();
|
|
||||||
TotalAllocatedStake::<T>::set(network, Some(current_staked - allocation));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear any other pending deallocations.
|
|
||||||
for (_, pending) in PendingDeallocations::<T>::drain_prefix((network, validator)) {
|
|
||||||
allocation.0 += pending.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// burn the allocation from the stake account
|
|
||||||
Coins::<T>::burn(
|
|
||||||
RawOrigin::Signed(Self::account()).into(),
|
|
||||||
Balance { coin: Coin::Serai, amount: allocation },
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Disable a Serai validator, preventing them from further authoring blocks.
|
|
||||||
///
|
|
||||||
/// Returns true if the validator-to-disable was actually a validator.
|
|
||||||
/// Returns false if they weren't.
|
|
||||||
fn disable_serai_validator(validator: Public) -> bool {
|
|
||||||
if let Some(index) =
|
|
||||||
Babe::<T>::authorities().into_iter().position(|(id, _)| id.into_inner() == validator)
|
|
||||||
{
|
|
||||||
SeraiDisabledIndices::<T>::set(u32::try_from(index).unwrap(), Some(validator));
|
|
||||||
|
|
||||||
let session = Self::session(NetworkId::Serai).unwrap();
|
|
||||||
Self::deposit_event(Event::ParticipantRemoved {
|
|
||||||
set: ValidatorSet { network: NetworkId::Serai, session },
|
|
||||||
removed: validator,
|
|
||||||
});
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,7 +504,7 @@ mod pallet {
|
|||||||
|
|
||||||
#[pallet::call]
|
#[pallet::call]
|
||||||
impl<T: Config> Pallet<T> {
|
impl<T: Config> Pallet<T> {
|
||||||
/*
|
/* TODO
|
||||||
#[pallet::call_index(0)]
|
#[pallet::call_index(0)]
|
||||||
#[pallet::weight((0, DispatchClass::Operational))] // TODO
|
#[pallet::weight((0, DispatchClass::Operational))] // TODO
|
||||||
pub fn set_keys(
|
pub fn set_keys(
|
||||||
@@ -761,7 +632,7 @@ mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* TODO
|
||||||
#[pallet::validate_unsigned]
|
#[pallet::validate_unsigned]
|
||||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||||
type Call = Call<T>;
|
type Call = Call<T>;
|
||||||
@@ -881,107 +752,6 @@ mod pallet {
|
|||||||
staked.0 >= new_required
|
staked.0 >= new_required
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config, V: Into<Public> + From<Public>> KeyOwnerProofSystem<(KeyTypeId, V)> for
|
|
||||||
Pallet<T> {
|
|
||||||
type Proof = MembershipProof<T>;
|
|
||||||
type IdentificationTuple = Public;
|
|
||||||
|
|
||||||
fn prove(key: (KeyTypeId, V)) -> Option<Self::Proof> {
|
|
||||||
Some(MembershipProof(key.1.into(), PhantomData))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_proof(key: (KeyTypeId, V), proof: Self::Proof) -> Option<Self::IdentificationTuple> {
|
|
||||||
let validator = key.1.into();
|
|
||||||
|
|
||||||
// check the offender and the proof offender are the same.
|
|
||||||
if validator != proof.0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check validator is valid
|
|
||||||
if !Self::can_slash_serai_validator(validator) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(validator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> ReportOffence<Public, Public, BabeEquivocationOffence<Public>> for Pallet<T> {
|
|
||||||
/// Report an `offence` and reward given `reporters`.
|
|
||||||
fn report_offence(
|
|
||||||
_: Vec<Public>,
|
|
||||||
offence: BabeEquivocationOffence<Public>,
|
|
||||||
) -> Result<(), OffenceError> {
|
|
||||||
// slash the offender
|
|
||||||
let offender = offence.offender;
|
|
||||||
Self::slash_serai_validator(offender);
|
|
||||||
|
|
||||||
// disable it
|
|
||||||
Self::disable_serai_validator(offender);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_known_offence(
|
|
||||||
offenders: &[Public],
|
|
||||||
_: &<BabeEquivocationOffence<Public> as Offence<Public>>::TimeSlot,
|
|
||||||
) -> bool {
|
|
||||||
for offender in offenders {
|
|
||||||
// It's not a known offence if we can still slash them
|
|
||||||
if Self::can_slash_serai_validator(*offender) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> ReportOffence<Public, Public, GrandpaEquivocationOffence<Public>> for Pallet<T> {
|
|
||||||
/// Report an `offence` and reward given `reporters`.
|
|
||||||
fn report_offence(
|
|
||||||
_: Vec<Public>,
|
|
||||||
offence: GrandpaEquivocationOffence<Public>,
|
|
||||||
) -> Result<(), OffenceError> {
|
|
||||||
// slash the offender
|
|
||||||
let offender = offence.offender;
|
|
||||||
Self::slash_serai_validator(offender);
|
|
||||||
|
|
||||||
// disable it
|
|
||||||
Self::disable_serai_validator(offender);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_known_offence(
|
|
||||||
offenders: &[Public],
|
|
||||||
_slot: &<GrandpaEquivocationOffence<Public> as Offence<Public>>::TimeSlot,
|
|
||||||
) -> bool {
|
|
||||||
for offender in offenders {
|
|
||||||
if Self::can_slash_serai_validator(*offender) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> FindAuthor<Public> for Pallet<T> {
|
|
||||||
fn find_author<'a, I>(digests: I) -> Option<Public>
|
|
||||||
where
|
|
||||||
I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
|
|
||||||
{
|
|
||||||
let i = Babe::<T>::find_author(digests)?;
|
|
||||||
Some(Babe::<T>::authorities()[i as usize].0.clone().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> DisabledValidators for Pallet<T> {
|
|
||||||
fn is_disabled(index: u32) -> bool {
|
|
||||||
SeraiDisabledIndices::<T>::get(index).is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user