1

I am configuring POA chain with validator set by :- https://github.com/gautamdhameja/substrate-validator-set/blob/master/docs/council-integration.md and trying to configure the collection pallet

I am using polkadot branch 0.9.30

In my runtime I am trying to configure like this

parameter_types! {
    pub const MinAuthorities: u32 = 2;
}
type CouncilCollective = pallet_collective::Instance1;
type EnsureRootOrHalfCouncil = EitherOfDiverse<
    EnsureRoot<AccountId>,
    pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>,
>;

impl pallet_validator_set::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    // see readme for type declaration
    type AddRemoveOrigin = EnsureRootOrHalfCouncil;
    type MinAuthorities = MinAuthorities;
}

and in pallet_validator_set I have the following

//! # Validator Set Pallet
//!
//! The Validator Set Pallet allows addition and removal of
//! authorities/validators via extrinsics (transaction calls), in
//! Substrate-based PoA networks. It also integrates with the im-online pallet
//! to automatically remove offline validators.
//!
//! The pallet uses the Session pallet and implements related traits for session
//! management. Currently it uses periodic session rotation provided by the
//! session pallet to automatically rotate sessions. For this reason, the
//! validator addition and removal becomes effective only after 2 sessions
//! (queuing + applying).

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

mod mock;
mod tests;

use frame_support::{
    ensure,
    pallet_prelude::*,
    traits::{EstimateNextSessionRotation, Get, ValidatorSet, ValidatorSetWithIdentification, FromContainsPair},
};
use frame_support::log;


pub use pallet::*;
use sp_runtime::traits::{Convert, Zero};
use sp_staking::offence::{Offence, OffenceError, ReportOffence};
use sp_std::{collections::btree_set::BTreeSet, prelude::*};

pub const LOG_TARGET: &'static str = "runtime::validator-set";

#[frame_support::pallet]
pub mod pallet {
    use super::*;
    use frame_system::pallet_prelude::*;

    /// Configure the pallet by specifying the parameters and types on which it
    /// depends.
    #[pallet::config]
    pub trait Config: frame_system::Config + pallet_session::Config {
        /// The Event type.
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

        /// Origin for adding or removing a validator.
        type AddRemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;

        /// Minimum number of validators to leave in the validator set during
        /// auto removal.
        type MinAuthorities: Get<u32>;
    }

    #[pallet::pallet]
    #[pallet::generate_store(pub(super) trait Store)]
    #[pallet::without_storage_info]
    pub struct Pallet<T>(_);

    #[pallet::storage]
    #[pallet::getter(fn flag)]
    /// Flag to indicate to the session pallet if session should be rotated
    pub type Flag<T: Config> = StorageValue<_, bool>;

    #[pallet::storage]
    #[pallet::getter(fn validators)]
    pub type Validators<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;

    #[pallet::storage]
    #[pallet::getter(fn approved_validators)]
    pub type ApprovedValidators<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;

    #[pallet::storage]
    #[pallet::getter(fn validators_to_remove)]
    pub type OfflineValidators<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;

    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        /// New validator addition initiated. Effective in ~2 sessions.
        ValidatorAdditionInitiated(T::AccountId),

