Skip to content

Commit

Permalink
chore: restructure substrate-validator-set pallet #735 (#767)
Browse files Browse the repository at this point in the history
  • Loading branch information
sameh-farouk authored Jul 11, 2023
1 parent 5140310 commit 07ad89a
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(feature = "runtime-benchmarks")]

use super::*;
use crate::Pallet as ValidatorSet;
use crate::{Call, Config, Event, Pallet};
use frame_benchmarking::{benchmarks, whitelisted_caller};
use frame_support::assert_ok;
use frame_system::{EventRecord, Pallet as System, RawOrigin};
Expand Down
245 changes: 77 additions & 168 deletions substrate-node/pallets/substrate-validator-set/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,14 @@

#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::{
ensure,
pallet_prelude::*,
traits::{EstimateNextSessionRotation, Get, ValidatorSet, ValidatorSetWithIdentification},
};
use log;
pub use pallet::*;
use sp_runtime::traits::{Convert, Zero};
use sp_staking::offence::{Offence, OffenceError, ReportOffence};
use sp_std::convert::TryInto;
use sp_std::{collections::btree_set::BTreeSet, prelude::*};

mod mock;
mod tests;

#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
mod validator_set;

pub mod weights;

Expand All @@ -39,7 +30,17 @@ pub const LOG_TARGET: &'static str = "runtime::validator-set";
pub mod pallet {
use super::weights::WeightInfo;
use super::*;
use frame_support::{
ensure,
pallet_prelude::*,
traits::{EstimateNextSessionRotation, Get, ValidatorSet, ValidatorSetWithIdentification},
};
use frame_system::pallet_prelude::*;
use log;
use sp_runtime::traits::{Convert, Zero};
use sp_staking::offence::{Offence, OffenceError, ReportOffence};
use sp_std::convert::TryInto;
use sp_std::{collections::btree_set::BTreeSet, prelude::*};

/// Configure the pallet by specifying the parameters and types on which it
/// depends.
Expand Down Expand Up @@ -182,185 +183,93 @@ pub mod pallet {
Ok(())
}
}
}

