bridge_hub_common/
message_queue.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//! Runtime configuration for MessageQueue pallet
16use codec::{Decode, Encode, MaxEncodedLen};
17use core::marker::PhantomData;
18use cumulus_primitives_core::{AggregateMessageOrigin as CumulusAggregateMessageOrigin, ParaId};
19use frame_support::{
20	traits::{ProcessMessage, ProcessMessageError, QueueFootprint, QueuePausedQuery},
21	weights::WeightMeter,
22};
23use pallet_message_queue::OnQueueChanged;
24use scale_info::TypeInfo;
25use snowbridge_core::ChannelId;
26use xcm::latest::prelude::{Junction, Location};
27
28/// The aggregate origin of an inbound message.
29/// This is specialized for BridgeHub, as the snowbridge-outbound-queue-pallet is also using
30/// the shared MessageQueue pallet.
31#[derive(Encode, Decode, Copy, MaxEncodedLen, Clone, Eq, PartialEq, TypeInfo, Debug)]
32pub enum AggregateMessageOrigin {
33	/// The message came from the para-chain itself.
34	Here,
35	/// The message came from the relay-chain.
36	///
37	/// This is used by the DMP queue.
38	Parent,
39	/// The message came from a sibling para-chain.
40	///
41	/// This is used by the HRMP queue.
42	Sibling(ParaId),
43	/// The message came from a snowbridge channel.
44	///
45	/// This is used by Snowbridge inbound queue.
46	Snowbridge(ChannelId),
47}
48
49impl From<AggregateMessageOrigin> for Location {
50	fn from(origin: AggregateMessageOrigin) -> Self {
51		use AggregateMessageOrigin::*;
52		match origin {
53			Here => Location::here(),
54			Parent => Location::parent(),
55			Sibling(id) => Location::new(1, Junction::Parachain(id.into())),
56			// NOTE: We don't need this conversion for Snowbridge. However, we have to
57			// implement it anyway as xcm_builder::ProcessXcmMessage requires it.
58			Snowbridge(_) => Location::default(),
59		}
60	}
61}
62
63impl From<CumulusAggregateMessageOrigin> for AggregateMessageOrigin {
64	fn from(origin: CumulusAggregateMessageOrigin) -> Self {
65		match origin {
66			CumulusAggregateMessageOrigin::Here => Self::Here,
67			CumulusAggregateMessageOrigin::Parent => Self::Parent,
68			CumulusAggregateMessageOrigin::Sibling(id) => Self::Sibling(id),
69		}
70	}
71}
72
73#[cfg(feature = "runtime-benchmarks")]
74impl From<u32> for AggregateMessageOrigin {
75	fn from(x: u32) -> Self {
76		match x {
77			0 => Self::Here,
78			1 => Self::Parent,
79			p => Self::Sibling(ParaId::from(p)),
80		}
81	}
82}
83
84/// Routes messages to either the XCMP or Snowbridge processor.
85pub struct BridgeHubMessageRouter<XcmpProcessor, SnowbridgeProcessor>(
86	PhantomData<(XcmpProcessor, SnowbridgeProcessor)>,
87)
88where
89	XcmpProcessor: ProcessMessage<Origin = AggregateMessageOrigin>,
90	SnowbridgeProcessor: ProcessMessage<Origin = AggregateMessageOrigin>;
91
92impl<XcmpProcessor, SnowbridgeProcessor> ProcessMessage
93	for BridgeHubMessageRouter<XcmpProcessor, SnowbridgeProcessor>
94where
95	XcmpProcessor: ProcessMessage<Origin = AggregateMessageOrigin>,
96	SnowbridgeProcessor: ProcessMessage<Origin = AggregateMessageOrigin>,
97{
98	type Origin = AggregateMessageOrigin;
99
100	fn process_message(
101		message: &[u8],
102		origin: Self::Origin,
103		meter: &mut WeightMeter,
104		id: &mut [u8; 32],
105	) -> Result<bool, ProcessMessageError> {
106		use AggregateMessageOrigin::*;
107		match origin {
108			Here | Parent | Sibling(_) =>
109				XcmpProcessor::process_message(message, origin, meter, id),
110			Snowbridge(_) => SnowbridgeProcessor::process_message(message, origin, meter, id),
111		}
112	}
113}
114
115/// Narrow the scope of the `Inner` query from `AggregateMessageOrigin` to `ParaId`.
116///
117/// All non-`Sibling` variants will be ignored.
118pub struct NarrowOriginToSibling<Inner>(PhantomData<Inner>);
119impl<Inner: QueuePausedQuery<ParaId>> QueuePausedQuery<AggregateMessageOrigin>
120	for NarrowOriginToSibling<Inner>
121{
122	fn is_paused(origin: &AggregateMessageOrigin) -> bool {
123		match origin {
124			AggregateMessageOrigin::Sibling(id) => Inner::is_paused(id),
125			_ => false,
126		}
127	}
128}
129
130impl<Inner: OnQueueChanged<ParaId>> OnQueueChanged<AggregateMessageOrigin>
131	for NarrowOriginToSibling<Inner>
132{
133	fn on_queue_changed(origin: AggregateMessageOrigin, fp: QueueFootprint) {
134		if let AggregateMessageOrigin::Sibling(id) = origin {
135			Inner::on_queue_changed(id, fp)
136		}
137	}
138}
139
140/// Convert a sibling `ParaId` to an `AggregateMessageOrigin`.
141pub struct ParaIdToSibling;
142impl sp_runtime::traits::Convert<ParaId, AggregateMessageOrigin> for ParaIdToSibling {
143	fn convert(para_id: ParaId) -> AggregateMessageOrigin {
144		AggregateMessageOrigin::Sibling(para_id)
145	}
146}