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_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
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 MaxApprovalCoalesceCountExceedHardLimit { max_approval_coalesce_count: u32 },
322 MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
324 minimum_validation_upgrade_delay: BlockNumber,
325 paras_availability_period: BlockNumber,
326 },
327 ValidationUpgradeDelayIsTooLow { validation_upgrade_delay: BlockNumber },
329 MaxUpwardMessageSizeExceeded { max_message_size: u32 },
333 MaxHorizontalMessageNumExceeded { max_message_num: u32 },
335 MaxUpwardMessageNumExceeded { max_message_num: u32 },
337 MaxHrmpOutboundChannelsExceeded,
339 MaxHrmpInboundChannelsExceeded,
341 ZeroMinimumBackingVotes,
343 InconsistentExecutorParams { inner: ExecutorParamError },
345 LookaheadZero,
347 OnDemandQueueSizeTooLarge,
349 ZeroDelayTranches,
351}
352
353impl<BlockNumber> HostConfiguration<BlockNumber>
354where
355 BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From<u32>,
356{
357 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 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 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 type WeightInfo: WeightInfo;
550 }
551
552 #[pallet::error]
553 pub enum Error<T> {
554 InvalidNewValue,
556 }
557
558 #[pallet::storage]
560 #[pallet::whitelist_storage]
561 pub type ActiveConfig<T: Config> =
562 StorageValue<_, HostConfiguration<BlockNumberFor<T>>, ValueQuery>;
563
564 #[pallet::storage]
572 pub type PendingConfigs<T: Config> =
573 StorageValue<_, Vec<(SessionIndex, HostConfiguration<BlockNumberFor<T>>)>, ValueQuery>;
574
575 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[pallet::call_index(29)]
940 #[pallet::weight((
941 T::WeightInfo::set_hrmp_open_request_ttl(),
942 DispatchClass::Operational,
943 ))]
944 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[pallet::call_index(45)]
1111 #[pallet::weight((
1112 T::WeightInfo::set_config_with_option_u32(), 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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
1296pub struct SessionChangeOutcome<BlockNumber> {
1299 pub prev_config: HostConfiguration<BlockNumber>,
1301 pub new_config: Option<HostConfiguration<BlockNumber>>,
1303}
1304
1305impl<T: Config> Pallet<T> {
1306 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
1308 Weight::zero()
1309 }
1310
1311 pub(crate) fn initializer_finalize() {}
1313
1314 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 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 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 ActiveConfig::<T>::put(new_config);
1347 }
1348
1349 PendingConfigs::<T>::put(future);
1350
1351 SessionChangeOutcome { prev_config, new_config }
1352 }
1353
1354 fn scheduled_session() -> SessionIndex {
1356 shared::Pallet::<T>::scheduled_session()
1357 }
1358
1359 pub fn force_set_active_config(config: HostConfiguration<BlockNumberFor<T>>) {
1363 ActiveConfig::<T>::set(config);
1364 }
1365
1366 #[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 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 updater(&mut base_config);
1425 let new_config = base_config;
1426
1427 if BypassConsistencyCheck::<T>::get() {
1428 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 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 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 pending_configs.push((scheduled_session, new_config));
1468 }
1469
1470 PendingConfigs::<T>::put(pending_configs);
1471
1472 Ok(())
1473 }
1474}
1475
1476pub 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}