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::{v0, MessageQueueChain, ParachainInherentData};
43use frame_support::{
44 dispatch::{DispatchClass, DispatchResult},
45 ensure,
46 inherent::{InherentData, InherentIdentifier, ProvideInherent},
47 traits::{Get, HandleMessage},
48 weights::Weight,
49};
50use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor};
51use parachain_inherent::{
52 deconstruct_parachain_inherent_data, AbridgedInboundDownwardMessages,
53 AbridgedInboundHrmpMessages, BasicParachainInherentData, InboundMessageId, InboundMessagesData,
54};
55use polkadot_parachain_primitives::primitives::RelayChainBlockNumber;
56use polkadot_runtime_parachains::{FeeTracker, GetMinFeeFactor};
57use scale_info::TypeInfo;
58use sp_runtime::{
59 traits::{BlockNumberProvider, Hash},
60 Debug, FixedU128, SaturatedConversion,
61};
62use xcm::{latest::XcmHash, VersionedLocation, VersionedXcm};
63use xcm_builder::InspectMessageQueues;
64
65mod benchmarking;
66pub mod block_weight;
67pub mod consensus_hook;
68pub mod migration;
69mod mock;
70pub mod relay_state_snapshot;
71#[cfg(test)]
72mod tests;
73mod unincluded_segment;
74pub mod weights;
75#[macro_use]
76pub mod validate_block;
77mod descendant_validation;
78pub mod parachain_inherent;
79
80use unincluded_segment::{
81 HrmpChannelUpdate, HrmpWatermarkUpdate, OutboundBandwidthLimits, SegmentTracker,
82};
83
84pub use consensus_hook::{ConsensusHook, ExpectParentIncluded};
85pub use cumulus_pallet_parachain_system_proc_macro::register_validate_block;
106pub use relay_state_snapshot::{MessagingStateSnapshot, RelayChainStateProof};
107pub use unincluded_segment::{Ancestor, UsedBandwidth};
108pub use weights::WeightInfo;
109
110use crate::parachain_inherent::AbridgedInboundMessagesSizeInfo;
111pub use pallet::*;
112
113const LOG_TARGET: &str = "runtime::parachain-system";
114
115#[derive(Encode, Decode, Clone, Debug, TypeInfo, Default)]
117pub struct PoVMessages {
118 pub relay_storage_root_or_hash: relay_chain::Hash,
120 pub core_selector: u8,
122 pub bundle_index: u8,
124 pub ump_msg_count: u32,
126 pub hrmp_outbound_count: u32,
128 pub hrmp_outbound_recipients: Vec<ParaId>,
130}
131
132pub trait CheckAssociatedRelayNumber {
141 fn check_associated_relay_number(
145 current: RelayChainBlockNumber,
146 previous: RelayChainBlockNumber,
147 );
148}
149
150pub struct RelayNumberStrictlyIncreases;
155
156impl CheckAssociatedRelayNumber for RelayNumberStrictlyIncreases {
157 fn check_associated_relay_number(
158 current: RelayChainBlockNumber,
159 previous: RelayChainBlockNumber,
160 ) {
161 if current <= previous {
162 panic!("Relay chain block number needs to strictly increase between Parachain blocks!")
163 }
164 }
165}
166
167pub struct AnyRelayNumber;
172
173impl CheckAssociatedRelayNumber for AnyRelayNumber {
174 fn check_associated_relay_number(_: RelayChainBlockNumber, _: RelayChainBlockNumber) {}
175}
176
177pub struct RelayNumberMonotonicallyIncreases;
182
183impl CheckAssociatedRelayNumber for RelayNumberMonotonicallyIncreases {
184 fn check_associated_relay_number(
185 current: RelayChainBlockNumber,
186 previous: RelayChainBlockNumber,
187 ) {
188 if current < previous {
189 panic!(
190 "Relay chain block number needs to monotonically increase between Parachain blocks!"
191 )
192 }
193 }
194}
195
196pub type MaxDmpMessageLenOf<T> = <<T as Config>::DmpQueue as HandleMessage>::MaxMessageLen;
198
199pub mod ump_constants {
200 pub const THRESHOLD_FACTOR: u32 = 2;
204}
205
206const V3_CLAIM_QUEUE_LOOKAHEAD: u8 = 2;
207const V2_CLAIM_QUEUE_LOOKAHEAD: u8 = 1;
208
209fn max_allowed_claim_queue_offset(v3_enabled: bool, relay_parent_offset: u8) -> u8 {
215 if v3_enabled {
216 V3_CLAIM_QUEUE_LOOKAHEAD
217 } else {
218 V2_CLAIM_QUEUE_LOOKAHEAD.saturating_add(relay_parent_offset)
219 }
220}
221
222#[frame_support::pallet]
223pub mod pallet {
224 use super::*;
225 use codec::Compact;
226 use cumulus_primitives_core::CoreInfoExistsAtMaxOnce;
227 use frame_support::pallet_prelude::{ValueQuery, *};
228 use frame_system::pallet_prelude::*;
229
230 #[pallet::pallet]
231 #[pallet::storage_version(migration::STORAGE_VERSION)]
232 #[pallet::without_storage_info]
233 pub struct Pallet<T>(_);
234
235 #[pallet::config]
236 pub trait Config: frame_system::Config<OnSetCode = ParachainSetCode<Self>> {
237 #[allow(deprecated)]
239 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
240
241 type OnSystemEvent: OnSystemEvent;
243
244 #[pallet::constant]
246 type SelfParaId: Get<ParaId>;
247
248 type OutboundXcmpMessageSource: XcmpMessageSource;
250
251 type DmpQueue: HandleMessage;
256
257 type ReservedDmpWeight: Get<Weight>;
259
260 type XcmpMessageHandler: XcmpMessageHandler;
264
265 type ReservedXcmpWeight: Get<Weight>;
267
268 type CheckAssociatedRelayNumber: CheckAssociatedRelayNumber;
270
271 type WeightInfo: WeightInfo;
273
274 type ConsensusHook: ConsensusHook;
285
286 type RelayParentOffset: Get<u32>;
301
302 type SchedulingSignatureVerifier: cumulus_primitives_core::VerifySchedulingSignature;
330 }
331
332 #[pallet::hooks]
333 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
334 fn on_finalize(_: BlockNumberFor<T>) {
339 <DidSetValidationCode<T>>::kill();
340 <UpgradeRestrictionSignal<T>>::kill();
341 let relay_upgrade_go_ahead = <UpgradeGoAhead<T>>::take();
342
343 let vfp = <ValidationData<T>>::get().expect(
344 r"Missing required set_validation_data inherent. This inherent must be
345 present in every block. This error typically occurs when the set_validation_data
346 execution failed and was rejected by the block builder. Check earlier log entries
347 for the specific cause of the failure.",
348 );
349
350 LastRelayChainBlockNumber::<T>::put(vfp.relay_parent_number);
351
352 let host_config = match HostConfiguration::<T>::get() {
353 Some(ok) => ok,
354 None => {
355 debug_assert!(
356 false,
357 "host configuration is promised to set until `on_finalize`; qed",
358 );
359 return;
360 },
361 };
362
363 let total_bandwidth_out = match RelevantMessagingState::<T>::get() {
367 Some(s) => OutboundBandwidthLimits::from_relay_chain_state(&s),
368 None => {
369 debug_assert!(
370 false,
371 "relevant messaging state is promised to be set until `on_finalize`; \
372 qed",
373 );
374 return;
375 },
376 };
377
378 Self::adjust_egress_bandwidth_limits();
381
382 let current_core_selector =
383 CumulusDigestItem::find_core_info(&frame_system::Pallet::<T>::digest())
384 .map_or(0, |ci| ci.selector.0);
385
386 let current_bundle_index =
387 CumulusDigestItem::find_block_bundle_info(&frame_system::Pallet::<T>::digest())
388 .map_or(0, |bi| bi.index);
389
390 let mut pov_tracker = PoVMessagesTracker::<T>::get()
391 .filter(|tracker| {
392 tracker.relay_storage_root_or_hash == vfp.relay_parent_storage_root &&
394 tracker.core_selector == current_core_selector &&
396 current_bundle_index > tracker.bundle_index
398 })
399 .unwrap_or_default();
400
401 pov_tracker.bundle_index = current_bundle_index;
402 pov_tracker.core_selector = current_core_selector;
403 pov_tracker.relay_storage_root_or_hash = vfp.relay_parent_storage_root;
404
405 let (ump_msg_count, ump_total_bytes) = <PendingUpwardMessages<T>>::mutate(|up| {
406 let (available_capacity, available_size) = match RelevantMessagingState::<T>::get()
407 {
408 Some(limits) => (
409 limits.relay_dispatch_queue_remaining_capacity.remaining_count,
410 limits.relay_dispatch_queue_remaining_capacity.remaining_size,
411 ),
412 None => {
413 debug_assert!(
414 false,
415 "relevant messaging state is promised to be set until `on_finalize`; \
416 qed",
417 );
418 return (0, 0);
419 },
420 };
421
422 let available_capacity = cmp::min(
423 available_capacity,
424 host_config
425 .max_upward_message_num_per_candidate
426 .saturating_sub(pov_tracker.ump_msg_count),
427 );
428
429 let (num, total_size) = up
432 .iter()
433 .scan((0u32, 0u32), |state, msg| {
434 let (cap_used, size_used) = *state;
435 let new_cap = cap_used.saturating_add(1);
436 let new_size = size_used.saturating_add(msg.len() as u32);
437 match available_capacity
438 .checked_sub(new_cap)
439 .and(available_size.checked_sub(new_size))
440 {
441 Some(_) => {
442 *state = (new_cap, new_size);
443 Some(*state)
444 },
445 _ => None,
446 }
447 })
448 .last()
449 .unwrap_or_default();
450
451 UpwardMessages::<T>::put(&up[..num as usize]);
454 *up = up.split_off(num as usize);
455
456 pov_tracker.ump_msg_count = pov_tracker.ump_msg_count.saturating_add(num);
457
458 let digest = frame_system::Pallet::<T>::digest();
459
460 let core_info = CumulusDigestItem::find_core_info(&digest);
461 PreviousCoreCount::<T>::put(
462 core_info.as_ref().map_or(Compact(1u16), |ci| ci.number_of_cores),
463 );
464
465 if CumulusDigestItem::is_last_block_in_core(&digest).unwrap_or(true) {
468 Self::send_ump_signals(core_info);
469 }
470
471 let threshold = host_config
475 .max_upward_queue_size
476 .saturating_div(ump_constants::THRESHOLD_FACTOR);
477 let remaining_total_size: usize = up.iter().map(UpwardMessage::len).sum();
478 if remaining_total_size <= threshold as usize {
479 Self::decrease_fee_factor(());
480 }
481
482 (num, total_size)
483 });
484
485 let maximum_channels = host_config
495 .hrmp_max_message_num_per_candidate
496 .min(<AnnouncedHrmpMessagesPerCandidate<T>>::take())
497 as usize;
498
499 let maximum_channels =
500 maximum_channels.saturating_sub(pov_tracker.hrmp_outbound_count as usize);
501
502 let outbound_messages = T::OutboundXcmpMessageSource::take_outbound_messages(
506 maximum_channels,
507 &pov_tracker.hrmp_outbound_recipients,
508 )
509 .into_iter()
510 .map(|(recipient, data)| OutboundHrmpMessage { recipient, data })
511 .collect::<Vec<_>>();
512
513 pov_tracker
514 .hrmp_outbound_recipients
515 .extend(outbound_messages.iter().map(|m| m.recipient));
516 pov_tracker.hrmp_outbound_count =
517 pov_tracker.hrmp_outbound_count.saturating_add(outbound_messages.len() as u32);
518 PoVMessagesTracker::<T>::put(pov_tracker);
519
520 {
523 let hrmp_outgoing = outbound_messages
524 .iter()
525 .map(|msg| {
526 (
527 msg.recipient,
528 HrmpChannelUpdate { msg_count: 1, total_bytes: msg.data.len() as u32 },
529 )
530 })
531 .collect();
532 let used_bandwidth =
533 UsedBandwidth { ump_msg_count, ump_total_bytes, hrmp_outgoing };
534
535 let mut aggregated_segment =
536 AggregatedUnincludedSegment::<T>::get().unwrap_or_default();
537 let consumed_go_ahead_signal =
538 if aggregated_segment.consumed_go_ahead_signal().is_some() {
539 None
542 } else {
543 relay_upgrade_go_ahead
544 };
545 let ancestor = Ancestor::new_unchecked(used_bandwidth, consumed_go_ahead_signal);
547
548 let watermark = HrmpWatermark::<T>::get();
549 let watermark_update = HrmpWatermarkUpdate::new(watermark, vfp.relay_parent_number);
550
551 aggregated_segment
552 .append(&ancestor, watermark_update, &total_bandwidth_out)
553 .expect("unincluded segment limits exceeded");
554 AggregatedUnincludedSegment::<T>::put(aggregated_segment);
555 UnincludedSegment::<T>::append(ancestor);
557 }
558
559 HrmpOutboundMessages::<T>::put(outbound_messages);
560 }
561
562 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
563 let mut weight = Weight::zero();
564
565 if !<DidSetValidationCode<T>>::get() {
569 NewValidationCode::<T>::kill();
573 weight += T::DbWeight::get().writes(1);
574 }
575
576 {
578 <UnincludedSegment<T>>::mutate(|chain| {
579 if let Some(ancestor) = chain.last_mut() {
580 let parent = frame_system::Pallet::<T>::parent_hash();
581 ancestor.replace_para_head_hash(parent);
584 }
585 });
586 weight += T::DbWeight::get().reads_writes(1, 1);
587
588 weight += T::DbWeight::get().reads_writes(3, 2);
590 }
591
592 BlockWeightMode::<T>::kill();
593
594 ValidationData::<T>::kill();
596 ProcessedDownwardMessages::<T>::kill();
600 UpwardMessages::<T>::kill();
601 HrmpOutboundMessages::<T>::kill();
602 CustomValidationHeadData::<T>::kill();
603 HrmpWatermark::<T>::get();
605 weight += T::DbWeight::get().reads_writes(1, 5);
606
607 weight += T::DbWeight::get().reads_writes(1, 1);
626 let hrmp_max_message_num_per_candidate = HostConfiguration::<T>::get()
627 .map(|cfg| cfg.hrmp_max_message_num_per_candidate)
628 .unwrap_or(0);
629 <AnnouncedHrmpMessagesPerCandidate<T>>::put(hrmp_max_message_num_per_candidate);
630
631 weight += T::DbWeight::get().reads_writes(
633 3 + hrmp_max_message_num_per_candidate as u64,
634 4 + hrmp_max_message_num_per_candidate as u64,
635 );
636
637 weight += T::DbWeight::get().reads_writes(1, 1);
639
640 weight += T::DbWeight::get().reads_writes(6, 3);
642
643 weight += T::DbWeight::get().reads(1);
645
646 match CumulusDigestItem::core_info_exists_at_max_once(
648 &frame_system::Pallet::<T>::digest(),
649 ) {
650 CoreInfoExistsAtMaxOnce::Once(core_info) => {
651 let max_allowed_offset = max_allowed_claim_queue_offset(
652 T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED,
653 T::RelayParentOffset::get().saturated_into::<u8>(),
654 );
655 assert!(
656 core_info.claim_queue_offset.0 <= max_allowed_offset,
657 "claim_queue_offset {} exceeds maximum allowed {}",
658 core_info.claim_queue_offset.0,
659 max_allowed_offset,
660 );
661 },
662 CoreInfoExistsAtMaxOnce::NotFound => {},
663 CoreInfoExistsAtMaxOnce::MoreThanOnce => {
664 panic!("`CumulusDigestItem::CoreInfo` must exist at max once.");
665 },
666 }
667
668 weight
669 }
670 }
671
672 #[pallet::call]
673 impl<T: Config> Pallet<T> {
674 #[pallet::call_index(0)]
684 #[pallet::weight((0, DispatchClass::Mandatory))]
685 pub fn set_validation_data(
688 origin: OriginFor<T>,
689 data: BasicParachainInherentData,
690 inbound_messages_data: InboundMessagesData,
691 ) -> DispatchResult {
692 ensure_none(origin)?;
693 assert!(
694 !<ValidationData<T>>::exists(),
695 "ValidationData must be updated only once in a block",
696 );
697
698 let mut total_weight = Weight::zero();
700
701 let BasicParachainInherentData {
708 validation_data: vfp,
709 relay_chain_state,
710 relay_parent_descendants,
711 collator_peer_id,
712 } = data;
713
714 T::CheckAssociatedRelayNumber::check_associated_relay_number(
716 vfp.relay_parent_number,
717 LastRelayChainBlockNumber::<T>::get(),
718 );
719
720 let relay_state_proof = RelayChainStateProof::new(
721 T::SelfParaId::get(),
722 vfp.relay_parent_storage_root,
723 relay_chain_state.clone(),
724 )
725 .expect("Invalid relay chain state proof");
726
727 let expected_rp_descendants_num = T::RelayParentOffset::get();
732 let v3_enabled = T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED;
733
734 if expected_rp_descendants_num > 0 && !v3_enabled {
735 if let Err(err) = descendant_validation::verify_relay_parent_descendants(
736 &relay_state_proof,
737 relay_parent_descendants,
738 vfp.relay_parent_storage_root,
739 expected_rp_descendants_num,
740 ) {
741 panic!(
742 "Unable to verify provided relay parent descendants. \
743 expected_rp_descendants_num: {expected_rp_descendants_num} \
744 error: {err:?}"
745 );
746 };
747 }
748
749 let (consensus_hook_weight, capacity) =
751 T::ConsensusHook::on_state_proof(&relay_state_proof);
752 total_weight += consensus_hook_weight;
753 total_weight += Self::maybe_drop_included_ancestors(&relay_state_proof, capacity);
754 frame_system::Pallet::<T>::deposit_log(
758 cumulus_primitives_core::rpsr_digest::relay_parent_storage_root_item(
759 vfp.relay_parent_storage_root,
760 vfp.relay_parent_number,
761 ),
762 );
763
764 let upgrade_go_ahead_signal = relay_state_proof
768 .read_upgrade_go_ahead_signal()
769 .expect("Invalid upgrade go ahead signal");
770
771 let upgrade_signal_in_segment = AggregatedUnincludedSegment::<T>::get()
772 .as_ref()
773 .and_then(SegmentTracker::consumed_go_ahead_signal);
774 if let Some(signal_in_segment) = upgrade_signal_in_segment.as_ref() {
775 assert_eq!(upgrade_go_ahead_signal, Some(*signal_in_segment));
778 }
779 match upgrade_go_ahead_signal {
780 Some(_signal) if upgrade_signal_in_segment.is_some() => {
781 },
783 Some(relay_chain::UpgradeGoAhead::GoAhead) => {
784 assert!(
785 <PendingValidationCode<T>>::exists(),
786 "No new validation function found in storage, GoAhead signal is not expected",
787 );
788 let validation_code = <PendingValidationCode<T>>::take();
789
790 frame_system::Pallet::<T>::update_code_in_storage(&validation_code);
791 <T::OnSystemEvent as OnSystemEvent>::on_validation_code_applied();
792 Self::deposit_event(Event::ValidationFunctionApplied {
793 relay_chain_block_num: vfp.relay_parent_number,
794 });
795 },
796 Some(relay_chain::UpgradeGoAhead::Abort) => {
797 <PendingValidationCode<T>>::kill();
798 Self::deposit_event(Event::ValidationFunctionDiscarded);
799 },
800 None => {},
801 }
802 <UpgradeRestrictionSignal<T>>::put(
803 relay_state_proof
804 .read_upgrade_restriction_signal()
805 .expect("Invalid upgrade restriction signal"),
806 );
807 <UpgradeGoAhead<T>>::put(upgrade_go_ahead_signal);
808
809 let host_config = relay_state_proof
810 .read_abridged_host_configuration()
811 .expect("Invalid host configuration in relay chain state proof");
812
813 let relevant_messaging_state = relay_state_proof
814 .read_messaging_state_snapshot(&host_config)
815 .expect("Invalid messaging state in relay chain state proof");
816
817 <ValidationData<T>>::put(&vfp);
818 <RelayStateProof<T>>::put(relay_chain_state);
819 <RelevantMessagingState<T>>::put(relevant_messaging_state.clone());
820 <HostConfiguration<T>>::put(host_config);
821
822 total_weight.saturating_accrue(
823 <T::OnSystemEvent as OnSystemEvent>::on_relay_state_proof(&relay_state_proof),
824 );
825
826 <T::OnSystemEvent as OnSystemEvent>::on_validation_data(&vfp);
827
828 match collator_peer_id {
829 Some(peer_id) => PendingApprovedPeer::<T>::put(peer_id),
830 None => PendingApprovedPeer::<T>::kill(),
831 }
832
833 total_weight.saturating_accrue(Self::enqueue_inbound_downward_messages(
834 relevant_messaging_state.dmq_mqc_head,
835 inbound_messages_data.downward_messages,
836 ));
837 total_weight.saturating_accrue(Self::enqueue_inbound_horizontal_messages(
838 &relevant_messaging_state.ingress_channels,
839 inbound_messages_data.horizontal_messages,
840 vfp.relay_parent_number,
841 ));
842
843 frame_system::Pallet::<T>::register_extra_weight_unchecked(
844 total_weight,
845 DispatchClass::Mandatory,
846 );
847
848 Ok(())
849 }
850
851 #[pallet::call_index(1)]
852 #[pallet::weight((1_000, DispatchClass::Operational))]
853 pub fn sudo_send_upward_message(
854 origin: OriginFor<T>,
855 message: UpwardMessage,
856 ) -> DispatchResult {
857 ensure_root(origin)?;
858 let _ = Self::send_upward_message(message);
859 Ok(())
860 }
861
862 }
865
866 #[pallet::event]
867 #[pallet::generate_deposit(pub(super) fn deposit_event)]
868 pub enum Event<T: Config> {
869 ValidationFunctionStored,
871 ValidationFunctionApplied { relay_chain_block_num: RelayChainBlockNumber },
873 ValidationFunctionDiscarded,
875 DownwardMessagesReceived { count: u32 },
877 DownwardMessagesProcessed { weight_used: Weight, dmq_head: relay_chain::Hash },
879 UpwardMessageSent { message_hash: Option<XcmHash> },
881 }
882
883 #[pallet::error]
884 pub enum Error<T> {
885 OverlappingUpgrades,
887 ProhibitedByPolkadot,
889 TooBig,
892 ValidationDataNotAvailable,
894 HostConfigurationNotAvailable,
896 NotScheduled,
898 }
899
900 #[pallet::storage]
907 #[pallet::whitelist_storage]
908 pub type BlockWeightMode<T: Config> =
909 StorageValue<_, block_weight::BlockWeightMode<T>, OptionQuery>;
910
911 #[pallet::storage]
915 #[pallet::whitelist_storage]
916 pub type PreviousCoreCount<T: Config> = StorageValue<_, Compact<u16>, OptionQuery>;
917
918 #[pallet::storage]
925 pub type UnincludedSegment<T: Config> = StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;
926
927 #[pallet::storage]
931 pub type AggregatedUnincludedSegment<T: Config> =
932 StorageValue<_, SegmentTracker<T::Hash>, OptionQuery>;
933
934 #[pallet::storage]
941 pub type PendingValidationCode<T: Config> = StorageValue<_, Vec<u8>, ValueQuery>;
942
943 #[pallet::storage]
949 pub type NewValidationCode<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
950
951 #[pallet::storage]
955 pub type ValidationData<T: Config> = StorageValue<_, PersistedValidationData>;
956
957 #[pallet::storage]
959 pub type DidSetValidationCode<T: Config> = StorageValue<_, bool, ValueQuery>;
960
961 #[pallet::storage]
965 pub type LastRelayChainBlockNumber<T: Config> =
966 StorageValue<_, RelayChainBlockNumber, ValueQuery>;
967
968 #[pallet::storage]
976 pub type UpgradeRestrictionSignal<T: Config> =
977 StorageValue<_, Option<relay_chain::UpgradeRestriction>, ValueQuery>;
978
979 #[pallet::storage]
985 pub type UpgradeGoAhead<T: Config> =
986 StorageValue<_, Option<relay_chain::UpgradeGoAhead>, ValueQuery>;
987
988 #[pallet::storage]
995 pub type RelayStateProof<T: Config> = StorageValue<_, sp_trie::StorageProof>;
996
997 #[pallet::storage]
1005 pub type RelevantMessagingState<T: Config> = StorageValue<_, MessagingStateSnapshot>;
1006
1007 #[pallet::storage]
1014 #[pallet::disable_try_decode_storage]
1015 pub type HostConfiguration<T: Config> = StorageValue<_, AbridgedHostConfiguration>;
1016
1017 #[pallet::storage]
1022 pub type LastDmqMqcHead<T: Config> = StorageValue<_, MessageQueueChain, ValueQuery>;
1023
1024 #[pallet::storage]
1029 pub type LastHrmpMqcHeads<T: Config> =
1030 StorageValue<_, BTreeMap<ParaId, MessageQueueChain>, ValueQuery>;
1031
1032 #[pallet::storage]
1036 pub type ProcessedDownwardMessages<T: Config> = StorageValue<_, u32, ValueQuery>;
1037
1038 #[pallet::storage]
1042 pub type LastProcessedDownwardMessage<T: Config> = StorageValue<_, InboundMessageId>;
1043
1044 #[pallet::storage]
1046 pub type HrmpWatermark<T: Config> = StorageValue<_, relay_chain::BlockNumber, ValueQuery>;
1047
1048 #[pallet::storage]
1052 pub type LastProcessedHrmpMessage<T: Config> = StorageValue<_, InboundMessageId>;
1053
1054 #[pallet::storage]
1058 pub type HrmpOutboundMessages<T: Config> =
1059 StorageValue<_, Vec<OutboundHrmpMessage>, ValueQuery>;
1060
1061 #[pallet::storage]
1065 pub type UpwardMessages<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1066
1067 #[pallet::storage]
1069 pub type PendingUpwardMessages<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1070
1071 #[pallet::storage]
1075 pub type PendingUpwardSignals<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1076
1077 #[pallet::storage]
1079 pub type PendingApprovedPeer<T: Config> =
1080 StorageValue<_, relay_chain::ApprovedPeerId, OptionQuery>;
1081
1082 #[pallet::storage]
1084 pub type UpwardDeliveryFeeFactor<T: Config> =
1085 StorageValue<_, FixedU128, ValueQuery, GetMinFeeFactor<Pallet<T>>>;
1086
1087 #[pallet::storage]
1090 pub type AnnouncedHrmpMessagesPerCandidate<T: Config> = StorageValue<_, u32, ValueQuery>;
1091
1092 #[pallet::storage]
1095 pub type ReservedXcmpWeightOverride<T: Config> = StorageValue<_, Weight>;
1096
1097 #[pallet::storage]
1100 pub type ReservedDmpWeightOverride<T: Config> = StorageValue<_, Weight>;
1101
1102 #[pallet::storage]
1106 pub type CustomValidationHeadData<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
1107
1108 #[pallet::storage]
1112 pub type PoVMessagesTracker<T: Config> = StorageValue<_, PoVMessages, OptionQuery>;
1113
1114 #[pallet::inherent]
1115 impl<T: Config> ProvideInherent for Pallet<T> {
1116 type Call = Call<T>;
1117 type Error = sp_inherents::MakeFatalError<()>;
1118 const INHERENT_IDENTIFIER: InherentIdentifier =
1119 cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER;
1120
1121 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
1122 let data = match data
1123 .get_data::<ParachainInherentData>(&Self::INHERENT_IDENTIFIER)
1124 .ok()
1125 .flatten()
1126 {
1127 None => {
1128 let data = data
1133 .get_data::<v0::ParachainInherentData>(
1134 &cumulus_primitives_parachain_inherent::PARACHAIN_INHERENT_IDENTIFIER_V0,
1135 )
1136 .ok()
1137 .flatten()?;
1138 data.into()
1139 },
1140 Some(data) => data,
1141 };
1142
1143 Some(Self::do_create_inherent(data))
1144 }
1145
1146 fn is_inherent(call: &Self::Call) -> bool {
1147 matches!(call, Call::set_validation_data { .. })
1148 }
1149 }
1150
1151 #[pallet::genesis_config]
1152 #[derive(frame_support::DefaultNoBound)]
1153 pub struct GenesisConfig<T: Config> {
1154 #[serde(skip)]
1155 pub _config: core::marker::PhantomData<T>,
1156 }
1157
1158 #[pallet::genesis_build]
1159 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
1160 fn build(&self) {
1161 sp_io::storage::set(b":c", &[]);
1163 }
1164 }
1165}
1166
1167impl<T: Config> Pallet<T> {
1168 pub fn unincluded_segment_size_after(included_hash: T::Hash) -> u32 {
1176 let segment = UnincludedSegment::<T>::get();
1177 crate::unincluded_segment::size_after_included(included_hash, &segment)
1178 }
1179
1180 pub fn max_claim_queue_offset() -> u8 {
1185 if !T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED {
1186 return V2_CLAIM_QUEUE_LOOKAHEAD;
1187 }
1188
1189 V3_CLAIM_QUEUE_LOOKAHEAD
1190 }
1191}
1192
1193impl<T: Config> FeeTracker for Pallet<T> {
1194 type Id = ();
1195
1196 fn get_fee_factor(_id: Self::Id) -> FixedU128 {
1197 UpwardDeliveryFeeFactor::<T>::get()
1198 }
1199
1200 fn set_fee_factor(_id: Self::Id, val: FixedU128) {
1201 UpwardDeliveryFeeFactor::<T>::set(val);
1202 }
1203}
1204
1205impl<T: Config> ListChannelInfos for Pallet<T> {
1206 fn outgoing_channels() -> Vec<ParaId> {
1207 let Some(state) = RelevantMessagingState::<T>::get() else { return Vec::new() };
1208 state.egress_channels.into_iter().map(|(id, _)| id).collect()
1209 }
1210}
1211
1212impl<T: Config> GetChannelInfo for Pallet<T> {
1213 fn get_channel_status(id: ParaId) -> ChannelStatus {
1214 let channels = match RelevantMessagingState::<T>::get() {
1229 None => {
1230 log::warn!("calling `get_channel_status` with no RelevantMessagingState?!");
1231 return ChannelStatus::Closed;
1232 },
1233 Some(d) => d.egress_channels,
1234 };
1235 let index = match channels.binary_search_by_key(&id, |item| item.0) {
1242 Err(_) => return ChannelStatus::Closed,
1243 Ok(i) => i,
1244 };
1245 let meta = &channels[index].1;
1246 if meta.msg_count + 1 > meta.max_capacity {
1247 return ChannelStatus::Full;
1249 }
1250 let max_size_now = meta.max_total_size - meta.total_size;
1251 let max_size_ever = meta.max_message_size;
1252 ChannelStatus::Ready(max_size_now as usize, max_size_ever as usize)
1253 }
1254
1255 fn get_channel_info(id: ParaId) -> Option<ChannelInfo> {
1256 let channels = RelevantMessagingState::<T>::get()?.egress_channels;
1257 let index = channels.binary_search_by_key(&id, |item| item.0).ok()?;
1258 let info = ChannelInfo {
1259 max_capacity: channels[index].1.max_capacity,
1260 max_total_size: channels[index].1.max_total_size,
1261 max_message_size: channels[index].1.max_message_size,
1262 msg_count: channels[index].1.msg_count,
1263 total_size: channels[index].1.total_size,
1264 };
1265 Some(info)
1266 }
1267}
1268
1269impl<T: Config> Pallet<T> {
1270 fn messages_collection_size_limit() -> usize {
1280 let max_block_weight = <T as frame_system::Config>::BlockWeights::get().max_block;
1281 let max_block_pov = max_block_weight.proof_size();
1282
1283 let remaining_proof_size =
1284 frame_system::Pallet::<T>::remaining_block_weight().remaining().proof_size();
1285
1286 (max_block_pov / 6).min(remaining_proof_size).saturated_into()
1287 }
1288
1289 fn do_create_inherent(data: ParachainInherentData) -> Call<T> {
1295 let (data, mut downward_messages, mut horizontal_messages) =
1296 deconstruct_parachain_inherent_data(data);
1297 let last_relay_block_number = LastRelayChainBlockNumber::<T>::get();
1298
1299 let messages_collection_size_limit = Self::messages_collection_size_limit();
1300 let last_processed_msg = LastProcessedDownwardMessage::<T>::get()
1302 .unwrap_or(InboundMessageId { sent_at: last_relay_block_number, reverse_idx: 0 });
1303 downward_messages.drop_processed_messages(&last_processed_msg);
1304 let mut size_limit = messages_collection_size_limit;
1305 let downward_messages = downward_messages.into_abridged(&mut size_limit);
1306
1307 let last_processed_msg = LastProcessedHrmpMessage::<T>::get()
1309 .unwrap_or(InboundMessageId { sent_at: last_relay_block_number, reverse_idx: 0 });
1310 horizontal_messages.drop_processed_messages(&last_processed_msg);
1311 size_limit = size_limit.saturating_add(messages_collection_size_limit);
1312 let horizontal_messages = horizontal_messages.into_abridged(&mut size_limit);
1313
1314 let inbound_messages_data =
1315 InboundMessagesData::new(downward_messages, horizontal_messages);
1316
1317 Call::set_validation_data { data, inbound_messages_data }
1318 }
1319
1320 fn enqueue_inbound_downward_messages(
1330 expected_dmq_mqc_head: relay_chain::Hash,
1331 downward_messages: AbridgedInboundDownwardMessages,
1332 ) -> Weight {
1333 downward_messages.check_enough_messages_included_basic("DMQ");
1334
1335 let mut dmq_head = <LastDmqMqcHead<T>>::get();
1336
1337 let (messages, hashed_messages) = downward_messages.messages();
1338 let message_count = messages.len() as u32;
1339 let weight_used = T::WeightInfo::enqueue_inbound_downward_messages(message_count);
1340 if let Some(last_msg) = messages.last() {
1341 Self::deposit_event(Event::DownwardMessagesReceived { count: message_count });
1342
1343 for msg in messages {
1345 dmq_head.extend_downward(msg);
1346 }
1347 <LastDmqMqcHead<T>>::put(&dmq_head);
1348 Self::deposit_event(Event::DownwardMessagesProcessed {
1349 weight_used,
1350 dmq_head: dmq_head.head(),
1351 });
1352
1353 let mut last_processed_msg =
1354 InboundMessageId { sent_at: last_msg.sent_at, reverse_idx: 0 };
1355 for msg in hashed_messages {
1356 dmq_head.extend_with_hashed_msg(msg);
1357
1358 if msg.sent_at == last_processed_msg.sent_at {
1359 last_processed_msg.reverse_idx += 1;
1360 }
1361 }
1362 LastProcessedDownwardMessage::<T>::put(last_processed_msg);
1363
1364 T::DmpQueue::handle_messages(downward_messages.bounded_msgs_iter());
1365 }
1366
1367 assert_eq!(dmq_head.head(), expected_dmq_mqc_head, "DMQ head mismatch");
1373
1374 ProcessedDownwardMessages::<T>::put(message_count);
1375
1376 weight_used
1377 }
1378
1379 fn get_ingress_channel_or_panic(
1380 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1381 sender: ParaId,
1382 ) -> &cumulus_primitives_core::AbridgedHrmpChannel {
1383 let maybe_channel_idx = ingress_channels
1384 .binary_search_by_key(&sender, |&(channel_sender, _)| channel_sender)
1385 .ok();
1386 let maybe_channel = maybe_channel_idx
1387 .and_then(|channel_idx| ingress_channels.get(channel_idx))
1388 .map(|(_, channel)| channel);
1389 maybe_channel.unwrap_or_else(|| {
1390 panic!(
1391 "One of the messages submitted by the collator was sent from a sender ({}) \
1392 that doesn't have a channel opened to this parachain",
1393 <ParaId as Into<u32>>::into(sender)
1394 )
1395 })
1396 }
1397
1398 fn check_hrmp_mcq_heads(
1399 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1400 mqc_heads: &mut BTreeMap<ParaId, MessageQueueChain>,
1401 ) {
1402 for (sender, channel) in ingress_channels {
1410 let cur_head = mqc_heads.entry(*sender).or_default().head();
1411 let target_head = channel.mqc_head.unwrap_or_default();
1412 assert_eq!(cur_head, target_head, "HRMP head mismatch");
1413 }
1414 }
1415
1416 fn check_hrmp_message_metadata(
1421 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1422 maybe_prev_msg_metadata: &mut Option<(u32, ParaId)>,
1423 msg_metadata: (u32, ParaId),
1424 ) {
1425 if let Some(prev_msg) = maybe_prev_msg_metadata {
1427 assert!(&msg_metadata >= prev_msg, "[HRMP] Messages order violation");
1428 }
1429 *maybe_prev_msg_metadata = Some(msg_metadata);
1430
1431 Self::get_ingress_channel_or_panic(ingress_channels, msg_metadata.1);
1433 }
1434
1435 fn enqueue_inbound_horizontal_messages(
1446 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1447 horizontal_messages: AbridgedInboundHrmpMessages,
1448 relay_parent_number: relay_chain::BlockNumber,
1449 ) -> Weight {
1450 let mut mqc_heads = <LastHrmpMqcHeads<T>>::get();
1451 let (messages, hashed_messages) = horizontal_messages.messages();
1452
1453 let maybe_first_hashed_msg_sender = hashed_messages.first().map(|(sender, _msg)| *sender);
1455 if let Some(first_hashed_msg_sender) = maybe_first_hashed_msg_sender {
1456 let channel =
1457 Self::get_ingress_channel_or_panic(ingress_channels, first_hashed_msg_sender);
1458 horizontal_messages.check_enough_messages_included_advanced(
1459 "HRMP",
1460 AbridgedInboundMessagesSizeInfo {
1461 max_full_messages_size: Self::messages_collection_size_limit(),
1462 first_hashed_msg_max_size: channel.max_message_size as usize,
1463 },
1464 );
1465 }
1466
1467 Self::prune_closed_mqc_heads(ingress_channels, &mut mqc_heads);
1468
1469 if messages.is_empty() {
1470 Self::check_hrmp_mcq_heads(ingress_channels, &mut mqc_heads);
1471 let last_processed_msg =
1472 InboundMessageId { sent_at: relay_parent_number, reverse_idx: 0 };
1473
1474 LastProcessedHrmpMessage::<T>::put(last_processed_msg);
1475 HrmpWatermark::<T>::put(relay_parent_number);
1476 LastHrmpMqcHeads::<T>::put(&mqc_heads); return T::DbWeight::get().reads_writes(1, 2);
1479 }
1480
1481 let mut prev_msg_metadata = None;
1482 let mut last_processed_block = HrmpWatermark::<T>::get();
1483 let mut last_processed_msg = InboundMessageId { sent_at: 0, reverse_idx: 0 };
1484 for (sender, msg) in messages {
1485 Self::check_hrmp_message_metadata(
1486 ingress_channels,
1487 &mut prev_msg_metadata,
1488 (msg.sent_at, *sender),
1489 );
1490 mqc_heads.entry(*sender).or_default().extend_hrmp(msg);
1491
1492 if msg.sent_at > last_processed_msg.sent_at && last_processed_msg.sent_at > 0 {
1493 last_processed_block = last_processed_msg.sent_at;
1494 }
1495 last_processed_msg.sent_at = msg.sent_at;
1496 }
1497
1498 LastHrmpMqcHeads::<T>::put(&mqc_heads);
1499
1500 for (sender, msg) in hashed_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_with_hashed_msg(msg);
1507
1508 if msg.sent_at == last_processed_msg.sent_at {
1509 last_processed_msg.reverse_idx += 1;
1510 }
1511 }
1512 if last_processed_msg.sent_at > 0 && last_processed_msg.reverse_idx == 0 {
1513 last_processed_block = last_processed_msg.sent_at;
1514 }
1515 LastProcessedHrmpMessage::<T>::put(&last_processed_msg);
1516 Self::check_hrmp_mcq_heads(ingress_channels, &mut mqc_heads);
1517
1518 let max_weight =
1519 <ReservedXcmpWeightOverride<T>>::get().unwrap_or_else(T::ReservedXcmpWeight::get);
1520 let weight_used = T::XcmpMessageHandler::handle_xcmp_messages(
1521 horizontal_messages.flat_msgs_iter(),
1522 max_weight,
1523 );
1524
1525 HrmpWatermark::<T>::put(last_processed_block);
1527
1528 weight_used.saturating_add(T::DbWeight::get().reads_writes(2, 3))
1529 }
1530
1531 fn prune_closed_mqc_heads(
1533 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1534 mqc_heads: &mut BTreeMap<ParaId, MessageQueueChain>,
1535 ) {
1536 mqc_heads.retain(|para, _| {
1538 ingress_channels
1539 .binary_search_by_key(para, |&(channel_sender, _)| channel_sender)
1540 .is_ok()
1541 });
1542 }
1543
1544 fn maybe_drop_included_ancestors(
1546 relay_state_proof: &RelayChainStateProof,
1547 capacity: consensus_hook::UnincludedSegmentCapacity,
1548 ) -> Weight {
1549 let mut weight_used = Weight::zero();
1550 let para_head =
1552 relay_state_proof.read_included_para_head().ok().map(|h| T::Hashing::hash(&h.0));
1553
1554 let unincluded_segment_len = <UnincludedSegment<T>>::decode_len().unwrap_or(0);
1555 weight_used += T::DbWeight::get().reads(1);
1556
1557 let included_head = match (para_head, capacity.is_expecting_included_parent()) {
1559 (Some(h), true) => {
1560 assert_eq!(
1561 h,
1562 frame_system::Pallet::<T>::parent_hash(),
1563 "expected parent to be included"
1564 );
1565
1566 h
1567 },
1568 (Some(h), false) => h,
1569 (None, true) => {
1570 frame_system::Pallet::<T>::parent_hash()
1573 },
1574 (None, false) => panic!("included head not present in relay storage proof"),
1575 };
1576
1577 let new_len = {
1578 let para_head_hash = included_head;
1579 let dropped: Vec<Ancestor<T::Hash>> = <UnincludedSegment<T>>::mutate(|chain| {
1580 let idx = chain
1583 .iter()
1584 .position(|block| {
1585 let head_hash = block
1586 .para_head_hash()
1587 .expect("para head hash is updated during block initialization; qed");
1588 head_hash == ¶_head_hash
1589 })
1590 .map_or(0, |idx| idx + 1); chain.drain(..idx).collect()
1593 });
1594 weight_used += T::DbWeight::get().reads_writes(1, 1);
1595
1596 let new_len = unincluded_segment_len - dropped.len();
1597 if !dropped.is_empty() {
1598 <AggregatedUnincludedSegment<T>>::mutate(|agg| {
1599 let agg = agg.as_mut().expect(
1600 "dropped part of the segment wasn't empty, hence value exists; qed",
1601 );
1602 for block in dropped {
1603 agg.subtract(&block);
1604 }
1605 });
1606 weight_used += T::DbWeight::get().reads_writes(1, 1);
1607 }
1608
1609 new_len as u32
1610 };
1611
1612 assert!(
1617 new_len < capacity.get(),
1618 "No space left for the block in the unincluded segment: new_len({new_len}) < capacity({})",
1619 capacity.get()
1620 );
1621 weight_used
1622 }
1623
1624 fn adjust_egress_bandwidth_limits() {
1629 let Some(unincluded_segment) = AggregatedUnincludedSegment::<T>::get() else { return };
1630
1631 <RelevantMessagingState<T>>::mutate(|messaging_state| {
1632 let Some(messaging_state) = messaging_state else { return };
1633
1634 let used_bandwidth = unincluded_segment.used_bandwidth();
1635
1636 let channels = &mut messaging_state.egress_channels;
1637 for (para_id, used) in used_bandwidth.hrmp_outgoing.iter() {
1638 let Ok(i) = channels.binary_search_by_key(para_id, |item| item.0) else {
1639 continue; };
1641
1642 let c = &mut channels[i].1;
1643
1644 c.total_size = (c.total_size + used.total_bytes).min(c.max_total_size);
1645 c.msg_count = (c.msg_count + used.msg_count).min(c.max_capacity);
1646 }
1647
1648 let upward_capacity = &mut messaging_state.relay_dispatch_queue_remaining_capacity;
1649 upward_capacity.remaining_count =
1650 upward_capacity.remaining_count.saturating_sub(used_bandwidth.ump_msg_count);
1651 upward_capacity.remaining_size =
1652 upward_capacity.remaining_size.saturating_sub(used_bandwidth.ump_total_bytes);
1653 });
1654 }
1655
1656 fn notify_polkadot_of_pending_upgrade(code: &[u8]) {
1660 NewValidationCode::<T>::put(code);
1661 <DidSetValidationCode<T>>::put(true);
1662 }
1663
1664 pub fn max_code_size() -> Option<u32> {
1668 <HostConfiguration<T>>::get().map(|cfg| cfg.max_code_size)
1669 }
1670
1671 pub fn schedule_code_upgrade(validation_function: Vec<u8>) -> DispatchResult {
1673 ensure!(<ValidationData<T>>::exists(), Error::<T>::ValidationDataNotAvailable);
1677 ensure!(<UpgradeRestrictionSignal<T>>::get().is_none(), Error::<T>::ProhibitedByPolkadot);
1678
1679 ensure!(!<PendingValidationCode<T>>::exists(), Error::<T>::OverlappingUpgrades);
1680 let cfg = HostConfiguration::<T>::get().ok_or(Error::<T>::HostConfigurationNotAvailable)?;
1681 ensure!(validation_function.len() <= cfg.max_code_size as usize, Error::<T>::TooBig);
1682
1683 Self::notify_polkadot_of_pending_upgrade(&validation_function);
1691 <PendingValidationCode<T>>::put(validation_function);
1692 Self::deposit_event(Event::ValidationFunctionStored);
1693
1694 Ok(())
1695 }
1696
1697 pub fn collect_collation_info(header: &HeaderFor<T>) -> CollationInfo {
1705 CollationInfo {
1706 hrmp_watermark: HrmpWatermark::<T>::get(),
1707 horizontal_messages: HrmpOutboundMessages::<T>::get(),
1708 upward_messages: UpwardMessages::<T>::get(),
1709 processed_downward_messages: ProcessedDownwardMessages::<T>::get(),
1710 new_validation_code: NewValidationCode::<T>::get().map(Into::into),
1711 head_data: CustomValidationHeadData::<T>::get()
1714 .map_or_else(|| header.encode(), |v| v)
1715 .into(),
1716 }
1717 }
1718
1719 pub fn set_custom_validation_head_data(head_data: Vec<u8>) {
1732 CustomValidationHeadData::<T>::put(head_data);
1733 }
1734
1735 fn send_ump_signals(core_info: Option<CoreInfo>) {
1737 let mut ump_signals = PendingUpwardSignals::<T>::take();
1738
1739 if let Some(core_info) = core_info {
1740 ump_signals.push(
1741 UMPSignal::SelectCore(core_info.selector, core_info.claim_queue_offset).encode(),
1742 );
1743 }
1744
1745 if let Some(approved_peer) = PendingApprovedPeer::<T>::take() {
1746 ump_signals.push(UMPSignal::ApprovedPeer(approved_peer).encode());
1747 }
1748
1749 if !ump_signals.is_empty() {
1750 UpwardMessages::<T>::append(UMP_SEPARATOR);
1751 ump_signals.into_iter().for_each(|s| UpwardMessages::<T>::append(s));
1752 }
1753 }
1754
1755 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
1760 pub fn open_outbound_hrmp_channel_for_benchmarks_or_tests(target_parachain: ParaId) {
1761 RelevantMessagingState::<T>::put(MessagingStateSnapshot {
1762 dmq_mqc_head: Default::default(),
1763 relay_dispatch_queue_remaining_capacity: Default::default(),
1764 ingress_channels: Default::default(),
1765 egress_channels: vec![(
1766 target_parachain,
1767 cumulus_primitives_core::AbridgedHrmpChannel {
1768 max_capacity: 10,
1769 max_total_size: 10_000_000_u32,
1770 max_message_size: 10_000_000_u32,
1771 msg_count: 5,
1772 total_size: 5_000_000_u32,
1773 mqc_head: None,
1774 },
1775 )],
1776 })
1777 }
1778
1779 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
1784 pub fn open_custom_outbound_hrmp_channel_for_benchmarks_or_tests(
1785 target_parachain: ParaId,
1786 channel: cumulus_primitives_core::AbridgedHrmpChannel,
1787 ) {
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![(target_parachain, channel)],
1793 })
1794 }
1795
1796 #[cfg(feature = "runtime-benchmarks")]
1798 pub fn initialize_for_set_code_benchmark(max_code_size: u32) {
1799 let vfp = PersistedValidationData {
1801 parent_head: polkadot_parachain_primitives::primitives::HeadData(Default::default()),
1802 relay_parent_number: 1,
1803 relay_parent_storage_root: Default::default(),
1804 max_pov_size: 1_000,
1805 };
1806 <ValidationData<T>>::put(&vfp);
1807
1808 let host_config = AbridgedHostConfiguration {
1810 max_code_size,
1811 max_head_data_size: 32 * 1024,
1812 max_upward_queue_count: 8,
1813 max_upward_queue_size: 1024 * 1024,
1814 max_upward_message_size: 4 * 1024,
1815 max_upward_message_num_per_candidate: 2,
1816 hrmp_max_message_num_per_candidate: 2,
1817 validation_upgrade_cooldown: 2,
1818 validation_upgrade_delay: 2,
1819 async_backing_params: relay_chain::AsyncBackingParams {
1820 allowed_ancestry_len: 0,
1821 max_candidate_depth: 0,
1822 },
1823 };
1824 <HostConfiguration<T>>::put(host_config);
1825 }
1826}
1827
1828pub struct ParachainSetCode<T>(core::marker::PhantomData<T>);
1830impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
1831 fn set_code(code: Vec<u8>) -> DispatchResult {
1832 Pallet::<T>::schedule_code_upgrade(code)
1833 }
1834}
1835
1836impl<T: Config> Pallet<T> {
1837 pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
1843 let message_len = message.len();
1844 if let Some(cfg) = HostConfiguration::<T>::get() {
1857 if message_len > cfg.max_upward_message_size as usize {
1858 return Err(MessageSendError::TooBig);
1859 }
1860 let threshold =
1861 cfg.max_upward_queue_size.saturating_div(ump_constants::THRESHOLD_FACTOR);
1862 <PendingUpwardMessages<T>>::append(message.clone());
1865 let pending_messages = PendingUpwardMessages::<T>::get();
1866 let total_size: usize = pending_messages.iter().map(UpwardMessage::len).sum();
1867 if total_size > threshold as usize {
1868 Self::increase_fee_factor((), message_len as u128);
1870 }
1871 } else {
1872 <PendingUpwardMessages<T>>::append(message.clone());
1882 };
1883
1884 let hash = sp_io::hashing::blake2_256(&message);
1887 Self::deposit_event(Event::UpwardMessageSent { message_hash: Some(hash) });
1888 Ok((0, hash))
1889 }
1890
1891 pub fn last_relay_block_number() -> RelayChainBlockNumber {
1894 LastRelayChainBlockNumber::<T>::get()
1895 }
1896}
1897
1898impl<T: Config> UpwardMessageSender for Pallet<T> {
1899 fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
1900 Self::send_upward_message(message)
1901 }
1902
1903 fn can_send_upward_message(message: &UpwardMessage) -> Result<(), MessageSendError> {
1904 let max_upward_message_size = HostConfiguration::<T>::get()
1905 .map(|cfg| cfg.max_upward_message_size)
1906 .ok_or(MessageSendError::Other)?;
1907 if message.len() > max_upward_message_size as usize {
1908 Err(MessageSendError::TooBig)
1909 } else {
1910 Ok(())
1911 }
1912 }
1913
1914 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
1915 fn ensure_successful_delivery() {
1916 const MAX_UPWARD_MESSAGE_SIZE: u32 = 65_531 * 3;
1917 const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
1918 HostConfiguration::<T>::mutate(|cfg| match cfg {
1919 Some(cfg) => cfg.max_upward_message_size = MAX_UPWARD_MESSAGE_SIZE,
1920 None => {
1921 *cfg = Some(AbridgedHostConfiguration {
1922 max_code_size: MAX_CODE_SIZE,
1923 max_head_data_size: 32 * 1024,
1924 max_upward_queue_count: 8,
1925 max_upward_queue_size: 1024 * 1024,
1926 max_upward_message_size: MAX_UPWARD_MESSAGE_SIZE,
1927 max_upward_message_num_per_candidate: 2,
1928 hrmp_max_message_num_per_candidate: 2,
1929 validation_upgrade_cooldown: 2,
1930 validation_upgrade_delay: 2,
1931 async_backing_params: relay_chain::AsyncBackingParams {
1932 allowed_ancestry_len: 0,
1933 max_candidate_depth: 0,
1934 },
1935 })
1936 },
1937 })
1938 }
1939}
1940
1941impl<T: Config> InspectMessageQueues for Pallet<T> {
1942 fn clear_messages() {
1943 PendingUpwardMessages::<T>::kill();
1944 }
1945
1946 fn get_messages() -> Vec<(VersionedLocation, Vec<VersionedXcm<()>>)> {
1947 use xcm::prelude::*;
1948
1949 let messages: Vec<VersionedXcm<()>> = PendingUpwardMessages::<T>::get()
1950 .iter()
1951 .map(|encoded_message| {
1952 VersionedXcm::<()>::decode_all_with_mem_and_depth_limit(&mut &encoded_message[..])
1953 .unwrap()
1954 })
1955 .collect();
1956
1957 if messages.is_empty() {
1958 vec![]
1959 } else {
1960 vec![(VersionedLocation::from(Location::parent()), messages)]
1961 }
1962 }
1963}
1964
1965#[cfg(feature = "runtime-benchmarks")]
1966impl<T: Config> polkadot_runtime_parachains::EnsureForParachain for Pallet<T> {
1967 fn ensure(para_id: ParaId) {
1968 if let ChannelStatus::Closed = Self::get_channel_status(para_id) {
1969 Self::open_outbound_hrmp_channel_for_benchmarks_or_tests(para_id)
1970 }
1971 }
1972}
1973
1974pub trait OnSystemEvent {
1982 fn on_validation_data(data: &PersistedValidationData);
1984 fn on_validation_code_applied();
1987 fn on_relay_state_proof(
1989 relay_state_proof: &relay_state_snapshot::RelayChainStateProof,
1990 ) -> Weight;
1991}
1992
1993#[impl_trait_for_tuples::impl_for_tuples(30)]
1994impl OnSystemEvent for Tuple {
1995 fn on_validation_data(data: &PersistedValidationData) {
1996 for_tuples!( #( Tuple::on_validation_data(data); )* );
1997 }
1998
1999 fn on_validation_code_applied() {
2000 for_tuples!( #( Tuple::on_validation_code_applied(); )* );
2001 }
2002
2003 fn on_relay_state_proof(
2004 relay_state_proof: &relay_state_snapshot::RelayChainStateProof,
2005 ) -> Weight {
2006 let mut weight = Weight::zero();
2007 for_tuples!( #( weight = weight.saturating_add(Tuple::on_relay_state_proof(relay_state_proof)); )* );
2008 weight
2009 }
2010}
2011
2012#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Default, Debug)]
2014pub struct RelayChainState {
2015 pub number: relay_chain::BlockNumber,
2017 pub state_root: relay_chain::Hash,
2019}
2020
2021pub trait RelaychainStateProvider {
2025 fn current_relay_chain_state() -> RelayChainState;
2029
2030 #[cfg(feature = "runtime-benchmarks")]
2035 fn set_current_relay_chain_state(_state: RelayChainState) {}
2036}
2037
2038pub struct RelaychainDataProvider<T>(core::marker::PhantomData<T>);
2054
2055impl<T: Config> BlockNumberProvider for RelaychainDataProvider<T> {
2056 type BlockNumber = relay_chain::BlockNumber;
2057
2058 fn current_block_number() -> relay_chain::BlockNumber {
2059 ValidationData::<T>::get()
2060 .map(|d| d.relay_parent_number)
2061 .unwrap_or_else(|| Pallet::<T>::last_relay_block_number())
2062 }
2063
2064 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
2065 fn set_block_number(block: Self::BlockNumber) {
2066 let mut validation_data = ValidationData::<T>::get().unwrap_or_else(||
2067 PersistedValidationData {
2069 parent_head: vec![].into(),
2070 relay_parent_number: Default::default(),
2071 max_pov_size: Default::default(),
2072 relay_parent_storage_root: Default::default(),
2073 });
2074 validation_data.relay_parent_number = block;
2075 ValidationData::<T>::put(validation_data)
2076 }
2077}
2078
2079impl<T: Config> RelaychainStateProvider for RelaychainDataProvider<T> {
2080 fn current_relay_chain_state() -> RelayChainState {
2081 ValidationData::<T>::get()
2082 .map(|d| RelayChainState {
2083 number: d.relay_parent_number,
2084 state_root: d.relay_parent_storage_root,
2085 })
2086 .unwrap_or_default()
2087 }
2088
2089 #[cfg(feature = "runtime-benchmarks")]
2090 fn set_current_relay_chain_state(state: RelayChainState) {
2091 let mut validation_data = ValidationData::<T>::get().unwrap_or_else(||
2092 PersistedValidationData {
2094 parent_head: vec![].into(),
2095 relay_parent_number: Default::default(),
2096 max_pov_size: Default::default(),
2097 relay_parent_storage_root: Default::default(),
2098 });
2099 validation_data.relay_parent_number = state.number;
2100 validation_data.relay_parent_storage_root = state.state_root;
2101 ValidationData::<T>::put(validation_data)
2102 }
2103}