1#![cfg_attr(not(feature = "std"), no_std)]
18
19extern crate alloc;
31
32use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec};
33use codec::{Decode, Encode};
34use core::cmp;
35use cumulus_primitives_core::{
36 relay_chain::{self, UMPSignal, UMP_SEPARATOR},
37 AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, CoreInfo,
38 CumulusDigestItem, GetChannelInfo, ListChannelInfos, MessageSendError, OutboundHrmpMessage,
39 ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, VerifySchedulingSignature,
40 XcmpMessageHandler, XcmpMessageSource,
41};
42use cumulus_primitives_parachain_inherent::{
43 v0, HashedMessage, MessageQueueChain, ParachainInherentData,
44};
45use frame_support::{
46 dispatch::{DispatchClass, DispatchResult},
47 ensure,
48 inherent::{InherentData, InherentIdentifier, ProvideInherent},
49 traits::{Get, HandleMessage},
50 weights::Weight,
51};
52use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor};
53use parachain_inherent::{
54 deconstruct_parachain_inherent_data, AbridgedInboundDownwardMessages,
55 AbridgedInboundHrmpMessages, BasicParachainInherentData, InboundMessageId, InboundMessagesData,
56};
57use polkadot_parachain_primitives::primitives::RelayChainBlockNumber;
58use polkadot_runtime_parachains::{FeeTracker, GetMinFeeFactor};
59use scale_info::TypeInfo;
60use sp_runtime::{
61 traits::{BlockNumberProvider, Hash},
62 Debug, FixedU128, SaturatedConversion,
63};
64use xcm::{latest::XcmHash, VersionedLocation, VersionedXcm};
65use xcm_builder::InspectMessageQueues;
66
67mod benchmarking;
68pub mod block_weight;
69pub mod consensus_hook;
70pub mod migration;
71mod mock;
72pub mod relay_state_snapshot;
73#[cfg(test)]
74mod tests;
75mod unincluded_segment;
76pub mod weights;
77#[macro_use]
78pub mod validate_block;
79mod descendant_validation;
80pub mod parachain_inherent;
81
82use unincluded_segment::{
83 HrmpChannelUpdate, HrmpWatermarkUpdate, OutboundBandwidthLimits, SegmentTracker,
84};
85
86pub use consensus_hook::{ConsensusHook, ExpectParentIncluded};
87pub use cumulus_pallet_parachain_system_proc_macro::register_validate_block;
108pub use relay_state_snapshot::{MessagingStateSnapshot, RelayChainStateProof};
109pub use unincluded_segment::{Ancestor, UsedBandwidth};
110pub use weights::WeightInfo;
111
112use crate::parachain_inherent::{AbridgedInboundMessagesSizeInfo, InboundHrmpMessageId};
113pub use pallet::*;
114
115const LOG_TARGET: &str = "runtime::parachain-system";
116
117#[derive(Encode, Decode, Clone, Debug, TypeInfo, Default)]
119pub struct PoVMessages {
120 pub relay_storage_root_or_hash: relay_chain::Hash,
122 pub core_selector: u8,
124 pub bundle_index: u8,
126 pub ump_msg_count: u32,
128 pub hrmp_outbound_count: u32,
130 pub hrmp_outbound_recipients: Vec<ParaId>,
132}
133
134pub trait CheckAssociatedRelayNumber {
143 fn check_associated_relay_number(
147 current: RelayChainBlockNumber,
148 previous: RelayChainBlockNumber,
149 );
150}
151
152pub struct RelayNumberStrictlyIncreases;
157
158impl CheckAssociatedRelayNumber for RelayNumberStrictlyIncreases {
159 fn check_associated_relay_number(
160 current: RelayChainBlockNumber,
161 previous: RelayChainBlockNumber,
162 ) {
163 if current <= previous {
164 panic!("Relay chain block number needs to strictly increase between Parachain blocks!")
165 }
166 }
167}
168
169pub struct AnyRelayNumber;
174
175impl CheckAssociatedRelayNumber for AnyRelayNumber {
176 fn check_associated_relay_number(_: RelayChainBlockNumber, _: RelayChainBlockNumber) {}
177}
178
179pub struct RelayNumberMonotonicallyIncreases;
184
185impl CheckAssociatedRelayNumber for RelayNumberMonotonicallyIncreases {
186 fn check_associated_relay_number(
187 current: RelayChainBlockNumber,
188 previous: RelayChainBlockNumber,
189 ) {
190 if current < previous {
191 panic!(
192 "Relay chain block number needs to monotonically increase between Parachain blocks!"
193 )
194 }
195 }
196}
197
198pub type MaxDmpMessageLenOf<T> = <<T as Config>::DmpQueue as HandleMessage>::MaxMessageLen;
200
201pub mod ump_constants {
202 pub const THRESHOLD_FACTOR: u32 = 2;
206}
207
208const V3_CLAIM_QUEUE_LOOKAHEAD: u8 = 2;
209const V2_CLAIM_QUEUE_LOOKAHEAD: u8 = 1;
210
211fn max_allowed_claim_queue_offset(v3_enabled: bool, relay_parent_offset: u8) -> u8 {
217 if v3_enabled {
218 V3_CLAIM_QUEUE_LOOKAHEAD
219 } else {
220 V2_CLAIM_QUEUE_LOOKAHEAD.saturating_add(relay_parent_offset)
221 }
222}
223
224#[frame_support::pallet]
225pub mod pallet {
226 use super::*;
227 use codec::Compact;
228 use cumulus_primitives_core::CoreInfoExistsAtMaxOnce;
229 use frame_support::pallet_prelude::{ValueQuery, *};
230 use frame_system::pallet_prelude::*;
231
232 #[pallet::pallet]
233 #[pallet::storage_version(migration::STORAGE_VERSION)]
234 #[pallet::without_storage_info]
235 pub struct Pallet<T>(_);
236
237 #[pallet::config]
238 pub trait Config: frame_system::Config<OnSetCode = ParachainSetCode<Self>> {
239 #[allow(deprecated)]
241 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
242
243 type OnSystemEvent: OnSystemEvent;
245
246 #[pallet::constant]
248 type SelfParaId: Get<ParaId>;
249
250 type OutboundXcmpMessageSource: XcmpMessageSource;
252
253 type DmpQueue: HandleMessage;
258
259 type ReservedDmpWeight: Get<Weight>;
261
262 type XcmpMessageHandler: XcmpMessageHandler;
266
267 type ReservedXcmpWeight: Get<Weight>;
269
270 type CheckAssociatedRelayNumber: CheckAssociatedRelayNumber;
272
273 type WeightInfo: WeightInfo;
275
276 type ConsensusHook: ConsensusHook;
287
288 type RelayParentOffset: Get<u32>;
303
304 type SchedulingSignatureVerifier: cumulus_primitives_core::VerifySchedulingSignature;
332 }
333
334 #[pallet::hooks]
335 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
336 fn on_finalize(_: BlockNumberFor<T>) {
341 <DidSetValidationCode<T>>::kill();
342 <UpgradeRestrictionSignal<T>>::kill();
343 let relay_upgrade_go_ahead = <UpgradeGoAhead<T>>::take();
344
345 let vfp = <ValidationData<T>>::get().expect(
346 r"Missing required set_validation_data inherent. This inherent must be
347 present in every block. This error typically occurs when the set_validation_data
348 execution failed and was rejected by the block builder. Check earlier log entries
349 for the specific cause of the failure.",
350 );
351
352 LastRelayChainBlockNumber::<T>::put(vfp.relay_parent_number);
353
354 let host_config = match HostConfiguration::<T>::get() {
355 Some(ok) => ok,
356 None => {
357 debug_assert!(
358 false,
359 "host configuration is promised to set until `on_finalize`; qed",
360 );
361 return;
362 },
363 };
364
365 let total_bandwidth_out = match RelevantMessagingState::<T>::get() {
369 Some(s) => OutboundBandwidthLimits::from_relay_chain_state(&s),
370 None => {
371 debug_assert!(
372 false,
373 "relevant messaging state is promised to be set until `on_finalize`; \
374 qed",
375 );
376 return;
377 },
378 };
379
380 Self::adjust_egress_bandwidth_limits();
383
384 let current_core_selector =
385 CumulusDigestItem::find_core_info(&frame_system::Pallet::<T>::digest())
386 .map_or(0, |ci| ci.selector.0);
387
388 let current_bundle_index =
389 CumulusDigestItem::find_block_bundle_info(&frame_system::Pallet::<T>::digest())
390 .map_or(0, |bi| bi.index);
391
392 let mut pov_tracker = PoVMessagesTracker::<T>::get()
393 .filter(|tracker| {
394 tracker.relay_storage_root_or_hash == vfp.relay_parent_storage_root &&
396 tracker.core_selector == current_core_selector &&
398 current_bundle_index > tracker.bundle_index
400 })
401 .unwrap_or_default();
402
403 pov_tracker.bundle_index = current_bundle_index;
404 pov_tracker.core_selector = current_core_selector;
405 pov_tracker.relay_storage_root_or_hash = vfp.relay_parent_storage_root;
406
407 let (ump_msg_count, ump_total_bytes) = <PendingUpwardMessages<T>>::mutate(|up| {
408 let (available_capacity, available_size) = match RelevantMessagingState::<T>::get()
409 {
410 Some(limits) => (
411 limits.relay_dispatch_queue_remaining_capacity.remaining_count,
412 limits.relay_dispatch_queue_remaining_capacity.remaining_size,
413 ),
414 None => {
415 debug_assert!(
416 false,
417 "relevant messaging state is promised to be set until `on_finalize`; \
418 qed",
419 );
420 return (0, 0);
421 },
422 };
423
424 let available_capacity = cmp::min(
425 available_capacity,
426 host_config
427 .max_upward_message_num_per_candidate
428 .saturating_sub(pov_tracker.ump_msg_count),
429 );
430
431 let (num, total_size) = up
434 .iter()
435 .scan((0u32, 0u32), |state, msg| {
436 let (cap_used, size_used) = *state;
437 let new_cap = cap_used.saturating_add(1);
438 let new_size = size_used.saturating_add(msg.len() as u32);
439 match available_capacity
440 .checked_sub(new_cap)
441 .and(available_size.checked_sub(new_size))
442 {
443 Some(_) => {
444 *state = (new_cap, new_size);
445 Some(*state)
446 },
447 _ => None,
448 }
449 })
450 .last()
451 .unwrap_or_default();
452
453 UpwardMessages::<T>::put(&up[..num as usize]);
456 *up = up.split_off(num as usize);
457
458 pov_tracker.ump_msg_count = pov_tracker.ump_msg_count.saturating_add(num);
459
460 let digest = frame_system::Pallet::<T>::digest();
461
462 let core_info = CumulusDigestItem::find_core_info(&digest);
463 PreviousCoreCount::<T>::put(
464 core_info.as_ref().map_or(Compact(1u16), |ci| ci.number_of_cores),
465 );
466
467 if CumulusDigestItem::is_last_block_in_core(&digest).unwrap_or(true) {
470 Self::send_ump_signals(core_info);
471 }
472
473 let threshold = host_config
477 .max_upward_queue_size
478 .saturating_div(ump_constants::THRESHOLD_FACTOR);
479 let remaining_total_size: usize = up.iter().map(UpwardMessage::len).sum();
480 if remaining_total_size <= threshold as usize {
481 Self::decrease_fee_factor(());
482 }
483
484 (num, total_size)
485 });
486
487 let maximum_channels = host_config
497 .hrmp_max_message_num_per_candidate
498 .min(<AnnouncedHrmpMessagesPerCandidate<T>>::take())
499 as usize;
500
501 let maximum_channels =
502 maximum_channels.saturating_sub(pov_tracker.hrmp_outbound_count as usize);
503
504 let outbound_messages = T::OutboundXcmpMessageSource::take_outbound_messages(
508 maximum_channels,
509 &pov_tracker.hrmp_outbound_recipients,
510 )
511 .into_iter()
512 .map(|(recipient, data)| OutboundHrmpMessage { recipient, data })
513 .collect::<Vec<_>>();
514
515 pov_tracker
516 .hrmp_outbound_recipients
517 .extend(outbound_messages.iter().map(|m| m.recipient));
518 pov_tracker.hrmp_outbound_count =
519 pov_tracker.hrmp_outbound_count.saturating_add(outbound_messages.len() as u32);
520 PoVMessagesTracker::<T>::put(pov_tracker);
521
522 {
525 let hrmp_outgoing = outbound_messages
526 .iter()
527 .map(|msg| {
528 (
529 msg.recipient,
530 HrmpChannelUpdate { msg_count: 1, total_bytes: msg.data.len() as u32 },
531 )
532 })
533 .collect();
534 let used_bandwidth =
535 UsedBandwidth { ump_msg_count, ump_total_bytes, hrmp_outgoing };
536
537 let mut aggregated_segment =
538 AggregatedUnincludedSegment::<T>::get().unwrap_or_default();
539 let consumed_go_ahead_signal =
540 if aggregated_segment.consumed_go_ahead_signal().is_some() {
541 None
544 } else {
545 relay_upgrade_go_ahead
546 };
547 let ancestor = Ancestor::new_unchecked(used_bandwidth, consumed_go_ahead_signal);
549
550 let watermark = HrmpWatermark::<T>::get();
551 let watermark_update = HrmpWatermarkUpdate::new(watermark, vfp.relay_parent_number);
552
553 aggregated_segment
554 .append(&ancestor, watermark_update, &total_bandwidth_out)
555 .expect("unincluded segment limits exceeded");
556 AggregatedUnincludedSegment::<T>::put(aggregated_segment);
557 UnincludedSegment::<T>::append(ancestor);
559 }
560
561 HrmpOutboundMessages::<T>::put(outbound_messages);
562 }
563
564 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
565 let mut weight = Weight::zero();
566
567 if !<DidSetValidationCode<T>>::get() {
571 NewValidationCode::<T>::kill();
575 weight += T::DbWeight::get().writes(1);
576 }
577
578 {
580 <UnincludedSegment<T>>::mutate(|chain| {
581 if let Some(ancestor) = chain.last_mut() {
582 let parent = frame_system::Pallet::<T>::parent_hash();
583 ancestor.replace_para_head_hash(parent);
586 }
587 });
588 weight += T::DbWeight::get().reads_writes(1, 1);
589
590 weight += T::DbWeight::get().reads_writes(3, 2);
592 }
593
594 BlockWeightMode::<T>::kill();
595
596 ValidationData::<T>::kill();
598 ProcessedDownwardMessages::<T>::kill();
602 UpwardMessages::<T>::kill();
603 HrmpOutboundMessages::<T>::kill();
604 CustomValidationHeadData::<T>::kill();
605 HrmpWatermark::<T>::get();
607 weight += T::DbWeight::get().reads_writes(1, 5);
608
609 weight += T::DbWeight::get().reads_writes(1, 1);
628 let hrmp_max_message_num_per_candidate = HostConfiguration::<T>::get()
629 .map(|cfg| cfg.hrmp_max_message_num_per_candidate)
630 .unwrap_or(0);
631 <AnnouncedHrmpMessagesPerCandidate<T>>::put(hrmp_max_message_num_per_candidate);
632
633 weight += T::DbWeight::get().reads_writes(
635 3 + hrmp_max_message_num_per_candidate as u64,
636 4 + hrmp_max_message_num_per_candidate as u64,
637 );
638
639 weight += T::DbWeight::get().reads_writes(1, 1);
641
642 weight += T::DbWeight::get().reads_writes(6, 3);
644
645 weight += T::DbWeight::get().reads(1);
647
648 match CumulusDigestItem::core_info_exists_at_max_once(
650 &frame_system::Pallet::<T>::digest(),
651 ) {
652 CoreInfoExistsAtMaxOnce::Once(core_info) => {
653 let max_allowed_offset = max_allowed_claim_queue_offset(
654 T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED,
655 T::RelayParentOffset::get().saturated_into::<u8>(),
656 );
657 assert!(
658 core_info.claim_queue_offset.0 <= max_allowed_offset,
659 "claim_queue_offset {} exceeds maximum allowed {}",
660 core_info.claim_queue_offset.0,
661 max_allowed_offset,
662 );
663 },
664 CoreInfoExistsAtMaxOnce::NotFound => {},
665 CoreInfoExistsAtMaxOnce::MoreThanOnce => {
666 panic!("`CumulusDigestItem::CoreInfo` must exist at max once.");
667 },
668 }
669
670 weight
671 }
672 }
673
674 #[pallet::call]
675 impl<T: Config> Pallet<T> {
676 #[pallet::call_index(0)]
686 #[pallet::weight((0, DispatchClass::Mandatory))]
687 pub fn set_validation_data(
690 origin: OriginFor<T>,
691 data: BasicParachainInherentData,
692 inbound_messages_data: InboundMessagesData,
693 ) -> DispatchResult {
694 ensure_none(origin)?;
695 assert!(
696 !<ValidationData<T>>::exists(),
697 "ValidationData must be updated only once in a block",
698 );
699
700 let mut total_weight = Weight::zero();
702
703 let BasicParachainInherentData {
710 validation_data: vfp,
711 relay_chain_state,
712 relay_parent_descendants,
713 collator_peer_id,
714 } = data;
715
716 T::CheckAssociatedRelayNumber::check_associated_relay_number(
718 vfp.relay_parent_number,
719 LastRelayChainBlockNumber::<T>::get(),
720 );
721
722 let relay_state_proof = RelayChainStateProof::new(
723 T::SelfParaId::get(),
724 vfp.relay_parent_storage_root,
725 relay_chain_state.clone(),
726 )
727 .expect("Invalid relay chain state proof");
728
729 let expected_rp_descendants_num = T::RelayParentOffset::get();
734 let v3_enabled = T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED;
735
736 if expected_rp_descendants_num > 0 && !v3_enabled {
737 if let Err(err) = descendant_validation::verify_relay_parent_descendants(
738 &relay_state_proof,
739 relay_parent_descendants,
740 vfp.relay_parent_storage_root,
741 expected_rp_descendants_num,
742 ) {
743 panic!(
744 "Unable to verify provided relay parent descendants. \
745 expected_rp_descendants_num: {expected_rp_descendants_num} \
746 error: {err:?}"
747 );
748 };
749 }
750
751 let (consensus_hook_weight, capacity) =
753 T::ConsensusHook::on_state_proof(&relay_state_proof);
754 total_weight += consensus_hook_weight;
755 total_weight += Self::maybe_drop_included_ancestors(&relay_state_proof, capacity);
756 frame_system::Pallet::<T>::deposit_log(
760 cumulus_primitives_core::rpsr_digest::relay_parent_storage_root_item(
761 vfp.relay_parent_storage_root,
762 vfp.relay_parent_number,
763 ),
764 );
765
766 let upgrade_go_ahead_signal = relay_state_proof
770 .read_upgrade_go_ahead_signal()
771 .expect("Invalid upgrade go ahead signal");
772
773 let upgrade_signal_in_segment = AggregatedUnincludedSegment::<T>::get()
774 .as_ref()
775 .and_then(SegmentTracker::consumed_go_ahead_signal);
776 if let Some(signal_in_segment) = upgrade_signal_in_segment.as_ref() {
777 assert_eq!(upgrade_go_ahead_signal, Some(*signal_in_segment));
780 }
781 match upgrade_go_ahead_signal {
782 Some(_signal) if upgrade_signal_in_segment.is_some() => {
783 },
785 Some(relay_chain::UpgradeGoAhead::GoAhead) => {
786 assert!(
787 <PendingValidationCode<T>>::exists(),
788 "No new validation function found in storage, GoAhead signal is not expected",
789 );
790 let validation_code = <PendingValidationCode<T>>::take();
791
792 frame_system::Pallet::<T>::update_code_in_storage(&validation_code);
793 <T::OnSystemEvent as OnSystemEvent>::on_validation_code_applied();
794 Self::deposit_event(Event::ValidationFunctionApplied {
795 relay_chain_block_num: vfp.relay_parent_number,
796 });
797 },
798 Some(relay_chain::UpgradeGoAhead::Abort) => {
799 <PendingValidationCode<T>>::kill();
800 Self::deposit_event(Event::ValidationFunctionDiscarded);
801 },
802 None => {},
803 }
804 <UpgradeRestrictionSignal<T>>::put(
805 relay_state_proof
806 .read_upgrade_restriction_signal()
807 .expect("Invalid upgrade restriction signal"),
808 );
809 <UpgradeGoAhead<T>>::put(upgrade_go_ahead_signal);
810
811 let host_config = relay_state_proof
812 .read_abridged_host_configuration()
813 .expect("Invalid host configuration in relay chain state proof");
814
815 let relevant_messaging_state = relay_state_proof
816 .read_messaging_state_snapshot(&host_config)
817 .expect("Invalid messaging state in relay chain state proof");
818
819 <ValidationData<T>>::put(&vfp);
820 <RelayStateProof<T>>::put(relay_chain_state);
821 <RelevantMessagingState<T>>::put(relevant_messaging_state.clone());
822 <HostConfiguration<T>>::put(host_config);
823
824 total_weight.saturating_accrue(
825 <T::OnSystemEvent as OnSystemEvent>::on_relay_state_proof(&relay_state_proof),
826 );
827
828 <T::OnSystemEvent as OnSystemEvent>::on_validation_data(&vfp);
829
830 match collator_peer_id {
831 Some(peer_id) => PendingApprovedPeer::<T>::put(peer_id),
832 None => PendingApprovedPeer::<T>::kill(),
833 }
834
835 total_weight.saturating_accrue(Self::enqueue_inbound_downward_messages(
836 relevant_messaging_state.dmq_mqc_head,
837 inbound_messages_data.downward_messages,
838 ));
839 total_weight.saturating_accrue(Self::enqueue_inbound_horizontal_messages(
840 &relevant_messaging_state.ingress_channels,
841 inbound_messages_data.horizontal_messages,
842 vfp.relay_parent_number,
843 ));
844
845 frame_system::Pallet::<T>::register_extra_weight_unchecked(
846 total_weight,
847 DispatchClass::Mandatory,
848 );
849
850 Ok(())
851 }
852
853 #[pallet::call_index(1)]
854 #[pallet::weight((1_000, DispatchClass::Operational))]
855 pub fn sudo_send_upward_message(
856 origin: OriginFor<T>,
857 message: UpwardMessage,
858 ) -> DispatchResult {
859 ensure_root(origin)?;
860 let _ = Self::send_upward_message(message);
861 Ok(())
862 }
863
864 }
867
868 #[pallet::event]
869 #[pallet::generate_deposit(pub(super) fn deposit_event)]
870 pub enum Event<T: Config> {
871 ValidationFunctionStored,
873 ValidationFunctionApplied { relay_chain_block_num: RelayChainBlockNumber },
875 ValidationFunctionDiscarded,
877 DownwardMessagesReceived { count: u32 },
879 DownwardMessagesProcessed { weight_used: Weight, dmq_head: relay_chain::Hash },
881 UpwardMessageSent { message_hash: Option<XcmHash> },
883 }
884
885 #[pallet::error]
886 pub enum Error<T> {
887 OverlappingUpgrades,
889 ProhibitedByPolkadot,
891 TooBig,
894 ValidationDataNotAvailable,
896 HostConfigurationNotAvailable,
898 NotScheduled,
900 }
901
902 #[pallet::storage]
909 #[pallet::whitelist_storage]
910 pub type BlockWeightMode<T: Config> =
911 StorageValue<_, block_weight::BlockWeightMode<T>, OptionQuery>;
912
913 #[pallet::storage]
917 #[pallet::whitelist_storage]
918 pub type PreviousCoreCount<T: Config> = StorageValue<_, Compact<u16>, OptionQuery>;
919
920 #[pallet::storage]
927 pub type UnincludedSegment<T: Config> = StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;
928
929 #[pallet::storage]
933 pub type AggregatedUnincludedSegment<T: Config> =
934 StorageValue<_, SegmentTracker<T::Hash>, OptionQuery>;
935
936 #[pallet::storage]
943 pub type PendingValidationCode<T: Config> = StorageValue<_, Vec<u8>, ValueQuery>;
944
945 #[pallet::storage]
951 pub type NewValidationCode<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
952
953 #[pallet::storage]
957 pub type ValidationData<T: Config> = StorageValue<_, PersistedValidationData>;
958
959 #[pallet::storage]
961 pub type DidSetValidationCode<T: Config> = StorageValue<_, bool, ValueQuery>;
962
963 #[pallet::storage]
967 pub type LastRelayChainBlockNumber<T: Config> =
968 StorageValue<_, RelayChainBlockNumber, ValueQuery>;
969
970 #[pallet::storage]
978 pub type UpgradeRestrictionSignal<T: Config> =
979 StorageValue<_, Option<relay_chain::UpgradeRestriction>, ValueQuery>;
980
981 #[pallet::storage]
987 pub type UpgradeGoAhead<T: Config> =
988 StorageValue<_, Option<relay_chain::UpgradeGoAhead>, ValueQuery>;
989
990 #[pallet::storage]
997 pub type RelayStateProof<T: Config> = StorageValue<_, sp_trie::StorageProof>;
998
999 #[pallet::storage]
1007 pub type RelevantMessagingState<T: Config> = StorageValue<_, MessagingStateSnapshot>;
1008
1009 #[pallet::storage]
1016 #[pallet::disable_try_decode_storage]
1017 pub type HostConfiguration<T: Config> = StorageValue<_, AbridgedHostConfiguration>;
1018
1019 #[pallet::storage]
1024 pub type LastDmqMqcHead<T: Config> = StorageValue<_, MessageQueueChain, ValueQuery>;
1025
1026 #[pallet::storage]
1031 pub type LastHrmpMqcHeads<T: Config> =
1032 StorageValue<_, BTreeMap<ParaId, MessageQueueChain>, ValueQuery>;
1033
1034 #[pallet::storage]
1038 pub type ProcessedDownwardMessages<T: Config> = StorageValue<_, u32, ValueQuery>;
1039
1040 #[pallet::storage]
1044 pub type LastProcessedDownwardMessage<T: Config> = StorageValue<_, InboundMessageId>;
1045
1046 #[pallet::storage]
1048 pub type HrmpWatermark<T: Config> = StorageValue<_, relay_chain::BlockNumber, ValueQuery>;
1049
1050 #[pallet::storage]
1054 pub type LastProcessedHrmpMessage<T: Config> = StorageValue<_, InboundHrmpMessageId>;
1055
1056 #[pallet::storage]
1060 pub type HrmpOutboundMessages<T: Config> =
1061 StorageValue<_, Vec<OutboundHrmpMessage>, ValueQuery>;
1062
1063 #[pallet::storage]
1067 pub type UpwardMessages<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1068
1069 #[pallet::storage]
1071 pub type PendingUpwardMessages<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1072
1073 #[pallet::storage]
1077 pub type PendingUpwardSignals<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1078
1079 #[pallet::storage]
1081 pub type PendingApprovedPeer<T: Config> =
1082 StorageValue<_, relay_chain::ApprovedPeerId, OptionQuery>;
1083
1084 #[pallet::storage]
1086 pub type UpwardDeliveryFeeFactor<T: Config> =
1087 StorageValue<_, FixedU128, ValueQuery, GetMinFeeFactor<Pallet<T>>>;
1088
1089 #[pallet::storage]
1092 pub type AnnouncedHrmpMessagesPerCandidate<T: Config> = StorageValue<_, u32, ValueQuery>;
1093
1094 #[pallet::storage]
1097 pub type ReservedXcmpWeightOverride<T: Config> = StorageValue<_, Weight>;
1098
1099 #[pallet::storage]
1102 pub type ReservedDmpWeightOverride<T: Config> = StorageValue<_, Weight>;
1103
1104 #[pallet::storage]
1108 pub type CustomValidationHeadData<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
1109
1110 #[pallet::storage]
1114 pub type PoVMessagesTracker<T: Config> = StorageValue<_, PoVMessages, OptionQuery>;
1115
1116 #[pallet::inherent]
1117 impl<T: Config> ProvideInherent for Pallet<T> {
1118 type Call = Call<T>;
1119 type Error = sp_inherents::MakeFatalError<()>;
1120 const INHERENT_IDENTIFIER: InherentIdentifier =
1121 cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER;
1122
1123 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
1124 let data = match data
1125 .get_data::<ParachainInherentData>(&Self::INHERENT_IDENTIFIER)
1126 .ok()
1127 .flatten()
1128 {
1129 None => {
1130 let data = data
1135 .get_data::<v0::ParachainInherentData>(
1136 &cumulus_primitives_parachain_inherent::PARACHAIN_INHERENT_IDENTIFIER_V0,
1137 )
1138 .ok()
1139 .flatten()?;
1140 data.into()
1141 },
1142 Some(data) => data,
1143 };
1144
1145 Some(Self::do_create_inherent(data))
1146 }
1147
1148 fn is_inherent(call: &Self::Call) -> bool {
1149 matches!(call, Call::set_validation_data { .. })
1150 }
1151 }
1152
1153 #[pallet::genesis_config]
1154 #[derive(frame_support::DefaultNoBound)]
1155 pub struct GenesisConfig<T: Config> {
1156 #[serde(skip)]
1157 pub _config: core::marker::PhantomData<T>,
1158 }
1159
1160 #[pallet::genesis_build]
1161 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
1162 fn build(&self) {
1163 sp_io::storage::set(b":c", &[]);
1165 }
1166 }
1167}
1168
1169impl<T: Config> Pallet<T> {
1170 pub fn unincluded_segment_size_after(included_hash: T::Hash) -> u32 {
1178 let segment = UnincludedSegment::<T>::get();
1179 crate::unincluded_segment::size_after_included(included_hash, &segment)
1180 }
1181
1182 pub fn max_claim_queue_offset() -> u8 {
1187 if !T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED {
1188 return V2_CLAIM_QUEUE_LOOKAHEAD;
1189 }
1190
1191 V3_CLAIM_QUEUE_LOOKAHEAD
1192 }
1193}
1194
1195impl<T: Config> FeeTracker for Pallet<T> {
1196 type Id = ();
1197
1198 fn get_fee_factor(_id: Self::Id) -> FixedU128 {
1199 UpwardDeliveryFeeFactor::<T>::get()
1200 }
1201
1202 fn set_fee_factor(_id: Self::Id, val: FixedU128) {
1203 UpwardDeliveryFeeFactor::<T>::set(val);
1204 }
1205}
1206
1207impl<T: Config> ListChannelInfos for Pallet<T> {
1208 fn outgoing_channels() -> Vec<ParaId> {
1209 let Some(state) = RelevantMessagingState::<T>::get() else { return Vec::new() };
1210 state.egress_channels.into_iter().map(|(id, _)| id).collect()
1211 }
1212}
1213
1214impl<T: Config> GetChannelInfo for Pallet<T> {
1215 fn get_channel_status(id: ParaId) -> ChannelStatus {
1216 let channels = match RelevantMessagingState::<T>::get() {
1231 None => {
1232 log::warn!("calling `get_channel_status` with no RelevantMessagingState?!");
1233 return ChannelStatus::Closed;
1234 },
1235 Some(d) => d.egress_channels,
1236 };
1237 let index = match channels.binary_search_by_key(&id, |item| item.0) {
1244 Err(_) => return ChannelStatus::Closed,
1245 Ok(i) => i,
1246 };
1247 let meta = &channels[index].1;
1248 if meta.msg_count + 1 > meta.max_capacity {
1249 return ChannelStatus::Full;
1251 }
1252 let max_size_now = meta.max_total_size - meta.total_size;
1253 let max_size_ever = meta.max_message_size;
1254 ChannelStatus::Ready(max_size_now as usize, max_size_ever as usize)
1255 }
1256
1257 fn get_channel_info(id: ParaId) -> Option<ChannelInfo> {
1258 let channels = RelevantMessagingState::<T>::get()?.egress_channels;
1259 let index = channels.binary_search_by_key(&id, |item| item.0).ok()?;
1260 let info = ChannelInfo {
1261 max_capacity: channels[index].1.max_capacity,
1262 max_total_size: channels[index].1.max_total_size,
1263 max_message_size: channels[index].1.max_message_size,
1264 msg_count: channels[index].1.msg_count,
1265 total_size: channels[index].1.total_size,
1266 };
1267 Some(info)
1268 }
1269}
1270
1271impl<T: Config> Pallet<T> {
1272 fn messages_collection_size_limit() -> usize {
1282 let max_block_weight = <T as frame_system::Config>::BlockWeights::get().max_block;
1283 let max_block_pov = max_block_weight.proof_size();
1284
1285 let remaining_proof_size =
1286 frame_system::Pallet::<T>::remaining_block_weight().remaining().proof_size();
1287
1288 (max_block_pov / 6).min(remaining_proof_size).saturated_into()
1289 }
1290
1291 fn do_create_inherent(data: ParachainInherentData) -> Call<T> {
1297 let (data, mut downward_messages, mut horizontal_messages) =
1298 deconstruct_parachain_inherent_data(data);
1299 let last_relay_block_number = LastRelayChainBlockNumber::<T>::get();
1300
1301 let messages_collection_size_limit = Self::messages_collection_size_limit();
1302 let last_processed_msg = LastProcessedDownwardMessage::<T>::get()
1304 .unwrap_or(InboundMessageId { sent_at: last_relay_block_number, reverse_idx: 0 });
1305 downward_messages.drop_processed_messages(&last_processed_msg);
1306 let mut size_limit = messages_collection_size_limit;
1307 let downward_messages = downward_messages.into_abridged(&mut size_limit);
1308
1309 let last_processed_msg =
1311 LastProcessedHrmpMessage::<T>::get().unwrap_or(InboundHrmpMessageId::Generic(
1312 InboundMessageId { sent_at: last_relay_block_number, reverse_idx: 0 },
1313 ));
1314 horizontal_messages.drop_hrmp_processed_messages(&last_processed_msg);
1315 size_limit = size_limit.saturating_add(messages_collection_size_limit);
1316 let horizontal_messages = horizontal_messages.into_abridged(&mut size_limit);
1317
1318 let inbound_messages_data =
1319 InboundMessagesData::new(downward_messages, horizontal_messages);
1320
1321 Call::set_validation_data { data, inbound_messages_data }
1322 }
1323
1324 fn enqueue_inbound_downward_messages(
1334 expected_dmq_mqc_head: relay_chain::Hash,
1335 downward_messages: AbridgedInboundDownwardMessages,
1336 ) -> Weight {
1337 downward_messages.check_enough_messages_included_basic("DMQ");
1338
1339 let mut dmq_head = <LastDmqMqcHead<T>>::get();
1340
1341 let (messages, hashed_messages) = downward_messages.messages();
1342 let message_count = messages.len() as u32;
1343 let weight_used = T::WeightInfo::enqueue_inbound_downward_messages(message_count);
1344 if let Some(last_msg) = messages.last() {
1345 Self::deposit_event(Event::DownwardMessagesReceived { count: message_count });
1346
1347 for msg in messages {
1349 dmq_head.extend_downward(msg);
1350 }
1351 <LastDmqMqcHead<T>>::put(&dmq_head);
1352 Self::deposit_event(Event::DownwardMessagesProcessed {
1353 weight_used,
1354 dmq_head: dmq_head.head(),
1355 });
1356
1357 let mut last_processed_msg =
1358 InboundMessageId { sent_at: last_msg.sent_at, reverse_idx: 0 };
1359 for msg in hashed_messages {
1360 dmq_head.extend_with_hashed_msg(msg);
1361
1362 if msg.sent_at == last_processed_msg.sent_at {
1363 last_processed_msg.reverse_idx += 1;
1364 }
1365 }
1366 LastProcessedDownwardMessage::<T>::put(last_processed_msg);
1367
1368 T::DmpQueue::handle_messages(downward_messages.bounded_msgs_iter());
1369 }
1370
1371 assert_eq!(dmq_head.head(), expected_dmq_mqc_head, "DMQ head mismatch");
1377
1378 ProcessedDownwardMessages::<T>::put(message_count);
1379
1380 weight_used
1381 }
1382
1383 fn get_ingress_channel_or_panic(
1384 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1385 sender: ParaId,
1386 ) -> &cumulus_primitives_core::AbridgedHrmpChannel {
1387 let maybe_channel_idx = ingress_channels
1388 .binary_search_by_key(&sender, |&(channel_sender, _)| channel_sender)
1389 .ok();
1390 let maybe_channel = maybe_channel_idx
1391 .and_then(|channel_idx| ingress_channels.get(channel_idx))
1392 .map(|(_, channel)| channel);
1393 maybe_channel.unwrap_or_else(|| {
1394 panic!(
1395 "One of the messages submitted by the collator was sent from a sender ({}) \
1396 that doesn't have a channel opened to this parachain",
1397 <ParaId as Into<u32>>::into(sender)
1398 )
1399 })
1400 }
1401
1402 fn check_hrmp_mcq_heads(
1403 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1404 mqc_heads: &mut BTreeMap<ParaId, MessageQueueChain>,
1405 ) {
1406 for (sender, channel) in ingress_channels {
1414 let cur_head = mqc_heads.entry(*sender).or_default().head();
1415 let target_head = channel.mqc_head.unwrap_or_default();
1416 assert_eq!(cur_head, target_head, "HRMP head mismatch");
1417 }
1418 }
1419
1420 fn check_hrmp_message_metadata(
1425 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1426 maybe_prev_msg_metadata: &mut Option<(u32, ParaId)>,
1427 msg_metadata: (u32, ParaId),
1428 ) {
1429 if let Some(prev_msg) = maybe_prev_msg_metadata {
1431 assert!(&msg_metadata >= prev_msg, "[HRMP] Messages order violation");
1432 }
1433 *maybe_prev_msg_metadata = Some(msg_metadata);
1434
1435 Self::get_ingress_channel_or_panic(ingress_channels, msg_metadata.1);
1437 }
1438
1439 fn enqueue_inbound_horizontal_messages(
1450 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1451 horizontal_messages: AbridgedInboundHrmpMessages,
1452 relay_parent_number: relay_chain::BlockNumber,
1453 ) -> Weight {
1454 let mut mqc_heads = <LastHrmpMqcHeads<T>>::get();
1455 let (messages, hashed_messages) = horizontal_messages.messages();
1456
1457 let maybe_first_hashed_msg_sender = hashed_messages.first().map(|(sender, _msg)| *sender);
1459 if let Some(first_hashed_msg_sender) = maybe_first_hashed_msg_sender {
1460 let channel =
1461 Self::get_ingress_channel_or_panic(ingress_channels, first_hashed_msg_sender);
1462 horizontal_messages.check_enough_messages_included_advanced(
1463 "HRMP",
1464 AbridgedInboundMessagesSizeInfo {
1465 max_full_messages_size: Self::messages_collection_size_limit(),
1466 first_hashed_msg_max_size: channel.max_message_size as usize,
1467 },
1468 );
1469 }
1470
1471 Self::prune_closed_mqc_heads(ingress_channels, &mut mqc_heads);
1472
1473 if messages.is_empty() {
1474 Self::check_hrmp_mcq_heads(ingress_channels, &mut mqc_heads);
1475
1476 HrmpWatermark::<T>::put(relay_parent_number);
1477 LastHrmpMqcHeads::<T>::put(&mqc_heads); return T::DbWeight::get().reads_writes(1, 2);
1480 }
1481
1482 let max_weight =
1483 <ReservedXcmpWeightOverride<T>>::get().unwrap_or_else(T::ReservedXcmpWeight::get);
1484 let (mut num_processed_pages, weight_used) = T::XcmpMessageHandler::handle_xcmp_messages(
1485 horizontal_messages.flat_msgs_iter(),
1486 max_weight,
1487 );
1488 num_processed_pages = cmp::min(num_processed_pages, messages.len());
1489 let (processed_messages, unprocessed_messages) = messages.split_at(num_processed_pages);
1490
1491 let mut prev_msg_metadata = None;
1492 let mut last_processed_block = HrmpWatermark::<T>::get();
1493 let mut last_processed_msg =
1494 LastProcessedHrmpMessage::<T>::get().unwrap_or(InboundHrmpMessageId::Specific {
1495 sent_at: 0,
1496 sender: 0.into(),
1497 reverse_idx: u32::MAX,
1498 });
1499
1500 for (sender, msg) in processed_messages {
1501 Self::check_hrmp_message_metadata(
1502 ingress_channels,
1503 &mut prev_msg_metadata,
1504 (msg.sent_at, *sender),
1505 );
1506 mqc_heads.entry(*sender).or_default().extend_hrmp(msg);
1507
1508 if msg.sent_at > last_processed_msg.sent_at() {
1509 last_processed_block = last_processed_block.max(last_processed_msg.sent_at());
1510 }
1511 last_processed_msg = InboundHrmpMessageId::Specific {
1512 sent_at: msg.sent_at,
1513 sender: *sender,
1514 reverse_idx: 0,
1515 };
1516 }
1517
1518 LastHrmpMqcHeads::<T>::put(&mqc_heads);
1519
1520 let unprocessed_messages = unprocessed_messages
1521 .iter()
1522 .map(|(sender, msg)| (*sender, HashedMessage::from(msg)))
1523 .collect::<Vec<_>>();
1524 for (sender, msg) in unprocessed_messages.iter().chain(hashed_messages) {
1525 Self::check_hrmp_message_metadata(
1526 ingress_channels,
1527 &mut prev_msg_metadata,
1528 (msg.sent_at, *sender),
1529 );
1530 mqc_heads.entry(*sender).or_default().extend_with_hashed_msg(msg);
1531
1532 if last_processed_msg.sent_at() == msg.sent_at &&
1533 (last_processed_msg.sender() == Some(*sender) ||
1534 last_processed_msg.sender() == None)
1535 {
1536 last_processed_msg.inc_reverse_idx();
1537 }
1538 }
1539 match hashed_messages.first() {
1540 Some((_, first_hashed_msg)) => {
1541 if first_hashed_msg.sent_at > last_processed_msg.sent_at() {
1542 last_processed_block = last_processed_block.max(last_processed_msg.sent_at());
1543 }
1544 },
1545 None => {
1546 last_processed_block = last_processed_block.max(last_processed_msg.sent_at());
1547 },
1548 }
1549 LastProcessedHrmpMessage::<T>::put(&last_processed_msg);
1550 Self::check_hrmp_mcq_heads(ingress_channels, &mut mqc_heads);
1551
1552 HrmpWatermark::<T>::put(last_processed_block);
1554
1555 weight_used.saturating_add(T::DbWeight::get().reads_writes(2, 3))
1556 }
1557
1558 fn prune_closed_mqc_heads(
1560 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1561 mqc_heads: &mut BTreeMap<ParaId, MessageQueueChain>,
1562 ) {
1563 mqc_heads.retain(|para, _| {
1565 ingress_channels
1566 .binary_search_by_key(para, |&(channel_sender, _)| channel_sender)
1567 .is_ok()
1568 });
1569 }
1570
1571 fn maybe_drop_included_ancestors(
1573 relay_state_proof: &RelayChainStateProof,
1574 capacity: consensus_hook::UnincludedSegmentCapacity,
1575 ) -> Weight {
1576 let mut weight_used = Weight::zero();
1577 let para_head =
1579 relay_state_proof.read_included_para_head().ok().map(|h| T::Hashing::hash(&h.0));
1580
1581 let unincluded_segment_len = <UnincludedSegment<T>>::decode_len().unwrap_or(0);
1582 weight_used += T::DbWeight::get().reads(1);
1583
1584 let included_head = match (para_head, capacity.is_expecting_included_parent()) {
1586 (Some(h), true) => {
1587 assert_eq!(
1588 h,
1589 frame_system::Pallet::<T>::parent_hash(),
1590 "expected parent to be included"
1591 );
1592
1593 h
1594 },
1595 (Some(h), false) => h,
1596 (None, true) => {
1597 frame_system::Pallet::<T>::parent_hash()
1600 },
1601 (None, false) => panic!("included head not present in relay storage proof"),
1602 };
1603
1604 let new_len = {
1605 let para_head_hash = included_head;
1606 let dropped: Vec<Ancestor<T::Hash>> = <UnincludedSegment<T>>::mutate(|chain| {
1607 let idx = chain
1610 .iter()
1611 .position(|block| {
1612 let head_hash = block
1613 .para_head_hash()
1614 .expect("para head hash is updated during block initialization; qed");
1615 head_hash == ¶_head_hash
1616 })
1617 .map_or(0, |idx| idx + 1); chain.drain(..idx).collect()
1620 });
1621 weight_used += T::DbWeight::get().reads_writes(1, 1);
1622
1623 let new_len = unincluded_segment_len - dropped.len();
1624 if !dropped.is_empty() {
1625 <AggregatedUnincludedSegment<T>>::mutate(|agg| {
1626 let agg = agg.as_mut().expect(
1627 "dropped part of the segment wasn't empty, hence value exists; qed",
1628 );
1629 for block in dropped {
1630 agg.subtract(&block);
1631 }
1632 });
1633 weight_used += T::DbWeight::get().reads_writes(1, 1);
1634 }
1635
1636 new_len as u32
1637 };
1638
1639 assert!(
1644 new_len < capacity.get(),
1645 "No space left for the block in the unincluded segment: new_len({new_len}) < capacity({})",
1646 capacity.get()
1647 );
1648 weight_used
1649 }
1650
1651 fn adjust_egress_bandwidth_limits() {
1656 let Some(unincluded_segment) = AggregatedUnincludedSegment::<T>::get() else { return };
1657
1658 <RelevantMessagingState<T>>::mutate(|messaging_state| {
1659 let Some(messaging_state) = messaging_state else { return };
1660
1661 let used_bandwidth = unincluded_segment.used_bandwidth();
1662
1663 let channels = &mut messaging_state.egress_channels;
1664 for (para_id, used) in used_bandwidth.hrmp_outgoing.iter() {
1665 let Ok(i) = channels.binary_search_by_key(para_id, |item| item.0) else {
1666 continue; };
1668
1669 let c = &mut channels[i].1;
1670
1671 c.total_size = (c.total_size + used.total_bytes).min(c.max_total_size);
1672 c.msg_count = (c.msg_count + used.msg_count).min(c.max_capacity);
1673 }
1674
1675 let upward_capacity = &mut messaging_state.relay_dispatch_queue_remaining_capacity;
1676 upward_capacity.remaining_count =
1677 upward_capacity.remaining_count.saturating_sub(used_bandwidth.ump_msg_count);
1678 upward_capacity.remaining_size =
1679 upward_capacity.remaining_size.saturating_sub(used_bandwidth.ump_total_bytes);
1680 });
1681 }
1682
1683 fn notify_polkadot_of_pending_upgrade(code: &[u8]) {
1687 NewValidationCode::<T>::put(code);
1688 <DidSetValidationCode<T>>::put(true);
1689 }
1690
1691 pub fn max_code_size() -> Option<u32> {
1695 <HostConfiguration<T>>::get().map(|cfg| cfg.max_code_size)
1696 }
1697
1698 pub fn schedule_code_upgrade(validation_function: Vec<u8>) -> DispatchResult {
1700 ensure!(<ValidationData<T>>::exists(), Error::<T>::ValidationDataNotAvailable);
1704 ensure!(<UpgradeRestrictionSignal<T>>::get().is_none(), Error::<T>::ProhibitedByPolkadot);
1705
1706 ensure!(!<PendingValidationCode<T>>::exists(), Error::<T>::OverlappingUpgrades);
1707 let cfg = HostConfiguration::<T>::get().ok_or(Error::<T>::HostConfigurationNotAvailable)?;
1708 ensure!(validation_function.len() <= cfg.max_code_size as usize, Error::<T>::TooBig);
1709
1710 Self::notify_polkadot_of_pending_upgrade(&validation_function);
1718 <PendingValidationCode<T>>::put(validation_function);
1719 Self::deposit_event(Event::ValidationFunctionStored);
1720
1721 Ok(())
1722 }
1723
1724 pub fn collect_collation_info(header: &HeaderFor<T>) -> CollationInfo {
1732 CollationInfo {
1733 hrmp_watermark: HrmpWatermark::<T>::get(),
1734 horizontal_messages: HrmpOutboundMessages::<T>::get(),
1735 upward_messages: UpwardMessages::<T>::get(),
1736 processed_downward_messages: ProcessedDownwardMessages::<T>::get(),
1737 new_validation_code: NewValidationCode::<T>::get().map(Into::into),
1738 head_data: CustomValidationHeadData::<T>::get()
1741 .map_or_else(|| header.encode(), |v| v)
1742 .into(),
1743 }
1744 }
1745
1746 pub fn set_custom_validation_head_data(head_data: Vec<u8>) {
1759 CustomValidationHeadData::<T>::put(head_data);
1760 }
1761
1762 fn send_ump_signals(core_info: Option<CoreInfo>) {
1764 let mut ump_signals = PendingUpwardSignals::<T>::take();
1765
1766 if let Some(core_info) = core_info {
1767 ump_signals.push(
1768 UMPSignal::SelectCore(core_info.selector, core_info.claim_queue_offset).encode(),
1769 );
1770 }
1771
1772 if let Some(approved_peer) = PendingApprovedPeer::<T>::take() {
1773 ump_signals.push(UMPSignal::ApprovedPeer(approved_peer).encode());
1774 }
1775
1776 if !ump_signals.is_empty() {
1777 UpwardMessages::<T>::append(UMP_SEPARATOR);
1778 ump_signals.into_iter().for_each(|s| UpwardMessages::<T>::append(s));
1779 }
1780 }
1781
1782 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
1787 pub fn open_outbound_hrmp_channel_for_benchmarks_or_tests(target_parachain: ParaId) {
1788 RelevantMessagingState::<T>::put(MessagingStateSnapshot {
1789 dmq_mqc_head: Default::default(),
1790 relay_dispatch_queue_remaining_capacity: Default::default(),
1791 ingress_channels: Default::default(),
1792 egress_channels: vec![(
1793 target_parachain,
1794 cumulus_primitives_core::AbridgedHrmpChannel {
1795 max_capacity: 10,
1796 max_total_size: 10_000_000_u32,
1797 max_message_size: 10_000_000_u32,
1798 msg_count: 5,
1799 total_size: 5_000_000_u32,
1800 mqc_head: None,
1801 },
1802 )],
1803 })
1804 }
1805
1806 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
1811 pub fn open_custom_outbound_hrmp_channel_for_benchmarks_or_tests(
1812 target_parachain: ParaId,
1813 channel: cumulus_primitives_core::AbridgedHrmpChannel,
1814 ) {
1815 RelevantMessagingState::<T>::put(MessagingStateSnapshot {
1816 dmq_mqc_head: Default::default(),
1817 relay_dispatch_queue_remaining_capacity: Default::default(),
1818 ingress_channels: Default::default(),
1819 egress_channels: vec![(target_parachain, channel)],
1820 })
1821 }
1822
1823 #[cfg(feature = "runtime-benchmarks")]
1825 pub fn initialize_for_set_code_benchmark(max_code_size: u32) {
1826 let vfp = PersistedValidationData {
1828 parent_head: polkadot_parachain_primitives::primitives::HeadData(Default::default()),
1829 relay_parent_number: 1,
1830 relay_parent_storage_root: Default::default(),
1831 max_pov_size: 1_000,
1832 };
1833 <ValidationData<T>>::put(&vfp);
1834
1835 let host_config = AbridgedHostConfiguration {
1837 max_code_size,
1838 max_head_data_size: 32 * 1024,
1839 max_upward_queue_count: 8,
1840 max_upward_queue_size: 1024 * 1024,
1841 max_upward_message_size: 4 * 1024,
1842 max_upward_message_num_per_candidate: 2,
1843 hrmp_max_message_num_per_candidate: 2,
1844 validation_upgrade_cooldown: 2,
1845 validation_upgrade_delay: 2,
1846 async_backing_params: relay_chain::AsyncBackingParams {
1847 allowed_ancestry_len: 0,
1848 max_candidate_depth: 0,
1849 },
1850 };
1851 <HostConfiguration<T>>::put(host_config);
1852 }
1853}
1854
1855pub struct ParachainSetCode<T>(core::marker::PhantomData<T>);
1857impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
1858 fn set_code(code: Vec<u8>) -> DispatchResult {
1859 Pallet::<T>::schedule_code_upgrade(code)
1860 }
1861}
1862
1863impl<T: Config> Pallet<T> {
1864 pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
1870 let message_len = message.len();
1871 if let Some(cfg) = HostConfiguration::<T>::get() {
1884 if message_len > cfg.max_upward_message_size as usize {
1885 return Err(MessageSendError::TooBig);
1886 }
1887 let threshold =
1888 cfg.max_upward_queue_size.saturating_div(ump_constants::THRESHOLD_FACTOR);
1889 <PendingUpwardMessages<T>>::append(message.clone());
1892 let pending_messages = PendingUpwardMessages::<T>::get();
1893 let total_size: usize = pending_messages.iter().map(UpwardMessage::len).sum();
1894 if total_size > threshold as usize {
1895 Self::increase_fee_factor((), message_len as u128);
1897 }
1898 } else {
1899 <PendingUpwardMessages<T>>::append(message.clone());
1909 };
1910
1911 let hash = sp_io::hashing::blake2_256(&message);
1914 Self::deposit_event(Event::UpwardMessageSent { message_hash: Some(hash) });
1915 Ok((0, hash))
1916 }
1917
1918 pub fn last_relay_block_number() -> RelayChainBlockNumber {
1921 LastRelayChainBlockNumber::<T>::get()
1922 }
1923}
1924
1925impl<T: Config> UpwardMessageSender for Pallet<T> {
1926 fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
1927 Self::send_upward_message(message)
1928 }
1929
1930 fn can_send_upward_message(message: &UpwardMessage) -> Result<(), MessageSendError> {
1931 let max_upward_message_size = HostConfiguration::<T>::get()
1932 .map(|cfg| cfg.max_upward_message_size)
1933 .ok_or(MessageSendError::Other)?;
1934 if message.len() > max_upward_message_size as usize {
1935 Err(MessageSendError::TooBig)
1936 } else {
1937 Ok(())
1938 }
1939 }
1940
1941 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
1942 fn ensure_successful_delivery() {
1943 const MAX_UPWARD_MESSAGE_SIZE: u32 = 65_531 * 3;
1944 const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
1945 HostConfiguration::<T>::mutate(|cfg| match cfg {
1946 Some(cfg) => cfg.max_upward_message_size = MAX_UPWARD_MESSAGE_SIZE,
1947 None => {
1948 *cfg = Some(AbridgedHostConfiguration {
1949 max_code_size: MAX_CODE_SIZE,
1950 max_head_data_size: 32 * 1024,
1951 max_upward_queue_count: 8,
1952 max_upward_queue_size: 1024 * 1024,
1953 max_upward_message_size: MAX_UPWARD_MESSAGE_SIZE,
1954 max_upward_message_num_per_candidate: 2,
1955 hrmp_max_message_num_per_candidate: 2,
1956 validation_upgrade_cooldown: 2,
1957 validation_upgrade_delay: 2,
1958 async_backing_params: relay_chain::AsyncBackingParams {
1959 allowed_ancestry_len: 0,
1960 max_candidate_depth: 0,
1961 },
1962 })
1963 },
1964 })
1965 }
1966}
1967
1968impl<T: Config> InspectMessageQueues for Pallet<T> {
1969 fn clear_messages() {
1970 PendingUpwardMessages::<T>::kill();
1971 }
1972
1973 fn get_messages() -> Vec<(VersionedLocation, Vec<VersionedXcm<()>>)> {
1974 use xcm::prelude::*;
1975
1976 let messages: Vec<VersionedXcm<()>> = PendingUpwardMessages::<T>::get()
1977 .iter()
1978 .map(|encoded_message| {
1979 VersionedXcm::<()>::decode_all_with_mem_and_depth_limit(&mut &encoded_message[..])
1980 .unwrap()
1981 })
1982 .collect();
1983
1984 if messages.is_empty() {
1985 vec![]
1986 } else {
1987 vec![(VersionedLocation::from(Location::parent()), messages)]
1988 }
1989 }
1990}
1991
1992#[cfg(feature = "runtime-benchmarks")]
1993impl<T: Config> polkadot_runtime_parachains::EnsureForParachain for Pallet<T> {
1994 fn ensure(para_id: ParaId) {
1995 if let ChannelStatus::Closed = Self::get_channel_status(para_id) {
1996 Self::open_outbound_hrmp_channel_for_benchmarks_or_tests(para_id)
1997 }
1998 }
1999}
2000
2001pub trait OnSystemEvent {
2009 fn on_validation_data(data: &PersistedValidationData);
2011 fn on_validation_code_applied();
2014 fn on_relay_state_proof(
2016 relay_state_proof: &relay_state_snapshot::RelayChainStateProof,
2017 ) -> Weight;
2018}
2019
2020#[impl_trait_for_tuples::impl_for_tuples(30)]
2021impl OnSystemEvent for Tuple {
2022 fn on_validation_data(data: &PersistedValidationData) {
2023 for_tuples!( #( Tuple::on_validation_data(data); )* );
2024 }
2025
2026 fn on_validation_code_applied() {
2027 for_tuples!( #( Tuple::on_validation_code_applied(); )* );
2028 }
2029
2030 fn on_relay_state_proof(
2031 relay_state_proof: &relay_state_snapshot::RelayChainStateProof,
2032 ) -> Weight {
2033 let mut weight = Weight::zero();
2034 for_tuples!( #( weight = weight.saturating_add(Tuple::on_relay_state_proof(relay_state_proof)); )* );
2035 weight
2036 }
2037}
2038
2039#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Default, Debug)]
2041pub struct RelayChainState {
2042 pub number: relay_chain::BlockNumber,
2044 pub state_root: relay_chain::Hash,
2046}
2047
2048pub trait RelaychainStateProvider {
2052 fn current_relay_chain_state() -> RelayChainState;
2056
2057 #[cfg(feature = "runtime-benchmarks")]
2062 fn set_current_relay_chain_state(_state: RelayChainState) {}
2063}
2064
2065pub struct RelaychainDataProvider<T>(core::marker::PhantomData<T>);
2081
2082impl<T: Config> BlockNumberProvider for RelaychainDataProvider<T> {
2083 type BlockNumber = relay_chain::BlockNumber;
2084
2085 fn current_block_number() -> relay_chain::BlockNumber {
2086 ValidationData::<T>::get()
2087 .map(|d| d.relay_parent_number)
2088 .unwrap_or_else(|| Pallet::<T>::last_relay_block_number())
2089 }
2090
2091 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
2092 fn set_block_number(block: Self::BlockNumber) {
2093 let mut validation_data = ValidationData::<T>::get().unwrap_or_else(||
2094 PersistedValidationData {
2096 parent_head: vec![].into(),
2097 relay_parent_number: Default::default(),
2098 max_pov_size: Default::default(),
2099 relay_parent_storage_root: Default::default(),
2100 });
2101 validation_data.relay_parent_number = block;
2102 ValidationData::<T>::put(validation_data)
2103 }
2104}
2105
2106impl<T: Config> RelaychainStateProvider for RelaychainDataProvider<T> {
2107 fn current_relay_chain_state() -> RelayChainState {
2108 ValidationData::<T>::get()
2109 .map(|d| RelayChainState {
2110 number: d.relay_parent_number,
2111 state_root: d.relay_parent_storage_root,
2112 })
2113 .unwrap_or_default()
2114 }
2115
2116 #[cfg(feature = "runtime-benchmarks")]
2117 fn set_current_relay_chain_state(state: RelayChainState) {
2118 let mut validation_data = ValidationData::<T>::get().unwrap_or_else(||
2119 PersistedValidationData {
2121 parent_head: vec![].into(),
2122 relay_parent_number: Default::default(),
2123 max_pov_size: Default::default(),
2124 relay_parent_storage_root: Default::default(),
2125 });
2126 validation_data.relay_parent_number = state.number;
2127 validation_data.relay_parent_storage_root = state.state_root;
2128 ValidationData::<T>::put(validation_data)
2129 }
2130}