referrerpolicy=no-referrer-when-downgrade

polkadot_node_core_runtime_api/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Implements the Runtime API Subsystem
18//!
19//! This provides a clean, ownerless wrapper around the parachain-related runtime APIs. This crate
20//! can also be used to cache responses from heavy runtime APIs.
21
22#![deny(unused_crate_dependencies)]
23#![warn(missing_docs)]
24
25use polkadot_node_subsystem::{
26	errors::RuntimeApiError,
27	messages::{RuntimeApiMessage, RuntimeApiRequest as Request},
28	overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult,
29};
30use polkadot_node_subsystem_types::RuntimeApiSubsystemClient;
31use polkadot_primitives::Hash;
32
33use cache::{RequestResult, RequestResultCache};
34use futures::{channel::oneshot, prelude::*, select, stream::FuturesUnordered};
35use std::sync::Arc;
36
37mod cache;
38
39mod metrics;
40use self::metrics::Metrics;
41
42#[cfg(test)]
43mod tests;
44
45const LOG_TARGET: &str = "parachain::runtime-api";
46
47/// The number of maximum runtime API requests can be executed in parallel.
48/// Further requests will backpressure the bounded channel.
49const MAX_PARALLEL_REQUESTS: usize = 4;
50
51/// The name of the blocking task that executes a runtime API request.
52const API_REQUEST_TASK_NAME: &str = "polkadot-runtime-api-request";
53
54/// The `RuntimeApiSubsystem`. See module docs for more details.
55pub struct RuntimeApiSubsystem<Client> {
56	client: Arc<Client>,
57	metrics: Metrics,
58	spawn_handle: Box<dyn overseer::gen::Spawner>,
59	/// All the active runtime API requests that are currently being executed.
60	active_requests: FuturesUnordered<oneshot::Receiver<Option<RequestResult>>>,
61	/// Requests results cache
62	requests_cache: RequestResultCache,
63}
64
65impl<Client> RuntimeApiSubsystem<Client> {
66	/// Create a new Runtime API subsystem wrapping the given client and metrics.
67	pub fn new(
68		client: Arc<Client>,
69		metrics: Metrics,
70		spawner: impl overseer::gen::Spawner + 'static,
71	) -> Self {
72		RuntimeApiSubsystem {
73			client,
74			metrics,
75			spawn_handle: Box::new(spawner),
76			active_requests: Default::default(),
77			requests_cache: RequestResultCache::default(),
78		}
79	}
80}
81
82#[overseer::subsystem(RuntimeApi, error = SubsystemError, prefix = self::overseer)]
83impl<Client, Context> RuntimeApiSubsystem<Client>
84where
85	Client: RuntimeApiSubsystemClient + Send + Sync + 'static,
86{
87	fn start(self, ctx: Context) -> SpawnedSubsystem {
88		SpawnedSubsystem { future: run(ctx, self).boxed(), name: "runtime-api-subsystem" }
89	}
90}
91
92impl<Client> RuntimeApiSubsystem<Client>
93where
94	Client: RuntimeApiSubsystemClient + Send + 'static + Sync,
95{
96	fn store_cache(&mut self, result: RequestResult) {
97		use RequestResult::*;
98
99		match result {
100			Authorities(relay_parent, authorities) =>
101				self.requests_cache.cache_authorities(relay_parent, authorities),
102			Validators(relay_parent, validators) =>
103				self.requests_cache.cache_validators(relay_parent, validators),
104			MinimumBackingVotes(session_index, minimum_backing_votes) => self
105				.requests_cache
106				.cache_minimum_backing_votes(session_index, minimum_backing_votes),
107			ValidatorGroups(relay_parent, groups) =>
108				self.requests_cache.cache_validator_groups(relay_parent, groups),
109			AvailabilityCores(relay_parent, cores) =>
110				self.requests_cache.cache_availability_cores(relay_parent, cores),
111			PersistedValidationData(relay_parent, para_id, assumption, data) => self
112				.requests_cache
113				.cache_persisted_validation_data((relay_parent, para_id, assumption), data),
114			AssumedValidationData(
115				_relay_parent,
116				para_id,
117				expected_persisted_validation_data_hash,
118				data,
119			) => self.requests_cache.cache_assumed_validation_data(
120				(para_id, expected_persisted_validation_data_hash),
121				data,
122			),
123			CheckValidationOutputs(relay_parent, para_id, commitments, b) => self
124				.requests_cache
125				.cache_check_validation_outputs((relay_parent, para_id, commitments), b),
126			SessionIndexForChild(relay_parent, session_index) =>
127				self.requests_cache.cache_session_index_for_child(relay_parent, session_index),
128			ValidationCode(relay_parent, para_id, assumption, code) => self
129				.requests_cache
130				.cache_validation_code((relay_parent, para_id, assumption), code),
131			ValidationCodeByHash(_relay_parent, validation_code_hash, code) =>
132				self.requests_cache.cache_validation_code_by_hash(validation_code_hash, code),
133			CandidatePendingAvailability(relay_parent, para_id, candidate) => self
134				.requests_cache
135				.cache_candidate_pending_availability((relay_parent, para_id), candidate),
136			CandidatesPendingAvailability(relay_parent, para_id, candidates) => self
137				.requests_cache
138				.cache_candidates_pending_availability((relay_parent, para_id), candidates),
139			CandidateEvents(relay_parent, events) =>
140				self.requests_cache.cache_candidate_events(relay_parent, events),
141			SessionExecutorParams(_relay_parent, session_index, index) =>
142				self.requests_cache.cache_session_executor_params(session_index, index),
143			SessionInfo(_relay_parent, session_index, info) =>
144				if let Some(info) = info {
145					self.requests_cache.cache_session_info(session_index, info);
146				},
147			DmqContents(relay_parent, para_id, messages) =>
148				self.requests_cache.cache_dmq_contents((relay_parent, para_id), messages),
149			InboundHrmpChannelsContents(relay_parent, para_id, contents) => self
150				.requests_cache
151				.cache_inbound_hrmp_channel_contents((relay_parent, para_id), contents),
152			CurrentBabeEpoch(relay_parent, epoch) =>
153				self.requests_cache.cache_current_babe_epoch(relay_parent, epoch),
154			FetchOnChainVotes(relay_parent, scraped) =>
155				self.requests_cache.cache_on_chain_votes(relay_parent, scraped),
156			PvfsRequirePrecheck(relay_parent, pvfs) =>
157				self.requests_cache.cache_pvfs_require_precheck(relay_parent, pvfs),
158			SubmitPvfCheckStatement(()) => {},
159			ValidationCodeHash(relay_parent, para_id, assumption, hash) => self
160				.requests_cache
161				.cache_validation_code_hash((relay_parent, para_id, assumption), hash),
162			Version(relay_parent, version) =>
163				self.requests_cache.cache_version(relay_parent, version),
164			Disputes(relay_parent, disputes) =>
165				self.requests_cache.cache_disputes(relay_parent, disputes),
166			UnappliedSlashes(relay_parent, unapplied_slashes) =>
167				self.requests_cache.cache_unapplied_slashes(relay_parent, unapplied_slashes),
168			UnappliedSlashesV2(relay_parent, unapplied_slashes_v2) => self
169				.requests_cache
170				.cache_unapplied_slashes_v2(relay_parent, unapplied_slashes_v2),
171			KeyOwnershipProof(relay_parent, validator_id, key_ownership_proof) => self
172				.requests_cache
173				.cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof),
174			ApprovalVotingParams(_relay_parent, session_index, params) =>
175				self.requests_cache.cache_approval_voting_params(session_index, params),
176			SubmitReportDisputeLost(_) => {},
177			DisabledValidators(relay_parent, disabled_validators) =>
178				self.requests_cache.cache_disabled_validators(relay_parent, disabled_validators),
179			ParaBackingState(relay_parent, para_id, constraints) => self
180				.requests_cache
181				.cache_para_backing_state((relay_parent, para_id), constraints),
182			AsyncBackingParams(relay_parent, params) =>
183				self.requests_cache.cache_async_backing_params(relay_parent, params),
184			NodeFeatures(session_index, params) =>
185				self.requests_cache.cache_node_features(session_index, params),
186			ClaimQueue(relay_parent, sender) => {
187				self.requests_cache.cache_claim_queue(relay_parent, sender);
188			},
189			BackingConstraints(relay_parent, para_id, constraints) => self
190				.requests_cache
191				.cache_backing_constraints((relay_parent, para_id), constraints),
192			SchedulingLookahead(session_index, scheduling_lookahead) => self
193				.requests_cache
194				.cache_scheduling_lookahead(session_index, scheduling_lookahead),
195			ValidationCodeBombLimit(session_index, limit) =>
196				self.requests_cache.cache_validation_code_bomb_limit(session_index, limit),
197			ParaIds(session_index, para_ids) => {
198				self.requests_cache.cache_para_ids(session_index, para_ids);
199			},
200		}
201	}
202
203	fn query_cache(&mut self, relay_parent: Hash, request: Request) -> Option<Request> {
204		macro_rules! query {
205			// Just query by relay parent
206			($cache_api_name:ident (), $sender:expr) => {{
207				let sender = $sender;
208				if let Some(value) = self.requests_cache.$cache_api_name(&relay_parent) {
209					let _ = sender.send(Ok(value.clone()));
210					self.metrics.on_cached_request();
211					None
212				} else {
213					Some(sender)
214				}
215			}};
216			// Query by relay parent + additional parameters
217			($cache_api_name:ident ($($param:expr),+), $sender:expr) => {{
218				let sender = $sender;
219				if let Some(value) = self.requests_cache.$cache_api_name((relay_parent.clone(), $($param.clone()),+)) {
220					self.metrics.on_cached_request();
221					let _ = sender.send(Ok(value.clone()));
222					None
223				} else {
224					Some(sender)
225				}
226			}}
227		}
228
229		match request {
230			Request::Version(sender) =>
231				query!(version(), sender).map(|sender| Request::Version(sender)),
232			Request::Authorities(sender) =>
233				query!(authorities(), sender).map(|sender| Request::Authorities(sender)),
234			Request::Validators(sender) =>
235				query!(validators(), sender).map(|sender| Request::Validators(sender)),
236			Request::ValidatorGroups(sender) =>
237				query!(validator_groups(), sender).map(|sender| Request::ValidatorGroups(sender)),
238			Request::AvailabilityCores(sender) => query!(availability_cores(), sender)
239				.map(|sender| Request::AvailabilityCores(sender)),
240			Request::PersistedValidationData(para, assumption, sender) =>
241				query!(persisted_validation_data(para, assumption), sender)
242					.map(|sender| Request::PersistedValidationData(para, assumption, sender)),
243			Request::AssumedValidationData(
244				para,
245				expected_persisted_validation_data_hash,
246				sender,
247			) => query!(
248				assumed_validation_data(para, expected_persisted_validation_data_hash),
249				sender
250			)
251			.map(|sender| {
252				Request::AssumedValidationData(
253					para,
254					expected_persisted_validation_data_hash,
255					sender,
256				)
257			}),
258			Request::CheckValidationOutputs(para, commitments, sender) =>
259				query!(check_validation_outputs(para, commitments), sender)
260					.map(|sender| Request::CheckValidationOutputs(para, commitments, sender)),
261			Request::SessionIndexForChild(sender) => query!(session_index_for_child(), sender)
262				.map(|sender| Request::SessionIndexForChild(sender)),
263			Request::ValidationCode(para, assumption, sender) =>
264				query!(validation_code(para, assumption), sender)
265					.map(|sender| Request::ValidationCode(para, assumption, sender)),
266			Request::ValidationCodeByHash(validation_code_hash, sender) =>
267				query!(validation_code_by_hash(validation_code_hash), sender)
268					.map(|sender| Request::ValidationCodeByHash(validation_code_hash, sender)),
269			Request::CandidatePendingAvailability(para, sender) =>
270				query!(candidate_pending_availability(para), sender)
271					.map(|sender| Request::CandidatePendingAvailability(para, sender)),
272			Request::CandidatesPendingAvailability(para, sender) =>
273				query!(candidates_pending_availability(para), sender)
274					.map(|sender| Request::CandidatesPendingAvailability(para, sender)),
275			Request::CandidateEvents(sender) =>
276				query!(candidate_events(), sender).map(|sender| Request::CandidateEvents(sender)),
277			Request::SessionExecutorParams(session_index, sender) => {
278				if let Some(executor_params) =
279					self.requests_cache.session_executor_params(session_index)
280				{
281					self.metrics.on_cached_request();
282					let _ = sender.send(Ok(executor_params.clone()));
283					None
284				} else {
285					Some(Request::SessionExecutorParams(session_index, sender))
286				}
287			},
288			Request::SessionInfo(index, sender) => {
289				if let Some(info) = self.requests_cache.session_info(index) {
290					self.metrics.on_cached_request();
291					let _ = sender.send(Ok(Some(info.clone())));
292					None
293				} else {
294					Some(Request::SessionInfo(index, sender))
295				}
296			},
297			Request::DmqContents(id, sender) =>
298				query!(dmq_contents(id), sender).map(|sender| Request::DmqContents(id, sender)),
299			Request::InboundHrmpChannelsContents(id, sender) =>
300				query!(inbound_hrmp_channels_contents(id), sender)
301					.map(|sender| Request::InboundHrmpChannelsContents(id, sender)),
302			Request::CurrentBabeEpoch(sender) =>
303				query!(current_babe_epoch(), sender).map(|sender| Request::CurrentBabeEpoch(sender)),
304			Request::FetchOnChainVotes(sender) =>
305				query!(on_chain_votes(), sender).map(|sender| Request::FetchOnChainVotes(sender)),
306			Request::PvfsRequirePrecheck(sender) => query!(pvfs_require_precheck(), sender)
307				.map(|sender| Request::PvfsRequirePrecheck(sender)),
308			request @ Request::SubmitPvfCheckStatement(_, _, _) => {
309				// This request is side-effecting and thus cannot be cached.
310				Some(request)
311			},
312			Request::ValidationCodeHash(para, assumption, sender) =>
313				query!(validation_code_hash(para, assumption), sender)
314					.map(|sender| Request::ValidationCodeHash(para, assumption, sender)),
315			Request::Disputes(sender) =>
316				query!(disputes(), sender).map(|sender| Request::Disputes(sender)),
317			Request::UnappliedSlashes(sender) =>
318				query!(unapplied_slashes(), sender).map(|sender| Request::UnappliedSlashes(sender)),
319			Request::UnappliedSlashesV2(sender) => query!(unapplied_slashes_v2(), sender)
320				.map(|sender| Request::UnappliedSlashesV2(sender)),
321			Request::KeyOwnershipProof(validator_id, sender) =>
322				query!(key_ownership_proof(validator_id), sender)
323					.map(|sender| Request::KeyOwnershipProof(validator_id, sender)),
324			Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) =>
325				query!(submit_report_dispute_lost(dispute_proof, key_ownership_proof), sender).map(
326					|sender| {
327						Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender)
328					},
329				),
330			Request::ApprovalVotingParams(session_index, sender) =>
331				query!(approval_voting_params(session_index), sender)
332					.map(|sender| Request::ApprovalVotingParams(session_index, sender)),
333			Request::DisabledValidators(sender) => query!(disabled_validators(), sender)
334				.map(|sender| Request::DisabledValidators(sender)),
335			Request::ParaBackingState(para, sender) => query!(para_backing_state(para), sender)
336				.map(|sender| Request::ParaBackingState(para, sender)),
337			Request::AsyncBackingParams(sender) => query!(async_backing_params(), sender)
338				.map(|sender| Request::AsyncBackingParams(sender)),
339			Request::MinimumBackingVotes(index, sender) => {
340				if let Some(value) = self.requests_cache.minimum_backing_votes(index) {
341					self.metrics.on_cached_request();
342					let _ = sender.send(Ok(value));
343					None
344				} else {
345					Some(Request::MinimumBackingVotes(index, sender))
346				}
347			},
348			Request::NodeFeatures(index, sender) => {
349				if let Some(value) = self.requests_cache.node_features(index) {
350					self.metrics.on_cached_request();
351					let _ = sender.send(Ok(value.clone()));
352					None
353				} else {
354					Some(Request::NodeFeatures(index, sender))
355				}
356			},
357			Request::ClaimQueue(sender) =>
358				query!(claim_queue(), sender).map(|sender| Request::ClaimQueue(sender)),
359			Request::BackingConstraints(para, sender) => query!(backing_constraints(para), sender)
360				.map(|sender| Request::BackingConstraints(para, sender)),
361			Request::SchedulingLookahead(index, sender) => {
362				if let Some(value) = self.requests_cache.scheduling_lookahead(index) {
363					self.metrics.on_cached_request();
364					let _ = sender.send(Ok(value));
365					None
366				} else {
367					Some(Request::SchedulingLookahead(index, sender))
368				}
369			},
370			Request::ValidationCodeBombLimit(index, sender) => {
371				if let Some(value) = self.requests_cache.validation_code_bomb_limit(index) {
372					self.metrics.on_cached_request();
373					let _ = sender.send(Ok(value));
374					None
375				} else {
376					Some(Request::ValidationCodeBombLimit(index, sender))
377				}
378			},
379			Request::ParaIds(index, sender) => {
380				if let Some(value) = self.requests_cache.para_ids(index) {
381					self.metrics.on_cached_request();
382					let _ = sender.send(Ok(value.clone()));
383					None
384				} else {
385					Some(Request::ParaIds(index, sender))
386				}
387			},
388		}
389	}
390
391	/// Spawn a runtime API request.
392	fn spawn_request(&mut self, relay_parent: Hash, request: Request) {
393		let client = self.client.clone();
394		let metrics = self.metrics.clone();
395		let (sender, receiver) = oneshot::channel();
396
397		// TODO: make the cache great again https://github.com/paritytech/polkadot/issues/5546
398		let request = match self.query_cache(relay_parent, request) {
399			Some(request) => request,
400			None => return,
401		};
402
403		let request = async move {
404			let result = make_runtime_api_request(client, metrics, relay_parent, request).await;
405			let _ = sender.send(result);
406		}
407		.boxed();
408
409		self.spawn_handle
410			.spawn_blocking(API_REQUEST_TASK_NAME, Some("runtime-api"), request);
411		self.active_requests.push(receiver);
412	}
413
414	/// Poll the active runtime API requests.
415	async fn poll_requests(&mut self) {
416		// If there are no active requests, this future should be pending forever.
417		if self.active_requests.len() == 0 {
418			return futures::pending!();
419		}
420
421		// If there are active requests, this will always resolve to `Some(_)` when a request is
422		// finished.
423		if let Some(Ok(Some(result))) = self.active_requests.next().await {
424			self.store_cache(result);
425		}
426	}
427
428	/// Returns true if our `active_requests` queue is full.
429	fn is_busy(&self) -> bool {
430		self.active_requests.len() >= MAX_PARALLEL_REQUESTS
431	}
432}
433
434#[overseer::contextbounds(RuntimeApi, prefix = self::overseer)]
435async fn run<Client, Context>(
436	mut ctx: Context,
437	mut subsystem: RuntimeApiSubsystem<Client>,
438) -> SubsystemResult<()>
439where
440	Client: RuntimeApiSubsystemClient + Send + Sync + 'static,
441{
442	loop {
443		// Let's add some back pressure when the subsystem is running at `MAX_PARALLEL_REQUESTS`.
444		// This can never block forever, because `active_requests` is owned by this task and any
445		// mutations happen either in `poll_requests` or `spawn_request` - so if `is_busy` returns
446		// true, then even if all of the requests finish before us calling `poll_requests` the
447		// `active_requests` length remains invariant.
448		if subsystem.is_busy() {
449			// Since we are not using any internal waiting queues, we need to wait for exactly
450			// one request to complete before we can read the next one from the overseer channel.
451			let _ = subsystem.poll_requests().await;
452		}
453
454		select! {
455			req = ctx.recv().fuse() => match req? {
456				FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()),
457				FromOrchestra::Signal(OverseerSignal::ActiveLeaves(_)) => {},
458				FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {},
459				FromOrchestra::Communication { msg } => match msg {
460					RuntimeApiMessage::Request(relay_parent, request) => {
461						subsystem.spawn_request(relay_parent, request);
462					},
463				}
464			},
465			_ = subsystem.poll_requests().fuse() => {},
466		}
467	}
468}
469
470async fn make_runtime_api_request<Client>(
471	client: Arc<Client>,
472	metrics: Metrics,
473	relay_parent: Hash,
474	request: Request,
475) -> Option<RequestResult>
476where
477	Client: RuntimeApiSubsystemClient + 'static,
478{
479	let _timer = metrics.time_make_runtime_api_request();
480
481	macro_rules! query {
482		($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr) => {{
483			query!($req_variant, $api_name($($param),*), ver = $version, $sender, result = ( relay_parent $(, $param )* ) )
484		}};
485		($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr, result = ( $($results:expr),* ) ) => {{
486			let sender = $sender;
487			let version: u32 = $version; // enforce type for the version expression
488			let runtime_version = client.api_version_parachain_host(relay_parent).await
489				.unwrap_or_else(|e| {
490					gum::warn!(
491						target: LOG_TARGET,
492						api = ?stringify!($api_name),
493						"cannot query the runtime API version: {}",
494						e,
495					);
496					Some(0)
497				})
498				.unwrap_or_else(|| {
499					gum::warn!(
500						target: LOG_TARGET,
501						"no runtime version is reported"
502					);
503					0
504				});
505
506			let res = if runtime_version >= version {
507				client.$api_name(relay_parent $(, $param.clone() )*).await
508					.map_err(|e| RuntimeApiError::Execution {
509						runtime_api_name: stringify!($api_name),
510						source: std::sync::Arc::new(e),
511					})
512			} else {
513				Err(RuntimeApiError::NotSupported {
514					runtime_api_name: stringify!($api_name),
515				})
516			};
517			metrics.on_request(res.is_ok());
518			let _ = sender.send(res.clone());
519
520			res.ok().map(|res| RequestResult::$req_variant($( $results, )* res))
521		}}
522	}
523
524	match request {
525		Request::Version(sender) => {
526			let runtime_version = match client.api_version_parachain_host(relay_parent).await {
527				Ok(Some(v)) => Ok(v),
528				Ok(None) => Err(RuntimeApiError::NotSupported { runtime_api_name: "api_version" }),
529				Err(e) => Err(RuntimeApiError::Execution {
530					runtime_api_name: "api_version",
531					source: std::sync::Arc::new(e),
532				}),
533			};
534
535			let _ = sender.send(runtime_version.clone());
536			runtime_version.ok().map(|v| RequestResult::Version(relay_parent, v))
537		},
538
539		Request::Authorities(sender) => query!(Authorities, authorities(), ver = 1, sender),
540		Request::Validators(sender) => query!(Validators, validators(), ver = 1, sender),
541		Request::ValidatorGroups(sender) => {
542			query!(ValidatorGroups, validator_groups(), ver = 1, sender)
543		},
544		Request::AvailabilityCores(sender) => {
545			query!(AvailabilityCores, availability_cores(), ver = 1, sender)
546		},
547		Request::PersistedValidationData(para, assumption, sender) => query!(
548			PersistedValidationData,
549			persisted_validation_data(para, assumption),
550			ver = 1,
551			sender
552		),
553		Request::AssumedValidationData(para, expected_persisted_validation_data_hash, sender) => {
554			query!(
555				AssumedValidationData,
556				assumed_validation_data(para, expected_persisted_validation_data_hash),
557				ver = 1,
558				sender
559			)
560		},
561		Request::CheckValidationOutputs(para, commitments, sender) => query!(
562			CheckValidationOutputs,
563			check_validation_outputs(para, commitments),
564			ver = 1,
565			sender
566		),
567		Request::SessionIndexForChild(sender) => {
568			query!(SessionIndexForChild, session_index_for_child(), ver = 1, sender)
569		},
570		Request::ValidationCode(para, assumption, sender) => {
571			query!(ValidationCode, validation_code(para, assumption), ver = 1, sender)
572		},
573		Request::ValidationCodeByHash(validation_code_hash, sender) => query!(
574			ValidationCodeByHash,
575			validation_code_by_hash(validation_code_hash),
576			ver = 1,
577			sender
578		),
579		Request::CandidatePendingAvailability(para, sender) => query!(
580			CandidatePendingAvailability,
581			candidate_pending_availability(para),
582			ver = 1,
583			sender
584		),
585		Request::CandidatesPendingAvailability(para, sender) => query!(
586			CandidatesPendingAvailability,
587			candidates_pending_availability(para),
588			ver = Request::CANDIDATES_PENDING_AVAILABILITY_RUNTIME_REQUIREMENT,
589			sender
590		),
591		Request::CandidateEvents(sender) => {
592			query!(CandidateEvents, candidate_events(), ver = 1, sender)
593		},
594		Request::SessionInfo(index, sender) => {
595			query!(SessionInfo, session_info(index), ver = 2, sender)
596		},
597		Request::SessionExecutorParams(session_index, sender) => query!(
598			SessionExecutorParams,
599			session_executor_params(session_index),
600			ver = Request::EXECUTOR_PARAMS_RUNTIME_REQUIREMENT,
601			sender
602		),
603		Request::DmqContents(id, sender) => query!(DmqContents, dmq_contents(id), ver = 1, sender),
604		Request::InboundHrmpChannelsContents(id, sender) => {
605			query!(InboundHrmpChannelsContents, inbound_hrmp_channels_contents(id), ver = 1, sender)
606		},
607		Request::CurrentBabeEpoch(sender) => {
608			query!(CurrentBabeEpoch, current_epoch(), ver = 1, sender)
609		},
610		Request::FetchOnChainVotes(sender) => {
611			query!(FetchOnChainVotes, on_chain_votes(), ver = 1, sender)
612		},
613		Request::SubmitPvfCheckStatement(stmt, signature, sender) => {
614			query!(
615				SubmitPvfCheckStatement,
616				submit_pvf_check_statement(stmt, signature),
617				ver = 2,
618				sender,
619				result = ()
620			)
621		},
622		Request::PvfsRequirePrecheck(sender) => {
623			query!(PvfsRequirePrecheck, pvfs_require_precheck(), ver = 2, sender)
624		},
625		Request::ValidationCodeHash(para, assumption, sender) => {
626			query!(ValidationCodeHash, validation_code_hash(para, assumption), ver = 2, sender)
627		},
628		Request::Disputes(sender) => {
629			query!(Disputes, disputes(), ver = Request::DISPUTES_RUNTIME_REQUIREMENT, sender)
630		},
631		Request::UnappliedSlashes(sender) => query!(
632			UnappliedSlashes,
633			unapplied_slashes(),
634			ver = Request::UNAPPLIED_SLASHES_RUNTIME_REQUIREMENT,
635			sender
636		),
637		Request::KeyOwnershipProof(validator_id, sender) => query!(
638			KeyOwnershipProof,
639			key_ownership_proof(validator_id),
640			ver = Request::KEY_OWNERSHIP_PROOF_RUNTIME_REQUIREMENT,
641			sender
642		),
643		Request::ApprovalVotingParams(session_index, sender) => {
644			query!(
645				ApprovalVotingParams,
646				approval_voting_params(session_index),
647				ver = Request::APPROVAL_VOTING_PARAMS_REQUIREMENT,
648				sender
649			)
650		},
651		Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) => query!(
652			SubmitReportDisputeLost,
653			submit_report_dispute_lost(dispute_proof, key_ownership_proof),
654			ver = Request::SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT,
655			sender,
656			result = ()
657		),
658		Request::MinimumBackingVotes(index, sender) => query!(
659			MinimumBackingVotes,
660			minimum_backing_votes(index),
661			ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT,
662			sender,
663			result = (index)
664		),
665		Request::DisabledValidators(sender) => query!(
666			DisabledValidators,
667			disabled_validators(),
668			ver = Request::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT,
669			sender
670		),
671		Request::ParaBackingState(para, sender) => {
672			query!(
673				ParaBackingState,
674				para_backing_state(para),
675				ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT,
676				sender
677			)
678		},
679		Request::AsyncBackingParams(sender) => {
680			query!(
681				AsyncBackingParams,
682				async_backing_params(),
683				ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT,
684				sender
685			)
686		},
687		Request::NodeFeatures(index, sender) => query!(
688			NodeFeatures,
689			node_features(),
690			ver = Request::NODE_FEATURES_RUNTIME_REQUIREMENT,
691			sender,
692			result = (index)
693		),
694		Request::ClaimQueue(sender) => query!(
695			ClaimQueue,
696			claim_queue(),
697			ver = Request::CLAIM_QUEUE_RUNTIME_REQUIREMENT,
698			sender
699		),
700		Request::BackingConstraints(para, sender) => {
701			query!(
702				BackingConstraints,
703				backing_constraints(para),
704				ver = Request::CONSTRAINTS_RUNTIME_REQUIREMENT,
705				sender
706			)
707		},
708		Request::SchedulingLookahead(index, sender) => query!(
709			SchedulingLookahead,
710			scheduling_lookahead(),
711			ver = Request::SCHEDULING_LOOKAHEAD_RUNTIME_REQUIREMENT,
712			sender,
713			result = (index)
714		),
715		Request::ValidationCodeBombLimit(index, sender) => query!(
716			ValidationCodeBombLimit,
717			validation_code_bomb_limit(),
718			ver = Request::VALIDATION_CODE_BOMB_LIMIT_RUNTIME_REQUIREMENT,
719			sender,
720			result = (index)
721		),
722		Request::ParaIds(index, sender) => query!(
723			ParaIds,
724			para_ids(),
725			ver = Request::PARAIDS_RUNTIME_REQUIREMENT,
726			sender,
727			result = (index)
728		),
729		Request::UnappliedSlashesV2(sender) => query!(
730			UnappliedSlashesV2,
731			unapplied_slashes_v2(),
732			ver = Request::UNAPPLIED_SLASHES_V2_RUNTIME_REQUIREMENT,
733			sender
734		),
735	}
736}