// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

use std::collections::{btree_map::BTreeMap, VecDeque};

use schnellru::{ByLength, LruMap};
use sp_consensus_babe::Epoch;

use polkadot_primitives::{
	async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber,
	CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex,
	CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId,
	InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption,
	PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo,
	ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
};

/// For consistency we have the same capacity for all caches. We use 128 as we'll only need that
/// much if finality stalls (we only query state for unfinalized blocks + maybe latest finalized).
/// In any case, a cache is an optimization. We should avoid a situation where having a large cache
/// leads to OOM or puts pressure on other important stuff like PVF execution/preparation.
const DEFAULT_CACHE_CAP: u32 = 128;

pub(crate) struct RequestResultCache {
	authorities: LruMap<Hash, Vec<AuthorityDiscoveryId>>,
	validators: LruMap<Hash, Vec<ValidatorId>>,
	validator_groups: LruMap<Hash, (Vec<Vec<ValidatorIndex>>, GroupRotationInfo)>,
	availability_cores: LruMap<Hash, Vec<CoreState>>,
	persisted_validation_data:
		LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option<PersistedValidationData>>,
	assumed_validation_data:
		LruMap<(ParaId, Hash), Option<(PersistedValidationData, ValidationCodeHash)>>,
	check_validation_outputs: LruMap<(Hash, ParaId, CandidateCommitments), bool>,
	session_index_for_child: LruMap<Hash, SessionIndex>,
	validation_code: LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option<ValidationCode>>,
	validation_code_by_hash: LruMap<ValidationCodeHash, Option<ValidationCode>>,
	candidate_pending_availability: LruMap<(Hash, ParaId), Option<CommittedCandidateReceipt>>,
	candidate_events: LruMap<Hash, Vec<CandidateEvent>>,
	session_executor_params: LruMap<SessionIndex, Option<ExecutorParams>>,
	session_info: LruMap<SessionIndex, SessionInfo>,
	dmq_contents: LruMap<(Hash, ParaId), Vec<InboundDownwardMessage<BlockNumber>>>,
	inbound_hrmp_channels_contents:
		LruMap<(Hash, ParaId), BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>>,
	current_babe_epoch: LruMap<Hash, Epoch>,
	on_chain_votes: LruMap<Hash, Option<ScrapedOnChainVotes>>,
	pvfs_require_precheck: LruMap<Hash, Vec<ValidationCodeHash>>,
	validation_code_hash:
		LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option<ValidationCodeHash>>,
	version: LruMap<Hash, u32>,
	disputes: LruMap<Hash, Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>>,
	unapplied_slashes: LruMap<Hash, Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>>,
	key_ownership_proof: LruMap<(Hash, ValidatorId), Option<slashing::OpaqueKeyOwnershipProof>>,
	minimum_backing_votes: LruMap<SessionIndex, u32>,
	disabled_validators: LruMap<Hash, Vec<ValidatorIndex>>,
	para_backing_state: LruMap<(Hash, ParaId), Option<async_backing::BackingState>>,
	async_backing_params: LruMap<Hash, async_backing::AsyncBackingParams>,
	node_features: LruMap<SessionIndex, NodeFeatures>,
	approval_voting_params: LruMap<SessionIndex, ApprovalVotingParams>,
	claim_queue: LruMap<Hash, BTreeMap<CoreIndex, VecDeque<ParaId>>>,
}

impl Default for RequestResultCache {
	fn default() -> Self {
		Self {
			authorities: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			validators: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			validator_groups: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			availability_cores: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			persisted_validation_data: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			assumed_validation_data: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			check_validation_outputs: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			session_index_for_child: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			validation_code: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			validation_code_by_hash: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			candidate_pending_availability: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			candidate_events: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			session_executor_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			session_info: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			dmq_contents: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			inbound_hrmp_channels_contents: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			current_babe_epoch: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			on_chain_votes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			pvfs_require_precheck: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			validation_code_hash: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			version: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			disputes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			unapplied_slashes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			key_ownership_proof: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			minimum_backing_votes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			approval_voting_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			disabled_validators: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			node_features: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
			claim_queue: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
		}
	}
}

