Unverified Commit 0a633cd4 authored by asynchronous rob's avatar asynchronous rob Committed by GitHub
Browse files

Configurable maximum validators (#2586)



* guide: max_validators

* guide: new approach

* restrict validators based on configurable max

* add some tests

* fix wasm build (Vec)

* clean up warnings

* add logging

* set validator indices in tests as well

* fix common tests

* Update runtime/parachains/src/util.rs

Co-authored-by: Andronik Ordian's avatarAndronik Ordian <write@reusable.software>

Co-authored-by: Andronik Ordian's avatarAndronik Ordian <write@reusable.software>
parent 359ec799
Pipeline #127495 passed with stages
in 32 minutes and 48 seconds
......@@ -33,16 +33,12 @@ bitfields: map ValidatorIndex => AvailabilityBitfield;
PendingAvailability: map ParaId => CandidatePendingAvailability;
/// The commitments of candidates pending availability, by ParaId.
PendingAvailabilityCommitments: map ParaId => CandidateCommitments;
/// The current validators, by their parachain session keys.
Validators: Vec<ValidatorId>;
```
## Session Change
1. Clear out all candidates pending availability.
1. Clear out all validator bitfields.
1. Update `Validators` with the validators from the session change notification.
## Routines
......
......@@ -20,6 +20,7 @@ Before initializing modules, remove all changes from the `BufferedSessionChanges
The other parachains modules are initialized in this order:
1. Configuration
1. Shared
1. Paras
1. Scheduler
1. Inclusion
......@@ -29,7 +30,7 @@ The other parachains modules are initialized in this order:
1. UMP
1. HRMP
The [Configuration Module](configuration.md) is first, since all other modules need to operate under the same configuration as each other. It would lead to inconsistency if, for example, the scheduler ran first and then the configuration was updated before the Inclusion module.
The [Configuration Module](configuration.md) is first, since all other modules need to operate under the same configuration as each other. Then the [Shared][shared.md] module is invoked, which determines the set of active validators. It would lead to inconsistency if, for example, the scheduler ran first and then the configuration was updated before the Inclusion module.
Set `HasInitialized` to true.
......
......@@ -149,7 +149,7 @@ enum FreedReason {
Storage layout:
```rust
/// All the validator groups. One for each core.
/// All the validator groups. One for each core. Indices are into the `ActiveValidators` storage.
ValidatorGroups: Vec<Vec<ValidatorIndex>>;
/// A queue of upcoming claims and which core they should be mapped onto.
ParathreadQueue: ParathreadQueue;
......@@ -178,14 +178,15 @@ Actions:
1. Set `SessionStartBlock` to current block number + 1, as session changes are applied at the end of the block.
1. Clear all `Some` members of `AvailabilityCores`. Return all parathread claims to queue with retries un-incremented.
1. Set `configuration = Configuration::configuration()` (see [`HostConfiguration`](../types/runtime.md#host-configuration))
1. Fetch `Shared::ActiveValidators` as AV.
1. Determine the number of cores & validator groups as `n_cores`. This is the maximum of
1. `Paras::parachains().len() + configuration.parathread_cores`
1. `n_validators / max_validators_per_core` if `configuration.max_validators_per_core` is `Some` and non-zero.
1. Resize `AvailabilityCores` to have length `n_cores` with all `None` entries.
1. Compute new validator groups by shuffling using a secure randomness beacon
- We obtain "shuffled validators" `SV` by shuffling the validators using the `SessionChangeNotification`'s random seed.
- Note that the total number of validators `V` in `SV` may not be evenly divided by `n_cores`.
- The groups are selected by partitioning `SV`. The first V % N groups will have (V / n_cores) + 1 members, while the remaining groups will have (V / N) members each.
- Note that the total number of validators `V` in AV may not be evenly divided by `n_cores`.
- The groups are selected by partitioning AV. The first V % N groups will have (V / n_cores) + 1 members, while the remaining groups will have (V / N) members each.
- Instead of using the indices within AV, which point to the broader set, indices _into_ AV should be used. This implies that groups should have simply ascending validator indices.
1. Prune the parathread queue to remove all retries beyond `configuration.parathread_retries`.
- Also prune all parathread claims corresponding to de-registered parathreads.
- all pruned claims should have their entry removed from the parathread index.
......
......@@ -47,7 +47,7 @@ Sessions: map SessionIndex => Option<SessionInfo>,
## Session Change
1. Update `EarliestStoredSession` based on `config.dispute_period` and remove all entries from `Sessions` from the previous value up to the new value.
1. Create a new entry in `Sessions` with information about the current session.
1. Create a new entry in `Sessions` with information about the current session. Use `shared::ActiveValidators` to determine the indices into the broader validator sets (validation, assignment, discovery) which are actually used for parachain validation. Only these validators should appear in the `SessionInfo`.
## Routines
......
......@@ -20,8 +20,14 @@ pub(crate) const SESSION_DELAY: SessionIndex = 2;
## Storage
```rust
// The current session index within the Parachains Runtime system.
/// The current session index within the Parachains Runtime system.
CurrentSessionIndex: SessionIndex;
/// All the validators actively participating in parachain consensus.
/// Indices are into the broader validator set.
ActiveValidatorIndices: Vec<ValidatorIndex>,
/// The parachain attestation keys of the validators actively participating in parachain consensus.
/// This should be the same length as `ActiveValidatorIndices`.
ActiveValidatorKeys: Vec<ValidatorId>
```
## Initialization
......@@ -35,8 +41,9 @@ them.
## Session Change
During a session change, the Shared Module receives and stores the current Session Index for that
block through the Session Change Notification.
During a session change, the Shared Module receives and stores the current Session Index directly from the initializer module, along with the broader validator set, and it returns the new list of validators.
The list of validators should be first shuffled according to the chain's random seed and then truncated. The indices of these validators should be set to `ActiveValidatorIndices` and then returned back to the initializer. `ActiveValidatorKeys` should be set accordingly.
This information is used in the:
......
......@@ -36,6 +36,8 @@ struct HostConfiguration {
pub scheduling_lookahead: u32,
/// The maximum number of validators to have per core. `None` means no maximum.
pub max_validators_per_core: Option<u32>,
/// The maximum number of validators to use for parachains, in total. `None` means no maximum.
pub max_validators: Option<u32>,
/// The amount of sessions to keep for disputes.
pub dispute_period: SessionIndex,
/// The amount of consensus slots that must pass between submitting an assignment and
......
......@@ -285,6 +285,7 @@ mod tests {
System: frame_system::{Module, Call, Config, Storage, Event<T>},
Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
Parachains: paras::{Module, Origin, Call, Storage, Config<T>},
Shared: shared::{Module, Call, Storage},
Inclusion: inclusion::{Module, Call, Storage, Event<T>},
Registrar: paras_registrar::{Module, Call, Storage},
Staking: pallet_staking::{Module, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
......@@ -466,7 +467,7 @@ mod tests {
pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");
mod app {
use super::super::Inclusion;
use super::super::Shared;
use sp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::KEY_TYPE);
......@@ -476,7 +477,7 @@ mod tests {
fn into_account(self) -> Self::AccountId {
let id = self.0.clone().into();
Inclusion::validators().iter().position(|b| *b == id).unwrap() as u64
Shared::active_validator_keys().iter().position(|b| *b == id).unwrap() as u64
}
}
}
......
......@@ -19,7 +19,7 @@
//! Configuration can change only at session boundaries and is buffered until then.
use sp_std::prelude::*;
use primitives::v1::{Balance, ValidatorId, SessionIndex};
use primitives::v1::{Balance, SessionIndex};
use frame_support::{
decl_storage, decl_module, decl_error,
ensure,
......@@ -146,6 +146,10 @@ pub struct HostConfiguration<BlockNumber> {
///
/// `None` means no maximum.
pub max_validators_per_core: Option<u32>,
/// The maximum number of valdiators to use for parachain consensus, period.
///
/// `None` means no maximum.
pub max_validators: Option<u32>,
/// The amount of sessions to keep for disputes.
pub dispute_period: SessionIndex,
/// The amount of consensus slots that must pass between submitting an assignment and
......@@ -181,6 +185,7 @@ impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber
parathread_retries: Default::default(),
scheduling_lookahead: Default::default(),
max_validators_per_core: Default::default(),
max_validators: None,
dispute_period: Default::default(),
n_delay_tranches: Default::default(),
zeroth_delay_tranche_width: Default::default(),
......@@ -400,6 +405,16 @@ decl_module! {
Ok(())
}
/// Set the maximum number of validators to use in parachain consensus.
#[weight = (1_000, DispatchClass::Operational)]
pub fn set_max_validators(origin, new: Option<u32>) -> DispatchResult {
ensure_root(origin)?;
Self::update_config_member(|config| {
sp_std::mem::replace(&mut config.max_validators, new) != new
});
Ok(())
}
/// Set the dispute period, in number of sessions to keep for disputes.
#[weight = (1_000, DispatchClass::Operational)]
pub fn set_dispute_period(origin, new: SessionIndex) -> DispatchResult {
......@@ -648,8 +663,6 @@ impl<T: Config> Module<T> {
/// Called by the initializer to note that a new session has started.
pub(crate) fn initializer_on_new_session(
_validators: &[ValidatorId],
_queued: &[ValidatorId],
session_index: &SessionIndex,
) {
if let Some(pending) = <Self as Store>::PendingConfig::take(session_index) {
......@@ -700,12 +713,12 @@ mod tests {
assert_eq!(Configuration::config(), old_config);
assert_eq!(<Configuration as Store>::PendingConfig::get(1), None);
Configuration::initializer_on_new_session(&[], &[], &1);
Configuration::initializer_on_new_session(&1);
assert_eq!(Configuration::config(), old_config);
assert_eq!(<Configuration as Store>::PendingConfig::get(2), Some(config.clone()));
Configuration::initializer_on_new_session(&[], &[], &2);
Configuration::initializer_on_new_session(&2);
assert_eq!(Configuration::config(), config);
assert_eq!(<Configuration as Store>::PendingConfig::get(3), None);
......@@ -729,6 +742,7 @@ mod tests {
thread_availability_period: 8,
scheduling_lookahead: 3,
max_validators_per_core: None,
max_validators: None,
dispute_period: 239,
no_show_slots: 240,
n_delay_tranches: 241,
......@@ -795,6 +809,9 @@ mod tests {
Configuration::set_max_validators_per_core(
Origin::root(), new_config.max_validators_per_core,
).unwrap();
Configuration::set_max_validators(
Origin::root(), new_config.max_validators,
).unwrap();
Configuration::set_dispute_period(
Origin::root(), new_config.dispute_period,
).unwrap();
......
......@@ -1164,7 +1164,12 @@ mod tests {
};
// NOTE: this is in initialization order.
Shared::initializer_on_new_session(&notification);
Shared::initializer_on_new_session(
notification.session_index,
notification.random_seed,
&notification.new_config,
notification.validators.clone(),
);
let outgoing_paras = Paras::initializer_on_new_session(&notification);
Hrmp::initializer_on_new_session(&notification, &outgoing_paras);
}
......
......@@ -22,7 +22,7 @@
use sp_std::prelude::*;
use primitives::v1::{
ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId,
CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId,
AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
BackedCandidate, CoreIndex, GroupIndex, CommittedCandidateReceipt,
CandidateReceipt, HeadData, CandidateHash, Hash,
......@@ -134,9 +134,6 @@ decl_storage! {
/// The commitments of candidates pending availability, by ParaId.
PendingAvailabilityCommitments: map hasher(twox_64_concat) ParaId
=> Option<CandidateCommitments>;
/// The current validators, by their parachain session keys.
Validators get(fn validators) config(validators): Vec<ValidatorId>;
}
}
......@@ -224,15 +221,13 @@ impl<T: Config> Module<T> {
/// Handle an incoming session change.
pub(crate) fn initializer_on_new_session(
notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>
_notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>
) {
// unlike most drain methods, drained elements are not cleared on `Drop` of the iterator
// and require consumption.
for _ in <PendingAvailabilityCommitments>::drain() { }
for _ in <PendingAvailability<T>>::drain() { }
for _ in <AvailabilityBitfields<T>>::drain() { }
Validators::set(notification.validators.clone()); // substrate forces us to clone, stupidly.
}
/// Process a set of incoming bitfields. Return a vec of cores freed by candidates
......@@ -242,7 +237,7 @@ impl<T: Config> Module<T> {
signed_bitfields: SignedAvailabilityBitfields,
core_lookup: impl Fn(CoreIndex) -> Option<ParaId>,
) -> Result<Vec<CoreIndex>, DispatchError> {
let validators = Validators::get();
let validators = shared::Module::<T>::active_validator_keys();
let session_index = shared::Module::<T>::session_index();
let mut assigned_paras_record: Vec<_> = (0..expected_bits)
......@@ -394,7 +389,7 @@ impl<T: Config> Module<T> {
return Ok(Vec::new());
}
let validators = Validators::get();
let validators = shared::Module::<T>::active_validator_keys();
let parent_hash = <frame_system::Module<T>>::parent_hash();
// At the moment we assume (and in fact enforce, below) that the relay-parent is always one
......@@ -900,7 +895,7 @@ mod tests {
use primitives::v1::{BlockNumber, Hash};
use primitives::v1::{
SignedAvailabilityBitfield, CompactStatement as Statement, ValidityAttestation, CollatorId,
CandidateCommitments, SignedStatement, CandidateDescriptor, ValidationCode,
CandidateCommitments, SignedStatement, CandidateDescriptor, ValidationCode, ValidatorId,
};
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use frame_support::traits::{OnFinalize, OnInitialize};
......@@ -1039,7 +1034,12 @@ mod tests {
Shared::initializer_finalize();
if let Some(notification) = new_session(b + 1) {
Shared::initializer_on_new_session(&notification);
Shared::initializer_on_new_session(
notification.session_index,
notification.random_seed,
&notification.new_config,
notification.validators.clone(),
);
Paras::initializer_on_new_session(&notification);
Inclusion::initializer_on_new_session(&notification);
}
......@@ -1064,11 +1064,11 @@ mod tests {
}
fn default_availability_votes() -> BitVec<BitOrderLsb0, u8> {
bitvec::bitvec![BitOrderLsb0, u8; 0; Validators::get().len()]
bitvec::bitvec![BitOrderLsb0, u8; 0; Shared::active_validator_keys().len()]
}
fn default_backing_bitfield() -> BitVec<BitOrderLsb0, u8> {
bitvec::bitvec![BitOrderLsb0, u8; 0; Validators::get().len()]
bitvec::bitvec![BitOrderLsb0, u8; 0; Shared::active_validator_keys().len()]
}
fn backing_bitfield(v: &[usize]) -> BitVec<BitOrderLsb0, u8> {
......@@ -1213,7 +1213,7 @@ mod tests {
let validator_public = validator_pubkeys(&validators);
new_test_ext(genesis_config(paras)).execute_with(|| {
Validators::set(validator_public.clone());
shared::Module::<Test>::set_active_validators(validator_public.clone());
shared::Module::<Test>::set_session_index(5);
let signing_context = SigningContext {
......@@ -1446,7 +1446,7 @@ mod tests {
let validator_public = validator_pubkeys(&validators);
new_test_ext(genesis_config(paras)).execute_with(|| {
Validators::set(validator_public.clone());
shared::Module::<Test>::set_active_validators(validator_public.clone());
shared::Module::<Test>::set_session_index(5);
let signing_context = SigningContext {
......@@ -1611,7 +1611,7 @@ mod tests {
let validator_public = validator_pubkeys(&validators);
new_test_ext(genesis_config(paras)).execute_with(|| {
Validators::set(validator_public.clone());
shared::Module::<Test>::set_active_validators(validator_public.clone());
shared::Module::<Test>::set_session_index(5);
run_to_block(5, |_| None);
......@@ -2098,7 +2098,7 @@ mod tests {
let validator_public = validator_pubkeys(&validators);
new_test_ext(genesis_config(paras)).execute_with(|| {
Validators::set(validator_public.clone());
shared::Module::<Test>::set_active_validators(validator_public.clone());
shared::Module::<Test>::set_session_index(5);
run_to_block(5, |_| None);
......@@ -2295,7 +2295,7 @@ mod tests {
let validator_public = validator_pubkeys(&validators);
new_test_ext(genesis_config(paras)).execute_with(|| {
Validators::set(validator_public.clone());
shared::Module::<Test>::set_active_validators(validator_public.clone());
shared::Module::<Test>::set_session_index(5);
run_to_block(5, |_| None);
......@@ -2372,7 +2372,7 @@ mod tests {
}
#[test]
fn session_change_wipes_and_updates_session_info() {
fn session_change_wipes() {
let chain_a = ParaId::from(1);
let chain_b = ParaId::from(2);
let thread_a = ParaId::from(3);
......@@ -2392,7 +2392,7 @@ mod tests {
let validator_public = validator_pubkeys(&validators);
new_test_ext(genesis_config(paras)).execute_with(|| {
Validators::set(validator_public.clone());
shared::Module::<Test>::set_active_validators(validator_public.clone());
shared::Module::<Test>::set_session_index(5);
let validators_new = vec![
......@@ -2456,7 +2456,6 @@ mod tests {
run_to_block(11, |_| None);
assert_eq!(Validators::get(), validator_public);
assert_eq!(shared::Module::<Test>::session_index(), 5);
assert!(<AvailabilityBitfields<Test>>::get(&ValidatorIndex(0)).is_some());
......@@ -2480,7 +2479,6 @@ mod tests {
_ => None,
});
assert_eq!(Validators::get(), validator_public_new);
assert_eq!(shared::Module::<Test>::session_index(), 6);
assert!(<AvailabilityBitfields<Test>>::get(&ValidatorIndex(0)).is_none());
......
......@@ -174,7 +174,7 @@ decl_module! {
impl<T: Config> Module<T> {
fn apply_new_session(
session_index: SessionIndex,
validators: Vec<ValidatorId>,
all_validators: Vec<ValidatorId>,
queued: Vec<ValidatorId>,
) {
let prev_config = <configuration::Module<T>>::config();
......@@ -189,10 +189,17 @@ impl<T: Config> Module<T> {
// We can't pass the new config into the thing that determines the new config,
// so we don't pass the `SessionChangeNotification` into this module.
configuration::Module::<T>::initializer_on_new_session(&validators, &queued, &session_index);
configuration::Module::<T>::initializer_on_new_session(&session_index);
let new_config = <configuration::Module<T>>::config();
let validators = shared::Module::<T>::initializer_on_new_session(
session_index,
random_seed.clone(),
&new_config,
all_validators,
);
let notification = SessionChangeNotification {
validators,
queued,
......@@ -202,7 +209,6 @@ impl<T: Config> Module<T> {
session_index,
};
shared::Module::<T>::initializer_on_new_session(&notification);
let outgoing_paras = paras::Module::<T>::initializer_on_new_session(&notification);
scheduler::Module::<T>::initializer_on_new_session(&notification);
inclusion::Module::<T>::initializer_on_new_session(&notification);
......
......@@ -775,7 +775,12 @@ mod tests {
if new_session.as_ref().map_or(false, |v| v.contains(&(b + 1))) {
let mut session_change_notification = SessionChangeNotification::default();
session_change_notification.session_index = Shared::session_index() + 1;
Shared::initializer_on_new_session(&session_change_notification);
Shared::initializer_on_new_session(
session_change_notification.session_index,
session_change_notification.random_seed,
&session_change_notification.new_config,
session_change_notification.validators.clone(),
);
Paras::initializer_on_new_session(&session_change_notification);
}
System::on_finalize(b);
......
......@@ -32,7 +32,7 @@ use crate::{initializer, inclusion, scheduler, configuration, paras, session_inf
/// Implementation for the `validators` function of the runtime API.
pub fn validators<T: initializer::Config>() -> Vec<ValidatorId> {
<inclusion::Module<T>>::validators()
<shared::Module<T>>::active_validator_keys()
}
/// Implementation for the `validator_groups` function of the runtime API.
......
......@@ -48,9 +48,6 @@ use frame_support::{
use parity_scale_codec::{Encode, Decode};
use sp_runtime::traits::{One, Saturating};
use rand::{SeedableRng, seq::SliceRandom};
use rand_chacha::ChaCha20Rng;
use crate::{configuration, paras, initializer::SessionChangeNotification};
/// A queued parathread entry, pre-assigned to a core.
......@@ -157,7 +154,9 @@ pub trait Config: frame_system::Config + configuration::Config + paras::Config {
decl_storage! {
trait Store for Module<T: Config> as ParaScheduler {
/// All the validator groups. One for each core.
/// All the validator groups. One for each core. Indices are into `ActiveValidators` - not the
/// broader set of Polkadot validators, but instead just the subset used for parachains during
/// this session.
///
/// Bound: The number of cores is the sum of the numbers of parachains and parathread multiplexers.
/// Reasonably, 100-1000. The dominant factor is the number of validators: safe upper bound at 10k.
......@@ -223,7 +222,6 @@ impl<T: Config> Module<T> {
pub(crate) fn initializer_on_new_session(notification: &SessionChangeNotification<T::BlockNumber>) {
let &SessionChangeNotification {
ref validators,
ref random_seed,
ref new_config,
..
} = notification;
......@@ -259,27 +257,26 @@ impl<T: Config> Module<T> {
if n_cores == 0 || validators.is_empty() {
ValidatorGroups::set(Vec::new());
} else {
let mut rng: ChaCha20Rng = SeedableRng::from_seed(*random_seed);
let mut shuffled_indices: Vec<_> = (0..validators.len())
.enumerate()
.map(|(i, _)| ValidatorIndex(i as _))
.collect();
shuffled_indices.shuffle(&mut rng);
let group_base_size = validators.len() / n_cores as usize;
let n_larger_groups = validators.len() % n_cores as usize;
let group_base_size = shuffled_indices.len() / n_cores as usize;
let n_larger_groups = shuffled_indices.len() % n_cores as usize;
// Groups contain indices into the validators from the session change notification,
// which are already shuffled.
let groups: Vec<Vec<_>> = (0..n_cores).map(|core_id| {
let n_members = if (core_id as usize) < n_larger_groups {
group_base_size + 1
} else {
group_base_size
};
let mut groups: Vec<Vec<ValidatorIndex>> = Vec::new();
for i in 0..n_larger_groups {
let offset = (group_base_size + 1) * i;
groups.push(
(0..group_base_size + 1).map(|j| offset + j).map(|j| ValidatorIndex(j as _)).collect()
);
}
shuffled_indices.drain(shuffled_indices.len() - n_members ..).rev().collect()
}).collect();
for i in 0..(n_cores as usize - n_larger_groups) {
let offset = (n_larger_groups * (group_base_size + 1)) + (i * group_base_size);
groups.push(
(0..group_base_size).map(|j| offset + j).map(|j| ValidatorIndex(j as _)).collect()
);
}
ValidatorGroups::set(groups);
}
......
......@@ -24,12 +24,14 @@ use frame_support::{
decl_storage, decl_module, decl_error,
traits::OneSessionHandler, weights::Weight,
};
use crate::{configuration, paras, scheduler};
use crate::{configuration, paras, scheduler, shared};
use crate::util::take_active_subset;
use sp_std::vec::Vec;
pub trait Config:
frame_system::Config
+ configuration::Config
+ shared::Config
+ paras::Config
+ scheduler::Config
+ AuthorityDiscoveryConfig
......@@ -88,6 +90,8 @@ impl<T: Config> Module<T> {
let validators = notification.validators.clone();
let discovery_keys = <T as AuthorityDiscoveryConfig>::authorities();
let assignment_keys = AssignmentKeysUnsafe::get();
let active_set = <shared::Module<T>>::active_validator_indices();
let validator_groups = <scheduler::Module<T>>::validator_groups();
let n_cores = n_parachains + config.parathread_cores;
let zeroth_delay_tranche_width = config.zeroth_delay_tranche_width;
......@@ -114,9 +118,9 @@ impl<T: Config> Module<T> {
}
// create a new entry in `Sessions` with information about the current session
let new_session_info = SessionInfo {
validators,
discovery_keys,
assignment_keys,
validators: take_active_subset(&active_set, &validators),
discovery_keys: take_active_subset(&active_set, &discovery_keys),
assignment_keys: take_active_subset(&active_set, &assignment_keys),
validator_groups,
n_cores,
zeroth_delay_tranche_width,
......@@ -186,11 +190,14 @@ mod tests {
if let Some(notification) = new_session(b + 1) {
Configuration::initializer_on_new_session(
&notification.validators,
&notification.queued,
&notification.session_index,
);
Shared::initializer_on_new_session(&notification);
Shared::initializer_on_new_session(
notification.session_index,
notification.random_seed,
&notification.new_config,
notification.validators.clone(),
);
SessionInfo::initializer_on_new_session(&notification);
}
......
......@@ -19,12 +19,17 @@
//! To avoid cyclic dependencies, it is important that this module is not
//! dependent on any of the other modules.