From a2b64706071cd566ac00456fd0b3761dca62a6f8 Mon Sep 17 00:00:00 2001
From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com>
Date: Fri, 1 Sep 2023 20:07:32 +0200
Subject: [PATCH] Use cached session index to obtain executor params (#1190)

* Import changes from archieved repo

* Revert erroneous changes

* Fix more tests

* Resolve discussions

* Fix MORE tests

* approval-voting: launch_approval better interface (#1355)

---------

Co-authored-by: Javier Viola <javier@parity.io>
Co-authored-by: ordian <noreply@reusable.software>
Co-authored-by: ordian <write@reusable.software>
---
 .../node/core/approval-voting/src/import.rs   |  60 +++-
 polkadot/node/core/approval-voting/src/lib.rs |  58 ++-
 .../node/core/approval-voting/src/tests.rs    |  15 +-
 polkadot/node/core/backing/src/lib.rs         |  18 +-
 polkadot/node/core/backing/src/tests/mod.rs   | 258 +++++++++++++-
 .../src/tests/prospective_parachains.rs       |  35 +-
 .../node/core/candidate-validation/src/lib.rs |  39 +-
 .../core/candidate-validation/src/tests.rs    | 336 +++++++-----------
 .../core/dispute-coordinator/src/import.rs    |  22 +-
 .../dispute-coordinator/src/initialized.rs    |   1 +
 .../node/core/dispute-coordinator/src/lib.rs  |   1 +
 .../src/participation/mod.rs                  |   1 +
 .../src/participation/queues/mod.rs           |  29 +-
 .../src/participation/queues/tests.rs         |   3 +-
 .../src/participation/tests.rs                |  11 +-
 .../core/dispute-coordinator/src/tests.rs     |  47 ++-
 polkadot/node/core/pvf/tests/it/main.rs       |   2 +-
 polkadot/node/malus/src/variants/common.rs    |  10 +
 .../src/pov_requester/mod.rs                  |   8 +-
 .../src/requester/tests.rs                    |   8 +-
 .../src/tests/state.rs                        |   8 +-
 .../src/collator_side/tests/mod.rs            |  14 +-
 .../dispute-distribution/src/tests/mod.rs     |  43 ++-
 .../src/legacy_v1/tests.rs                    |  69 +++-
 .../node/overseer/examples/minimal-example.rs |   1 +
 polkadot/node/overseer/src/tests.rs           |   2 +
 polkadot/node/subsystem-types/src/messages.rs |   2 +
 .../node/subsystem-util/src/runtime/error.rs  |   4 +
 .../node/subsystem-util/src/runtime/mod.rs    |  25 +-
 29 files changed, 809 insertions(+), 321 deletions(-)

diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs
index 6f376fc6fcc..df712fc45a5 100644
--- a/polkadot/node/core/approval-voting/src/import.rs
+++ b/polkadot/node/core/approval-voting/src/import.rs
@@ -598,7 +598,9 @@ pub(crate) mod tests {
 	use polkadot_node_subsystem::messages::{AllMessages, ApprovalVotingMessage};
 	use polkadot_node_subsystem_test_helpers::make_subsystem_context;
 	use polkadot_node_subsystem_util::database::Database;
-	use polkadot_primitives::{Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex};
+	use polkadot_primitives::{
+		ExecutorParams, Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex,
+	};
 	pub(crate) use sp_consensus_babe::{
 		digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest},
 		AllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch,
@@ -835,6 +837,20 @@ pub(crate) mod tests {
 					si_tx.send(Ok(Some(session_info.clone()))).unwrap();
 				}
 			);
+
+			assert_matches!(
+				handle.recv().await,
+				AllMessages::RuntimeApi(
+					RuntimeApiMessage::Request(
+						req_block_hash,
+						RuntimeApiRequest::SessionExecutorParams(idx, si_tx),
+					)
+				) => {
+					assert_eq!(session, idx);
+					assert_eq!(req_block_hash, hash);
+					si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				}
+			);
 		});
 
 		futures::executor::block_on(futures::future::join(test_fut, aux_fut));
@@ -952,6 +968,20 @@ pub(crate) mod tests {
 					si_tx.send(Ok(Some(session_info.clone()))).unwrap();
 				}
 			);
+
+			assert_matches!(
+				handle.recv().await,
+				AllMessages::RuntimeApi(
+					RuntimeApiMessage::Request(
+						req_block_hash,
+						RuntimeApiRequest::SessionExecutorParams(idx, si_tx),
+					)
+				) => {
+					assert_eq!(session, idx);
+					assert_eq!(req_block_hash, hash);
+					si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				}
+			);
 		});
 
 		futures::executor::block_on(futures::future::join(test_fut, aux_fut));
@@ -1172,6 +1202,20 @@ pub(crate) mod tests {
 					si_tx.send(Ok(Some(session_info.clone()))).unwrap();
 				}
 			);
+
+			assert_matches!(
+				handle.recv().await,
+				AllMessages::RuntimeApi(
+					RuntimeApiMessage::Request(
+						req_block_hash,
+						RuntimeApiRequest::SessionExecutorParams(idx, si_tx),
+					)
+				) => {
+					assert_eq!(session, idx);
+					assert_eq!(req_block_hash, hash);
+					si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				}
+			);
 		});
 
 		futures::executor::block_on(futures::future::join(test_fut, aux_fut));
@@ -1374,6 +1418,20 @@ pub(crate) mod tests {
 				}
 			);
 
+			assert_matches!(
+				handle.recv().await,
+				AllMessages::RuntimeApi(
+					RuntimeApiMessage::Request(
+						req_block_hash,
+						RuntimeApiRequest::SessionExecutorParams(idx, si_tx),
+					)
+				) => {
+					assert_eq!(session, idx);
+					assert_eq!(req_block_hash, hash);
+					si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				}
+			);
+
 			assert_matches!(
 				handle.recv().await,
 				AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks(
diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs
index e99572b31c4..0087f8e1435 100644
--- a/polkadot/node/core/approval-voting/src/lib.rs
+++ b/polkadot/node/core/approval-voting/src/lib.rs
@@ -45,13 +45,13 @@ use polkadot_node_subsystem_util::{
 	self,
 	database::Database,
 	metrics::{self, prometheus},
-	runtime::{Config as RuntimeInfoConfig, RuntimeInfo},
+	runtime::{Config as RuntimeInfoConfig, ExtendedSessionInfo, RuntimeInfo},
 	TimeoutExt,
 };
 use polkadot_primitives::{
 	ApprovalVote, BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, DisputeStatement,
-	GroupIndex, Hash, PvfExecTimeoutKind, SessionIndex, SessionInfo, ValidDisputeStatementKind,
-	ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature,
+	ExecutorParams, GroupIndex, Hash, PvfExecTimeoutKind, SessionIndex, SessionInfo,
+	ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature,
 };
 use sc_keystore::LocalKeystore;
 use sp_application_crypto::Pair;
@@ -643,12 +643,12 @@ impl CurrentlyCheckingSet {
 	}
 }
 
-async fn get_session_info<'a, Sender>(
+async fn get_extended_session_info<'a, Sender>(
 	runtime_info: &'a mut RuntimeInfo,
 	sender: &mut Sender,
 	relay_parent: Hash,
 	session_index: SessionIndex,
-) -> Option<&'a SessionInfo>
+) -> Option<&'a ExtendedSessionInfo>
 where
 	Sender: SubsystemSender<RuntimeApiMessage>,
 {
@@ -656,19 +656,33 @@ where
 		.get_session_info_by_index(sender, relay_parent, session_index)
 		.await
 	{
-		Ok(extended_info) => Some(&extended_info.session_info),
+		Ok(extended_info) => Some(&extended_info),
 		Err(_) => {
 			gum::debug!(
 				target: LOG_TARGET,
 				session = session_index,
 				?relay_parent,
-				"Can't obtain SessionInfo"
+				"Can't obtain SessionInfo or ExecutorParams"
 			);
 			None
 		},
 	}
 }
 
