use crate::{
configuration, paras, scheduler, shared,
util::{take_active_subset, take_active_subset_and_inactive},
};
use alloc::vec::Vec;
use frame_support::{
pallet_prelude::*,
traits::{OneSessionHandler, ValidatorSet, ValidatorSetWithIdentification},
};
use frame_system::pallet_prelude::BlockNumberFor;
use polkadot_primitives::{
AssignmentId, AuthorityDiscoveryId, ExecutorParams, SessionIndex, SessionInfo,
};
pub use pallet::*;
pub mod migration;
#[cfg(test)]
mod tests;
pub type AccountId<T> = <<T as Config>::ValidatorSet as ValidatorSet<
<T as frame_system::Config>::AccountId,
>>::ValidatorId;
pub type IdentificationTuple<T> = (
AccountId<T>,
<<T as Config>::ValidatorSet as ValidatorSetWithIdentification<
<T as frame_system::Config>::AccountId,
>>::Identification,
);
#[frame_support::pallet]
pub mod pallet {
use super::*;
#[pallet::pallet]
#[pallet::storage_version(migration::STORAGE_VERSION)]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config:
frame_system::Config
+ configuration::Config
+ shared::Config
+ paras::Config
+ scheduler::Config
+ AuthorityDiscoveryConfig
{
type ValidatorSet: ValidatorSetWithIdentification<Self::AccountId>;
}
#[pallet::storage]
pub(super) type AssignmentKeysUnsafe<T: Config> =
StorageValue<_, Vec<AssignmentId>, ValueQuery>;
#[pallet::storage]
pub type EarliestStoredSession<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
#[pallet::storage]
pub type Sessions<T: Config> = StorageMap<_, Identity, SessionIndex, SessionInfo>;
#[pallet::storage]
pub type AccountKeys<T: Config> = StorageMap<_, Identity, SessionIndex, Vec<AccountId<T>>>;
#[pallet::storage]
pub type SessionExecutorParams<T: Config> =
StorageMap<_, Identity, SessionIndex, ExecutorParams>;
}
pub trait AuthorityDiscoveryConfig {
fn authorities() -> Vec<AuthorityDiscoveryId>;
}
impl<T: pallet_authority_discovery::Config> AuthorityDiscoveryConfig for T {
fn authorities() -> Vec<AuthorityDiscoveryId> {
pallet_authority_discovery::Pallet::<T>::current_authorities().to_vec()
}
}
impl<T: Config> Pallet<T> {
pub(crate) fn initializer_on_new_session(
notification: &crate::initializer::SessionChangeNotification<BlockNumberFor<T>>,
) {
let config = configuration::ActiveConfig::<T>::get();
let dispute_period = config.dispute_period;
let validators = notification.validators.clone().into();
let discovery_keys = <T as AuthorityDiscoveryConfig>::authorities();
let assignment_keys = AssignmentKeysUnsafe::<T>::get();
let active_set = shared::ActiveValidatorIndices::<T>::get();
let validator_groups = scheduler::ValidatorGroups::<T>::get();
let n_cores = validator_groups.len() as u32;
let zeroth_delay_tranche_width = config.zeroth_delay_tranche_width;
let relay_vrf_modulo_samples = config.relay_vrf_modulo_samples;
let n_delay_tranches = config.n_delay_tranches;
let no_show_slots = config.no_show_slots;
let needed_approvals = config.needed_approvals;
let new_session_index = notification.session_index;
let random_seed = notification.random_seed;
let old_earliest_stored_session = EarliestStoredSession::<T>::get();
let new_earliest_stored_session = new_session_index.saturating_sub(dispute_period);
let new_earliest_stored_session =
core::cmp::max(new_earliest_stored_session, old_earliest_stored_session);
if old_earliest_stored_session != 0 || Sessions::<T>::get(0).is_some() {
for idx in old_earliest_stored_session..new_earliest_stored_session {
Sessions::<T>::remove(&idx);
AccountKeys::<T>::remove(&idx);
SessionExecutorParams::<T>::remove(&idx);
}
EarliestStoredSession::<T>::set(new_earliest_stored_session);
} else {
EarliestStoredSession::<T>::set(new_session_index);
}
let account_ids = T::ValidatorSet::validators();
let active_account_ids = take_active_subset(&active_set, &account_ids);
AccountKeys::<T>::insert(&new_session_index, &active_account_ids);
let new_session_info = SessionInfo {
validators, discovery_keys: take_active_subset_and_inactive(&active_set, &discovery_keys),
assignment_keys: take_active_subset(&active_set, &assignment_keys),
validator_groups: validator_groups.into(),
n_cores,
zeroth_delay_tranche_width,
relay_vrf_modulo_samples,
n_delay_tranches,
no_show_slots,
needed_approvals,
active_validator_indices: active_set,
random_seed,
dispute_period,
};
Sessions::<T>::insert(&new_session_index, &new_session_info);
SessionExecutorParams::<T>::insert(&new_session_index, config.executor_params);
}
pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
Weight::zero()
}
pub(crate) fn initializer_finalize() {}
}
impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
type Public = AssignmentId;
}
impl<T: pallet_session::Config + Config> OneSessionHandler<T::AccountId> for Pallet<T> {
type Key = AssignmentId;
fn on_genesis_session<'a, I: 'a>(_validators: I)
where
I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
{
}
fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, _queued: I)
where
I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
{
let assignment_keys: Vec<_> = validators.map(|(_, v)| v).collect();
AssignmentKeysUnsafe::<T>::set(assignment_keys);
}
fn on_disabled(_i: u32) {}
}