referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/
hrmp.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17use 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
40/// Maximum bound that can be set for inbound channels.
41///
42/// If inaccurate, the weighing of this pallet might become inaccurate. It is expected form the
43/// `configurations` pallet to check these values before setting
44pub const HRMP_MAX_INBOUND_CHANNELS_BOUND: u32 = 128;
45/// Same as [`HRMP_MAX_INBOUND_CHANNELS_BOUND`], but for outbound channels.
46pub 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
74/// A weight info that is only suitable for testing.
75pub 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/// A description of a request to open an HRMP channel.
117#[derive(Encode, Decode, TypeInfo)]
118pub struct HrmpOpenChannelRequest {
119	/// Indicates if this request was confirmed by the recipient.
120	pub confirmed: bool,
121	/// NOTE: this field is deprecated. Channel open requests became non-expiring and this value
122	/// became unused.
123	pub _age: SessionIndex,
124	/// The amount that the sender supplied at the time of creation of this request.
125	pub sender_deposit: Balance,
126	/// The maximum message size that could be put into the channel.
127	pub max_message_size: u32,
128	/// The maximum number of messages that can be pending in the channel at once.
129	pub max_capacity: u32,
130	/// The maximum total size of the messages that can be pending in the channel at once.
131	pub max_total_size: u32,
132}
133
134/// A metadata of an HRMP channel.
135#[derive(Encode, Decode, TypeInfo)]
136#[cfg_attr(test, derive(Debug))]
137pub struct HrmpChannel {
138	// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct
139	// requires special treatment.
140	//
141	// A parachain requested this struct can only depend on the subset of this struct.
142	// Specifically, only a first few fields can be depended upon (See `AbridgedHrmpChannel`).
143	// These fields cannot be changed without corresponding migration of parachains.
144	/// The maximum number of messages that can be pending in the channel at once.
145	pub max_capacity: u32,
146	/// The maximum total size of the messages that can be pending in the channel at once.
147	pub max_total_size: u32,
148	/// The maximum message size that could be put into the channel.
149	pub max_message_size: u32,
150	/// The current number of messages pending in the channel.
151	/// Invariant: should be less or equal to `max_capacity`.s`.
152	pub msg_count: u32,
153	/// The total size in bytes of all message payloads in the channel.
154	/// Invariant: should be less or equal to `max_total_size`.
155	pub total_size: u32,
156	/// A head of the Message Queue Chain for this channel. Each link in this chain has a form:
157	/// `(prev_head, B, H(M))`, where
158	/// - `prev_head`: is the previous value of `mqc_head` or zero if none.
159	/// - `B`: is the [relay-chain] block number in which a message was appended
160	/// - `H(M)`: is the hash of the message being appended.
161	/// This value is initialized to a special value that consists of all zeroes which indicates
162	/// that no messages were previously added.
163	pub mqc_head: Option<Hash>,
164	/// The amount that the sender supplied as a deposit when opening this channel.
165	pub sender_deposit: Balance,
166	/// The amount that the recipient supplied as a deposit when accepting opening this channel.
167	pub recipient_deposit: Balance,
168}
169
170/// An error returned by [`Pallet::check_hrmp_watermark`] that indicates an acceptance criteria
171/// check didn't pass.
172pub(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
178/// An error returned by [`Pallet::check_outbound_hrmp`] that indicates an acceptance criteria check
179/// didn't pass.
180pub(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		/// The outer event type.
264		#[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		/// The origin that can perform "force" actions on channels.
272		type ChannelManager: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
273
274		/// Holds the channel deposits when this pallet is its own [`Config::DepositProvider`].
275		///
276		/// NOTE that this Currency instance will be charged with the amounts defined in the
277		/// `Configuration` pallet. Specifically, that means that the `Balance` of the `Currency`
278		/// implementation should be the same as `Balance` as used in the `Configuration`.
279		type Currency: ReservableCurrency<Self::AccountId>;
280
281		/// Where the channel deposits are held, see [`deposits`]. `Pallet<Self>` holds them in
282		/// [`Config::Currency`].
283		type DepositProvider: ChannelDepositProvider<OnDepositSet = Pallet<Self>>;
284
285		/// The default channel size and capacity to use when opening a channel to a system
286		/// parachain.
287		type DefaultChannelSizeAndCapacityWithSystem: Get<(u32, u32)>;
288
289		/// Means of converting an `Xcm` into a `VersionedXcm`. This pallet sends HRMP XCM
290		/// notifications to the channel-related parachains, while the `WrapVersion` implementation
291		/// attempts to wrap them into the most suitable XCM version for the destination parachain.
292		///
293		/// NOTE: For example, `pallet_xcm` provides an accurate implementation (recommended), or
294		/// the default `()` implementation uses the latest XCM version for all parachains.
295		type VersionWrapper: xcm::WrapVersion;
296
297		/// Something that provides the weight of this pallet.
298		type WeightInfo: WeightInfo;
299	}
300
301	#[pallet::event]
302	#[pallet::generate_deposit(pub(super) fn deposit_event)]
303	pub enum Event<T: Config> {
304		/// Open HRMP channel requested.
305		OpenChannelRequested {
306			sender: ParaId,
307			recipient: ParaId,
308			proposed_max_capacity: u32,
309			proposed_max_message_size: u32,
310		},
311		/// An HRMP channel request sent by the receiver was canceled by either party.
312		OpenChannelCanceled { by_parachain: ParaId, channel_id: HrmpChannelId },
313		/// Open HRMP channel accepted.
314		OpenChannelAccepted { sender: ParaId, recipient: ParaId },
315		/// HRMP channel closed.
316		ChannelClosed { by_parachain: ParaId, channel_id: HrmpChannelId },
317		/// An HRMP channel was opened via Root origin.
318		HrmpChannelForceOpened {
319			sender: ParaId,
320			recipient: ParaId,
321			proposed_max_capacity: u32,
322			proposed_max_message_size: u32,
323		},
324		/// An HRMP channel was opened with a system chain.
325		HrmpSystemChannelOpened {
326			sender: ParaId,
327			recipient: ParaId,
328			proposed_max_capacity: u32,
329			proposed_max_message_size: u32,
330		},
331		/// An HRMP channel's deposits were updated.
332		OpenChannelDepositsUpdated { sender: ParaId, recipient: ParaId },
333	}
334
335	#[pallet::error]
336	pub enum Error<T> {
337		/// The sender tried to open a channel to themselves.
338		OpenHrmpChannelToSelf,
339		/// The recipient is not a valid para.
340		OpenHrmpChannelInvalidRecipient,
341		/// The requested capacity is zero.
342		OpenHrmpChannelZeroCapacity,
343		/// The requested capacity exceeds the global limit.
344		OpenHrmpChannelCapacityExceedsLimit,
345		/// The requested maximum message size is 0.
346		OpenHrmpChannelZeroMessageSize,
347		/// The open request requested the message size that exceeds the global limit.
348		OpenHrmpChannelMessageSizeExceedsLimit,
349		/// The channel already exists
350		OpenHrmpChannelAlreadyExists,
351		/// There is already a request to open the same channel.
352		OpenHrmpChannelAlreadyRequested,
353		/// The sender already has the maximum number of allowed outbound channels.
354		OpenHrmpChannelLimitExceeded,
355		/// The channel from the sender to the origin doesn't exist.
356		AcceptHrmpChannelDoesntExist,
357		/// The channel is already confirmed.
358		AcceptHrmpChannelAlreadyConfirmed,
359		/// The recipient already has the maximum number of allowed inbound channels.
360		AcceptHrmpChannelLimitExceeded,
361		/// The origin tries to close a channel where it is neither the sender nor the recipient.
362		CloseHrmpChannelUnauthorized,
363		/// The channel to be closed doesn't exist.
364		CloseHrmpChannelDoesntExist,
365		/// The channel close request is already requested.
366		CloseHrmpChannelAlreadyUnderway,
367		/// Canceling is requested by neither the sender nor recipient of the open channel request.
368		CancelHrmpOpenChannelUnauthorized,
369		/// The open request doesn't exist.
370		OpenHrmpChannelDoesntExist,
371		/// Cannot cancel an HRMP open channel request because it is already confirmed.
372		OpenHrmpChannelAlreadyConfirmed,
373		/// The provided witness data is wrong.
374		WrongWitness,
375		/// The channel between these two chains cannot be authorized.
376		ChannelCreationNotAuthorized,
377	}
378
379	/// The set of pending HRMP open channel requests.
380	///
381	/// The set is accompanied by a list for iteration.
382	///
383	/// Invariant:
384	/// - There are no channels that exists in list but not in the set and vice versa.
385	#[pallet::storage]
386	pub type HrmpOpenChannelRequests<T: Config> =
387		StorageMap<_, Twox64Concat, HrmpChannelId, HrmpOpenChannelRequest>;
388
389	// NOTE: could become bounded, but we don't have a global maximum for this.
390	// `HRMP_MAX_INBOUND_CHANNELS_BOUND` are per parachain, while this storage tracks the
391	// global state.
392	#[pallet::storage]
393	pub type HrmpOpenChannelRequestsList<T: Config> =
394		StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
395
396	/// This mapping tracks how many open channel requests are initiated by a given sender para.
397	/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items that has
398	/// `(X, _)` as the number of `HrmpOpenChannelRequestCount` for `X`.
399	#[pallet::storage]
400	pub type HrmpOpenChannelRequestCount<T: Config> =
401		StorageMap<_, Twox64Concat, ParaId, u32, ValueQuery>;
402
403	/// This mapping tracks how many open channel requests were accepted by a given recipient para.
404	/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items `(_, X)` with
405	/// `confirmed` set to true, as the number of `HrmpAcceptedChannelRequestCount` for `X`.
406	#[pallet::storage]
407	pub type HrmpAcceptedChannelRequestCount<T: Config> =
408		StorageMap<_, Twox64Concat, ParaId, u32, ValueQuery>;
409
410	/// A set of pending HRMP close channel requests that are going to be closed during the session
411	/// change. Used for checking if a given channel is registered for closure.
412	///
413	/// The set is accompanied by a list for iteration.
414	///
415	/// Invariant:
416	/// - There are no channels that exists in list but not in the set and vice versa.
417	#[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	/// The HRMP watermark associated with each para.
425	/// Invariant:
426	/// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a
427	///   session.
428	#[pallet::storage]
429	pub type HrmpWatermarks<T: Config> = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor<T>>;
430
431	/// HRMP channel data associated with each para.
432	/// Invariant:
433	/// - each participant in the channel should satisfy `Paras::is_valid_para(P)` within a session.
434	#[pallet::storage]
435	pub type HrmpChannels<T: Config> = StorageMap<_, Twox64Concat, HrmpChannelId, HrmpChannel>;
436
437	/// Ingress/egress indexes allow to find all the senders and receivers given the opposite side.
438	/// I.e.
439	///
440	/// (a) ingress index allows to find all the senders for a given recipient.
441	/// (b) egress index allows to find all the recipients for a given sender.
442	///
443	/// Invariants:
444	/// - for each ingress index entry for `P` each item `I` in the index should present in
445	///   `HrmpChannels` as `(I, P)`.
446	/// - for each egress index entry for `P` each item `E` in the index should present in
447	///   `HrmpChannels` as `(P, E)`.
448	/// - there should be no other dangling channels in `HrmpChannels`.
449	/// - the vectors are sorted.
450	#[pallet::storage]
451	pub type HrmpIngressChannelsIndex<T: Config> =
452		StorageMap<_, Twox64Concat, ParaId, Vec<ParaId>, ValueQuery>;
453
454	// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
455	// the format will require migration of parachains.
456	#[pallet::storage]
457	pub type HrmpEgressChannelsIndex<T: Config> =
458		StorageMap<_, Twox64Concat, ParaId, Vec<ParaId>, ValueQuery>;
459
460	/// Storage for the messages for each channel.
461	/// Invariant: cannot be non-empty if the corresponding channel in `HrmpChannels` is `None`.
462	#[pallet::storage]
463	pub type HrmpChannelContents<T: Config> = StorageMap<
464		_,
465		Twox64Concat,
466		HrmpChannelId,
467		Vec<InboundHrmpMessage<BlockNumberFor<T>>>,
468		ValueQuery,
469	>;
470
471	/// Maintains a mapping that can be used to answer the question: What paras sent a message at
472	/// the given block number for a given receiver. Invariants:
473	/// - The inner `Vec<ParaId>` is never empty.
474	/// - The inner `Vec<ParaId>` cannot store two same `ParaId`.
475	/// - The outer vector is sorted ascending by block number and cannot store two items with the
476	///   same block number.
477	#[pallet::storage]
478	pub type HrmpChannelDigests<T: Config> =
479		StorageMap<_, Twox64Concat, ParaId, Vec<(BlockNumberFor<T>, Vec<ParaId>)>, ValueQuery>;
480
481	/// Preopen the given HRMP channels.
482	///
483	/// The values in the tuple corresponds to
484	/// `(sender, recipient, max_capacity, max_message_size)`, i.e. similar to `init_open_channel`.
485	/// In fact, the initialization is performed as if the `init_open_channel` and
486	/// `accept_open_channel` were called with the respective parameters and the session change take
487	///  place.
488	///
489	/// As such, each channel initializer should satisfy the same constraints, namely:
490	///
491	/// 1. `max_capacity` and `max_message_size` should be within the limits set by the
492	///    configuration pallet.
493	/// 2. `sender` and `recipient` must be valid paras.
494	#[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		/// Initiate opening a channel from a parachain to a given recipient with given channel
512		/// parameters.
513		///
514		/// - `proposed_max_capacity` - specifies how many messages can be in the channel at once.
515		/// - `proposed_max_message_size` - specifies the maximum size of the messages.
516		///
517		/// These numbers are a subject to the relay-chain configuration limits.
518		///
519		/// The channel can be opened only after the recipient confirms it and only on a session
520		/// change.
521		#[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			// `OpenChannelRequested` is emitted once the deposit is set and the request recorded.
534			Self::init_open_channel(
535				origin,
536				recipient,
537				proposed_max_capacity,
538				proposed_max_message_size,
539			)
540		}
541
542		/// Accept a pending open channel request from the given sender.
543		///
544		/// The channel will be opened only on the next session boundary.
545		#[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			// `OpenChannelAccepted` is emitted once the deposit is set and the request confirmed.
553			Self::accept_open_channel(origin, sender)
554		}
555
556		/// Initiate unilateral closing of a channel. The origin must be either the sender or the
557		/// recipient in the channel being closed.
558		///
559		/// The closure can only happen on a session change.
560		#[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		/// This extrinsic triggers the cleanup of all the HRMP storage items that a para may have.
573		/// Normally this happens once per session, but this allows you to trigger the cleanup
574		/// immediately for a specific parachain.
575		///
576		/// Number of inbound and outbound channels for `para` must be provided as witness data.
577		///
578		/// Origin must be the `ChannelManager`.
579		#[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(&para);
601			Ok(())
602		}
603
604		/// Force process HRMP open channel requests.
605		///
606		/// If there are pending HRMP open channel requests, you can use this function to process
607		/// all of those requests immediately.
608		///
609		/// Total number of opening channels must be provided as witness data.
610		///
611		/// Origin must be the `ChannelManager`.
612		#[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		/// Force process HRMP close channel requests.
629		///
630		/// If there are pending HRMP close channel requests, you can use this function to process
631		/// all of those requests immediately.
632		///
633		/// Total number of closing channels must be provided as witness data.
634		///
635		/// Origin must be the `ChannelManager`.
636		#[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		/// This cancels a pending open channel request. It can be canceled by either of the sender
652		/// or the recipient for that request. The origin must be either of those.
653		///
654		/// The cancellation happens immediately. It is not possible to cancel the request if it is
655		/// already accepted.
656		///
657		/// Total number of open requests (i.e. `HrmpOpenChannelRequestsList`) must be provided as
658		/// witness data.
659		#[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		/// Open a channel from a `sender` to a `recipient` `ParaId`. Although opened by governance,
681		/// the `max_capacity` and `max_message_size` are still subject to the Relay Chain's
682		/// configured limits.
683		///
684		/// Expected use is when one (and only one) of the `ParaId`s involved in the channel is
685		/// governed by the system, e.g. a system parachain.
686		///
687		/// Origin must be the `ChannelManager`.
688		#[pallet::call_index(7)]
689		#[pallet::weight(
690			// A cancel, an init and an accept each ask the provider.
691			<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			// Guard against a common footgun where someone makes a channel request to a system
704			// parachain and then makes a proposal to open the channel via governance, which fails
705			// because `init_open_channel` fails if there is an existing request. This check will
706			// clear an existing request such that `init_open_channel` should otherwise succeed.
707			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			// Now we proceed with normal init/accept, except that we set `no_deposit` to true such
717			// that it will not require deposits from either member.
718			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		/// Establish an HRMP channel between two system chains. If the channel does not already
731		/// exist, the transaction fees will be refunded to the caller. The system does not take
732		/// deposits for channels between system chains, and automatically sets the message number
733		/// and size limits to the maximum allowed by the network's configuration.
734		///
735		/// Arguments:
736		///
737		/// - `sender`: A system chain, `ParaId`.
738		/// - `recipient`: A system chain, `ParaId`.
739		///
740		/// Any signed origin can call this function, but _both_ inputs MUST be system chains. If
741		/// the channel does not exist yet, there is no fee.
742		#[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			// both chains must be system
752			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		/// Update the deposits held for an HRMP channel to the latest `Configuration`. Channels
775		/// with system chains do not require a deposit.
776		///
777		/// Arguments:
778		///
779		/// - `sender`: A chain, `ParaId`.
780		/// - `recipient`: A chain, `ParaId`.
781		///
782		/// Any signed origin can call this function.
783		#[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			// nothing to update
801			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			// `OpenChannelDepositsUpdated` is emitted once the deposits are set and recorded.
809			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		/// Establish a bidirectional HRMP channel between a parachain and a system chain.
824		///
825		/// Arguments:
826		///
827		/// - `target_system_chain`: A system chain, `ParaId`.
828		///
829		/// The origin needs to be the parachain origin.
830		#[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			// create bidirectional channel
844			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
892/// Routines and getters related to HRMP.
893impl<T: Config> Pallet<T> {
894	/// Block initialization logic, called by initializer.
895	pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
896		Weight::zero()
897	}
898
899	/// Block finalization logic, called by initializer.
900	pub(crate) fn initializer_finalize() {}
901
902	/// Called by the initializer to note that a new session has started.
903	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(&notification.prev_config, outgoing_paras);
908		Self::process_hrmp_open_channel_requests(&notification.prev_config);
909		Self::process_hrmp_close_channel_requests();
910		// TODO(ahm-v2): add `DepositProvider::weight_of_try_set_deposit` per release made above.
911		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	/// Iterate over all paras that were noted for offboarding and remove all the data
920	/// associated with them.
921	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			// we need a few extra bits of data to weigh this -- all of this is read internally
930			// anyways, so no overhead.
931			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	// Go over the HRMP open channel requests and remove all in which offboarding paras participate.
944	//
945	// This will also perform the refunds for the counterparty if it doesn't offboard.
946	pub(crate) fn clean_open_channel_requests(
947		config: &HostConfiguration<BlockNumberFor<T>>,
948		outgoing: &[ParaId],
949	) -> Weight {
950		// First collect all the channel ids of the open requests in which there is at least one
951		// party presents in the outgoing list.
952		//
953		// Both the open channel request list and outgoing list are expected to be small enough.
954		// In the most common case there will be only single outgoing para.
955		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		// Then iterate over all open requests to be removed, pull them out of the set and perform
962		// the refunds if applicable.
963		for req_id in go {
964			let req_data = match HrmpOpenChannelRequests::<T>::take(&req_id) {
965				Some(req_data) => req_data,
966				None => {
967					// Can't normally happen but no need to panic.
968					continue;
969				},
970			};
971
972			// Return the deposit of the sender, but only if it is not the para being offboarded.
973			let unless_offboarding =
974				|para: ParaId, deposit: Balance| (!outgoing.contains(&para)).then_some(deposit);
975			let sender_deposit = unless_offboarding(req_id.sender, req_data.sender_deposit);
976
977			// If the request was confirmed, then it means it was confirmed in the finished session.
978			// Therefore, the config's hrmp_recipient_deposit represents the actual value of the
979			// deposit.
980			//
981			// We still want to refund the deposit only if the para is not being offboarded.
982			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	/// Remove all storage entries associated with the given para.
995	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	/// Iterate over all open channel requests and:
1015	///
1016	/// - prune the stale requests
1017	/// - enact the confirmed requests
1018	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		// iterate the vector starting from the end making our way to the beginning. This way we
1025		// can leverage `swap_remove` to efficiently remove an item during iteration.
1026		let mut idx = open_req_channels.len();
1027		loop {
1028			// bail if we've iterated over all items.
1029			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	/// Iterate over all close channel requests unconditionally closing the channels.
1085	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	/// Close and remove the designated HRMP channel.
1094	///
1095	/// This includes returning the deposits.
1096	///
1097	/// This function is idempotent, meaning that after the first application it should have no
1098	/// effect (i.e. it won't return the deposits twice).
1099	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	/// Check that the candidate of the given recipient controls the HRMP watermark properly.
1121	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		// First, check where the watermark CANNOT legally land.
1127		//
1128		// (a) For ensuring that messages are eventually processed, we require each parablock's
1129		//     watermark to be greater than the last one. The exception to this is if the previous
1130		//     watermark was already equal to the current relay-parent number.
1131		//
1132		// (b) However, a parachain cannot read into "the future", therefore the watermark should
1133		//     not be greater than the relay-chain context block which the parablock refers to.
1134		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		// Second, check where the watermark CAN land. It's one of the following:
1159		//
1160		// (a) The relay parent block number (checked above).
1161		// (b) A relay-chain block in which this para received at least one message (checked here)
1162		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	/// Returns HRMP watermarks of previously sent messages to a given para.
1175	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		// The current watermark will remain valid until updated.
1182		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				// the messages must be sorted in ascending order and there must be no two messages
1210				// sent to the same recipient. Thus we can check that every recipient is strictly
1211				// greater than the previous one.
1212				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	/// Returns remaining outbound channels capacity in messages and in bytes per recipient para.
1257	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		// sift through the incoming messages digest to collect the paras that sent at least one
1279		// message to this parachain between the old and new watermarks.
1280		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		// having all senders we can trivially find out the channels which we need to prune.
1295		let channels_to_prune =
1296			senders.into_iter().map(|sender| HrmpChannelId { sender, recipient });
1297		for channel_id in channels_to_prune {
1298			// prune each channel up to the new watermark keeping track how many messages we removed
1299			// and what is the total byte size of them.
1300			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			// update the channel metadata.
1319			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	/// Process the outbound HRMP messages by putting them into the appropriate recipient queues.
1331	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					// apparently, that since acceptance of this candidate the recipient was
1341					// offboarded and the channel no longer exists.
1342					continue;
1343				},
1344			};
1345
1346			let inbound = InboundHrmpMessage { sent_at: now, data: out_msg.data };
1347
1348			// book keeping
1349			channel.msg_count += 1;
1350			channel.total_size += inbound.data.len() as u32;
1351
1352			// compute the new MQC head of the channel
1353			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			// The digests are sorted in ascending by block number order. There are only two
1365			// possible scenarios here ("the current" is the block of candidate's inclusion):
1366			//
1367			// (a) It's the first time anybody sends a message to this recipient within this block.
1368			//     In this case, the digest vector would be empty or the block number of the latest
1369			//     entry is smaller than the current.
1370			//
1371			// (b) Somebody has already sent a message within the current block. That means that
1372			//     the block number of the latest entry is equal to the current.
1373			//
1374			// Note that having the latest entry greater than the current block number is a logical
1375			// error.
1376			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	/// Initiate opening a channel from a parachain to a given recipient with given channel
1391	/// parameters. If neither chain is part of the system, then a deposit from the `Configuration`
1392	/// will be required for `origin` (the sender) upon opening the request and the `recipient` upon
1393	/// accepting it.
1394	///
1395	/// Basically the same as [`hrmp_init_open_channel`](Pallet::hrmp_init_open_channel) but
1396	/// intended for calling directly from other pallets rather than dispatched.
1397	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	/// Second half of [`Self::init_open_channel`], run once the sender's deposit is taken.
1453	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	/// Accept a pending open channel request from the given sender.
1500	///
1501	/// Basically the same as [`hrmp_accept_open_channel`](Pallet::hrmp_accept_open_channel) but
1502	/// intended for calling directly from other pallets rather than dispatched.
1503	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		// check if by accepting this open channel request, this parachain would exceed the
1510		// number of inbound channels.
1511		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	/// Second half of [`Self::accept_open_channel`], run once the recipient's deposit is taken.
1530	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		// persist the updated open channel request and then increment the number of accepted
1542		// channels.
1543		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	/// Second half of [`Self::poke_channel_deposits`], run once both deposits are changed.
1561	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		// check if the origin is allowed to close the channel.
1586		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		// Remove the request by the channel id and sync the accompanying list with the set.
1593		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		// Don't decrease `HrmpAcceptedChannelRequestCount` because we don't consider confirmed
1602		// requests here.
1603
1604		// Unreserve the sender's deposit. The recipient could not have left their deposit because
1605		// we ensured that the request is not confirmed.
1606		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		// check if the origin is allowed to close the channel.
1613		ensure!(channel_id.is_participant(origin), Error::<T>::CloseHrmpChannelUnauthorized);
1614
1615		// check if the channel requested to close does exist.
1616		ensure!(
1617			HrmpChannels::<T>::get(&channel_id).is_some(),
1618			Error::<T>::CloseHrmpChannelDoesntExist,
1619		);
1620
1621		// check that there is no outstanding close request for this channel
1622		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	/// Returns the list of MQC heads for the inbound channels of the given recipient para paired
1652	/// with the sender para ids. This vector is sorted ascending by the para id and doesn't contain
1653	/// multiple entries with the same sender.
1654	#[cfg(test)]
1655	fn hrmp_mqc_heads(recipient: ParaId) -> Vec<(ParaId, Hash)> {
1656		let sender_set = HrmpIngressChannelsIndex::<T>::get(&recipient);
1657
1658		// The ingress channels vector is sorted, thus `mqc_heads` is sorted as well.
1659		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	/// Returns contents of all channels addressed to the given recipient. Channels that have no
1672	/// messages in them are also included.
1673	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	/// Decreases the open channel request count for the given sender. If the value reaches zero
1691	/// it is removed completely.
1692	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	/// Decreases the accepted channel request count for the given sender. If the value reaches
1702	/// zero it is removed completely.
1703	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		// verify that the set of keys in `HrmpOpenChannelRequestCount` corresponds to the set
1735		// of _senders_ in `HrmpOpenChannelRequests`.
1736		//
1737		// having ensured that, we can go ahead and go over all counts and verify that they match.
1738		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		// The same as above, but for accepted channel request count. Note that we are interested
1754		// only in confirmed open requests.
1755		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		// A HRMP watermark can be None for an onboarded parachain. However, an offboarded parachain
1777		// cannot have an HRMP watermark: it should've been cleanup.
1778		assert_contains_only_onboarded(
1779			HrmpWatermarks::<T>::iter().map(|(k, _)| k).collect::<Vec<_>>(),
1780			"HRMP watermarks should contain only onboarded paras",
1781		);
1782
1783		// An entry in `HrmpChannels` indicates that the channel is open. Only open channels can
1784		// have contents.
1785		for (non_empty_channel, contents) in HrmpChannelContents::<T>::iter() {
1786			assert!(HrmpChannels::<T>::contains_key(&non_empty_channel));
1787
1788			// pedantic check: there should be no empty vectors in storage, those should be modeled
1789			// by a removed kv pair.
1790			assert!(!contents.is_empty());
1791		}
1792
1793		// Senders and recipients must be onboarded. Otherwise, all channels associated with them
1794		// are removed.
1795		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		// Check the docs for `HrmpIngressChannelsIndex` and `HrmpEgressChannelsIndex` in decl
1803		// storage to get an index what are the channel mappings indexes.
1804		//
1805		// Here, from indexes.
1806		//
1807		// ingress         egress
1808		//
1809		// a -> [x, y]     x -> [a, b]
1810		// b -> [x, z]     y -> [a]
1811		//                 z -> [b]
1812		//
1813		// we derive a list of channels they represent.
1814		//
1815		//   (a, x)         (a, x)
1816		//   (a, y)         (a, y)
1817		//   (b, x)         (b, x)
1818		//   (b, z)         (b, z)
1819		//
1820		// and then that we compare that to the channel list in the `HrmpChannels`.
1821		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 that items are in **strictly** ascending order. The strictness also implies
1846			// there are no duplicates.
1847			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				// check for duplicates. For that we sort the vector, then perform deduplication.
1853				// if the vector stayed the same, there are no duplicates.
1854				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	/// Wraps HRMP XCM notifications to the most suitable XCM version for the destination para.
1868	/// If the XCM version is unknown, the latest XCM version is used as a best effort.
1869	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		// Return a closure that can prepare notifications.
1879		move |dest| {
1880			// Attempt to wrap the notification for the destination parachain.
1881			T::VersionWrapper::wrap_version(
1882				&Location::new(0, [Junction::Parachain(dest.into())]),
1883				notification(),
1884			)
1885			.unwrap_or_else(|_| {
1886				// As a best effort, if we cannot resolve the version, fallback to using the latest
1887				// version.
1888				VersionedXcm::from(notification())
1889			})
1890			.encode()
1891		}
1892	}
1893
1894	/// Sends/enqueues notification to the destination parachain.
1895	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		// prepare notification
1902		let notification_bytes = notification_bytes_for(dest);
1903
1904		// try to enqueue
1905		if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) =
1906			dmp::Pallet::<T>::queue_downward_message(&config, dest, notification_bytes)
1907		{
1908			// this should never happen unless the max downward message size is configured to a
1909			// jokingly small number.
1910			log::error!(
1911				target: LOG_TARGET,
1912				"sending '{log_label}::notification_bytes' failed."
1913			);
1914			debug_assert!(false);
1915		}
1916	}
1917}