+async fn get_session_info<'a, Sender>(
+	runtime_info: &'a mut RuntimeInfo,
+	sender: &mut Sender,
+	relay_parent: Hash,
+	session_index: SessionIndex,
+) -> Option<&'a SessionInfo>
+where
+	Sender: SubsystemSender<RuntimeApiMessage>,
+{
+	get_extended_session_info(runtime_info, sender, relay_parent, session_index)
+		.await
+		.map(|extended_info| &extended_info.session_info)
+}
+
 struct State {
 	keystore: Arc<LocalKeystore>,
 	slot_duration_millis: u64,
@@ -746,6 +760,7 @@ enum Action {
 		relay_block_hash: Hash,
 		candidate_index: CandidateIndex,
 		session: SessionIndex,
+		executor_params: ExecutorParams,
 		candidate: CandidateReceipt,
 		backing_group: GroupIndex,
 	},
@@ -968,6 +983,7 @@ async fn handle_actions<Context>(
 				relay_block_hash,
 				candidate_index,
 				session,
+				executor_params,
 				candidate,
 				backing_group,
 			} => {
@@ -1008,6 +1024,7 @@ async fn handle_actions<Context>(
 					},
 					None => {
 						let ctx = &mut *ctx;
+
 						currently_checking_set
 							.insert_relay_block_hash(
 								candidate_hash,
@@ -1022,6 +1039,7 @@ async fn handle_actions<Context>(
 										validator_index,
 										block_hash,
 										backing_group,
+										executor_params,
 										&launch_approval_span,
 									)
 									.await
@@ -2328,17 +2346,18 @@ async fn process_wakeup<Context>(
 		_ => return Ok(Vec::new()),
 	};
 
-	let session_info = match get_session_info(
-		session_info_provider,
-		ctx.sender(),
-		block_entry.parent_hash(),
-		block_entry.session(),
-	)
-	.await
-	{
-		Some(i) => i,
-		None => return Ok(Vec::new()),
-	};
+	let ExtendedSessionInfo { ref session_info, ref executor_params, .. } =
+		match get_extended_session_info(
+			session_info_provider,
+			ctx.sender(),
+			block_entry.parent_hash(),
+			block_entry.session(),
+		)
+		.await
+		{
+			Some(i) => i,
+			None => return Ok(Vec::new()),
+		};
 
 	let block_tick = slot_number_to_tick(state.slot_duration_millis, block_entry.slot());
 	let no_show_duration = slot_number_to_tick(
@@ -2425,6 +2444,7 @@ async fn process_wakeup<Context>(
 				relay_block_hash: relay_block,
 				candidate_index: i as _,
 				session: block_entry.session(),
+				executor_params: executor_params.clone(),
 				candidate: candidate_receipt,
 				backing_group,
 			});
@@ -2466,6 +2486,7 @@ async fn launch_approval<Context>(
 	validator_index: ValidatorIndex,
 	block_hash: Hash,
 	backing_group: GroupIndex,
+	executor_params: ExecutorParams,
 	span: &jaeger::Span,
 ) -> SubsystemResult<RemoteHandle<ApprovalState>> {
 	let (a_tx, a_rx) = oneshot::channel();
@@ -2611,6 +2632,7 @@ async fn launch_approval<Context>(
 				validation_code,
 				candidate.clone(),
 				available_data.pov,
+				executor_params,
 				PvfExecTimeoutKind::Approval,
 				val_tx,
 			))
diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs
index f58e60c6a48..3c7b74b26fb 100644
--- a/polkadot/node/core/approval-voting/src/tests.rs
+++ b/polkadot/node/core/approval-voting/src/tests.rs
@@ -910,6 +910,19 @@ async fn import_block(
 					si_tx.send(Ok(Some(session_info.clone()))).unwrap();
 				}
 			);
+			assert_matches!(
+				overseer_recv(overseer).await,
+				AllMessages::RuntimeApi(
+					RuntimeApiMessage::Request(
+						req_block_hash,
+						RuntimeApiRequest::SessionExecutorParams(_, si_tx),
+					)
+				) => {
+					// Make sure all SessionExecutorParams calls are not made for the leaf (but for its relay parent)
+					assert_ne!(req_block_hash, hashes[(number-1) as usize].0);
+					si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				}
+			);
 		}
 
 		assert_matches!(
@@ -2376,7 +2389,7 @@ async fn handle_double_assignment_import(
 
 	assert_matches!(
 		overseer_recv(virtual_overseer).await,
-		AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx)) if timeout == PvfExecTimeoutKind::Approval => {
+		AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx)) if timeout == PvfExecTimeoutKind::Approval => {
 			tx.send(Ok(ValidationResult::Valid(Default::default(), Default::default())))
 				.unwrap();
 		}
diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs
index a75571da76d..97efb3ba808 100644
--- a/polkadot/node/core/backing/src/lib.rs
+++ b/polkadot/node/core/backing/src/lib.rs
@@ -96,8 +96,8 @@ use polkadot_node_subsystem::{
 use polkadot_node_subsystem_util::{
 	self as util,
 	backing_implicit_view::{FetchError as ImplicitViewFetchError, View as ImplicitView},
-	request_from_runtime, request_session_index_for_child, request_validator_groups,
-	request_validators,
+	executor_params_at_relay_parent, request_from_runtime, request_session_index_for_child,
+	request_validator_groups, request_validators,
 	runtime::{
 		self, prospective_parachains_mode, request_min_backing_votes, ProspectiveParachainsMode,
 	},
@@ -105,9 +105,9 @@ use polkadot_node_subsystem_util::{
 };
 use polkadot_primitives::{
 	BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt,
-	CommittedCandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, PersistedValidationData,
-	PvfExecTimeoutKind, SigningContext, ValidationCode, ValidatorId, ValidatorIndex,
-	ValidatorSignature, ValidityAttestation,
+	CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, Hash, Id as ParaId,
+	PersistedValidationData, PvfExecTimeoutKind, SigningContext, ValidationCode, ValidatorId,
+	ValidatorIndex, ValidatorSignature, ValidityAttestation,
 };
 use sp_keystore::KeystorePtr;
 use statement_table::{
@@ -555,6 +555,7 @@ async fn request_candidate_validation(
 	code: ValidationCode,
 	candidate_receipt: CandidateReceipt,
 	pov: Arc<PoV>,
+	executor_params: ExecutorParams,
 ) -> Result<ValidationResult, Error> {
 	let (tx, rx) = oneshot::channel();
 
@@ -564,6 +565,7 @@ async fn request_candidate_validation(
 			code,
 			candidate_receipt,
 			pov,
+			executor_params,
 			PvfExecTimeoutKind::Backing,
 			tx,
 		))
@@ -630,6 +632,11 @@ async fn validate_and_make_available(
 		}
 	};
 
+	let executor_params = match executor_params_at_relay_parent(relay_parent, &mut sender).await {
+		Ok(ep) => ep,
+		Err(e) => return Err(Error::UtilError(e)),
+	};
+
 	let pov = match pov {
 		PoVData::Ready(pov) => pov,
 		PoVData::FetchFromValidator { from_validator, candidate_hash, pov_hash } =>
@@ -665,6 +672,7 @@ async fn validate_and_make_available(
 			validation_code,
 			candidate.clone(),
 			pov.clone(),
+			executor_params,
 		)
 		.await?
 	};
diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs
index 06baebc98e6..f5ea827d254 100644
--- a/polkadot/node/core/backing/src/tests/mod.rs
+++ b/polkadot/node/core/backing/src/tests/mod.rs
@@ -348,6 +348,24 @@ fn backing_second_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::CandidateValidation(
@@ -356,6 +374,7 @@ fn backing_second_works() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -494,6 +513,24 @@ fn backing_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		// Sending a `Statement::Seconded` for our assignment will start
 		// validation process. The first thing requested is the PoV.
 		assert_matches!(
@@ -519,6 +556,7 @@ fn backing_works() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -678,6 +716,24 @@ fn backing_works_while_validation_ongoing() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		// Sending a `Statement::Seconded` for our assignment will start
 		// validation process. The first thing requested is PoV from the
 		// `PoVDistribution`.
@@ -704,6 +760,7 @@ fn backing_works_while_validation_ongoing() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -850,6 +907,24 @@ fn backing_misbehavior_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::AvailabilityDistribution(
@@ -871,6 +946,7 @@ fn backing_misbehavior_works() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -1036,6 +1112,24 @@ fn backing_dont_second_invalid() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::CandidateValidation(
@@ -1044,6 +1138,7 @@ fn backing_dont_second_invalid() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -1082,6 +1177,24 @@ fn backing_dont_second_invalid() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::CandidateValidation(
@@ -1090,6 +1203,7 @@ fn backing_dont_second_invalid() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -1200,6 +1314,24 @@ fn backing_second_after_first_fails_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		// Subsystem requests PoV and requests validation.
 		assert_matches!(
 			virtual_overseer.recv().await,
@@ -1223,6 +1355,7 @@ fn backing_second_after_first_fails_works() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -1289,6 +1422,24 @@ fn backing_second_after_first_fails_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::CandidateValidation(
@@ -1357,6 +1508,24 @@ fn backing_works_after_failed_validation() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		// Subsystem requests PoV and requests validation.
 		assert_matches!(
 			virtual_overseer.recv().await,
@@ -1380,6 +1549,7 @@ fn backing_works_after_failed_validation() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -1566,6 +1736,24 @@ fn retry_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		// Subsystem requests PoV and requests validation.
 		// We cancel - should mean retry on next backing statement.
 		assert_matches!(
@@ -1586,7 +1774,7 @@ fn retry_works() {
 		virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await;
 
 		// Not deterministic which message comes first:
-		for _ in 0u32..3 {
+		for _ in 0u32..5 {
 			match virtual_overseer.recv().await {
 				AllMessages::Provisioner(ProvisionerMessage::ProvisionableData(
 					_,
@@ -1605,6 +1793,18 @@ fn retry_works() {
 				)) if hash == validation_code.hash() => {
 					tx.send(Ok(Some(validation_code.clone()))).unwrap();
 				},
+				AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_,
+					RuntimeApiRequest::SessionIndexForChild(tx),
+				)) => {
+					tx.send(Ok(1u32.into())).unwrap();
+				},
+				AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_,
+					RuntimeApiRequest::SessionExecutorParams(sess_idx, tx),
+				)) if sess_idx == 1 => {
+					tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				},
 				msg => {
 					assert!(false, "Unexpected message: {:?}", msg);
 				},
@@ -1624,6 +1824,24 @@ fn retry_works() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::AvailabilityDistribution(
@@ -1647,6 +1865,7 @@ fn retry_works() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					..
 				),
@@ -1821,6 +2040,24 @@ fn cannot_second_multiple_candidates_per_parent() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::CandidateValidation(
@@ -1829,6 +2066,7 @@ fn cannot_second_multiple_candidates_per_parent() {
 					_validation_code,
 					candidate_receipt,
 					_pov,
+					_,
 					timeout,
 					tx,
 				),
@@ -1907,6 +2145,24 @@ fn cannot_second_multiple_candidates_per_parent() {
 			}
 		);
 
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+			) => {
+				tx.send(Ok(1u32.into())).unwrap();
+			}
+		);
+
+		assert_matches!(
+			virtual_overseer.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+			) if sess_idx == 1 => {
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			}
+		);
+
 		assert_matches!(
 			virtual_overseer.recv().await,
 			AllMessages::CandidateValidation(
diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs
index 7a30886736d..07e2a3a89bb 100644
--- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs
+++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs
@@ -217,6 +217,24 @@ async fn assert_validate_seconded_candidate(
 		}
 	);
 
+	assert_matches!(
+		virtual_overseer.recv().await,
+		AllMessages::RuntimeApi(
+			RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
+		) => {
+			tx.send(Ok(1u32.into())).unwrap();
+		}
+	);
+
+	assert_matches!(
+		virtual_overseer.recv().await,
+		AllMessages::RuntimeApi(
+			RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx))
+		) if sess_idx == 1 => {
+			tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+		}
+	);
+
 	if fetch_pov {
 		assert_matches!(
 			virtual_overseer.recv().await,
@@ -239,6 +257,7 @@ async fn assert_validate_seconded_candidate(
 			_validation_code,
 			candidate_receipt,
 			_pov,
+			_,
 			timeout,
 			tx,
 		)) if &_pvd == pvd &&
@@ -1339,7 +1358,7 @@ fn concurrent_dependent_candidates() {
 					tx.send(pov.clone()).unwrap();
 				},
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::ValidateFromExhaustive(.., candidate, _, _, tx),
+					CandidateValidationMessage::ValidateFromExhaustive(.., candidate, _, _, _, tx),
 				) => {
 					let candidate_hash = candidate.hash();
 					let (head_data, pvd) = if candidate_hash == candidate_a_hash {
@@ -1396,6 +1415,20 @@ fn concurrent_dependent_candidates() {
 						break
 					}
 				},
+				AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_,
+					RuntimeApiRequest::SessionIndexForChild(tx),
+				)) => {
+					tx.send(Ok(1u32.into())).unwrap();
+				},
+				AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_,
+					RuntimeApiRequest::SessionExecutorParams(sess_idx, tx),
+				)) => {
+					assert_eq!(sess_idx, 1);
+					tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+				},
+
 				_ => panic!("unexpected message received from overseer: {:?}", msg),
 			}
 		}
diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs
index 0da2853340d..3281fcc59a1 100644
--- a/polkadot/node/core/candidate-validation/src/lib.rs
+++ b/polkadot/node/core/candidate-validation/src/lib.rs
@@ -164,6 +164,7 @@ async fn run<Context>(
 				CandidateValidationMessage::ValidateFromChainState(
 					candidate_receipt,
 					pov,
+					executor_params,
 					timeout,
 					response_sender,
 				) => {
@@ -179,6 +180,7 @@ async fn run<Context>(
 								validation_host,
 								candidate_receipt,
 								pov,
+								executor_params,
 								timeout,
 								&metrics,
 							)
@@ -196,23 +198,23 @@ async fn run<Context>(
 					validation_code,
 					candidate_receipt,
 					pov,
+					executor_params,
 					timeout,
 					response_sender,
 				) => {
 					let bg = {
-						let mut sender = ctx.sender().clone();
 						let metrics = metrics.clone();
 						let validation_host = validation_host.clone();
 
 						async move {
 							let _timer = metrics.time_validate_from_exhaustive();
 							let res = validate_candidate_exhaustive(
-								&mut sender,
 								validation_host,
 								persisted_validation_data,
 								validation_code,
 								candidate_receipt,
 								pov,
+								executor_params,
 								timeout,
 								&metrics,
 							)
@@ -497,6 +499,7 @@ async fn validate_from_chain_state<Sender>(
 	validation_host: ValidationHost,
 	candidate_receipt: CandidateReceipt,
 	pov: Arc<PoV>,
+	executor_params: ExecutorParams,
 	exec_timeout_kind: PvfExecTimeoutKind,
 	metrics: &Metrics,
 ) -> Result<ValidationResult, ValidationFailed>
@@ -511,12 +514,12 @@ where
 		};
 
 	let validation_result = validate_candidate_exhaustive(
-		sender,
 		validation_host,
 		validation_data,
 		validation_code,
 		candidate_receipt.clone(),
 		pov,
+		executor_params,
 		exec_timeout_kind,
 		metrics,
 	)
@@ -546,19 +549,16 @@ where
 	validation_result
 }
 
-async fn validate_candidate_exhaustive<Sender>(
-	sender: &mut Sender,
+async fn validate_candidate_exhaustive(
 	mut validation_backend: impl ValidationBackend + Send,
 	persisted_validation_data: PersistedValidationData,
 	validation_code: ValidationCode,
 	candidate_receipt: CandidateReceipt,
 	pov: Arc<PoV>,
+	executor_params: ExecutorParams,
 	exec_timeout_kind: PvfExecTimeoutKind,
 	metrics: &Metrics,
-) -> Result<ValidationResult, ValidationFailed>
-where
-	Sender: SubsystemSender<RuntimeApiMessage>,
-{
+) -> Result<ValidationResult, ValidationFailed> {
 	let _timer = metrics.time_validate_candidate_exhaustive();
 
 	let validation_code_hash = validation_code.hash();
@@ -615,27 +615,6 @@ where
 		relay_parent_storage_root: persisted_validation_data.relay_parent_storage_root,
 	};
 
-	let executor_params = if let Ok(executor_params) =
-		executor_params_at_relay_parent(candidate_receipt.descriptor.relay_parent, sender).await
-	{
-		gum::debug!(
-			target: LOG_TARGET,
-			?validation_code_hash,
-			?para_id,
-			"Acquired executor params for the session: {:?}",
-			executor_params,
-		);
-		executor_params
-	} else {
-		gum::warn!(
-			target: LOG_TARGET,
-			?validation_code_hash,
-			?para_id,
-			"Failed to acquire executor params for the session",
-		);
-		return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent))
-	};
-
 	let result = validation_backend
 		.validate_candidate_with_retry(
 			raw_validation_code.to_vec(),
diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs
index 2dcead4db46..af530a20c4e 100644
--- a/polkadot/node/core/candidate-validation/src/tests.rs
+++ b/polkadot/node/core/candidate-validation/src/tests.rs
@@ -26,37 +26,6 @@ use polkadot_primitives::{HeadData, Id as ParaId, UpwardMessage};
 use sp_core::testing::TaskExecutor;
 use sp_keyring::Sr25519Keyring;
 
-fn test_with_executor_params<T: futures::Future<Output = R>, R, M>(
-	mut ctx_handle: test_helpers::TestSubsystemContextHandle<M>,
-	test: impl FnOnce() -> T,
-) -> R {
-	let test_fut = test();
-
-	let overseer = async move {
-		assert_matches!(
-			ctx_handle.recv().await,
-			AllMessages::RuntimeApi(
-				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx))
-			) => {
-				tx.send(Ok(1u32.into())).unwrap();
-			}
-		);
-		assert_matches!(
-			ctx_handle.recv().await,
-			AllMessages::RuntimeApi(
-				RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(_, tx))
-			) => {
-				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
-			}
-		);
-	};
-
-	futures::pin_mut!(test_fut);
-	futures::pin_mut!(overseer);
-	let v = executor::block_on(future::join(test_fut, overseer));
-	v.0
-}
-
 #[test]
 fn correctly_checks_included_assumption() {
 	let validation_data: PersistedValidationData = Default::default();
@@ -460,23 +429,16 @@ fn candidate_validation_ok_is_ok() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
-			validation_data.clone(),
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	})
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
+		validation_data.clone(),
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	))
 	.unwrap();
 
 	assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
@@ -517,27 +479,21 @@ fn candidate_validation_bad_return_is_invalid() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result(Err(
-				ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
-			)),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	});
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result(Err(
+			ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
+		)),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	))
+	.unwrap();
 
