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