referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/runtime_api_impl/
v13.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//! A module exporting runtime API implementation functions for all runtime APIs using `v5`
15//! primitives.
16//!
17//! Runtimes implementing the v13 runtime API are recommended to forward directly to these
18//! functions.
19
20use crate::{
21	configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler,
22	session_info, shared,
23};
24use alloc::{
25	collections::{btree_map::BTreeMap, vec_deque::VecDeque},
26	vec,
27	vec::Vec,
28};
29use frame_support::{pallet_prelude::StorageVersion, traits::GetStorageVersion};
30use frame_system::pallet_prelude::*;
31use polkadot_primitives::{
32	async_backing::{
33		AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints,
34		InboundHrmpLimitations, OutboundHrmpChannelLimitations,
35	},
36	slashing, ApprovalVotingParams, AuthorityDiscoveryId, CandidateDescriptorVersion,
37	CandidateEvent, CandidateHash, CommittedCandidateReceiptV2 as CommittedCandidateReceipt,
38	CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash,
39	Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCore,
40	OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScheduledCore,
41	ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash,
42	ValidatorId, ValidatorIndex, ValidatorSignature,
43};
44use sp_runtime::traits::One;
45
46/// Implementation for the `validators` function of the runtime API.
47pub fn validators<T: initializer::Config>() -> Vec<ValidatorId> {
48	shared::ActiveValidatorKeys::<T>::get()
49}
50
51/// Implementation for the `validator_groups` function of the runtime API.
52pub fn validator_groups<T: initializer::Config>(
53) -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumberFor<T>>) {
54	// This formula needs to be the same as the one we use
55	// when populating group_responsible in `availability_cores`
56	let now = frame_system::Pallet::<T>::block_number() + One::one();
57
58	let groups = scheduler::ValidatorGroups::<T>::get();
59	let rotation_info = scheduler::Pallet::<T>::group_rotation_info(now);
60
61	(groups, rotation_info)
62}
63
64/// Implementation for the `availability_cores` function of the runtime API.
65pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, BlockNumberFor<T>>> {
66	let time_out_for = scheduler::Pallet::<T>::availability_timeout_predicate();
67
68	let group_responsible_for =
69		|backed_in_number, core_index| match scheduler::Pallet::<T>::group_assigned_to_core(
70			core_index,
71			backed_in_number,
72		) {
73			Some(g) => g,
74			None => {
75				log::warn!(
76					target: "runtime::polkadot-api::v2",
77					"Could not determine the group responsible for core extracted \
78					from list of cores for some prior block in same session",
79				);
80
81				GroupIndex(0)
82			},
83		};
84
85	let claim_queue = scheduler::Pallet::<T>::claim_queue();
86	let occupied_cores: BTreeMap<CoreIndex, inclusion::CandidatePendingAvailability<_, _>> =
87		inclusion::Pallet::<T>::get_occupied_cores().collect();
88	let n_cores = scheduler::Pallet::<T>::num_availability_cores();
89
90	(0..n_cores)
91		.map(|core_idx| {
92			let core_idx = CoreIndex(core_idx as u32);
93			if let Some(pending_availability) = occupied_cores.get(&core_idx) {
94				// Use the same block number for determining the responsible group as
95				// the backing subsystem would use when it calls validator_groups API.
96				// For V3 candidates, look up the scheduling parent block number from the
97				// relay parent tracker (because it may no longer be in the scheduling parent
98				// tracker, as pending availability candidates can have out of scope scheduling
99				// parents).
100				// For V1/V2, fall back to the relay parent number from the storage.
101				// This is a temporary fallback, because when this is rolled out, the relay parent
102				// tracker does not contain entries for all relay parents in the session. After v3
103				// receipt feature is enabled, we can remove this and always use the scheduling
104				// parent.
105				let scheduling_parent_number = if pending_availability
106					.candidate_descriptor()
107					.version() == CandidateDescriptorVersion::V3
108				{
109					let sp = pending_availability.candidate_descriptor().scheduling_parent();
110					// Workaround for issue #64.
111					let scheduling_parent_number = if shared::Pallet::<T>::on_chain_storage_version(
112					) == StorageVersion::new(1)
113					{
114						shared::migration::v1::AllowedRelayParents::<T>::get().get_number(sp)
115					} else {
116						let session_index = shared::CurrentSessionIndex::<T>::get();
117						shared::Pallet::<T>::get_relay_parent_info(session_index, sp)
118							.map(|info| info.number)
119					};
120
121					scheduling_parent_number.unwrap_or_else(|| {
122						log::warn!(
123							target: "runtime::polkadot-api",
124							"Could not determine the scheduling parent of this v3 candidate {:?}",
125							pending_availability.candidate_hash()
126						);
127						pending_availability.relay_parent_number()
128					})
129				} else {
130					pending_availability.relay_parent_number()
131				};
132				let backing_group_allocation_time = scheduling_parent_number + One::one();
133				CoreState::Occupied(OccupiedCore {
134					next_up_on_available: claim_queue
135						.get(&core_idx)
136						.and_then(|q| q.front())
137						.map(|&para_id| ScheduledCore { para_id, collator: None }),
138					occupied_since: pending_availability.backed_in_number(),
139					time_out_at: time_out_for(pending_availability.backed_in_number()).live_until,
140					next_up_on_time_out: claim_queue
141						.get(&core_idx)
142						.and_then(|q| q.front())
143						.map(|&para_id| ScheduledCore { para_id, collator: None }),
144					availability: pending_availability.availability_votes().clone(),
145					group_responsible: group_responsible_for(
146						backing_group_allocation_time,
147						pending_availability.core_occupied(),
148					),
149					candidate_hash: pending_availability.candidate_hash(),
150					candidate_descriptor: pending_availability.candidate_descriptor().clone(),
151				})
152			} else {
153				if let Some(&para_id) = claim_queue.get(&core_idx).and_then(|q| q.front()) {
154					CoreState::Scheduled(ScheduledCore { para_id, collator: None })
155				} else {
156					CoreState::Free
157				}
158			}
159		})
160		.collect()
161}
162
163/// Returns current block number being processed and the corresponding root hash.
164fn current_relay_parent<T: frame_system::Config>(
165) -> (BlockNumberFor<T>, <T as frame_system::Config>::Hash) {
166	use codec::Decode as _;
167	let state_version = frame_system::Pallet::<T>::runtime_version().state_version();
168	let relay_parent_number = frame_system::Pallet::<T>::block_number();
169	let relay_parent_storage_root = T::Hash::decode(&mut &sp_io::storage::root(state_version)[..])
170		.expect("storage root must decode to the Hash type; qed");
171	(relay_parent_number, relay_parent_storage_root)
172}
173
174fn with_assumption<Config, T, F>(
175	para_id: ParaId,
176	assumption: OccupiedCoreAssumption,
177	build: F,
178) -> Option<T>
179where
180	Config: inclusion::Config,
181	F: FnOnce() -> Option<T>,
182{
183	match assumption {
184		OccupiedCoreAssumption::Included => {
185			<inclusion::Pallet<Config>>::force_enact(para_id);
186			build()
187		},
188		OccupiedCoreAssumption::TimedOut => build(),
189		OccupiedCoreAssumption::Free => {
190			if !<inclusion::Pallet<Config>>::candidates_pending_availability(para_id).is_empty() {
191				None
192			} else {
193				build()
194			}
195		},
196	}
197}
198
199/// Implementation for the `persisted_validation_data` function of the runtime API.
200pub fn persisted_validation_data<T: initializer::Config>(
201	para_id: ParaId,
202	assumption: OccupiedCoreAssumption,
203) -> Option<PersistedValidationData<T::Hash, BlockNumberFor<T>>> {
204	let (relay_parent_number, relay_parent_storage_root) = current_relay_parent::<T>();
205	with_assumption::<T, _, _>(para_id, assumption, || {
206		crate::util::make_persisted_validation_data::<T>(
207			para_id,
208			relay_parent_number,
209			relay_parent_storage_root,
210		)
211	})
212}
213
214/// Implementation for the `assumed_validation_data` function of the runtime API.
215pub fn assumed_validation_data<T: initializer::Config>(
216	para_id: ParaId,
217	expected_persisted_validation_data_hash: Hash,
218) -> Option<(PersistedValidationData<T::Hash, BlockNumberFor<T>>, ValidationCodeHash)> {
219	let (relay_parent_number, relay_parent_storage_root) = current_relay_parent::<T>();
220	// This closure obtains the `persisted_validation_data` for the given `para_id` and matches
221	// its hash against an expected one.
222	let make_validation_data = || {
223		crate::util::make_persisted_validation_data::<T>(
224			para_id,
225			relay_parent_number,
226			relay_parent_storage_root,
227		)
228		.filter(|validation_data| validation_data.hash() == expected_persisted_validation_data_hash)
229	};
230
231	let persisted_validation_data = make_validation_data().or_else(|| {
232		// Try again with force enacting the pending candidates. This check only makes sense if
233		// there are any pending candidates.
234		(!inclusion::Pallet::<T>::candidates_pending_availability(para_id).is_empty())
235			.then_some(())
236			.and_then(|_| {
237				inclusion::Pallet::<T>::force_enact(para_id);
238				make_validation_data()
239			})
240	});
241	// If we were successful, also query current validation code hash.
242	persisted_validation_data.zip(paras::CurrentCodeHash::<T>::get(&para_id))
243}
244
245/// Implementation for the `check_validation_outputs` function of the runtime API.
246pub fn check_validation_outputs<T: initializer::Config>(
247	para_id: ParaId,
248	outputs: polkadot_primitives::CandidateCommitments,
249) -> bool {
250	let relay_parent_number = frame_system::Pallet::<T>::block_number();
251	inclusion::Pallet::<T>::check_validation_outputs_for_runtime_api(
252		para_id,
253		relay_parent_number,
254		outputs,
255	)
256}
257
258/// Implementation for the `session_index_for_child` function of the runtime API.
259pub fn session_index_for_child<T: initializer::Config>() -> SessionIndex {
260	// Just returns the session index from `inclusion`. Runtime APIs follow
261	// initialization so the initializer will have applied any pending session change
262	// which is expected at the child of the block whose context the runtime API was invoked
263	// in.
264	//
265	// Incidentally, this is also the rationale for why it is OK to query validators or
266	// occupied cores or etc. and expect the correct response "for child".
267	shared::CurrentSessionIndex::<T>::get()
268}
269
270/// Implementation for the `AuthorityDiscoveryApi::authorities()` function of the runtime API.
271/// It is a heavy call, but currently only used for authority discovery, so it is fine.
272/// Gets next, current and some historical authority ids using `session_info` module.
273pub fn relevant_authority_ids<T: initializer::Config + pallet_authority_discovery::Config>(
274) -> Vec<AuthorityDiscoveryId> {
275	let current_session_index = session_index_for_child::<T>();
276	let earliest_stored_session = session_info::EarliestStoredSession::<T>::get();
277
278	// Due to `max_validators`, the `SessionInfo` stores only the validators who are actively
279	// selected to participate in parachain consensus. We'd like all authorities for the current
280	// and next sessions to be used in authority-discovery. The two sets likely have large overlap.
281	let mut authority_ids = pallet_authority_discovery::Pallet::<T>::current_authorities().to_vec();
282	authority_ids.extend(pallet_authority_discovery::Pallet::<T>::next_authorities().to_vec());
283
284	// Due to disputes, we'd like to remain connected to authorities of the previous few sessions.
285	// For this, we don't need anyone other than the validators actively participating in consensus.
286	for session_index in earliest_stored_session..current_session_index {
287		let info = session_info::Sessions::<T>::get(session_index);
288		if let Some(mut info) = info {
289			authority_ids.append(&mut info.discovery_keys);
290		}
291	}
292
293	authority_ids.sort();
294	authority_ids.dedup();
295
296	authority_ids
297}
298
299/// Implementation for the `validation_code` function of the runtime API.
300pub fn validation_code<T: initializer::Config>(
301	para_id: ParaId,
302	assumption: OccupiedCoreAssumption,
303) -> Option<ValidationCode> {
304	with_assumption::<T, _, _>(para_id, assumption, || paras::Pallet::<T>::current_code(&para_id))
305}
306
307/// Implementation for the `candidate_pending_availability` function of the runtime API.
308#[deprecated(
309	note = "`candidate_pending_availability` will be removed. Use `candidates_pending_availability` to query
310	all candidates pending availability"
311)]
312pub fn candidate_pending_availability<T: initializer::Config>(
313	para_id: ParaId,
314) -> Option<CommittedCandidateReceipt<T::Hash>> {
315	inclusion::Pallet::<T>::first_candidate_pending_availability(para_id)
316}
317
318/// Implementation for the `candidate_events` function of the runtime API.
319// NOTE: this runs without block initialization, as it accesses events.
320// this means it can run in a different session than other runtime APIs at the same block.
321pub fn candidate_events<T, F>(extract_event: F) -> Vec<CandidateEvent<T::Hash>>
322where
323	T: initializer::Config,
324	F: Fn(<T as frame_system::Config>::RuntimeEvent) -> Option<inclusion::Event<T>>,
325{
326	use inclusion::Event as RawEvent;
327
328	frame_system::Pallet::<T>::read_events_no_consensus()
329		.into_iter()
330		.filter_map(|record| extract_event(record.event))
331		.filter_map(|event| {
332			Some(match event {
333				RawEvent::<T>::CandidateBacked(c, h, core, group) => {
334					CandidateEvent::CandidateBacked(c, h, core, group)
335				},
336				RawEvent::<T>::CandidateIncluded(c, h, core, group) => {
337					CandidateEvent::CandidateIncluded(c, h, core, group)
338				},
339				RawEvent::<T>::CandidateTimedOut(c, h, core) => {
340					CandidateEvent::CandidateTimedOut(c, h, core)
341				},
342				// Not needed for candidate events.
343				RawEvent::<T>::UpwardMessagesReceived { .. } => return None,
344				RawEvent::<T>::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
345			})
346		})
347		.collect()
348}
349
350/// Get the session info for the given session, if stored.
351pub fn session_info<T: session_info::Config>(index: SessionIndex) -> Option<SessionInfo> {
352	session_info::Sessions::<T>::get(index)
353}
354
355/// Implementation for the `dmq_contents` function of the runtime API.
356pub fn dmq_contents<T: dmp::Config>(
357	recipient: ParaId,
358) -> Vec<InboundDownwardMessage<BlockNumberFor<T>>> {
359	dmp::Pallet::<T>::dmq_contents(recipient)
360}
361
362/// Implementation for the `inbound_hrmp_channels_contents` function of the runtime API.
363pub fn inbound_hrmp_channels_contents<T: hrmp::Config>(
364	recipient: ParaId,
365) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumberFor<T>>>> {
366	hrmp::Pallet::<T>::inbound_hrmp_channels_contents(recipient)
367}
368
369/// Implementation for the `validation_code_by_hash` function of the runtime API.
370pub fn validation_code_by_hash<T: paras::Config>(
371	hash: ValidationCodeHash,
372) -> Option<ValidationCode> {
373	paras::CodeByHash::<T>::get(hash)
374}
375
376/// Disputes imported via means of on-chain imports.
377pub fn on_chain_votes<T: paras_inherent::Config>() -> Option<ScrapedOnChainVotes<T::Hash>> {
378	paras_inherent::OnChainVotes::<T>::get()
379}
380
381/// Submits an PVF pre-checking vote.
382pub fn submit_pvf_check_statement<T: paras::Config>(
383	stmt: PvfCheckStatement,
384	signature: ValidatorSignature,
385) {
386	paras::Pallet::<T>::submit_pvf_check_statement(stmt, signature)
387}
388
389/// Returns the list of all PVF code hashes that require pre-checking.
390pub fn pvfs_require_precheck<T: paras::Config>() -> Vec<ValidationCodeHash> {
391	paras::Pallet::<T>::pvfs_require_precheck()
392}
393
394/// Returns the validation code hash for the given parachain making the given
395/// `OccupiedCoreAssumption`.
396pub fn validation_code_hash<T>(
397	para_id: ParaId,
398	assumption: OccupiedCoreAssumption,
399) -> Option<ValidationCodeHash>
400where
401	T: inclusion::Config,
402{
403	with_assumption::<T, _, _>(para_id, assumption, || paras::CurrentCodeHash::<T>::get(&para_id))
404}
405
406/// Implementation for `get_session_disputes` function from the runtime API
407pub fn get_session_disputes<T: disputes::Config>(
408) -> Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumberFor<T>>)> {
409	disputes::Pallet::<T>::disputes()
410}
411
412/// Get session executor parameter set
413pub fn session_executor_params<T: session_info::Config>(
414	session_index: SessionIndex,
415) -> Option<ExecutorParams> {
416	session_info::SessionExecutorParams::<T>::get(session_index)
417}
418
419/// Implementation of `unapplied_slashes` runtime API
420pub fn unapplied_slashes<T: disputes::slashing::Config>(
421) -> Vec<(SessionIndex, CandidateHash, slashing::LegacyPendingSlashes)> {
422	disputes::slashing::Pallet::<T>::unapplied_slashes()
423		.into_iter()
424		.filter_map(|(session, candidate_hash, pending_slash)| {
425			let legacy_pending_slash = slashing::LegacyPendingSlashes {
426				keys: pending_slash.keys,
427				kind: pending_slash.kind.try_into().ok()?,
428			};
429			Some((session, candidate_hash, legacy_pending_slash))
430		})
431		.collect()
432}
433
434/// Implementation of `unapplied_slashes_v2` runtime API
435pub fn unapplied_slashes_v2<T: disputes::slashing::Config>(
436) -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)> {
437	disputes::slashing::Pallet::<T>::unapplied_slashes()
438}
439
440/// Implementation of `submit_report_dispute_lost` runtime API
441pub fn submit_unsigned_slashing_report<T: disputes::slashing::Config>(
442	dispute_proof: slashing::DisputeProof,
443	key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
444) -> Option<()> {
445	let key_ownership_proof = key_ownership_proof.decode()?;
446
447	disputes::slashing::Pallet::<T>::submit_unsigned_slashing_report(
448		dispute_proof,
449		key_ownership_proof,
450	)
451}
452
453/// Return the min backing votes threshold from the configuration.
454pub fn minimum_backing_votes<T: initializer::Config>() -> u32 {
455	configuration::ActiveConfig::<T>::get().minimum_backing_votes
456}
457
458// Helper function that returns the backing constraints given a parachain id.
459pub fn backing_constraints<T: initializer::Config>(
460	para_id: ParaId,
461) -> Option<Constraints<BlockNumberFor<T>>> {
462	let config = configuration::ActiveConfig::<T>::get();
463	let now = frame_system::Pallet::<T>::block_number();
464
465	// Workaround for issue #64.
466	let min_global_relay_parent_number = if shared::Pallet::<T>::on_chain_storage_version() ==
467		StorageVersion::new(1)
468	{
469		shared::migration::v1::AllowedRelayParents::<T>::get().hypothetical_earliest_block_number(
470			now,
471			config.scheduler_params.lookahead.saturating_sub(1),
472		)
473	} else {
474		shared::Pallet::<T>::get_minimum_relay_parent_number().unwrap_or(now)
475	};
476
477	let min_para_relay_parent_number = inclusion::Pallet::<T>::para_most_recent_context(&para_id)
478		.map(|ctx| core::cmp::max(ctx, min_global_relay_parent_number))
479		.unwrap_or(min_global_relay_parent_number);
480
481	let required_parent = paras::Heads::<T>::get(para_id)?;
482	let validation_code_hash = paras::CurrentCodeHash::<T>::get(para_id)?;
483
484	let upgrade_restriction = paras::UpgradeRestrictionSignal::<T>::get(para_id);
485	let future_validation_code =
486		paras::FutureCodeUpgrades::<T>::get(para_id).and_then(|block_num| {
487			// Only read the storage if there's a pending upgrade.
488			Some(block_num).zip(paras::FutureCodeHash::<T>::get(para_id))
489		});
490
491	let (ump_msg_count, ump_total_bytes) =
492		inclusion::Pallet::<T>::relay_dispatch_queue_size(para_id);
493	let ump_remaining = config.max_upward_queue_count - ump_msg_count;
494	let ump_remaining_bytes = config.max_upward_queue_size - ump_total_bytes;
495
496	let dmp_remaining_messages = dmp::Pallet::<T>::dmq_contents(para_id)
497		.into_iter()
498		.map(|msg| msg.sent_at)
499		.collect();
500
501	let valid_watermarks = hrmp::Pallet::<T>::valid_watermarks(para_id);
502	let hrmp_inbound = InboundHrmpLimitations { valid_watermarks };
503	let hrmp_channels_out = hrmp::Pallet::<T>::outbound_remaining_capacity(para_id)
504		.into_iter()
505		.map(|(para, (messages_remaining, bytes_remaining))| {
506			(para, OutboundHrmpChannelLimitations { messages_remaining, bytes_remaining })
507		})
508		.collect();
509
510	Some(Constraints {
511		min_relay_parent_number: min_para_relay_parent_number,
512		max_pov_size: config.max_pov_size,
513		max_code_size: config.max_code_size,
514		max_head_data_size: Constraints::<BlockNumberFor<T>>::DEFAULT_MAX_HEAD_DATA_SIZE,
515		ump_remaining,
516		ump_remaining_bytes,
517		max_ump_num_per_candidate: config.max_upward_message_num_per_candidate,
518		dmp_remaining_messages,
519		hrmp_inbound,
520		hrmp_channels_out,
521		max_hrmp_num_per_candidate: config.hrmp_max_message_num_per_candidate,
522		required_parent,
523		validation_code_hash,
524		upgrade_restriction,
525		future_validation_code,
526	})
527}
528
529/// Implementation for `ParaBackingState` function from the runtime API
530#[deprecated(note = "`backing_state` will be removed. Use `backing_constraints` and
531	`candidates_pending_availability` instead.")]
532pub fn backing_state<T: initializer::Config>(
533	para_id: ParaId,
534) -> Option<BackingState<T::Hash, BlockNumberFor<T>>> {
535	let constraints = backing_constraints::<T>(para_id)?;
536
537	let pending_availability = {
538		crate::inclusion::PendingAvailability::<T>::get(&para_id)
539			.map(|pending_candidates| {
540				pending_candidates
541					.into_iter()
542					.map(|candidate| {
543						CandidatePendingAvailability {
544							candidate_hash: candidate.candidate_hash(),
545							descriptor: candidate.candidate_descriptor().clone(),
546							commitments: candidate.candidate_commitments().clone(),
547							relay_parent_number: candidate.relay_parent_number(),
548							max_pov_size: constraints.max_pov_size, /* assume always same in
549							                                         * session. */
550						}
551					})
552					.collect()
553			})
554			.unwrap_or_else(|| vec![])
555	};
556
557	Some(BackingState { constraints, pending_availability })
558}
559
560/// Implementation for `AsyncBackingParams` function from the runtime API
561#[deprecated = "AsyncBackingParams are going to be removed and ignored by relay chain validators, in favour of dynamically computed values based on the claim queue assignments"]
562pub fn async_backing_params<T: configuration::Config>() -> AsyncBackingParams {
563	configuration::ActiveConfig::<T>::get().async_backing_params
564}
565
566/// Implementation for `DisabledValidators`
567// CAVEAT: this should only be called on the node side
568// as it might produce incorrect results on session boundaries
569pub fn disabled_validators<T>() -> Vec<ValidatorIndex>
570where
571	T: shared::Config,
572{
573	<shared::Pallet<T>>::disabled_validators()
574}
575
576/// Returns the current state of the node features.
577pub fn node_features<T: initializer::Config>() -> NodeFeatures {
578	configuration::ActiveConfig::<T>::get().node_features
579}
580
581/// Approval voting subsystem configuration parameters
582pub fn approval_voting_params<T: initializer::Config>() -> ApprovalVotingParams {
583	configuration::ActiveConfig::<T>::get().approval_voting_params
584}
585
586/// Returns the claimqueue from the scheduler
587pub fn claim_queue<T: scheduler::Config>() -> BTreeMap<CoreIndex, VecDeque<ParaId>> {
588	scheduler::Pallet::<T>::claim_queue()
589}
590
591/// Returns all the candidates that are pending availability for a given `ParaId`.
592/// Deprecates `candidate_pending_availability` in favor of supporting elastic scaling.
593pub fn candidates_pending_availability<T: initializer::Config>(
594	para_id: ParaId,
595) -> Vec<CommittedCandidateReceipt<T::Hash>> {
596	<inclusion::Pallet<T>>::candidates_pending_availability(para_id)
597}
598
599/// Implementation for `validation_code_bomb_limit` function from the runtime API
600pub fn validation_code_bomb_limit<T: initializer::Config>() -> u32 {
601	configuration::ActiveConfig::<T>::get().max_code_size *
602		configuration::MAX_VALIDATION_CODE_COMPRESSION_RATIO
603}
604
605/// Implementation for `scheduling_lookahead` function from the runtime API
606pub fn scheduling_lookahead<T: initializer::Config>() -> u32 {
607	configuration::ActiveConfig::<T>::get().scheduler_params.lookahead
608}