-	assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)));
+	assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::Timeout));
 }
 
 // Test that we vote valid if we get `AmbiguousWorkerDeath`, retry, and then succeed.
@@ -588,26 +544,19 @@ fn candidate_validation_one_ambiguous_error_is_valid() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result_list(vec![
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
-				Ok(validation_result),
-			]),
-			validation_data.clone(),
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	})
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result_list(vec![
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
+			Ok(validation_result),
+		]),
+		validation_data.clone(),
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	))
 	.unwrap();
 
 	assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
@@ -648,26 +597,19 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result_list(vec![
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
-			]),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	})
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result_list(vec![
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
+		]),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	))
 	.unwrap();
 
 	assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::ExecutionError(_)));
@@ -702,29 +644,22 @@ fn candidate_validation_retry_internal_errors() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result_list(vec![
-				Err(InternalValidationError::HostCommunication("foo".into()).into()),
-				// Throw an AWD error, we should still retry again.
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
-				// Throw another internal error.
-				Err(InternalValidationError::HostCommunication("bar".into()).into()),
-			]),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	});
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result_list(vec![
+			Err(InternalValidationError::HostCommunication("foo".into()).into()),
+			// Throw an AWD error, we should still retry again.
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
+			// Throw another internal error.
+			Err(InternalValidationError::HostCommunication("bar".into()).into()),
+		]),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	));
 
 	assert_matches!(v, Err(ValidationFailed(s)) if s.contains("bar"));
 }
