Skip to content

Commit 59f868d

Browse files
tdimitrovsandreim
andauthored
Deprecate para_id() from CoreState in polkadot primitives (paritytech#3979)
With Coretime enabled we can no longer assume there is a static 1:1 mapping between core index and para id. This mapping should be obtained from the scheduler/claimqueue on block by block basis. This PR modifies `para_id()` (from `CoreState`) to return the scheduled `ParaId` for occupied cores and removes its usages in the code. Closes paritytech#3948 --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com>
1 parent bd4471b commit 59f868d

6 files changed

Lines changed: 108 additions & 43 deletions

File tree

cumulus/client/consensus/aura/src/collators/lookahead.rs

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ use polkadot_node_subsystem::messages::{
4949
CollationGenerationMessage, RuntimeApiMessage, RuntimeApiRequest,
5050
};
5151
use polkadot_overseer::Handle as OverseerHandle;
52-
use polkadot_primitives::{CollatorPair, CoreIndex, Id as ParaId, OccupiedCoreAssumption};
52+
use polkadot_primitives::{
53+
AsyncBackingParams, CollatorPair, CoreIndex, CoreState, Id as ParaId, OccupiedCoreAssumption,
54+
};
5355

5456
use futures::{channel::oneshot, prelude::*};
5557
use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf};
@@ -186,10 +188,14 @@ where
186188

187189
// TODO: Currently we use just the first core here, but for elastic scaling
188190
// we iterate and build on all of the cores returned.
189-
let core_index = if let Some(core_index) =
190-
cores_scheduled_for_para(relay_parent, params.para_id, &mut params.overseer_handle)
191-
.await
192-
.get(0)
191+
let core_index = if let Some(core_index) = cores_scheduled_for_para(
192+
relay_parent,
193+
params.para_id,
194+
&mut params.overseer_handle,
195+
&mut params.relay_client,
196+
)
197+
.await
198+
.get(0)
193199
{
194200
*core_index
195201
} else {
@@ -223,7 +229,10 @@ where
223229
let parent_search_params = ParentSearchParams {
224230
relay_parent,
225231
para_id: params.para_id,
226-
ancestry_lookback: max_ancestry_lookback(relay_parent, &params.relay_client).await,
232+
ancestry_lookback: async_backing_params(relay_parent, &params.relay_client)
233+
.await
234+
.map(|c| c.allowed_ancestry_len as usize)
235+
.unwrap_or(0),
227236
max_depth: PARENT_SEARCH_DEPTH,
228237
ignore_alternative_branches: true,
229238
};
@@ -461,21 +470,19 @@ where
461470
Some(SlotClaim::unchecked::<P>(author_pub, slot, timestamp))
462471
}
463472

