diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 68c243b57ad25..a7a9a72325d4c 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -317,6 +317,23 @@ where }, }; + let session_index = match params + .relay_client + .session_index_for_child(relay_parent) + .await + { + Ok(session_index) => session_index, + Err(err) => { + tracing::error!( + target: crate::LOG_TARGET, + ?err, + ?relay_parent, + "Failed to fetch session index." + ); + continue; + }, + }; + let parent_search_result = match crate::collators::find_parent( relay_parent, params.para_id, @@ -501,11 +518,12 @@ where SubmitCollationParams { relay_parent, collation, - parent_head: parent_header.encode().into(), validation_code_hash, result_sender: None, core_index, scheduling_parent: None, + session_index, + validation_data, }, ), "SubmitCollation", diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs index 7cfde76a7921e..98885c84350c6 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs @@ -474,7 +474,7 @@ where parachain_candidate: candidate.into(), validation_code_hash, core_index: core.core_index(), - max_pov_size: validation_data.max_pov_size, + validation_data, }) { tracing::error!(target: crate::LOG_TARGET, ?err, "Unable to send block to collation task."); return; diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs index b1008ac283111..c0fa0846de001 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs @@ -15,7 +15,6 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use codec::Encode; use std::path::PathBuf; use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; @@ -126,7 +125,7 @@ async fn handle_collation_message session_index, + Err(err) => { + tracing::error!( + target: LOG_TARGET, + ?err, + ?relay_parent, + "Failed to fetch session index." + ); + return; + }, + }; + tracing::debug!(target: LOG_TARGET, ?core_index, ?hash, %number, "Submitting collation for core."); overseer_handle @@ -178,11 +190,12 @@ async fn handle_collation_message { pub validation_code_hash: ValidationCodeHash, /// Core index that this block should be submitted on pub core_index: CoreIndex, - /// Maximum pov size. Currently needed only for exporting PoV. - pub max_pov_size: u32, + /// The persisted validation data for this collation. + pub validation_data: PersistedValidationData, } diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 6a9aa2c361e33..b523babed1848 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -229,44 +229,28 @@ impl CollationGenerationSubsystem { let SubmitCollationParams { relay_parent, collation, - parent_head, validation_code_hash, result_sender, core_index, scheduling_parent, + session_index, + validation_data, } = params; - let mut validation_data = match request_persisted_validation_data( - relay_parent, - config.para_id, - OccupiedCoreAssumption::TimedOut, - ctx.sender(), - ) - .await - .await?? - { - Some(v) => v, - None => { - gum::debug!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - our_para = %config.para_id, - "No validation data for para - does it exist at this relay-parent?", - ); - return Ok(()); - }, - }; - - // We need to swap the parent-head data, but all other fields here will be correct. - validation_data.parent_head = parent_head; - - let claim_queue = request_claim_queue(relay_parent, ctx.sender()).await.await??; + // For V2 descriptors, scheduling_parent is None and relay_parent serves both roles. + let scheduling_parent_or_relay = scheduling_parent.unwrap_or(relay_parent); + let claim_queue = + request_claim_queue(scheduling_parent_or_relay, ctx.sender()).await.await??; - let session_index = - request_session_index_for_child(relay_parent, ctx.sender()).await.await??; + let scheduling_session = + request_session_index_for_child(scheduling_parent_or_relay, ctx.sender()) + .await + .await??; - let session_info = - self.session_info_cache.get(relay_parent, session_index, ctx.sender()).await?; + let session_info = self + .session_info_cache + .get(scheduling_parent_or_relay, scheduling_session, ctx.sender()) + .await?; let collation = PreparedCollation { collation, relay_parent, @@ -276,6 +260,7 @@ impl CollationGenerationSubsystem { n_validators: session_info.n_validators, core_index, session_index, + scheduling_session, }; construct_and_distribute_receipt( @@ -300,7 +285,7 @@ impl CollationGenerationSubsystem { return Ok(()); }; - let Some(relay_parent) = maybe_activated else { return Ok(()) }; + let Some(activated) = maybe_activated else { return Ok(()) }; // If there is no collation function provided, bail out early. // Important: Lookahead collator and slot based collator do not use `CollatorFn`. @@ -313,14 +298,14 @@ impl CollationGenerationSubsystem { let _timer = self.metrics.time_new_activation(); let session_index = - request_session_index_for_child(relay_parent, ctx.sender()).await.await??; + request_session_index_for_child(activated, ctx.sender()).await.await??; let session_info = - self.session_info_cache.get(relay_parent, session_index, ctx.sender()).await?; + self.session_info_cache.get(activated, session_index, ctx.sender()).await?; let n_validators = session_info.n_validators; let claim_queue = - ClaimQueueSnapshot::from(request_claim_queue(relay_parent, ctx.sender()).await.await??); + ClaimQueueSnapshot::from(request_claim_queue(activated, ctx.sender()).await.await??); let assigned_cores = claim_queue .iter_all_claims() @@ -338,7 +323,7 @@ impl CollationGenerationSubsystem { // for some more blocks, or even time out. We assume all cores are being freed. let mut validation_data = match request_persisted_validation_data( - relay_parent, + activated, para_id, // Just use included assumption always. If there are no pending candidates it's a // no-op. @@ -352,7 +337,7 @@ impl CollationGenerationSubsystem { None => { gum::debug!( target: LOG_TARGET, - relay_parent = ?relay_parent, + relay_parent = ?activated, our_para = %para_id, "validation data is not available", ); @@ -361,7 +346,7 @@ impl CollationGenerationSubsystem { }; let validation_code_hash = match request_validation_code_hash( - relay_parent, + activated, para_id, // Just use included assumption always. If there are no pending candidates it's a // no-op. @@ -375,7 +360,7 @@ impl CollationGenerationSubsystem { None => { gum::debug!( target: LOG_TARGET, - relay_parent = ?relay_parent, + relay_parent = ?activated, our_para = %para_id, "validation code hash is not found.", ); @@ -403,7 +388,7 @@ impl CollationGenerationSubsystem { }; let (collation, result_sender) = - match collator_fn(relay_parent, &validation_data).await { + match collator_fn(activated, &validation_data).await { Some(collation) => collation.into_inner(), None => { gum::debug!( @@ -486,12 +471,14 @@ impl CollationGenerationSubsystem { PreparedCollation { collation, para_id, - relay_parent, + relay_parent: activated, validation_data: validation_data.clone(), validation_code_hash, n_validators, core_index: descriptor_core_index, session_index, + // V2 only: relay_parent == scheduling_parent, same session. + scheduling_session: session_index, }, &mut task_sender, result_sender, @@ -572,7 +559,10 @@ struct PreparedCollation { validation_code_hash: ValidationCodeHash, n_validators: usize, core_index: CoreIndex, + /// The relay parent's session index. session_index: SessionIndex, + /// The scheduling parent's session index. + scheduling_session: SessionIndex, } /// Takes a prepared collation, along with its context, and produces a candidate receipt @@ -594,6 +584,7 @@ async fn construct_and_distribute_receipt( n_validators, core_index, session_index, + scheduling_session, } = collation; let persisted_validation_data_hash = validation_data.hash(); @@ -641,6 +632,7 @@ async fn construct_and_distribute_receipt( relay_parent, core_index, session_index, + scheduling_session, persisted_validation_data_hash, pov_hash, erasure_root, diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index a306b3b9d7c01..7807f917fe294 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -178,10 +178,16 @@ fn submit_collation_is_no_op_before_initialization() { relay_parent: Hash::repeat_byte(0), scheduling_parent: Some(Hash::repeat_byte(0)), collation: test_collation(), - parent_head: vec![1, 2, 3].into(), validation_code_hash: Hash::repeat_byte(1).into(), result_sender: None, core_index: CoreIndex(0), + session_index: 1, + validation_data: PersistedValidationData { + parent_head: vec![1, 2, 3].into(), + relay_parent_number: 10, + relay_parent_storage_root: Hash::repeat_byte(1), + max_pov_size: 1024, + }, }), }) .await; @@ -223,10 +229,11 @@ fn submit_collation_leads_to_distribution() { relay_parent, scheduling_parent: Some(relay_parent), collation, - parent_head: dummy_head_data(), validation_code_hash, result_sender: None, core_index: CoreIndex(0), + session_index: 1, + validation_data: expected_pvd.clone(), }), }) .await; @@ -234,8 +241,6 @@ fn submit_collation_leads_to_distribution() { helpers::handle_runtime_calls_on_submit_collation( &mut virtual_overseer, relay_parent, - para_id, - expected_pvd.clone(), [(CoreIndex(0), VecDeque::from([para_id]))].into(), ) .await; @@ -259,6 +264,78 @@ fn submit_collation_leads_to_distribution() { }); } +#[test] +fn submit_collation_v3_runtime_calls_use_scheduling_parent() { + let relay_parent = Hash::repeat_byte(0xAA); + let scheduling_parent = Hash::repeat_byte(0xBB); + let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); + let parent_head = dummy_head_data(); + let para_id = ParaId::from(5); + let expected_pvd = PersistedValidationData { + parent_head: parent_head.clone(), + relay_parent_number: 10, + relay_parent_storage_root: Hash::repeat_byte(1), + max_pov_size: 1024, + }; + + test_harness(|mut virtual_overseer| async move { + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::Initialize(test_config_no_collator(para_id)), + }) + .await; + + let mut collation = test_collation(); + collation.upward_messages.force_push(UMP_SEPARATOR); + collation + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(0)).encode()); + + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::SubmitCollation(SubmitCollationParams { + relay_parent, + scheduling_parent: Some(scheduling_parent), + collation, + validation_code_hash, + result_sender: None, + core_index: CoreIndex(0), + session_index: 1, + validation_data: expected_pvd.clone(), + }), + }) + .await; + + // All runtime API calls must be against the scheduling_parent, not relay_parent. + helpers::handle_runtime_calls_on_submit_collation( + &mut virtual_overseer, + scheduling_parent, + [(CoreIndex(0), VecDeque::from([para_id]))].into(), + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { + candidate_receipt, + parent_head_data_hash, + .. + }) => { + let CandidateReceiptV2 { descriptor, .. } = candidate_receipt; + assert_eq!(parent_head_data_hash, parent_head.hash()); + assert_eq!(descriptor.persisted_validation_data_hash(), expected_pvd.hash()); + // relay_parent in the descriptor is the execution context + assert_eq!(descriptor.relay_parent(), relay_parent); + // scheduling_parent in the descriptor is the scheduling context + assert_eq!(descriptor.scheduling_parent(), scheduling_parent); + assert_eq!(descriptor.version(), CandidateDescriptorVersion::V3); + } + ); + + virtual_overseer + }); +} + #[test] fn distribute_collation_only_for_assigned_para_id_at_offset_0() { let activated_hash: Hash = [1; 32].into(); @@ -469,10 +546,11 @@ fn v2_receipts_failed_core_index_check() { relay_parent, scheduling_parent: Some(relay_parent), collation: test_collation(), - parent_head: dummy_head_data(), validation_code_hash, result_sender: None, core_index: CoreIndex(0), + session_index: 1, + validation_data: expected_pvd.clone(), }), }) .await; @@ -480,8 +558,6 @@ fn v2_receipts_failed_core_index_check() { helpers::handle_runtime_calls_on_submit_collation( &mut virtual_overseer, relay_parent, - para_id, - expected_pvd.clone(), // Core index commitment is on core 0 but don't add any assignment for core 0. [(CoreIndex(1), [para_id].into_iter().collect())].into_iter().collect(), ) @@ -527,10 +603,11 @@ fn approved_peer_signal() { relay_parent, scheduling_parent: Some(relay_parent), collation, - parent_head: dummy_head_data(), validation_code_hash, result_sender: None, core_index: CoreIndex(0), + session_index: 1, + validation_data: expected_pvd.clone(), }), }) .await; @@ -538,8 +615,6 @@ fn approved_peer_signal() { helpers::handle_runtime_calls_on_submit_collation( &mut virtual_overseer, relay_parent, - para_id, - expected_pvd.clone(), [(CoreIndex(0), [para_id].into_iter().collect())].into_iter().collect(), ) .await; @@ -706,32 +781,20 @@ mod helpers { } } - // Handles all runtime requests performed in `handle_submit_collation` + // Handles all runtime requests performed in `handle_submit_collation`. + // All requests are made against the scheduling parent (or relay_parent for V2). pub async fn handle_runtime_calls_on_submit_collation( virtual_overseer: &mut VirtualOverseer, - relay_parent: Hash, - para_id: ParaId, - expected_pvd: PersistedValidationData, + scheduling_parent: Hash, claim_queue: BTreeMap>, ) { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { - assert_eq!(rp, relay_parent); - assert_eq!(id, para_id); - assert_eq!(a, OccupiedCoreAssumption::TimedOut); - - tx.send(Ok(Some(expected_pvd))).unwrap(); - } - ); - assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( rp, RuntimeApiRequest::ClaimQueue(tx), )) => { - assert_eq!(rp, relay_parent); + assert_eq!(rp, scheduling_parent); tx.send(Ok(claim_queue)).unwrap(); } ); @@ -739,7 +802,7 @@ mod helpers { assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::SessionIndexForChild(tx))) => { - assert_eq!(rp, relay_parent); + assert_eq!(rp, scheduling_parent); tx.send(Ok(1)).unwrap(); } ); @@ -747,7 +810,7 @@ mod helpers { assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::Validators(tx))) => { - assert_eq!(rp, relay_parent); + assert_eq!(rp, scheduling_parent); tx.send(Ok(vec![ Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into(), diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index a9a5d3e9920ef..c5a79b5700e50 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -4416,7 +4416,8 @@ fn version_acceptance_before_and_after_v3_activation_on_second() { test_state.chain_ids[0], test_state.relay_parent, CoreIndex(0), - 1, + 1, // session_index + 1, // scheduling_session_index pvd.hash(), pov_hash, make_erasure_root(&test_state, pov.clone(), pvd.clone()), @@ -4521,7 +4522,8 @@ fn version_acceptance_before_and_after_v3_activation_on_statement() { test_state.chain_ids[0], test_state.relay_parent, CoreIndex(0), - 1, + 1, // session_index + 1, // scheduling_session_index pvd.hash(), pov_hash, make_erasure_root(&test_state, pov.clone(), pvd.clone()), diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 8ce2eb57bdb0e..f6f8e54cc80d8 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -921,6 +921,7 @@ fn v3_ump_signal_enforcement() { relay_parent, CoreIndex(0), 1, + 1, validation_data.hash(), pov.hash(), validation_code.hash(), @@ -2681,6 +2682,7 @@ fn pre_validation_v3_scheduling_offset_mismatch() { dummy_hash(), // relay_parent CoreIndex(0), 1, // session_index + 1, // scheduling_session_index dummy_hash(), pov.hash(), validation_code.hash(), @@ -3057,6 +3059,7 @@ fn pre_validation_relay_parent_session_check_v3_ancestor_query() { relay_parent, CoreIndex(1), 1, + 1, dummy_hash(), pov.hash(), validation_code.hash(), diff --git a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs index c46770f617667..68de7ee0a3aba 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs @@ -131,6 +131,7 @@ impl CandidateBuilder { self.relay_parent, CoreIndex(0), 1, + 1, persisted_validation_data.hash(), Hash::repeat_byte(1), Hash::repeat_byte(42), diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index 384cacf575e52..465ad05b5f9e3 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -4190,6 +4190,7 @@ fn v3_sanity_check_uses_scheduling_session_not_relay_parent_session() { relay_parent, core, relay_parent_session, + relay_parent_session, Hash::zero(), Hash::zero(), Hash::zero(), diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index fbda18b2317d5..50b94bad536e1 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -529,8 +529,6 @@ pub struct SubmitCollationParams { pub relay_parent: Hash, /// The collation itself (PoV and commitments) pub collation: Collation, - /// The parent block's head-data. - pub parent_head: HeadData, /// The hash of the validation code the collation was created against. pub validation_code_hash: ValidationCodeHash, /// An optional result sender that should be informed about a successfully seconded collation. @@ -547,6 +545,12 @@ pub struct SubmitCollationParams { /// /// WARNING: Should only be set if the `CandidateReceiptV3` node feature is set. pub scheduling_parent: Option, + /// The session index of the relay parent. Goes into the candidate descriptor. + /// Must be provided by the caller because the relay parent's state may be pruned. + pub session_index: SessionIndex, + /// The persisted validation data for this collation. The `parent_head` field must be set + /// to the correct parent head-data for the parablock being submitted. + pub validation_data: PersistedValidationData, } /// This is the data we keep available for each candidate included in the relay chain. diff --git a/polkadot/primitives/src/v9/mod.rs b/polkadot/primitives/src/v9/mod.rs index 0d177214ed04d..79a94f58b348e 100644 --- a/polkadot/primitives/src/v9/mod.rs +++ b/polkadot/primitives/src/v9/mod.rs @@ -2387,6 +2387,7 @@ impl> CandidateDescriptorV2 { relay_parent: H, core_index: CoreIndex, session_index: SessionIndex, + scheduling_session_index: SessionIndex, persisted_validation_data_hash: Hash, pov_hash: Hash, erasure_root: Hash, @@ -2400,7 +2401,10 @@ impl> CandidateDescriptorV2 { version: 1, core_index: core_index.0 as u16, session_index, - scheduling_session_offset: 0, + scheduling_session_offset: scheduling_session_index + .saturating_sub(session_index) + .try_into() + .expect("scheduling session offset should fit in u8"), reserved1: [0; 24], persisted_validation_data_hash, pov_hash, @@ -3309,7 +3313,8 @@ pub mod tests { Id::from(1u32), Hash::repeat_byte(1), CoreIndex(0), - 1, + 1, // session_index + 1, // scheduling_session_index Hash::repeat_byte(2), Hash::repeat_byte(3), Hash::repeat_byte(4), diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index ff08c4ddaa313..f0de469d3e9f4 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -452,6 +452,7 @@ pub fn dummy_candidate_descriptor_v3 + Copy + Default>( relay_parent, CoreIndex(1), 1, + 1, invalid, invalid, invalid, @@ -650,6 +651,7 @@ pub fn make_valid_candidate_descriptor_v3 + Copy + Default>( relay_parent: H, core_index: CoreIndex, session_index: SessionIndex, + scheduling_session_index: SessionIndex, persisted_validation_data_hash: Hash, pov_hash: Hash, validation_code_hash: impl Into, @@ -664,6 +666,7 @@ pub fn make_valid_candidate_descriptor_v3 + Copy + Default>( relay_parent, core_index, session_index, + scheduling_session_index, persisted_validation_data_hash, pov_hash, erasure_root, diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 9527abcfb5048..9b298fe1460a7 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -691,6 +691,7 @@ impl BenchBuilder { relay_parent, core_idx, self.target_session, + self.target_session, // scheduling_session_index persisted_validation_data_hash, pov_hash, Default::default(), diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 901fc2ceaa465..b4ae7bc30a615 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -322,6 +322,7 @@ impl TestCandidateBuilder { self.relay_parent, core_index, self.descriptor_session_index.unwrap_or(0), + self.descriptor_session_index.unwrap_or(0), // scheduling_session_index self.persisted_validation_data_hash, self.pov_hash, Default::default(), diff --git a/prdoc/pr_11456.prdoc b/prdoc/pr_11456.prdoc new file mode 100644 index 0000000000000..76dac5e972074 --- /dev/null +++ b/prdoc/pr_11456.prdoc @@ -0,0 +1,46 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: 'Collation generation: pass validation data from caller, fetch session from scheduling parent' + +doc: +- audience: Node Dev + description: | + Makes `handle_submit_collation` robust for V3 candidate descriptors where + the relay parent can be old/ancient (pruned state). Instead of fetching + `PersistedValidationData` and `session_index` from the relay parent's + runtime state (which may be unavailable), the caller now provides + `PersistedValidationData` directly in `SubmitCollationParams`, and the + session index is now fetched correctly from the scheduling parent (which + always has available state). + + The `parent_head` field is removed from `SubmitCollationParams` — callers should set + `validation_data.parent_head` directly instead. + + All runtime API calls in the submit collation path now correctly target the scheduling + parent rather than the relay parent. + + `CandidateDescriptorV2::new_v3` now takes an explicit `scheduling_session_index` + parameter instead of hardcoding the offset to 0. + +crates: +- name: polkadot-primitives + bump: major +- name: polkadot-primitives-test-helpers + bump: major +- name: polkadot-node-primitives + bump: major +- name: polkadot-node-collation-generation + bump: patch +- name: polkadot-node-core-backing + bump: patch +- name: polkadot-node-core-candidate-validation + bump: patch +- name: polkadot-node-core-prospective-parachains + bump: patch +- name: polkadot-collator-protocol + bump: patch +- name: polkadot-runtime-parachains + bump: patch +- name: cumulus-client-consensus-aura + bump: patch