From a1c6502d9a9e8de00b621cd2431d4d7f4de17a92 Mon Sep 17 00:00:00 2001
From: Branislav Kontur <bkontur@gmail.com>
Date: Mon, 13 Mar 2023 15:11:10 +0100
Subject: [PATCH] Backport xcm bridging extensions to the bridge repo (#1813)

* Backport xcm bridging extensions to the bridge repo

* Fixes

* Fixes
---
 bridges/bin/runtime-common/src/lib.rs         |   3 +
 bridges/bin/runtime-common/src/messages.rs    |  10 +-
 .../src/messages_xcm_extension.rs             | 181 ++++++++++++++++++
 3 files changed, 189 insertions(+), 5 deletions(-)
 create mode 100644 bridges/bin/runtime-common/src/messages_xcm_extension.rs

diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs
index d9c87049077..ed486c04abc 100644
--- a/bridges/bin/runtime-common/src/lib.rs
+++ b/bridges/bin/runtime-common/src/lib.rs
@@ -28,6 +28,7 @@ pub mod messages;
 pub mod messages_api;
 pub mod messages_benchmarking;
 pub mod messages_call_ext;
+pub mod messages_xcm_extension;
 pub mod parachains_benchmarking;
 pub mod refund_relayer_extension;
 
@@ -37,6 +38,8 @@ mod mock;
 #[cfg(feature = "integrity-test")]
 pub mod integrity;
 
+const LOG_TARGET_BRIDGE_DISPATCH: &str = "runtime::bridge-dispatch";
+
 /// A duplication of the `FilterCall` trait.
 ///
 /// We need this trait in order to be able to implement it for the messages pallet,
diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs
index 4eb44ea85ed..4493ac66742 100644
--- a/bridges/bin/runtime-common/src/messages.rs
+++ b/bridges/bin/runtime-common/src/messages.rs
@@ -497,7 +497,7 @@ pub mod target {
 					let weight = XcmWeigher::weight(&mut payload.xcm.1);
 					let weight = weight.unwrap_or_else(|e| {
 						log::debug!(
-							target: "runtime::bridge-dispatch",
+							target: crate::LOG_TARGET_BRIDGE_DISPATCH,
 							"Failed to compute dispatch weight of incoming XCM message {:?}/{}: {:?}",
 							message.key.lane_id,
 							message.key.nonce,
@@ -525,7 +525,7 @@ pub mod target {
 				let FromBridgedChainMessagePayload { xcm: (location, xcm), weight: weight_limit } =
 					message.data.payload?;
 				log::trace!(
-					target: "runtime::bridge-dispatch",
+					target: crate::LOG_TARGET_BRIDGE_DISPATCH,
 					"Going to execute message {:?} (weight limit: {:?}): {:?} {:?}",
 					message_id,
 					weight_limit,
@@ -551,7 +551,7 @@ pub mod target {
 			match xcm_outcome {
 				Ok(outcome) => {
 					log::trace!(
-						target: "runtime::bridge-dispatch",
+						target: crate::LOG_TARGET_BRIDGE_DISPATCH,
 						"Incoming message {:?} dispatched with result: {:?}",
 						message_id,
 						outcome,
@@ -560,7 +560,7 @@ pub mod target {
 						Ok(_weight) => (),
 						Err(e) => {
 							log::error!(
-								target: "runtime::bridge-dispatch",
+								target: crate::LOG_TARGET_BRIDGE_DISPATCH,
 								"Incoming message {:?} was not dispatched, error: {:?}",
 								message_id,
 								e,
@@ -570,7 +570,7 @@ pub mod target {
 				},
 				Err(e) => {
 					log::error!(
-						target: "runtime::bridge-dispatch",
+						target: crate::LOG_TARGET_BRIDGE_DISPATCH,
 						"Incoming message {:?} was not dispatched, codec error: {:?}",
 						message_id,
 						e,
diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs
new file mode 100644
index 00000000000..7163d8a5357
--- /dev/null
+++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs
@@ -0,0 +1,181 @@
+// Copyright 2023 Parity Technologies (UK) Ltd.
+// This file is part of Parity Bridges Common.
+
+// Parity Bridges Common is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity Bridges Common is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Module provides utilities for easier XCM handling, e.g:
+//! [`XcmExecutor`] -> [`MessageSender`] -> <outbound message queue>
+//!                                             |
+//!                                          <relayer>
+//!                                             |
+//! [`XcmRouter`] <- [`MessageDispatch`] <- <inbound message queue>
+
+use bp_messages::{
+	source_chain::MessagesBridge,
+	target_chain::{DispatchMessage, MessageDispatch},
+	LaneId,
+};
+use bp_runtime::{messages::MessageDispatchResult, AccountIdOf, Chain};
+use codec::{Decode, Encode};
+use frame_support::{dispatch::Weight, traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound};
+use scale_info::TypeInfo;
+use xcm_builder::{DispatchBlob, DispatchBlobError, HaulBlob, HaulBlobError};
+
+/// Plain "XCM" payload, which we transfer through bridge
+pub type XcmAsPlainPayload = sp_std::prelude::Vec<u8>;
+
+/// Message dispatch result type for single message
+#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)]
+pub enum XcmBlobMessageDispatchResult {
+	InvalidPayload,
+	Dispatched,
+	NotDispatched(#[codec(skip)] &'static str),
+}
+
+/// [`XcmBlobMessageDispatch`] is responsible for dispatching received messages
+pub struct XcmBlobMessageDispatch<
+	SourceBridgeHubChain,
+	TargetBridgeHubChain,
+	DispatchBlob,
+	DispatchBlobWeigher,
+> {
+	_marker: sp_std::marker::PhantomData<(
+		SourceBridgeHubChain,
+		TargetBridgeHubChain,
+		DispatchBlob,
+		DispatchBlobWeigher,
+	)>,
+}
+
+impl<
+		SourceBridgeHubChain: Chain,
+		TargetBridgeHubChain: Chain,
+		BlobDispatcher: DispatchBlob,
+		DispatchBlobWeigher: Get<Weight>,
+	> MessageDispatch<AccountIdOf<SourceBridgeHubChain>>
+	for XcmBlobMessageDispatch<
+		SourceBridgeHubChain,
+		TargetBridgeHubChain,
+		BlobDispatcher,
+		DispatchBlobWeigher,
+	>
+{
+	type DispatchPayload = XcmAsPlainPayload;
+	type DispatchLevelResult = XcmBlobMessageDispatchResult;
+
+	fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight {
+		DispatchBlobWeigher::get()
+	}
+
+	fn dispatch(
+		_relayer_account: &AccountIdOf<SourceBridgeHubChain>,
+		message: DispatchMessage<Self::DispatchPayload>,
+	) -> MessageDispatchResult<Self::DispatchLevelResult> {
+		let payload = match message.data.payload {
+			Ok(payload) => payload,
+			Err(e) => {
+				log::error!(
+					target: crate::LOG_TARGET_BRIDGE_DISPATCH,
+					"[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}",
+					e,
+					message.key.nonce
+				);
+				return MessageDispatchResult {
+					// TODO:check-parameter - setup uspent_weight? https://github.com/paritytech/polkadot/issues/6629
+					unspent_weight: Weight::zero(),
+					dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload,
+				}
+			},
+		};
+		let dispatch_level_result = match BlobDispatcher::dispatch_blob(payload) {
+			Ok(_) => {
+				log::debug!(
+					target: crate::LOG_TARGET_BRIDGE_DISPATCH,
+					"[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}",
+					message.key.nonce
+				);
+				XcmBlobMessageDispatchResult::Dispatched
+			},
+			Err(e) => {
+				let e = match e {
+					DispatchBlobError::Unbridgable => "DispatchBlobError::Unbridgable",
+					DispatchBlobError::InvalidEncoding => "DispatchBlobError::InvalidEncoding",
+					DispatchBlobError::UnsupportedLocationVersion =>
+						"DispatchBlobError::UnsupportedLocationVersion",
+					DispatchBlobError::UnsupportedXcmVersion =>
+						"DispatchBlobError::UnsupportedXcmVersion",
+					DispatchBlobError::RoutingError => "DispatchBlobError::RoutingError",
+					DispatchBlobError::NonUniversalDestination =>
+						"DispatchBlobError::NonUniversalDestination",
+					DispatchBlobError::WrongGlobal => "DispatchBlobError::WrongGlobal",
+				};
+				log::error!(
+					target: crate::LOG_TARGET_BRIDGE_DISPATCH,
+					"[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}",
+					e, message.key.nonce
+				);
+				XcmBlobMessageDispatchResult::NotDispatched(e)
+			},
+		};
+		MessageDispatchResult {
+			// TODO:check-parameter - setup uspent_weight?  https://github.com/paritytech/polkadot/issues/6629
+			unspent_weight: Weight::zero(),
+			dispatch_level_result,
+		}
+	}
+}
+
+/// [`XcmBlobHauler`] is responsible for sending messages to the bridge "point-to-point link" from
+/// one side, where on the other it can be dispatched by [`XcmBlobMessageDispatch`].
+pub trait XcmBlobHauler {
+	/// Runtime message sender adapter.
+	type MessageSender: MessagesBridge<Self::MessageSenderOrigin, XcmAsPlainPayload>;
+
+	/// Runtime message sender origin, which is used by [`MessageSender`].
+	type MessageSenderOrigin;
+	/// Our location within the Consensus Universe.
+	fn message_sender_origin() -> Self::MessageSenderOrigin;
+
+	/// Return message lane (as "point-to-point link") used to deliver XCM messages.
+	fn xcm_lane() -> LaneId;
+}
+
+/// XCM bridge adapter which connects [`XcmBlobHauler`] with [`MessageSender`] and makes sure that
+/// XCM blob is sent to the [`pallet_bridge_messages`] queue to be relayed.
+pub struct XcmBlobHaulerAdapter<XcmBlobHauler>(sp_std::marker::PhantomData<XcmBlobHauler>);
+impl<HaulerOrigin, H: XcmBlobHauler<MessageSenderOrigin = HaulerOrigin>> HaulBlob
+	for XcmBlobHaulerAdapter<H>
+{
+	fn haul_blob(blob: sp_std::prelude::Vec<u8>) -> Result<(), HaulBlobError> {
+		let lane = H::xcm_lane();
+		let result = H::MessageSender::send_message(H::message_sender_origin(), lane, blob);
+		let result = result
+			.map(|artifacts| (lane, artifacts.nonce).using_encoded(sp_io::hashing::blake2_256));
+		match &result {
+			Ok(result) => log::info!(
+				target: crate::LOG_TARGET_BRIDGE_DISPATCH,
+				"haul_blob result - ok: {:?} on lane: {:?}",
+				result,
+				lane
+			),
+			Err(error) => log::error!(
+				target: crate::LOG_TARGET_BRIDGE_DISPATCH,
+				"haul_blob result - error: {:?} on lane: {:?}",
+				error,
+				lane
+			),
+		};
+		result.map(|_| ()).map_err(|_| HaulBlobError::Transport("MessageSenderError"))
+	}
+}
-- 
GitLab