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