From 2557181ecfe031c81c7b6a6801882c028140e664 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 24 Dec 2020 13:55:34 -0500 Subject: [PATCH] Alter behavior of `max_validators_per_core` (#2143) * guide: ensure max-per-core leads to creation of extra, semi-useless cores * alter behavior of max_validators_per_core * guide fixes --- .../src/runtime/scheduler.md | 13 ++++---- polkadot/runtime/parachains/src/scheduler.rs | 33 +++++++++++-------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md b/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md index e66eceefc0..0587e9ee8e 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md @@ -175,13 +175,14 @@ Actions: 1. Set `SessionStartBlock` to current block number. 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. Resize `AvailabilityCores` to have length `Paras::parachains().len() + configuration.parathread_cores with all `None` entries. +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 need a total of `N = Paras::parachains().len() + configuration.parathread_cores` validator groups. - - First, we obtain "shuffled validators" `SV` by shuffling the validators using the `SessionChangeNotification`'s random seed. - - Then, we truncate `SV` to have at most `configuration.max_validators_per_core * N` members, if `configuration.max_validators_per_core` is `Some`. - - Note that the total number of validators `V` in `SV` may not be evenly divided by `N`. - - The groups are selected by partitioning `SV`. The first V % N groups will have (V / N) + 1 members, while the remaining groups will have (V / N) members each. + - 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. 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. diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 27fa9efdfd..e9c92b9bd7 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -173,7 +173,9 @@ decl_storage! { /// The i'th parachain belongs to the i'th core, with the remaining cores all being /// parathread-multiplexers. /// - /// Bounded by the number of cores: one for each parachain and parathread multiplexer. + /// Bounded by the maximum of either of these two values: + /// * The number of parachains and parathread multiplexers + /// * The number of validators divided by `configuration.max_validators_per_core`. AvailabilityCores get(fn availability_cores): Vec>; /// An index used to ensure that only one claim on a parathread exists in the queue or is /// currently being handled by an occupied core. @@ -240,7 +242,13 @@ impl Module { let mut thread_queue = ParathreadQueue::get(); let n_parachains = >::parachains().len() as u32; - let n_cores = n_parachains + config.parathread_cores; + let n_cores = core::cmp::max( + n_parachains + config.parathread_cores, + match config.max_validators_per_core { + Some(x) if x != 0 => { validators.len() as u32 / x }, + _ => 0, + }, + ); >::set(>::block_number()); AvailabilityCores::mutate(|cores| { @@ -272,14 +280,6 @@ impl Module { shuffled_indices.shuffle(&mut rng); - // trim to max per cores. do this after shuffling. - { - if let Some(max_per_core) = config.max_validators_per_core { - let max_total = max_per_core * n_cores; - shuffled_indices.truncate(max_total as usize); - } - } - let group_base_size = shuffled_indices.len() / n_cores as usize; let n_larger_groups = shuffled_indices.len() % n_cores as usize; @@ -1070,6 +1070,7 @@ mod tests { new_test_ext(genesis_config).execute_with(|| { let chain_a = ParaId::from(1); let chain_b = ParaId::from(2); + let chain_c = ParaId::from(3); // ensure that we have 5 groups by registering 2 parachains. Paras::schedule_para_initialize(chain_a, ParaGenesisArgs { @@ -1082,6 +1083,11 @@ mod tests { validation_code: Vec::new().into(), parachain: true, }); + Paras::schedule_para_initialize(chain_c, ParaGenesisArgs { + genesis_head: Vec::new().into(), + validation_code: Vec::new().into(), + parachain: false, + }); run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { @@ -1102,11 +1108,10 @@ mod tests { }); let groups = ValidatorGroups::get(); - assert_eq!(groups.len(), 2); + assert_eq!(groups.len(), 7); - // Even though there are 7 validators, only 1 validator per group - // due to the max. - for i in 0..2 { + // Every validator gets its own group, even though there are 2 paras. + for i in 0..7 { assert_eq!(groups[i].len(), 1); } });