impl RequestResultCache {
	pub(crate) fn authorities(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&Vec<AuthorityDiscoveryId>> {
		self.authorities.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_authorities(
		&mut self,
		relay_parent: Hash,
		authorities: Vec<AuthorityDiscoveryId>,
	) {
		self.authorities.insert(relay_parent, authorities);
	}

	pub(crate) fn validators(&mut self, relay_parent: &Hash) -> Option<&Vec<ValidatorId>> {
		self.validators.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_validators(&mut self, relay_parent: Hash, validators: Vec<ValidatorId>) {
		self.validators.insert(relay_parent, validators);
	}

	pub(crate) fn validator_groups(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&(Vec<Vec<ValidatorIndex>>, GroupRotationInfo)> {
		self.validator_groups.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_validator_groups(
		&mut self,
		relay_parent: Hash,
		groups: (Vec<Vec<ValidatorIndex>>, GroupRotationInfo),
	) {
		self.validator_groups.insert(relay_parent, groups);
	}

	pub(crate) fn availability_cores(&mut self, relay_parent: &Hash) -> Option<&Vec<CoreState>> {
		self.availability_cores.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_availability_cores(&mut self, relay_parent: Hash, cores: Vec<CoreState>) {
		self.availability_cores.insert(relay_parent, cores);
	}

	pub(crate) fn persisted_validation_data(
		&mut self,
		key: (Hash, ParaId, OccupiedCoreAssumption),
	) -> Option<&Option<PersistedValidationData>> {
		self.persisted_validation_data.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_persisted_validation_data(
		&mut self,
		key: (Hash, ParaId, OccupiedCoreAssumption),
		data: Option<PersistedValidationData>,
	) {
		self.persisted_validation_data.insert(key, data);
	}

	pub(crate) fn assumed_validation_data(
		&mut self,
		key: (Hash, ParaId, Hash),
	) -> Option<&Option<(PersistedValidationData, ValidationCodeHash)>> {
		self.assumed_validation_data.get(&(key.1, key.2)).map(|v| &*v)
	}

	pub(crate) fn cache_assumed_validation_data(
		&mut self,
		key: (ParaId, Hash),
		data: Option<(PersistedValidationData, ValidationCodeHash)>,
	) {
		self.assumed_validation_data.insert(key, data);
	}

	pub(crate) fn check_validation_outputs(
		&mut self,
		key: (Hash, ParaId, CandidateCommitments),
	) -> Option<&bool> {
		self.check_validation_outputs.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_check_validation_outputs(
		&mut self,
		key: (Hash, ParaId, CandidateCommitments),
		value: bool,
	) {
		self.check_validation_outputs.insert(key, value);
	}

	pub(crate) fn session_index_for_child(&mut self, relay_parent: &Hash) -> Option<&SessionIndex> {
		self.session_index_for_child.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_session_index_for_child(
		&mut self,
		relay_parent: Hash,
		index: SessionIndex,
	) {
		self.session_index_for_child.insert(relay_parent, index);
	}

	pub(crate) fn validation_code(
		&mut self,
		key: (Hash, ParaId, OccupiedCoreAssumption),
	) -> Option<&Option<ValidationCode>> {
		self.validation_code.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_validation_code(
		&mut self,
		key: (Hash, ParaId, OccupiedCoreAssumption),
		value: Option<ValidationCode>,
	) {
		self.validation_code.insert(key, value);
	}

	// the actual key is `ValidationCodeHash` (`Hash` is ignored),
	// but we keep the interface that way to keep the macro simple
	pub(crate) fn validation_code_by_hash(
		&mut self,
		key: (Hash, ValidationCodeHash),
	) -> Option<&Option<ValidationCode>> {
		self.validation_code_by_hash.get(&key.1).map(|v| &*v)
	}

	pub(crate) fn cache_validation_code_by_hash(
		&mut self,
		key: ValidationCodeHash,
		value: Option<ValidationCode>,
	) {
		self.validation_code_by_hash.insert(key, value);
	}

	pub(crate) fn candidate_pending_availability(
		&mut self,
		key: (Hash, ParaId),
	) -> Option<&Option<CommittedCandidateReceipt>> {
		self.candidate_pending_availability.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_candidate_pending_availability(
		&mut self,
		key: (Hash, ParaId),
		value: Option<CommittedCandidateReceipt>,
	) {
		self.candidate_pending_availability.insert(key, value);
	}

	pub(crate) fn candidate_events(&mut self, relay_parent: &Hash) -> Option<&Vec<CandidateEvent>> {
		self.candidate_events.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_candidate_events(
		&mut self,
		relay_parent: Hash,
		events: Vec<CandidateEvent>,
	) {
		self.candidate_events.insert(relay_parent, events);
	}

	pub(crate) fn session_info(&mut self, key: SessionIndex) -> Option<&SessionInfo> {
		self.session_info.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_session_info(&mut self, key: SessionIndex, value: SessionInfo) {
		self.session_info.insert(key, value);
	}

	pub(crate) fn session_executor_params(
		&mut self,
		session_index: SessionIndex,
	) -> Option<&Option<ExecutorParams>> {
		self.session_executor_params.get(&session_index).map(|v| &*v)
	}

	pub(crate) fn cache_session_executor_params(
		&mut self,
		session_index: SessionIndex,
		value: Option<ExecutorParams>,
	) {
		self.session_executor_params.insert(session_index, value);
	}

	pub(crate) fn dmq_contents(
		&mut self,
		key: (Hash, ParaId),
	) -> Option<&Vec<InboundDownwardMessage<BlockNumber>>> {
		self.dmq_contents.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_dmq_contents(
		&mut self,
		key: (Hash, ParaId),
		value: Vec<InboundDownwardMessage<BlockNumber>>,
	) {
		self.dmq_contents.insert(key, value);
	}

	pub(crate) fn inbound_hrmp_channels_contents(
		&mut self,
		key: (Hash, ParaId),
	) -> Option<&BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>> {
		self.inbound_hrmp_channels_contents.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_inbound_hrmp_channel_contents(
		&mut self,
		key: (Hash, ParaId),
		value: BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>,
	) {
		self.inbound_hrmp_channels_contents.insert(key, value);
	}

	pub(crate) fn current_babe_epoch(&mut self, relay_parent: &Hash) -> Option<&Epoch> {
		self.current_babe_epoch.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_current_babe_epoch(&mut self, relay_parent: Hash, epoch: Epoch) {
		self.current_babe_epoch.insert(relay_parent, epoch);
	}

	pub(crate) fn on_chain_votes(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&Option<ScrapedOnChainVotes>> {
		self.on_chain_votes.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_on_chain_votes(
		&mut self,
		relay_parent: Hash,
		scraped: Option<ScrapedOnChainVotes>,
	) {
		self.on_chain_votes.insert(relay_parent, scraped);
	}

	pub(crate) fn pvfs_require_precheck(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&Vec<ValidationCodeHash>> {
		self.pvfs_require_precheck.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_pvfs_require_precheck(
		&mut self,
		relay_parent: Hash,
		pvfs: Vec<ValidationCodeHash>,
	) {
		self.pvfs_require_precheck.insert(relay_parent, pvfs);
	}

	pub(crate) fn validation_code_hash(
		&mut self,
		key: (Hash, ParaId, OccupiedCoreAssumption),
	) -> Option<&Option<ValidationCodeHash>> {
		self.validation_code_hash.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_validation_code_hash(
		&mut self,
		key: (Hash, ParaId, OccupiedCoreAssumption),
		value: Option<ValidationCodeHash>,
	) {
		self.validation_code_hash.insert(key, value);
	}

	pub(crate) fn version(&mut self, relay_parent: &Hash) -> Option<&u32> {
		self.version.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_version(&mut self, key: Hash, value: u32) {
		self.version.insert(key, value);
	}

	pub(crate) fn disputes(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>> {
		self.disputes.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_disputes(
		&mut self,
		relay_parent: Hash,
		value: Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>,
	) {
		self.disputes.insert(relay_parent, value);
	}

	pub(crate) fn unapplied_slashes(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>> {
		self.unapplied_slashes.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_unapplied_slashes(
		&mut self,
		relay_parent: Hash,
		value: Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>,
	) {
		self.unapplied_slashes.insert(relay_parent, value);
	}

	pub(crate) fn key_ownership_proof(
		&mut self,
		key: (Hash, ValidatorId),
	) -> Option<&Option<slashing::OpaqueKeyOwnershipProof>> {
		self.key_ownership_proof.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_key_ownership_proof(
		&mut self,
		key: (Hash, ValidatorId),
		value: Option<slashing::OpaqueKeyOwnershipProof>,
	) {
		self.key_ownership_proof.insert(key, value);
	}

	// This request is never cached, hence always returns `None`.
	pub(crate) fn submit_report_dispute_lost(
		&mut self,
		_key: (Hash, slashing::DisputeProof, slashing::OpaqueKeyOwnershipProof),
	) -> Option<&Option<()>> {
		None
	}

	pub(crate) fn minimum_backing_votes(&mut self, session_index: SessionIndex) -> Option<u32> {
		self.minimum_backing_votes.get(&session_index).copied()
	}

	pub(crate) fn cache_minimum_backing_votes(
		&mut self,
		session_index: SessionIndex,
		minimum_backing_votes: u32,
	) {
		self.minimum_backing_votes.insert(session_index, minimum_backing_votes);
	}

	pub(crate) fn node_features(&mut self, session_index: SessionIndex) -> Option<&NodeFeatures> {
		self.node_features.get(&session_index).map(|f| &*f)
	}

	pub(crate) fn cache_node_features(
		&mut self,
		session_index: SessionIndex,
		features: NodeFeatures,
	) {
		self.node_features.insert(session_index, features);
	}

	pub(crate) fn disabled_validators(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&Vec<ValidatorIndex>> {
		self.disabled_validators.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_disabled_validators(
		&mut self,
		relay_parent: Hash,
		disabled_validators: Vec<ValidatorIndex>,
	) {
		self.disabled_validators.insert(relay_parent, disabled_validators);
	}

	pub(crate) fn para_backing_state(
		&mut self,
		key: (Hash, ParaId),
	) -> Option<&Option<async_backing::BackingState>> {
		self.para_backing_state.get(&key).map(|v| &*v)
	}

	pub(crate) fn cache_para_backing_state(
		&mut self,
		key: (Hash, ParaId),
		value: Option<async_backing::BackingState>,
	) {
		self.para_backing_state.insert(key, value);
	}

	pub(crate) fn async_backing_params(
		&mut self,
		key: &Hash,
	) -> Option<&async_backing::AsyncBackingParams> {
		self.async_backing_params.get(key).map(|v| &*v)
	}

	pub(crate) fn cache_async_backing_params(
		&mut self,
		key: Hash,
		value: async_backing::AsyncBackingParams,
	) {
		self.async_backing_params.insert(key, value);
	}

	pub(crate) fn approval_voting_params(
		&mut self,
		key: (Hash, SessionIndex),
	) -> Option<&ApprovalVotingParams> {
		self.approval_voting_params.get(&key.1).map(|v| &*v)
	}

	pub(crate) fn cache_approval_voting_params(
		&mut self,
		session_index: SessionIndex,
		value: ApprovalVotingParams,
	) {
		self.approval_voting_params.insert(session_index, value);
	}

	pub(crate) fn claim_queue(
		&mut self,
		relay_parent: &Hash,
	) -> Option<&BTreeMap<CoreIndex, VecDeque<ParaId>>> {
		self.claim_queue.get(relay_parent).map(|v| &*v)
	}

	pub(crate) fn cache_claim_queue(
		&mut self,
		relay_parent: Hash,
		value: BTreeMap<CoreIndex, VecDeque<ParaId>>,
	) {
		self.claim_queue.insert(relay_parent, value);
	}
}

pub(crate) enum RequestResult {
	// The structure of each variant is (relay_parent, [params,]*, result)
	Authorities(Hash, Vec<AuthorityDiscoveryId>),
	Validators(Hash, Vec<ValidatorId>),
	MinimumBackingVotes(Hash, SessionIndex, u32),
	ValidatorGroups(Hash, (Vec<Vec<ValidatorIndex>>, GroupRotationInfo)),
	AvailabilityCores(Hash, Vec<CoreState>),
	PersistedValidationData(Hash, ParaId, OccupiedCoreAssumption, Option<PersistedValidationData>),
	AssumedValidationData(
		Hash,
		ParaId,
		Hash,
		Option<(PersistedValidationData, ValidationCodeHash)>,
	),
	CheckValidationOutputs(Hash, ParaId, CandidateCommitments, bool),
	SessionIndexForChild(Hash, SessionIndex),
	ValidationCode(Hash, ParaId, OccupiedCoreAssumption, Option<ValidationCode>),
	ValidationCodeByHash(Hash, ValidationCodeHash, Option<ValidationCode>),
	CandidatePendingAvailability(Hash, ParaId, Option<CommittedCandidateReceipt>),
	CandidateEvents(Hash, Vec<CandidateEvent>),
	SessionExecutorParams(Hash, SessionIndex, Option<ExecutorParams>),
	SessionInfo(Hash, SessionIndex, Option<SessionInfo>),
	DmqContents(Hash, ParaId, Vec<InboundDownwardMessage<BlockNumber>>),
	InboundHrmpChannelsContents(
		Hash,
		ParaId,
		BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>,
	),
	CurrentBabeEpoch(Hash, Epoch),
	FetchOnChainVotes(Hash, Option<ScrapedOnChainVotes>),
	PvfsRequirePrecheck(Hash, Vec<ValidationCodeHash>),
	// This is a request with side-effects and no result, hence ().
	SubmitPvfCheckStatement(Hash, PvfCheckStatement, ValidatorSignature, ()),
	ValidationCodeHash(Hash, ParaId, OccupiedCoreAssumption, Option<ValidationCodeHash>),
	Version(Hash, u32),
	Disputes(Hash, Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>),
	UnappliedSlashes(Hash, Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>),
	KeyOwnershipProof(Hash, ValidatorId, Option<slashing::OpaqueKeyOwnershipProof>),
	// This is a request with side-effects.
	SubmitReportDisputeLost(
		Hash,
		slashing::DisputeProof,
		slashing::OpaqueKeyOwnershipProof,
		Option<()>,
	),
	ApprovalVotingParams(Hash, SessionIndex, ApprovalVotingParams),
	DisabledValidators(Hash, Vec<ValidatorIndex>),
	ParaBackingState(Hash, ParaId, Option<async_backing::BackingState>),
	AsyncBackingParams(Hash, async_backing::AsyncBackingParams),
	NodeFeatures(SessionIndex, NodeFeatures),
	ClaimQueue(Hash, BTreeMap<CoreIndex, VecDeque<ParaId>>),
}
