referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/
configuration.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//! Configuration manager for the Polkadot runtime parachains logic.
18//!
19//! Configuration can change only at session boundaries and is buffered until then.
20
21use crate::shared;
22use alloc::vec::Vec;
23use codec::{Decode, Encode};
24use frame_support::{pallet_prelude::*, DefaultNoBound};
25use frame_system::pallet_prelude::*;
26use polkadot_parachain_primitives::primitives::{
27	MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM,
28};
29use polkadot_primitives::{
30	ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams,
31	NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE,
32	ON_DEMAND_MAX_QUEUE_MAX_SIZE,
33};
34use sp_runtime::{traits::Zero, Perbill, Percent};
35
36#[cfg(test)]
37mod tests;
38
39#[cfg(feature = "runtime-benchmarks")]
40mod benchmarking;
41
42pub mod migration;
43
44pub use pallet::*;
45use polkadot_primitives::SchedulerParams;
46
47const LOG_TARGET: &str = "runtime::configuration";
48
49// This value is derived from network layer limits. See `sc_network::MAX_RESPONSE_SIZE` and
50// `polkadot_node_network_protocol::POV_RESPONSE_SIZE`.
51const POV_SIZE_HARD_LIMIT: u32 = 16 * 1024 * 1024;
52
53// The maximum compression ratio that we use to compute the maximum uncompressed code size.
54pub(crate) const MAX_VALIDATION_CODE_COMPRESSION_RATIO: u32 = 10;
55
56/// All configuration of the runtime with respect to paras.
57#[derive(
58	Clone,
59	Encode,
60	Decode,
61	PartialEq,
62	sp_core::RuntimeDebug,
63	scale_info::TypeInfo,
64	serde::Serialize,
65	serde::Deserialize,
66)]
67#[serde(deny_unknown_fields)]
68pub struct HostConfiguration<BlockNumber> {
69	// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct
70	// requires special treatment.
71	//
72	// A parachain requested this struct can only depend on the subset of this struct.
73	// Specifically, only a first few fields can be depended upon. These fields cannot be changed
74	// without corresponding migration of the parachains.
75	/**
76	 * The parameters that are required for the parachains.
77	 */
78
79	/// The maximum validation code size, in bytes.
80	pub max_code_size: u32,
81	/// The maximum head-data size, in bytes.
82	pub max_head_data_size: u32,
83	/// Total number of individual messages allowed in the parachain -> relay-chain message queue.
84	pub max_upward_queue_count: u32,
85	/// Total size of messages allowed in the parachain -> relay-chain message queue before which
86	/// no further messages may be added to it. If it exceeds this then the queue may contain only
87	/// a single message.
88	pub max_upward_queue_size: u32,
89	/// The maximum size of an upward message that can be sent by a candidate.
90	///
91	/// This parameter affects the size upper bound of the `CandidateCommitments`.
92	pub max_upward_message_size: u32,
93	/// The maximum number of messages that a candidate can contain.
94	///
95	/// This parameter affects the size upper bound of the `CandidateCommitments`.
96	pub max_upward_message_num_per_candidate: u32,
97	/// The maximum number of outbound HRMP messages can be sent by a candidate.
98	///
99	/// This parameter affects the upper bound of size of `CandidateCommitments`.
100	pub hrmp_max_message_num_per_candidate: u32,
101	/// The minimum period, in blocks, between which parachains can update their validation code.
102	///
103	/// This number is used to prevent parachains from spamming the relay chain with validation
104	/// code upgrades. The only thing it controls is the number of blocks the
105	/// `UpgradeRestrictionSignal` is set for the parachain in question.
106	///
107	/// If PVF pre-checking is enabled this should be greater than the maximum number of blocks
108	/// PVF pre-checking can take. Intuitively, this number should be greater than the duration
109	/// specified by [`pvf_voting_ttl`](Self::pvf_voting_ttl). Unlike,
110	/// [`pvf_voting_ttl`](Self::pvf_voting_ttl), this parameter uses blocks as a unit.
111	#[cfg_attr(feature = "std", serde(alias = "validation_upgrade_frequency"))]
112	pub validation_upgrade_cooldown: BlockNumber,
113	/// The delay, in blocks, after which an upgrade of the validation code is applied.
114	///
115	/// The upgrade for a parachain takes place when the first candidate which has relay-parent >=
116	/// the relay-chain block where the upgrade is scheduled. This block is referred as to
117	/// `expected_at`.
118	///
119	/// `expected_at` is determined when the upgrade is scheduled. This happens when the candidate
120	/// that signals the upgrade is enacted. Right now, the relay-parent block number of the
121	/// candidate scheduling the upgrade is used to determine the `expected_at`. This may change in
122	/// the future with [#4601].
123	///
124	/// When PVF pre-checking is enabled, the upgrade is scheduled only after the PVF pre-check has
125	/// been completed.
126	///
127	/// Note, there are situations in which `expected_at` in the past. For example, if
128	/// [`paras_availability_period`](SchedulerParams::paras_availability_period) is less than the
129	/// delay set by this field or if PVF pre-check took more time than the delay. In such cases,
130	/// the upgrade is further at the earliest possible time determined by
131	/// [`minimum_validation_upgrade_delay`](Self::minimum_validation_upgrade_delay).
132	///
133	/// The rationale for this delay has to do with relay-chain reversions. In case there is an
134	/// invalid candidate produced with the new version of the code, then the relay-chain can
135	/// revert [`validation_upgrade_delay`](Self::validation_upgrade_delay) many blocks back and
136	/// still find the new code in the storage by hash.
137	///
138	/// [#4601]: https://github.com/paritytech/polkadot/issues/4601
139	pub validation_upgrade_delay: BlockNumber,
140	/// Asynchronous backing parameters.
141	pub async_backing_params: AsyncBackingParams,
142
143	/**
144	 * The parameters that are not essential, but still may be of interest for parachains.
145	 */
146
147	/// The maximum POV block size, in bytes.
148	pub max_pov_size: u32,
149	/// The maximum size of a message that can be put in a downward message queue.
150	///
151	/// Since we require receiving at least one DMP message the obvious upper bound of the size is
152	/// the PoV size. Of course, there is a lot of other different things that a parachain may
153	/// decide to do with its PoV so this value in practice will be picked as a fraction of the PoV
154	/// size.
155	pub max_downward_message_size: u32,
156	/// The maximum number of outbound HRMP channels a parachain is allowed to open.
157	pub hrmp_max_parachain_outbound_channels: u32,
158	/// The deposit that the sender should provide for opening an HRMP channel.
159	pub hrmp_sender_deposit: Balance,
160	/// The deposit that the recipient should provide for accepting opening an HRMP channel.
161	pub hrmp_recipient_deposit: Balance,
162	/// The maximum number of messages allowed in an HRMP channel at once.
163	pub hrmp_channel_max_capacity: u32,
164	/// The maximum total size of messages in bytes allowed in an HRMP channel at once.
165	pub hrmp_channel_max_total_size: u32,
166	/// The maximum number of inbound HRMP channels a parachain is allowed to accept.
167	pub hrmp_max_parachain_inbound_channels: u32,
168	/// The maximum size of a message that could ever be put into an HRMP channel.
169	///
170	/// This parameter affects the upper bound of size of `CandidateCommitments`.
171	pub hrmp_channel_max_message_size: u32,
172	/// The executor environment parameters
173	pub executor_params: ExecutorParams,
174
175	/**
176	 * Parameters that will unlikely be needed by parachains.
177	 */
178
179	/// How long to keep code on-chain, in blocks. This should be sufficiently long that disputes
180	/// have concluded.
181	pub code_retention_period: BlockNumber,
182
183	/// The maximum number of validators to use for parachain consensus, period.
184	///
185	/// `None` means no maximum.
186	pub max_validators: Option<u32>,
187	/// The amount of sessions to keep for disputes.
188	pub dispute_period: SessionIndex,
189	/// How long after dispute conclusion to accept statements.
190	pub dispute_post_conclusion_acceptance_period: BlockNumber,
191	/// The amount of consensus slots that must pass between submitting an assignment and
192	/// submitting an approval vote before a validator is considered a no-show.
193	///
194	/// Must be at least 1.
195	pub no_show_slots: u32,
196	/// The number of delay tranches in total. Must be at least 1.
197	pub n_delay_tranches: u32,
198	/// The width of the zeroth delay tranche for approval assignments. This many delay tranches
199	/// beyond 0 are all consolidated to form a wide 0 tranche.
200	pub zeroth_delay_tranche_width: u32,
201	/// The number of validators needed to approve a block.
202	pub needed_approvals: u32,
203	/// The number of samples to do of the `RelayVRFModulo` approval assignment criterion.
204	pub relay_vrf_modulo_samples: u32,
205	/// If an active PVF pre-checking vote observes this many number of sessions it gets
206	/// automatically rejected.
207	///
208	/// 0 means PVF pre-checking will be rejected on the first observed session unless the voting
209	/// gained supermajority before that the session change.
210	pub pvf_voting_ttl: SessionIndex,
211	/// The lower bound number of blocks an upgrade can be scheduled.
212	///
213	/// Typically, upgrade gets scheduled
214	/// [`validation_upgrade_delay`](Self::validation_upgrade_delay) relay-chain blocks after
215	/// the relay-parent of the parablock that signalled the validation code upgrade. However,
216	/// in the case a pre-checking voting was concluded in a longer duration the upgrade will be
217	/// scheduled to the next block.
218	///
219	/// That can disrupt parachain inclusion. Specifically, it will make the blocks that were
220	/// already backed invalid.
221	///
222	/// To prevent that, we introduce the minimum number of blocks after which the upgrade can be
223	/// scheduled. This number is controlled by this field.
224	///
225	/// This value should be greater than
226	/// [`paras_availability_period`](SchedulerParams::paras_availability_period).
227	pub minimum_validation_upgrade_delay: BlockNumber,
228	/// The minimum number of valid backing statements required to consider a parachain candidate
229	/// backable.
230	pub minimum_backing_votes: u32,
231	/// Node features enablement.
232	pub node_features: NodeFeatures,
233	/// Params used by approval-voting
234	pub approval_voting_params: ApprovalVotingParams,
235	/// Scheduler parameters
236	pub scheduler_params: SchedulerParams<BlockNumber>,
237}
238
239impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber> {
240	fn default() -> Self {
241		let ret = Self {
242			async_backing_params: AsyncBackingParams {
243				max_candidate_depth: 0,
244				allowed_ancestry_len: 0,
245			},
246			no_show_slots: 1u32.into(),
247			validation_upgrade_cooldown: Default::default(),
248			validation_upgrade_delay: 2u32.into(),
249			code_retention_period: Default::default(),
250			max_code_size: MAX_CODE_SIZE,
251			max_pov_size: Default::default(),
252			max_head_data_size: Default::default(),
253			max_validators: None,
254			dispute_period: 6,
255			dispute_post_conclusion_acceptance_period: 100.into(),
256			n_delay_tranches: 1,
257			zeroth_delay_tranche_width: Default::default(),
258			needed_approvals: Default::default(),
259			relay_vrf_modulo_samples: Default::default(),
260			max_upward_queue_count: Default::default(),
261			max_upward_queue_size: Default::default(),
262			max_downward_message_size: Default::default(),
263			max_upward_message_size: Default::default(),
264			max_upward_message_num_per_candidate: Default::default(),
265			hrmp_sender_deposit: Default::default(),
266			hrmp_recipient_deposit: Default::default(),
267			hrmp_channel_max_capacity: Default::default(),
268			hrmp_channel_max_total_size: Default::default(),
269			hrmp_max_parachain_inbound_channels: Default::default(),
270			hrmp_channel_max_message_size: Default::default(),
271			hrmp_max_parachain_outbound_channels: Default::default(),
272			hrmp_max_message_num_per_candidate: Default::default(),
273			pvf_voting_ttl: 2u32.into(),
274			minimum_validation_upgrade_delay: 2.into(),
275			executor_params: Default::default(),
276			approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 },
277			minimum_backing_votes: LEGACY_MIN_BACKING_VOTES,
278			node_features: NodeFeatures::EMPTY,
279			scheduler_params: Default::default(),
280		};
281
282		#[cfg(feature = "runtime-benchmarks")]
283		let ret = ret.with_benchmarking_default();
284		ret
285	}
286}
287
288#[cfg(feature = "runtime-benchmarks")]
289impl<BlockNumber: Default + From<u32>> HostConfiguration<BlockNumber> {
290	/// Mutate the values of self to be good estimates for benchmarking.
291	///
292	/// The values do not need to be worst-case, since the benchmarking logic extrapolates. They
293	/// should be a bit more than usually expected.
294	fn with_benchmarking_default(mut self) -> Self {
295		self.max_head_data_size = self.max_head_data_size.max(1 << 20);
296		self.max_downward_message_size = self.max_downward_message_size.max(1 << 16);
297		self.hrmp_channel_max_capacity = self.hrmp_channel_max_capacity.max(1000);
298		self.hrmp_channel_max_message_size = self.hrmp_channel_max_message_size.max(1 << 16);
299		self.hrmp_max_parachain_inbound_channels =
300			self.hrmp_max_parachain_inbound_channels.max(100);
301		self.hrmp_max_parachain_outbound_channels =
302			self.hrmp_max_parachain_outbound_channels.max(100);
303		self
304	}
305}
306
307/// Enumerates the possible inconsistencies of `HostConfiguration`.
308#[derive(Debug)]
309pub enum InconsistentError<BlockNumber> {
310	/// `group_rotation_frequency` is set to zero.
311	ZeroGroupRotationFrequency,
312	/// `paras_availability_period` is set to zero.
313	ZeroParasAvailabilityPeriod,
314	/// `no_show_slots` is set to zero.
315	ZeroNoShowSlots,
316	/// `max_code_size` exceeds the hard limit of `MAX_CODE_SIZE`.
317	MaxCodeSizeExceedHardLimit { max_code_size: u32 },
318	/// `max_head_data_size` exceeds the hard limit of `MAX_HEAD_DATA_SIZE`.
319	MaxHeadDataSizeExceedHardLimit { max_head_data_size: u32 },
320	/// `max_pov_size` exceeds the hard limit of `POV_SIZE_HARD_LIMIT`.
321	MaxPovSizeExceedHardLimit { max_pov_size: u32 },
322	/// `minimum_validation_upgrade_delay` is less than `paras_availability_period`.
323	MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
324		minimum_validation_upgrade_delay: BlockNumber,
325		paras_availability_period: BlockNumber,
326	},
327	/// `validation_upgrade_delay` is less than or equal 1.
328	ValidationUpgradeDelayIsTooLow { validation_upgrade_delay: BlockNumber },
329	/// Maximum UMP message size
330	/// ([`MAX_UPWARD_MESSAGE_SIZE_BOUND`](crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND))
331	/// exceeded.
332	MaxUpwardMessageSizeExceeded { max_message_size: u32 },
333	/// Maximum HRMP message num ([`MAX_HORIZONTAL_MESSAGE_NUM`]) exceeded.
334	MaxHorizontalMessageNumExceeded { max_message_num: u32 },
335	/// Maximum UMP message num ([`MAX_UPWARD_MESSAGE_NUM`]) exceeded.
336	MaxUpwardMessageNumExceeded { max_message_num: u32 },
337	/// Maximum number of HRMP outbound channels exceeded.
338	MaxHrmpOutboundChannelsExceeded,
339	/// Maximum number of HRMP inbound channels exceeded.
340	MaxHrmpInboundChannelsExceeded,
341	/// `minimum_backing_votes` is set to zero.
342	ZeroMinimumBackingVotes,
343	/// `executor_params` are inconsistent.
344	InconsistentExecutorParams { inner: ExecutorParamError },
345	/// Lookahead is zero, while it must be at least 1 for parachains to work.
346	LookaheadZero,
347	/// Passed in queue size for on-demand was too large.
348	OnDemandQueueSizeTooLarge,
349	/// Number of delay tranches cannot be 0.
350	ZeroDelayTranches,
351}
352
353impl<BlockNumber> HostConfiguration<BlockNumber>
354where
355	BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From<u32>,
356{
357	/// Checks that this instance is consistent with the requirements on each individual member.
358	///
359	/// # Errors
360	///
361	/// This function returns an error if the configuration is inconsistent.
362	pub fn check_consistency(&self) -> Result<(), InconsistentError<BlockNumber>> {
363		use InconsistentError::*;
364
365		if self.scheduler_params.group_rotation_frequency.is_zero() {
366			return Err(ZeroGroupRotationFrequency)
367		}
368
369		if self.scheduler_params.paras_availability_period.is_zero() {
370			return Err(ZeroParasAvailabilityPeriod)
371		}
372
373		if self.no_show_slots.is_zero() {
374			return Err(ZeroNoShowSlots)
375		}
376
377		if self.max_code_size > MAX_CODE_SIZE {
378			return Err(MaxCodeSizeExceedHardLimit { max_code_size: self.max_code_size })
379		}
380
381		if self.max_head_data_size > MAX_HEAD_DATA_SIZE {
382			return Err(MaxHeadDataSizeExceedHardLimit {
383				max_head_data_size: self.max_head_data_size,
384			})
385		}
386
387		if self.max_pov_size > POV_SIZE_HARD_LIMIT {
388			return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size })
389		}
390
391		if self.minimum_validation_upgrade_delay <= self.scheduler_params.paras_availability_period
392		{
393			return Err(MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
394				minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(),
395				paras_availability_period: self.scheduler_params.paras_availability_period.clone(),
396			})
397		}
398
399		if self.validation_upgrade_delay <= 1.into() {
400			return Err(ValidationUpgradeDelayIsTooLow {
401				validation_upgrade_delay: self.validation_upgrade_delay.clone(),
402			})
403		}
404
405		if self.max_upward_message_size > crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND {
406			return Err(MaxUpwardMessageSizeExceeded {
407				max_message_size: self.max_upward_message_size,
408			})
409		}
410
411		if self.hrmp_max_message_num_per_candidate > MAX_HORIZONTAL_MESSAGE_NUM {
412			return Err(MaxHorizontalMessageNumExceeded {
413				max_message_num: self.hrmp_max_message_num_per_candidate,
414			})
415		}
416
417		if self.max_upward_message_num_per_candidate > MAX_UPWARD_MESSAGE_NUM {
418			return Err(MaxUpwardMessageNumExceeded {
419				max_message_num: self.max_upward_message_num_per_candidate,
420			})
421		}
422
423		if self.hrmp_max_parachain_outbound_channels > crate::hrmp::HRMP_MAX_OUTBOUND_CHANNELS_BOUND
424		{
425			return Err(MaxHrmpOutboundChannelsExceeded)
426		}
427
428		if self.hrmp_max_parachain_inbound_channels > crate::hrmp::HRMP_MAX_INBOUND_CHANNELS_BOUND {
429			return Err(MaxHrmpInboundChannelsExceeded)
430		}
431
432		if self.minimum_backing_votes.is_zero() {
433			return Err(ZeroMinimumBackingVotes)
434		}
435
436		if let Err(inner) = self.executor_params.check_consistency() {
437			return Err(InconsistentExecutorParams { inner })
438		}
439
440		if self.scheduler_params.lookahead == 0 {
441			return Err(LookaheadZero)
442		}
443
444		if self.scheduler_params.on_demand_queue_max_size > ON_DEMAND_MAX_QUEUE_MAX_SIZE {
445			return Err(OnDemandQueueSizeTooLarge)
446		}
447
448		if self.n_delay_tranches.is_zero() {
449			return Err(ZeroDelayTranches)
450		}
451
452		Ok(())
453	}
454
455	/// Checks that this instance is consistent with the requirements on each individual member.
456	///
457	/// # Panics
458	///
459	/// This function panics if the configuration is inconsistent.
460	pub fn panic_if_not_consistent(&self) {
461		if let Err(err) = self.check_consistency() {
462			panic!("Host configuration is inconsistent: {:?}\nCfg:\n{:#?}", err, self);
463		}
464	}
465}
466
467pub trait WeightInfo {
468	fn set_config_with_block_number() -> Weight;
469	fn set_config_with_u32() -> Weight;
470	fn set_config_with_option_u32() -> Weight;
471	fn set_config_with_balance() -> Weight;
472	fn set_hrmp_open_request_ttl() -> Weight;
473	fn set_config_with_executor_params() -> Weight;
474	fn set_config_with_perbill() -> Weight;
475	fn set_node_feature() -> Weight;
476	fn set_config_with_scheduler_params() -> Weight;
477}
478
479pub struct TestWeightInfo;
480impl WeightInfo for TestWeightInfo {
481	fn set_config_with_block_number() -> Weight {
482		Weight::MAX
483	}
484	fn set_config_with_u32() -> Weight {
485		Weight::MAX
486	}
487	fn set_config_with_option_u32() -> Weight {
488		Weight::MAX
489	}
490	fn set_config_with_balance() -> Weight {
491		Weight::MAX
492	}
493	fn set_hrmp_open_request_ttl() -> Weight {
494		Weight::MAX
495	}
496	fn set_config_with_executor_params() -> Weight {
497		Weight::MAX
498	}
499	fn set_config_with_perbill() -> Weight {
500		Weight::MAX
501	}
502	fn set_node_feature() -> Weight {
503		Weight::MAX
504	}
505	fn set_config_with_scheduler_params() -> Weight {
506		Weight::MAX
507	}
508}
509
510#[frame_support::pallet]
511pub mod pallet {
512	use super::*;
513
514	/// The in-code storage version.
515	///
516	/// v0-v1:  <https://github.com/paritytech/polkadot/pull/3575>
517	/// v1-v2:  <https://github.com/paritytech/polkadot/pull/4420>
518	/// v2-v3:  <https://github.com/paritytech/polkadot/pull/6091>
519	/// v3-v4:  <https://github.com/paritytech/polkadot/pull/6345>
520	/// v4-v5:  <https://github.com/paritytech/polkadot/pull/6937>
521	///       + <https://github.com/paritytech/polkadot/pull/6961>
522	///       + <https://github.com/paritytech/polkadot/pull/6934>
523	/// v5-v6:  <https://github.com/paritytech/polkadot/pull/6271> (remove UMP dispatch queue)
524	/// v6-v7:  <https://github.com/paritytech/polkadot/pull/7396>
525	/// v7-v8:  <https://github.com/paritytech/polkadot/pull/6969>
526	/// v8-v9:  <https://github.com/paritytech/polkadot/pull/7577>
527	/// v9-v10: <https://github.com/paritytech/polkadot-sdk/pull/2177>
528	/// v10-11: <https://github.com/paritytech/polkadot-sdk/pull/1191>
529	/// v11-12: <https://github.com/paritytech/polkadot-sdk/pull/3181>
530	const STORAGE_VERSION: StorageVersion = StorageVersion::new(12);
531
532	#[pallet::pallet]
533	#[pallet::storage_version(STORAGE_VERSION)]
534	#[pallet::without_storage_info]
535	pub struct Pallet<T>(_);
536
537	#[pallet::config]
538	pub trait Config: frame_system::Config + shared::Config {
539		/// Weight information for extrinsics in this pallet.
540		type WeightInfo: WeightInfo;
541	}
542
543	#[pallet::error]
544	pub enum Error<T> {
545		/// The new value for a configuration parameter is invalid.
546		InvalidNewValue,
547	}
548
549	/// The active configuration for the current session.
550	#[pallet::storage]
551	#[pallet::whitelist_storage]
552	pub type ActiveConfig<T: Config> =
553		StorageValue<_, HostConfiguration<BlockNumberFor<T>>, ValueQuery>;
554
555	/// Pending configuration changes.
556	///
557	/// This is a list of configuration changes, each with a session index at which it should
558	/// be applied.
559	///
560	/// The list is sorted ascending by session index. Also, this list can only contain at most
561	/// 2 items: for the next session and for the `scheduled_session`.
562	#[pallet::storage]
563	pub type PendingConfigs<T: Config> =
564		StorageValue<_, Vec<(SessionIndex, HostConfiguration<BlockNumberFor<T>>)>, ValueQuery>;
565
566	/// If this is set, then the configuration setters will bypass the consistency checks. This
567	/// is meant to be used only as the last resort.
568	#[pallet::storage]
569	pub(crate) type BypassConsistencyCheck<T: Config> = StorageValue<_, bool, ValueQuery>;
570
571	#[pallet::genesis_config]
572	#[derive(DefaultNoBound)]
573	pub struct GenesisConfig<T: Config> {
574		pub config: HostConfiguration<BlockNumberFor<T>>,
575	}
576
577	#[pallet::genesis_build]
578	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
579		fn build(&self) {
580			self.config.panic_if_not_consistent();
581			ActiveConfig::<T>::put(&self.config);
582		}
583	}
584
585	#[pallet::call]
586	impl<T: Config> Pallet<T> {
587		/// Set the validation upgrade cooldown.
588		#[pallet::call_index(0)]
589		#[pallet::weight((
590			T::WeightInfo::set_config_with_block_number(),
591			DispatchClass::Operational,
592		))]
593		pub fn set_validation_upgrade_cooldown(
594			origin: OriginFor<T>,
595			new: BlockNumberFor<T>,
596		) -> DispatchResult {
597			ensure_root(origin)?;
598			Self::schedule_config_update(|config| {
599				config.validation_upgrade_cooldown = new;
600			})
601		}
602
603		/// Set the validation upgrade delay.
604		#[pallet::call_index(1)]
605		#[pallet::weight((
606			T::WeightInfo::set_config_with_block_number(),
607			DispatchClass::Operational,
608		))]
609		pub fn set_validation_upgrade_delay(
610			origin: OriginFor<T>,
611			new: BlockNumberFor<T>,
612		) -> DispatchResult {
613			ensure_root(origin)?;
614			Self::schedule_config_update(|config| {
615				config.validation_upgrade_delay = new;
616			})
617		}
618
619		/// Set the acceptance period for an included candidate.
620		#[pallet::call_index(2)]
621		#[pallet::weight((
622			T::WeightInfo::set_config_with_block_number(),
623			DispatchClass::Operational,
624		))]
625		pub fn set_code_retention_period(
626			origin: OriginFor<T>,
627			new: BlockNumberFor<T>,
628		) -> DispatchResult {
629			ensure_root(origin)?;
630			Self::schedule_config_update(|config| {
631				config.code_retention_period = new;
632			})
633		}
634
635		/// Set the max validation code size for incoming upgrades.
636		#[pallet::call_index(3)]
637		#[pallet::weight((
638			T::WeightInfo::set_config_with_u32(),
639			DispatchClass::Operational,
640		))]
641		pub fn set_max_code_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
642			ensure_root(origin)?;
643			Self::schedule_config_update(|config| {
644				config.max_code_size = new;
645			})
646		}
647
648		/// Set the max POV block size for incoming upgrades.
649		#[pallet::call_index(4)]
650		#[pallet::weight((
651			T::WeightInfo::set_config_with_u32(),
652			DispatchClass::Operational,
653		))]
654		pub fn set_max_pov_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
655			ensure_root(origin)?;
656			Self::schedule_config_update(|config| {
657				config.max_pov_size = new;
658			})
659		}
660
661		/// Set the max head data size for paras.
662		#[pallet::call_index(5)]
663		#[pallet::weight((
664			T::WeightInfo::set_config_with_u32(),
665			DispatchClass::Operational,
666		))]
667		pub fn set_max_head_data_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
668			ensure_root(origin)?;
669			Self::schedule_config_update(|config| {
670				config.max_head_data_size = new;
671			})
672		}
673
674		/// Set the number of coretime execution cores.
675		///
676		/// NOTE: that this configuration is managed by the coretime chain. Only manually change
677		/// this, if you really know what you are doing!
678		#[pallet::call_index(6)]
679		#[pallet::weight((
680			T::WeightInfo::set_config_with_u32(),
681			DispatchClass::Operational,
682		))]
683		pub fn set_coretime_cores(origin: OriginFor<T>, new: u32) -> DispatchResult {
684			ensure_root(origin)?;
685			Self::set_coretime_cores_unchecked(new)
686		}
687
688		// Call index 7 used to be `set_max_availability_timeouts`, which was removed.
689
690		/// Set the parachain validator-group rotation frequency
691		#[pallet::call_index(8)]
692		#[pallet::weight((
693			T::WeightInfo::set_config_with_block_number(),
694			DispatchClass::Operational,
695		))]
696		pub fn set_group_rotation_frequency(
697			origin: OriginFor<T>,
698			new: BlockNumberFor<T>,
699		) -> DispatchResult {
700			ensure_root(origin)?;
701			Self::schedule_config_update(|config| {
702				config.scheduler_params.group_rotation_frequency = new;
703			})
704		}
705
706		/// Set the availability period for paras.
707		#[pallet::call_index(9)]
708		#[pallet::weight((
709			T::WeightInfo::set_config_with_block_number(),
710			DispatchClass::Operational,
711		))]
712		pub fn set_paras_availability_period(
713			origin: OriginFor<T>,
714			new: BlockNumberFor<T>,
715		) -> DispatchResult {
716			ensure_root(origin)?;
717			Self::schedule_config_update(|config| {
718				config.scheduler_params.paras_availability_period = new;
719			})
720		}
721
722		/// Set the scheduling lookahead, in expected number of blocks at peak throughput.
723		#[pallet::call_index(11)]
724		#[pallet::weight((
725			T::WeightInfo::set_config_with_u32(),
726			DispatchClass::Operational,
727		))]
728		pub fn set_scheduling_lookahead(origin: OriginFor<T>, new: u32) -> DispatchResult {
729			ensure_root(origin)?;
730			Self::schedule_config_update(|config| {
731				config.scheduler_params.lookahead = new;
732			})
733		}
734
735		/// Set the maximum number of validators to assign to any core.
736		#[pallet::call_index(12)]
737		#[pallet::weight((
738			T::WeightInfo::set_config_with_option_u32(),
739			DispatchClass::Operational,
740		))]
741		pub fn set_max_validators_per_core(
742			origin: OriginFor<T>,
743			new: Option<u32>,
744		) -> DispatchResult {
745			ensure_root(origin)?;
746			Self::schedule_config_update(|config| {
747				config.scheduler_params.max_validators_per_core = new;
748			})
749		}
750
751		/// Set the maximum number of validators to use in parachain consensus.
752		#[pallet::call_index(13)]
753		#[pallet::weight((
754			T::WeightInfo::set_config_with_option_u32(),
755			DispatchClass::Operational,
756		))]
757		pub fn set_max_validators(origin: OriginFor<T>, new: Option<u32>) -> DispatchResult {
758			ensure_root(origin)?;
759			Self::schedule_config_update(|config| {
760				config.max_validators = new;
761			})
762		}
763
764		/// Set the dispute period, in number of sessions to keep for disputes.
765		#[pallet::call_index(14)]
766		#[pallet::weight((
767			T::WeightInfo::set_config_with_u32(),
768			DispatchClass::Operational,
769		))]
770		pub fn set_dispute_period(origin: OriginFor<T>, new: SessionIndex) -> DispatchResult {
771			ensure_root(origin)?;
772			Self::schedule_config_update(|config| {
773				config.dispute_period = new;
774			})
775		}
776
777		/// Set the dispute post conclusion acceptance period.
778		#[pallet::call_index(15)]
779		#[pallet::weight((
780			T::WeightInfo::set_config_with_block_number(),
781			DispatchClass::Operational,
782		))]
783		pub fn set_dispute_post_conclusion_acceptance_period(
784			origin: OriginFor<T>,
785			new: BlockNumberFor<T>,
786		) -> DispatchResult {
787			ensure_root(origin)?;
788			Self::schedule_config_update(|config| {
789				config.dispute_post_conclusion_acceptance_period = new;
790			})
791		}
792
793		/// Set the no show slots, in number of number of consensus slots.
794		/// Must be at least 1.
795		#[pallet::call_index(18)]
796		#[pallet::weight((
797			T::WeightInfo::set_config_with_u32(),
798			DispatchClass::Operational,
799		))]
800		pub fn set_no_show_slots(origin: OriginFor<T>, new: u32) -> DispatchResult {
801			ensure_root(origin)?;
802			Self::schedule_config_update(|config| {
803				config.no_show_slots = new;
804			})
805		}
806
807		/// Set the total number of delay tranches.
808		#[pallet::call_index(19)]
809		#[pallet::weight((
810			T::WeightInfo::set_config_with_u32(),
811			DispatchClass::Operational,
812		))]
813		pub fn set_n_delay_tranches(origin: OriginFor<T>, new: u32) -> DispatchResult {
814			ensure_root(origin)?;
815			Self::schedule_config_update(|config| {
816				config.n_delay_tranches = new;
817			})
818		}
819
820		/// Set the zeroth delay tranche width.
821		#[pallet::call_index(20)]
822		#[pallet::weight((
823			T::WeightInfo::set_config_with_u32(),
824			DispatchClass::Operational,
825		))]
826		pub fn set_zeroth_delay_tranche_width(origin: OriginFor<T>, new: u32) -> DispatchResult {
827			ensure_root(origin)?;
828			Self::schedule_config_update(|config| {
829				config.zeroth_delay_tranche_width = new;
830			})
831		}
832
833		/// Set the number of validators needed to approve a block.
834		#[pallet::call_index(21)]
835		#[pallet::weight((
836			T::WeightInfo::set_config_with_u32(),
837			DispatchClass::Operational,
838		))]
839		pub fn set_needed_approvals(origin: OriginFor<T>, new: u32) -> DispatchResult {
840			ensure_root(origin)?;
841			Self::schedule_config_update(|config| {
842				config.needed_approvals = new;
843			})
844		}
845
846		/// Set the number of samples to do of the `RelayVRFModulo` approval assignment criterion.
847		#[pallet::call_index(22)]
848		#[pallet::weight((
849			T::WeightInfo::set_config_with_u32(),
850			DispatchClass::Operational,
851		))]
852		pub fn set_relay_vrf_modulo_samples(origin: OriginFor<T>, new: u32) -> DispatchResult {
853			ensure_root(origin)?;
854			Self::schedule_config_update(|config| {
855				config.relay_vrf_modulo_samples = new;
856			})
857		}
858
859		/// Sets the maximum items that can present in a upward dispatch queue at once.
860		#[pallet::call_index(23)]
861		#[pallet::weight((
862			T::WeightInfo::set_config_with_u32(),
863			DispatchClass::Operational,
864		))]
865		pub fn set_max_upward_queue_count(origin: OriginFor<T>, new: u32) -> DispatchResult {
866			ensure_root(origin)?;
867			Self::schedule_config_update(|config| {
868				config.max_upward_queue_count = new;
869			})
870		}
871
872		/// Sets the maximum total size of items that can present in a upward dispatch queue at
873		/// once.
874		#[pallet::call_index(24)]
875		#[pallet::weight((
876			T::WeightInfo::set_config_with_u32(),
877			DispatchClass::Operational,
878		))]
879		pub fn set_max_upward_queue_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
880			ensure_root(origin)?;
881
882			Self::schedule_config_update(|config| {
883				config.max_upward_queue_size = new;
884			})
885		}
886
887		/// Set the critical downward message size.
888		#[pallet::call_index(25)]
889		#[pallet::weight((
890			T::WeightInfo::set_config_with_u32(),
891			DispatchClass::Operational,
892		))]
893		pub fn set_max_downward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
894			ensure_root(origin)?;
895			Self::schedule_config_update(|config| {
896				config.max_downward_message_size = new;
897			})
898		}
899
900		/// Sets the maximum size of an upward message that can be sent by a candidate.
901		#[pallet::call_index(27)]
902		#[pallet::weight((
903			T::WeightInfo::set_config_with_u32(),
904			DispatchClass::Operational,
905		))]
906		pub fn set_max_upward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
907			ensure_root(origin)?;
908			Self::schedule_config_update(|config| {
909				config.max_upward_message_size = new;
910			})
911		}
912
913		/// Sets the maximum number of messages that a candidate can contain.
914		#[pallet::call_index(28)]
915		#[pallet::weight((
916			T::WeightInfo::set_config_with_u32(),
917			DispatchClass::Operational,
918		))]
919		pub fn set_max_upward_message_num_per_candidate(
920			origin: OriginFor<T>,
921			new: u32,
922		) -> DispatchResult {
923			ensure_root(origin)?;
924			Self::schedule_config_update(|config| {
925				config.max_upward_message_num_per_candidate = new;
926			})
927		}
928
929		/// Sets the number of sessions after which an HRMP open channel request expires.
930		#[pallet::call_index(29)]
931		#[pallet::weight((
932			T::WeightInfo::set_hrmp_open_request_ttl(),
933			DispatchClass::Operational,
934		))]
935		// Deprecated, but is not marked as such, because that would trigger warnings coming from
936		// the macro.
937		pub fn set_hrmp_open_request_ttl(_origin: OriginFor<T>, _new: u32) -> DispatchResult {
938			Err("this doesn't have any effect".into())
939		}
940
941		/// Sets the amount of funds that the sender should provide for opening an HRMP channel.
942		#[pallet::call_index(30)]
943		#[pallet::weight((
944			T::WeightInfo::set_config_with_balance(),
945			DispatchClass::Operational,
946		))]
947		pub fn set_hrmp_sender_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
948			ensure_root(origin)?;
949			Self::schedule_config_update(|config| {
950				config.hrmp_sender_deposit = new;
951			})
952		}
953
954		/// Sets the amount of funds that the recipient should provide for accepting opening an HRMP
955		/// channel.
956		#[pallet::call_index(31)]
957		#[pallet::weight((
958			T::WeightInfo::set_config_with_balance(),
959			DispatchClass::Operational,
960		))]
961		pub fn set_hrmp_recipient_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
962			ensure_root(origin)?;
963			Self::schedule_config_update(|config| {
964				config.hrmp_recipient_deposit = new;
965			})
966		}
967
968		/// Sets the maximum number of messages allowed in an HRMP channel at once.
969		#[pallet::call_index(32)]
970		#[pallet::weight((
971			T::WeightInfo::set_config_with_u32(),
972			DispatchClass::Operational,
973		))]
974		pub fn set_hrmp_channel_max_capacity(origin: OriginFor<T>, new: u32) -> DispatchResult {
975			ensure_root(origin)?;
976			Self::schedule_config_update(|config| {
977				config.hrmp_channel_max_capacity = new;
978			})
979		}
980
981		/// Sets the maximum total size of messages in bytes allowed in an HRMP channel at once.
982		#[pallet::call_index(33)]
983		#[pallet::weight((
984			T::WeightInfo::set_config_with_u32(),
985			DispatchClass::Operational,
986		))]
987		pub fn set_hrmp_channel_max_total_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
988			ensure_root(origin)?;
989			Self::schedule_config_update(|config| {
990				config.hrmp_channel_max_total_size = new;
991			})
992		}
993
994		/// Sets the maximum number of inbound HRMP channels a parachain is allowed to accept.
995		#[pallet::call_index(34)]
996		#[pallet::weight((
997			T::WeightInfo::set_config_with_u32(),
998			DispatchClass::Operational,
999		))]
1000		pub fn set_hrmp_max_parachain_inbound_channels(
1001			origin: OriginFor<T>,
1002			new: u32,
1003		) -> DispatchResult {
1004			ensure_root(origin)?;
1005			Self::schedule_config_update(|config| {
1006				config.hrmp_max_parachain_inbound_channels = new;
1007			})
1008		}
1009
1010		/// Sets the maximum size of a message that could ever be put into an HRMP channel.
1011		#[pallet::call_index(36)]
1012		#[pallet::weight((
1013			T::WeightInfo::set_config_with_u32(),
1014			DispatchClass::Operational,
1015		))]
1016		pub fn set_hrmp_channel_max_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1017			ensure_root(origin)?;
1018			Self::schedule_config_update(|config| {
1019				config.hrmp_channel_max_message_size = new;
1020			})
1021		}
1022
1023		/// Sets the maximum number of outbound HRMP channels a parachain is allowed to open.
1024		#[pallet::call_index(37)]
1025		#[pallet::weight((
1026			T::WeightInfo::set_config_with_u32(),
1027			DispatchClass::Operational,
1028		))]
1029		pub fn set_hrmp_max_parachain_outbound_channels(
1030			origin: OriginFor<T>,
1031			new: u32,
1032		) -> DispatchResult {
1033			ensure_root(origin)?;
1034			Self::schedule_config_update(|config| {
1035				config.hrmp_max_parachain_outbound_channels = new;
1036			})
1037		}
1038
1039		/// Sets the maximum number of outbound HRMP messages can be sent by a candidate.
1040		#[pallet::call_index(39)]
1041		#[pallet::weight((
1042			T::WeightInfo::set_config_with_u32(),
1043			DispatchClass::Operational,
1044		))]
1045		pub fn set_hrmp_max_message_num_per_candidate(
1046			origin: OriginFor<T>,
1047			new: u32,
1048		) -> DispatchResult {
1049			ensure_root(origin)?;
1050			Self::schedule_config_update(|config| {
1051				config.hrmp_max_message_num_per_candidate = new;
1052			})
1053		}
1054
1055		/// Set the number of session changes after which a PVF pre-checking voting is rejected.
1056		#[pallet::call_index(42)]
1057		#[pallet::weight((
1058			T::WeightInfo::set_config_with_u32(),
1059			DispatchClass::Operational,
1060		))]
1061		pub fn set_pvf_voting_ttl(origin: OriginFor<T>, new: SessionIndex) -> DispatchResult {
1062			ensure_root(origin)?;
1063			Self::schedule_config_update(|config| {
1064				config.pvf_voting_ttl = new;
1065			})
1066		}
1067
1068		/// Sets the minimum delay between announcing the upgrade block for a parachain until the
1069		/// upgrade taking place.
1070		///
1071		/// See the field documentation for information and constraints for the new value.
1072		#[pallet::call_index(43)]
1073		#[pallet::weight((
1074			T::WeightInfo::set_config_with_block_number(),
1075			DispatchClass::Operational,
1076		))]
1077		pub fn set_minimum_validation_upgrade_delay(
1078			origin: OriginFor<T>,
1079			new: BlockNumberFor<T>,
1080		) -> DispatchResult {
1081			ensure_root(origin)?;
1082			Self::schedule_config_update(|config| {
1083				config.minimum_validation_upgrade_delay = new;
1084			})
1085		}
1086
1087		/// Setting this to true will disable consistency checks for the configuration setters.
1088		/// Use with caution.
1089		#[pallet::call_index(44)]
1090		#[pallet::weight((
1091			T::DbWeight::get().writes(1),
1092			DispatchClass::Operational,
1093		))]
1094		pub fn set_bypass_consistency_check(origin: OriginFor<T>, new: bool) -> DispatchResult {
1095			ensure_root(origin)?;
1096			BypassConsistencyCheck::<T>::put(new);
1097			Ok(())
1098		}
1099
1100		/// Set the asynchronous backing parameters.
1101		#[pallet::call_index(45)]
1102		#[pallet::weight((
1103			T::WeightInfo::set_config_with_option_u32(), // The same size in bytes.
1104			DispatchClass::Operational,
1105		))]
1106		pub fn set_async_backing_params(
1107			origin: OriginFor<T>,
1108			new: AsyncBackingParams,
1109		) -> DispatchResult {
1110			ensure_root(origin)?;
1111			Self::schedule_config_update(|config| {
1112				config.async_backing_params = new;
1113			})
1114		}
1115
1116		/// Set PVF executor parameters.
1117		#[pallet::call_index(46)]
1118		#[pallet::weight((
1119			T::WeightInfo::set_config_with_executor_params(),
1120			DispatchClass::Operational,
1121		))]
1122		pub fn set_executor_params(origin: OriginFor<T>, new: ExecutorParams) -> DispatchResult {
1123			ensure_root(origin)?;
1124			Self::schedule_config_update(|config| {
1125				config.executor_params = new;
1126			})
1127		}
1128
1129		/// Set the on demand (parathreads) base fee.
1130		#[pallet::call_index(47)]
1131		#[pallet::weight((
1132			T::WeightInfo::set_config_with_balance(),
1133			DispatchClass::Operational,
1134		))]
1135		pub fn set_on_demand_base_fee(origin: OriginFor<T>, new: Balance) -> DispatchResult {
1136			ensure_root(origin)?;
1137			Self::schedule_config_update(|config| {
1138				config.scheduler_params.on_demand_base_fee = new;
1139			})
1140		}
1141
1142		/// Set the on demand (parathreads) fee variability.
1143		#[pallet::call_index(48)]
1144		#[pallet::weight((
1145			T::WeightInfo::set_config_with_perbill(),
1146			DispatchClass::Operational,
1147		))]
1148		pub fn set_on_demand_fee_variability(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
1149			ensure_root(origin)?;
1150			Self::schedule_config_update(|config| {
1151				config.scheduler_params.on_demand_fee_variability = new;
1152			})
1153		}
1154
1155		/// Set the on demand (parathreads) queue max size.
1156		#[pallet::call_index(49)]
1157		#[pallet::weight((
1158			T::WeightInfo::set_config_with_option_u32(),
1159			DispatchClass::Operational,
1160		))]
1161		pub fn set_on_demand_queue_max_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1162			ensure_root(origin)?;
1163			Self::schedule_config_update(|config| {
1164				config.scheduler_params.on_demand_queue_max_size = new;
1165			})
1166		}
1167
1168		/// Set the on demand (parathreads) fee variability.
1169		#[pallet::call_index(50)]
1170		#[pallet::weight((
1171			T::WeightInfo::set_config_with_perbill(),
1172			DispatchClass::Operational,
1173		))]
1174		pub fn set_on_demand_target_queue_utilization(
1175			origin: OriginFor<T>,
1176			new: Perbill,
1177		) -> DispatchResult {
1178			ensure_root(origin)?;
1179			Self::schedule_config_update(|config| {
1180				config.scheduler_params.on_demand_target_queue_utilization = new;
1181			})
1182		}
1183
1184		// Call index 51 used to be `set_on_demand_ttl`, which was removed.
1185
1186		/// Set the minimum backing votes threshold.
1187		#[pallet::call_index(52)]
1188		#[pallet::weight((
1189			T::WeightInfo::set_config_with_u32(),
1190			DispatchClass::Operational
1191		))]
1192		pub fn set_minimum_backing_votes(origin: OriginFor<T>, new: u32) -> DispatchResult {
1193			ensure_root(origin)?;
1194			Self::schedule_config_update(|config| {
1195				config.minimum_backing_votes = new;
1196			})
1197		}
1198
1199		/// Set/Unset a node feature.
1200		#[pallet::call_index(53)]
1201		#[pallet::weight((
1202			T::WeightInfo::set_node_feature(),
1203			DispatchClass::Operational
1204		))]
1205		pub fn set_node_feature(origin: OriginFor<T>, index: u8, value: bool) -> DispatchResult {
1206			ensure_root(origin)?;
1207
1208			Self::schedule_config_update(|config| {
1209				let index = usize::from(index);
1210				if config.node_features.len() <= index {
1211					config.node_features.resize(index + 1, false);
1212				}
1213				config.node_features.set(index, value);
1214			})
1215		}
1216
1217		/// Set approval-voting-params.
1218		#[pallet::call_index(54)]
1219		#[pallet::weight((
1220			T::WeightInfo::set_config_with_executor_params(),
1221			DispatchClass::Operational,
1222		))]
1223		pub fn set_approval_voting_params(
1224			origin: OriginFor<T>,
1225			new: ApprovalVotingParams,
1226		) -> DispatchResult {
1227			ensure_root(origin)?;
1228			Self::schedule_config_update(|config| {
1229				config.approval_voting_params = new;
1230			})
1231		}
1232
1233		/// Set scheduler-params.
1234		#[pallet::call_index(55)]
1235		#[pallet::weight((
1236			T::WeightInfo::set_config_with_scheduler_params(),
1237			DispatchClass::Operational,
1238		))]
1239		pub fn set_scheduler_params(
1240			origin: OriginFor<T>,
1241			new: SchedulerParams<BlockNumberFor<T>>,
1242		) -> DispatchResult {
1243			ensure_root(origin)?;
1244			Self::schedule_config_update(|config| {
1245				config.scheduler_params = new;
1246			})
1247		}
1248	}
1249
1250	impl<T: Config> Pallet<T> {
1251		/// Set coretime cores.
1252		///
1253		/// To be used if authorization is checked otherwise.
1254		pub fn set_coretime_cores_unchecked(new: u32) -> DispatchResult {
1255			Self::schedule_config_update(|config| {
1256				config.scheduler_params.num_cores = new;
1257			})
1258		}
1259	}
1260
1261	#[pallet::hooks]
1262	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1263		fn integrity_test() {
1264			assert_eq!(
1265				&ActiveConfig::<T>::hashed_key(),
1266				polkadot_primitives::well_known_keys::ACTIVE_CONFIG,
1267				"`well_known_keys::ACTIVE_CONFIG` doesn't match key of `ActiveConfig`! Make sure that the name of the\
1268				 configuration pallet is `Configuration` in the runtime!",
1269			);
1270		}
1271	}
1272}
1273
1274/// A struct that holds the configuration that was active before the session change and optionally
1275/// a configuration that became active after the session change.
1276pub struct SessionChangeOutcome<BlockNumber> {
1277	/// Previously active configuration.
1278	pub prev_config: HostConfiguration<BlockNumber>,
1279	/// If new configuration was applied during the session change, this is the new configuration.
1280	pub new_config: Option<HostConfiguration<BlockNumber>>,
1281}
1282
1283impl<T: Config> Pallet<T> {
1284	/// Called by the initializer to initialize the configuration pallet.
1285	pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
1286		Weight::zero()
1287	}
1288
1289	/// Called by the initializer to finalize the configuration pallet.
1290	pub(crate) fn initializer_finalize() {}
1291
1292	/// Called by the initializer to note that a new session has started.
1293	///
1294	/// Returns the configuration that was actual before the session change and the configuration
1295	/// that became active after the session change. If there were no scheduled changes, both will
1296	/// be the same.
1297	pub(crate) fn initializer_on_new_session(
1298		session_index: &SessionIndex,
1299	) -> SessionChangeOutcome<BlockNumberFor<T>> {
1300		let pending_configs = PendingConfigs::<T>::get();
1301		let prev_config = ActiveConfig::<T>::get();
1302
1303		// No pending configuration changes, so we're done.
1304		if pending_configs.is_empty() {
1305			return SessionChangeOutcome { prev_config, new_config: None }
1306		}
1307
1308		let (mut past_and_present, future) = pending_configs
1309			.into_iter()
1310			.partition::<Vec<_>, _>(|&(apply_at_session, _)| apply_at_session <= *session_index);
1311
1312		if past_and_present.len() > 1 {
1313			// This should never happen since we schedule configuration changes only into the future
1314			// sessions and this handler called for each session change.
1315			log::error!(
1316				target: LOG_TARGET,
1317				"Skipping applying configuration changes scheduled sessions in the past",
1318			);
1319		}
1320
1321		let new_config = past_and_present.pop().map(|(_, config)| config);
1322		if let Some(ref new_config) = new_config {
1323			// Apply the new configuration.
1324			ActiveConfig::<T>::put(new_config);
1325		}
1326
1327		PendingConfigs::<T>::put(future);
1328
1329		SessionChangeOutcome { prev_config, new_config }
1330	}
1331
1332	/// Return the session index that should be used for any future scheduled changes.
1333	fn scheduled_session() -> SessionIndex {
1334		shared::Pallet::<T>::scheduled_session()
1335	}
1336
1337	/// Forcibly set the active config. This should be used with extreme care, and typically
1338	/// only when enabling parachains runtime pallets for the first time on a chain which has
1339	/// been running without them.
1340	pub fn force_set_active_config(config: HostConfiguration<BlockNumberFor<T>>) {
1341		ActiveConfig::<T>::set(config);
1342	}
1343
1344	/// This function should be used to update members of the configuration.
1345	///
1346	/// This function is used to update the configuration in a way that is safe. It will check the
1347	/// resulting configuration and ensure that the update is valid. If the update is invalid, it
1348	/// will check if the previous configuration was valid. If it was invalid, we proceed with
1349	/// updating the configuration, giving a chance to recover from such a condition.
1350	///
1351	/// The actual configuration change takes place after a couple of sessions have passed. In case
1352	/// this function is called more than once in the same session, then the pending configuration
1353	/// change will be updated.
1354	/// In other words, all the configuration changes made in the same session will be folded
1355	/// together in the order they were made, and only once the scheduled session is reached will
1356	/// the final pending configuration be applied.
1357	// NOTE: Explicitly tell rustc not to inline this, because otherwise heuristics note the
1358	// incoming closure make it attractive to inline. However, in that case, we will end up with
1359	// lots of duplicated code (making this function show up on top of the heaviest functions) only
1360	// for the sake of essentially avoiding an indirect call. It is not worth it.
1361	#[inline(never)]
1362	pub(crate) fn schedule_config_update(
1363		updater: impl FnOnce(&mut HostConfiguration<BlockNumberFor<T>>),
1364	) -> DispatchResult {
1365		let mut pending_configs = PendingConfigs::<T>::get();
1366
1367		// 1. pending_configs = [] No pending configuration changes.
1368		//
1369		//    That means we should use the active config as the base configuration. We will insert
1370		//    the new pending configuration as (cur+2, new_config) into the list.
1371		//
1372		// 2. pending_configs = [(cur+2, X)] There is a configuration that is pending for the
1373		//    scheduled session.
1374		//
1375		//    We will use X as the base configuration. We can update the pending configuration X
1376		//    directly.
1377		//
1378		// 3. pending_configs = [(cur+1, X)] There is a pending configuration scheduled and it will
1379		//    be applied in the next session.
1380		//
1381		//    We will use X as the base configuration. We need to schedule a new configuration
1382		// change    for the `scheduled_session` and use X as the base for the new configuration.
1383		//
1384		// 4. pending_configs = [(cur+1, X), (cur+2, Y)] There is a pending configuration change in
1385		//    the next session and for the scheduled session. Due to case №3, we can be sure that Y
1386		//    is based on top of X. This means we can use Y as the base configuration and update Y
1387		//    directly.
1388		//
1389		// There cannot be (cur, X) because those are applied in the session change handler for the
1390		// current session.
1391
1392		// First, we need to decide what we should use as the base configuration.
1393		let mut base_config = pending_configs
1394			.last()
1395			.map(|(_, config)| config.clone())
1396			.unwrap_or_else(ActiveConfig::<T>::get);
1397		let base_config_consistent = base_config.check_consistency().is_ok();
1398
1399		// Now, we need to decide what the new configuration should be.
1400		// We also move the `base_config` to `new_config` to emphasize that the base config was
1401		// destroyed by the `updater`.
1402		updater(&mut base_config);
1403		let new_config = base_config;
1404
1405		if BypassConsistencyCheck::<T>::get() {
1406			// This will emit a warning each configuration update if the consistency check is
1407			// bypassed. This is an attempt to make sure the bypass is not accidentally left on.
1408			log::warn!(
1409				target: LOG_TARGET,
1410				"Bypassing the consistency check for the configuration change!",
1411			);
1412		} else if let Err(e) = new_config.check_consistency() {
1413			if base_config_consistent {
1414				// Base configuration is consistent and the new configuration is inconsistent.
1415				// This means that the value set by the `updater` is invalid and we can return
1416				// it as an error.
1417				log::warn!(
1418					target: LOG_TARGET,
1419					"Configuration change rejected due to invalid configuration: {:?}",
1420					e,
1421				);
1422				return Err(Error::<T>::InvalidNewValue.into())
1423			} else {
1424				// The configuration was already broken, so we can as well proceed with the update.
1425				// You cannot break something that is already broken.
1426				//
1427				// That will allow to call several functions and ultimately return the configuration
1428				// into consistent state.
1429				log::warn!(
1430					target: LOG_TARGET,
1431					"The new configuration is broken but the old is broken as well. Proceeding",
1432				);
1433			}
1434		}
1435
1436		let scheduled_session = Self::scheduled_session();
1437
1438		if let Some(&mut (_, ref mut config)) = pending_configs
1439			.iter_mut()
1440			.find(|&&mut (apply_at_session, _)| apply_at_session >= scheduled_session)
1441		{
1442			*config = new_config;
1443		} else {
1444			// We are scheduling a new configuration change for the scheduled session.
1445			pending_configs.push((scheduled_session, new_config));
1446		}
1447
1448		PendingConfigs::<T>::put(pending_configs);
1449
1450		Ok(())
1451	}
1452}
1453
1454/// The implementation of `Get<(u32, u32)>` which reads `ActiveConfig` and returns `P` percent of
1455/// `hrmp_channel_max_message_size` / `hrmp_channel_max_capacity`.
1456pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>(core::marker::PhantomData<(T, P)>);
1457impl<T: crate::hrmp::pallet::Config, P: Get<Percent>> Get<(u32, u32)>
1458	for ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>
1459{
1460	fn get() -> (u32, u32) {
1461		let config = ActiveConfig::<T>::get();
1462		let percent = P::get();
1463		(percent * config.hrmp_channel_max_message_size, percent * config.hrmp_channel_max_capacity)
1464	}
1465}