referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/
configuration.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Configuration manager for the Polkadot runtime parachains logic.
18//!
19//! Configuration can change only at session boundaries and is buffered until then.
20
21use crate::shared;
22use alloc::vec::Vec;
23use codec::{Decode, Encode};
24use frame_support::{pallet_prelude::*, DefaultNoBound};
25use frame_system::pallet_prelude::*;
26use polkadot_parachain_primitives::primitives::{
27	MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM,
28};
29use polkadot_primitives::{
30	ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams,
31	NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE,
32	ON_DEMAND_MAX_QUEUE_MAX_SIZE,
33};
34use sp_runtime::{traits::Zero, Perbill, Percent};
35
36#[cfg(test)]
37mod tests;
38
39#[cfg(feature = "runtime-benchmarks")]
40mod benchmarking;
41
42pub mod migration;
43
44pub use pallet::*;
45use polkadot_primitives::vstaging::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	Debug,
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	/// The parameters that are required for the parachains.
76
77	/// The maximum validation code size, in bytes.
78	pub max_code_size: u32,
79	/// The maximum head-data size, in bytes.
80	pub max_head_data_size: u32,
81	/// Total number of individual messages allowed in the parachain -> relay-chain message queue.
82	pub max_upward_queue_count: u32,
83	/// Total size of messages allowed in the parachain -> relay-chain message queue before which
84	/// no further messages may be added to it. If it exceeds this then the queue may contain only
85	/// a single message.
86	pub max_upward_queue_size: u32,
87	/// The maximum size of an upward message that can be sent by a candidate.
88	///
89	/// This parameter affects the size upper bound of the `CandidateCommitments`.
90	pub max_upward_message_size: u32,
91	/// The maximum number of messages that a candidate can contain.
92	///
93	/// This parameter affects the size upper bound of the `CandidateCommitments`.
94	pub max_upward_message_num_per_candidate: u32,
95	/// The maximum number of outbound HRMP messages can be sent by a candidate.
96	///
97	/// This parameter affects the upper bound of size of `CandidateCommitments`.
98	pub hrmp_max_message_num_per_candidate: u32,
99	/// The minimum period, in blocks, between which parachains can update their validation code.
100	///
101	/// This number is used to prevent parachains from spamming the relay chain with validation
102	/// code upgrades. The only thing it controls is the number of blocks the
103	/// `UpgradeRestrictionSignal` is set for the parachain in question.
104	///
105	/// If PVF pre-checking is enabled this should be greater than the maximum number of blocks
106	/// PVF pre-checking can take. Intuitively, this number should be greater than the duration
107	/// specified by [`pvf_voting_ttl`](Self::pvf_voting_ttl). Unlike,
108	/// [`pvf_voting_ttl`](Self::pvf_voting_ttl), this parameter uses blocks as a unit.
109	#[cfg_attr(feature = "std", serde(alias = "validation_upgrade_frequency"))]
110	pub validation_upgrade_cooldown: BlockNumber,
111	/// The delay, in blocks, after which an upgrade of the validation code is applied.
112	///
113	/// The upgrade for a parachain takes place when the first candidate which has relay-parent >=
114	/// the relay-chain block where the upgrade is scheduled. This block is referred as to
115	/// `expected_at`.
116	///
117	/// `expected_at` is determined when the upgrade is scheduled. This happens when the candidate
118	/// that signals the upgrade is enacted. Right now, the relay-parent block number of the
119	/// candidate scheduling the upgrade is used to determine the `expected_at`. This may change in
120	/// the future with [#4601].
121	///
122	/// When PVF pre-checking is enabled, the upgrade is scheduled only after the PVF pre-check has
123	/// been completed.
124	///
125	/// Note, there are situations in which `expected_at` in the past. For example, if
126	/// [`paras_availability_period`](SchedulerParams::paras_availability_period) is less than the
127	/// delay set by this field or if PVF pre-check took more time than the delay. In such cases,
128	/// the upgrade is further at the earliest possible time determined by
129	/// [`minimum_validation_upgrade_delay`](Self::minimum_validation_upgrade_delay).
130	///
131	/// The rationale for this delay has to do with relay-chain reversions. In case there is an
132	/// invalid candidate produced with the new version of the code, then the relay-chain can
133	/// revert [`validation_upgrade_delay`](Self::validation_upgrade_delay) many blocks back and
134	/// still find the new code in the storage by hash.
135	///
136	/// [#4601]: https://github.com/paritytech/polkadot/issues/4601
137	pub validation_upgrade_delay: BlockNumber,
138	/// Asynchronous backing parameters.
139	pub async_backing_params: AsyncBackingParams,
140
141	/// The parameters that are not essential, but still may be of interest for parachains.
142
143	/// The maximum POV block size, in bytes.
144	pub max_pov_size: u32,
145	/// The maximum size of a message that can be put in a downward message queue.
146	///
147	/// Since we require receiving at least one DMP message the obvious upper bound of the size is
148	/// the PoV size. Of course, there is a lot of other different things that a parachain may
149	/// decide to do with its PoV so this value in practice will be picked as a fraction of the PoV
150	/// size.
151	pub max_downward_message_size: u32,
152	/// The maximum number of outbound HRMP channels a parachain is allowed to open.
153	pub hrmp_max_parachain_outbound_channels: u32,
154	/// The deposit that the sender should provide for opening an HRMP channel.
155	pub hrmp_sender_deposit: Balance,
156	/// The deposit that the recipient should provide for accepting opening an HRMP channel.
157	pub hrmp_recipient_deposit: Balance,
158	/// The maximum number of messages allowed in an HRMP channel at once.
159	pub hrmp_channel_max_capacity: u32,
160	/// The maximum total size of messages in bytes allowed in an HRMP channel at once.
161	pub hrmp_channel_max_total_size: u32,
162	/// The maximum number of inbound HRMP channels a parachain is allowed to accept.
163	pub hrmp_max_parachain_inbound_channels: u32,
164	/// The maximum size of a message that could ever be put into an HRMP channel.
165	///
166	/// This parameter affects the upper bound of size of `CandidateCommitments`.
167	pub hrmp_channel_max_message_size: u32,
168	/// The executor environment parameters
169	pub executor_params: ExecutorParams,
170
171	/// Parameters that will unlikely be needed by parachains.
172
173	/// How long to keep code on-chain, in blocks. This should be sufficiently long that disputes
174	/// have concluded.
175	pub code_retention_period: BlockNumber,
176
177	/// The maximum number of validators to use for parachain consensus, period.
178	///
179	/// `None` means no maximum.
180	pub max_validators: Option<u32>,
181	/// The amount of sessions to keep for disputes.
182	pub dispute_period: SessionIndex,
183	/// How long after dispute conclusion to accept statements.
184	pub dispute_post_conclusion_acceptance_period: BlockNumber,
185	/// The amount of consensus slots that must pass between submitting an assignment and
186	/// submitting an approval vote before a validator is considered a no-show.
187	///
188	/// Must be at least 1.
189	pub no_show_slots: u32,
190	/// The number of delay tranches in total. Must be at least 1.
191	pub n_delay_tranches: u32,
192	/// The width of the zeroth delay tranche for approval assignments. This many delay tranches
193	/// beyond 0 are all consolidated to form a wide 0 tranche.
194	pub zeroth_delay_tranche_width: u32,
195	/// The number of validators needed to approve a block.
196	pub needed_approvals: u32,
197	/// The number of samples to do of the `RelayVRFModulo` approval assignment criterion.
198	pub relay_vrf_modulo_samples: u32,
199	/// If an active PVF pre-checking vote observes this many number of sessions it gets
200	/// automatically rejected.
201	///
202	/// 0 means PVF pre-checking will be rejected on the first observed session unless the voting
203	/// gained supermajority before that the session change.
204	pub pvf_voting_ttl: SessionIndex,
205	/// The lower bound number of blocks an upgrade can be scheduled.
206	///
207	/// Typically, upgrade gets scheduled
208	/// [`validation_upgrade_delay`](Self::validation_upgrade_delay) relay-chain blocks after
209	/// the relay-parent of the parablock that signalled the validation code upgrade. However,
210	/// in the case a pre-checking voting was concluded in a longer duration the upgrade will be
211	/// scheduled to the next block.
212	///
213	/// That can disrupt parachain inclusion. Specifically, it will make the blocks that were
214	/// already backed invalid.
215	///
216	/// To prevent that, we introduce the minimum number of blocks after which the upgrade can be
217	/// scheduled. This number is controlled by this field.
218	///
219	/// This value should be greater than
220	/// [`paras_availability_period`](SchedulerParams::paras_availability_period).
221	pub minimum_validation_upgrade_delay: BlockNumber,
222	/// The minimum number of valid backing statements required to consider a parachain candidate
223	/// backable.
224	pub minimum_backing_votes: u32,
225	/// Node features enablement.
226	pub node_features: NodeFeatures,
227	/// Params used by approval-voting
228	pub approval_voting_params: ApprovalVotingParams,
229	/// Scheduler parameters
230	pub scheduler_params: SchedulerParams<BlockNumber>,
231	/// The maximum session age of a relay parent that a parachain block can build upon.
232	pub max_relay_parent_session_age: u32,
233}
234
235impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber> {
236	fn default() -> Self {
237		let ret = Self {
238			async_backing_params: AsyncBackingParams {
239				max_candidate_depth: 0,
240				allowed_ancestry_len: 0,
241			},
242			no_show_slots: 1u32.into(),
243			validation_upgrade_cooldown: Default::default(),
244			validation_upgrade_delay: 2u32.into(),
245			code_retention_period: Default::default(),
246			max_code_size: MAX_CODE_SIZE,
247			max_pov_size: Default::default(),
248			max_head_data_size: Default::default(),
249			max_validators: None,
250			dispute_period: 6,
251			dispute_post_conclusion_acceptance_period: 100.into(),
252			n_delay_tranches: 1,
253			zeroth_delay_tranche_width: Default::default(),
254			needed_approvals: Default::default(),
255			relay_vrf_modulo_samples: Default::default(),
256			max_upward_queue_count: Default::default(),
257			max_upward_queue_size: Default::default(),
258			max_downward_message_size: Default::default(),
259			max_upward_message_size: Default::default(),
260			max_upward_message_num_per_candidate: Default::default(),
261			hrmp_sender_deposit: Default::default(),
262			hrmp_recipient_deposit: Default::default(),
263			hrmp_channel_max_capacity: Default::default(),
264			hrmp_channel_max_total_size: Default::default(),
265			hrmp_max_parachain_inbound_channels: Default::default(),
266			hrmp_channel_max_message_size: Default::default(),
267			hrmp_max_parachain_outbound_channels: Default::default(),
268			hrmp_max_message_num_per_candidate: Default::default(),
269			pvf_voting_ttl: 2u32.into(),
270			minimum_validation_upgrade_delay: 2.into(),
271			executor_params: Default::default(),
272			approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 },
273			minimum_backing_votes: LEGACY_MIN_BACKING_VOTES,
274			node_features: NodeFeatures::EMPTY,
275			scheduler_params: Default::default(),
276			max_relay_parent_session_age: 0,
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
327	/// ([`MAX_UPWARD_MESSAGE_SIZE_BOUND`](crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND))
328	/// exceeded.
329	MaxUpwardMessageSizeExceeded { max_message_size: u32 },
330	/// Maximum HRMP message num ([`MAX_HORIZONTAL_MESSAGE_NUM`]) exceeded.
331	MaxHorizontalMessageNumExceeded { max_message_num: u32 },
332	/// Maximum UMP message num ([`MAX_UPWARD_MESSAGE_NUM`]) exceeded.
333	MaxUpwardMessageNumExceeded { max_message_num: u32 },
334	/// Maximum number of HRMP outbound channels exceeded.
335	MaxHrmpOutboundChannelsExceeded,
336	/// Maximum number of HRMP inbound channels exceeded.
337	MaxHrmpInboundChannelsExceeded,
338	/// `minimum_backing_votes` is set to zero.
339	ZeroMinimumBackingVotes,
340	/// `executor_params` are inconsistent.
341	InconsistentExecutorParams { inner: ExecutorParamError },
342	/// Lookahead is zero, while it must be at least 1 for parachains to work.
343	LookaheadZero,
344	/// Passed in queue size for on-demand was too large.
345	OnDemandQueueSizeTooLarge,
346	/// Number of delay tranches cannot be 0.
347	ZeroDelayTranches,
348}
349
350impl<BlockNumber> HostConfiguration<BlockNumber>
351where
352	BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From<u32>,
353{
354	/// Checks that this instance is consistent with the requirements on each individual member.
355	///
356	/// # Errors
357	///
358	/// This function returns an error if the configuration is inconsistent.
359	pub fn check_consistency(&self) -> Result<(), InconsistentError<BlockNumber>> {
360		use InconsistentError::*;
361
362		if self.scheduler_params.group_rotation_frequency.is_zero() {
363			return Err(ZeroGroupRotationFrequency);
364		}
365
366		if self.scheduler_params.paras_availability_period.is_zero() {
367			return Err(ZeroParasAvailabilityPeriod);
368		}
369
370		if self.no_show_slots.is_zero() {
371			return Err(ZeroNoShowSlots);
372		}
373
374		if self.max_code_size > MAX_CODE_SIZE {
375			return Err(MaxCodeSizeExceedHardLimit { max_code_size: self.max_code_size });
376		}
377
378		if self.max_head_data_size > MAX_HEAD_DATA_SIZE {
379			return Err(MaxHeadDataSizeExceedHardLimit {
380				max_head_data_size: self.max_head_data_size,
381			});
382		}
383
384		if self.max_pov_size > POV_SIZE_HARD_LIMIT {
385			return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size });
386		}
387
388		if self.minimum_validation_upgrade_delay <= self.scheduler_params.paras_availability_period
389		{
390			return Err(MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
391				minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(),
392				paras_availability_period: self.scheduler_params.paras_availability_period.clone(),
393			});
394		}
395
396		if self.validation_upgrade_delay <= 1.into() {
397			return Err(ValidationUpgradeDelayIsTooLow {
398				validation_upgrade_delay: self.validation_upgrade_delay.clone(),
399			});
400		}
401
402		if self.max_upward_message_size > crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND {
403			return Err(MaxUpwardMessageSizeExceeded {
404				max_message_size: self.max_upward_message_size,
405			});
406		}
407
408		if self.hrmp_max_message_num_per_candidate > MAX_HORIZONTAL_MESSAGE_NUM {
409			return Err(MaxHorizontalMessageNumExceeded {
410				max_message_num: self.hrmp_max_message_num_per_candidate,
411			});
412		}
413
414		if self.max_upward_message_num_per_candidate > MAX_UPWARD_MESSAGE_NUM {
415			return Err(MaxUpwardMessageNumExceeded {
416				max_message_num: self.max_upward_message_num_per_candidate,
417			});
418		}
419
420		if self.hrmp_max_parachain_outbound_channels > crate::hrmp::HRMP_MAX_OUTBOUND_CHANNELS_BOUND
421		{
422			return Err(MaxHrmpOutboundChannelsExceeded);
423		}
424
425		if self.hrmp_max_parachain_inbound_channels > crate::hrmp::HRMP_MAX_INBOUND_CHANNELS_BOUND {
426			return Err(MaxHrmpInboundChannelsExceeded);
427		}
428
429		if self.minimum_backing_votes.is_zero() {
430			return Err(ZeroMinimumBackingVotes);
431		}
432
433		if let Err(inner) = self.executor_params.check_consistency() {
434			return Err(InconsistentExecutorParams { inner });
435		}
436
437		if self.scheduler_params.lookahead == 0 {
438			return Err(LookaheadZero);
439		}
440
441		if self.scheduler_params.on_demand_queue_max_size > ON_DEMAND_MAX_QUEUE_MAX_SIZE {
442			return Err(OnDemandQueueSizeTooLarge);
443		}
444
445		if self.n_delay_tranches.is_zero() {
446			return Err(ZeroDelayTranches);
447		}
448
449		Ok(())
450	}
451
452	/// Checks that this instance is consistent with the requirements on each individual member.
453	///
454	/// # Panics
455	///
456	/// This function panics if the configuration is inconsistent.
457	pub fn panic_if_not_consistent(&self) {
458		if let Err(err) = self.check_consistency() {
459			panic!("Host configuration is inconsistent: {:?}\nCfg:\n{:#?}", err, self);
460		}
461	}
462}
463
464pub trait WeightInfo {
465	fn set_config_with_block_number() -> Weight;
466	fn set_config_with_u32() -> Weight;
467	fn set_config_with_option_u32() -> Weight;
468	fn set_config_with_balance() -> Weight;
469	fn set_hrmp_open_request_ttl() -> Weight;
470	fn set_config_with_executor_params() -> Weight;
471	fn set_config_with_perbill() -> Weight;
472	fn set_node_feature() -> Weight;
473	fn set_config_with_scheduler_params() -> Weight;
474}
475
476pub struct TestWeightInfo;
477impl WeightInfo for TestWeightInfo {
478	fn set_config_with_block_number() -> Weight {
479		Weight::MAX
480	}
481	fn set_config_with_u32() -> Weight {
482		Weight::MAX
483	}
484	fn set_config_with_option_u32() -> Weight {
485		Weight::MAX
486	}
487	fn set_config_with_balance() -> Weight {
488		Weight::MAX
489	}
490	fn set_hrmp_open_request_ttl() -> Weight {
491		Weight::MAX
492	}
493	fn set_config_with_executor_params() -> Weight {
494		Weight::MAX
495	}
496	fn set_config_with_perbill() -> Weight {
497		Weight::MAX
498	}
499	fn set_node_feature() -> Weight {
500		Weight::MAX
501	}
502	fn set_config_with_scheduler_params() -> Weight {
503		Weight::MAX
504	}
505}
506
507#[frame_support::pallet]
508pub mod pallet {
509	use super::*;
510
511	/// The in-code storage version.
512	///
513	/// v0-v1:  <https://github.com/paritytech/polkadot/pull/3575>
514	/// v1-v2:  <https://github.com/paritytech/polkadot/pull/4420>
515	/// v2-v3:  <https://github.com/paritytech/polkadot/pull/6091>
516	/// v3-v4:  <https://github.com/paritytech/polkadot/pull/6345>
517	/// v4-v5:  <https://github.com/paritytech/polkadot/pull/6937>
518	///       + <https://github.com/paritytech/polkadot/pull/6961>
519	///       + <https://github.com/paritytech/polkadot/pull/6934>
520	/// v5-v6:  <https://github.com/paritytech/polkadot/pull/6271> (remove UMP dispatch queue)
521	/// v6-v7:  <https://github.com/paritytech/polkadot/pull/7396>
522	/// v7-v8:  <https://github.com/paritytech/polkadot/pull/6969>
523	/// v8-v9:  <https://github.com/paritytech/polkadot/pull/7577>
524	/// v9-v10: <https://github.com/paritytech/polkadot-sdk/pull/2177>
525	/// v10-11: <https://github.com/paritytech/polkadot-sdk/pull/1191>
526	/// v11-12: <https://github.com/paritytech/polkadot-sdk/pull/3181>
527	/// v12-13: added max_relay_parent_session_age to SchedulerParams
528	const STORAGE_VERSION: StorageVersion = StorageVersion::new(13);
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
880			Self::schedule_config_update(|config| {
881				config.max_upward_queue_size = new;
882			})
883		}
884
885		/// Set the critical downward message size.
886		#[pallet::call_index(25)]
887		#[pallet::weight((
888			T::WeightInfo::set_config_with_u32(),
889			DispatchClass::Operational,
890		))]
891		pub fn set_max_downward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
892			ensure_root(origin)?;
893			Self::schedule_config_update(|config| {
894				config.max_downward_message_size = new;
895			})
896		}
897
898		/// Sets the maximum size of an upward message that can be sent by a candidate.
899		#[pallet::call_index(27)]
900		#[pallet::weight((
901			T::WeightInfo::set_config_with_u32(),
902			DispatchClass::Operational,
903		))]
904		pub fn set_max_upward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
905			ensure_root(origin)?;
906			Self::schedule_config_update(|config| {
907				config.max_upward_message_size = new;
908			})
909		}
910
911		/// Sets the maximum number of messages that a candidate can contain.
912		#[pallet::call_index(28)]
913		#[pallet::weight((
914			T::WeightInfo::set_config_with_u32(),
915			DispatchClass::Operational,
916		))]
917		pub fn set_max_upward_message_num_per_candidate(
918			origin: OriginFor<T>,
919			new: u32,
920		) -> DispatchResult {
921			ensure_root(origin)?;
922			Self::schedule_config_update(|config| {
923				config.max_upward_message_num_per_candidate = new;
924			})
925		}
926
927		/// Sets the number of sessions after which an HRMP open channel request expires.
928		#[pallet::call_index(29)]
929		#[pallet::weight((
930			T::WeightInfo::set_hrmp_open_request_ttl(),
931			DispatchClass::Operational,
932		))]
933		// Deprecated, but is not marked as such, because that would trigger warnings coming from
934		// the macro.
935		pub fn set_hrmp_open_request_ttl(_origin: OriginFor<T>, _new: u32) -> DispatchResult {
936			Err("this doesn't have any effect".into())
937		}
938
939		/// Sets the amount of funds that the sender should provide for opening an HRMP channel.
940		#[pallet::call_index(30)]
941		#[pallet::weight((
942			T::WeightInfo::set_config_with_balance(),
943			DispatchClass::Operational,
944		))]
945		pub fn set_hrmp_sender_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
946			ensure_root(origin)?;
947			Self::schedule_config_update(|config| {
948				config.hrmp_sender_deposit = new;
949			})
950		}
951
952		/// Sets the amount of funds that the recipient should provide for accepting opening an HRMP
953		/// channel.
954		#[pallet::call_index(31)]
955		#[pallet::weight((
956			T::WeightInfo::set_config_with_balance(),
957			DispatchClass::Operational,
958		))]
959		pub fn set_hrmp_recipient_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
960			ensure_root(origin)?;
961			Self::schedule_config_update(|config| {
962				config.hrmp_recipient_deposit = new;
963			})
964		}
965
966		/// Sets the maximum number of messages allowed in an HRMP channel at once.
967		#[pallet::call_index(32)]
968		#[pallet::weight((
969			T::WeightInfo::set_config_with_u32(),
970			DispatchClass::Operational,
971		))]
972		pub fn set_hrmp_channel_max_capacity(origin: OriginFor<T>, new: u32) -> DispatchResult {
973			ensure_root(origin)?;
974			Self::schedule_config_update(|config| {
975				config.hrmp_channel_max_capacity = new;
976			})
977		}
978
979		/// Sets the maximum total size of messages in bytes allowed in an HRMP channel at once.
980		#[pallet::call_index(33)]
981		#[pallet::weight((
982			T::WeightInfo::set_config_with_u32(),
983			DispatchClass::Operational,
984		))]
985		pub fn set_hrmp_channel_max_total_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
986			ensure_root(origin)?;
987			Self::schedule_config_update(|config| {
988				config.hrmp_channel_max_total_size = new;
989			})
990		}
991
992		/// Sets the maximum number of inbound HRMP channels a parachain is allowed to accept.
993		#[pallet::call_index(34)]
994		#[pallet::weight((
995			T::WeightInfo::set_config_with_u32(),
996			DispatchClass::Operational,
997		))]
998		pub fn set_hrmp_max_parachain_inbound_channels(
999			origin: OriginFor<T>,
1000			new: u32,
1001		) -> DispatchResult {
1002			ensure_root(origin)?;
1003			Self::schedule_config_update(|config| {
1004				config.hrmp_max_parachain_inbound_channels = new;
1005			})
1006		}
1007
1008		/// Sets the maximum size of a message that could ever be put into an HRMP channel.
1009		#[pallet::call_index(36)]
1010		#[pallet::weight((
1011			T::WeightInfo::set_config_with_u32(),
1012			DispatchClass::Operational,
1013		))]
1014		pub fn set_hrmp_channel_max_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1015			ensure_root(origin)?;
1016			Self::schedule_config_update(|config| {
1017				config.hrmp_channel_max_message_size = new;
1018			})
1019		}
1020
1021		/// Sets the maximum number of outbound HRMP channels a parachain is allowed to open.
1022		#[pallet::call_index(37)]
1023		#[pallet::weight((
1024			T::WeightInfo::set_config_with_u32(),
1025			DispatchClass::Operational,
1026		))]
1027		pub fn set_hrmp_max_parachain_outbound_channels(
1028			origin: OriginFor<T>,
1029			new: u32,
1030		) -> DispatchResult {
1031			ensure_root(origin)?;
1032			Self::schedule_config_update(|config| {
1033				config.hrmp_max_parachain_outbound_channels = new;
1034			})
1035		}
1036
1037		/// Sets the maximum number of outbound HRMP messages can be sent by a candidate.
1038		#[pallet::call_index(39)]
1039		#[pallet::weight((
1040			T::WeightInfo::set_config_with_u32(),
1041			DispatchClass::Operational,
1042		))]
1043		pub fn set_hrmp_max_message_num_per_candidate(
1044			origin: OriginFor<T>,
1045			new: u32,
1046		) -> DispatchResult {
1047			ensure_root(origin)?;
1048			Self::schedule_config_update(|config| {
1049				config.hrmp_max_message_num_per_candidate = new;
1050			})
1051		}
1052
1053		/// Set the number of session changes after which a PVF pre-checking voting is rejected.
1054		#[pallet::call_index(42)]
1055		#[pallet::weight((
1056			T::WeightInfo::set_config_with_u32(),
1057			DispatchClass::Operational,
1058		))]
1059		pub fn set_pvf_voting_ttl(origin: OriginFor<T>, new: SessionIndex) -> DispatchResult {
1060			ensure_root(origin)?;
1061			Self::schedule_config_update(|config| {
1062				config.pvf_voting_ttl = new;
1063			})
1064		}
1065
1066		/// Sets the minimum delay between announcing the upgrade block for a parachain until the
1067		/// upgrade taking place.
1068		///
1069		/// See the field documentation for information and constraints for the new value.
1070		#[pallet::call_index(43)]
1071		#[pallet::weight((
1072			T::WeightInfo::set_config_with_block_number(),
1073			DispatchClass::Operational,
1074		))]
1075		pub fn set_minimum_validation_upgrade_delay(
1076			origin: OriginFor<T>,
1077			new: BlockNumberFor<T>,
1078		) -> DispatchResult {
1079			ensure_root(origin)?;
1080			Self::schedule_config_update(|config| {
1081				config.minimum_validation_upgrade_delay = new;
1082			})
1083		}
1084
1085		/// Setting this to true will disable consistency checks for the configuration setters.
1086		/// Use with caution.
1087		#[pallet::call_index(44)]
1088		#[pallet::weight((
1089			T::DbWeight::get().writes(1),
1090			DispatchClass::Operational,
1091		))]
1092		pub fn set_bypass_consistency_check(origin: OriginFor<T>, new: bool) -> DispatchResult {
1093			ensure_root(origin)?;
1094			BypassConsistencyCheck::<T>::put(new);
1095			Ok(())
1096		}
1097
1098		/// Set the asynchronous backing parameters.
1099		#[pallet::call_index(45)]
1100		#[pallet::weight((
1101			T::WeightInfo::set_config_with_option_u32(), // The same size in bytes.
1102			DispatchClass::Operational,
1103		))]
1104		pub fn set_async_backing_params(
1105			origin: OriginFor<T>,
1106			new: AsyncBackingParams,
1107		) -> DispatchResult {
1108			ensure_root(origin)?;
1109			Self::schedule_config_update(|config| {
1110				config.async_backing_params = new;
1111			})
1112		}
1113
1114		/// Set PVF executor parameters.
1115		#[pallet::call_index(46)]
1116		#[pallet::weight((
1117			T::WeightInfo::set_config_with_executor_params(),
1118			DispatchClass::Operational,
1119		))]
1120		pub fn set_executor_params(origin: OriginFor<T>, new: ExecutorParams) -> DispatchResult {
1121			ensure_root(origin)?;
1122			Self::schedule_config_update(|config| {
1123				config.executor_params = new;
1124			})
1125		}
1126
1127		/// Set the on demand (parathreads) base fee.
1128		#[pallet::call_index(47)]
1129		#[pallet::weight((
1130			T::WeightInfo::set_config_with_balance(),
1131			DispatchClass::Operational,
1132		))]
1133		pub fn set_on_demand_base_fee(origin: OriginFor<T>, new: Balance) -> DispatchResult {
1134			ensure_root(origin)?;
1135			Self::schedule_config_update(|config| {
1136				config.scheduler_params.on_demand_base_fee = new;
1137			})
1138		}
1139
1140		/// Set the on demand (parathreads) fee variability.
1141		#[pallet::call_index(48)]
1142		#[pallet::weight((
1143			T::WeightInfo::set_config_with_perbill(),
1144			DispatchClass::Operational,
1145		))]
1146		pub fn set_on_demand_fee_variability(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
1147			ensure_root(origin)?;
1148			Self::schedule_config_update(|config| {
1149				config.scheduler_params.on_demand_fee_variability = new;
1150			})
1151		}
1152
1153		/// Set the on demand (parathreads) queue max size.
1154		#[pallet::call_index(49)]
1155		#[pallet::weight((
1156			T::WeightInfo::set_config_with_option_u32(),
1157			DispatchClass::Operational,
1158		))]
1159		pub fn set_on_demand_queue_max_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1160			ensure_root(origin)?;
1161			Self::schedule_config_update(|config| {
1162				config.scheduler_params.on_demand_queue_max_size = new;
1163			})
1164		}
1165
1166		/// Set the on demand (parathreads) fee variability.
1167		#[pallet::call_index(50)]
1168		#[pallet::weight((
1169			T::WeightInfo::set_config_with_perbill(),
1170			DispatchClass::Operational,
1171		))]
1172		pub fn set_on_demand_target_queue_utilization(
1173			origin: OriginFor<T>,
1174			new: Perbill,
1175		) -> DispatchResult {
1176			ensure_root(origin)?;
1177			Self::schedule_config_update(|config| {
1178				config.scheduler_params.on_demand_target_queue_utilization = new;
1179			})
1180		}
1181
1182		// Call index 51 used to be `set_on_demand_ttl`, which was removed.
1183
1184		/// Set the minimum backing votes threshold.
1185		#[pallet::call_index(52)]
1186		#[pallet::weight((
1187			T::WeightInfo::set_config_with_u32(),
1188			DispatchClass::Operational
1189		))]
1190		pub fn set_minimum_backing_votes(origin: OriginFor<T>, new: u32) -> DispatchResult {
1191			ensure_root(origin)?;
1192			Self::schedule_config_update(|config| {
1193				config.minimum_backing_votes = new;
1194			})
1195		}
1196
1197		/// Set/Unset a node feature.
1198		#[pallet::call_index(53)]
1199		#[pallet::weight((
1200			T::WeightInfo::set_node_feature(),
1201			DispatchClass::Operational
1202		))]
1203		pub fn set_node_feature(origin: OriginFor<T>, index: u8, value: bool) -> DispatchResult {
1204			ensure_root(origin)?;
1205
1206			Self::schedule_config_update(|config| {
1207				let index = usize::from(index);
1208				if config.node_features.len() <= index {
1209					config.node_features.resize(index + 1, false);
1210				}
1211				config.node_features.set(index, value);
1212			})
1213		}
1214
1215		/// Set approval-voting-params.
1216		#[pallet::call_index(54)]
1217		#[pallet::weight((
1218			T::WeightInfo::set_config_with_executor_params(),
1219			DispatchClass::Operational,
1220		))]
1221		pub fn set_approval_voting_params(
1222			origin: OriginFor<T>,
1223			new: ApprovalVotingParams,
1224		) -> DispatchResult {
1225			ensure_root(origin)?;
1226			Self::schedule_config_update(|config| {
1227				config.approval_voting_params = new;
1228			})
1229		}
1230
1231		/// Set scheduler-params.
1232		#[pallet::call_index(55)]
1233		#[pallet::weight((
1234			T::WeightInfo::set_config_with_scheduler_params(),
1235			DispatchClass::Operational,
1236		))]
1237		pub fn set_scheduler_params(
1238			origin: OriginFor<T>,
1239			new: SchedulerParams<BlockNumberFor<T>>,
1240		) -> DispatchResult {
1241			ensure_root(origin)?;
1242			Self::schedule_config_update(|config| {
1243				config.scheduler_params = new;
1244			})
1245		}
1246
1247		/// Set the maximum relay parent session age.
1248		#[pallet::call_index(56)]
1249		#[pallet::weight((
1250			T::WeightInfo::set_config_with_u32(),
1251			DispatchClass::Operational,
1252		))]
1253		pub fn set_max_relay_parent_session_age(origin: OriginFor<T>, new: u32) -> DispatchResult {
1254			ensure_root(origin)?;
1255			Self::schedule_config_update(|config| {
1256				config.max_relay_parent_session_age = new;
1257			})
1258		}
1259	}
1260
1261	impl<T: Config> Pallet<T> {
1262		/// Set coretime cores.
1263		///
1264		/// To be used if authorization is checked otherwise.
1265		pub fn set_coretime_cores_unchecked(new: u32) -> DispatchResult {
1266			Self::schedule_config_update(|config| {
1267				config.scheduler_params.num_cores = new;
1268			})
1269		}
1270	}
1271
1272	#[pallet::hooks]
1273	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1274		fn integrity_test() {
1275			assert_eq!(
1276				&ActiveConfig::<T>::hashed_key(),
1277				polkadot_primitives::well_known_keys::ACTIVE_CONFIG,
1278				"`well_known_keys::ACTIVE_CONFIG` doesn't match key of `ActiveConfig`! Make sure that the name of the\
1279				 configuration pallet is `Configuration` in the runtime!",
1280			);
1281		}
1282	}
1283}
1284
1285/// A struct that holds the configuration that was active before the session change and optionally
1286/// a configuration that became active after the session change.
1287pub struct SessionChangeOutcome<BlockNumber> {
1288	/// Previously active configuration.
1289	pub prev_config: HostConfiguration<BlockNumber>,
1290	/// If new configuration was applied during the session change, this is the new configuration.
1291	pub new_config: Option<HostConfiguration<BlockNumber>>,
1292}
1293
1294impl<T: Config> Pallet<T> {
1295	/// Called by the initializer to initialize the configuration pallet.
1296	pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
1297		Weight::zero()
1298	}
1299
1300	/// Called by the initializer to finalize the configuration pallet.
1301	pub(crate) fn initializer_finalize() {}
1302
1303	/// Called by the initializer to note that a new session has started.
1304	///
1305	/// Returns the configuration that was actual before the session change and the configuration
1306	/// that became active after the session change. If there were no scheduled changes, both will
1307	/// be the same.
1308	pub(crate) fn initializer_on_new_session(
1309		session_index: &SessionIndex,
1310	) -> SessionChangeOutcome<BlockNumberFor<T>> {
1311		let pending_configs = PendingConfigs::<T>::get();
1312		let prev_config = ActiveConfig::<T>::get();
1313
1314		// No pending configuration changes, so we're done.
1315		if pending_configs.is_empty() {
1316			return SessionChangeOutcome { prev_config, new_config: None };
1317		}
1318
1319		let (mut past_and_present, future) = pending_configs
1320			.into_iter()
1321			.partition::<Vec<_>, _>(|&(apply_at_session, _)| apply_at_session <= *session_index);
1322
1323		if past_and_present.len() > 1 {
1324			// This should never happen since we schedule configuration changes only into the future
1325			// sessions and this handler called for each session change.
1326			log::error!(
1327				target: LOG_TARGET,
1328				"Skipping applying configuration changes scheduled sessions in the past",
1329			);
1330		}
1331
1332		let new_config = past_and_present.pop().map(|(_, config)| config);
1333		if let Some(ref new_config) = new_config {
1334			// Apply the new configuration.
1335			ActiveConfig::<T>::put(new_config);
1336		}
1337
1338		PendingConfigs::<T>::put(future);
1339
1340		SessionChangeOutcome { prev_config, new_config }
1341	}
1342
1343	/// Return the session index that should be used for any future scheduled changes.
1344	fn scheduled_session() -> SessionIndex {
1345		shared::Pallet::<T>::scheduled_session()
1346	}
1347
1348	/// Forcibly set the active config. This should be used with extreme care, and typically
1349	/// only when enabling parachains runtime pallets for the first time on a chain which has
1350	/// been running without them.
1351	pub fn force_set_active_config(config: HostConfiguration<BlockNumberFor<T>>) {
1352		ActiveConfig::<T>::set(config);
1353	}
1354
1355	/// This function should be used to update members of the configuration.
1356	///
1357	/// This function is used to update the configuration in a way that is safe. It will check the
1358	/// resulting configuration and ensure that the update is valid. If the update is invalid, it
1359	/// will check if the previous configuration was valid. If it was invalid, we proceed with
1360	/// updating the configuration, giving a chance to recover from such a condition.
1361	///
1362	/// The actual configuration change takes place after a couple of sessions have passed. In case
1363	/// this function is called more than once in the same session, then the pending configuration
1364	/// change will be updated.
1365	/// In other words, all the configuration changes made in the same session will be folded
1366	/// together in the order they were made, and only once the scheduled session is reached will
1367	/// the final pending configuration be applied.
1368	// NOTE: Explicitly tell rustc not to inline this, because otherwise heuristics note the
1369	// incoming closure make it attractive to inline. However, in that case, we will end up with
1370	// lots of duplicated code (making this function show up on top of the heaviest functions) only
1371	// for the sake of essentially avoiding an indirect call. It is not worth it.
1372	#[inline(never)]
1373	pub(crate) fn schedule_config_update(
1374		updater: impl FnOnce(&mut HostConfiguration<BlockNumberFor<T>>),
1375	) -> DispatchResult {
1376		let mut pending_configs = PendingConfigs::<T>::get();
1377
1378		// 1. pending_configs = [] No pending configuration changes.
1379		//
1380		//    That means we should use the active config as the base configuration. We will insert
1381		//    the new pending configuration as (cur+2, new_config) into the list.
1382		//
1383		// 2. pending_configs = [(cur+2, X)] There is a configuration that is pending for the
1384		//    scheduled session.
1385		//
1386		//    We will use X as the base configuration. We can update the pending configuration X
1387		//    directly.
1388		//
1389		// 3. pending_configs = [(cur+1, X)] There is a pending configuration scheduled and it will
1390		//    be applied in the next session.
1391		//
1392		//    We will use X as the base configuration. We need to schedule a new configuration
1393		// change    for the `scheduled_session` and use X as the base for the new configuration.
1394		//
1395		// 4. pending_configs = [(cur+1, X), (cur+2, Y)] There is a pending configuration change in
1396		//    the next session and for the scheduled session. Due to case №3, we can be sure that Y
1397		//    is based on top of X. This means we can use Y as the base configuration and update Y
1398		//    directly.
1399		//
1400		// There cannot be (cur, X) because those are applied in the session change handler for the
1401		// current session.
1402
1403		// First, we need to decide what we should use as the base configuration.
1404		let mut base_config = pending_configs
1405			.last()
1406			.map(|(_, config)| config.clone())
1407			.unwrap_or_else(ActiveConfig::<T>::get);
1408		let base_config_consistent = base_config.check_consistency().is_ok();
1409
1410		// Now, we need to decide what the new configuration should be.
1411		// We also move the `base_config` to `new_config` to emphasize that the base config was
1412		// destroyed by the `updater`.
1413		updater(&mut base_config);
1414		let new_config = base_config;
1415
1416		if BypassConsistencyCheck::<T>::get() {
1417			// This will emit a warning each configuration update if the consistency check is
1418			// bypassed. This is an attempt to make sure the bypass is not accidentally left on.
1419			log::warn!(
1420				target: LOG_TARGET,
1421				"Bypassing the consistency check for the configuration change!",
1422			);
1423		} else if let Err(e) = new_config.check_consistency() {
1424			if base_config_consistent {
1425				// Base configuration is consistent and the new configuration is inconsistent.
1426				// This means that the value set by the `updater` is invalid and we can return
1427				// it as an error.
1428				log::warn!(
1429					target: LOG_TARGET,
1430					"Configuration change rejected due to invalid configuration: {:?}",
1431					e,
1432				);
1433				return Err(Error::<T>::InvalidNewValue.into());
1434			} else {
1435				// The configuration was already broken, so we can as well proceed with the update.
1436				// You cannot break something that is already broken.
1437				//
1438				// That will allow to call several functions and ultimately return the configuration
1439				// into consistent state.
1440				log::warn!(
1441					target: LOG_TARGET,
1442					"The new configuration is broken but the old is broken as well. Proceeding",
1443				);
1444			}
1445		}
1446
1447		let scheduled_session = Self::scheduled_session();
1448
1449		if let Some(&mut (_, ref mut config)) = pending_configs
1450			.iter_mut()
1451			.find(|&&mut (apply_at_session, _)| apply_at_session >= scheduled_session)
1452		{
1453			*config = new_config;
1454		} else {
1455			// We are scheduling a new configuration change for the scheduled session.
1456			pending_configs.push((scheduled_session, new_config));
1457		}
1458
1459		PendingConfigs::<T>::put(pending_configs);
1460
1461		Ok(())
1462	}
1463}
1464
1465/// The implementation of `Get<(u32, u32)>` which reads `ActiveConfig` and returns `P` percent of
1466/// `hrmp_channel_max_message_size` / `hrmp_channel_max_capacity`.
1467pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>(core::marker::PhantomData<(T, P)>);
1468impl<T: crate::hrmp::pallet::Config, P: Get<Percent>> Get<(u32, u32)>
1469	for ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>
1470{
1471	fn get() -> (u32, u32) {
1472		let config = ActiveConfig::<T>::get();
1473		let percent = P::get();
1474		(percent * config.hrmp_channel_max_message_size, percent * config.hrmp_channel_max_capacity)
1475	}
1476}