@@ -758,29 +693,22 @@ fn candidate_validation_retry_panic_errors() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result_list(vec![
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("foo".into()))),
-				// Throw an AWD error, we should still retry again.
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
-				// Throw another panic error.
-				Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("bar".into()))),
-			]),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	});
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result_list(vec![
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("foo".into()))),
+			// Throw an AWD error, we should still retry again.
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::AmbiguousWorkerDeath)),
+			// Throw another panic error.
+			Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Panic("bar".into()))),
+		]),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	));
 
 	assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(s))) if s == "bar".to_string());
 }
@@ -813,25 +741,18 @@ fn candidate_validation_timeout_is_internal_error() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result(Err(
-				ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
-			)),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	});
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result(Err(
+			ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
+		)),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	));
 
 	assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)));
 }
@@ -867,23 +788,16 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() {
 		hrmp_watermark: 12345,
 	};
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let result = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	})
+	let result = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	))
 	.unwrap();
 
 	// Ensure `post validation` check on the commitments hash works as expected.
@@ -919,11 +833,9 @@ fn candidate_validation_code_mismatch_is_invalid() {
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
 	let pool = TaskExecutor::new();
-	let (mut ctx, _ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
+	let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
 
 	let v = executor::block_on(validate_candidate_exhaustive(
-		ctx.sender(),
 		MockValidateCandidateBackend::with_hardcoded_result(Err(
 			ValidationError::InvalidCandidate(WasmInvalidCandidate::HardTimeout),
 		)),
@@ -931,6 +843,7 @@ fn candidate_validation_code_mismatch_is_invalid() {
 		validation_code,
 		candidate_receipt,
 		Arc::new(pov),
+		ExecutorParams::default(),
 		PvfExecTimeoutKind::Backing,
 		&Default::default(),
 	))
@@ -981,23 +894,16 @@ fn compressed_code_works() {
 
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() };
 
-	let pool = TaskExecutor::new();
-	let (mut ctx, ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
-	let metrics = Metrics::default();
-
-	let v = test_with_executor_params(ctx_handle, || {
-		validate_candidate_exhaustive(
-			ctx.sender(),
-			MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
-			validation_data,
-			validation_code,
-			candidate_receipt,
-			Arc::new(pov),
-			PvfExecTimeoutKind::Backing,
-			&metrics,
-		)
-	});
+	let v = executor::block_on(validate_candidate_exhaustive(
+		MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
+		validation_data,
+		validation_code,
+		candidate_receipt,
+		Arc::new(pov),
+		ExecutorParams::default(),
+		PvfExecTimeoutKind::Backing,
+		&Default::default(),
+	));
 
 	assert_matches!(v, Ok(ValidationResult::Valid(_, _)));
 }
@@ -1037,16 +943,15 @@ fn code_decompression_failure_is_error() {
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
 	let pool = TaskExecutor::new();
-	let (mut ctx, _ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
+	let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
 
 	let v = executor::block_on(validate_candidate_exhaustive(
-		ctx.sender(),
 		MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
 		validation_data,
 		validation_code,
 		candidate_receipt,
 		Arc::new(pov),
+		ExecutorParams::default(),
 		PvfExecTimeoutKind::Backing,
 		&Default::default(),
 	));
@@ -1090,16 +995,15 @@ fn pov_decompression_failure_is_invalid() {
 	let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() };
 
 	let pool = TaskExecutor::new();
-	let (mut ctx, _ctx_handle) =
-		test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
+	let (_ctx, _ctx_handle) = test_helpers::make_subsystem_context::<AllMessages, _>(pool.clone());
 
 	let v = executor::block_on(validate_candidate_exhaustive(
-		ctx.sender(),
 		MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)),
 		validation_data,
 		validation_code,
 		candidate_receipt,
 		Arc::new(pov),
+		ExecutorParams::default(),
 		PvfExecTimeoutKind::Backing,
 		&Default::default(),
 	));
diff --git a/polkadot/node/core/dispute-coordinator/src/import.rs b/polkadot/node/core/dispute-coordinator/src/import.rs
index 0da3723ebf2..cf51ae4d365 100644
--- a/polkadot/node/core/dispute-coordinator/src/import.rs
+++ b/polkadot/node/core/dispute-coordinator/src/import.rs
@@ -34,8 +34,9 @@ use polkadot_node_primitives::{
 use polkadot_node_subsystem::overseer;
 use polkadot_node_subsystem_util::runtime::RuntimeInfo;
 use polkadot_primitives::{
-	CandidateReceipt, DisputeStatement, Hash, IndexedVec, SessionIndex, SessionInfo,
-	ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature,
+	CandidateReceipt, DisputeStatement, ExecutorParams, Hash, IndexedVec, SessionIndex,
+	SessionInfo, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair,
+	ValidatorSignature,
 };
 use sc_keystore::LocalKeystore;
 
@@ -47,6 +48,8 @@ pub struct CandidateEnvironment<'a> {
 	session_index: SessionIndex,
 	/// Session for above index.
 	session: &'a SessionInfo,
+	/// Executor parameters for the session.
+	executor_params: &'a ExecutorParams,
 	/// Validator indices controlled by this node.
 	controlled_indices: HashSet<ValidatorIndex>,
 }
@@ -63,17 +66,17 @@ impl<'a> CandidateEnvironment<'a> {
 		session_index: SessionIndex,
 		relay_parent: Hash,
 	) -> Option<CandidateEnvironment<'a>> {
-		let session_info = match runtime_info
+		let (session, executor_params) = match runtime_info
 			.get_session_info_by_index(ctx.sender(), relay_parent, session_index)
 			.await
 		{
-			Ok(extended_session_info) => &extended_session_info.session_info,
+			Ok(extended_session_info) =>
+				(&extended_session_info.session_info, &extended_session_info.executor_params),
 			Err(_) => return None,
 		};
 
-		let controlled_indices =
-			find_controlled_validator_indices(keystore, &session_info.validators);
-		Some(Self { session_index, session: session_info, controlled_indices })
+		let controlled_indices = find_controlled_validator_indices(keystore, &session.validators);
+		Some(Self { session_index, session, executor_params, controlled_indices })
 	}
 
 	/// Validators in the candidate's session.
@@ -86,6 +89,11 @@ impl<'a> CandidateEnvironment<'a> {
 		&self.session
 	}
 
+	/// Executor parameters for the candidate's session
+	pub fn executor_params(&self) -> &ExecutorParams {
+		&self.executor_params
+	}
+
 	/// Retrieve `SessionIndex` for this environment.
 	pub fn session_index(&self) -> SessionIndex {
 		self.session_index
diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs
index c1d02ef976c..dd7aef19f6e 100644
--- a/polkadot/node/core/dispute-coordinator/src/initialized.rs
+++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs
@@ -1160,6 +1160,7 @@ impl Initialized {
 					ParticipationRequest::new(
 						new_state.candidate_receipt().clone(),
 						session,
+						env.executor_params().clone(),
 						request_timer,
 					),
 				)
diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs
index f7e3d0657f2..3f0fd401314 100644
--- a/polkadot/node/core/dispute-coordinator/src/lib.rs
+++ b/polkadot/node/core/dispute-coordinator/src/lib.rs
@@ -398,6 +398,7 @@ impl DisputeCoordinatorSubsystem {
 						ParticipationRequest::new(
 							vote_state.votes().candidate_receipt.clone(),
 							session,
+							env.executor_params().clone(),
 							request_timer,
 						),
 					));
diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs
index 25b7352807f..5a3c4be90aa 100644
--- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs
+++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs
@@ -366,6 +366,7 @@ async fn participate(
 			validation_code,
 			req.candidate_receipt().clone(),
 			available_data.pov,
+			req.executor_params(),
 			PvfExecTimeoutKind::Approval,
 			validation_tx,
 		))
diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs
index 8a4374999f8..1105135a747 100644
--- a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs
+++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs
@@ -21,7 +21,9 @@ use std::{
 
 use futures::channel::oneshot;
 use polkadot_node_subsystem::{messages::ChainApiMessage, overseer};
-use polkadot_primitives::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex};
+use polkadot_primitives::{
+	BlockNumber, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex,
+};
 
 use crate::{
 	error::{FatalError, FatalResult, Result},
@@ -73,6 +75,7 @@ pub struct ParticipationRequest {
 	candidate_hash: CandidateHash,
 	candidate_receipt: CandidateReceipt,
 	session: SessionIndex,
+	executor_params: ExecutorParams,
 	request_timer: Option<prometheus::HistogramTimer>, // Sends metric data when request is dropped
 }
 
@@ -120,9 +123,16 @@ impl ParticipationRequest {
 	pub fn new(
 		candidate_receipt: CandidateReceipt,
 		session: SessionIndex,
+		executor_params: ExecutorParams,
 		request_timer: Option<prometheus::HistogramTimer>,
 	) -> Self {
-		Self { candidate_hash: candidate_receipt.hash(), candidate_receipt, session, request_timer }
+		Self {
+			candidate_hash: candidate_receipt.hash(),
+			candidate_receipt,
+			session,
+			executor_params,
+			request_timer,
+		}
 	}
 
 	pub fn candidate_receipt(&'_ self) -> &'_ CandidateReceipt {
@@ -134,6 +144,9 @@ impl ParticipationRequest {
 	pub fn session(&self) -> SessionIndex {
 		self.session
 	}
+	pub fn executor_params(&self) -> ExecutorParams {
+		self.executor_params.clone()
+	}
 	pub fn discard_timer(&mut self) {
 		if let Some(timer) = self.request_timer.take() {
 			timer.stop_and_discard();
@@ -150,11 +163,17 @@ impl ParticipationRequest {
 #[cfg(test)]
 impl PartialEq for ParticipationRequest {
 	fn eq(&self, other: &Self) -> bool {
-		let ParticipationRequest { candidate_receipt, candidate_hash, session, request_timer: _ } =
-			self;
+		let ParticipationRequest {
+			candidate_receipt,
+			candidate_hash,
+			session,
+			executor_params,
+			request_timer: _,
+		} = self;
 		candidate_receipt == other.candidate_receipt() &&
 			candidate_hash == other.candidate_hash() &&
-			*session == other.session()
+			*session == other.session() &&
+			executor_params.hash() == other.executor_params.hash()
 	}
 }
 #[cfg(test)]
diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs
index d4f43639ce8..63bfc1d7d02 100644
--- a/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs
+++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs
@@ -27,7 +27,7 @@ fn make_participation_request(hash: Hash) -> ParticipationRequest {
 	// make it differ:
 	receipt.commitments_hash = hash;
 	let request_timer = Metrics::default().time_participation_pipeline();
-	ParticipationRequest::new(receipt, 1, request_timer)
+	ParticipationRequest::new(receipt, 1, Default::default(), request_timer)
 }
 
 /// Make dummy comparator for request, based on the given block number.
@@ -46,6 +46,7 @@ fn clone_request(request: &ParticipationRequest) -> ParticipationRequest {
 		candidate_receipt: request.candidate_receipt.clone(),
 		candidate_hash: request.candidate_hash,
 		session: request.session,
+		executor_params: request.executor_params.clone(),
 		request_timer: None,
 	}
 }
diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs
index 32725a3ac65..a2e8e88cb67 100644
--- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs
+++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs
@@ -73,7 +73,8 @@ async fn participate_with_commitments_hash<Context>(
 	let session = 1;
 
 	let request_timer = participation.metrics.time_participation_pipeline();
-	let req = ParticipationRequest::new(candidate_receipt, session, request_timer);
+	let req =
+		ParticipationRequest::new(candidate_receipt, session, Default::default(), request_timer);
 
 	participation
 		.queue_participation(ctx, ParticipationPriority::BestEffort, req)
@@ -120,7 +121,7 @@ pub async fn participation_full_happy_path(
 	assert_matches!(
 	ctx_handle.recv().await,
 	AllMessages::CandidateValidation(
-		CandidateValidationMessage::ValidateFromExhaustive(_, _, candidate_receipt, _, timeout, tx)
+		CandidateValidationMessage::ValidateFromExhaustive(_, _, candidate_receipt, _, _, timeout, tx)
 		) if timeout == PvfExecTimeoutKind::Approval => {
 			if expected_commitments_hash != candidate_receipt.commitments_hash {
 				tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap();
@@ -455,7 +456,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() {
 		assert_matches!(
 			ctx_handle.recv().await,
 			AllMessages::CandidateValidation(
-				CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx)
+				CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx)
 			) if timeout == PvfExecTimeoutKind::Approval => {
 				tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap();
 			},
@@ -492,7 +493,7 @@ fn cast_invalid_vote_if_commitments_dont_match() {
 		assert_matches!(
 			ctx_handle.recv().await,
 			AllMessages::CandidateValidation(
-				CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx)
+				CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx)
 			) if timeout == PvfExecTimeoutKind::Approval => {
 				tx.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap();
 			},
@@ -529,7 +530,7 @@ fn cast_valid_vote_if_validation_passes() {
 		assert_matches!(
 			ctx_handle.recv().await,
 			AllMessages::CandidateValidation(
-				CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, timeout, tx)
+				CandidateValidationMessage::ValidateFromExhaustive(_, _, _, _, _, timeout, tx)
 			) if timeout == PvfExecTimeoutKind::Approval => {
 				tx.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap();
 			},
diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs
index 75eae8200dc..8d6a2e10396 100644
--- a/polkadot/node/core/dispute-coordinator/src/tests.rs
+++ b/polkadot/node/core/dispute-coordinator/src/tests.rs
@@ -63,9 +63,9 @@ use polkadot_node_subsystem_test_helpers::{
 };
 use polkadot_primitives::{
 	ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
-	CandidateReceipt, CoreIndex, DisputeStatement, GroupIndex, Hash, HeadData, Header, IndexedVec,
-	MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext,
-	ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature,
+	CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, HeadData,
+	Header, IndexedVec, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SessionInfo,
+	SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature,
 };
 
 use crate::{
@@ -347,6 +347,17 @@ impl TestState {
 									let _ = tx.send(Ok(Some(self.session_info())));
 								}
 							);
+							assert_matches!(
+								overseer_recv(virtual_overseer).await,
+								AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+									h,
+									RuntimeApiRequest::SessionExecutorParams(session_index, tx),
+								)) => {
+									assert_eq!(h, block_hash);
+									assert_eq!(session_index, i);
+									let _ = tx.send(Ok(Some(ExecutorParams::default())));
+								}
+							);
 						}
 					}
 
@@ -3482,6 +3493,16 @@ fn session_info_is_requested_only_once() {
 					let _ = tx.send(Ok(Some(test_state.session_info())));
 				}
 			);
+			assert_matches!(
+				virtual_overseer.recv().await,
+				AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+					_,
+					RuntimeApiRequest::SessionExecutorParams(session_index, tx),
+				)) => {
+					assert_eq!(session_index, 2);
+					let _ = tx.send(Ok(Some(ExecutorParams::default())));
+				}
+			);
 			test_state
 		})
 	});
@@ -3532,6 +3553,16 @@ fn session_info_big_jump_works() {
 						let _ = tx.send(Ok(Some(test_state.session_info())));
 					}
 				);
+				assert_matches!(
+					virtual_overseer.recv().await,
+					AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+						_,
+						RuntimeApiRequest::SessionExecutorParams(session_index, tx),
+					)) => {
+						assert_eq!(session_index, expected_idx);
+						let _ = tx.send(Ok(Some(ExecutorParams::default())));
+					}
+				);
 			}
 			test_state
 		})
