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			KeyOwnershipProof(relay_parent, validator_id, key_ownership_proof) => self
169				.requests_cache
170				.cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof),
171			ApprovalVotingParams(_relay_parent, session_index, params) =>
172				self.requests_cache.cache_approval_voting_params(session_index, params),
173			SubmitReportDisputeLost(_) => {},
174			DisabledValidators(relay_parent, disabled_validators) =>
175				self.requests_cache.cache_disabled_validators(relay_parent, disabled_validators),
176			ParaBackingState(relay_parent, para_id, constraints) => self
177				.requests_cache
178				.cache_para_backing_state((relay_parent, para_id), constraints),
179			AsyncBackingParams(relay_parent, params) =>
180				self.requests_cache.cache_async_backing_params(relay_parent, params),
181			NodeFeatures(session_index, params) =>
182				self.requests_cache.cache_node_features(session_index, params),
183			ClaimQueue(relay_parent, sender) => {
184				self.requests_cache.cache_claim_queue(relay_parent, sender);
185			},
186			BackingConstraints(relay_parent, para_id, constraints) => self
187				.requests_cache
188				.cache_backing_constraints((relay_parent, para_id), constraints),
189			SchedulingLookahead(session_index, scheduling_lookahead) => self
190				.requests_cache
191				.cache_scheduling_lookahead(session_index, scheduling_lookahead),
192			ValidationCodeBombLimit(session_index, limit) =>
193				self.requests_cache.cache_validation_code_bomb_limit(session_index, limit),
194			ParaIds(session_index, para_ids) => {
195				self.requests_cache.cache_para_ids(session_index, para_ids);
196			},
197		}
198	}
199
200	fn query_cache(&mut self, relay_parent: Hash, request: Request) -> Option<Request> {
201		macro_rules! query {
202			// Just query by relay parent
203			($cache_api_name:ident (), $sender:expr) => {{
204				let sender = $sender;
205				if let Some(value) = self.requests_cache.$cache_api_name(&relay_parent) {
206					let _ = sender.send(Ok(value.clone()));
207					self.metrics.on_cached_request();
208					None
209				} else {
210					Some(sender)
211				}
212			}};
213			// Query by relay parent + additional parameters
214			($cache_api_name:ident ($($param:expr),+), $sender:expr) => {{
215				let sender = $sender;
216				if let Some(value) = self.requests_cache.$cache_api_name((relay_parent.clone(), $($param.clone()),+)) {
217					self.metrics.on_cached_request();
218					let _ = sender.send(Ok(value.clone()));
219					None
220				} else {
221					Some(sender)
222				}
223			}}
224		}
225
226		match request {
227			Request::Version(sender) =>
228				query!(version(), sender).map(|sender| Request::Version(sender)),
229			Request::Authorities(sender) =>
230				query!(authorities(), sender).map(|sender| Request::Authorities(sender)),
231			Request::Validators(sender) =>
232				query!(validators(), sender).map(|sender| Request::Validators(sender)),
233			Request::ValidatorGroups(sender) =>
234				query!(validator_groups(), sender).map(|sender| Request::ValidatorGroups(sender)),
235			Request::AvailabilityCores(sender) => query!(availability_cores(), sender)
236				.map(|sender| Request::AvailabilityCores(sender)),
237			Request::PersistedValidationData(para, assumption, sender) =>
238				query!(persisted_validation_data(para, assumption), sender)
239					.map(|sender| Request::PersistedValidationData(para, assumption, sender)),
240			Request::AssumedValidationData(
241				para,
242				expected_persisted_validation_data_hash,
243				sender,
244			) => query!(
245				assumed_validation_data(para, expected_persisted_validation_data_hash),
246				sender
247			)
248			.map(|sender| {
249				Request::AssumedValidationData(
250					para,
251					expected_persisted_validation_data_hash,
252					sender,
253				)
254			}),
255			Request::CheckValidationOutputs(para, commitments, sender) =>
256				query!(check_validation_outputs(para, commitments), sender)
257					.map(|sender| Request::CheckValidationOutputs(para, commitments, sender)),
258			Request::SessionIndexForChild(sender) => query!(session_index_for_child(), sender)
259				.map(|sender| Request::SessionIndexForChild(sender)),
260			Request::ValidationCode(para, assumption, sender) =>
261				query!(validation_code(para, assumption), sender)
262					.map(|sender| Request::ValidationCode(para, assumption, sender)),
263			Request::ValidationCodeByHash(validation_code_hash, sender) =>
264				query!(validation_code_by_hash(validation_code_hash), sender)
265					.map(|sender| Request::ValidationCodeByHash(validation_code_hash, sender)),
266			Request::CandidatePendingAvailability(para, sender) =>
267				query!(candidate_pending_availability(para), sender)
268					.map(|sender| Request::CandidatePendingAvailability(para, sender)),
269			Request::CandidatesPendingAvailability(para, sender) =>
270				query!(candidates_pending_availability(para), sender)
271					.map(|sender| Request::CandidatesPendingAvailability(para, sender)),
272			Request::CandidateEvents(sender) =>
273				query!(candidate_events(), sender).map(|sender| Request::CandidateEvents(sender)),
274			Request::SessionExecutorParams(session_index, sender) => {
275				if let Some(executor_params) =
276					self.requests_cache.session_executor_params(session_index)
277				{
278					self.metrics.on_cached_request();
279					let _ = sender.send(Ok(executor_params.clone()));
280					None
281				} else {
282					Some(Request::SessionExecutorParams(session_index, sender))
283				}
284			},
285			Request::SessionInfo(index, sender) => {
286				if let Some(info) = self.requests_cache.session_info(index) {
287					self.metrics.on_cached_request();
288					let _ = sender.send(Ok(Some(info.clone())));
289					None
290				} else {
291					Some(Request::SessionInfo(index, sender))
292				}
293			},
294			Request::DmqContents(id, sender) =>
295				query!(dmq_contents(id), sender).map(|sender| Request::DmqContents(id, sender)),
296			Request::InboundHrmpChannelsContents(id, sender) =>
297				query!(inbound_hrmp_channels_contents(id), sender)
298					.map(|sender| Request::InboundHrmpChannelsContents(id, sender)),
299			Request::CurrentBabeEpoch(sender) =>
300				query!(current_babe_epoch(), sender).map(|sender| Request::CurrentBabeEpoch(sender)),
301			Request::FetchOnChainVotes(sender) =>
302				query!(on_chain_votes(), sender).map(|sender| Request::FetchOnChainVotes(sender)),
303			Request::PvfsRequirePrecheck(sender) => query!(pvfs_require_precheck(), sender)
304				.map(|sender| Request::PvfsRequirePrecheck(sender)),
305			request @ Request::SubmitPvfCheckStatement(_, _, _) => {
306				// This request is side-effecting and thus cannot be cached.
307				Some(request)
308			},
309			Request::ValidationCodeHash(para, assumption, sender) =>
310				query!(validation_code_hash(para, assumption), sender)
311					.map(|sender| Request::ValidationCodeHash(para, assumption, sender)),
312			Request::Disputes(sender) =>
313				query!(disputes(), sender).map(|sender| Request::Disputes(sender)),
314			Request::UnappliedSlashes(sender) =>
315				query!(unapplied_slashes(), sender).map(|sender| Request::UnappliedSlashes(sender)),
316			Request::KeyOwnershipProof(validator_id, sender) =>
317				query!(key_ownership_proof(validator_id), sender)
318					.map(|sender| Request::KeyOwnershipProof(validator_id, sender)),
319			Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) =>
320				query!(submit_report_dispute_lost(dispute_proof, key_ownership_proof), sender).map(
321					|sender| {
322						Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender)
323					},
324				),
325			Request::ApprovalVotingParams(session_index, sender) =>
326				query!(approval_voting_params(session_index), sender)
327					.map(|sender| Request::ApprovalVotingParams(session_index, sender)),
328			Request::DisabledValidators(sender) => query!(disabled_validators(), sender)
329				.map(|sender| Request::DisabledValidators(sender)),
330			Request::ParaBackingState(para, sender) => query!(para_backing_state(para), sender)
331				.map(|sender| Request::ParaBackingState(para, sender)),
332			Request::AsyncBackingParams(sender) => query!(async_backing_params(), sender)
333				.map(|sender| Request::AsyncBackingParams(sender)),
334			Request::MinimumBackingVotes(index, sender) => {
335				if let Some(value) = self.requests_cache.minimum_backing_votes(index) {
336					self.metrics.on_cached_request();
337					let _ = sender.send(Ok(value));
338					None
339				} else {
340					Some(Request::MinimumBackingVotes(index, sender))
341				}
342			},
343			Request::NodeFeatures(index, sender) => {
344				if let Some(value) = self.requests_cache.node_features(index) {
345					self.metrics.on_cached_request();
346					let _ = sender.send(Ok(value.clone()));
347					None
348				} else {
349					Some(Request::NodeFeatures(index, sender))
350				}
351			},
352			Request::ClaimQueue(sender) =>
353				query!(claim_queue(), sender).map(|sender| Request::ClaimQueue(sender)),
354			Request::BackingConstraints(para, sender) => query!(backing_constraints(para), sender)
355				.map(|sender| Request::BackingConstraints(para, sender)),
356			Request::SchedulingLookahead(index, sender) => {
357				if let Some(value) = self.requests_cache.scheduling_lookahead(index) {
358					self.metrics.on_cached_request();
359					let _ = sender.send(Ok(value));
360					None
361				} else {
362					Some(Request::SchedulingLookahead(index, sender))
363				}
364			},
365			Request::ValidationCodeBombLimit(index, sender) => {
366				if let Some(value) = self.requests_cache.validation_code_bomb_limit(index) {
367					self.metrics.on_cached_request();
368					let _ = sender.send(Ok(value));
369					None
370				} else {
371					Some(Request::ValidationCodeBombLimit(index, sender))
372				}
373			},
374			Request::ParaIds(index, sender) => {
375				if let Some(value) = self.requests_cache.para_ids(index) {
376					self.metrics.on_cached_request();
377					let _ = sender.send(Ok(value.clone()));
378					None
379				} else {
380					Some(Request::ParaIds(index, sender))
381				}
382			},
383		}
384	}
385
386	/// Spawn a runtime API request.
387	fn spawn_request(&mut self, relay_parent: Hash, request: Request) {
388		let client = self.client.clone();
389		let metrics = self.metrics.clone();
390		let (sender, receiver) = oneshot::channel();
391
392		// TODO: make the cache great again https://github.com/paritytech/polkadot/issues/5546
393		let request = match self.query_cache(relay_parent, request) {
394			Some(request) => request,
395			None => return,
396		};
397
398		let request = async move {
399			let result = make_runtime_api_request(client, metrics, relay_parent, request).await;
400			let _ = sender.send(result);
401		}
402		.boxed();
403
404		self.spawn_handle
405			.spawn_blocking(API_REQUEST_TASK_NAME, Some("runtime-api"), request);
406		self.active_requests.push(receiver);
407	}
408
409	/// Poll the active runtime API requests.
410	async fn poll_requests(&mut self) {
411		// If there are no active requests, this future should be pending forever.
412		if self.active_requests.len() == 0 {
413			return futures::pending!();
414		}
415
416		// If there are active requests, this will always resolve to `Some(_)` when a request is
417		// finished.
418		if let Some(Ok(Some(result))) = self.active_requests.next().await {
419			self.store_cache(result);
420		}
421	}
422
423	/// Returns true if our `active_requests` queue is full.
424	fn is_busy(&self) -> bool {
425		self.active_requests.len() >= MAX_PARALLEL_REQUESTS
426	}
427}
428
429#[overseer::contextbounds(RuntimeApi, prefix = self::overseer)]
430async fn run<Client, Context>(
431	mut ctx: Context,
432	mut subsystem: RuntimeApiSubsystem<Client>,
433) -> SubsystemResult<()>
434where
435	Client: RuntimeApiSubsystemClient + Send + Sync + 'static,
436{
437	loop {
438		// Let's add some back pressure when the subsystem is running at `MAX_PARALLEL_REQUESTS`.
439		// This can never block forever, because `active_requests` is owned by this task and any
440		// mutations happen either in `poll_requests` or `spawn_request` - so if `is_busy` returns
441		// true, then even if all of the requests finish before us calling `poll_requests` the
442		// `active_requests` length remains invariant.
443		if subsystem.is_busy() {
444			// Since we are not using any internal waiting queues, we need to wait for exactly
445			// one request to complete before we can read the next one from the overseer channel.
446			let _ = subsystem.poll_requests().await;
447		}
448
449		select! {
450			req = ctx.recv().fuse() => match req? {
451				FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()),
452				FromOrchestra::Signal(OverseerSignal::ActiveLeaves(_)) => {},
453				FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {},
454				FromOrchestra::Communication { msg } => match msg {
455					RuntimeApiMessage::Request(relay_parent, request) => {
456						subsystem.spawn_request(relay_parent, request);
457					},
458				}
459			},
460			_ = subsystem.poll_requests().fuse() => {},
461		}
462	}
463}
464
465async fn make_runtime_api_request<Client>(
466	client: Arc<Client>,
467	metrics: Metrics,
468	relay_parent: Hash,
469	request: Request,
470) -> Option<RequestResult>
471where
472	Client: RuntimeApiSubsystemClient + 'static,
473{
474	let _timer = metrics.time_make_runtime_api_request();
475
476	macro_rules! query {
477		($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr) => {{
478			query!($req_variant, $api_name($($param),*), ver = $version, $sender, result = ( relay_parent $(, $param )* ) )
479		}};
480		($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr, result = ( $($results:expr),* ) ) => {{
481			let sender = $sender;
482			let version: u32 = $version; // enforce type for the version expression
483			let runtime_version = client.api_version_parachain_host(relay_parent).await
484				.unwrap_or_else(|e| {
485					gum::warn!(
486						target: LOG_TARGET,
487						api = ?stringify!($api_name),
488						"cannot query the runtime API version: {}",
489						e,
490					);
491					Some(0)
492				})
493				.unwrap_or_else(|| {
494					gum::warn!(
495						target: LOG_TARGET,
496						"no runtime version is reported"
497					);
498					0
499				});
500
501			let res = if runtime_version >= version {
502				client.$api_name(relay_parent $(, $param.clone() )*).await
503					.map_err(|e| RuntimeApiError::Execution {
504						runtime_api_name: stringify!($api_name),
505						source: std::sync::Arc::new(e),
506					})
507			} else {
508				Err(RuntimeApiError::NotSupported {
509					runtime_api_name: stringify!($api_name),
510				})
511			};
512			metrics.on_request(res.is_ok());
513			let _ = sender.send(res.clone());
514
515			res.ok().map(|res| RequestResult::$req_variant($( $results, )* res))
516		}}
517	}
518
519	match request {
520		Request::Version(sender) => {
521			let runtime_version = match client.api_version_parachain_host(relay_parent).await {
522				Ok(Some(v)) => Ok(v),
523				Ok(None) => Err(RuntimeApiError::NotSupported { runtime_api_name: "api_version" }),
524				Err(e) => Err(RuntimeApiError::Execution {
525					runtime_api_name: "api_version",
526					source: std::sync::Arc::new(e),
527				}),
528			};
529
530			let _ = sender.send(runtime_version.clone());
531			runtime_version.ok().map(|v| RequestResult::Version(relay_parent, v))
532		},
533
534		Request::Authorities(sender) => query!(Authorities, authorities(), ver = 1, sender),
535		Request::Validators(sender) => query!(Validators, validators(), ver = 1, sender),
536		Request::ValidatorGroups(sender) => {
537			query!(ValidatorGroups, validator_groups(), ver = 1, sender)
538		},
539		Request::AvailabilityCores(sender) => {
540			query!(AvailabilityCores, availability_cores(), ver = 1, sender)
541		},
542		Request::PersistedValidationData(para, assumption, sender) => query!(
543			PersistedValidationData,
544			persisted_validation_data(para, assumption),
545			ver = 1,
546			sender
547		),
548		Request::AssumedValidationData(para, expected_persisted_validation_data_hash, sender) => {
549			query!(
550				AssumedValidationData,
551				assumed_validation_data(para, expected_persisted_validation_data_hash),
552				ver = 1,
553				sender
554			)
555		},
556		Request::CheckValidationOutputs(para, commitments, sender) => query!(
557			CheckValidationOutputs,
558			check_validation_outputs(para, commitments),
559			ver = 1,
560			sender
561		),
562		Request::SessionIndexForChild(sender) => {
563			query!(SessionIndexForChild, session_index_for_child(), ver = 1, sender)
564		},
565		Request::ValidationCode(para, assumption, sender) => {
566			query!(ValidationCode, validation_code(para, assumption), ver = 1, sender)
567		},
568		Request::ValidationCodeByHash(validation_code_hash, sender) => query!(
569			ValidationCodeByHash,
570			validation_code_by_hash(validation_code_hash),
571			ver = 1,
572			sender
573		),
574		Request::CandidatePendingAvailability(para, sender) => query!(
575			CandidatePendingAvailability,
576			candidate_pending_availability(para),
577			ver = 1,
578			sender
579		),
580		Request::CandidatesPendingAvailability(para, sender) => query!(
581			CandidatesPendingAvailability,
582			candidates_pending_availability(para),
583			ver = Request::CANDIDATES_PENDING_AVAILABILITY_RUNTIME_REQUIREMENT,
584			sender
585		),
586		Request::CandidateEvents(sender) => {
587			query!(CandidateEvents, candidate_events(), ver = 1, sender)
588		},
589		Request::SessionInfo(index, sender) => {
590			query!(SessionInfo, session_info(index), ver = 2, sender)
591		},
592		Request::SessionExecutorParams(session_index, sender) => query!(
593			SessionExecutorParams,
594			session_executor_params(session_index),
595			ver = Request::EXECUTOR_PARAMS_RUNTIME_REQUIREMENT,
596			sender
597		),
598		Request::DmqContents(id, sender) => query!(DmqContents, dmq_contents(id), ver = 1, sender),
599		Request::InboundHrmpChannelsContents(id, sender) => {
600			query!(InboundHrmpChannelsContents, inbound_hrmp_channels_contents(id), ver = 1, sender)
601		},
602		Request::CurrentBabeEpoch(sender) => {
603			query!(CurrentBabeEpoch, current_epoch(), ver = 1, sender)
604		},
605		Request::FetchOnChainVotes(sender) => {
606			query!(FetchOnChainVotes, on_chain_votes(), ver = 1, sender)
607		},
608		Request::SubmitPvfCheckStatement(stmt, signature, sender) => {
609			query!(
610				SubmitPvfCheckStatement,
611				submit_pvf_check_statement(stmt, signature),
612				ver = 2,
613				sender,
614				result = ()
615			)
616		},
617		Request::PvfsRequirePrecheck(sender) => {
618			query!(PvfsRequirePrecheck, pvfs_require_precheck(), ver = 2, sender)
619		},
620		Request::ValidationCodeHash(para, assumption, sender) => {
621			query!(ValidationCodeHash, validation_code_hash(para, assumption), ver = 2, sender)
622		},
623		Request::Disputes(sender) => {
624			query!(Disputes, disputes(), ver = Request::DISPUTES_RUNTIME_REQUIREMENT, sender)
625		},
626		Request::UnappliedSlashes(sender) => query!(
627			UnappliedSlashes,
628			unapplied_slashes(),
629			ver = Request::UNAPPLIED_SLASHES_RUNTIME_REQUIREMENT,
630			sender
631		),
632		Request::KeyOwnershipProof(validator_id, sender) => query!(
633			KeyOwnershipProof,
634			key_ownership_proof(validator_id),
635			ver = Request::KEY_OWNERSHIP_PROOF_RUNTIME_REQUIREMENT,
636			sender
637		),
638		Request::ApprovalVotingParams(session_index, sender) => {
639			query!(
640				ApprovalVotingParams,
641				approval_voting_params(session_index),
642				ver = Request::APPROVAL_VOTING_PARAMS_REQUIREMENT,
643				sender
644			)
645		},
646		Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) => query!(
647			SubmitReportDisputeLost,
648			submit_report_dispute_lost(dispute_proof, key_ownership_proof),
649			ver = Request::SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT,
650			sender,
651			result = ()
652		),
653		Request::MinimumBackingVotes(index, sender) => query!(
654			MinimumBackingVotes,
655			minimum_backing_votes(index),
656			ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT,
657			sender,
658			result = (index)
659		),
660		Request::DisabledValidators(sender) => query!(
661			DisabledValidators,
662			disabled_validators(),
663			ver = Request::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT,
664			sender
665		),
666		Request::ParaBackingState(para, sender) => {
667			query!(
668				ParaBackingState,
669				para_backing_state(para),
670				ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT,
671				sender
672			)
673		},
674		Request::AsyncBackingParams(sender) => {
675			query!(
676				AsyncBackingParams,
677				async_backing_params(),
678				ver = Request::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT,
679				sender
680			)
681		},
682		Request::NodeFeatures(index, sender) => query!(
683			NodeFeatures,
684			node_features(),
685			ver = Request::NODE_FEATURES_RUNTIME_REQUIREMENT,
686			sender,
687			result = (index)
688		),
689		Request::ClaimQueue(sender) => query!(
690			ClaimQueue,
691			claim_queue(),
692			ver = Request::CLAIM_QUEUE_RUNTIME_REQUIREMENT,
693			sender
694		),
695		Request::BackingConstraints(para, sender) => {
696			query!(
697				BackingConstraints,
698				backing_constraints(para),
699				ver = Request::CONSTRAINTS_RUNTIME_REQUIREMENT,
700				sender
701			)
702		},
703		Request::SchedulingLookahead(index, sender) => query!(
704			SchedulingLookahead,
705			scheduling_lookahead(),
706			ver = Request::SCHEDULING_LOOKAHEAD_RUNTIME_REQUIREMENT,
707			sender,
708			result = (index)
709		),
710		Request::ValidationCodeBombLimit(index, sender) => query!(
711			ValidationCodeBombLimit,
712			validation_code_bomb_limit(),
713			ver = Request::VALIDATION_CODE_BOMB_LIMIT_RUNTIME_REQUIREMENT,
714			sender,
715			result = (index)
716		),
717		Request::ParaIds(index, sender) => query!(
718			ParaIds,
719			para_ids(),
720			ver = Request::PARAIDS_RUNTIME_REQUIREMENT,
721			sender,
722			result = (index)
723		),
724	}
725}