1use crate::{
18 configuration::{self, HostConfiguration},
19 dmp, ensure_parachain, initializer, paras,
20};
21use alloc::{
22 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
23 vec,
24 vec::Vec,
25};
26use codec::{Decode, Encode};
27use core::{fmt, mem};
28use frame_support::{pallet_prelude::*, traits::ReservableCurrency, DefaultNoBound};
29use frame_system::pallet_prelude::*;
30use polkadot_parachain_primitives::primitives::{HorizontalMessages, IsSystem};
31use polkadot_primitives::{
32 Balance, Hash, HrmpChannelId, Id as ParaId, InboundHrmpMessage, OutboundHrmpMessage,
33 SessionIndex,
34};
35use scale_info::TypeInfo;
36use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, UniqueSaturatedInto};
37
38pub use pallet::*;
39
40pub const HRMP_MAX_INBOUND_CHANNELS_BOUND: u32 = 128;
45pub const HRMP_MAX_OUTBOUND_CHANNELS_BOUND: u32 = 128;
47
48#[cfg(test)]
49pub(crate) mod tests;
50
51#[cfg(feature = "runtime-benchmarks")]
52mod benchmarking;
53
54pub mod deposits;
55use deposits::{ChannelDepositProvider, DepositAction, DepositChange, DepositChangeRequest};
56
57const LOG_TARGET: &str = "runtime::hrmp";
58
59pub trait WeightInfo {
60 fn hrmp_init_open_channel() -> Weight;
61 fn hrmp_accept_open_channel() -> Weight;
62 fn hrmp_close_channel() -> Weight;
63 fn force_clean_hrmp(i: u32, e: u32) -> Weight;
64 fn force_process_hrmp_open(c: u32) -> Weight;
65 fn force_process_hrmp_close(c: u32) -> Weight;
66 fn hrmp_cancel_open_request(c: u32) -> Weight;
67 fn clean_open_channel_requests(c: u32) -> Weight;
68 fn force_open_hrmp_channel(c: u32) -> Weight;
69 fn establish_system_channel() -> Weight;
70 fn poke_channel_deposits() -> Weight;
71 fn establish_channel_with_system() -> Weight;
72}
73
74pub struct TestWeightInfo;
76
77impl WeightInfo for TestWeightInfo {
78 fn hrmp_accept_open_channel() -> Weight {
79 Weight::MAX
80 }
81 fn force_clean_hrmp(_: u32, _: u32) -> Weight {
82 Weight::MAX
83 }
84 fn force_process_hrmp_close(_: u32) -> Weight {
85 Weight::MAX
86 }
87 fn force_process_hrmp_open(_: u32) -> Weight {
88 Weight::MAX
89 }
90 fn hrmp_cancel_open_request(_: u32) -> Weight {
91 Weight::MAX
92 }
93 fn hrmp_close_channel() -> Weight {
94 Weight::MAX
95 }
96 fn hrmp_init_open_channel() -> Weight {
97 Weight::MAX
98 }
99 fn clean_open_channel_requests(_: u32) -> Weight {
100 Weight::MAX
101 }
102 fn force_open_hrmp_channel(_: u32) -> Weight {
103 Weight::MAX
104 }
105 fn establish_system_channel() -> Weight {
106 Weight::MAX
107 }
108 fn poke_channel_deposits() -> Weight {
109 Weight::MAX
110 }
111 fn establish_channel_with_system() -> Weight {
112 Weight::MAX
113 }
114}
115
116#[derive(Encode, Decode, TypeInfo)]
118pub struct HrmpOpenChannelRequest {
119 pub confirmed: bool,
121 pub _age: SessionIndex,
124 pub sender_deposit: Balance,
126 pub max_message_size: u32,
128 pub max_capacity: u32,
130 pub max_total_size: u32,
132}
133
134#[derive(Encode, Decode, TypeInfo)]
136#[cfg_attr(test, derive(Debug))]
137pub struct HrmpChannel {
138 pub max_capacity: u32,
146 pub max_total_size: u32,
148 pub max_message_size: u32,
150 pub msg_count: u32,
153 pub total_size: u32,
156 pub mqc_head: Option<Hash>,
164 pub sender_deposit: Balance,
166 pub recipient_deposit: Balance,
168}
169
170pub(crate) enum HrmpWatermarkAcceptanceErr<BlockNumber> {
173 AdvancementRule { new_watermark: BlockNumber, last_watermark: BlockNumber },
174 AheadRelayParent { new_watermark: BlockNumber, relay_chain_parent_number: BlockNumber },
175 LandsOnBlockWithNoMessages { new_watermark: BlockNumber },
176}
177
178pub(crate) enum OutboundHrmpAcceptanceErr {
181 MoreMessagesThanPermitted { sent: u32, permitted: u32 },
182 NotSorted { idx: u32 },
183 NoSuchChannel { idx: u32, channel_id: HrmpChannelId },
184 MaxMessageSizeExceeded { idx: u32, msg_size: u32, max_size: u32 },
185 TotalSizeExceeded { idx: u32, total_size: u32, limit: u32 },
186 CapacityExceeded { idx: u32, count: u32, limit: u32 },
187}
188
189impl<BlockNumber> fmt::Debug for HrmpWatermarkAcceptanceErr<BlockNumber>
190where
191 BlockNumber: fmt::Debug,
192{
193 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
194 use HrmpWatermarkAcceptanceErr::*;
195 match self {
196 AdvancementRule { new_watermark, last_watermark } => write!(
197 fmt,
198 "the HRMP watermark is not advanced relative to the last watermark ({:?} > {:?})",
199 new_watermark, last_watermark,
200 ),
201 AheadRelayParent { new_watermark, relay_chain_parent_number } => write!(
202 fmt,
203 "the HRMP watermark is ahead the relay-parent ({:?} > {:?})",
204 new_watermark, relay_chain_parent_number
205 ),
206 LandsOnBlockWithNoMessages { new_watermark } => write!(
207 fmt,
208 "the HRMP watermark ({:?}) doesn't land on a block with messages received",
209 new_watermark
210 ),
211 }
212 }
213}
214
215impl fmt::Debug for OutboundHrmpAcceptanceErr {
216 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
217 use OutboundHrmpAcceptanceErr::*;
218 match self {
219 MoreMessagesThanPermitted { sent, permitted } => write!(
220 fmt,
221 "more HRMP messages than permitted by config ({} > {})",
222 sent, permitted,
223 ),
224 NotSorted { idx } => {
225 write!(fmt, "the HRMP messages are not sorted (first unsorted is at index {})", idx,)
226 },
227 NoSuchChannel { idx, channel_id } => write!(
228 fmt,
229 "the HRMP message at index {} is sent to a non existent channel {:?}->{:?}",
230 idx, channel_id.sender, channel_id.recipient,
231 ),
232 MaxMessageSizeExceeded { idx, msg_size, max_size } => write!(
233 fmt,
234 "the HRMP message at index {} exceeds the negotiated channel maximum message size ({} > {})",
235 idx, msg_size, max_size,
236 ),
237 TotalSizeExceeded { idx, total_size, limit } => write!(
238 fmt,
239 "sending the HRMP message at index {} would exceed the negotiated channel total size ({} > {})",
240 idx, total_size, limit,
241 ),
242 CapacityExceeded { idx, count, limit } => write!(
243 fmt,
244 "sending the HRMP message at index {} would exceed the negotiated channel capacity ({} > {})",
245 idx, count, limit,
246 ),
247 }
248 }
249}
250
251#[frame_support::pallet]
252pub mod pallet {
253 use super::*;
254
255 #[pallet::pallet]
256 #[pallet::without_storage_info]
257 pub struct Pallet<T>(_);
258
259 #[pallet::config]
260 pub trait Config:
261 frame_system::Config + configuration::Config + paras::Config + dmp::Config
262 {
263 #[allow(deprecated)]
265 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
266
267 type RuntimeOrigin: From<crate::Origin>
268 + From<<Self as frame_system::Config>::RuntimeOrigin>
269 + Into<Result<crate::Origin, <Self as Config>::RuntimeOrigin>>;
270
271 type ChannelManager: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
273
274 type Currency: ReservableCurrency<Self::AccountId>;
280
281 type DepositProvider: ChannelDepositProvider<OnDepositSet = Pallet<Self>>;
284
285 type DefaultChannelSizeAndCapacityWithSystem: Get<(u32, u32)>;
288
289 type VersionWrapper: xcm::WrapVersion;
296
297 type WeightInfo: WeightInfo;
299 }
300
301 #[pallet::event]
302 #[pallet::generate_deposit(pub(super) fn deposit_event)]
303 pub enum Event<T: Config> {
304 OpenChannelRequested {
306 sender: ParaId,
307 recipient: ParaId,
308 proposed_max_capacity: u32,
309 proposed_max_message_size: u32,
310 },
311 OpenChannelCanceled { by_parachain: ParaId, channel_id: HrmpChannelId },
313 OpenChannelAccepted { sender: ParaId, recipient: ParaId },
315 ChannelClosed { by_parachain: ParaId, channel_id: HrmpChannelId },
317 HrmpChannelForceOpened {
319 sender: ParaId,
320 recipient: ParaId,
321 proposed_max_capacity: u32,
322 proposed_max_message_size: u32,
323 },
324 HrmpSystemChannelOpened {
326 sender: ParaId,
327 recipient: ParaId,
328 proposed_max_capacity: u32,
329 proposed_max_message_size: u32,
330 },
331 OpenChannelDepositsUpdated { sender: ParaId, recipient: ParaId },
333 }
334
335 #[pallet::error]
336 pub enum Error<T> {
337 OpenHrmpChannelToSelf,
339 OpenHrmpChannelInvalidRecipient,
341 OpenHrmpChannelZeroCapacity,
343 OpenHrmpChannelCapacityExceedsLimit,
345 OpenHrmpChannelZeroMessageSize,
347 OpenHrmpChannelMessageSizeExceedsLimit,
349 OpenHrmpChannelAlreadyExists,
351 OpenHrmpChannelAlreadyRequested,
353 OpenHrmpChannelLimitExceeded,
355 AcceptHrmpChannelDoesntExist,
357 AcceptHrmpChannelAlreadyConfirmed,
359 AcceptHrmpChannelLimitExceeded,
361 CloseHrmpChannelUnauthorized,
363 CloseHrmpChannelDoesntExist,
365 CloseHrmpChannelAlreadyUnderway,
367 CancelHrmpOpenChannelUnauthorized,
369 OpenHrmpChannelDoesntExist,
371 OpenHrmpChannelAlreadyConfirmed,
373 WrongWitness,
375 ChannelCreationNotAuthorized,
377 }
378
379 #[pallet::storage]
386 pub type HrmpOpenChannelRequests<T: Config> =
387 StorageMap<_, Twox64Concat, HrmpChannelId, HrmpOpenChannelRequest>;
388
389 #[pallet::storage]
393 pub type HrmpOpenChannelRequestsList<T: Config> =
394 StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
395
396 #[pallet::storage]
400 pub type HrmpOpenChannelRequestCount<T: Config> =
401 StorageMap<_, Twox64Concat, ParaId, u32, ValueQuery>;
402
403 #[pallet::storage]
407 pub type HrmpAcceptedChannelRequestCount<T: Config> =
408 StorageMap<_, Twox64Concat, ParaId, u32, ValueQuery>;
409
410 #[pallet::storage]
418 pub type HrmpCloseChannelRequests<T: Config> = StorageMap<_, Twox64Concat, HrmpChannelId, ()>;
419
420 #[pallet::storage]
421 pub type HrmpCloseChannelRequestsList<T: Config> =
422 StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
423
424 #[pallet::storage]
429 pub type HrmpWatermarks<T: Config> = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor<T>>;
430
431 #[pallet::storage]
435 pub type HrmpChannels<T: Config> = StorageMap<_, Twox64Concat, HrmpChannelId, HrmpChannel>;
436
437 #[pallet::storage]
451 pub type HrmpIngressChannelsIndex<T: Config> =
452 StorageMap<_, Twox64Concat, ParaId, Vec<ParaId>, ValueQuery>;
453
454 #[pallet::storage]
457 pub type HrmpEgressChannelsIndex<T: Config> =
458 StorageMap<_, Twox64Concat, ParaId, Vec<ParaId>, ValueQuery>;
459
460 #[pallet::storage]
463 pub type HrmpChannelContents<T: Config> = StorageMap<
464 _,
465 Twox64Concat,
466 HrmpChannelId,
467 Vec<InboundHrmpMessage<BlockNumberFor<T>>>,
468 ValueQuery,
469 >;
470
471 #[pallet::storage]
478 pub type HrmpChannelDigests<T: Config> =
479 StorageMap<_, Twox64Concat, ParaId, Vec<(BlockNumberFor<T>, Vec<ParaId>)>, ValueQuery>;
480
481 #[pallet::genesis_config]
495 #[derive(DefaultNoBound)]
496 pub struct GenesisConfig<T: Config> {
497 #[serde(skip)]
498 _config: core::marker::PhantomData<T>,
499 preopen_hrmp_channels: Vec<(ParaId, ParaId, u32, u32)>,
500 }
501
502 #[pallet::genesis_build]
503 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
504 fn build(&self) {
505 initialize_storage::<T>(&self.preopen_hrmp_channels);
506 }
507 }
508
509 #[pallet::call]
510 impl<T: Config> Pallet<T> {
511 #[pallet::call_index(0)]
522 #[pallet::weight(
523 <T as Config>::WeightInfo::hrmp_init_open_channel()
524 .saturating_add(T::DepositProvider::weight_of_try_set_deposit())
525 )]
526 pub fn hrmp_init_open_channel(
527 origin: OriginFor<T>,
528 recipient: ParaId,
529 proposed_max_capacity: u32,
530 proposed_max_message_size: u32,
531 ) -> DispatchResult {
532 let origin = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin))?;
533 Self::init_open_channel(
535 origin,
536 recipient,
537 proposed_max_capacity,
538 proposed_max_message_size,
539 )
540 }
541
542 #[pallet::call_index(1)]
546 #[pallet::weight(
547 <T as Config>::WeightInfo::hrmp_accept_open_channel()
548 .saturating_add(T::DepositProvider::weight_of_try_set_deposit())
549 )]
550 pub fn hrmp_accept_open_channel(origin: OriginFor<T>, sender: ParaId) -> DispatchResult {
551 let origin = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin))?;
552 Self::accept_open_channel(origin, sender)
554 }
555
556 #[pallet::call_index(2)]
561 #[pallet::weight(<T as Config>::WeightInfo::hrmp_close_channel())]
562 pub fn hrmp_close_channel(
563 origin: OriginFor<T>,
564 channel_id: HrmpChannelId,
565 ) -> DispatchResult {
566 let origin = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin))?;
567 Self::close_channel(origin, channel_id.clone())?;
568 Self::deposit_event(Event::ChannelClosed { by_parachain: origin, channel_id });
569 Ok(())
570 }
571
572 #[pallet::call_index(3)]
580 #[pallet::weight(<T as Config>::WeightInfo::force_clean_hrmp(*num_inbound, *num_outbound))]
581 pub fn force_clean_hrmp(
582 origin: OriginFor<T>,
583 para: ParaId,
584 num_inbound: u32,
585 num_outbound: u32,
586 ) -> DispatchResult {
587 T::ChannelManager::ensure_origin(origin)?;
588
589 ensure!(
590 HrmpIngressChannelsIndex::<T>::decode_len(para).unwrap_or_default() <=
591 num_inbound as usize,
592 Error::<T>::WrongWitness
593 );
594 ensure!(
595 HrmpEgressChannelsIndex::<T>::decode_len(para).unwrap_or_default() <=
596 num_outbound as usize,
597 Error::<T>::WrongWitness
598 );
599
600 Self::clean_hrmp_after_outgoing(¶);
601 Ok(())
602 }
603
604 #[pallet::call_index(4)]
613 #[pallet::weight(<T as Config>::WeightInfo::force_process_hrmp_open(*channels))]
614 pub fn force_process_hrmp_open(origin: OriginFor<T>, channels: u32) -> DispatchResult {
615 T::ChannelManager::ensure_origin(origin)?;
616
617 ensure!(
618 HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32 <=
619 channels,
620 Error::<T>::WrongWitness
621 );
622
623 let host_config = configuration::ActiveConfig::<T>::get();
624 Self::process_hrmp_open_channel_requests(&host_config);
625 Ok(())
626 }
627
628 #[pallet::call_index(5)]
637 #[pallet::weight(<T as Config>::WeightInfo::force_process_hrmp_close(*channels))]
638 pub fn force_process_hrmp_close(origin: OriginFor<T>, channels: u32) -> DispatchResult {
639 T::ChannelManager::ensure_origin(origin)?;
640
641 ensure!(
642 HrmpCloseChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32 <=
643 channels,
644 Error::<T>::WrongWitness
645 );
646
647 Self::process_hrmp_close_channel_requests();
648 Ok(())
649 }
650
651 #[pallet::call_index(6)]
660 #[pallet::weight(
661 <T as Config>::WeightInfo::hrmp_cancel_open_request(*open_requests)
662 .saturating_add(T::DepositProvider::weight_of_try_set_deposit())
663 )]
664 pub fn hrmp_cancel_open_request(
665 origin: OriginFor<T>,
666 channel_id: HrmpChannelId,
667 open_requests: u32,
668 ) -> DispatchResult {
669 let origin = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin))?;
670 ensure!(
671 HrmpOpenChannelRequestsList::<T>::decode_len().unwrap_or_default() as u32 <=
672 open_requests,
673 Error::<T>::WrongWitness
674 );
675 Self::cancel_open_request(origin, channel_id.clone())?;
676 Self::deposit_event(Event::OpenChannelCanceled { by_parachain: origin, channel_id });
677 Ok(())
678 }
679
680 #[pallet::call_index(7)]
689 #[pallet::weight(
690 <T as Config>::WeightInfo::force_open_hrmp_channel(1)
692 .saturating_add(T::DepositProvider::weight_of_try_set_deposit().saturating_mul(3))
693 )]
694 pub fn force_open_hrmp_channel(
695 origin: OriginFor<T>,
696 sender: ParaId,
697 recipient: ParaId,
698 max_capacity: u32,
699 max_message_size: u32,
700 ) -> DispatchResultWithPostInfo {
701 T::ChannelManager::ensure_origin(origin)?;
702
703 let channel_id = HrmpChannelId { sender, recipient };
708 let cancel_request: u32 =
709 if let Some(_open_channel) = HrmpOpenChannelRequests::<T>::get(&channel_id) {
710 Self::cancel_open_request(sender, channel_id)?;
711 1
712 } else {
713 0
714 };
715
716 Self::init_open_channel(sender, recipient, max_capacity, max_message_size)?;
719 Self::accept_open_channel(recipient, sender)?;
720 Self::deposit_event(Event::HrmpChannelForceOpened {
721 sender,
722 recipient,
723 proposed_max_capacity: max_capacity,
724 proposed_max_message_size: max_message_size,
725 });
726
727 Ok(Some(<T as Config>::WeightInfo::force_open_hrmp_channel(cancel_request)).into())
728 }
729
730 #[pallet::call_index(8)]
743 #[pallet::weight(<T as Config>::WeightInfo::establish_system_channel())]
744 pub fn establish_system_channel(
745 origin: OriginFor<T>,
746 sender: ParaId,
747 recipient: ParaId,
748 ) -> DispatchResultWithPostInfo {
749 let _caller = ensure_signed(origin)?;
750
751 ensure!(
753 sender.is_system() && recipient.is_system(),
754 Error::<T>::ChannelCreationNotAuthorized
755 );
756
757 let config = configuration::ActiveConfig::<T>::get();
758 let max_message_size = config.hrmp_channel_max_message_size;
759 let max_capacity = config.hrmp_channel_max_capacity;
760
761 Self::init_open_channel(sender, recipient, max_capacity, max_message_size)?;
762 Self::accept_open_channel(recipient, sender)?;
763
764 Self::deposit_event(Event::HrmpSystemChannelOpened {
765 sender,
766 recipient,
767 proposed_max_capacity: max_capacity,
768 proposed_max_message_size: max_message_size,
769 });
770
771 Ok(Pays::No.into())
772 }
773
774 #[pallet::call_index(9)]
784 #[pallet::weight(
785 <T as Config>::WeightInfo::poke_channel_deposits()
786 .saturating_add(T::DepositProvider::weight_of_try_set_deposit())
787 )]
788 pub fn poke_channel_deposits(
789 origin: OriginFor<T>,
790 sender: ParaId,
791 recipient: ParaId,
792 ) -> DispatchResult {
793 let _caller = ensure_signed(origin)?;
794 let channel_id = HrmpChannelId { sender, recipient };
795 let channel = HrmpChannels::<T>::get(&channel_id)
796 .ok_or(Error::<T>::OpenHrmpChannelDoesntExist)?;
797
798 let config = configuration::ActiveConfig::<T>::get();
799 let (sender_deposit, recipient_deposit) = Self::required_deposits(&channel_id, &config);
800 if (channel.sender_deposit, channel.recipient_deposit) ==
802 (sender_deposit, recipient_deposit)
803 {
804 Self::deposit_event(Event::OpenChannelDepositsUpdated { sender, recipient });
805 return Ok(());
806 }
807
808 Self::set_deposit(DepositChangeRequest {
810 channel_id,
811 sender: Some(DepositChange {
812 current: channel.sender_deposit,
813 target: sender_deposit,
814 }),
815 recipient: Some(DepositChange {
816 current: channel.recipient_deposit,
817 target: recipient_deposit,
818 }),
819 action: DepositAction::PokeChannelDeposits,
820 })
821 }
822
823 #[pallet::call_index(10)]
831 #[pallet::weight(<T as Config>::WeightInfo::establish_channel_with_system())]
832 pub fn establish_channel_with_system(
833 origin: OriginFor<T>,
834 target_system_chain: ParaId,
835 ) -> DispatchResultWithPostInfo {
836 let sender = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin))?;
837
838 ensure!(target_system_chain.is_system(), Error::<T>::ChannelCreationNotAuthorized);
839
840 let (max_message_size, max_capacity) =
841 T::DefaultChannelSizeAndCapacityWithSystem::get();
842
843 Self::init_open_channel(sender, target_system_chain, max_capacity, max_message_size)?;
845 Self::accept_open_channel(target_system_chain, sender)?;
846
847 Self::init_open_channel(target_system_chain, sender, max_capacity, max_message_size)?;
848 Self::accept_open_channel(sender, target_system_chain)?;
849
850 Self::deposit_event(Event::HrmpSystemChannelOpened {
851 sender,
852 recipient: target_system_chain,
853 proposed_max_capacity: max_capacity,
854 proposed_max_message_size: max_message_size,
855 });
856
857 Self::deposit_event(Event::HrmpSystemChannelOpened {
858 sender: target_system_chain,
859 recipient: sender,
860 proposed_max_capacity: max_capacity,
861 proposed_max_message_size: max_message_size,
862 });
863
864 Ok(Pays::No.into())
865 }
866 }
867}
868
869fn initialize_storage<T: Config>(preopen_hrmp_channels: &[(ParaId, ParaId, u32, u32)]) {
870 let host_config = configuration::ActiveConfig::<T>::get();
871 for &(sender, recipient, max_capacity, max_message_size) in preopen_hrmp_channels {
872 if let Err(err) =
873 preopen_hrmp_channel::<T>(sender, recipient, max_capacity, max_message_size)
874 {
875 panic!("failed to initialize the genesis storage: {:?}", err);
876 }
877 }
878 Pallet::<T>::process_hrmp_open_channel_requests(&host_config);
879}
880
881fn preopen_hrmp_channel<T: Config>(
882 sender: ParaId,
883 recipient: ParaId,
884 max_capacity: u32,
885 max_message_size: u32,
886) -> DispatchResult {
887 Pallet::<T>::init_open_channel(sender, recipient, max_capacity, max_message_size)?;
888 Pallet::<T>::accept_open_channel(recipient, sender)?;
889 Ok(())
890}
891
892impl<T: Config> Pallet<T> {
894 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
896 Weight::zero()
897 }
898
899 pub(crate) fn initializer_finalize() {}
901
902 pub(crate) fn initializer_on_new_session(
904 notification: &initializer::SessionChangeNotification<BlockNumberFor<T>>,
905 outgoing_paras: &[ParaId],
906 ) -> Weight {
907 let w1 = Self::perform_outgoing_para_cleanup(¬ification.prev_config, outgoing_paras);
908 Self::process_hrmp_open_channel_requests(¬ification.prev_config);
909 Self::process_hrmp_close_channel_requests();
910 w1.saturating_add(<T as Config>::WeightInfo::force_process_hrmp_open(
912 outgoing_paras.len() as u32
913 ))
914 .saturating_add(<T as Config>::WeightInfo::force_process_hrmp_close(
915 outgoing_paras.len() as u32,
916 ))
917 }
918
919 fn perform_outgoing_para_cleanup(
922 config: &HostConfiguration<BlockNumberFor<T>>,
923 outgoing: &[ParaId],
924 ) -> Weight {
925 let mut w = Self::clean_open_channel_requests(config, outgoing);
926 for outgoing_para in outgoing {
927 Self::clean_hrmp_after_outgoing(outgoing_para);
928
929 let ingress_count =
932 HrmpIngressChannelsIndex::<T>::decode_len(outgoing_para).unwrap_or_default() as u32;
933 let egress_count =
934 HrmpEgressChannelsIndex::<T>::decode_len(outgoing_para).unwrap_or_default() as u32;
935 w = w.saturating_add(<T as Config>::WeightInfo::force_clean_hrmp(
936 ingress_count,
937 egress_count,
938 ));
939 }
940 w
941 }
942
943 pub(crate) fn clean_open_channel_requests(
947 config: &HostConfiguration<BlockNumberFor<T>>,
948 outgoing: &[ParaId],
949 ) -> Weight {
950 let open_channel_reqs = HrmpOpenChannelRequestsList::<T>::get();
956 let (go, stay): (Vec<HrmpChannelId>, Vec<HrmpChannelId>) = open_channel_reqs
957 .into_iter()
958 .partition(|req_id| outgoing.iter().any(|id| req_id.is_participant(*id)));
959 HrmpOpenChannelRequestsList::<T>::put(stay);
960
961 for req_id in go {
964 let req_data = match HrmpOpenChannelRequests::<T>::take(&req_id) {
965 Some(req_data) => req_data,
966 None => {
967 continue;
969 },
970 };
971
972 let unless_offboarding =
974 |para: ParaId, deposit: Balance| (!outgoing.contains(¶)).then_some(deposit);
975 let sender_deposit = unless_offboarding(req_id.sender, req_data.sender_deposit);
976
977 let recipient_deposit = if req_data.confirmed {
983 Self::decrease_accepted_channel_request_count(req_id.recipient);
984 unless_offboarding(req_id.recipient, config.hrmp_recipient_deposit)
985 } else {
986 None
987 };
988 Self::release_deposits(&req_id, sender_deposit, recipient_deposit);
989 }
990
991 <T as Config>::WeightInfo::clean_open_channel_requests(outgoing.len() as u32)
992 }
993
994 fn clean_hrmp_after_outgoing(outgoing_para: &ParaId) {
996 HrmpOpenChannelRequestCount::<T>::remove(outgoing_para);
997 HrmpAcceptedChannelRequestCount::<T>::remove(outgoing_para);
998
999 let ingress = HrmpIngressChannelsIndex::<T>::take(outgoing_para)
1000 .into_iter()
1001 .map(|sender| HrmpChannelId { sender, recipient: *outgoing_para });
1002 let egress = HrmpEgressChannelsIndex::<T>::take(outgoing_para)
1003 .into_iter()
1004 .map(|recipient| HrmpChannelId { sender: *outgoing_para, recipient });
1005 let mut to_close = ingress.chain(egress).collect::<Vec<_>>();
1006 to_close.sort();
1007 to_close.dedup();
1008
1009 for channel in to_close {
1010 Self::close_hrmp_channel(&channel);
1011 }
1012 }
1013
1014 fn process_hrmp_open_channel_requests(config: &HostConfiguration<BlockNumberFor<T>>) {
1019 let mut open_req_channels = HrmpOpenChannelRequestsList::<T>::get();
1020 if open_req_channels.is_empty() {
1021 return;
1022 }
1023
1024 let mut idx = open_req_channels.len();
1027 loop {
1028 if idx == 0 {
1030 break;
1031 }
1032
1033 idx -= 1;
1034 let channel_id = open_req_channels[idx].clone();
1035 let request = HrmpOpenChannelRequests::<T>::get(&channel_id).expect(
1036 "can't be `None` due to the invariant that the list contains the same items as the set; qed",
1037 );
1038
1039 let system_channel = channel_id.sender.is_system() || channel_id.recipient.is_system();
1040 let sender_deposit = request.sender_deposit;
1041 let recipient_deposit = if system_channel { 0 } else { config.hrmp_recipient_deposit };
1042
1043 if request.confirmed {
1044 if paras::Pallet::<T>::is_valid_para(channel_id.sender) &&
1045 paras::Pallet::<T>::is_valid_para(channel_id.recipient)
1046 {
1047 HrmpChannels::<T>::insert(
1048 &channel_id,
1049 HrmpChannel {
1050 sender_deposit,
1051 recipient_deposit,
1052 max_capacity: request.max_capacity,
1053 max_total_size: request.max_total_size,
1054 max_message_size: request.max_message_size,
1055 msg_count: 0,
1056 total_size: 0,
1057 mqc_head: None,
1058 },
1059 );
1060
1061 HrmpIngressChannelsIndex::<T>::mutate(&channel_id.recipient, |v| {
1062 if let Err(i) = v.binary_search(&channel_id.sender) {
1063 v.insert(i, channel_id.sender);
1064 }
1065 });
1066 HrmpEgressChannelsIndex::<T>::mutate(&channel_id.sender, |v| {
1067 if let Err(i) = v.binary_search(&channel_id.recipient) {
1068 v.insert(i, channel_id.recipient);
1069 }
1070 });
1071 }
1072
1073 Self::decrease_open_channel_request_count(channel_id.sender);
1074 Self::decrease_accepted_channel_request_count(channel_id.recipient);
1075
1076 let _ = open_req_channels.swap_remove(idx);
1077 HrmpOpenChannelRequests::<T>::remove(&channel_id);
1078 }
1079 }
1080
1081 HrmpOpenChannelRequestsList::<T>::put(open_req_channels);
1082 }
1083
1084 fn process_hrmp_close_channel_requests() {
1086 let close_reqs = HrmpCloseChannelRequestsList::<T>::take();
1087 for condemned_ch_id in close_reqs {
1088 HrmpCloseChannelRequests::<T>::remove(&condemned_ch_id);
1089 Self::close_hrmp_channel(&condemned_ch_id);
1090 }
1091 }
1092
1093 fn close_hrmp_channel(channel_id: &HrmpChannelId) {
1100 if let Some(HrmpChannel { sender_deposit, recipient_deposit, .. }) =
1101 HrmpChannels::<T>::take(channel_id)
1102 {
1103 Self::release_deposits(channel_id, Some(sender_deposit), Some(recipient_deposit));
1104 }
1105
1106 HrmpChannelContents::<T>::remove(channel_id);
1107
1108 HrmpEgressChannelsIndex::<T>::mutate(&channel_id.sender, |v| {
1109 if let Ok(i) = v.binary_search(&channel_id.recipient) {
1110 v.remove(i);
1111 }
1112 });
1113 HrmpIngressChannelsIndex::<T>::mutate(&channel_id.recipient, |v| {
1114 if let Ok(i) = v.binary_search(&channel_id.sender) {
1115 v.remove(i);
1116 }
1117 });
1118 }
1119
1120 pub(crate) fn check_hrmp_watermark(
1122 recipient: ParaId,
1123 relay_chain_parent_number: BlockNumberFor<T>,
1124 new_hrmp_watermark: BlockNumberFor<T>,
1125 ) -> Result<(), HrmpWatermarkAcceptanceErr<BlockNumberFor<T>>> {
1126 if new_hrmp_watermark == relay_chain_parent_number {
1135 return Ok(());
1136 }
1137
1138 if new_hrmp_watermark > relay_chain_parent_number {
1139 return Err(HrmpWatermarkAcceptanceErr::AheadRelayParent {
1140 new_watermark: new_hrmp_watermark,
1141 relay_chain_parent_number,
1142 });
1143 }
1144
1145 if let Some(last_watermark) = HrmpWatermarks::<T>::get(&recipient) {
1146 if new_hrmp_watermark < last_watermark {
1147 return Err(HrmpWatermarkAcceptanceErr::AdvancementRule {
1148 new_watermark: new_hrmp_watermark,
1149 last_watermark,
1150 });
1151 }
1152
1153 if new_hrmp_watermark == last_watermark {
1154 return Ok(());
1155 }
1156 }
1157
1158 let digest = HrmpChannelDigests::<T>::get(&recipient);
1163 if !digest
1164 .binary_search_by_key(&new_hrmp_watermark, |(block_no, _)| *block_no)
1165 .is_ok()
1166 {
1167 return Err(HrmpWatermarkAcceptanceErr::LandsOnBlockWithNoMessages {
1168 new_watermark: new_hrmp_watermark,
1169 });
1170 }
1171 Ok(())
1172 }
1173
1174 pub(crate) fn valid_watermarks(recipient: ParaId) -> Vec<BlockNumberFor<T>> {
1176 let mut valid_watermarks: Vec<_> = HrmpChannelDigests::<T>::get(&recipient)
1177 .into_iter()
1178 .map(|(block_no, _)| block_no)
1179 .collect();
1180
1181 if let Some(last_watermark) = HrmpWatermarks::<T>::get(&recipient) {
1183 if valid_watermarks.first().map_or(false, |w| w > &last_watermark) {
1184 valid_watermarks.insert(0, last_watermark);
1185 }
1186 }
1187
1188 valid_watermarks
1189 }
1190
1191 pub(crate) fn check_outbound_hrmp(
1192 config: &HostConfiguration<BlockNumberFor<T>>,
1193 sender: ParaId,
1194 out_hrmp_msgs: &[OutboundHrmpMessage<ParaId>],
1195 ) -> Result<(), OutboundHrmpAcceptanceErr> {
1196 if out_hrmp_msgs.len() as u32 > config.hrmp_max_message_num_per_candidate {
1197 return Err(OutboundHrmpAcceptanceErr::MoreMessagesThanPermitted {
1198 sent: out_hrmp_msgs.len() as u32,
1199 permitted: config.hrmp_max_message_num_per_candidate,
1200 });
1201 }
1202
1203 let mut last_recipient = None::<ParaId>;
1204
1205 for (idx, out_msg) in
1206 out_hrmp_msgs.iter().enumerate().map(|(idx, out_msg)| (idx as u32, out_msg))
1207 {
1208 match last_recipient {
1209 Some(last_recipient) if out_msg.recipient <= last_recipient => {
1213 return Err(OutboundHrmpAcceptanceErr::NotSorted { idx })
1214 },
1215 _ => last_recipient = Some(out_msg.recipient),
1216 }
1217
1218 let channel_id = HrmpChannelId { sender, recipient: out_msg.recipient };
1219
1220 let channel = match HrmpChannels::<T>::get(&channel_id) {
1221 Some(channel) => channel,
1222 None => return Err(OutboundHrmpAcceptanceErr::NoSuchChannel { channel_id, idx }),
1223 };
1224
1225 let msg_size = out_msg.data.len() as u32;
1226 if msg_size > channel.max_message_size {
1227 return Err(OutboundHrmpAcceptanceErr::MaxMessageSizeExceeded {
1228 idx,
1229 msg_size,
1230 max_size: channel.max_message_size,
1231 });
1232 }
1233
1234 let new_total_size = channel.total_size + out_msg.data.len() as u32;
1235 if new_total_size > channel.max_total_size {
1236 return Err(OutboundHrmpAcceptanceErr::TotalSizeExceeded {
1237 idx,
1238 total_size: new_total_size,
1239 limit: channel.max_total_size,
1240 });
1241 }
1242
1243 let new_msg_count = channel.msg_count + 1;
1244 if new_msg_count > channel.max_capacity {
1245 return Err(OutboundHrmpAcceptanceErr::CapacityExceeded {
1246 idx,
1247 count: new_msg_count,
1248 limit: channel.max_capacity,
1249 });
1250 }
1251 }
1252
1253 Ok(())
1254 }
1255
1256 pub(crate) fn outbound_remaining_capacity(sender: ParaId) -> Vec<(ParaId, (u32, u32))> {
1258 let recipients = HrmpEgressChannelsIndex::<T>::get(&sender);
1259 let mut remaining = Vec::with_capacity(recipients.len());
1260
1261 for recipient in recipients {
1262 let Some(channel) = HrmpChannels::<T>::get(&HrmpChannelId { sender, recipient }) else {
1263 continue;
1264 };
1265 remaining.push((
1266 recipient,
1267 (
1268 channel.max_capacity - channel.msg_count,
1269 channel.max_total_size - channel.total_size,
1270 ),
1271 ));
1272 }
1273
1274 remaining
1275 }
1276
1277 pub(crate) fn prune_hrmp(recipient: ParaId, new_hrmp_watermark: BlockNumberFor<T>) {
1278 let senders = HrmpChannelDigests::<T>::mutate(&recipient, |digest| {
1281 let mut senders = BTreeSet::new();
1282 let mut leftover = Vec::with_capacity(digest.len());
1283 for (block_no, paras_sent_msg) in mem::replace(digest, Vec::new()) {
1284 if block_no <= new_hrmp_watermark {
1285 senders.extend(paras_sent_msg);
1286 } else {
1287 leftover.push((block_no, paras_sent_msg));
1288 }
1289 }
1290 *digest = leftover;
1291 senders
1292 });
1293
1294 let channels_to_prune =
1296 senders.into_iter().map(|sender| HrmpChannelId { sender, recipient });
1297 for channel_id in channels_to_prune {
1298 let (mut pruned_cnt, mut pruned_size) = (0, 0);
1301
1302 let contents = HrmpChannelContents::<T>::get(&channel_id);
1303 let mut leftover = Vec::with_capacity(contents.len());
1304 for msg in contents {
1305 if msg.sent_at <= new_hrmp_watermark {
1306 pruned_cnt += 1;
1307 pruned_size += msg.data.len();
1308 } else {
1309 leftover.push(msg);
1310 }
1311 }
1312 if !leftover.is_empty() {
1313 HrmpChannelContents::<T>::insert(&channel_id, leftover);
1314 } else {
1315 HrmpChannelContents::<T>::remove(&channel_id);
1316 }
1317
1318 HrmpChannels::<T>::mutate(&channel_id, |channel| {
1320 if let Some(ref mut channel) = channel {
1321 channel.msg_count -= pruned_cnt as u32;
1322 channel.total_size -= pruned_size as u32;
1323 }
1324 });
1325 }
1326
1327 HrmpWatermarks::<T>::insert(&recipient, new_hrmp_watermark);
1328 }
1329
1330 pub(crate) fn queue_outbound_hrmp(sender: ParaId, out_hrmp_msgs: HorizontalMessages) {
1332 let now = frame_system::Pallet::<T>::block_number();
1333
1334 for out_msg in out_hrmp_msgs {
1335 let channel_id = HrmpChannelId { sender, recipient: out_msg.recipient };
1336
1337 let mut channel = match HrmpChannels::<T>::get(&channel_id) {
1338 Some(channel) => channel,
1339 None => {
1340 continue;
1343 },
1344 };
1345
1346 let inbound = InboundHrmpMessage { sent_at: now, data: out_msg.data };
1347
1348 channel.msg_count += 1;
1350 channel.total_size += inbound.data.len() as u32;
1351
1352 let prev_head = channel.mqc_head.unwrap_or(Default::default());
1354 let new_head = BlakeTwo256::hash_of(&(
1355 prev_head,
1356 inbound.sent_at,
1357 T::Hashing::hash_of(&inbound.data),
1358 ));
1359 channel.mqc_head = Some(new_head);
1360
1361 HrmpChannels::<T>::insert(&channel_id, channel);
1362 HrmpChannelContents::<T>::append(&channel_id, inbound);
1363
1364 let mut recipient_digest = HrmpChannelDigests::<T>::get(&channel_id.recipient);
1377 if let Some(cur_block_digest) = recipient_digest
1378 .last_mut()
1379 .filter(|(block_no, _)| *block_no == now)
1380 .map(|(_, ref mut d)| d)
1381 {
1382 cur_block_digest.push(sender);
1383 } else {
1384 recipient_digest.push((now, vec![sender]));
1385 }
1386 HrmpChannelDigests::<T>::insert(&channel_id.recipient, recipient_digest);
1387 }
1388 }
1389
1390 pub fn init_open_channel(
1398 origin: ParaId,
1399 recipient: ParaId,
1400 proposed_max_capacity: u32,
1401 proposed_max_message_size: u32,
1402 ) -> DispatchResult {
1403 ensure!(origin != recipient, Error::<T>::OpenHrmpChannelToSelf);
1404 ensure!(
1405 paras::Pallet::<T>::is_valid_para(recipient),
1406 Error::<T>::OpenHrmpChannelInvalidRecipient,
1407 );
1408
1409 let config = configuration::ActiveConfig::<T>::get();
1410 ensure!(proposed_max_capacity > 0, Error::<T>::OpenHrmpChannelZeroCapacity);
1411 ensure!(
1412 proposed_max_capacity <= config.hrmp_channel_max_capacity,
1413 Error::<T>::OpenHrmpChannelCapacityExceedsLimit,
1414 );
1415 ensure!(proposed_max_message_size > 0, Error::<T>::OpenHrmpChannelZeroMessageSize);
1416 ensure!(
1417 proposed_max_message_size <= config.hrmp_channel_max_message_size,
1418 Error::<T>::OpenHrmpChannelMessageSizeExceedsLimit,
1419 );
1420
1421 let channel_id = HrmpChannelId { sender: origin, recipient };
1422 ensure!(
1423 HrmpOpenChannelRequests::<T>::get(&channel_id).is_none(),
1424 Error::<T>::OpenHrmpChannelAlreadyRequested,
1425 );
1426 ensure!(
1427 HrmpChannels::<T>::get(&channel_id).is_none(),
1428 Error::<T>::OpenHrmpChannelAlreadyExists,
1429 );
1430
1431 let egress_cnt = HrmpEgressChannelsIndex::<T>::decode_len(&origin).unwrap_or(0) as u32;
1432 let open_req_cnt = HrmpOpenChannelRequestCount::<T>::get(&origin);
1433 let channel_num_limit = config.hrmp_max_parachain_outbound_channels;
1434 ensure!(
1435 egress_cnt + open_req_cnt < channel_num_limit,
1436 Error::<T>::OpenHrmpChannelLimitExceeded,
1437 );
1438
1439 let (sender_deposit, _) = Self::required_deposits(&channel_id, &config);
1440 Self::set_deposit(DepositChangeRequest {
1441 channel_id,
1442 sender: Some(DepositChange { current: 0, target: sender_deposit }),
1443 recipient: None,
1444 action: DepositAction::InitOpenChannel {
1445 max_capacity: proposed_max_capacity,
1446 max_message_size: proposed_max_message_size,
1447 max_total_size: config.hrmp_channel_max_total_size,
1448 },
1449 })
1450 }
1451
1452 fn finish_init_open_channel(
1454 channel_id: &HrmpChannelId,
1455 sender_deposit: Balance,
1456 max_capacity: u32,
1457 max_message_size: u32,
1458 max_total_size: u32,
1459 ) {
1460 let config = configuration::ActiveConfig::<T>::get();
1461 let (sender, recipient) = (channel_id.sender, channel_id.recipient);
1462
1463 HrmpOpenChannelRequestCount::<T>::mutate(&sender, |count| *count += 1);
1464 HrmpOpenChannelRequests::<T>::insert(
1465 channel_id,
1466 HrmpOpenChannelRequest {
1467 confirmed: false,
1468 _age: 0,
1469 sender_deposit,
1470 max_capacity,
1471 max_message_size,
1472 max_total_size,
1473 },
1474 );
1475 HrmpOpenChannelRequestsList::<T>::append(channel_id);
1476
1477 Self::send_to_para(
1478 "init_open_channel",
1479 &config,
1480 recipient,
1481 Self::wrap_notification(|| {
1482 use xcm::opaque::latest::{prelude::*, Xcm};
1483 Xcm(vec![HrmpNewChannelOpenRequest {
1484 sender: sender.into(),
1485 max_capacity,
1486 max_message_size,
1487 }])
1488 }),
1489 );
1490
1491 Self::deposit_event(Event::OpenChannelRequested {
1492 sender,
1493 recipient,
1494 proposed_max_capacity: max_capacity,
1495 proposed_max_message_size: max_message_size,
1496 });
1497 }
1498
1499 pub fn accept_open_channel(origin: ParaId, sender: ParaId) -> DispatchResult {
1504 let channel_id = HrmpChannelId { sender, recipient: origin };
1505 let channel_req = HrmpOpenChannelRequests::<T>::get(&channel_id)
1506 .ok_or(Error::<T>::AcceptHrmpChannelDoesntExist)?;
1507 ensure!(!channel_req.confirmed, Error::<T>::AcceptHrmpChannelAlreadyConfirmed);
1508
1509 let config = configuration::ActiveConfig::<T>::get();
1512 let channel_num_limit = config.hrmp_max_parachain_inbound_channels;
1513 let ingress_cnt = HrmpIngressChannelsIndex::<T>::decode_len(&origin).unwrap_or(0) as u32;
1514 let accepted_cnt = HrmpAcceptedChannelRequestCount::<T>::get(&origin);
1515 ensure!(
1516 ingress_cnt + accepted_cnt < channel_num_limit,
1517 Error::<T>::AcceptHrmpChannelLimitExceeded,
1518 );
1519
1520 let (_, recipient_deposit) = Self::required_deposits(&channel_id, &config);
1521 Self::set_deposit(DepositChangeRequest {
1522 channel_id,
1523 sender: None,
1524 recipient: Some(DepositChange { current: 0, target: recipient_deposit }),
1525 action: DepositAction::AcceptOpenChannel,
1526 })
1527 }
1528
1529 fn finish_accept_open_channel(channel_id: &HrmpChannelId) {
1531 let config = configuration::ActiveConfig::<T>::get();
1532 let (sender, recipient) = (channel_id.sender, channel_id.recipient);
1533 let Some(mut channel_req) = HrmpOpenChannelRequests::<T>::get(channel_id) else {
1534 log::error!(
1535 target: LOG_TARGET,
1536 "accept of {channel_id:?} completed after its open request was dropped"
1537 );
1538 return;
1539 };
1540
1541 channel_req.confirmed = true;
1544 HrmpOpenChannelRequests::<T>::insert(channel_id, channel_req);
1545 HrmpAcceptedChannelRequestCount::<T>::mutate(&recipient, |count| *count += 1);
1546
1547 Self::send_to_para(
1548 "accept_open_channel",
1549 &config,
1550 sender,
1551 Self::wrap_notification(|| {
1552 use xcm::opaque::latest::{prelude::*, Xcm};
1553 Xcm(vec![HrmpChannelAccepted { recipient: recipient.into() }])
1554 }),
1555 );
1556
1557 Self::deposit_event(Event::OpenChannelAccepted { sender, recipient });
1558 }
1559
1560 fn finish_poke_channel_deposits(
1562 channel_id: &HrmpChannelId,
1563 sender: Option<DepositChange>,
1564 recipient: Option<DepositChange>,
1565 ) {
1566 let updated = HrmpChannels::<T>::mutate(channel_id, |channel| {
1567 let Some(channel) = channel else { return false };
1568 if let Some(change) = sender {
1569 channel.sender_deposit = change.target;
1570 }
1571 if let Some(change) = recipient {
1572 channel.recipient_deposit = change.target;
1573 }
1574 true
1575 });
1576 if updated {
1577 let HrmpChannelId { sender, recipient } = *channel_id;
1578 Self::deposit_event(Event::OpenChannelDepositsUpdated { sender, recipient });
1579 } else {
1580 log::error!(target: LOG_TARGET, "poke of {channel_id:?} completed after it was closed");
1581 }
1582 }
1583
1584 fn cancel_open_request(origin: ParaId, channel_id: HrmpChannelId) -> DispatchResult {
1585 ensure!(channel_id.is_participant(origin), Error::<T>::CancelHrmpOpenChannelUnauthorized);
1587
1588 let open_channel_req = HrmpOpenChannelRequests::<T>::get(&channel_id)
1589 .ok_or(Error::<T>::OpenHrmpChannelDoesntExist)?;
1590 ensure!(!open_channel_req.confirmed, Error::<T>::OpenHrmpChannelAlreadyConfirmed);
1591
1592 HrmpOpenChannelRequests::<T>::remove(&channel_id);
1594 HrmpOpenChannelRequestsList::<T>::mutate(|open_req_channels| {
1595 if let Some(pos) = open_req_channels.iter().position(|x| x == &channel_id) {
1596 open_req_channels.swap_remove(pos);
1597 }
1598 });
1599
1600 Self::decrease_open_channel_request_count(channel_id.sender);
1601 Self::release_deposits(&channel_id, Some(open_channel_req.sender_deposit), None);
1607
1608 Ok(())
1609 }
1610
1611 fn close_channel(origin: ParaId, channel_id: HrmpChannelId) -> Result<(), Error<T>> {
1612 ensure!(channel_id.is_participant(origin), Error::<T>::CloseHrmpChannelUnauthorized);
1614
1615 ensure!(
1617 HrmpChannels::<T>::get(&channel_id).is_some(),
1618 Error::<T>::CloseHrmpChannelDoesntExist,
1619 );
1620
1621 ensure!(
1623 HrmpCloseChannelRequests::<T>::get(&channel_id).is_none(),
1624 Error::<T>::CloseHrmpChannelAlreadyUnderway,
1625 );
1626
1627 HrmpCloseChannelRequests::<T>::insert(&channel_id, ());
1628 HrmpCloseChannelRequestsList::<T>::append(channel_id.clone());
1629
1630 let config = configuration::ActiveConfig::<T>::get();
1631 let opposite_party =
1632 if origin == channel_id.sender { channel_id.recipient } else { channel_id.sender };
1633
1634 Self::send_to_para(
1635 "close_channel",
1636 &config,
1637 opposite_party,
1638 Self::wrap_notification(|| {
1639 use xcm::opaque::latest::{prelude::*, Xcm};
1640 Xcm(vec![HrmpChannelClosing {
1641 initiator: origin.into(),
1642 sender: channel_id.sender.into(),
1643 recipient: channel_id.recipient.into(),
1644 }])
1645 }),
1646 );
1647
1648 Ok(())
1649 }
1650
1651 #[cfg(test)]
1655 fn hrmp_mqc_heads(recipient: ParaId) -> Vec<(ParaId, Hash)> {
1656 let sender_set = HrmpIngressChannelsIndex::<T>::get(&recipient);
1657
1658 let mut mqc_heads = Vec::with_capacity(sender_set.len());
1660 for sender in sender_set {
1661 let channel_metadata = HrmpChannels::<T>::get(&HrmpChannelId { sender, recipient });
1662 let mqc_head = channel_metadata
1663 .and_then(|metadata| metadata.mqc_head)
1664 .unwrap_or(Hash::default());
1665 mqc_heads.push((sender, mqc_head));
1666 }
1667
1668 mqc_heads
1669 }
1670
1671 pub(crate) fn inbound_hrmp_channels_contents(
1674 recipient: ParaId,
1675 ) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumberFor<T>>>> {
1676 let sender_set = HrmpIngressChannelsIndex::<T>::get(&recipient);
1677
1678 let mut inbound_hrmp_channels_contents = BTreeMap::new();
1679 for sender in sender_set {
1680 let channel_contents =
1681 HrmpChannelContents::<T>::get(&HrmpChannelId { sender, recipient });
1682 inbound_hrmp_channels_contents.insert(sender, channel_contents);
1683 }
1684
1685 inbound_hrmp_channels_contents
1686 }
1687}
1688
1689impl<T: Config> Pallet<T> {
1690 fn decrease_open_channel_request_count(sender: ParaId) {
1693 HrmpOpenChannelRequestCount::<T>::mutate_exists(&sender, |opt_rc| {
1694 *opt_rc = opt_rc.and_then(|rc| match rc.saturating_sub(1) {
1695 0 => None,
1696 n => Some(n),
1697 });
1698 });
1699 }
1700
1701 fn decrease_accepted_channel_request_count(recipient: ParaId) {
1704 HrmpAcceptedChannelRequestCount::<T>::mutate_exists(&recipient, |opt_rc| {
1705 *opt_rc = opt_rc.and_then(|rc| match rc.saturating_sub(1) {
1706 0 => None,
1707 n => Some(n),
1708 });
1709 });
1710 }
1711
1712 #[cfg(any(feature = "runtime-benchmarks", test))]
1713 fn assert_storage_consistency_exhaustive() {
1714 fn assert_is_sorted<T: Ord>(slice: &[T], id: &str) {
1715 assert!(slice.windows(2).all(|xs| xs[0] <= xs[1]), "{} supposed to be sorted", id);
1716 }
1717
1718 let assert_contains_only_onboarded = |paras: Vec<ParaId>, cause: &str| {
1719 for para in paras {
1720 assert!(
1721 crate::paras::Pallet::<T>::is_valid_para(para),
1722 "{}: {:?} para is offboarded",
1723 cause,
1724 para
1725 );
1726 }
1727 };
1728
1729 assert_eq!(
1730 HrmpOpenChannelRequests::<T>::iter().map(|(k, _)| k).collect::<BTreeSet<_>>(),
1731 HrmpOpenChannelRequestsList::<T>::get().into_iter().collect::<BTreeSet<_>>(),
1732 );
1733
1734 assert_eq!(
1739 HrmpOpenChannelRequestCount::<T>::iter()
1740 .map(|(k, _)| k)
1741 .collect::<BTreeSet<_>>(),
1742 HrmpOpenChannelRequests::<T>::iter()
1743 .map(|(k, _)| k.sender)
1744 .collect::<BTreeSet<_>>(),
1745 );
1746 for (open_channel_initiator, expected_num) in HrmpOpenChannelRequestCount::<T>::iter() {
1747 let actual_num = HrmpOpenChannelRequests::<T>::iter()
1748 .filter(|(ch, _)| ch.sender == open_channel_initiator)
1749 .count() as u32;
1750 assert_eq!(expected_num, actual_num);
1751 }
1752
1753 assert_eq!(
1756 HrmpAcceptedChannelRequestCount::<T>::iter()
1757 .map(|(k, _)| k)
1758 .collect::<BTreeSet<_>>(),
1759 HrmpOpenChannelRequests::<T>::iter()
1760 .filter(|(_, v)| v.confirmed)
1761 .map(|(k, _)| k.recipient)
1762 .collect::<BTreeSet<_>>(),
1763 );
1764 for (channel_recipient, expected_num) in HrmpAcceptedChannelRequestCount::<T>::iter() {
1765 let actual_num = HrmpOpenChannelRequests::<T>::iter()
1766 .filter(|(ch, v)| ch.recipient == channel_recipient && v.confirmed)
1767 .count() as u32;
1768 assert_eq!(expected_num, actual_num);
1769 }
1770
1771 assert_eq!(
1772 HrmpCloseChannelRequests::<T>::iter().map(|(k, _)| k).collect::<BTreeSet<_>>(),
1773 HrmpCloseChannelRequestsList::<T>::get().into_iter().collect::<BTreeSet<_>>(),
1774 );
1775
1776 assert_contains_only_onboarded(
1779 HrmpWatermarks::<T>::iter().map(|(k, _)| k).collect::<Vec<_>>(),
1780 "HRMP watermarks should contain only onboarded paras",
1781 );
1782
1783 for (non_empty_channel, contents) in HrmpChannelContents::<T>::iter() {
1786 assert!(HrmpChannels::<T>::contains_key(&non_empty_channel));
1787
1788 assert!(!contents.is_empty());
1791 }
1792
1793 assert_contains_only_onboarded(
1796 HrmpChannels::<T>::iter()
1797 .flat_map(|(k, _)| vec![k.sender, k.recipient])
1798 .collect::<Vec<_>>(),
1799 "senders and recipients in all channels should be onboarded",
1800 );
1801
1802 let channel_set_derived_from_ingress = HrmpIngressChannelsIndex::<T>::iter()
1822 .flat_map(|(p, v)| v.into_iter().map(|i| (i, p)).collect::<Vec<_>>())
1823 .collect::<BTreeSet<_>>();
1824 let channel_set_derived_from_egress = HrmpEgressChannelsIndex::<T>::iter()
1825 .flat_map(|(p, v)| v.into_iter().map(|e| (p, e)).collect::<Vec<_>>())
1826 .collect::<BTreeSet<_>>();
1827 let channel_set_ground_truth = HrmpChannels::<T>::iter()
1828 .map(|(k, _)| (k.sender, k.recipient))
1829 .collect::<BTreeSet<_>>();
1830 assert_eq!(channel_set_derived_from_ingress, channel_set_derived_from_egress);
1831 assert_eq!(channel_set_derived_from_egress, channel_set_ground_truth);
1832
1833 HrmpIngressChannelsIndex::<T>::iter()
1834 .map(|(_, v)| v)
1835 .for_each(|v| assert_is_sorted(&v, "HrmpIngressChannelsIndex"));
1836 HrmpEgressChannelsIndex::<T>::iter()
1837 .map(|(_, v)| v)
1838 .for_each(|v| assert_is_sorted(&v, "HrmpIngressChannelsIndex"));
1839
1840 assert_contains_only_onboarded(
1841 HrmpChannelDigests::<T>::iter().map(|(k, _)| k).collect::<Vec<_>>(),
1842 "HRMP channel digests should contain only onboarded paras",
1843 );
1844 for (_digest_for_para, digest) in HrmpChannelDigests::<T>::iter() {
1845 assert!(digest.windows(2).all(|xs| xs[0].0 < xs[1].0));
1848
1849 for (_, mut senders) in digest {
1850 assert!(!senders.is_empty());
1851
1852 senders.sort();
1855 let orig_senders = senders.clone();
1856 senders.dedup();
1857 assert_eq!(
1858 orig_senders, senders,
1859 "duplicates removed implies existence of duplicates"
1860 );
1861 }
1862 }
1863 }
1864}
1865
1866impl<T: Config> Pallet<T> {
1867 fn wrap_notification(
1870 mut notification: impl FnMut() -> xcm::opaque::latest::opaque::Xcm,
1871 ) -> impl FnOnce(ParaId) -> polkadot_primitives::DownwardMessage {
1872 use xcm::{
1873 opaque::VersionedXcm,
1874 prelude::{Junction, Location},
1875 WrapVersion,
1876 };
1877
1878 move |dest| {
1880 T::VersionWrapper::wrap_version(
1882 &Location::new(0, [Junction::Parachain(dest.into())]),
1883 notification(),
1884 )
1885 .unwrap_or_else(|_| {
1886 VersionedXcm::from(notification())
1889 })
1890 .encode()
1891 }
1892 }
1893
1894 fn send_to_para(
1896 log_label: &str,
1897 config: &HostConfiguration<BlockNumberFor<T>>,
1898 dest: ParaId,
1899 notification_bytes_for: impl FnOnce(ParaId) -> polkadot_primitives::DownwardMessage,
1900 ) {
1901 let notification_bytes = notification_bytes_for(dest);
1903
1904 if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) =
1906 dmp::Pallet::<T>::queue_downward_message(&config, dest, notification_bytes)
1907 {
1908 log::error!(
1911 target: LOG_TARGET,
1912 "sending '{log_label}::notification_bytes' failed."
1913 );
1914 debug_assert!(false);
1915 }
1916 }
1917}