1use crate::{inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND, shared};
22use alloc::vec::Vec;
23use codec::{Decode, Encode};
24use frame_support::{pallet_prelude::*, DefaultNoBound};
25use frame_system::pallet_prelude::*;
26use polkadot_parachain_primitives::primitives::{
27 MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM,
28};
29use polkadot_primitives::{
30 ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams,
31 NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE,
32 ON_DEMAND_MAX_QUEUE_MAX_SIZE,
33};
34use sp_runtime::{traits::Zero, Perbill, Percent};
35
36#[cfg(test)]
37mod tests;
38
39#[cfg(feature = "runtime-benchmarks")]
40mod benchmarking;
41
42pub mod migration;
43
44pub use pallet::*;
45use polkadot_primitives::SchedulerParams;
46
47const LOG_TARGET: &str = "runtime::configuration";
48
49const POV_SIZE_HARD_LIMIT: u32 = 16 * 1024 * 1024;
52
53#[derive(
55 Clone,
56 Encode,
57 Decode,
58 PartialEq,
59 sp_core::RuntimeDebug,
60 scale_info::TypeInfo,
61 serde::Serialize,
62 serde::Deserialize,
63)]
64#[serde(deny_unknown_fields)]
65pub struct HostConfiguration<BlockNumber> {
66 pub max_code_size: u32,
78 pub max_head_data_size: u32,
80 pub max_upward_queue_count: u32,
82 pub max_upward_queue_size: u32,
86 pub max_upward_message_size: u32,
90 pub max_upward_message_num_per_candidate: u32,
94 pub hrmp_max_message_num_per_candidate: u32,
98 #[cfg_attr(feature = "std", serde(alias = "validation_upgrade_frequency"))]
109 pub validation_upgrade_cooldown: BlockNumber,
110 pub validation_upgrade_delay: BlockNumber,
137 pub async_backing_params: AsyncBackingParams,
139
140 pub max_pov_size: u32,
146 pub max_downward_message_size: u32,
153 pub hrmp_max_parachain_outbound_channels: u32,
155 pub hrmp_sender_deposit: Balance,
157 pub hrmp_recipient_deposit: Balance,
159 pub hrmp_channel_max_capacity: u32,
161 pub hrmp_channel_max_total_size: u32,
163 pub hrmp_max_parachain_inbound_channels: u32,
165 pub hrmp_channel_max_message_size: u32,
169 pub executor_params: ExecutorParams,
171
172 pub code_retention_period: BlockNumber,
179
180 pub max_validators: Option<u32>,
184 pub dispute_period: SessionIndex,
186 pub dispute_post_conclusion_acceptance_period: BlockNumber,
188 pub no_show_slots: u32,
193 pub n_delay_tranches: u32,
195 pub zeroth_delay_tranche_width: u32,
198 pub needed_approvals: u32,
200 pub relay_vrf_modulo_samples: u32,
202 pub pvf_voting_ttl: SessionIndex,
208 pub minimum_validation_upgrade_delay: BlockNumber,
225 pub minimum_backing_votes: u32,
228 pub node_features: NodeFeatures,
230 pub approval_voting_params: ApprovalVotingParams,
232 pub scheduler_params: SchedulerParams<BlockNumber>,
234}
235
236impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber> {
237 fn default() -> Self {
238 let ret = Self {
239 async_backing_params: AsyncBackingParams {
240 max_candidate_depth: 0,
241 allowed_ancestry_len: 0,
242 },
243 no_show_slots: 1u32.into(),
244 validation_upgrade_cooldown: Default::default(),
245 validation_upgrade_delay: 2u32.into(),
246 code_retention_period: Default::default(),
247 max_code_size: MAX_CODE_SIZE,
248 max_pov_size: Default::default(),
249 max_head_data_size: Default::default(),
250 max_validators: None,
251 dispute_period: 6,
252 dispute_post_conclusion_acceptance_period: 100.into(),
253 n_delay_tranches: 1,
254 zeroth_delay_tranche_width: Default::default(),
255 needed_approvals: Default::default(),
256 relay_vrf_modulo_samples: Default::default(),
257 max_upward_queue_count: Default::default(),
258 max_upward_queue_size: Default::default(),
259 max_downward_message_size: Default::default(),
260 max_upward_message_size: Default::default(),
261 max_upward_message_num_per_candidate: Default::default(),
262 hrmp_sender_deposit: Default::default(),
263 hrmp_recipient_deposit: Default::default(),
264 hrmp_channel_max_capacity: Default::default(),
265 hrmp_channel_max_total_size: Default::default(),
266 hrmp_max_parachain_inbound_channels: Default::default(),
267 hrmp_channel_max_message_size: Default::default(),
268 hrmp_max_parachain_outbound_channels: Default::default(),
269 hrmp_max_message_num_per_candidate: Default::default(),
270 pvf_voting_ttl: 2u32.into(),
271 minimum_validation_upgrade_delay: 2.into(),
272 executor_params: Default::default(),
273 approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 },
274 minimum_backing_votes: LEGACY_MIN_BACKING_VOTES,
275 node_features: NodeFeatures::EMPTY,
276 scheduler_params: Default::default(),
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 },
328 MaxHorizontalMessageNumExceeded { max_message_num: u32 },
330 MaxUpwardMessageNumExceeded { max_message_num: u32 },
332 MaxHrmpOutboundChannelsExceeded,
334 MaxHrmpInboundChannelsExceeded,
336 ZeroMinimumBackingVotes,
338 InconsistentExecutorParams { inner: ExecutorParamError },
340 LookaheadZero,
342 OnDemandQueueSizeTooLarge,
344 ZeroDelayTranches,
346}
347
348impl<BlockNumber> HostConfiguration<BlockNumber>
349where
350 BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From<u32>,
351{
352 pub fn check_consistency(&self) -> Result<(), InconsistentError<BlockNumber>> {
358 use InconsistentError::*;
359
360 if self.scheduler_params.group_rotation_frequency.is_zero() {
361 return Err(ZeroGroupRotationFrequency)
362 }
363
364 if self.scheduler_params.paras_availability_period.is_zero() {
365 return Err(ZeroParasAvailabilityPeriod)
366 }
367
368 if self.no_show_slots.is_zero() {
369 return Err(ZeroNoShowSlots)
370 }
371
372 if self.max_code_size > MAX_CODE_SIZE {
373 return Err(MaxCodeSizeExceedHardLimit { max_code_size: self.max_code_size })
374 }
375
376 if self.max_head_data_size > MAX_HEAD_DATA_SIZE {
377 return Err(MaxHeadDataSizeExceedHardLimit {
378 max_head_data_size: self.max_head_data_size,
379 })
380 }
381
382 if self.max_pov_size > POV_SIZE_HARD_LIMIT {
383 return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size })
384 }
385
386 if self.minimum_validation_upgrade_delay <= self.scheduler_params.paras_availability_period
387 {
388 return Err(MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
389 minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(),
390 paras_availability_period: self.scheduler_params.paras_availability_period.clone(),
391 })
392 }
393
394 if self.validation_upgrade_delay <= 1.into() {
395 return Err(ValidationUpgradeDelayIsTooLow {
396 validation_upgrade_delay: self.validation_upgrade_delay.clone(),
397 })
398 }
399
400 if self.max_upward_message_size > crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND {
401 return Err(MaxUpwardMessageSizeExceeded {
402 max_message_size: self.max_upward_message_size,
403 })
404 }
405
406 if self.hrmp_max_message_num_per_candidate > MAX_HORIZONTAL_MESSAGE_NUM {
407 return Err(MaxHorizontalMessageNumExceeded {
408 max_message_num: self.hrmp_max_message_num_per_candidate,
409 })
410 }
411
412 if self.max_upward_message_num_per_candidate > MAX_UPWARD_MESSAGE_NUM {
413 return Err(MaxUpwardMessageNumExceeded {
414 max_message_num: self.max_upward_message_num_per_candidate,
415 })
416 }
417
418 if self.hrmp_max_parachain_outbound_channels > crate::hrmp::HRMP_MAX_OUTBOUND_CHANNELS_BOUND
419 {
420 return Err(MaxHrmpOutboundChannelsExceeded)
421 }
422
423 if self.hrmp_max_parachain_inbound_channels > crate::hrmp::HRMP_MAX_INBOUND_CHANNELS_BOUND {
424 return Err(MaxHrmpInboundChannelsExceeded)
425 }
426
427 if self.minimum_backing_votes.is_zero() {
428 return Err(ZeroMinimumBackingVotes)
429 }
430
431 if let Err(inner) = self.executor_params.check_consistency() {
432 return Err(InconsistentExecutorParams { inner })
433 }
434
435 if self.scheduler_params.lookahead == 0 {
436 return Err(LookaheadZero)
437 }
438
439 if self.scheduler_params.on_demand_queue_max_size > ON_DEMAND_MAX_QUEUE_MAX_SIZE {
440 return Err(OnDemandQueueSizeTooLarge)
441 }
442
443 if self.n_delay_tranches.is_zero() {
444 return Err(ZeroDelayTranches)
445 }
446
447 Ok(())
448 }
449
450 pub fn panic_if_not_consistent(&self) {
456 if let Err(err) = self.check_consistency() {
457 panic!("Host configuration is inconsistent: {:?}\nCfg:\n{:#?}", err, self);
458 }
459 }
460}
461
462pub trait WeightInfo {
463 fn set_config_with_block_number() -> Weight;
464 fn set_config_with_u32() -> Weight;
465 fn set_config_with_option_u32() -> Weight;
466 fn set_config_with_balance() -> Weight;
467 fn set_hrmp_open_request_ttl() -> Weight;
468 fn set_config_with_executor_params() -> Weight;
469 fn set_config_with_perbill() -> Weight;
470 fn set_node_feature() -> Weight;
471 fn set_config_with_scheduler_params() -> Weight;
472}
473
474pub struct TestWeightInfo;
475impl WeightInfo for TestWeightInfo {
476 fn set_config_with_block_number() -> Weight {
477 Weight::MAX
478 }
479 fn set_config_with_u32() -> Weight {
480 Weight::MAX
481 }
482 fn set_config_with_option_u32() -> Weight {
483 Weight::MAX
484 }
485 fn set_config_with_balance() -> Weight {
486 Weight::MAX
487 }
488 fn set_hrmp_open_request_ttl() -> Weight {
489 Weight::MAX
490 }
491 fn set_config_with_executor_params() -> Weight {
492 Weight::MAX
493 }
494 fn set_config_with_perbill() -> Weight {
495 Weight::MAX
496 }
497 fn set_node_feature() -> Weight {
498 Weight::MAX
499 }
500 fn set_config_with_scheduler_params() -> Weight {
501 Weight::MAX
502 }
503}
504
505#[frame_support::pallet]
506pub mod pallet {
507 use super::*;
508
509 const STORAGE_VERSION: StorageVersion = StorageVersion::new(12);
526
527 #[pallet::pallet]
528 #[pallet::storage_version(STORAGE_VERSION)]
529 #[pallet::without_storage_info]
530 pub struct Pallet<T>(_);
531
532 #[pallet::config]
533 pub trait Config: frame_system::Config + shared::Config {
534 type WeightInfo: WeightInfo;
536 }
537
538 #[pallet::error]
539 pub enum Error<T> {
540 InvalidNewValue,
542 }
543
544 #[pallet::storage]
546 #[pallet::whitelist_storage]
547 pub type ActiveConfig<T: Config> =
548 StorageValue<_, HostConfiguration<BlockNumberFor<T>>, ValueQuery>;
549
550 #[pallet::storage]
558 pub type PendingConfigs<T: Config> =
559 StorageValue<_, Vec<(SessionIndex, HostConfiguration<BlockNumberFor<T>>)>, ValueQuery>;
560
561 #[pallet::storage]
564 pub(crate) type BypassConsistencyCheck<T: Config> = StorageValue<_, bool, ValueQuery>;
565
566 #[pallet::genesis_config]
567 #[derive(DefaultNoBound)]
568 pub struct GenesisConfig<T: Config> {
569 pub config: HostConfiguration<BlockNumberFor<T>>,
570 }
571
572 #[pallet::genesis_build]
573 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
574 fn build(&self) {
575 self.config.panic_if_not_consistent();
576 ActiveConfig::<T>::put(&self.config);
577 }
578 }
579
580 #[pallet::call]
581 impl<T: Config> Pallet<T> {
582 #[pallet::call_index(0)]
584 #[pallet::weight((
585 T::WeightInfo::set_config_with_block_number(),
586 DispatchClass::Operational,
587 ))]
588 pub fn set_validation_upgrade_cooldown(
589 origin: OriginFor<T>,
590 new: BlockNumberFor<T>,
591 ) -> DispatchResult {
592 ensure_root(origin)?;
593 Self::schedule_config_update(|config| {
594 config.validation_upgrade_cooldown = new;
595 })
596 }
597
598 #[pallet::call_index(1)]
600 #[pallet::weight((
601 T::WeightInfo::set_config_with_block_number(),
602 DispatchClass::Operational,
603 ))]
604 pub fn set_validation_upgrade_delay(
605 origin: OriginFor<T>,
606 new: BlockNumberFor<T>,
607 ) -> DispatchResult {
608 ensure_root(origin)?;
609 Self::schedule_config_update(|config| {
610 config.validation_upgrade_delay = new;
611 })
612 }
613
614 #[pallet::call_index(2)]
616 #[pallet::weight((
617 T::WeightInfo::set_config_with_block_number(),
618 DispatchClass::Operational,
619 ))]
620 pub fn set_code_retention_period(
621 origin: OriginFor<T>,
622 new: BlockNumberFor<T>,
623 ) -> DispatchResult {
624 ensure_root(origin)?;
625 Self::schedule_config_update(|config| {
626 config.code_retention_period = new;
627 })
628 }
629
630 #[pallet::call_index(3)]
632 #[pallet::weight((
633 T::WeightInfo::set_config_with_u32(),
634 DispatchClass::Operational,
635 ))]
636 pub fn set_max_code_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
637 ensure_root(origin)?;
638 Self::schedule_config_update(|config| {
639 config.max_code_size = new;
640 })
641 }
642
643 #[pallet::call_index(4)]
645 #[pallet::weight((
646 T::WeightInfo::set_config_with_u32(),
647 DispatchClass::Operational,
648 ))]
649 pub fn set_max_pov_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
650 ensure_root(origin)?;
651 Self::schedule_config_update(|config| {
652 config.max_pov_size = new;
653 })
654 }
655
656 #[pallet::call_index(5)]
658 #[pallet::weight((
659 T::WeightInfo::set_config_with_u32(),
660 DispatchClass::Operational,
661 ))]
662 pub fn set_max_head_data_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
663 ensure_root(origin)?;
664 Self::schedule_config_update(|config| {
665 config.max_head_data_size = new;
666 })
667 }
668
669 #[pallet::call_index(6)]
674 #[pallet::weight((
675 T::WeightInfo::set_config_with_u32(),
676 DispatchClass::Operational,
677 ))]
678 pub fn set_coretime_cores(origin: OriginFor<T>, new: u32) -> DispatchResult {
679 ensure_root(origin)?;
680 Self::set_coretime_cores_unchecked(new)
681 }
682
683 #[pallet::call_index(8)]
687 #[pallet::weight((
688 T::WeightInfo::set_config_with_block_number(),
689 DispatchClass::Operational,
690 ))]
691 pub fn set_group_rotation_frequency(
692 origin: OriginFor<T>,
693 new: BlockNumberFor<T>,
694 ) -> DispatchResult {
695 ensure_root(origin)?;
696 Self::schedule_config_update(|config| {
697 config.scheduler_params.group_rotation_frequency = new;
698 })
699 }
700
701 #[pallet::call_index(9)]
703 #[pallet::weight((
704 T::WeightInfo::set_config_with_block_number(),
705 DispatchClass::Operational,
706 ))]
707 pub fn set_paras_availability_period(
708 origin: OriginFor<T>,
709 new: BlockNumberFor<T>,
710 ) -> DispatchResult {
711 ensure_root(origin)?;
712 Self::schedule_config_update(|config| {
713 config.scheduler_params.paras_availability_period = new;
714 })
715 }
716
717 #[pallet::call_index(11)]
719 #[pallet::weight((
720 T::WeightInfo::set_config_with_u32(),
721 DispatchClass::Operational,
722 ))]
723 pub fn set_scheduling_lookahead(origin: OriginFor<T>, new: u32) -> DispatchResult {
724 ensure_root(origin)?;
725 Self::schedule_config_update(|config| {
726 config.scheduler_params.lookahead = new;
727 })
728 }
729
730 #[pallet::call_index(12)]
732 #[pallet::weight((
733 T::WeightInfo::set_config_with_option_u32(),
734 DispatchClass::Operational,
735 ))]
736 pub fn set_max_validators_per_core(
737 origin: OriginFor<T>,
738 new: Option<u32>,
739 ) -> DispatchResult {
740 ensure_root(origin)?;
741 Self::schedule_config_update(|config| {
742 config.scheduler_params.max_validators_per_core = new;
743 })
744 }
745
746 #[pallet::call_index(13)]
748 #[pallet::weight((
749 T::WeightInfo::set_config_with_option_u32(),
750 DispatchClass::Operational,
751 ))]
752 pub fn set_max_validators(origin: OriginFor<T>, new: Option<u32>) -> DispatchResult {
753 ensure_root(origin)?;
754 Self::schedule_config_update(|config| {
755 config.max_validators = new;
756 })
757 }
758
759 #[pallet::call_index(14)]
761 #[pallet::weight((
762 T::WeightInfo::set_config_with_u32(),
763 DispatchClass::Operational,
764 ))]
765 pub fn set_dispute_period(origin: OriginFor<T>, new: SessionIndex) -> DispatchResult {
766 ensure_root(origin)?;
767 Self::schedule_config_update(|config| {
768 config.dispute_period = new;
769 })
770 }
771
772 #[pallet::call_index(15)]
774 #[pallet::weight((
775 T::WeightInfo::set_config_with_block_number(),
776 DispatchClass::Operational,
777 ))]
778 pub fn set_dispute_post_conclusion_acceptance_period(
779 origin: OriginFor<T>,
780 new: BlockNumberFor<T>,
781 ) -> DispatchResult {
782 ensure_root(origin)?;
783 Self::schedule_config_update(|config| {
784 config.dispute_post_conclusion_acceptance_period = new;
785 })
786 }
787
788 #[pallet::call_index(18)]
791 #[pallet::weight((
792 T::WeightInfo::set_config_with_u32(),
793 DispatchClass::Operational,
794 ))]
795 pub fn set_no_show_slots(origin: OriginFor<T>, new: u32) -> DispatchResult {
796 ensure_root(origin)?;
797 Self::schedule_config_update(|config| {
798 config.no_show_slots = new;
799 })
800 }
801
802 #[pallet::call_index(19)]
804 #[pallet::weight((
805 T::WeightInfo::set_config_with_u32(),
806 DispatchClass::Operational,
807 ))]
808 pub fn set_n_delay_tranches(origin: OriginFor<T>, new: u32) -> DispatchResult {
809 ensure_root(origin)?;
810 Self::schedule_config_update(|config| {
811 config.n_delay_tranches = new;
812 })
813 }
814
815 #[pallet::call_index(20)]
817 #[pallet::weight((
818 T::WeightInfo::set_config_with_u32(),
819 DispatchClass::Operational,
820 ))]
821 pub fn set_zeroth_delay_tranche_width(origin: OriginFor<T>, new: u32) -> DispatchResult {
822 ensure_root(origin)?;
823 Self::schedule_config_update(|config| {
824 config.zeroth_delay_tranche_width = new;
825 })
826 }
827
828 #[pallet::call_index(21)]
830 #[pallet::weight((
831 T::WeightInfo::set_config_with_u32(),
832 DispatchClass::Operational,
833 ))]
834 pub fn set_needed_approvals(origin: OriginFor<T>, new: u32) -> DispatchResult {
835 ensure_root(origin)?;
836 Self::schedule_config_update(|config| {
837 config.needed_approvals = new;
838 })
839 }
840
841 #[pallet::call_index(22)]
843 #[pallet::weight((
844 T::WeightInfo::set_config_with_u32(),
845 DispatchClass::Operational,
846 ))]
847 pub fn set_relay_vrf_modulo_samples(origin: OriginFor<T>, new: u32) -> DispatchResult {
848 ensure_root(origin)?;
849 Self::schedule_config_update(|config| {
850 config.relay_vrf_modulo_samples = new;
851 })
852 }
853
854 #[pallet::call_index(23)]
856 #[pallet::weight((
857 T::WeightInfo::set_config_with_u32(),
858 DispatchClass::Operational,
859 ))]
860 pub fn set_max_upward_queue_count(origin: OriginFor<T>, new: u32) -> DispatchResult {
861 ensure_root(origin)?;
862 Self::schedule_config_update(|config| {
863 config.max_upward_queue_count = new;
864 })
865 }
866
867 #[pallet::call_index(24)]
870 #[pallet::weight((
871 T::WeightInfo::set_config_with_u32(),
872 DispatchClass::Operational,
873 ))]
874 pub fn set_max_upward_queue_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
875 ensure_root(origin)?;
876 ensure!(new <= MAX_UPWARD_MESSAGE_SIZE_BOUND, Error::<T>::InvalidNewValue);
877
878 Self::schedule_config_update(|config| {
879 config.max_upward_queue_size = new;
880 })
881 }
882
883 #[pallet::call_index(25)]
885 #[pallet::weight((
886 T::WeightInfo::set_config_with_u32(),
887 DispatchClass::Operational,
888 ))]
889 pub fn set_max_downward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
890 ensure_root(origin)?;
891 Self::schedule_config_update(|config| {
892 config.max_downward_message_size = new;
893 })
894 }
895
896 #[pallet::call_index(27)]
898 #[pallet::weight((
899 T::WeightInfo::set_config_with_u32(),
900 DispatchClass::Operational,
901 ))]
902 pub fn set_max_upward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
903 ensure_root(origin)?;
904 Self::schedule_config_update(|config| {
905 config.max_upward_message_size = new;
906 })
907 }
908
909 #[pallet::call_index(28)]
911 #[pallet::weight((
912 T::WeightInfo::set_config_with_u32(),
913 DispatchClass::Operational,
914 ))]
915 pub fn set_max_upward_message_num_per_candidate(
916 origin: OriginFor<T>,
917 new: u32,
918 ) -> DispatchResult {
919 ensure_root(origin)?;
920 Self::schedule_config_update(|config| {
921 config.max_upward_message_num_per_candidate = new;
922 })
923 }
924
925 #[pallet::call_index(29)]
927 #[pallet::weight((
928 T::WeightInfo::set_hrmp_open_request_ttl(),
929 DispatchClass::Operational,
930 ))]
931 pub fn set_hrmp_open_request_ttl(_origin: OriginFor<T>, _new: u32) -> DispatchResult {
934 Err("this doesn't have any effect".into())
935 }
936
937 #[pallet::call_index(30)]
939 #[pallet::weight((
940 T::WeightInfo::set_config_with_balance(),
941 DispatchClass::Operational,
942 ))]
943 pub fn set_hrmp_sender_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
944 ensure_root(origin)?;
945 Self::schedule_config_update(|config| {
946 config.hrmp_sender_deposit = new;
947 })
948 }
949
950 #[pallet::call_index(31)]
953 #[pallet::weight((
954 T::WeightInfo::set_config_with_balance(),
955 DispatchClass::Operational,
956 ))]
957 pub fn set_hrmp_recipient_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
958 ensure_root(origin)?;
959 Self::schedule_config_update(|config| {
960 config.hrmp_recipient_deposit = new;
961 })
962 }
963
964 #[pallet::call_index(32)]
966 #[pallet::weight((
967 T::WeightInfo::set_config_with_u32(),
968 DispatchClass::Operational,
969 ))]
970 pub fn set_hrmp_channel_max_capacity(origin: OriginFor<T>, new: u32) -> DispatchResult {
971 ensure_root(origin)?;
972 Self::schedule_config_update(|config| {
973 config.hrmp_channel_max_capacity = new;
974 })
975 }
976
977 #[pallet::call_index(33)]
979 #[pallet::weight((
980 T::WeightInfo::set_config_with_u32(),
981 DispatchClass::Operational,
982 ))]
983 pub fn set_hrmp_channel_max_total_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
984 ensure_root(origin)?;
985 Self::schedule_config_update(|config| {
986 config.hrmp_channel_max_total_size = new;
987 })
988 }
989
990 #[pallet::call_index(34)]
992 #[pallet::weight((
993 T::WeightInfo::set_config_with_u32(),
994 DispatchClass::Operational,
995 ))]
996 pub fn set_hrmp_max_parachain_inbound_channels(
997 origin: OriginFor<T>,
998 new: u32,
999 ) -> DispatchResult {
1000 ensure_root(origin)?;
1001 Self::schedule_config_update(|config| {
1002 config.hrmp_max_parachain_inbound_channels = new;
1003 })
1004 }
1005
1006 #[pallet::call_index(36)]
1008 #[pallet::weight((
1009 T::WeightInfo::set_config_with_u32(),
1010 DispatchClass::Operational,
1011 ))]
1012 pub fn set_hrmp_channel_max_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1013 ensure_root(origin)?;
1014 Self::schedule_config_update(|config| {
1015 config.hrmp_channel_max_message_size = new;
1016 })
1017 }
1018
1019 #[pallet::call_index(37)]
1021 #[pallet::weight((
1022 T::WeightInfo::set_config_with_u32(),
1023 DispatchClass::Operational,
1024 ))]
1025 pub fn set_hrmp_max_parachain_outbound_channels(
1026 origin: OriginFor<T>,
1027 new: u32,
1028 ) -> DispatchResult {
1029 ensure_root(origin)?;
1030 Self::schedule_config_update(|config| {
1031 config.hrmp_max_parachain_outbound_channels = new;
1032 })
1033 }
1034
1035 #[pallet::call_index(39)]
1037 #[pallet::weight((
1038 T::WeightInfo::set_config_with_u32(),
1039 DispatchClass::Operational,
1040 ))]
1041 pub fn set_hrmp_max_message_num_per_candidate(
1042 origin: OriginFor<T>,
1043 new: u32,
1044 ) -> DispatchResult {
1045 ensure_root(origin)?;
1046 Self::schedule_config_update(|config| {
1047 config.hrmp_max_message_num_per_candidate = new;
1048 })
1049 }
1050
1051 #[pallet::call_index(42)]
1053 #[pallet::weight((
1054 T::WeightInfo::set_config_with_u32(),
1055 DispatchClass::Operational,
1056 ))]
1057 pub fn set_pvf_voting_ttl(origin: OriginFor<T>, new: SessionIndex) -> DispatchResult {
1058 ensure_root(origin)?;
1059 Self::schedule_config_update(|config| {
1060 config.pvf_voting_ttl = new;
1061 })
1062 }
1063
1064 #[pallet::call_index(43)]
1069 #[pallet::weight((
1070 T::WeightInfo::set_config_with_block_number(),
1071 DispatchClass::Operational,
1072 ))]
1073 pub fn set_minimum_validation_upgrade_delay(
1074 origin: OriginFor<T>,
1075 new: BlockNumberFor<T>,
1076 ) -> DispatchResult {
1077 ensure_root(origin)?;
1078 Self::schedule_config_update(|config| {
1079 config.minimum_validation_upgrade_delay = new;
1080 })
1081 }
1082
1083 #[pallet::call_index(44)]
1086 #[pallet::weight((
1087 T::DbWeight::get().writes(1),
1088 DispatchClass::Operational,
1089 ))]
1090 pub fn set_bypass_consistency_check(origin: OriginFor<T>, new: bool) -> DispatchResult {
1091 ensure_root(origin)?;
1092 BypassConsistencyCheck::<T>::put(new);
1093 Ok(())
1094 }
1095
1096 #[pallet::call_index(45)]
1098 #[pallet::weight((
1099 T::WeightInfo::set_config_with_option_u32(), DispatchClass::Operational,
1101 ))]
1102 pub fn set_async_backing_params(
1103 origin: OriginFor<T>,
1104 new: AsyncBackingParams,
1105 ) -> DispatchResult {
1106 ensure_root(origin)?;
1107 Self::schedule_config_update(|config| {
1108 config.async_backing_params = new;
1109 })
1110 }
1111
1112 #[pallet::call_index(46)]
1114 #[pallet::weight((
1115 T::WeightInfo::set_config_with_executor_params(),
1116 DispatchClass::Operational,
1117 ))]
1118 pub fn set_executor_params(origin: OriginFor<T>, new: ExecutorParams) -> DispatchResult {
1119 ensure_root(origin)?;
1120 Self::schedule_config_update(|config| {
1121 config.executor_params = new;
1122 })
1123 }
1124
1125 #[pallet::call_index(47)]
1127 #[pallet::weight((
1128 T::WeightInfo::set_config_with_balance(),
1129 DispatchClass::Operational,
1130 ))]
1131 pub fn set_on_demand_base_fee(origin: OriginFor<T>, new: Balance) -> DispatchResult {
1132 ensure_root(origin)?;
1133 Self::schedule_config_update(|config| {
1134 config.scheduler_params.on_demand_base_fee = new;
1135 })
1136 }
1137
1138 #[pallet::call_index(48)]
1140 #[pallet::weight((
1141 T::WeightInfo::set_config_with_perbill(),
1142 DispatchClass::Operational,
1143 ))]
1144 pub fn set_on_demand_fee_variability(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
1145 ensure_root(origin)?;
1146 Self::schedule_config_update(|config| {
1147 config.scheduler_params.on_demand_fee_variability = new;
1148 })
1149 }
1150
1151 #[pallet::call_index(49)]
1153 #[pallet::weight((
1154 T::WeightInfo::set_config_with_option_u32(),
1155 DispatchClass::Operational,
1156 ))]
1157 pub fn set_on_demand_queue_max_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1158 ensure_root(origin)?;
1159 Self::schedule_config_update(|config| {
1160 config.scheduler_params.on_demand_queue_max_size = new;
1161 })
1162 }
1163
1164 #[pallet::call_index(50)]
1166 #[pallet::weight((
1167 T::WeightInfo::set_config_with_perbill(),
1168 DispatchClass::Operational,
1169 ))]
1170 pub fn set_on_demand_target_queue_utilization(
1171 origin: OriginFor<T>,
1172 new: Perbill,
1173 ) -> DispatchResult {
1174 ensure_root(origin)?;
1175 Self::schedule_config_update(|config| {
1176 config.scheduler_params.on_demand_target_queue_utilization = new;
1177 })
1178 }
1179
1180 #[pallet::call_index(52)]
1184 #[pallet::weight((
1185 T::WeightInfo::set_config_with_u32(),
1186 DispatchClass::Operational
1187 ))]
1188 pub fn set_minimum_backing_votes(origin: OriginFor<T>, new: u32) -> DispatchResult {
1189 ensure_root(origin)?;
1190 Self::schedule_config_update(|config| {
1191 config.minimum_backing_votes = new;
1192 })
1193 }
1194
1195 #[pallet::call_index(53)]
1197 #[pallet::weight((
1198 T::WeightInfo::set_node_feature(),
1199 DispatchClass::Operational
1200 ))]
1201 pub fn set_node_feature(origin: OriginFor<T>, index: u8, value: bool) -> DispatchResult {
1202 ensure_root(origin)?;
1203
1204 Self::schedule_config_update(|config| {
1205 let index = usize::from(index);
1206 if config.node_features.len() <= index {
1207 config.node_features.resize(index + 1, false);
1208 }
1209 config.node_features.set(index, value);
1210 })
1211 }
1212
1213 #[pallet::call_index(54)]
1215 #[pallet::weight((
1216 T::WeightInfo::set_config_with_executor_params(),
1217 DispatchClass::Operational,
1218 ))]
1219 pub fn set_approval_voting_params(
1220 origin: OriginFor<T>,
1221 new: ApprovalVotingParams,
1222 ) -> DispatchResult {
1223 ensure_root(origin)?;
1224 Self::schedule_config_update(|config| {
1225 config.approval_voting_params = new;
1226 })
1227 }
1228
1229 #[pallet::call_index(55)]
1231 #[pallet::weight((
1232 T::WeightInfo::set_config_with_scheduler_params(),
1233 DispatchClass::Operational,
1234 ))]
1235 pub fn set_scheduler_params(
1236 origin: OriginFor<T>,
1237 new: SchedulerParams<BlockNumberFor<T>>,
1238 ) -> DispatchResult {
1239 ensure_root(origin)?;
1240 Self::schedule_config_update(|config| {
1241 config.scheduler_params = new;
1242 })
1243 }
1244 }
1245
1246 impl<T: Config> Pallet<T> {
1247 pub fn set_coretime_cores_unchecked(new: u32) -> DispatchResult {
1251 Self::schedule_config_update(|config| {
1252 config.scheduler_params.num_cores = new;
1253 })
1254 }
1255 }
1256
1257 #[pallet::hooks]
1258 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1259 fn integrity_test() {
1260 assert_eq!(
1261 &ActiveConfig::<T>::hashed_key(),
1262 polkadot_primitives::well_known_keys::ACTIVE_CONFIG,
1263 "`well_known_keys::ACTIVE_CONFIG` doesn't match key of `ActiveConfig`! Make sure that the name of the\
1264 configuration pallet is `Configuration` in the runtime!",
1265 );
1266 }
1267 }
1268}
1269
1270pub struct SessionChangeOutcome<BlockNumber> {
1273 pub prev_config: HostConfiguration<BlockNumber>,
1275 pub new_config: Option<HostConfiguration<BlockNumber>>,
1277}
1278
1279impl<T: Config> Pallet<T> {
1280 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
1282 Weight::zero()
1283 }
1284
1285 pub(crate) fn initializer_finalize() {}
1287
1288 pub(crate) fn initializer_on_new_session(
1294 session_index: &SessionIndex,
1295 ) -> SessionChangeOutcome<BlockNumberFor<T>> {
1296 let pending_configs = PendingConfigs::<T>::get();
1297 let prev_config = ActiveConfig::<T>::get();
1298
1299 if pending_configs.is_empty() {
1301 return SessionChangeOutcome { prev_config, new_config: None }
1302 }
1303
1304 let (mut past_and_present, future) = pending_configs
1305 .into_iter()
1306 .partition::<Vec<_>, _>(|&(apply_at_session, _)| apply_at_session <= *session_index);
1307
1308 if past_and_present.len() > 1 {
1309 log::error!(
1312 target: LOG_TARGET,
1313 "Skipping applying configuration changes scheduled sessions in the past",
1314 );
1315 }
1316
1317 let new_config = past_and_present.pop().map(|(_, config)| config);
1318 if let Some(ref new_config) = new_config {
1319 ActiveConfig::<T>::put(new_config);
1321 }
1322
1323 PendingConfigs::<T>::put(future);
1324
1325 SessionChangeOutcome { prev_config, new_config }
1326 }
1327
1328 fn scheduled_session() -> SessionIndex {
1330 shared::Pallet::<T>::scheduled_session()
1331 }
1332
1333 pub fn force_set_active_config(config: HostConfiguration<BlockNumberFor<T>>) {
1337 ActiveConfig::<T>::set(config);
1338 }
1339
1340 #[inline(never)]
1355 pub(crate) fn schedule_config_update(
1356 updater: impl FnOnce(&mut HostConfiguration<BlockNumberFor<T>>),
1357 ) -> DispatchResult {
1358 let mut pending_configs = PendingConfigs::<T>::get();
1359
1360 let mut base_config = pending_configs
1387 .last()
1388 .map(|(_, config)| config.clone())
1389 .unwrap_or_else(ActiveConfig::<T>::get);
1390 let base_config_consistent = base_config.check_consistency().is_ok();
1391
1392 updater(&mut base_config);
1396 let new_config = base_config;
1397
1398 if BypassConsistencyCheck::<T>::get() {
1399 log::warn!(
1402 target: LOG_TARGET,
1403 "Bypassing the consistency check for the configuration change!",
1404 );
1405 } else if let Err(e) = new_config.check_consistency() {
1406 if base_config_consistent {
1407 log::warn!(
1411 target: LOG_TARGET,
1412 "Configuration change rejected due to invalid configuration: {:?}",
1413 e,
1414 );
1415 return Err(Error::<T>::InvalidNewValue.into())
1416 } else {
1417 log::warn!(
1423 target: LOG_TARGET,
1424 "The new configuration is broken but the old is broken as well. Proceeding",
1425 );
1426 }
1427 }
1428
1429 let scheduled_session = Self::scheduled_session();
1430
1431 if let Some(&mut (_, ref mut config)) = pending_configs
1432 .iter_mut()
1433 .find(|&&mut (apply_at_session, _)| apply_at_session >= scheduled_session)
1434 {
1435 *config = new_config;
1436 } else {
1437 pending_configs.push((scheduled_session, new_config));
1439 }
1440
1441 PendingConfigs::<T>::put(pending_configs);
1442
1443 Ok(())
1444 }
1445}
1446
1447pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>(core::marker::PhantomData<(T, P)>);
1450impl<T: crate::hrmp::pallet::Config, P: Get<Percent>> Get<(u32, u32)>
1451 for ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>
1452{
1453 fn get() -> (u32, u32) {
1454 let config = ActiveConfig::<T>::get();
1455 let percent = P::get();
1456 (percent * config.hrmp_channel_max_message_size, percent * config.hrmp_channel_max_capacity)
1457 }
1458}