@@ -3582,6 +3613,16 @@ fn session_info_small_jump_works() {
 						let _ = tx.send(Ok(Some(test_state.session_info())));
 					}
 				);
+				assert_matches!(
+					virtual_overseer.recv().await,
+					AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+						_,
+						RuntimeApiRequest::SessionExecutorParams(session_index, tx),
+					)) => {
+						assert_eq!(session_index, expected_idx);
+						let _ = tx.send(Ok(Some(ExecutorParams::default())));
+					}
+				);
 			}
 			test_state
 		})
diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs
index 8574bc16c5d..12d87ee4426 100644
--- a/polkadot/node/core/pvf/tests/it/main.rs
+++ b/polkadot/node/core/pvf/tests/it/main.rs
@@ -258,7 +258,7 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() {
 #[tokio::test]
 async fn deleting_prepared_artifact_does_not_dispute() {
 	let host = TestHost::new();
-	let cache_dir = host.cache_dir.path().clone();
+	let cache_dir = host.cache_dir.path();
 
 	let result = host
 		.validate_candidate(
diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs
index 475ca8f3145..bc5f6f92aed 100644
--- a/polkadot/node/malus/src/variants/common.rs
+++ b/polkadot/node/malus/src/variants/common.rs
@@ -278,6 +278,7 @@ where
 						validation_code,
 						candidate_receipt,
 						pov,
+						executor_params,
 						timeout,
 						sender,
 					),
@@ -292,6 +293,7 @@ where
 									validation_code,
 									candidate_receipt,
 									pov,
+									executor_params,
 									timeout,
 									sender,
 								),
@@ -329,6 +331,7 @@ where
 										validation_code,
 										candidate_receipt,
 										pov,
+										executor_params,
 										timeout,
 										sender,
 									),