impl<T: Config> Pallet<T> {
fn initialize_validators(validators: &[T::AccountId]) {
assert!(
validators.len() as u32 >= T::MinAuthorities::get(),
"Initial set of validators must be at least T::MinAuthorities"
);
assert!(
<Validators<T>>::get().is_empty(),
"Validators are already initialized!"
);

<Validators<T>>::put(validators);
<ApprovedValidators<T>>::put(validators);
}

fn do_add_validator(validator_id: T::AccountId) -> DispatchResult {
let validator_set: BTreeSet<_> = <Validators<T>>::get().into_iter().collect();
ensure!(
!validator_set.contains(&validator_id),
Error::<T>::Duplicate
);
<Validators<T>>::mutate(|v| v.push(validator_id.clone()));

Self::deposit_event(Event::ValidatorAdditionInitiated(validator_id.clone()));
log::debug!(target: LOG_TARGET, "Validator addition initiated.");

Ok(())
}

fn do_remove_validator(validator_id: T::AccountId) -> DispatchResult {
let mut validators = <Validators<T>>::get();

// Ensuring that the post removal, target validator count doesn't go
// below the minimum.
ensure!(
validators.len().saturating_sub(1) as u32 >= T::MinAuthorities::get(),
Error::<T>::TooLowValidatorCount
);

validators.retain(|v| *v != validator_id);

<Validators<T>>::put(validators);

Self::deposit_event(Event::ValidatorRemovalInitiated(validator_id.clone()));
log::debug!(target: LOG_TARGET, "Validator removal initiated.");

Ok(())
}

fn approve_validator(validator_id: T::AccountId) -> DispatchResult {
let approved_set: BTreeSet<_> = <ApprovedValidators<T>>::get().into_iter().collect();
ensure!(!approved_set.contains(&validator_id), Error::<T>::Duplicate);
<ApprovedValidators<T>>::mutate(|v| v.push(validator_id.clone()));
Ok(())
}

fn unapprove_validator(validator_id: T::AccountId) -> DispatchResult {
let mut approved_set = <ApprovedValidators<T>>::get();
approved_set.retain(|v| *v != validator_id);
Ok(())
}
// Provides the new set of validators to the session module when session is
// being rotated.
impl<T: Config> pallet_session::SessionManager<T::AccountId> for Pallet<T> {
// Plan a new session and provide new validator set.
fn new_session(_new_index: u32) -> Option<Vec<T::AccountId>> {
// Remove any offline validators. This will only work when the runtime
// also has the im-online pallet.
Self::remove_offline_validators();

log::debug!(
target: LOG_TARGET,
"New session called; updated validator set provided."
);

// Adds offline validators to a local cache for removal at new session.
fn mark_for_removal(validator_id: T::AccountId) {
<OfflineValidators<T>>::mutate(|v| v.push(validator_id));
log::debug!(
target: LOG_TARGET,
"Offline validator marked for auto removal."
);
}
Some(Self::validators())
}

// Removes offline validators from the validator set and clears the offline
// cache. It is called in the session change hook and removes the validators
// who were reported offline during the session that is ending. We do not
// check for `MinAuthorities` here, because the offline validators will not
// produce blocks and will have the same overall effect on the runtime.
fn remove_offline_validators() {
let validators_to_remove: BTreeSet<_> = <OfflineValidators<T>>::get().into_iter().collect();

// Delete from active validator set.
<Validators<T>>::mutate(|vs| vs.retain(|v| !validators_to_remove.contains(v)));
log::debug!(
target: LOG_TARGET,
"Initiated removal of {:?} offline validators.",
validators_to_remove.len()
);

// Clear the offline validator list to avoid repeated deletion.
<OfflineValidators<T>>::put(Vec::<T::AccountId>::new());
}
}
fn end_session(_end_index: u32) {}

// Provides the new set of validators to the session module when session is
// being rotated.
impl<T: Config> pallet_session::SessionManager<T::AccountId> for Pallet<T> {
// Plan a new session and provide new validator set.
fn new_session(_new_index: u32) -> Option<Vec<T::AccountId>> {
// Remove any offline validators. This will only work when the runtime
// also has the im-online pallet.
Self::remove_offline_validators();

log::debug!(
target: LOG_TARGET,
"New session called; updated validator set provided."
);

Some(Self::validators())
fn start_session(_start_index: u32) {}
}

fn end_session(_end_index: u32) {}
impl<T: Config> EstimateNextSessionRotation<T::BlockNumber> for Pallet<T> {
fn average_session_length() -> T::BlockNumber {
Zero::zero()
}

fn start_session(_start_index: u32) {}
}
fn estimate_current_session_progress(
_now: T::BlockNumber,
) -> (Option<sp_runtime::Permill>, frame_support::dispatch::Weight) {
(None, Zero::zero())
}

impl<T: Config> EstimateNextSessionRotation<T::BlockNumber> for Pallet<T> {
fn average_session_length() -> T::BlockNumber {
Zero::zero()
fn estimate_next_session_rotation(
_now: T::BlockNumber,
) -> (Option<T::BlockNumber>, frame_support::dispatch::Weight) {
(None, Zero::zero())
}
}

fn estimate_current_session_progress(
_now: T::BlockNumber,
) -> (Option<sp_runtime::Permill>, frame_support::dispatch::Weight) {
(None, Zero::zero())
}
// Implementation of Convert trait for mapping ValidatorId with AccountId.
pub struct ValidatorOf<T>(sp_std::marker::PhantomData<T>);

fn estimate_next_session_rotation(
_now: T::BlockNumber,
) -> (Option<T::BlockNumber>, frame_support::dispatch::Weight) {
(None, Zero::zero())
impl<T: Config> Convert<T::ValidatorId, Option<T::ValidatorId>> for ValidatorOf<T> {
fn convert(account: T::ValidatorId) -> Option<T::ValidatorId> {
Some(account)
}
}
}

// Implementation of Convert trait for mapping ValidatorId with AccountId.
pub struct ValidatorOf<T>(sp_std::marker::PhantomData<T>);

impl<T: Config> Convert<T::ValidatorId, Option<T::ValidatorId>> for ValidatorOf<T> {
fn convert(account: T::ValidatorId) -> Option<T::ValidatorId> {
Some(account)
}
}
impl<T: Config> ValidatorSet<T::AccountId> for Pallet<T> {
type ValidatorId = T::ValidatorId;
type ValidatorIdOf = T::ValidatorIdOf;

impl<T: Config> ValidatorSet<T::AccountId> for Pallet<T> {
type ValidatorId = T::ValidatorId;
type ValidatorIdOf = T::ValidatorIdOf;
fn session_index() -> sp_staking::SessionIndex {
pallet_session::Pallet::<T>::current_index()
}

fn session_index() -> sp_staking::SessionIndex {
pallet_session::Pallet::<T>::current_index()
fn validators() -> Vec<Self::ValidatorId> {
pallet_session::Pallet::<T>::validators()
}
}

fn validators() -> Vec<Self::ValidatorId> {
pallet_session::Pallet::<T>::validators()
impl<T: Config> ValidatorSetWithIdentification<T::AccountId> for Pallet<T> {
type Identification = T::ValidatorId;
type IdentificationOf = ValidatorOf<T>;
}
}

impl<T: Config> ValidatorSetWithIdentification<T::AccountId> for Pallet<T> {
type Identification = T::ValidatorId;
type IdentificationOf = ValidatorOf<T>;
}
// Offence reporting and unresponsiveness management.
impl<T: Config, O: Offence<(T::AccountId, T::AccountId)>>
ReportOffence<T::AccountId, (T::AccountId, T::AccountId), O> for Pallet<T>
{
fn report_offence(_reporters: Vec<T::AccountId>, offence: O) -> Result<(), OffenceError> {
let offenders = offence.offenders();

// Offence reporting and unresponsiveness management.
impl<T: Config, O: Offence<(T::AccountId, T::AccountId)>>
ReportOffence<T::AccountId, (T::AccountId, T::AccountId), O> for Pallet<T>
{
fn report_offence(_reporters: Vec<T::AccountId>, offence: O) -> Result<(), OffenceError> {
let offenders = offence.offenders();
for (v, _) in offenders.into_iter() {
Self::mark_for_removal(v);
}

for (v, _) in offenders.into_iter() {
Self::mark_for_removal(v);
Ok(())
}

Ok(())
}

fn is_known_offence(
_offenders: &[(T::AccountId, T::AccountId)],
_time_slot: &O::TimeSlot,
) -> bool {
false
fn is_known_offence(
_offenders: &[(T::AccountId, T::AccountId)],
_time_slot: &O::TimeSlot,
) -> bool {
false
}
}
}
}
3 changes: 1 addition & 2 deletions substrate-node/pallets/substrate-validator-set/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

#![cfg(test)]

use super::*;
use crate as validator_set;
use frame_support::{parameter_types, traits::ConstU32, traits::GenesisBuild, BasicExternalities};
use frame_system::EnsureRoot;
use pallet_session::*;
use parity_scale_codec::{Decode, Encode};
use sp_core::{crypto::key_types::DUMMY, H256};
use sp_runtime::{
impl_opaque_keys,
Expand All @@ -16,7 +16,6 @@ use sp_runtime::{
};
use sp_std::convert::{TryFrom, TryInto};
use std::cell::RefCell;
use parity_scale_codec::{Decode, Encode};

impl_opaque_keys! {
pub struct MockSessionKeys {
Expand Down
3 changes: 2 additions & 1 deletion substrate-node/pallets/substrate-validator-set/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

#![cfg(test)]

use super::*;
use crate::mock::*;
use crate::mock::{authorities, new_test_ext, Session, TestRuntime, ValidatorSet};
use crate::Error;
use frame_support::{assert_noop, assert_ok};
use frame_system::RawOrigin;
use sp_runtime::testing::UintAuthorityId;
use sp_runtime::DispatchError;

#[test]
fn simple_setup_should_work() {
Expand Down
Loading

0 comments on commit 07ad89a

Please sign in to comment.