Skip to content

Commit f4133b0

Browse files
authored
fix claim queue size (#6257)
Reported in #6161 (comment) Fixes a bug introduced in #5461, where the claim queue would contain entries even if the validator groups storage is empty (which happens during the first session). This PR sets the claim queue core count to be the minimum between the num_cores param and the number of validator groups TODO: - [x] prdoc - [x] unit test
1 parent 9353a28 commit f4133b0

File tree

3 files changed

+52
-14
lines changed

3 files changed

+52
-14
lines changed

polkadot/runtime/parachains/src/scheduler.rs

+23-13
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ use frame_support::{pallet_prelude::*, traits::Defensive};
4545
use frame_system::pallet_prelude::BlockNumberFor;
4646
pub use polkadot_core_primitives::v2::BlockNumber;
4747
use polkadot_primitives::{
48-
CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, ValidatorIndex,
48+
CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, SchedulerParams,
49+
ValidatorIndex,
4950
};
5051
use sp_runtime::traits::One;
5152

@@ -131,7 +132,7 @@ impl<T: Config> Pallet<T> {
131132
pub(crate) fn initializer_on_new_session(
132133
notification: &SessionChangeNotification<BlockNumberFor<T>>,
133134
) {
134-
let SessionChangeNotification { validators, new_config, prev_config, .. } = notification;
135+
let SessionChangeNotification { validators, new_config, .. } = notification;
135136
let config = new_config;
136137
let assigner_cores = config.scheduler_params.num_cores;
137138

@@ -186,7 +187,7 @@ impl<T: Config> Pallet<T> {
186187
}
187188

188189
// Resize and populate claim queue.
189-
Self::maybe_resize_claim_queue(prev_config.scheduler_params.num_cores, assigner_cores);
190+
Self::maybe_resize_claim_queue();
190191
Self::populate_claim_queue_after_session_change();
191192

192193
let now = frame_system::Pallet::<T>::block_number() + One::one();
@@ -203,6 +204,12 @@ impl<T: Config> Pallet<T> {
203204
ValidatorGroups::<T>::decode_len().unwrap_or(0)
204205
}
205206

207+
/// Expected claim queue len. Can be different than the real length if for example we don't have
208+
/// assignments for a core.
209+
fn expected_claim_queue_len(config: &SchedulerParams<BlockNumberFor<T>>) -> u32 {
210+
core::cmp::min(config.num_cores, Self::num_availability_cores() as u32)
211+
}
212+
206213
/// Get the group assigned to a specific core by index at the current block number. Result
207214
/// undefined if the core index is unknown or the block number is less than the session start
208215
/// index.
@@ -325,11 +332,11 @@ impl<T: Config> Pallet<T> {
325332
/// and fill the queue from the assignment provider.
326333
pub(crate) fn advance_claim_queue(except_for: &BTreeSet<CoreIndex>) {
327334
let config = configuration::ActiveConfig::<T>::get();
328-
let num_assigner_cores = config.scheduler_params.num_cores;
335+
let expected_claim_queue_len = Self::expected_claim_queue_len(&config.scheduler_params);
329336
// Extra sanity, config should already never be smaller than 1:
330337
let n_lookahead = config.scheduler_params.lookahead.max(1);
331338

332-
for core_idx in 0..num_assigner_cores {
339+
for core_idx in 0..expected_claim_queue_len {
333340
let core_idx = CoreIndex::from(core_idx);
334341

335342
if !except_for.contains(&core_idx) {
@@ -345,13 +352,16 @@ impl<T: Config> Pallet<T> {
345352
}
346353

347354
// on new session
348-
fn maybe_resize_claim_queue(old_core_count: u32, new_core_count: u32) {
349-
if new_core_count < old_core_count {
355+
fn maybe_resize_claim_queue() {
356+
let cq = ClaimQueue::<T>::get();
357+
let Some((old_max_core, _)) = cq.last_key_value() else { return };
358+
let config = configuration::ActiveConfig::<T>::get();
359+
let new_core_count = Self::expected_claim_queue_len(&config.scheduler_params);
360+
361+
if new_core_count < (old_max_core.0 + 1) {
350362
ClaimQueue::<T>::mutate(|cq| {
351-
let to_remove: Vec<_> = cq
352-
.range(CoreIndex(new_core_count)..CoreIndex(old_core_count))
353-
.map(|(k, _)| *k)
354-
.collect();
363+
let to_remove: Vec<_> =
364+
cq.range(CoreIndex(new_core_count)..=*old_max_core).map(|(k, _)| *k).collect();
355365
for key in to_remove {
356366
if let Some(dropped_assignments) = cq.remove(&key) {
357367
Self::push_back_to_assignment_provider(dropped_assignments.into_iter());
@@ -367,9 +377,9 @@ impl<T: Config> Pallet<T> {
367377
let config = configuration::ActiveConfig::<T>::get();
368378
// Extra sanity, config should already never be smaller than 1:
369379
let n_lookahead = config.scheduler_params.lookahead.max(1);
370-
let new_core_count = config.scheduler_params.num_cores;
380+
let expected_claim_queue_len = Self::expected_claim_queue_len(&config.scheduler_params);
371381

372-
for core_idx in 0..new_core_count {
382+
for core_idx in 0..expected_claim_queue_len {
373383
let core_idx = CoreIndex::from(core_idx);
374384
Self::fill_claim_queue(core_idx, n_lookahead);
375385
}

polkadot/runtime/parachains/src/scheduler/tests.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -726,8 +726,26 @@ fn session_change_decreasing_number_of_cores() {
726726
[assignment_b.clone()].into_iter().collect::<VecDeque<_>>()
727727
);
728728

729-
// No more assignments now.
730729
Scheduler::advance_claim_queue(&Default::default());
730+
// No more assignments now.
731+
assert_eq!(Scheduler::claim_queue_len(), 0);
732+
733+
// Retain number of cores to 1 but remove all validator groups. The claim queue length
734+
// should be the minimum of these two.
735+
736+
// Add an assignment.
737+
MockAssigner::add_test_assignment(assignment_b.clone());
738+
739+
run_to_block(4, |number| match number {
740+
4 => Some(SessionChangeNotification {
741+
new_config: new_config.clone(),
742+
prev_config: new_config.clone(),
743+
validators: vec![],
744+
..Default::default()
745+
}),
746+
_ => None,
747+
});
748+
731749
assert_eq!(Scheduler::claim_queue_len(), 0);
732750
});
733751
}

prdoc/pr_6257.prdoc

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
title: 'fix claim queue size when validator groups count is smaller'
2+
doc:
3+
- audience: Runtime Dev
4+
description: 'Fixes a bug introduced in https://github.com/paritytech/polkadot-sdk/pull/5461, where the claim queue
5+
would contain entries even if the validator groups storage is empty (which happens during the first session).
6+
This PR sets the claim queue core count to be the minimum between the num_cores param and the number of validator groups.'
7+
8+
crates:
9+
- name: polkadot-runtime-parachains
10+
bump: patch

0 commit comments

Comments
 (0)