@@ -368,6 +371,7 @@ where
 										validation_code,
 										candidate_receipt,
 										pov,
+										executor_params,
 										timeout,
 										sender,
 									),
@@ -382,6 +386,7 @@ where
 							validation_code,
 							candidate_receipt,
 							pov,
+							executor_params,
 							timeout,
 							sender,
 						),
@@ -394,6 +399,7 @@ where
 					CandidateValidationMessage::ValidateFromChainState(
 						candidate_receipt,
 						pov,
+						executor_params,
 						timeout,
 						response_sender,
 					),
@@ -406,6 +412,7 @@ where
 								msg: CandidateValidationMessage::ValidateFromChainState(
 									candidate_receipt,
 									pov,
+									executor_params,
 									timeout,
 									response_sender,
 								),
@@ -435,6 +442,7 @@ where
 								msg: CandidateValidationMessage::ValidateFromChainState(
 									candidate_receipt,
 									pov,
+									executor_params,
 									timeout,
 									response_sender,
 								),
@@ -468,6 +476,7 @@ where
 									msg: CandidateValidationMessage::ValidateFromChainState(
 										candidate_receipt,
 										pov,
+										executor_params,
 										timeout,
 										response_sender,
 									),
@@ -479,6 +488,7 @@ where
 						msg: CandidateValidationMessage::ValidateFromChainState(
 							candidate_receipt,
 							pov,
+							executor_params,
 							timeout,
 							response_sender,
 						),