464-
/// Reads allowed ancestry length parameter from the relay chain storage at the given relay parent.
465-
///
466-
/// Falls back to 0 in case of an error.
467-
async fn max_ancestry_lookback(
473+
/// Reads async backing parameters from the relay chain storage at the given relay parent.
474+
async fn async_backing_params(
468475
relay_parent: PHash,
469476
relay_client: &impl RelayChainInterface,
470-
) -> usize {
477+
) -> Option<AsyncBackingParams> {
471478
match load_abridged_host_configuration(relay_parent, relay_client).await {
472-
Ok(Some(config)) => config.async_backing_params.allowed_ancestry_len as usize,
479+
Ok(Some(config)) => Some(config.async_backing_params),
473480
Ok(None) => {
474481
tracing::error!(
475482
target: crate::LOG_TARGET,
476483
"Active config is missing in relay chain storage",
477484
);
478-
0
485+
None
479486
},
480487
Err(err) => {
481488
tracing::error!(
@@ -484,7 +491,7 @@ async fn max_ancestry_lookback(
484491
?relay_parent,
485492
"Failed to read active config from relay chain client",
486493
);
487-
0
494+
None
488495
},
489496
}
490497
}
@@ -494,7 +501,9 @@ async fn cores_scheduled_for_para(
494501
relay_parent: PHash,
495502
para_id: ParaId,
496503
overseer_handle: &mut OverseerHandle,
504+
relay_client: &impl RelayChainInterface,
497505
) -> Vec<CoreIndex> {
506+
// Get `AvailabilityCores` from runtime
498507
let (tx, rx) = oneshot::channel();
499508
let request = RuntimeApiRequest::AvailabilityCores(tx);
500509
overseer_handle
@@ -522,11 +531,25 @@ async fn cores_scheduled_for_para(
522531
},
523532
};
524533

534+
let max_candidate_depth = async_backing_params(relay_parent, relay_client)
535+
.await
536+
.map(|c| c.max_candidate_depth)
537+
.unwrap_or(0);
538+
525539
cores
526540
.iter()
527541
.enumerate()
528542
.filter_map(|(index, core)| {
529-
if core.para_id() == Some(para_id) {
543+
let core_para_id = match core {
544+
CoreState::Scheduled(scheduled_core) => Some(scheduled_core.para_id),
545+
CoreState::Occupied(occupied_core) if max_candidate_depth >= 1 => occupied_core
546+
.next_up_on_available
547+
.as_ref()
548+
.map(|scheduled_core| scheduled_core.para_id),
549+
CoreState::Free | CoreState::Occupied(_) => None,
550+
};
551+
552+
if core_para_id == Some(para_id) {
530553
Some(CoreIndex(index as u32))
531554
} else {
532555
None

polkadot/node/core/prospective-parachains/src/tests.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,7 +1797,10 @@ fn persists_pending_availability_candidate() {
17971797
test_state.availability_cores = test_state
17981798
.availability_cores
17991799
.into_iter()
1800-
.filter(|core| core.para_id().map_or(false, |id| id == para_id))
1800+
.filter(|core| match core {
1801+
CoreState::Scheduled(scheduled_core) => scheduled_core.para_id == para_id,
1802+
_ => false,
1803+
})
18011804
.collect();
18021805
assert_eq!(test_state.availability_cores.len(), 1);
18031806

@@ -1896,7 +1899,10 @@ fn backwards_compatible() {
18961899
test_state.availability_cores = test_state
18971900
.availability_cores
18981901
.into_iter()
1899-
.filter(|core| core.para_id().map_or(false, |id| id == para_id))
1902+
.filter(|core| match core {
1903+
CoreState::Scheduled(scheduled_core) => scheduled_core.para_id == para_id,
1904+
_ => false,
1905+
})
19001906
.collect();
19011907
assert_eq!(test_state.availability_cores.len(), 1);
19021908

polkadot/node/core/provisioner/src/tests.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,11 @@ mod select_candidates {
918918
let committed_receipts: Vec<_> = (0..mock_cores.len())
919919
.map(|i| {
920920
let mut descriptor = dummy_candidate_descriptor(dummy_hash());
921-
descriptor.para_id = mock_cores[i].para_id().unwrap();
921+
descriptor.para_id = if let Scheduled(scheduled_core) = &mock_cores[i] {
922+
scheduled_core.para_id
923+
} else {
924+
panic!("`mock_cores` is not initialized with `Scheduled`?")
925+
};
922926
descriptor.persisted_validation_data_hash = empty_hash;
923927
descriptor.pov_hash = Hash::from_low_u64_be(i as u64);
924928
CommittedCandidateReceipt {

polkadot/node/network/statement-distribution/src/v2/mod.rs

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use polkadot_node_subsystem_util::{
4646
backing_implicit_view::View as ImplicitView,
4747
reputation::ReputationAggregator,
4848
runtime::{request_min_backing_votes, ProspectiveParachainsMode},
49-
vstaging::fetch_claim_queue,
49+
vstaging::{fetch_claim_queue, ClaimQueueSnapshot},
5050
};
5151
use polkadot_primitives::{
5252
AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex,
@@ -681,25 +681,33 @@ pub(crate) async fn handle_active_leaves_update<Context>(
681681
.map_err(JfyiError::FetchValidatorGroups)?
682682
.1;
683683

684+
let maybe_claim_queue = fetch_claim_queue(ctx.sender(), new_relay_parent)
685+
.await
686+
.unwrap_or_else(|err| {
687+
gum::debug!(target: LOG_TARGET, ?new_relay_parent, ?err, "handle_active_leaves_update: `claim_queue` API not available");
688+
None
689+
});
690+
684691
let local_validator = per_session.local_validator.and_then(|v| {
685692
if let LocalValidatorIndex::Active(idx) = v {
686693
find_active_validator_state(
687694
idx,
688695
&per_session.groups,
689696
&availability_cores,
690697
&group_rotation_info,
698+
&maybe_claim_queue,
691699
seconding_limit,
700+
max_candidate_depth,
692701
)
693702
} else {
694703
Some(LocalValidatorState { grid_tracker: GridTracker::default(), active: None })
695704
}
696705
});
697706

698707
let groups_per_para = determine_groups_per_para(
699-
ctx.sender(),
700-
new_relay_parent,
701708
availability_cores,
702709
group_rotation_info,
710+
&maybe_claim_queue,
703711
max_candidate_depth,
704712
)
705713
.await;
@@ -752,26 +760,38 @@ fn find_active_validator_state(
752760
groups: &Groups,
753761
availability_cores: &[CoreState],
754762
group_rotation_info: &GroupRotationInfo,
763+
maybe_claim_queue: &Option<ClaimQueueSnapshot>,
755764
seconding_limit: usize,
765+
max_candidate_depth: usize,
756766
) -> Option<LocalValidatorState> {
757767
if groups.all().is_empty() {
758768
return None
759769
}
760770

761771
let our_group = groups.by_validator_index(validator_index)?;
762772

763-
// note: this won't work well for on-demand parachains because it only works
764-
// when core assignments to paras are static throughout the session.
765-
766-
let core = group_rotation_info.core_for_group(our_group, availability_cores.len());
767-
let para = availability_cores.get(core.0 as usize).and_then(|c| c.para_id());
773+
let core_index = group_rotation_info.core_for_group(our_group, availability_cores.len());
774+
let para_assigned_to_core = if let Some(claim_queue) = maybe_claim_queue {
775+
claim_queue.get_claim_for(core_index, 0)
776+
} else {
777+
availability_cores
778+
.get(core_index.0 as usize)
779+
.and_then(|core_state| match core_state {
780+
CoreState::Scheduled(scheduled_core) => Some(scheduled_core.para_id),
781+
CoreState::Occupied(occupied_core) if max_candidate_depth >= 1 => occupied_core
782+
.next_up_on_available
783+
.as_ref()
784+
.map(|scheduled_core| scheduled_core.para_id),
785+
CoreState::Free | CoreState::Occupied(_) => None,
786+
})
787+
};
768788
let group_validators = groups.get(our_group)?.to_owned();
769789

770790
Some(LocalValidatorState {
771791
active: Some(ActiveValidatorState {
772792
index: validator_index,
773793
group: our_group,
774-
assignment: para,
794+
assignment: para_assigned_to_core,
775795
cluster_tracker: ClusterTracker::new(group_validators, seconding_limit)
776796
.expect("group is non-empty because we are in it; qed"),
777797
}),
@@ -2138,24 +2158,11 @@ async fn provide_candidate_to_grid<Context>(
21382158

21392159
// Utility function to populate per relay parent `ParaId` to `GroupIndex` mappings.
21402160
async fn determine_groups_per_para(
2141-
sender: &mut impl overseer::StatementDistributionSenderTrait,
2142-
relay_parent: Hash,
21432161
availability_cores: Vec<CoreState>,
21442162
group_rotation_info: GroupRotationInfo,
2163+
maybe_claim_queue: &Option<ClaimQueueSnapshot>,
21452164
max_candidate_depth: usize,
21462165
) -> HashMap<ParaId, Vec<GroupIndex>> {
2147-
let maybe_claim_queue = fetch_claim_queue(sender, relay_parent)
2148-
.await
2149-
.unwrap_or_else(|err| {
2150-
gum::debug!(
2151-
target: LOG_TARGET,
2152-
?relay_parent,
2153-
?err,
2154-
"determine_groups_per_para: `claim_queue` API not available, falling back to iterating availability cores"
2155-
);
2156-
None
2157-
});
2158-
21592166
let n_cores = availability_cores.len();
21602167

21612168
// Determine the core indices occupied by each para at the current relay parent. To support

polkadot/primitives/src/v7/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,10 +1086,16 @@ pub enum CoreState<H = Hash, N = BlockNumber> {
10861086
}
10871087

10881088
impl<N> CoreState<N> {
1089-
/// If this core state has a `para_id`, return it.
1089+
/// Returns the scheduled `ParaId` for the core or `None` if nothing is scheduled.
1090+
///
1091+
/// This function is deprecated. `ClaimQueue` should be used to obtain the scheduled `ParaId`s
1092+
/// for each core.
1093+
#[deprecated(
1094+
note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead."
1095+
)]
10901096
pub fn para_id(&self) -> Option<Id> {
10911097
match self {
1092-
Self::Occupied(ref core) => Some(core.para_id()),
1098+
Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id),
10931099
Self::Scheduled(core) => Some(core.para_id),
10941100
Self::Free => None,
10951101
}

prdoc/pr_3979.prdoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
2+
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
3+
4+
title: Deprecate `para_id()` from `CoreState` in polkadot primitives
5+
6+
doc:
7+
- audience: "Node Dev"
8+
description: |
9+
`CoreState`'s `para_id()` function is getting deprecated in favour of direct usage of the
10+
`ClaimQueue`. This is the preferred approach because it provides a better view on what is
11+
scheduled on each core.
12+
13+
crates:
14+
- name: polkadot-primitives
15+
bump: minor
16+
- name: polkadot-statement-distribution
17+
bump: minor
18+
- name: cumulus-client-consensus-aura
19+
bump: minor

0 commit comments

Comments
 (0)