|
| 1 | +// Copyright 2023 Parity Technologies (UK) Ltd. |
| 2 | +// This file is part of Parity Bridges Common. |
| 3 | + |
| 4 | +// Parity Bridges Common 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 | +// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + |
| 17 | +//! Module provides utilities for easier XCM handling, e.g: |
| 18 | +//! [`XcmExecutor`] -> [`MessageSender`] -> <outbound message queue> |
| 19 | +//! | |
| 20 | +//! <relayer> |
| 21 | +//! | |
| 22 | +//! [`XcmRouter`] <- [`MessageDispatch`] <- <inbound message queue> |
| 23 | +
|
| 24 | +use bp_messages::{ |
| 25 | + source_chain::MessagesBridge, |
| 26 | + target_chain::{DispatchMessage, MessageDispatch}, |
| 27 | + LaneId, |
| 28 | +}; |
| 29 | +use bp_runtime::{messages::MessageDispatchResult, AccountIdOf, Chain}; |
| 30 | +use codec::{Decode, Encode}; |
| 31 | +use frame_support::{dispatch::Weight, traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound}; |
| 32 | +use scale_info::TypeInfo; |
| 33 | +use xcm_builder::{DispatchBlob, DispatchBlobError, HaulBlob, HaulBlobError}; |
| 34 | + |
| 35 | +/// Plain "XCM" payload, which we transfer through bridge |
| 36 | +pub type XcmAsPlainPayload = sp_std::prelude::Vec<u8>; |
| 37 | + |
| 38 | +/// Message dispatch result type for single message |
| 39 | +#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] |
| 40 | +pub enum XcmBlobMessageDispatchResult { |
| 41 | + InvalidPayload, |
| 42 | + Dispatched, |
| 43 | + NotDispatched(#[codec(skip)] &'static str), |
| 44 | +} |
| 45 | + |
| 46 | +/// [`XcmBlobMessageDispatch`] is responsible for dispatching received messages |
| 47 | +pub struct XcmBlobMessageDispatch< |
| 48 | + SourceBridgeHubChain, |
| 49 | + TargetBridgeHubChain, |
| 50 | + DispatchBlob, |
| 51 | + DispatchBlobWeigher, |
| 52 | +> { |
| 53 | + _marker: sp_std::marker::PhantomData<( |
| 54 | + SourceBridgeHubChain, |
| 55 | + TargetBridgeHubChain, |
| 56 | + DispatchBlob, |
| 57 | + DispatchBlobWeigher, |
| 58 | + )>, |
| 59 | +} |
| 60 | + |
| 61 | +impl< |
| 62 | + SourceBridgeHubChain: Chain, |
| 63 | + TargetBridgeHubChain: Chain, |
| 64 | + BlobDispatcher: DispatchBlob, |
| 65 | + DispatchBlobWeigher: Get<Weight>, |
| 66 | + > MessageDispatch<AccountIdOf<SourceBridgeHubChain>> |
| 67 | + for XcmBlobMessageDispatch< |
| 68 | + SourceBridgeHubChain, |
| 69 | + TargetBridgeHubChain, |
| 70 | + BlobDispatcher, |
| 71 | + DispatchBlobWeigher, |
| 72 | + > |
| 73 | +{ |
| 74 | + type DispatchPayload = XcmAsPlainPayload; |
| 75 | + type DispatchLevelResult = XcmBlobMessageDispatchResult; |
| 76 | + |
| 77 | + fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight { |
| 78 | + DispatchBlobWeigher::get() |
| 79 | + } |
| 80 | + |
| 81 | + fn dispatch( |
| 82 | + _relayer_account: &AccountIdOf<SourceBridgeHubChain>, |
| 83 | + message: DispatchMessage<Self::DispatchPayload>, |
| 84 | + ) -> MessageDispatchResult<Self::DispatchLevelResult> { |
| 85 | + let payload = match message.data.payload { |
| 86 | + Ok(payload) => payload, |
| 87 | + Err(e) => { |
| 88 | + log::error!( |
| 89 | + target: crate::LOG_TARGET_BRIDGE_DISPATCH, |
| 90 | + "[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}", |
| 91 | + e, |
| 92 | + message.key.nonce |
| 93 | + ); |
| 94 | + return MessageDispatchResult { |
| 95 | + // TODO:check-parameter - setup uspent_weight? https://github.com/paritytech/polkadot/issues/6629 |
| 96 | + unspent_weight: Weight::zero(), |
| 97 | + dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, |
| 98 | + } |
| 99 | + }, |
| 100 | + }; |
| 101 | + let dispatch_level_result = match BlobDispatcher::dispatch_blob(payload) { |
| 102 | + Ok(_) => { |
| 103 | + log::debug!( |
| 104 | + target: crate::LOG_TARGET_BRIDGE_DISPATCH, |
| 105 | + "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}", |
| 106 | + message.key.nonce |
| 107 | + ); |
| 108 | + XcmBlobMessageDispatchResult::Dispatched |
| 109 | + }, |
| 110 | + Err(e) => { |
| 111 | + let e = match e { |
| 112 | + DispatchBlobError::Unbridgable => "DispatchBlobError::Unbridgable", |
| 113 | + DispatchBlobError::InvalidEncoding => "DispatchBlobError::InvalidEncoding", |
| 114 | + DispatchBlobError::UnsupportedLocationVersion => |
| 115 | + "DispatchBlobError::UnsupportedLocationVersion", |
| 116 | + DispatchBlobError::UnsupportedXcmVersion => |
| 117 | + "DispatchBlobError::UnsupportedXcmVersion", |
| 118 | + DispatchBlobError::RoutingError => "DispatchBlobError::RoutingError", |
| 119 | + DispatchBlobError::NonUniversalDestination => |
| 120 | + "DispatchBlobError::NonUniversalDestination", |
| 121 | + DispatchBlobError::WrongGlobal => "DispatchBlobError::WrongGlobal", |
| 122 | + }; |
| 123 | + log::error!( |
| 124 | + target: crate::LOG_TARGET_BRIDGE_DISPATCH, |
| 125 | + "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", |
| 126 | + e, message.key.nonce |
| 127 | + ); |
| 128 | + XcmBlobMessageDispatchResult::NotDispatched(e) |
| 129 | + }, |
| 130 | + }; |
| 131 | + MessageDispatchResult { |
| 132 | + // TODO:check-parameter - setup uspent_weight? https://github.com/paritytech/polkadot/issues/6629 |
| 133 | + unspent_weight: Weight::zero(), |
| 134 | + dispatch_level_result, |
| 135 | + } |
| 136 | + } |
| 137 | +} |
| 138 | + |
| 139 | +/// [`XcmBlobHauler`] is responsible for sending messages to the bridge "point-to-point link" from |
| 140 | +/// one side, where on the other it can be dispatched by [`XcmBlobMessageDispatch`]. |
| 141 | +pub trait XcmBlobHauler { |
| 142 | + /// Runtime message sender adapter. |
| 143 | + type MessageSender: MessagesBridge<Self::MessageSenderOrigin, XcmAsPlainPayload>; |
| 144 | + |
| 145 | + /// Runtime message sender origin, which is used by [`MessageSender`]. |
| 146 | + type MessageSenderOrigin; |
| 147 | + /// Our location within the Consensus Universe. |
| 148 | + fn message_sender_origin() -> Self::MessageSenderOrigin; |
| 149 | + |
| 150 | + /// Return message lane (as "point-to-point link") used to deliver XCM messages. |
| 151 | + fn xcm_lane() -> LaneId; |
| 152 | +} |
| 153 | + |
| 154 | +/// XCM bridge adapter which connects [`XcmBlobHauler`] with [`MessageSender`] and makes sure that |
| 155 | +/// XCM blob is sent to the [`pallet_bridge_messages`] queue to be relayed. |
| 156 | +pub struct XcmBlobHaulerAdapter<XcmBlobHauler>(sp_std::marker::PhantomData<XcmBlobHauler>); |
| 157 | +impl<HaulerOrigin, H: XcmBlobHauler<MessageSenderOrigin = HaulerOrigin>> HaulBlob |
| 158 | + for XcmBlobHaulerAdapter<H> |
| 159 | +{ |
| 160 | + fn haul_blob(blob: sp_std::prelude::Vec<u8>) -> Result<(), HaulBlobError> { |
| 161 | + let lane = H::xcm_lane(); |
| 162 | + let result = H::MessageSender::send_message(H::message_sender_origin(), lane, blob); |
| 163 | + let result = result |
| 164 | + .map(|artifacts| (lane, artifacts.nonce).using_encoded(sp_io::hashing::blake2_256)); |
| 165 | + match &result { |
| 166 | + Ok(result) => log::info!( |
| 167 | + target: crate::LOG_TARGET_BRIDGE_DISPATCH, |
| 168 | + "haul_blob result - ok: {:?} on lane: {:?}", |
| 169 | + result, |
| 170 | + lane |
| 171 | + ), |
| 172 | + Err(error) => log::error!( |
| 173 | + target: crate::LOG_TARGET_BRIDGE_DISPATCH, |
| 174 | + "haul_blob result - error: {:?} on lane: {:?}", |
| 175 | + error, |
| 176 | + lane |
| 177 | + ), |
| 178 | + }; |
| 179 | + result.map(|_| ()).map_err(|_| HaulBlobError::Transport("MessageSenderError")) |
| 180 | + } |
| 181 | +} |
0 commit comments