1use 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
49const POV_SIZE_HARD_LIMIT: u32 = 16 * 1024 * 1024;
52
53pub(crate) const MAX_VALIDATION_CODE_COMPRESSION_RATIO: u32 = 10;
55
56#[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 pub max_code_size: u32,
79 pub max_head_data_size: u32,
81 pub max_upward_queue_count: u32,
83 pub max_upward_queue_size: u32,
87 pub max_upward_message_size: u32,
91 pub max_upward_message_num_per_candidate: u32,
95 pub hrmp_max_message_num_per_candidate: u32,
99 #[cfg_attr(feature = "std", serde(alias = "validation_upgrade_frequency"))]
110 pub validation_upgrade_cooldown: BlockNumber,
111 pub validation_upgrade_delay: BlockNumber,
138 pub async_backing_params: AsyncBackingParams,
140
141 pub max_pov_size: u32,
145 pub max_downward_message_size: u32,
152 pub hrmp_max_parachain_outbound_channels: u32,
154 pub hrmp_sender_deposit: Balance,
156 pub hrmp_recipient_deposit: Balance,
158 pub hrmp_channel_max_capacity: u32,
160 pub hrmp_channel_max_total_size: u32,
162 pub hrmp_max_parachain_inbound_channels: u32,
164 pub hrmp_channel_max_message_size: u32,
168 pub executor_params: ExecutorParams,
170
171 pub code_retention_period: BlockNumber,
176
177 pub max_validators: Option<u32>,
181 pub dispute_period: SessionIndex,
183 pub dispute_post_conclusion_acceptance_period: BlockNumber,
185 pub no_show_slots: u32,
190 pub n_delay_tranches: u32,
192 pub zeroth_delay_tranche_width: u32,
195 pub needed_approvals: u32,
197 pub relay_vrf_modulo_samples: u32,
199 pub pvf_voting_ttl: SessionIndex,
205 pub minimum_validation_upgrade_delay: BlockNumber,
222 pub minimum_backing_votes: u32,
225 pub node_features: NodeFeatures,
227 pub approval_voting_params: ApprovalVotingParams,
229 pub scheduler_params: SchedulerParams<BlockNumber>,
231 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 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#[derive(Debug)]
306pub enum InconsistentError<BlockNumber> {
307 ZeroGroupRotationFrequency,
309 ZeroParasAvailabilityPeriod,
311 ZeroNoShowSlots,
313 MaxCodeSizeExceedHardLimit { max_code_size: u32 },
315 MaxHeadDataSizeExceedHardLimit { max_head_data_size: u32 },
317 MaxPovSizeExceedHardLimit { max_pov_size: u32 },
319 MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
321 minimum_validation_upgrade_delay: BlockNumber,
322 paras_availability_period: BlockNumber,
323 },
324 ValidationUpgradeDelayIsTooLow { validation_upgrade_delay: BlockNumber },
326 MaxUpwardMessageSizeExceeded { max_message_size: u32 },
330 MaxHorizontalMessageNumExceeded { max_message_num: u32 },
332 MaxUpwardMessageNumExceeded { max_message_num: u32 },
334 MaxHrmpOutboundChannelsExceeded,
336 MaxHrmpInboundChannelsExceeded,
338 ZeroMinimumBackingVotes,
340 InconsistentExecutorParams { inner: ExecutorParamError },
342 LookaheadZero,
344 OnDemandQueueSizeTooLarge,
346 ZeroDelayTranches,
348}
349
350impl<BlockNumber> HostConfiguration<BlockNumber>
351where
352 BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From<u32>,
353{
354 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 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 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 type WeightInfo: WeightInfo;
539 }
540
541 #[pallet::error]
542 pub enum Error<T> {
543 InvalidNewValue,
545 }
546
547 #[pallet::storage]
549 #[pallet::whitelist_storage]
550 pub type ActiveConfig<T: Config> =
551 StorageValue<_, HostConfiguration<BlockNumberFor<T>>, ValueQuery>;
552
553 #[pallet::storage]
561 pub type PendingConfigs<T: Config> =
562 StorageValue<_, Vec<(SessionIndex, HostConfiguration<BlockNumberFor<T>>)>, ValueQuery>;
563
564 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[pallet::call_index(29)]
929 #[pallet::weight((
930 T::WeightInfo::set_hrmp_open_request_ttl(),
931 DispatchClass::Operational,
932 ))]
933 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[pallet::call_index(45)]
1100 #[pallet::weight((
1101 T::WeightInfo::set_config_with_option_u32(), 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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
1285pub struct SessionChangeOutcome<BlockNumber> {
1288 pub prev_config: HostConfiguration<BlockNumber>,
1290 pub new_config: Option<HostConfiguration<BlockNumber>>,
1292}
1293
1294impl<T: Config> Pallet<T> {
1295 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
1297 Weight::zero()
1298 }
1299
1300 pub(crate) fn initializer_finalize() {}
1302
1303 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 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 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 ActiveConfig::<T>::put(new_config);
1336 }
1337
1338 PendingConfigs::<T>::put(future);
1339
1340 SessionChangeOutcome { prev_config, new_config }
1341 }
1342
1343 fn scheduled_session() -> SessionIndex {
1345 shared::Pallet::<T>::scheduled_session()
1346 }
1347
1348 pub fn force_set_active_config(config: HostConfiguration<BlockNumberFor<T>>) {
1352 ActiveConfig::<T>::set(config);
1353 }
1354
1355 #[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 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 updater(&mut base_config);
1414 let new_config = base_config;
1415
1416 if BypassConsistencyCheck::<T>::get() {
1417 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 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 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 pending_configs.push((scheduled_session, new_config));
1457 }
1458
1459 PendingConfigs::<T>::put(pending_configs);
1460
1461 Ok(())
1462 }
1463}
1464
1465pub 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}