diff --git a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs
index 8fc9fa82153..12a97a1fb5a 100644
--- a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs
+++ b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs
@@ -146,7 +146,7 @@ mod tests {
 		AllMessages, AvailabilityDistributionMessage, RuntimeApiMessage, RuntimeApiRequest,
 	};
 	use polkadot_node_subsystem_test_helpers as test_helpers;
-	use polkadot_primitives::{CandidateHash, Hash, ValidatorIndex};
+	use polkadot_primitives::{CandidateHash, ExecutorParams, Hash, ValidatorIndex};
 	use test_helpers::mock::make_ferdie_keystore;
 
 	use super::*;
@@ -208,6 +208,12 @@ mod tests {
 					)) => {
 						tx.send(Ok(Some(make_session_info()))).unwrap();
 					},
+					AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+						_,
+						RuntimeApiRequest::SessionExecutorParams(_, tx),
+					)) => {
+						tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+					},
 					AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendRequests(
 						mut reqs,
 						_,
diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs
index b74a69ea076..5f7e4c36f06 100644
--- a/polkadot/node/network/availability-distribution/src/requester/tests.rs
+++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs
@@ -24,8 +24,8 @@ use polkadot_node_network_protocol::jaeger;
 use polkadot_node_primitives::{BlockData, ErasureChunk, PoV};
 use polkadot_node_subsystem_util::runtime::RuntimeInfo;
 use polkadot_primitives::{
-	BlockNumber, CoreState, GroupIndex, Hash, Id as ParaId, ScheduledCore, SessionIndex,
-	SessionInfo,
+	BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore,
+	SessionIndex, SessionInfo,
 };
 use sp_core::traits::SpawnNamed;
 
@@ -120,6 +120,10 @@ fn spawn_virtual_overseer(
 								tx.send(Ok(Some(test_state.session_info.clone())))
 									.expect("Receiver should be alive.");
 							},
+							RuntimeApiRequest::SessionExecutorParams(_, tx) => {
+								tx.send(Ok(Some(ExecutorParams::default())))
+									.expect("Receiver should be alive.");
+							},
 							RuntimeApiRequest::AvailabilityCores(tx) => {
 								let para_id = ParaId::from(1_u32);
 								let maybe_block_position =
diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs
index 706ec13a3e9..ecde44788c2 100644
--- a/polkadot/node/network/availability-distribution/src/tests/state.rs
+++ b/polkadot/node/network/availability-distribution/src/tests/state.rs
@@ -48,8 +48,8 @@ use polkadot_node_subsystem::{
 };
 use polkadot_node_subsystem_test_helpers as test_helpers;
 use polkadot_primitives::{
-	CandidateHash, CoreState, GroupIndex, Hash, Id as ParaId, ScheduledCore, SessionInfo,
-	ValidatorIndex,
+	CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore,
+	SessionInfo, ValidatorIndex,
 };
 use test_helpers::mock::make_ferdie_keystore;
 
@@ -267,6 +267,10 @@ impl TestState {
 							tx.send(Ok(Some(self.session_info.clone())))
 								.expect("Receiver should be alive.");
 						},
+						RuntimeApiRequest::SessionExecutorParams(_, tx) => {
+							tx.send(Ok(Some(ExecutorParams::default())))
+								.expect("Receiver should be alive.");
+						},
 						RuntimeApiRequest::AvailabilityCores(tx) => {
 							gum::trace!(target: LOG_TARGET, cores= ?self.cores[&hash], hash = ?hash, "Sending out cores for hash");
 							tx.send(Ok(self.cores[&hash].clone()))
diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs
index fae719b2b4a..8b28730c901 100644
--- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs
+++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs
@@ -45,8 +45,8 @@ use polkadot_node_subsystem::{
 use polkadot_node_subsystem_test_helpers as test_helpers;
 use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt};
 use polkadot_primitives::{
-	AuthorityDiscoveryId, CollatorPair, GroupIndex, GroupRotationInfo, IndexedVec, ScheduledCore,
-	SessionIndex, SessionInfo, ValidatorId, ValidatorIndex,
+	AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, GroupRotationInfo, IndexedVec,
+	ScheduledCore, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex,
 };
 use polkadot_primitives_test_helpers::TestCandidateBuilder;
 
@@ -398,6 +398,16 @@ async fn distribute_collation_with_receipt(
 				tx.send(Ok(Some(test_state.session_info.clone()))).unwrap();
 			},
 
+			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+				relay_parent,
+				RuntimeApiRequest::SessionExecutorParams(session_index, tx),
+			)) => {
+				assert_eq!(relay_parent, relay_parent);
+				assert_eq!(session_index, test_state.current_session_index());
+
+				tx.send(Ok(Some(ExecutorParams::default()))).unwrap();
+			},
+
 			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
 				_relay_parent,
 				RuntimeApiRequest::ValidatorGroups(tx),
diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs
index bc8e8e8be16..f53b9c0dd4b 100644
--- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs
+++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs
@@ -57,7 +57,8 @@ use polkadot_node_subsystem_test_helpers::{
 	mock::make_ferdie_keystore, subsystem_test_harness, TestSubsystemContextHandle,
 };
 use polkadot_primitives::{
-	AuthorityDiscoveryId, CandidateHash, CandidateReceipt, Hash, SessionIndex, SessionInfo,
+	AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex,
+	SessionInfo,
 };
 
 use self::mock::{
@@ -635,6 +636,16 @@ async fn nested_network_dispute_request<'a, F, O>(
 			},
 			unexpected => panic!("Unexpected message {:?}", unexpected),
 		}
+		match handle.recv().await {
+			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+				_,
+				RuntimeApiRequest::SessionExecutorParams(_, tx),
+			)) => {
+				tx.send(Ok(Some(ExecutorParams::default())))
+					.expect("Receiver should stay alive.");
+			},
+			unexpected => panic!("Unexpected message {:?}", unexpected),
+		}
 	}
 
 	// Import should get initiated:
