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