        /// Validator removal initiated. Effective in ~2 sessions.
        ValidatorRemovalInitiated(T::AccountId),
    }

    // Errors inform users that something went wrong.
    #[pallet::error]
    pub enum Error<T> {
        /// Target (post-removal) validator count is below the minimum.
        TooLowValidatorCount,
        /// Validator is already in the validator set.
        Duplicate,
        /// Validator is not approved for re-addition.
        ValidatorNotApproved,
        /// Only the validator can add itself back after coming online.
        BadOrigin,
    }

    #[pallet::hooks]
    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}

    #[pallet::genesis_config]
    pub struct GenesisConfig<T: Config> {
        pub initial_validators: Vec<T::AccountId>,
    }

    #[cfg(feature = "std")]
    impl<T: Config> Default for GenesisConfig<T> {
        fn default() -> Self {
            Self { initial_validators: Default::default() }
        }
    }

    #[pallet::genesis_build]
    impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
        fn build(&self) {
            Pallet::<T>::initialize_validators(&self.initial_validators);
        }
    }

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        /// Add a new validator.
        ///
        /// New validator's session keys should be set in Session pallet before
        /// calling this.
        ///
        /// The origin can be configured using the `AddRemoveOrigin` type in the
        /// host runtime. Can also be set to sudo/root.
        #[pallet::weight(0)]
        pub fn add_validator(origin: OriginFor<T>, validator_id: T::AccountId) -> DispatchResult {
            T::AddRemoveOrigin::ensure_origin(origin)?;

            Self::do_add_validator(validator_id.clone())?;
            Self::approve_validator(validator_id)?;

            Ok(())
        }

        /// Remove a validator.
        ///
        /// The origin can be configured using the `AddRemoveOrigin` type in the
        /// host runtime. Can also be set to sudo/root.
        #[pallet::weight(0)]
        pub fn remove_validator(
            origin: OriginFor<T>,
            validator_id: T::AccountId,
        ) -> DispatchResult {
            T::AddRemoveOrigin::ensure_origin(origin)?;

            Self::do_remove_validator(validator_id.clone())?;
            Self::unapprove_validator(validator_id)?;

            Ok(())
        }

        /// Add an approved validator again when it comes back online.
        ///
        /// For this call, the dispatch origin must be the validator itself.
        #[pallet::weight(0)]
        pub fn add_validator_again(
            origin: OriginFor<T>,
            validator_id: T::AccountId,
        ) -> DispatchResult {
            let who = ensure_signed(origin)?;
            ensure!(who == validator_id, Error::<T>::BadOrigin);

            let approved_set: BTreeSet<_> = <ApprovedValidators<T>>::get().into_iter().collect();
            ensure!(approved_set.contains(&validator_id), Error::<T>::ValidatorNotApproved);

            Self::do_add_validator(validator_id)?;

            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(())
    }

    // 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.");
    }

    // 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());
    }
}

// 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 end_session(_end_index: u32) {}

    fn start_session(_start_index: u32) {}
}

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

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

    fn estimate_next_session_rotation(
        _now: T::BlockNumber,
    ) -> (Option<T::BlockNumber>, 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>);

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;

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

    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>;
}

// 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);
        }

        Ok(())
    }

    fn is_known_offence(
        _offenders: &[(T::AccountId, T::AccountId)],
        _time_slot: &O::TimeSlot,
    ) -> bool {
        false
    }
}

impl<T: Config> pallet_session::ShouldEndSession<T::BlockNumber> for Pallet<T> {
    fn should_end_session(_now: T::BlockNumber) -> bool {
        Self::flag().unwrap_or(false)
    }
}

But when I try to compile the code I am getting following error

type AddRemoveOrigin = EnsureRootOrHalfCouncil;
      |                            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<RuntimeOrigin>` is not implemented for `Result<pallet_collective::RawOrigin<AccountId32, Instance1>, RuntimeOrigin>`

and I cannot configure this

type EnsureRootOrHalfCouncil = EnsureOneOf<
    AccountId,
    EnsureRoot<AccountId>,
    pallet_collective::EnsureProportionAtLeast<1, 2, AccountId>
>;

and seems its depreciated

How to configure collection pallet for validator_set and fix this error?

1 Answer 1

1

Ensure that in your runtime lib.rs file you have the following:

construct_runtime! {
   ...
   Collective: pallet_collective,
   // Or if you specify the parts manually
   Collective: pallet::collective::{Pallet, Call, Origin, Event},
   ...
}

You need to add the pallet_collective::RawOrigin to the RuntimeOrigin which is done by construct_runtime! when told that the pallet exposes an Origin.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.