@@ -746,15 +757,27 @@ async fn activate_leaf(
 
 	if let Some(session_info) = new_session {
 		assert_matches!(
-		handle.recv().await,
-		AllMessages::RuntimeApi(RuntimeApiMessage::Request(
-			h,
-			RuntimeApiRequest::SessionInfo(session_idx, tx)
-		)) => {
-			assert_eq!(h, activate);
-			assert_eq!(session_index, session_idx);
-			tx.send(Ok(Some(session_info))).expect("Receiver should stay alive.");
-		});
+			handle.recv().await,
+			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+				h,
+				RuntimeApiRequest::SessionInfo(session_idx, tx)
+			)) => {
+				assert_eq!(h, activate);
+				assert_eq!(session_index, session_idx);
+				tx.send(Ok(Some(session_info))).expect("Receiver should stay alive.");
+			}
+		);
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(RuntimeApiMessage::Request(
+				h,
+				RuntimeApiRequest::SessionExecutorParams(session_idx, tx)
+			)) => {
+				assert_eq!(h, activate);
+				assert_eq!(session_index, session_idx);
+				tx.send(Ok(Some(ExecutorParams::default()))).expect("Receiver should stay alive.");
+			}
+		);
 	}
 
 	assert_matches!(
diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs
index a8ce65f2986..63ac1febde5 100644
--- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs
+++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs
@@ -44,7 +44,8 @@ use polkadot_node_subsystem::{
 };
 use polkadot_node_subsystem_test_helpers::mock::make_ferdie_keystore;
 use polkadot_primitives::{
-	GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo, ValidationCode,
+	ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo,
+	ValidationCode,
 };
 use polkadot_primitives_test_helpers::{
 	dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng,
@@ -828,6 +829,17 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() {
 			}
 		);
 
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx))
+			)
+				if r == hash_a && sess_index == session_index
+			=> {
+				let _ = tx.send(Ok(Some(ExecutorParams::default())));
+			}
+		);
+
 		// notify of peers and view
 		handle
 			.send(FromOrchestra::Communication {
@@ -1062,6 +1074,17 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing(
 			}
 		);
 
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx))
+			)
+				if r == hash_a && sess_index == session_index
+			=> {
+				let _ = tx.send(Ok(Some(ExecutorParams::default())));
+			}
+		);
+
 		// notify of peers and view
 		handle
 			.send(FromOrchestra::Communication {
@@ -1586,6 +1609,17 @@ fn delay_reputation_changes() {
 			}
 		);
 
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx))
+			)
+				if r == hash_a && sess_index == session_index
+			=> {
+				let _ = tx.send(Ok(Some(ExecutorParams::default())));
+			}
+		);
+
 		// notify of peers and view
 		handle
 			.send(FromOrchestra::Communication {
@@ -2060,6 +2094,17 @@ fn share_prioritizes_backing_group() {
 			}
 		);
 
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx))
+			)
+				if r == hash_a && sess_index == session_index
+			=> {
+				let _ = tx.send(Ok(Some(ExecutorParams::default())));
+			}
+		);
+
 		// notify of dummy peers and view
 		for (peer, pair) in dummy_peers.clone().into_iter().zip(dummy_pairs) {
 			handle
@@ -2376,6 +2421,17 @@ fn peer_cant_flood_with_large_statements() {
 			}
 		);
 
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx))
+			)
+				if r == hash_a && sess_index == session_index
+			=> {
+				let _ = tx.send(Ok(Some(ExecutorParams::default())));
+			}
+		);
+
 		// notify of peers and view
 		handle
 			.send(FromOrchestra::Communication {
@@ -2595,6 +2651,17 @@ fn handle_multiple_seconded_statements() {
 			}
 		);
 
+		assert_matches!(
+			handle.recv().await,
+			AllMessages::RuntimeApi(
+				RuntimeApiMessage::Request(r, RuntimeApiRequest::SessionExecutorParams(sess_index, tx))
+			)
+				if r == relay_parent_hash && sess_index == session_index
+			=> {
+				let _ = tx.send(Ok(Some(ExecutorParams::default())));
+			}
+		);
+
 		// notify of peers and view
 		for peer in all_peers.iter() {
 			handle
diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs
index a823b1d3961..e78941776d5 100644
--- a/polkadot/node/overseer/examples/minimal-example.rs
+++ b/polkadot/node/overseer/examples/minimal-example.rs
@@ -76,6 +76,7 @@ impl Subsystem1 {
 			let msg = CandidateValidationMessage::ValidateFromChainState(
 				candidate_receipt,
 				PoV { block_data: BlockData(Vec::new()) }.into(),
+				Default::default(),
 				PvfExecTimeoutKind::Backing,
 				tx,
 			);
diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs
index 4ac538a7fd3..22d9bf0a708 100644
--- a/polkadot/node/overseer/src/tests.rs
+++ b/polkadot/node/overseer/src/tests.rs
@@ -106,6 +106,7 @@ where
 						ctx.send_message(CandidateValidationMessage::ValidateFromChainState(
 							candidate_receipt,
 							PoV { block_data: BlockData(Vec::new()) }.into(),
+							Default::default(),
 							PvfExecTimeoutKind::Backing,
 							tx,
 						))
@@ -779,6 +780,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage {
 	CandidateValidationMessage::ValidateFromChainState(
 		candidate_receipt,
 		pov,
+		Default::default(),
 		PvfExecTimeoutKind::Backing,
 		sender,
 	)
diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs
index 6b078e08377..a53908d3c2c 100644
--- a/polkadot/node/subsystem-types/src/messages.rs
+++ b/polkadot/node/subsystem-types/src/messages.rs
@@ -143,6 +143,7 @@ pub enum CandidateValidationMessage {
 	ValidateFromChainState(
 		CandidateReceipt,
 		Arc<PoV>,
+		ExecutorParams,
 		/// Execution timeout
 		PvfExecTimeoutKind,
 		oneshot::Sender<Result<ValidationResult, ValidationFailed>>,
@@ -161,6 +162,7 @@ pub enum CandidateValidationMessage {
 		ValidationCode,
 		CandidateReceipt,
 		Arc<PoV>,
+		ExecutorParams,
 		/// Execution timeout
 		PvfExecTimeoutKind,
 		oneshot::Sender<Result<ValidationResult, ValidationFailed>>,
diff --git a/polkadot/node/subsystem-util/src/runtime/error.rs b/polkadot/node/subsystem-util/src/runtime/error.rs
index 9c3d57b8ea6..8751693b078 100644
--- a/polkadot/node/subsystem-util/src/runtime/error.rs
+++ b/polkadot/node/subsystem-util/src/runtime/error.rs
@@ -38,6 +38,10 @@ pub enum Error {
 	/// We tried fetching a session info which was not available.
 	#[error("There was no session with the given index {0}")]
 	NoSuchSession(SessionIndex),
+
+	/// We tried fetching executor params for a session which were not available.
+	#[error("There was no executor parameters for session with the given index {0}")]
+	NoExecutorParams(SessionIndex),
 }
 
 pub type Result<T> = std::result::Result<T, Error>;
diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs
index fcd778b0784..fc767faa763 100644
--- a/polkadot/node/subsystem-util/src/runtime/mod.rs
+++ b/polkadot/node/subsystem-util/src/runtime/mod.rs
@@ -29,17 +29,18 @@ use polkadot_node_subsystem::{
 	overseer, SubsystemSender,
 };
 use polkadot_primitives::{
-	vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, GroupIndex, GroupRotationInfo,
-	Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed,
-	SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId,
-	ValidatorIndex, LEGACY_MIN_BACKING_VOTES,
+	vstaging, CandidateEvent, CandidateHash, CoreState, EncodeAs, ExecutorParams, GroupIndex,
+	GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, SessionIndex,
+	SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash,
+	ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES,
 };
 
 use crate::{
 	request_availability_cores, request_candidate_events, request_from_runtime,
-	request_key_ownership_proof, request_on_chain_votes, request_session_index_for_child,
-	request_session_info, request_staging_async_backing_params, request_submit_report_dispute_lost,
-	request_unapplied_slashes, request_validation_code_by_hash, request_validator_groups,
+	request_key_ownership_proof, request_on_chain_votes, request_session_executor_params,
+	request_session_index_for_child, request_session_info, request_staging_async_backing_params,
+	request_submit_report_dispute_lost, request_unapplied_slashes, request_validation_code_by_hash,
+	request_validator_groups,
 };
 
 /// Errors that can happen on runtime fetches.
@@ -84,6 +85,8 @@ pub struct ExtendedSessionInfo {
 	pub session_info: SessionInfo,
 	/// Contains useful information about ourselves, in case this node is a validator.
 	pub validator_info: ValidatorInfo,
+	/// Session executor parameters
+	pub executor_params: ExecutorParams,
 }
 
 /// Information about ourselves, in case we are an `Authority`.
@@ -174,9 +177,15 @@ impl RuntimeInfo {
 				recv_runtime(request_session_info(parent, session_index, sender).await)
 					.await?
 					.ok_or(JfyiError::NoSuchSession(session_index))?;
+
+			let executor_params =
+				recv_runtime(request_session_executor_params(parent, session_index, sender).await)
+					.await?
+					.ok_or(JfyiError::NoExecutorParams(session_index))?;
+
 			let validator_info = self.get_validator_info(&session_info)?;
 
-			let full_info = ExtendedSessionInfo { session_info, validator_info };
+			let full_info = ExtendedSessionInfo { session_info, validator_info, executor_params };
 
 			self.session_info_cache.insert(session_index, full_info);
 		}
-- 
GitLab