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
53pub(crate) const MAX_VALIDATION_CODE_COMPRESSION_RATIO: u32 = 10;
55
56#[derive(
58 Clone,
59 Encode,
60 Decode,
61 PartialEq,
62 sp_core::RuntimeDebug,
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,
81 pub max_head_data_size: u32,
83 pub max_upward_queue_count: u32,
85 pub max_upward_queue_size: u32,
89 pub max_upward_message_size: u32,
93 pub max_upward_message_num_per_candidate: u32,
97 pub hrmp_max_message_num_per_candidate: u32,
101 #[cfg_attr(feature = "std", serde(alias = "validation_upgrade_frequency"))]
112 pub validation_upgrade_cooldown: BlockNumber,
113 pub validation_upgrade_delay: BlockNumber,
140 pub async_backing_params: AsyncBackingParams,
142
143 pub max_pov_size: u32,
149 pub max_downward_message_size: u32,
156 pub hrmp_max_parachain_outbound_channels: u32,
158 pub hrmp_sender_deposit: Balance,
160 pub hrmp_recipient_deposit: Balance,
162 pub hrmp_channel_max_capacity: u32,
164 pub hrmp_channel_max_total_size: u32,
166 pub hrmp_max_parachain_inbound_channels: u32,
168 pub hrmp_channel_max_message_size: u32,
172 pub executor_params: ExecutorParams,
174
175 pub code_retention_period: BlockNumber,
182
183 pub max_validators: Option<u32>,
187 pub dispute_period: SessionIndex,
189 pub dispute_post_conclusion_acceptance_period: BlockNumber,
191 pub no_show_slots: u32,
196 pub n_delay_tranches: u32,
198 pub zeroth_delay_tranche_width: u32,
201 pub needed_approvals: u32,
203 pub relay_vrf_modulo_samples: u32,
205 pub pvf_voting_ttl: SessionIndex,
211 pub minimum_validation_upgrade_delay: BlockNumber,
228 pub minimum_backing_votes: u32,
231 pub node_features: NodeFeatures,
233 pub approval_voting_params: ApprovalVotingParams,
235 pub scheduler_params: SchedulerParams<BlockNumber>,
237}
238
239impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber> {
240 fn default() -> Self {
241 let ret = Self {
242 async_backing_params: AsyncBackingParams {
243 max_candidate_depth: 0,
244 allowed_ancestry_len: 0,
245 },
246 no_show_slots: 1u32.into(),
247 validation_upgrade_cooldown: Default::default(),
248 validation_upgrade_delay: 2u32.into(),
249 code_retention_period: Default::default(),
250 max_code_size: MAX_CODE_SIZE,
251 max_pov_size: Default::default(),
252 max_head_data_size: Default::default(),
253 max_validators: None,
254 dispute_period: 6,
255 dispute_post_conclusion_acceptance_period: 100.into(),
256 n_delay_tranches: 1,
257 zeroth_delay_tranche_width: Default::default(),
258 needed_approvals: Default::default(),
259 relay_vrf_modulo_samples: Default::default(),
260 max_upward_queue_count: Default::default(),
261 max_upward_queue_size: Default::default(),
262 max_downward_message_size: Default::default(),
263 max_upward_message_size: Default::default(),
264 max_upward_message_num_per_candidate: Default::default(),
265 hrmp_sender_deposit: Default::default(),
266 hrmp_recipient_deposit: Default::default(),
267 hrmp_channel_max_capacity: Default::default(),
268 hrmp_channel_max_total_size: Default::default(),
269 hrmp_max_parachain_inbound_channels: Default::default(),
270 hrmp_channel_max_message_size: Default::default(),
271 hrmp_max_parachain_outbound_channels: Default::default(),
272 hrmp_max_message_num_per_candidate: Default::default(),
273 pvf_voting_ttl: 2u32.into(),
274 minimum_validation_upgrade_delay: 2.into(),
275 executor_params: Default::default(),
276 approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 },
277 minimum_backing_votes: LEGACY_MIN_BACKING_VOTES,
278 node_features: NodeFeatures::EMPTY,
279 scheduler_params: Default::default(),
280 };
281
282 #[cfg(feature = "runtime-benchmarks")]
283 let ret = ret.with_benchmarking_default();
284 ret
285 }
286}
287
288#[cfg(feature = "runtime-benchmarks")]
289impl<BlockNumber: Default + From<u32>> HostConfiguration<BlockNumber> {
290 fn with_benchmarking_default(mut self) -> Self {
295 self.max_head_data_size = self.max_head_data_size.max(1 << 20);
296 self.max_downward_message_size = self.max_downward_message_size.max(1 << 16);
297 self.hrmp_channel_max_capacity = self.hrmp_channel_max_capacity.max(1000);
298 self.hrmp_channel_max_message_size = self.hrmp_channel_max_message_size.max(1 << 16);
299 self.hrmp_max_parachain_inbound_channels =
300 self.hrmp_max_parachain_inbound_channels.max(100);
301 self.hrmp_max_parachain_outbound_channels =
302 self.hrmp_max_parachain_outbound_channels.max(100);
303 self
304 }
305}
306
307#[derive(Debug)]
309pub enum InconsistentError<BlockNumber> {
310 ZeroGroupRotationFrequency,
312 ZeroParasAvailabilityPeriod,
314 ZeroNoShowSlots,
316 MaxCodeSizeExceedHardLimit { max_code_size: u32 },
318 MaxHeadDataSizeExceedHardLimit { max_head_data_size: u32 },
320 MaxPovSizeExceedHardLimit { max_pov_size: 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 },
331 MaxHorizontalMessageNumExceeded { max_message_num: u32 },
333 MaxUpwardMessageNumExceeded { max_message_num: u32 },
335 MaxHrmpOutboundChannelsExceeded,
337 MaxHrmpInboundChannelsExceeded,
339 ZeroMinimumBackingVotes,
341 InconsistentExecutorParams { inner: ExecutorParamError },
343 LookaheadZero,
345 OnDemandQueueSizeTooLarge,
347 ZeroDelayTranches,
349}
350
351impl<BlockNumber> HostConfiguration<BlockNumber>
352where
353 BlockNumber: Zero + PartialOrd + core::fmt::Debug + Clone + From<u32>,
354{
355 pub fn check_consistency(&self) -> Result<(), InconsistentError<BlockNumber>> {
361 use InconsistentError::*;
362
363 if self.scheduler_params.group_rotation_frequency.is_zero() {
364 return Err(ZeroGroupRotationFrequency)
365 }
366
367 if self.scheduler_params.paras_availability_period.is_zero() {
368 return Err(ZeroParasAvailabilityPeriod)
369 }
370
371 if self.no_show_slots.is_zero() {
372 return Err(ZeroNoShowSlots)
373 }
374
375 if self.max_code_size > MAX_CODE_SIZE {
376 return Err(MaxCodeSizeExceedHardLimit { max_code_size: self.max_code_size })
377 }
378
379 if self.max_head_data_size > MAX_HEAD_DATA_SIZE {
380 return Err(MaxHeadDataSizeExceedHardLimit {
381 max_head_data_size: self.max_head_data_size,
382 })
383 }
384
385 if self.max_pov_size > POV_SIZE_HARD_LIMIT {
386 return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size })
387 }
388
389 if self.minimum_validation_upgrade_delay <= self.scheduler_params.paras_availability_period
390 {
391 return Err(MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod {
392 minimum_validation_upgrade_delay: self.minimum_validation_upgrade_delay.clone(),
393 paras_availability_period: self.scheduler_params.paras_availability_period.clone(),
394 })
395 }
396
397 if self.validation_upgrade_delay <= 1.into() {
398 return Err(ValidationUpgradeDelayIsTooLow {
399 validation_upgrade_delay: self.validation_upgrade_delay.clone(),
400 })
401 }
402
403 if self.max_upward_message_size > crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND {
404 return Err(MaxUpwardMessageSizeExceeded {
405 max_message_size: self.max_upward_message_size,
406 })
407 }
408
409 if self.hrmp_max_message_num_per_candidate > MAX_HORIZONTAL_MESSAGE_NUM {
410 return Err(MaxHorizontalMessageNumExceeded {
411 max_message_num: self.hrmp_max_message_num_per_candidate,
412 })
413 }
414
415 if self.max_upward_message_num_per_candidate > MAX_UPWARD_MESSAGE_NUM {
416 return Err(MaxUpwardMessageNumExceeded {
417 max_message_num: self.max_upward_message_num_per_candidate,
418 })
419 }
420
421 if self.hrmp_max_parachain_outbound_channels > crate::hrmp::HRMP_MAX_OUTBOUND_CHANNELS_BOUND
422 {
423 return Err(MaxHrmpOutboundChannelsExceeded)
424 }
425
426 if self.hrmp_max_parachain_inbound_channels > crate::hrmp::HRMP_MAX_INBOUND_CHANNELS_BOUND {
427 return Err(MaxHrmpInboundChannelsExceeded)
428 }
429
430 if self.minimum_backing_votes.is_zero() {
431 return Err(ZeroMinimumBackingVotes)
432 }
433
434 if let Err(inner) = self.executor_params.check_consistency() {
435 return Err(InconsistentExecutorParams { inner })
436 }
437
438 if self.scheduler_params.lookahead == 0 {
439 return Err(LookaheadZero)
440 }
441
442 if self.scheduler_params.on_demand_queue_max_size > ON_DEMAND_MAX_QUEUE_MAX_SIZE {
443 return Err(OnDemandQueueSizeTooLarge)
444 }
445
446 if self.n_delay_tranches.is_zero() {
447 return Err(ZeroDelayTranches)
448 }
449
450 Ok(())
451 }
452
453 pub fn panic_if_not_consistent(&self) {
459 if let Err(err) = self.check_consistency() {
460 panic!("Host configuration is inconsistent: {:?}\nCfg:\n{:#?}", err, self);
461 }
462 }
463}
464
465pub trait WeightInfo {
466 fn set_config_with_block_number() -> Weight;
467 fn set_config_with_u32() -> Weight;
468 fn set_config_with_option_u32() -> Weight;
469 fn set_config_with_balance() -> Weight;
470 fn set_hrmp_open_request_ttl() -> Weight;
471 fn set_config_with_executor_params() -> Weight;
472 fn set_config_with_perbill() -> Weight;
473 fn set_node_feature() -> Weight;
474 fn set_config_with_scheduler_params() -> Weight;
475}
476
477pub struct TestWeightInfo;
478impl WeightInfo for TestWeightInfo {
479 fn set_config_with_block_number() -> Weight {
480 Weight::MAX
481 }
482 fn set_config_with_u32() -> Weight {
483 Weight::MAX
484 }
485 fn set_config_with_option_u32() -> Weight {
486 Weight::MAX
487 }
488 fn set_config_with_balance() -> Weight {
489 Weight::MAX
490 }
491 fn set_hrmp_open_request_ttl() -> Weight {
492 Weight::MAX
493 }
494 fn set_config_with_executor_params() -> Weight {
495 Weight::MAX
496 }
497 fn set_config_with_perbill() -> Weight {
498 Weight::MAX
499 }
500 fn set_node_feature() -> Weight {
501 Weight::MAX
502 }
503 fn set_config_with_scheduler_params() -> Weight {
504 Weight::MAX
505 }
506}
507
508#[frame_support::pallet]
509pub mod pallet {
510 use super::*;
511
512 const STORAGE_VERSION: StorageVersion = StorageVersion::new(12);
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 ensure!(new <= MAX_UPWARD_MESSAGE_SIZE_BOUND, Error::<T>::InvalidNewValue);
880
881 Self::schedule_config_update(|config| {
882 config.max_upward_queue_size = new;
883 })
884 }
885
886 #[pallet::call_index(25)]
888 #[pallet::weight((
889 T::WeightInfo::set_config_with_u32(),
890 DispatchClass::Operational,
891 ))]
892 pub fn set_max_downward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
893 ensure_root(origin)?;
894 Self::schedule_config_update(|config| {
895 config.max_downward_message_size = new;
896 })
897 }
898
899 #[pallet::call_index(27)]
901 #[pallet::weight((
902 T::WeightInfo::set_config_with_u32(),
903 DispatchClass::Operational,
904 ))]
905 pub fn set_max_upward_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
906 ensure_root(origin)?;
907 Self::schedule_config_update(|config| {
908 config.max_upward_message_size = new;
909 })
910 }
911
912 #[pallet::call_index(28)]
914 #[pallet::weight((
915 T::WeightInfo::set_config_with_u32(),
916 DispatchClass::Operational,
917 ))]
918 pub fn set_max_upward_message_num_per_candidate(
919 origin: OriginFor<T>,
920 new: u32,
921 ) -> DispatchResult {
922 ensure_root(origin)?;
923 Self::schedule_config_update(|config| {
924 config.max_upward_message_num_per_candidate = new;
925 })
926 }
927
928 #[pallet::call_index(29)]
930 #[pallet::weight((
931 T::WeightInfo::set_hrmp_open_request_ttl(),
932 DispatchClass::Operational,
933 ))]
934 pub fn set_hrmp_open_request_ttl(_origin: OriginFor<T>, _new: u32) -> DispatchResult {
937 Err("this doesn't have any effect".into())
938 }
939
940 #[pallet::call_index(30)]
942 #[pallet::weight((
943 T::WeightInfo::set_config_with_balance(),
944 DispatchClass::Operational,
945 ))]
946 pub fn set_hrmp_sender_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
947 ensure_root(origin)?;
948 Self::schedule_config_update(|config| {
949 config.hrmp_sender_deposit = new;
950 })
951 }
952
953 #[pallet::call_index(31)]
956 #[pallet::weight((
957 T::WeightInfo::set_config_with_balance(),
958 DispatchClass::Operational,
959 ))]
960 pub fn set_hrmp_recipient_deposit(origin: OriginFor<T>, new: Balance) -> DispatchResult {
961 ensure_root(origin)?;
962 Self::schedule_config_update(|config| {
963 config.hrmp_recipient_deposit = new;
964 })
965 }
966
967 #[pallet::call_index(32)]
969 #[pallet::weight((
970 T::WeightInfo::set_config_with_u32(),
971 DispatchClass::Operational,
972 ))]
973 pub fn set_hrmp_channel_max_capacity(origin: OriginFor<T>, new: u32) -> DispatchResult {
974 ensure_root(origin)?;
975 Self::schedule_config_update(|config| {
976 config.hrmp_channel_max_capacity = new;
977 })
978 }
979
980 #[pallet::call_index(33)]
982 #[pallet::weight((
983 T::WeightInfo::set_config_with_u32(),
984 DispatchClass::Operational,
985 ))]
986 pub fn set_hrmp_channel_max_total_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
987 ensure_root(origin)?;
988 Self::schedule_config_update(|config| {
989 config.hrmp_channel_max_total_size = new;
990 })
991 }
992
993 #[pallet::call_index(34)]
995 #[pallet::weight((
996 T::WeightInfo::set_config_with_u32(),
997 DispatchClass::Operational,
998 ))]
999 pub fn set_hrmp_max_parachain_inbound_channels(
1000 origin: OriginFor<T>,
1001 new: u32,
1002 ) -> DispatchResult {
1003 ensure_root(origin)?;
1004 Self::schedule_config_update(|config| {
1005 config.hrmp_max_parachain_inbound_channels = new;
1006 })
1007 }
1008
1009 #[pallet::call_index(36)]
1011 #[pallet::weight((
1012 T::WeightInfo::set_config_with_u32(),
1013 DispatchClass::Operational,
1014 ))]
1015 pub fn set_hrmp_channel_max_message_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1016 ensure_root(origin)?;
1017 Self::schedule_config_update(|config| {
1018 config.hrmp_channel_max_message_size = new;
1019 })
1020 }
1021
1022 #[pallet::call_index(37)]
1024 #[pallet::weight((
1025 T::WeightInfo::set_config_with_u32(),
1026 DispatchClass::Operational,
1027 ))]
1028 pub fn set_hrmp_max_parachain_outbound_channels(
1029 origin: OriginFor<T>,
1030 new: u32,
1031 ) -> DispatchResult {
1032 ensure_root(origin)?;
1033 Self::schedule_config_update(|config| {
1034 config.hrmp_max_parachain_outbound_channels = new;
1035 })
1036 }
1037
1038 #[pallet::call_index(39)]
1040 #[pallet::weight((
1041 T::WeightInfo::set_config_with_u32(),
1042 DispatchClass::Operational,
1043 ))]
1044 pub fn set_hrmp_max_message_num_per_candidate(
1045 origin: OriginFor<T>,
1046 new: u32,
1047 ) -> DispatchResult {
1048 ensure_root(origin)?;
1049 Self::schedule_config_update(|config| {
1050 config.hrmp_max_message_num_per_candidate = new;
1051 })
1052 }
1053
1054 #[pallet::call_index(42)]
1056 #[pallet::weight((
1057 T::WeightInfo::set_config_with_u32(),
1058 DispatchClass::Operational,
1059 ))]
1060 pub fn set_pvf_voting_ttl(origin: OriginFor<T>, new: SessionIndex) -> DispatchResult {
1061 ensure_root(origin)?;
1062 Self::schedule_config_update(|config| {
1063 config.pvf_voting_ttl = new;
1064 })
1065 }
1066
1067 #[pallet::call_index(43)]
1072 #[pallet::weight((
1073 T::WeightInfo::set_config_with_block_number(),
1074 DispatchClass::Operational,
1075 ))]
1076 pub fn set_minimum_validation_upgrade_delay(
1077 origin: OriginFor<T>,
1078 new: BlockNumberFor<T>,
1079 ) -> DispatchResult {
1080 ensure_root(origin)?;
1081 Self::schedule_config_update(|config| {
1082 config.minimum_validation_upgrade_delay = new;
1083 })
1084 }
1085
1086 #[pallet::call_index(44)]
1089 #[pallet::weight((
1090 T::DbWeight::get().writes(1),
1091 DispatchClass::Operational,
1092 ))]
1093 pub fn set_bypass_consistency_check(origin: OriginFor<T>, new: bool) -> DispatchResult {
1094 ensure_root(origin)?;
1095 BypassConsistencyCheck::<T>::put(new);
1096 Ok(())
1097 }
1098
1099 #[pallet::call_index(45)]
1101 #[pallet::weight((
1102 T::WeightInfo::set_config_with_option_u32(), DispatchClass::Operational,
1104 ))]
1105 pub fn set_async_backing_params(
1106 origin: OriginFor<T>,
1107 new: AsyncBackingParams,
1108 ) -> DispatchResult {
1109 ensure_root(origin)?;
1110 Self::schedule_config_update(|config| {
1111 config.async_backing_params = new;
1112 })
1113 }
1114
1115 #[pallet::call_index(46)]
1117 #[pallet::weight((
1118 T::WeightInfo::set_config_with_executor_params(),
1119 DispatchClass::Operational,
1120 ))]
1121 pub fn set_executor_params(origin: OriginFor<T>, new: ExecutorParams) -> DispatchResult {
1122 ensure_root(origin)?;
1123 Self::schedule_config_update(|config| {
1124 config.executor_params = new;
1125 })
1126 }
1127
1128 #[pallet::call_index(47)]
1130 #[pallet::weight((
1131 T::WeightInfo::set_config_with_balance(),
1132 DispatchClass::Operational,
1133 ))]
1134 pub fn set_on_demand_base_fee(origin: OriginFor<T>, new: Balance) -> DispatchResult {
1135 ensure_root(origin)?;
1136 Self::schedule_config_update(|config| {
1137 config.scheduler_params.on_demand_base_fee = new;
1138 })
1139 }
1140
1141 #[pallet::call_index(48)]
1143 #[pallet::weight((
1144 T::WeightInfo::set_config_with_perbill(),
1145 DispatchClass::Operational,
1146 ))]
1147 pub fn set_on_demand_fee_variability(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
1148 ensure_root(origin)?;
1149 Self::schedule_config_update(|config| {
1150 config.scheduler_params.on_demand_fee_variability = new;
1151 })
1152 }
1153
1154 #[pallet::call_index(49)]
1156 #[pallet::weight((
1157 T::WeightInfo::set_config_with_option_u32(),
1158 DispatchClass::Operational,
1159 ))]
1160 pub fn set_on_demand_queue_max_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
1161 ensure_root(origin)?;
1162 Self::schedule_config_update(|config| {
1163 config.scheduler_params.on_demand_queue_max_size = new;
1164 })
1165 }
1166
1167 #[pallet::call_index(50)]
1169 #[pallet::weight((
1170 T::WeightInfo::set_config_with_perbill(),
1171 DispatchClass::Operational,
1172 ))]
1173 pub fn set_on_demand_target_queue_utilization(
1174 origin: OriginFor<T>,
1175 new: Perbill,
1176 ) -> DispatchResult {
1177 ensure_root(origin)?;
1178 Self::schedule_config_update(|config| {
1179 config.scheduler_params.on_demand_target_queue_utilization = new;
1180 })
1181 }
1182
1183 #[pallet::call_index(52)]
1187 #[pallet::weight((
1188 T::WeightInfo::set_config_with_u32(),
1189 DispatchClass::Operational
1190 ))]
1191 pub fn set_minimum_backing_votes(origin: OriginFor<T>, new: u32) -> DispatchResult {
1192 ensure_root(origin)?;
1193 Self::schedule_config_update(|config| {
1194 config.minimum_backing_votes = new;
1195 })
1196 }
1197
1198 #[pallet::call_index(53)]
1200 #[pallet::weight((
1201 T::WeightInfo::set_node_feature(),
1202 DispatchClass::Operational
1203 ))]
1204 pub fn set_node_feature(origin: OriginFor<T>, index: u8, value: bool) -> DispatchResult {
1205 ensure_root(origin)?;
1206
1207 Self::schedule_config_update(|config| {
1208 let index = usize::from(index);
1209 if config.node_features.len() <= index {
1210 config.node_features.resize(index + 1, false);
1211 }
1212 config.node_features.set(index, value);
1213 })
1214 }
1215
1216 #[pallet::call_index(54)]
1218 #[pallet::weight((
1219 T::WeightInfo::set_config_with_executor_params(),
1220 DispatchClass::Operational,
1221 ))]
1222 pub fn set_approval_voting_params(
1223 origin: OriginFor<T>,
1224 new: ApprovalVotingParams,
1225 ) -> DispatchResult {
1226 ensure_root(origin)?;
1227 Self::schedule_config_update(|config| {
1228 config.approval_voting_params = new;
1229 })
1230 }
1231
1232 #[pallet::call_index(55)]
1234 #[pallet::weight((
1235 T::WeightInfo::set_config_with_scheduler_params(),
1236 DispatchClass::Operational,
1237 ))]
1238 pub fn set_scheduler_params(
1239 origin: OriginFor<T>,
1240 new: SchedulerParams<BlockNumberFor<T>>,
1241 ) -> DispatchResult {
1242 ensure_root(origin)?;
1243 Self::schedule_config_update(|config| {
1244 config.scheduler_params = new;
1245 })
1246 }
1247 }
1248
1249 impl<T: Config> Pallet<T> {
1250 pub fn set_coretime_cores_unchecked(new: u32) -> DispatchResult {
1254 Self::schedule_config_update(|config| {
1255 config.scheduler_params.num_cores = new;
1256 })
1257 }
1258 }
1259
1260 #[pallet::hooks]
1261 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1262 fn integrity_test() {
1263 assert_eq!(
1264 &ActiveConfig::<T>::hashed_key(),
1265 polkadot_primitives::well_known_keys::ACTIVE_CONFIG,
1266 "`well_known_keys::ACTIVE_CONFIG` doesn't match key of `ActiveConfig`! Make sure that the name of the\
1267 configuration pallet is `Configuration` in the runtime!",
1268 );
1269 }
1270 }
1271}
1272
1273pub struct SessionChangeOutcome<BlockNumber> {
1276 pub prev_config: HostConfiguration<BlockNumber>,
1278 pub new_config: Option<HostConfiguration<BlockNumber>>,
1280}
1281
1282impl<T: Config> Pallet<T> {
1283 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
1285 Weight::zero()
1286 }
1287
1288 pub(crate) fn initializer_finalize() {}
1290
1291 pub(crate) fn initializer_on_new_session(
1297 session_index: &SessionIndex,
1298 ) -> SessionChangeOutcome<BlockNumberFor<T>> {
1299 let pending_configs = PendingConfigs::<T>::get();
1300 let prev_config = ActiveConfig::<T>::get();
1301
1302 if pending_configs.is_empty() {
1304 return SessionChangeOutcome { prev_config, new_config: None }
1305 }
1306
1307 let (mut past_and_present, future) = pending_configs
1308 .into_iter()
1309 .partition::<Vec<_>, _>(|&(apply_at_session, _)| apply_at_session <= *session_index);
1310
1311 if past_and_present.len() > 1 {
1312 log::error!(
1315 target: LOG_TARGET,
1316 "Skipping applying configuration changes scheduled sessions in the past",
1317 );
1318 }
1319
1320 let new_config = past_and_present.pop().map(|(_, config)| config);
1321 if let Some(ref new_config) = new_config {
1322 ActiveConfig::<T>::put(new_config);
1324 }
1325
1326 PendingConfigs::<T>::put(future);
1327
1328 SessionChangeOutcome { prev_config, new_config }
1329 }
1330
1331 fn scheduled_session() -> SessionIndex {
1333 shared::Pallet::<T>::scheduled_session()
1334 }
1335
1336 pub fn force_set_active_config(config: HostConfiguration<BlockNumberFor<T>>) {
1340 ActiveConfig::<T>::set(config);
1341 }
1342
1343 #[inline(never)]
1361 pub(crate) fn schedule_config_update(
1362 updater: impl FnOnce(&mut HostConfiguration<BlockNumberFor<T>>),
1363 ) -> DispatchResult {
1364 let mut pending_configs = PendingConfigs::<T>::get();
1365
1366 let mut base_config = pending_configs
1393 .last()
1394 .map(|(_, config)| config.clone())
1395 .unwrap_or_else(ActiveConfig::<T>::get);
1396 let base_config_consistent = base_config.check_consistency().is_ok();
1397
1398 updater(&mut base_config);
1402 let new_config = base_config;
1403
1404 if BypassConsistencyCheck::<T>::get() {
1405 log::warn!(
1408 target: LOG_TARGET,
1409 "Bypassing the consistency check for the configuration change!",
1410 );
1411 } else if let Err(e) = new_config.check_consistency() {
1412 if base_config_consistent {
1413 log::warn!(
1417 target: LOG_TARGET,
1418 "Configuration change rejected due to invalid configuration: {:?}",
1419 e,
1420 );
1421 return Err(Error::<T>::InvalidNewValue.into())
1422 } else {
1423 log::warn!(
1429 target: LOG_TARGET,
1430 "The new configuration is broken but the old is broken as well. Proceeding",
1431 );
1432 }
1433 }
1434
1435 let scheduled_session = Self::scheduled_session();
1436
1437 if let Some(&mut (_, ref mut config)) = pending_configs
1438 .iter_mut()
1439 .find(|&&mut (apply_at_session, _)| apply_at_session >= scheduled_session)
1440 {
1441 *config = new_config;
1442 } else {
1443 pending_configs.push((scheduled_session, new_config));
1445 }
1446
1447 PendingConfigs::<T>::put(pending_configs);
1448
1449 Ok(())
1450 }
1451}
1452
1453pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>(core::marker::PhantomData<(T, P)>);
1456impl<T: crate::hrmp::pallet::Config, P: Get<Percent>> Get<(u32, u32)>
1457 for ActiveConfigHrmpChannelSizeAndCapacityRatio<T, P>
1458{
1459 fn get() -> (u32, u32) {
1460 let config = ActiveConfig::<T>::get();
1461 let percent = P::get();
1462 (percent * config.hrmp_channel_max_message_size, percent * config.hrmp_channel_max_capacity)
1463 }
1464}