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, DecodeLimit, 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, MAX_XCM_DECODE_DEPTH};
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
206#[frame_support::pallet]
207pub mod pallet {
208 use super::*;
209 use codec::Compact;
210 use cumulus_primitives_core::CoreInfoExistsAtMaxOnce;
211 use frame_support::pallet_prelude::{ValueQuery, *};
212 use frame_system::pallet_prelude::*;
213
214 #[pallet::pallet]
215 #[pallet::storage_version(migration::STORAGE_VERSION)]
216 #[pallet::without_storage_info]
217 pub struct Pallet<T>(_);
218
219 #[pallet::config]
220 pub trait Config: frame_system::Config<OnSetCode = ParachainSetCode<Self>> {
221 #[allow(deprecated)]
223 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
224
225 type OnSystemEvent: OnSystemEvent;
227
228 #[pallet::constant]
230 type SelfParaId: Get<ParaId>;
231
232 type OutboundXcmpMessageSource: XcmpMessageSource;
234
235 type DmpQueue: HandleMessage;
240
241 type ReservedDmpWeight: Get<Weight>;
243
244 type XcmpMessageHandler: XcmpMessageHandler;
248
249 type ReservedXcmpWeight: Get<Weight>;
251
252 type CheckAssociatedRelayNumber: CheckAssociatedRelayNumber;
254
255 type WeightInfo: WeightInfo;
257
258 type ConsensusHook: ConsensusHook;
269
270 type RelayParentOffset: Get<u32>;
285
286 type SchedulingSignatureVerifier: cumulus_primitives_core::VerifySchedulingSignature;
314 }
315
316 #[pallet::hooks]
317 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
318 fn on_finalize(_: BlockNumberFor<T>) {
323 <DidSetValidationCode<T>>::kill();
324 <UpgradeRestrictionSignal<T>>::kill();
325 let relay_upgrade_go_ahead = <UpgradeGoAhead<T>>::take();
326
327 let vfp = <ValidationData<T>>::get().expect(
328 r"Missing required set_validation_data inherent. This inherent must be
329 present in every block. This error typically occurs when the set_validation_data
330 execution failed and was rejected by the block builder. Check earlier log entries
331 for the specific cause of the failure.",
332 );
333
334 LastRelayChainBlockNumber::<T>::put(vfp.relay_parent_number);
335
336 let host_config = match HostConfiguration::<T>::get() {
337 Some(ok) => ok,
338 None => {
339 debug_assert!(
340 false,
341 "host configuration is promised to set until `on_finalize`; qed",
342 );
343 return;
344 },
345 };
346
347 let total_bandwidth_out = match RelevantMessagingState::<T>::get() {
351 Some(s) => OutboundBandwidthLimits::from_relay_chain_state(&s),
352 None => {
353 debug_assert!(
354 false,
355 "relevant messaging state is promised to be set until `on_finalize`; \
356 qed",
357 );
358 return;
359 },
360 };
361
362 Self::adjust_egress_bandwidth_limits();
365
366 let current_core_selector =
367 CumulusDigestItem::find_core_info(&frame_system::Pallet::<T>::digest())
368 .map_or(0, |ci| ci.selector.0);
369
370 let current_bundle_index =
371 CumulusDigestItem::find_block_bundle_info(&frame_system::Pallet::<T>::digest())
372 .map_or(0, |bi| bi.index);
373
374 let mut pov_tracker = PoVMessagesTracker::<T>::get()
375 .filter(|tracker| {
376 tracker.relay_storage_root_or_hash == vfp.relay_parent_storage_root &&
378 tracker.core_selector == current_core_selector &&
380 current_bundle_index > tracker.bundle_index
382 })
383 .unwrap_or_default();
384
385 pov_tracker.bundle_index = current_bundle_index;
386 pov_tracker.core_selector = current_core_selector;
387 pov_tracker.relay_storage_root_or_hash = vfp.relay_parent_storage_root;
388
389 let (ump_msg_count, ump_total_bytes) = <PendingUpwardMessages<T>>::mutate(|up| {
390 let (available_capacity, available_size) = match RelevantMessagingState::<T>::get()
391 {
392 Some(limits) => (
393 limits.relay_dispatch_queue_remaining_capacity.remaining_count,
394 limits.relay_dispatch_queue_remaining_capacity.remaining_size,
395 ),
396 None => {
397 debug_assert!(
398 false,
399 "relevant messaging state is promised to be set until `on_finalize`; \
400 qed",
401 );
402 return (0, 0);
403 },
404 };
405
406 let available_capacity = cmp::min(
407 available_capacity,
408 host_config
409 .max_upward_message_num_per_candidate
410 .saturating_sub(pov_tracker.ump_msg_count),
411 );
412
413 let (num, total_size) = up
416 .iter()
417 .scan((0u32, 0u32), |state, msg| {
418 let (cap_used, size_used) = *state;
419 let new_cap = cap_used.saturating_add(1);
420 let new_size = size_used.saturating_add(msg.len() as u32);
421 match available_capacity
422 .checked_sub(new_cap)
423 .and(available_size.checked_sub(new_size))
424 {
425 Some(_) => {
426 *state = (new_cap, new_size);
427 Some(*state)
428 },
429 _ => None,
430 }
431 })
432 .last()
433 .unwrap_or_default();
434
435 UpwardMessages::<T>::put(&up[..num as usize]);
438 *up = up.split_off(num as usize);
439
440 pov_tracker.ump_msg_count = pov_tracker.ump_msg_count.saturating_add(num);
441
442 let digest = frame_system::Pallet::<T>::digest();
443
444 let core_info = CumulusDigestItem::find_core_info(&digest);
445 PreviousCoreCount::<T>::put(
446 core_info.as_ref().map_or(Compact(1u16), |ci| ci.number_of_cores),
447 );
448
449 if CumulusDigestItem::is_last_block_in_core(&digest).unwrap_or(true) {
452 Self::send_ump_signals(core_info);
453 }
454
455 let threshold = host_config
459 .max_upward_queue_size
460 .saturating_div(ump_constants::THRESHOLD_FACTOR);
461 let remaining_total_size: usize = up.iter().map(UpwardMessage::len).sum();
462 if remaining_total_size <= threshold as usize {
463 Self::decrease_fee_factor(());
464 }
465
466 (num, total_size)
467 });
468
469 let maximum_channels = host_config
479 .hrmp_max_message_num_per_candidate
480 .min(<AnnouncedHrmpMessagesPerCandidate<T>>::take())
481 as usize;
482
483 let maximum_channels =
484 maximum_channels.saturating_sub(pov_tracker.hrmp_outbound_count as usize);
485
486 let outbound_messages = T::OutboundXcmpMessageSource::take_outbound_messages(
490 maximum_channels,
491 &pov_tracker.hrmp_outbound_recipients,
492 )
493 .into_iter()
494 .map(|(recipient, data)| OutboundHrmpMessage { recipient, data })
495 .collect::<Vec<_>>();
496
497 pov_tracker
498 .hrmp_outbound_recipients
499 .extend(outbound_messages.iter().map(|m| m.recipient));
500 pov_tracker.hrmp_outbound_count =
501 pov_tracker.hrmp_outbound_count.saturating_add(outbound_messages.len() as u32);
502 PoVMessagesTracker::<T>::put(pov_tracker);
503
504 {
507 let hrmp_outgoing = outbound_messages
508 .iter()
509 .map(|msg| {
510 (
511 msg.recipient,
512 HrmpChannelUpdate { msg_count: 1, total_bytes: msg.data.len() as u32 },
513 )
514 })
515 .collect();
516 let used_bandwidth =
517 UsedBandwidth { ump_msg_count, ump_total_bytes, hrmp_outgoing };
518
519 let mut aggregated_segment =
520 AggregatedUnincludedSegment::<T>::get().unwrap_or_default();
521 let consumed_go_ahead_signal =
522 if aggregated_segment.consumed_go_ahead_signal().is_some() {
523 None
526 } else {
527 relay_upgrade_go_ahead
528 };
529 let ancestor = Ancestor::new_unchecked(used_bandwidth, consumed_go_ahead_signal);
531
532 let watermark = HrmpWatermark::<T>::get();
533 let watermark_update = HrmpWatermarkUpdate::new(watermark, vfp.relay_parent_number);
534
535 aggregated_segment
536 .append(&ancestor, watermark_update, &total_bandwidth_out)
537 .expect("unincluded segment limits exceeded");
538 AggregatedUnincludedSegment::<T>::put(aggregated_segment);
539 UnincludedSegment::<T>::append(ancestor);
541 }
542
543 HrmpOutboundMessages::<T>::put(outbound_messages);
544 }
545
546 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
547 let mut weight = Weight::zero();
548
549 if !<DidSetValidationCode<T>>::get() {
553 NewValidationCode::<T>::kill();
557 weight += T::DbWeight::get().writes(1);
558 }
559
560 {
562 <UnincludedSegment<T>>::mutate(|chain| {
563 if let Some(ancestor) = chain.last_mut() {
564 let parent = frame_system::Pallet::<T>::parent_hash();
565 ancestor.replace_para_head_hash(parent);
568 }
569 });
570 weight += T::DbWeight::get().reads_writes(1, 1);
571
572 weight += T::DbWeight::get().reads_writes(3, 2);
574 }
575
576 BlockWeightMode::<T>::kill();
577
578 ValidationData::<T>::kill();
580 ProcessedDownwardMessages::<T>::kill();
584 UpwardMessages::<T>::kill();
585 HrmpOutboundMessages::<T>::kill();
586 CustomValidationHeadData::<T>::kill();
587 HrmpWatermark::<T>::get();
589 weight += T::DbWeight::get().reads_writes(1, 5);
590
591 weight += T::DbWeight::get().reads_writes(1, 1);
610 let hrmp_max_message_num_per_candidate = HostConfiguration::<T>::get()
611 .map(|cfg| cfg.hrmp_max_message_num_per_candidate)
612 .unwrap_or(0);
613 <AnnouncedHrmpMessagesPerCandidate<T>>::put(hrmp_max_message_num_per_candidate);
614
615 weight += T::DbWeight::get().reads_writes(
617 3 + hrmp_max_message_num_per_candidate as u64,
618 4 + hrmp_max_message_num_per_candidate as u64,
619 );
620
621 weight += T::DbWeight::get().reads_writes(1, 1);
623
624 weight += T::DbWeight::get().reads_writes(6, 3);
626
627 weight += T::DbWeight::get().reads(1);
629
630 match CumulusDigestItem::core_info_exists_at_max_once(
637 &frame_system::Pallet::<T>::digest(),
638 ) {
639 CoreInfoExistsAtMaxOnce::Once(core_info) => {
640 let mut max_allowed_offset = Self::max_claim_queue_offset();
641 if !T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED {
642 max_allowed_offset = max_allowed_offset
643 .saturating_add(T::RelayParentOffset::get().saturated_into::<u8>())
644 }
645 assert!(
646 core_info.claim_queue_offset.0 <= max_allowed_offset,
647 "claim_queue_offset {} exceeds maximum allowed {}",
648 core_info.claim_queue_offset.0,
649 max_allowed_offset,
650 );
651 },
652 CoreInfoExistsAtMaxOnce::NotFound => {},
653 CoreInfoExistsAtMaxOnce::MoreThanOnce => {
654 panic!("`CumulusDigestItem::CoreInfo` must exist at max once.");
655 },
656 }
657
658 weight
659 }
660 }
661
662 #[pallet::call]
663 impl<T: Config> Pallet<T> {
664 #[pallet::call_index(0)]
674 #[pallet::weight((0, DispatchClass::Mandatory))]
675 pub fn set_validation_data(
678 origin: OriginFor<T>,
679 data: BasicParachainInherentData,
680 inbound_messages_data: InboundMessagesData,
681 ) -> DispatchResult {
682 ensure_none(origin)?;
683 assert!(
684 !<ValidationData<T>>::exists(),
685 "ValidationData must be updated only once in a block",
686 );
687
688 let mut total_weight = Weight::zero();
690
691 let BasicParachainInherentData {
698 validation_data: vfp,
699 relay_chain_state,
700 relay_parent_descendants,
701 collator_peer_id,
702 } = data;
703
704 T::CheckAssociatedRelayNumber::check_associated_relay_number(
706 vfp.relay_parent_number,
707 LastRelayChainBlockNumber::<T>::get(),
708 );
709
710 let relay_state_proof = RelayChainStateProof::new(
711 T::SelfParaId::get(),
712 vfp.relay_parent_storage_root,
713 relay_chain_state.clone(),
714 )
715 .expect("Invalid relay chain state proof");
716
717 let expected_rp_descendants_num = T::RelayParentOffset::get();
722 let v3_enabled = T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED;
723
724 if expected_rp_descendants_num > 0 && !v3_enabled {
725 if let Err(err) = descendant_validation::verify_relay_parent_descendants(
726 &relay_state_proof,
727 relay_parent_descendants,
728 vfp.relay_parent_storage_root,
729 expected_rp_descendants_num,
730 ) {
731 panic!(
732 "Unable to verify provided relay parent descendants. \
733 expected_rp_descendants_num: {expected_rp_descendants_num} \
734 error: {err:?}"
735 );
736 };
737 }
738
739 let (consensus_hook_weight, capacity) =
741 T::ConsensusHook::on_state_proof(&relay_state_proof);
742 total_weight += consensus_hook_weight;
743 total_weight += Self::maybe_drop_included_ancestors(&relay_state_proof, capacity);
744 frame_system::Pallet::<T>::deposit_log(
748 cumulus_primitives_core::rpsr_digest::relay_parent_storage_root_item(
749 vfp.relay_parent_storage_root,
750 vfp.relay_parent_number,
751 ),
752 );
753
754 let upgrade_go_ahead_signal = relay_state_proof
758 .read_upgrade_go_ahead_signal()
759 .expect("Invalid upgrade go ahead signal");
760
761 let upgrade_signal_in_segment = AggregatedUnincludedSegment::<T>::get()
762 .as_ref()
763 .and_then(SegmentTracker::consumed_go_ahead_signal);
764 if let Some(signal_in_segment) = upgrade_signal_in_segment.as_ref() {
765 assert_eq!(upgrade_go_ahead_signal, Some(*signal_in_segment));
768 }
769 match upgrade_go_ahead_signal {
770 Some(_signal) if upgrade_signal_in_segment.is_some() => {
771 },
773 Some(relay_chain::UpgradeGoAhead::GoAhead) => {
774 assert!(
775 <PendingValidationCode<T>>::exists(),
776 "No new validation function found in storage, GoAhead signal is not expected",
777 );
778 let validation_code = <PendingValidationCode<T>>::take();
779
780 frame_system::Pallet::<T>::update_code_in_storage(&validation_code);
781 <T::OnSystemEvent as OnSystemEvent>::on_validation_code_applied();
782 Self::deposit_event(Event::ValidationFunctionApplied {
783 relay_chain_block_num: vfp.relay_parent_number,
784 });
785 },
786 Some(relay_chain::UpgradeGoAhead::Abort) => {
787 <PendingValidationCode<T>>::kill();
788 Self::deposit_event(Event::ValidationFunctionDiscarded);
789 },
790 None => {},
791 }
792 <UpgradeRestrictionSignal<T>>::put(
793 relay_state_proof
794 .read_upgrade_restriction_signal()
795 .expect("Invalid upgrade restriction signal"),
796 );
797 <UpgradeGoAhead<T>>::put(upgrade_go_ahead_signal);
798
799 let host_config = relay_state_proof
800 .read_abridged_host_configuration()
801 .expect("Invalid host configuration in relay chain state proof");
802
803 let relevant_messaging_state = relay_state_proof
804 .read_messaging_state_snapshot(&host_config)
805 .expect("Invalid messaging state in relay chain state proof");
806
807 <ValidationData<T>>::put(&vfp);
808 <RelayStateProof<T>>::put(relay_chain_state);
809 <RelevantMessagingState<T>>::put(relevant_messaging_state.clone());
810 <HostConfiguration<T>>::put(host_config);
811
812 total_weight.saturating_accrue(
813 <T::OnSystemEvent as OnSystemEvent>::on_relay_state_proof(&relay_state_proof),
814 );
815
816 <T::OnSystemEvent as OnSystemEvent>::on_validation_data(&vfp);
817
818 match collator_peer_id {
819 Some(peer_id) => PendingApprovedPeer::<T>::put(peer_id),
820 None => PendingApprovedPeer::<T>::kill(),
821 }
822
823 total_weight.saturating_accrue(Self::enqueue_inbound_downward_messages(
824 relevant_messaging_state.dmq_mqc_head,
825 inbound_messages_data.downward_messages,
826 ));
827 total_weight.saturating_accrue(Self::enqueue_inbound_horizontal_messages(
828 &relevant_messaging_state.ingress_channels,
829 inbound_messages_data.horizontal_messages,
830 vfp.relay_parent_number,
831 ));
832
833 frame_system::Pallet::<T>::register_extra_weight_unchecked(
834 total_weight,
835 DispatchClass::Mandatory,
836 );
837
838 Ok(())
839 }
840
841 #[pallet::call_index(1)]
842 #[pallet::weight((1_000, DispatchClass::Operational))]
843 pub fn sudo_send_upward_message(
844 origin: OriginFor<T>,
845 message: UpwardMessage,
846 ) -> DispatchResult {
847 ensure_root(origin)?;
848 let _ = Self::send_upward_message(message);
849 Ok(())
850 }
851
852 }
855
856 #[pallet::event]
857 #[pallet::generate_deposit(pub(super) fn deposit_event)]
858 pub enum Event<T: Config> {
859 ValidationFunctionStored,
861 ValidationFunctionApplied { relay_chain_block_num: RelayChainBlockNumber },
863 ValidationFunctionDiscarded,
865 DownwardMessagesReceived { count: u32 },
867 DownwardMessagesProcessed { weight_used: Weight, dmq_head: relay_chain::Hash },
869 UpwardMessageSent { message_hash: Option<XcmHash> },
871 }
872
873 #[pallet::error]
874 pub enum Error<T> {
875 OverlappingUpgrades,
877 ProhibitedByPolkadot,
879 TooBig,
882 ValidationDataNotAvailable,
884 HostConfigurationNotAvailable,
886 NotScheduled,
888 }
889
890 #[pallet::storage]
897 #[pallet::whitelist_storage]
898 pub type BlockWeightMode<T: Config> =
899 StorageValue<_, block_weight::BlockWeightMode<T>, OptionQuery>;
900
901 #[pallet::storage]
905 #[pallet::whitelist_storage]
906 pub type PreviousCoreCount<T: Config> = StorageValue<_, Compact<u16>, OptionQuery>;
907
908 #[pallet::storage]
915 pub type UnincludedSegment<T: Config> = StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;
916
917 #[pallet::storage]
921 pub type AggregatedUnincludedSegment<T: Config> =
922 StorageValue<_, SegmentTracker<T::Hash>, OptionQuery>;
923
924 #[pallet::storage]
931 pub type PendingValidationCode<T: Config> = StorageValue<_, Vec<u8>, ValueQuery>;
932
933 #[pallet::storage]
939 pub type NewValidationCode<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
940
941 #[pallet::storage]
945 pub type ValidationData<T: Config> = StorageValue<_, PersistedValidationData>;
946
947 #[pallet::storage]
949 pub type DidSetValidationCode<T: Config> = StorageValue<_, bool, ValueQuery>;
950
951 #[pallet::storage]
955 pub type LastRelayChainBlockNumber<T: Config> =
956 StorageValue<_, RelayChainBlockNumber, ValueQuery>;
957
958 #[pallet::storage]
966 pub type UpgradeRestrictionSignal<T: Config> =
967 StorageValue<_, Option<relay_chain::UpgradeRestriction>, ValueQuery>;
968
969 #[pallet::storage]
975 pub type UpgradeGoAhead<T: Config> =
976 StorageValue<_, Option<relay_chain::UpgradeGoAhead>, ValueQuery>;
977
978 #[pallet::storage]
985 pub type RelayStateProof<T: Config> = StorageValue<_, sp_trie::StorageProof>;
986
987 #[pallet::storage]
995 pub type RelevantMessagingState<T: Config> = StorageValue<_, MessagingStateSnapshot>;
996
997 #[pallet::storage]
1004 #[pallet::disable_try_decode_storage]
1005 pub type HostConfiguration<T: Config> = StorageValue<_, AbridgedHostConfiguration>;
1006
1007 #[pallet::storage]
1012 pub type LastDmqMqcHead<T: Config> = StorageValue<_, MessageQueueChain, ValueQuery>;
1013
1014 #[pallet::storage]
1019 pub type LastHrmpMqcHeads<T: Config> =
1020 StorageValue<_, BTreeMap<ParaId, MessageQueueChain>, ValueQuery>;
1021
1022 #[pallet::storage]
1026 pub type ProcessedDownwardMessages<T: Config> = StorageValue<_, u32, ValueQuery>;
1027
1028 #[pallet::storage]
1032 pub type LastProcessedDownwardMessage<T: Config> = StorageValue<_, InboundMessageId>;
1033
1034 #[pallet::storage]
1036 pub type HrmpWatermark<T: Config> = StorageValue<_, relay_chain::BlockNumber, ValueQuery>;
1037
1038 #[pallet::storage]
1042 pub type LastProcessedHrmpMessage<T: Config> = StorageValue<_, InboundMessageId>;
1043
1044 #[pallet::storage]
1048 pub type HrmpOutboundMessages<T: Config> =
1049 StorageValue<_, Vec<OutboundHrmpMessage>, ValueQuery>;
1050
1051 #[pallet::storage]
1055 pub type UpwardMessages<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1056
1057 #[pallet::storage]
1059 pub type PendingUpwardMessages<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1060
1061 #[pallet::storage]
1065 pub type PendingUpwardSignals<T: Config> = StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
1066
1067 #[pallet::storage]
1069 pub type PendingApprovedPeer<T: Config> =
1070 StorageValue<_, relay_chain::ApprovedPeerId, OptionQuery>;
1071
1072 #[pallet::storage]
1074 pub type UpwardDeliveryFeeFactor<T: Config> =
1075 StorageValue<_, FixedU128, ValueQuery, GetMinFeeFactor<Pallet<T>>>;
1076
1077 #[pallet::storage]
1080 pub type AnnouncedHrmpMessagesPerCandidate<T: Config> = StorageValue<_, u32, ValueQuery>;
1081
1082 #[pallet::storage]
1085 pub type ReservedXcmpWeightOverride<T: Config> = StorageValue<_, Weight>;
1086
1087 #[pallet::storage]
1090 pub type ReservedDmpWeightOverride<T: Config> = StorageValue<_, Weight>;
1091
1092 #[pallet::storage]
1096 pub type CustomValidationHeadData<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
1097
1098 #[pallet::storage]
1102 pub type PoVMessagesTracker<T: Config> = StorageValue<_, PoVMessages, OptionQuery>;
1103
1104 #[pallet::inherent]
1105 impl<T: Config> ProvideInherent for Pallet<T> {
1106 type Call = Call<T>;
1107 type Error = sp_inherents::MakeFatalError<()>;
1108 const INHERENT_IDENTIFIER: InherentIdentifier =
1109 cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER;
1110
1111 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
1112 let data = match data
1113 .get_data::<ParachainInherentData>(&Self::INHERENT_IDENTIFIER)
1114 .ok()
1115 .flatten()
1116 {
1117 None => {
1118 let data = data
1123 .get_data::<v0::ParachainInherentData>(
1124 &cumulus_primitives_parachain_inherent::PARACHAIN_INHERENT_IDENTIFIER_V0,
1125 )
1126 .ok()
1127 .flatten()?;
1128 data.into()
1129 },
1130 Some(data) => data,
1131 };
1132
1133 Some(Self::do_create_inherent(data))
1134 }
1135
1136 fn is_inherent(call: &Self::Call) -> bool {
1137 matches!(call, Call::set_validation_data { .. })
1138 }
1139 }
1140
1141 #[pallet::genesis_config]
1142 #[derive(frame_support::DefaultNoBound)]
1143 pub struct GenesisConfig<T: Config> {
1144 #[serde(skip)]
1145 pub _config: core::marker::PhantomData<T>,
1146 }
1147
1148 #[pallet::genesis_build]
1149 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
1150 fn build(&self) {
1151 sp_io::storage::set(b":c", &[]);
1153 }
1154 }
1155}
1156
1157impl<T: Config> Pallet<T> {
1158 pub fn unincluded_segment_size_after(included_hash: T::Hash) -> u32 {
1166 let segment = UnincludedSegment::<T>::get();
1167 crate::unincluded_segment::size_after_included(included_hash, &segment)
1168 }
1169
1170 pub fn max_claim_queue_offset() -> u8 {
1175 if !T::SchedulingSignatureVerifier::V3_SCHEDULING_ENABLED {
1176 return 1;
1177 }
1178
1179 2
1180 }
1181}
1182
1183impl<T: Config> FeeTracker for Pallet<T> {
1184 type Id = ();
1185
1186 fn get_fee_factor(_id: Self::Id) -> FixedU128 {
1187 UpwardDeliveryFeeFactor::<T>::get()
1188 }
1189
1190 fn set_fee_factor(_id: Self::Id, val: FixedU128) {
1191 UpwardDeliveryFeeFactor::<T>::set(val);
1192 }
1193}
1194
1195impl<T: Config> ListChannelInfos for Pallet<T> {
1196 fn outgoing_channels() -> Vec<ParaId> {
1197 let Some(state) = RelevantMessagingState::<T>::get() else { return Vec::new() };
1198 state.egress_channels.into_iter().map(|(id, _)| id).collect()
1199 }
1200}
1201
1202impl<T: Config> GetChannelInfo for Pallet<T> {
1203 fn get_channel_status(id: ParaId) -> ChannelStatus {
1204 let channels = match RelevantMessagingState::<T>::get() {
1219 None => {
1220 log::warn!("calling `get_channel_status` with no RelevantMessagingState?!");
1221 return ChannelStatus::Closed;
1222 },
1223 Some(d) => d.egress_channels,
1224 };
1225 let index = match channels.binary_search_by_key(&id, |item| item.0) {
1232 Err(_) => return ChannelStatus::Closed,
1233 Ok(i) => i,
1234 };
1235 let meta = &channels[index].1;
1236 if meta.msg_count + 1 > meta.max_capacity {
1237 return ChannelStatus::Full;
1239 }
1240 let max_size_now = meta.max_total_size - meta.total_size;
1241 let max_size_ever = meta.max_message_size;
1242 ChannelStatus::Ready(max_size_now as usize, max_size_ever as usize)
1243 }
1244
1245 fn get_channel_info(id: ParaId) -> Option<ChannelInfo> {
1246 let channels = RelevantMessagingState::<T>::get()?.egress_channels;
1247 let index = channels.binary_search_by_key(&id, |item| item.0).ok()?;
1248 let info = ChannelInfo {
1249 max_capacity: channels[index].1.max_capacity,
1250 max_total_size: channels[index].1.max_total_size,
1251 max_message_size: channels[index].1.max_message_size,
1252 msg_count: channels[index].1.msg_count,
1253 total_size: channels[index].1.total_size,
1254 };
1255 Some(info)
1256 }
1257}
1258
1259impl<T: Config> Pallet<T> {
1260 fn messages_collection_size_limit() -> usize {
1270 let max_block_weight = <T as frame_system::Config>::BlockWeights::get().max_block;
1271 let max_block_pov = max_block_weight.proof_size();
1272
1273 let remaining_proof_size =
1274 frame_system::Pallet::<T>::remaining_block_weight().remaining().proof_size();
1275
1276 (max_block_pov / 6).min(remaining_proof_size).saturated_into()
1277 }
1278
1279 fn do_create_inherent(data: ParachainInherentData) -> Call<T> {
1285 let (data, mut downward_messages, mut horizontal_messages) =
1286 deconstruct_parachain_inherent_data(data);
1287 let last_relay_block_number = LastRelayChainBlockNumber::<T>::get();
1288
1289 let messages_collection_size_limit = Self::messages_collection_size_limit();
1290 let last_processed_msg = LastProcessedDownwardMessage::<T>::get()
1292 .unwrap_or(InboundMessageId { sent_at: last_relay_block_number, reverse_idx: 0 });
1293 downward_messages.drop_processed_messages(&last_processed_msg);
1294 let mut size_limit = messages_collection_size_limit;
1295 let downward_messages = downward_messages.into_abridged(&mut size_limit);
1296
1297 let last_processed_msg = LastProcessedHrmpMessage::<T>::get()
1299 .unwrap_or(InboundMessageId { sent_at: last_relay_block_number, reverse_idx: 0 });
1300 horizontal_messages.drop_processed_messages(&last_processed_msg);
1301 size_limit = size_limit.saturating_add(messages_collection_size_limit);
1302 let horizontal_messages = horizontal_messages.into_abridged(&mut size_limit);
1303
1304 let inbound_messages_data =
1305 InboundMessagesData::new(downward_messages, horizontal_messages);
1306
1307 Call::set_validation_data { data, inbound_messages_data }
1308 }
1309
1310 fn enqueue_inbound_downward_messages(
1320 expected_dmq_mqc_head: relay_chain::Hash,
1321 downward_messages: AbridgedInboundDownwardMessages,
1322 ) -> Weight {
1323 downward_messages.check_enough_messages_included_basic("DMQ");
1324
1325 let mut dmq_head = <LastDmqMqcHead<T>>::get();
1326
1327 let (messages, hashed_messages) = downward_messages.messages();
1328 let message_count = messages.len() as u32;
1329 let weight_used = T::WeightInfo::enqueue_inbound_downward_messages(message_count);
1330 if let Some(last_msg) = messages.last() {
1331 Self::deposit_event(Event::DownwardMessagesReceived { count: message_count });
1332
1333 for msg in messages {
1335 dmq_head.extend_downward(msg);
1336 }
1337 <LastDmqMqcHead<T>>::put(&dmq_head);
1338 Self::deposit_event(Event::DownwardMessagesProcessed {
1339 weight_used,
1340 dmq_head: dmq_head.head(),
1341 });
1342
1343 let mut last_processed_msg =
1344 InboundMessageId { sent_at: last_msg.sent_at, reverse_idx: 0 };
1345 for msg in hashed_messages {
1346 dmq_head.extend_with_hashed_msg(msg);
1347
1348 if msg.sent_at == last_processed_msg.sent_at {
1349 last_processed_msg.reverse_idx += 1;
1350 }
1351 }
1352 LastProcessedDownwardMessage::<T>::put(last_processed_msg);
1353
1354 T::DmpQueue::handle_messages(downward_messages.bounded_msgs_iter());
1355 }
1356
1357 assert_eq!(dmq_head.head(), expected_dmq_mqc_head, "DMQ head mismatch");
1363
1364 ProcessedDownwardMessages::<T>::put(message_count);
1365
1366 weight_used
1367 }
1368
1369 fn get_ingress_channel_or_panic(
1370 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1371 sender: ParaId,
1372 ) -> &cumulus_primitives_core::AbridgedHrmpChannel {
1373 let maybe_channel_idx = ingress_channels
1374 .binary_search_by_key(&sender, |&(channel_sender, _)| channel_sender)
1375 .ok();
1376 let maybe_channel = maybe_channel_idx
1377 .and_then(|channel_idx| ingress_channels.get(channel_idx))
1378 .map(|(_, channel)| channel);
1379 maybe_channel.unwrap_or_else(|| {
1380 panic!(
1381 "One of the messages submitted by the collator was sent from a sender ({}) \
1382 that doesn't have a channel opened to this parachain",
1383 <ParaId as Into<u32>>::into(sender)
1384 )
1385 })
1386 }
1387
1388 fn check_hrmp_mcq_heads(
1389 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1390 mqc_heads: &mut BTreeMap<ParaId, MessageQueueChain>,
1391 ) {
1392 for (sender, channel) in ingress_channels {
1400 let cur_head = mqc_heads.entry(*sender).or_default().head();
1401 let target_head = channel.mqc_head.unwrap_or_default();
1402 assert_eq!(cur_head, target_head, "HRMP head mismatch");
1403 }
1404 }
1405
1406 fn check_hrmp_message_metadata(
1411 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1412 maybe_prev_msg_metadata: &mut Option<(u32, ParaId)>,
1413 msg_metadata: (u32, ParaId),
1414 ) {
1415 if let Some(prev_msg) = maybe_prev_msg_metadata {
1417 assert!(&msg_metadata >= prev_msg, "[HRMP] Messages order violation");
1418 }
1419 *maybe_prev_msg_metadata = Some(msg_metadata);
1420
1421 Self::get_ingress_channel_or_panic(ingress_channels, msg_metadata.1);
1423 }
1424
1425 fn enqueue_inbound_horizontal_messages(
1436 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1437 horizontal_messages: AbridgedInboundHrmpMessages,
1438 relay_parent_number: relay_chain::BlockNumber,
1439 ) -> Weight {
1440 let mut mqc_heads = <LastHrmpMqcHeads<T>>::get();
1441 let (messages, hashed_messages) = horizontal_messages.messages();
1442
1443 let maybe_first_hashed_msg_sender = hashed_messages.first().map(|(sender, _msg)| *sender);
1445 if let Some(first_hashed_msg_sender) = maybe_first_hashed_msg_sender {
1446 let channel =
1447 Self::get_ingress_channel_or_panic(ingress_channels, first_hashed_msg_sender);
1448 horizontal_messages.check_enough_messages_included_advanced(
1449 "HRMP",
1450 AbridgedInboundMessagesSizeInfo {
1451 max_full_messages_size: Self::messages_collection_size_limit(),
1452 first_hashed_msg_max_size: channel.max_message_size as usize,
1453 },
1454 );
1455 }
1456
1457 Self::prune_closed_mqc_heads(ingress_channels, &mut mqc_heads);
1458
1459 if messages.is_empty() {
1460 Self::check_hrmp_mcq_heads(ingress_channels, &mut mqc_heads);
1461 let last_processed_msg =
1462 InboundMessageId { sent_at: relay_parent_number, reverse_idx: 0 };
1463
1464 LastProcessedHrmpMessage::<T>::put(last_processed_msg);
1465 HrmpWatermark::<T>::put(relay_parent_number);
1466 LastHrmpMqcHeads::<T>::put(&mqc_heads); return T::DbWeight::get().reads_writes(1, 2);
1469 }
1470
1471 let mut prev_msg_metadata = None;
1472 let mut last_processed_block = HrmpWatermark::<T>::get();
1473 let mut last_processed_msg = InboundMessageId { sent_at: 0, reverse_idx: 0 };
1474 for (sender, msg) in messages {
1475 Self::check_hrmp_message_metadata(
1476 ingress_channels,
1477 &mut prev_msg_metadata,
1478 (msg.sent_at, *sender),
1479 );
1480 mqc_heads.entry(*sender).or_default().extend_hrmp(msg);
1481
1482 if msg.sent_at > last_processed_msg.sent_at && last_processed_msg.sent_at > 0 {
1483 last_processed_block = last_processed_msg.sent_at;
1484 }
1485 last_processed_msg.sent_at = msg.sent_at;
1486 }
1487
1488 LastHrmpMqcHeads::<T>::put(&mqc_heads);
1489
1490 for (sender, msg) in hashed_messages {
1491 Self::check_hrmp_message_metadata(
1492 ingress_channels,
1493 &mut prev_msg_metadata,
1494 (msg.sent_at, *sender),
1495 );
1496 mqc_heads.entry(*sender).or_default().extend_with_hashed_msg(msg);
1497
1498 if msg.sent_at == last_processed_msg.sent_at {
1499 last_processed_msg.reverse_idx += 1;
1500 }
1501 }
1502 if last_processed_msg.sent_at > 0 && last_processed_msg.reverse_idx == 0 {
1503 last_processed_block = last_processed_msg.sent_at;
1504 }
1505 LastProcessedHrmpMessage::<T>::put(&last_processed_msg);
1506 Self::check_hrmp_mcq_heads(ingress_channels, &mut mqc_heads);
1507
1508 let max_weight =
1509 <ReservedXcmpWeightOverride<T>>::get().unwrap_or_else(T::ReservedXcmpWeight::get);
1510 let weight_used = T::XcmpMessageHandler::handle_xcmp_messages(
1511 horizontal_messages.flat_msgs_iter(),
1512 max_weight,
1513 );
1514
1515 HrmpWatermark::<T>::put(last_processed_block);
1517
1518 weight_used.saturating_add(T::DbWeight::get().reads_writes(2, 3))
1519 }
1520
1521 fn prune_closed_mqc_heads(
1523 ingress_channels: &[(ParaId, cumulus_primitives_core::AbridgedHrmpChannel)],
1524 mqc_heads: &mut BTreeMap<ParaId, MessageQueueChain>,
1525 ) {
1526 mqc_heads.retain(|para, _| {
1528 ingress_channels
1529 .binary_search_by_key(para, |&(channel_sender, _)| channel_sender)
1530 .is_ok()
1531 });
1532 }
1533
1534 fn maybe_drop_included_ancestors(
1536 relay_state_proof: &RelayChainStateProof,
1537 capacity: consensus_hook::UnincludedSegmentCapacity,
1538 ) -> Weight {
1539 let mut weight_used = Weight::zero();
1540 let para_head =
1542 relay_state_proof.read_included_para_head().ok().map(|h| T::Hashing::hash(&h.0));
1543
1544 let unincluded_segment_len = <UnincludedSegment<T>>::decode_len().unwrap_or(0);
1545 weight_used += T::DbWeight::get().reads(1);
1546
1547 let included_head = match (para_head, capacity.is_expecting_included_parent()) {
1549 (Some(h), true) => {
1550 assert_eq!(
1551 h,
1552 frame_system::Pallet::<T>::parent_hash(),
1553 "expected parent to be included"
1554 );
1555
1556 h
1557 },
1558 (Some(h), false) => h,
1559 (None, true) => {
1560 frame_system::Pallet::<T>::parent_hash()
1563 },
1564 (None, false) => panic!("included head not present in relay storage proof"),
1565 };
1566
1567 let new_len = {
1568 let para_head_hash = included_head;
1569 let dropped: Vec<Ancestor<T::Hash>> = <UnincludedSegment<T>>::mutate(|chain| {
1570 let idx = chain
1573 .iter()
1574 .position(|block| {
1575 let head_hash = block
1576 .para_head_hash()
1577 .expect("para head hash is updated during block initialization; qed");
1578 head_hash == ¶_head_hash
1579 })
1580 .map_or(0, |idx| idx + 1); chain.drain(..idx).collect()
1583 });
1584 weight_used += T::DbWeight::get().reads_writes(1, 1);
1585
1586 let new_len = unincluded_segment_len - dropped.len();
1587 if !dropped.is_empty() {
1588 <AggregatedUnincludedSegment<T>>::mutate(|agg| {
1589 let agg = agg.as_mut().expect(
1590 "dropped part of the segment wasn't empty, hence value exists; qed",
1591 );
1592 for block in dropped {
1593 agg.subtract(&block);
1594 }
1595 });
1596 weight_used += T::DbWeight::get().reads_writes(1, 1);
1597 }
1598
1599 new_len as u32
1600 };
1601
1602 assert!(
1607 new_len < capacity.get(),
1608 "No space left for the block in the unincluded segment: new_len({new_len}) < capacity({})",
1609 capacity.get()
1610 );
1611 weight_used
1612 }
1613
1614 fn adjust_egress_bandwidth_limits() {
1619 let Some(unincluded_segment) = AggregatedUnincludedSegment::<T>::get() else { return };
1620
1621 <RelevantMessagingState<T>>::mutate(|messaging_state| {
1622 let Some(messaging_state) = messaging_state else { return };
1623
1624 let used_bandwidth = unincluded_segment.used_bandwidth();
1625
1626 let channels = &mut messaging_state.egress_channels;
1627 for (para_id, used) in used_bandwidth.hrmp_outgoing.iter() {
1628 let Ok(i) = channels.binary_search_by_key(para_id, |item| item.0) else {
1629 continue; };
1631
1632 let c = &mut channels[i].1;
1633
1634 c.total_size = (c.total_size + used.total_bytes).min(c.max_total_size);
1635 c.msg_count = (c.msg_count + used.msg_count).min(c.max_capacity);
1636 }
1637
1638 let upward_capacity = &mut messaging_state.relay_dispatch_queue_remaining_capacity;
1639 upward_capacity.remaining_count =
1640 upward_capacity.remaining_count.saturating_sub(used_bandwidth.ump_msg_count);
1641 upward_capacity.remaining_size =
1642 upward_capacity.remaining_size.saturating_sub(used_bandwidth.ump_total_bytes);
1643 });
1644 }
1645
1646 fn notify_polkadot_of_pending_upgrade(code: &[u8]) {
1650 NewValidationCode::<T>::put(code);
1651 <DidSetValidationCode<T>>::put(true);
1652 }
1653
1654 pub fn max_code_size() -> Option<u32> {
1658 <HostConfiguration<T>>::get().map(|cfg| cfg.max_code_size)
1659 }
1660
1661 pub fn schedule_code_upgrade(validation_function: Vec<u8>) -> DispatchResult {
1663 ensure!(<ValidationData<T>>::exists(), Error::<T>::ValidationDataNotAvailable);
1667 ensure!(<UpgradeRestrictionSignal<T>>::get().is_none(), Error::<T>::ProhibitedByPolkadot);
1668
1669 ensure!(!<PendingValidationCode<T>>::exists(), Error::<T>::OverlappingUpgrades);
1670 let cfg = HostConfiguration::<T>::get().ok_or(Error::<T>::HostConfigurationNotAvailable)?;
1671 ensure!(validation_function.len() <= cfg.max_code_size as usize, Error::<T>::TooBig);
1672
1673 Self::notify_polkadot_of_pending_upgrade(&validation_function);
1681 <PendingValidationCode<T>>::put(validation_function);
1682 Self::deposit_event(Event::ValidationFunctionStored);
1683
1684 Ok(())
1685 }
1686
1687 pub fn collect_collation_info(header: &HeaderFor<T>) -> CollationInfo {
1695 CollationInfo {
1696 hrmp_watermark: HrmpWatermark::<T>::get(),
1697 horizontal_messages: HrmpOutboundMessages::<T>::get(),
1698 upward_messages: UpwardMessages::<T>::get(),
1699 processed_downward_messages: ProcessedDownwardMessages::<T>::get(),
1700 new_validation_code: NewValidationCode::<T>::get().map(Into::into),
1701 head_data: CustomValidationHeadData::<T>::get()
1704 .map_or_else(|| header.encode(), |v| v)
1705 .into(),
1706 }
1707 }
1708
1709 pub fn set_custom_validation_head_data(head_data: Vec<u8>) {
1722 CustomValidationHeadData::<T>::put(head_data);
1723 }
1724
1725 fn send_ump_signals(core_info: Option<CoreInfo>) {
1727 let mut ump_signals = PendingUpwardSignals::<T>::take();
1728
1729 if let Some(core_info) = core_info {
1730 ump_signals.push(
1731 UMPSignal::SelectCore(core_info.selector, core_info.claim_queue_offset).encode(),
1732 );
1733 }
1734
1735 if let Some(approved_peer) = PendingApprovedPeer::<T>::take() {
1736 ump_signals.push(UMPSignal::ApprovedPeer(approved_peer).encode());
1737 }
1738
1739 if !ump_signals.is_empty() {
1740 UpwardMessages::<T>::append(UMP_SEPARATOR);
1741 ump_signals.into_iter().for_each(|s| UpwardMessages::<T>::append(s));
1742 }
1743 }
1744
1745 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
1750 pub fn open_outbound_hrmp_channel_for_benchmarks_or_tests(target_parachain: ParaId) {
1751 RelevantMessagingState::<T>::put(MessagingStateSnapshot {
1752 dmq_mqc_head: Default::default(),
1753 relay_dispatch_queue_remaining_capacity: Default::default(),
1754 ingress_channels: Default::default(),
1755 egress_channels: vec![(
1756 target_parachain,
1757 cumulus_primitives_core::AbridgedHrmpChannel {
1758 max_capacity: 10,
1759 max_total_size: 10_000_000_u32,
1760 max_message_size: 10_000_000_u32,
1761 msg_count: 5,
1762 total_size: 5_000_000_u32,
1763 mqc_head: None,
1764 },
1765 )],
1766 })
1767 }
1768
1769 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
1774 pub fn open_custom_outbound_hrmp_channel_for_benchmarks_or_tests(
1775 target_parachain: ParaId,
1776 channel: cumulus_primitives_core::AbridgedHrmpChannel,
1777 ) {
1778 RelevantMessagingState::<T>::put(MessagingStateSnapshot {
1779 dmq_mqc_head: Default::default(),
1780 relay_dispatch_queue_remaining_capacity: Default::default(),
1781 ingress_channels: Default::default(),
1782 egress_channels: vec![(target_parachain, channel)],
1783 })
1784 }
1785
1786 #[cfg(feature = "runtime-benchmarks")]
1788 pub fn initialize_for_set_code_benchmark(max_code_size: u32) {
1789 let vfp = PersistedValidationData {
1791 parent_head: polkadot_parachain_primitives::primitives::HeadData(Default::default()),
1792 relay_parent_number: 1,
1793 relay_parent_storage_root: Default::default(),
1794 max_pov_size: 1_000,
1795 };
1796 <ValidationData<T>>::put(&vfp);
1797
1798 let host_config = AbridgedHostConfiguration {
1800 max_code_size,
1801 max_head_data_size: 32 * 1024,
1802 max_upward_queue_count: 8,
1803 max_upward_queue_size: 1024 * 1024,
1804 max_upward_message_size: 4 * 1024,
1805 max_upward_message_num_per_candidate: 2,
1806 hrmp_max_message_num_per_candidate: 2,
1807 validation_upgrade_cooldown: 2,
1808 validation_upgrade_delay: 2,
1809 async_backing_params: relay_chain::AsyncBackingParams {
1810 allowed_ancestry_len: 0,
1811 max_candidate_depth: 0,
1812 },
1813 };
1814 <HostConfiguration<T>>::put(host_config);
1815 }
1816}
1817
1818pub struct ParachainSetCode<T>(core::marker::PhantomData<T>);
1820impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
1821 fn set_code(code: Vec<u8>) -> DispatchResult {
1822 Pallet::<T>::schedule_code_upgrade(code)
1823 }
1824}
1825
1826impl<T: Config> Pallet<T> {
1827 pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
1833 let message_len = message.len();
1834 if let Some(cfg) = HostConfiguration::<T>::get() {
1847 if message_len > cfg.max_upward_message_size as usize {
1848 return Err(MessageSendError::TooBig);
1849 }
1850 let threshold =
1851 cfg.max_upward_queue_size.saturating_div(ump_constants::THRESHOLD_FACTOR);
1852 <PendingUpwardMessages<T>>::append(message.clone());
1855 let pending_messages = PendingUpwardMessages::<T>::get();
1856 let total_size: usize = pending_messages.iter().map(UpwardMessage::len).sum();
1857 if total_size > threshold as usize {
1858 Self::increase_fee_factor((), message_len as u128);
1860 }
1861 } else {
1862 <PendingUpwardMessages<T>>::append(message.clone());
1872 };
1873
1874 let hash = sp_io::hashing::blake2_256(&message);
1877 Self::deposit_event(Event::UpwardMessageSent { message_hash: Some(hash) });
1878 Ok((0, hash))
1879 }
1880
1881 pub fn last_relay_block_number() -> RelayChainBlockNumber {
1884 LastRelayChainBlockNumber::<T>::get()
1885 }
1886}
1887
1888impl<T: Config> UpwardMessageSender for Pallet<T> {
1889 fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
1890 Self::send_upward_message(message)
1891 }
1892
1893 fn can_send_upward_message(message: &UpwardMessage) -> Result<(), MessageSendError> {
1894 let max_upward_message_size = HostConfiguration::<T>::get()
1895 .map(|cfg| cfg.max_upward_message_size)
1896 .ok_or(MessageSendError::Other)?;
1897 if message.len() > max_upward_message_size as usize {
1898 Err(MessageSendError::TooBig)
1899 } else {
1900 Ok(())
1901 }
1902 }
1903
1904 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
1905 fn ensure_successful_delivery() {
1906 const MAX_UPWARD_MESSAGE_SIZE: u32 = 65_531 * 3;
1907 const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
1908 HostConfiguration::<T>::mutate(|cfg| match cfg {
1909 Some(cfg) => cfg.max_upward_message_size = MAX_UPWARD_MESSAGE_SIZE,
1910 None => {
1911 *cfg = Some(AbridgedHostConfiguration {
1912 max_code_size: MAX_CODE_SIZE,
1913 max_head_data_size: 32 * 1024,
1914 max_upward_queue_count: 8,
1915 max_upward_queue_size: 1024 * 1024,
1916 max_upward_message_size: MAX_UPWARD_MESSAGE_SIZE,
1917 max_upward_message_num_per_candidate: 2,
1918 hrmp_max_message_num_per_candidate: 2,
1919 validation_upgrade_cooldown: 2,
1920 validation_upgrade_delay: 2,
1921 async_backing_params: relay_chain::AsyncBackingParams {
1922 allowed_ancestry_len: 0,
1923 max_candidate_depth: 0,
1924 },
1925 })
1926 },
1927 })
1928 }
1929}
1930
1931impl<T: Config> InspectMessageQueues for Pallet<T> {
1932 fn clear_messages() {
1933 PendingUpwardMessages::<T>::kill();
1934 }
1935
1936 fn get_messages() -> Vec<(VersionedLocation, Vec<VersionedXcm<()>>)> {
1937 use xcm::prelude::*;
1938
1939 let messages: Vec<VersionedXcm<()>> = PendingUpwardMessages::<T>::get()
1940 .iter()
1941 .map(|encoded_message| {
1942 VersionedXcm::<()>::decode_all_with_depth_limit(
1943 MAX_XCM_DECODE_DEPTH,
1944 &mut &encoded_message[..],
1945 )
1946 .unwrap()
1947 })
1948 .collect();
1949
1950 if messages.is_empty() {
1951 vec![]
1952 } else {
1953 vec![(VersionedLocation::from(Location::parent()), messages)]
1954 }
1955 }
1956}
1957
1958#[cfg(feature = "runtime-benchmarks")]
1959impl<T: Config> polkadot_runtime_parachains::EnsureForParachain for Pallet<T> {
1960 fn ensure(para_id: ParaId) {
1961 if let ChannelStatus::Closed = Self::get_channel_status(para_id) {
1962 Self::open_outbound_hrmp_channel_for_benchmarks_or_tests(para_id)
1963 }
1964 }
1965}
1966
1967pub trait OnSystemEvent {
1975 fn on_validation_data(data: &PersistedValidationData);
1977 fn on_validation_code_applied();
1980 fn on_relay_state_proof(
1982 relay_state_proof: &relay_state_snapshot::RelayChainStateProof,
1983 ) -> Weight;
1984}
1985
1986#[impl_trait_for_tuples::impl_for_tuples(30)]
1987impl OnSystemEvent for Tuple {
1988 fn on_validation_data(data: &PersistedValidationData) {
1989 for_tuples!( #( Tuple::on_validation_data(data); )* );
1990 }
1991
1992 fn on_validation_code_applied() {
1993 for_tuples!( #( Tuple::on_validation_code_applied(); )* );
1994 }
1995
1996 fn on_relay_state_proof(
1997 relay_state_proof: &relay_state_snapshot::RelayChainStateProof,
1998 ) -> Weight {
1999 let mut weight = Weight::zero();
2000 for_tuples!( #( weight = weight.saturating_add(Tuple::on_relay_state_proof(relay_state_proof)); )* );
2001 weight
2002 }
2003}
2004
2005#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Default, Debug)]
2007pub struct RelayChainState {
2008 pub number: relay_chain::BlockNumber,
2010 pub state_root: relay_chain::Hash,
2012}
2013
2014pub trait RelaychainStateProvider {
2018 fn current_relay_chain_state() -> RelayChainState;
2022
2023 #[cfg(feature = "runtime-benchmarks")]
2028 fn set_current_relay_chain_state(_state: RelayChainState) {}
2029}
2030
2031#[deprecated = "Use `RelaychainDataProvider` instead"]
2039pub type RelaychainBlockNumberProvider<T> = RelaychainDataProvider<T>;
2040
2041pub struct RelaychainDataProvider<T>(core::marker::PhantomData<T>);
2051
2052impl<T: Config> BlockNumberProvider for RelaychainDataProvider<T> {
2053 type BlockNumber = relay_chain::BlockNumber;
2054
2055 fn current_block_number() -> relay_chain::BlockNumber {
2056 ValidationData::<T>::get()
2057 .map(|d| d.relay_parent_number)
2058 .unwrap_or_else(|| Pallet::<T>::last_relay_block_number())
2059 }
2060
2061 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
2062 fn set_block_number(block: Self::BlockNumber) {
2063 let mut validation_data = ValidationData::<T>::get().unwrap_or_else(||
2064 PersistedValidationData {
2066 parent_head: vec![].into(),
2067 relay_parent_number: Default::default(),
2068 max_pov_size: Default::default(),
2069 relay_parent_storage_root: Default::default(),
2070 });
2071 validation_data.relay_parent_number = block;
2072 ValidationData::<T>::put(validation_data)
2073 }
2074}
2075
2076impl<T: Config> RelaychainStateProvider for RelaychainDataProvider<T> {
2077 fn current_relay_chain_state() -> RelayChainState {
2078 ValidationData::<T>::get()
2079 .map(|d| RelayChainState {
2080 number: d.relay_parent_number,
2081 state_root: d.relay_parent_storage_root,
2082 })
2083 .unwrap_or_default()
2084 }
2085
2086 #[cfg(feature = "runtime-benchmarks")]
2087 fn set_current_relay_chain_state(state: RelayChainState) {
2088 let mut validation_data = ValidationData::<T>::get().unwrap_or_else(||
2089 PersistedValidationData {
2091 parent_head: vec![].into(),
2092 relay_parent_number: Default::default(),
2093 max_pov_size: Default::default(),
2094 relay_parent_storage_root: Default::default(),
2095 });
2096 validation_data.relay_parent_number = state.number;
2097 validation_data.relay_parent_storage_root = state.state_root;
2098 ValidationData::<T>::put(validation_data)
2099 }
2100}