diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index 70f7703882..a062744108 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -889,7 +889,7 @@ impl_runtime_apis! { params: MessageParams, ) -> (millau_messages::ToMillauMessagePayload, Balance) { let message_payload = vec![0; params.size as usize]; - let dispatch_origin = pallet_bridge_dispatch::CallOrigin::SourceAccount( + let dispatch_origin = bp_message_dispatch::CallOrigin::SourceAccount( params.sender_account, ); @@ -959,10 +959,10 @@ impl_runtime_apis! { make_millau_outbound_lane_data_key, make_millau_header, call_weight, - pallet_bridge_dispatch::MessagePayload { + bp_message_dispatch::MessagePayload { spec_version: VERSION.spec_version, weight: call_weight, - origin: pallet_bridge_dispatch::CallOrigin::< + origin: bp_message_dispatch::CallOrigin::< bp_millau::AccountId, MultiSigner, Signature, diff --git a/bridges/bin/runtime-common/README.md b/bridges/bin/runtime-common/README.md index b375f48309..a7322af973 100644 --- a/bridges/bin/runtime-common/README.md +++ b/bridges/bin/runtime-common/README.md @@ -8,7 +8,7 @@ messages module into your runtime. Basic prerequisites of these helpers are: - all message lanes are identical and may be used to transfer the same messages; - the messages sent over the bridge are dispatched using [call dispatch module](../../modules/dispatch/README.md); -- the messages are `pallet_bridge_dispatch::MessagePayload` structures, where `call` field is +- the messages are `bp_message_dispatch::MessagePayload` structures, where `call` field is encoded `Call` of the target chain. This means that the `Call` is opaque to the [messages module](../../modules/messages/README.md) instance at the source chain. It is pre-encoded by the message submitter; @@ -118,7 +118,7 @@ are: `maximal_message_size`, `verify_chain_message`, `verify_messages_delivery_p `estimate_message_dispatch_and_delivery_fee`. `FromThisChainMessagePayload` is a message that the sender sends through our bridge. It is the -`pallet_bridge_dispatch::MessagePayload`, where `call` field is encoded target chain call. So +`bp_message_dispatch::MessagePayload`, where `call` field is encoded target chain call. So at this chain we don't see internals of this call - we just know its size. `FromThisChainMessageVerifier` is an implementation of `bp_messages::LaneMessageVerifier`. It @@ -131,8 +131,8 @@ has following checks in its `verify_message` method: 1. it'll reject a message if it has the wrong dispatch origin declared. Like if the submitter is not the root of this chain, but it tries to dispatch the message at the target chain using - `pallet_bridge_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature - in the `pallet_bridge_dispatch::CallOrigin::TargetAccount` origin; + `bp_message_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature + in the `bp_message_dispatch::CallOrigin::TargetAccount` origin; 1. it'll reject a message if the delivery and dispatch fee that the submitter wants to pay is lesser than the fee that is computed using the `estimate_message_dispatch_and_delivery_fee` function. diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs index 9f25039dc4..e879aa17bf 100644 --- a/bridges/bin/runtime-common/src/messages.rs +++ b/bridges/bin/runtime-common/src/messages.rs @@ -180,7 +180,7 @@ pub mod source { pub type BridgedChainOpaqueCall = Vec; /// Message payload for This -> Bridged chain messages. - pub type FromThisChainMessagePayload = pallet_bridge_dispatch::MessagePayload< + pub type FromThisChainMessagePayload = bp_message_dispatch::MessagePayload< AccountIdOf>, SignerOf>, SignatureOf>, @@ -395,14 +395,14 @@ pub mod target { use super::*; /// Call origin for Bridged -> This chain messages. - pub type FromBridgedChainMessageCallOrigin = pallet_bridge_dispatch::CallOrigin< + pub type FromBridgedChainMessageCallOrigin = bp_message_dispatch::CallOrigin< AccountIdOf>, SignerOf>, SignatureOf>, >; /// Decoded Bridged -> This message payload. - pub type FromBridgedChainMessagePayload = pallet_bridge_dispatch::MessagePayload< + pub type FromBridgedChainMessagePayload = bp_message_dispatch::MessagePayload< AccountIdOf>, SignerOf>, SignatureOf>, @@ -931,7 +931,7 @@ mod tests { let message_on_bridged_chain = source::FromThisChainMessagePayload:: { spec_version: 1, weight: 100, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: ThisChainCall::Transfer.encode(), } .encode(); @@ -945,7 +945,7 @@ mod tests { target::FromBridgedChainMessagePayload:: { spec_version: 1, weight: 100, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: target::FromBridgedChainEncodedMessageCall:: { encoded_call: ThisChainCall::Transfer.encode(), _marker: PhantomData::default(), @@ -962,7 +962,7 @@ mod tests { source::FromThisChainMessagePayload:: { spec_version: 1, weight: 100, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: vec![42], } } @@ -1012,7 +1012,7 @@ mod tests { let payload = source::FromThisChainMessagePayload:: { spec_version: 1, weight: 100, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: vec![42], }; @@ -1055,7 +1055,7 @@ mod tests { let payload = source::FromThisChainMessagePayload:: { spec_version: 1, weight: 100, - origin: pallet_bridge_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)), + origin: bp_message_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)), call: vec![42], }; @@ -1122,7 +1122,7 @@ mod tests { > { spec_version: 1, weight: 5, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: vec![1, 2, 3, 4, 5, 6], },) .is_err() @@ -1137,7 +1137,7 @@ mod tests { > { spec_version: 1, weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + 1, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: vec![1, 2, 3, 4, 5, 6], },) .is_err() @@ -1152,7 +1152,7 @@ mod tests { > { spec_version: 1, weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: vec![0; source::maximal_message_size::() as usize + 1], },) .is_err() @@ -1167,7 +1167,7 @@ mod tests { > { spec_version: 1, weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, - origin: pallet_bridge_dispatch::CallOrigin::SourceRoot, + origin: bp_message_dispatch::CallOrigin::SourceRoot, call: vec![0; source::maximal_message_size::() as _], },), Ok(()), diff --git a/bridges/docs/high-level-overview.md b/bridges/docs/high-level-overview.md index 14b1eee6d4..9ca3ca42ff 100644 --- a/bridges/docs/high-level-overview.md +++ b/bridges/docs/high-level-overview.md @@ -172,6 +172,6 @@ source chain needs to prove ownership of this account by using their target chai sign: `(Call, SourceChainAccountId).encode()`. This will be included in the message payload and verified by the target chain before dispatch. -See [`CallOrigin` documentation](../modules/dispatch/src/lib.rs) for more details. +See [`CallOrigin` documentation](../primitives/message-dispatch/src/lib.rs) for more details. #### Message Relayers Strategy diff --git a/bridges/modules/dispatch/README.md b/bridges/modules/dispatch/README.md index f2ee04beaf..c4e703c402 100644 --- a/bridges/modules/dispatch/README.md +++ b/bridges/modules/dispatch/README.md @@ -13,7 +13,7 @@ Every message that is being dispatched has three main characteristics: - `id` is the unique id of the message within the given bridge. For messages coming from the [messages module](../messages/README.md), it may worth to use a tuple `(LaneId, MessageNonce)` to identify a message; -- `message` is the `pallet_bridge_dispatch::MessagePayload` structure. The `call` field is set +- `message` is the `bp_message_dispatch::MessagePayload` structure. The `call` field is set to the (potentially) encoded `Call` of this chain. The easiest way to understand what is happening when a `Call` is being dispatched, is to look at the @@ -33,7 +33,7 @@ module events set: chain storage has been corrupted. The `Call` is decoded after `spec_version` check, so we'll never try to decode `Call` from other runtime version; - `MessageSignatureMismatch` event is emitted if submitter has chose to dispatch message using - specified this chain account (`pallet_bridge_dispatch::CallOrigin::TargetAccount` origin), + specified this chain account (`bp_message_dispatch::CallOrigin::TargetAccount` origin), but he has failed to prove that he owns the private key for this account; - `MessageCallRejected` event is emitted if the module has been deployed with some call filter and this filter has rejected the `Call`. In your bridge you may choose to reject all messages except diff --git a/bridges/modules/dispatch/src/lib.rs b/bridges/modules/dispatch/src/lib.rs index f9649c58c4..0b0074c20b 100644 --- a/bridges/modules/dispatch/src/lib.rs +++ b/bridges/modules/dispatch/src/lib.rs @@ -24,8 +24,8 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] -use bp_message_dispatch::{MessageDispatch, Weight}; -use bp_runtime::{derive_account_id, InstanceId, Size, SourceAccount}; +use bp_message_dispatch::{CallOrigin, MessageDispatch, MessagePayload, SpecVersion, Weight}; +use bp_runtime::{derive_account_id, InstanceId, SourceAccount}; use codec::{Decode, Encode}; use frame_support::{ decl_event, decl_module, decl_storage, @@ -33,7 +33,6 @@ use frame_support::{ ensure, traits::{Filter, Get}, weights::{extract_actual_weight, GetDispatchInfo}, - RuntimeDebug, }; use frame_system::RawOrigin; use sp_runtime::{ @@ -42,78 +41,6 @@ use sp_runtime::{ }; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; -/// Spec version type. -pub type SpecVersion = u32; - -// TODO [#895] move to primitives -/// Origin of a Call when it is dispatched on the target chain. -/// -/// The source chain can (and should) verify that the message can be dispatched on the target chain -/// with a particular origin given the source chain's origin. This can be done with the -/// `verify_message_origin()` function. -#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)] -pub enum CallOrigin { - /// Call is sent by the Root origin on the source chain. On the target chain it is dispatched - /// from a derived account. - /// - /// The derived account represents the source Root account on the target chain. This is useful - /// if the target chain needs some way of knowing that a call came from a priviledged origin on - /// the source chain (maybe to allow a configuration change for example). - SourceRoot, - - /// Call is sent by `SourceChainAccountId` on the source chain. On the target chain it is - /// dispatched from an account controlled by a private key on the target chain. - /// - /// The account can be identified by `TargetChainAccountPublic`. The proof that the - /// `SourceChainAccountId` controls `TargetChainAccountPublic` is the `TargetChainSignature` - /// over `(Call, SourceChainAccountId, TargetChainSpecVersion, SourceChainBridgeId).encode()`. - /// - /// NOTE sending messages using this origin (or any other) does not have replay protection! - /// The assumption is that both the source account and the target account is controlled by - /// the same entity, so source-chain replay protection is sufficient. - /// As a consequence, it's extremely important for the target chain user to never produce - /// a signature with their target-private key on something that could be sent over the bridge, - /// i.e. if the target user signs `(, Call::Transfer(X, 5))` - /// The owner of `some-source-account-id` can send that message multiple times, which would - /// result with multiple transfer calls being dispatched on the target chain. - /// So please, NEVER USE YOUR PRIVATE KEY TO SIGN SOMETHING YOU DON'T FULLY UNDERSTAND! - TargetAccount(SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature), - - /// Call is sent by the `SourceChainAccountId` on the source chain. On the target chain it is - /// dispatched from a derived account ID. - /// - /// The account ID on the target chain is derived from the source account ID This is useful if - /// you need a way to represent foreign accounts on this chain for call dispatch purposes. - /// - /// Note that the derived account does not need to have a private key on the target chain. This - /// origin can therefore represent proxies, pallets, etc. as well as "regular" accounts. - SourceAccount(SourceChainAccountId), -} - -// TODO [#895] move to primitives -/// Message payload type used by dispatch module. -#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)] -pub struct MessagePayload { - /// Runtime specification version. We only dispatch messages that have the same - /// runtime version. Otherwise we risk to misinterpret encoded calls. - pub spec_version: SpecVersion, - /// Weight of the call, declared by the message sender. If it is less than actual - /// static weight, the call is not dispatched. - pub weight: Weight, - /// Call origin to be used during dispatch. - pub origin: CallOrigin, - /// The call itself. - pub call: Call, -} - -impl Size - for MessagePayload> -{ - fn size_hint(&self) -> u32 { - self.call.len() as _ - } -} - /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. diff --git a/bridges/primitives/message-dispatch/Cargo.toml b/bridges/primitives/message-dispatch/Cargo.toml index 293c637e8d..84fa48553a 100644 --- a/bridges/primitives/message-dispatch/Cargo.toml +++ b/bridges/primitives/message-dispatch/Cargo.toml @@ -10,9 +10,16 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" bp-runtime = { path = "../runtime", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } + [features] default = ["std"] std = [ "bp-runtime/std", "codec/std", + "frame-support/std", + "sp-std/std", ] diff --git a/bridges/primitives/message-dispatch/src/lib.rs b/bridges/primitives/message-dispatch/src/lib.rs index 3b83e38517..1244371239 100644 --- a/bridges/primitives/message-dispatch/src/lib.rs +++ b/bridges/primitives/message-dispatch/src/lib.rs @@ -19,11 +19,17 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] -use bp_runtime::InstanceId; +use bp_runtime::{InstanceId, Size}; +use codec::{Decode, Encode}; +use frame_support::RuntimeDebug; +use sp_std::prelude::*; /// Message dispatch weight. pub type Weight = u64; +/// Spec version type. +pub type SpecVersion = u32; + /// A generic trait to dispatch arbitrary messages delivered over the bridge. pub trait MessageDispatch { /// A type of the message to be dispatched. @@ -47,3 +53,70 @@ pub trait MessageDispatch { /// the whole message). fn dispatch(bridge: InstanceId, id: MessageId, message: Result); } + +/// Origin of a Call when it is dispatched on the target chain. +/// +/// The source chain can (and should) verify that the message can be dispatched on the target chain +/// with a particular origin given the source chain's origin. This can be done with the +/// `verify_message_origin()` function. +#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)] +pub enum CallOrigin { + /// Call is sent by the Root origin on the source chain. On the target chain it is dispatched + /// from a derived account. + /// + /// The derived account represents the source Root account on the target chain. This is useful + /// if the target chain needs some way of knowing that a call came from a priviledged origin on + /// the source chain (maybe to allow a configuration change for example). + SourceRoot, + + /// Call is sent by `SourceChainAccountId` on the source chain. On the target chain it is + /// dispatched from an account controlled by a private key on the target chain. + /// + /// The account can be identified by `TargetChainAccountPublic`. The proof that the + /// `SourceChainAccountId` controls `TargetChainAccountPublic` is the `TargetChainSignature` + /// over `(Call, SourceChainAccountId, TargetChainSpecVersion, SourceChainBridgeId).encode()`. + /// + /// NOTE sending messages using this origin (or any other) does not have replay protection! + /// The assumption is that both the source account and the target account is controlled by + /// the same entity, so source-chain replay protection is sufficient. + /// As a consequence, it's extremely important for the target chain user to never produce + /// a signature with their target-private key on something that could be sent over the bridge, + /// i.e. if the target user signs `(, Call::Transfer(X, 5))` + /// The owner of `some-source-account-id` can send that message multiple times, which would + /// result with multiple transfer calls being dispatched on the target chain. + /// So please, NEVER USE YOUR PRIVATE KEY TO SIGN SOMETHING YOU DON'T FULLY UNDERSTAND! + TargetAccount(SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature), + + /// Call is sent by the `SourceChainAccountId` on the source chain. On the target chain it is + /// dispatched from a derived account ID. + /// + /// The account ID on the target chain is derived from the source account ID This is useful if + /// you need a way to represent foreign accounts on this chain for call dispatch purposes. + /// + /// Note that the derived account does not need to have a private key on the target chain. This + /// origin can therefore represent proxies, pallets, etc. as well as "regular" accounts. + SourceAccount(SourceChainAccountId), +} + +/// Message payload type used by dispatch module. +#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)] +pub struct MessagePayload { + /// Runtime specification version. We only dispatch messages that have the same + /// runtime version. Otherwise we risk to misinterpret encoded calls. + pub spec_version: SpecVersion, + /// Weight of the call, declared by the message sender. If it is less than actual + /// static weight, the call is not dispatched. + pub weight: Weight, + /// Call origin to be used during dispatch. + pub origin: CallOrigin, + /// The call itself. + pub call: Call, +} + +impl Size + for MessagePayload> +{ + fn size_hint(&self) -> u32 { + self.call.len() as _ + } +} diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml index f5711e0766..fc61d138fd 100644 --- a/bridges/relays/bin-substrate/Cargo.toml +++ b/bridges/relays/bin-substrate/Cargo.toml @@ -23,6 +23,7 @@ structopt = "0.3" bp-header-chain = { path = "../../primitives/header-chain" } bp-kusama = { path = "../../primitives/chain-kusama" } bp-messages = { path = "../../primitives/messages" } +bp-message-dispatch = { path = "../../primitives/message-dispatch" } bp-millau = { path = "../../primitives/chain-millau" } bp-polkadot = { path = "../../primitives/chain-polkadot" } bp-rialto = { path = "../../primitives/chain-rialto" } @@ -36,7 +37,6 @@ finality-relay = { path = "../finality" } headers-relay = { path = "../headers" } messages-relay = { path = "../messages" } millau-runtime = { path = "../../bin/millau/runtime" } -pallet-bridge-dispatch = { path = "../../modules/dispatch" } pallet-bridge-messages = { path = "../../modules/messages" } relay-kusama-client = { path = "../client-kusama" } relay-millau-client = { path = "../client-millau" } diff --git a/bridges/relays/bin-substrate/src/chains/millau.rs b/bridges/relays/bin-substrate/src/chains/millau.rs index ac5e611fdb..41ac760828 100644 --- a/bridges/relays/bin-substrate/src/chains/millau.rs +++ b/bridges/relays/bin-substrate/src/chains/millau.rs @@ -21,9 +21,9 @@ use crate::cli::{ encode_call::{self, Call, CliEncodeCall}, encode_message, send_message, CliChain, }; +use bp_message_dispatch::{CallOrigin, MessagePayload}; use codec::Decode; use frame_support::weights::{GetDispatchInfo, Weight}; -use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; use relay_millau_client::Millau; use sp_version::RuntimeVersion; diff --git a/bridges/relays/bin-substrate/src/chains/mod.rs b/bridges/relays/bin-substrate/src/chains/mod.rs index 20ddf4a92a..b4061ced37 100644 --- a/bridges/relays/bin-substrate/src/chains/mod.rs +++ b/bridges/relays/bin-substrate/src/chains/mod.rs @@ -132,7 +132,7 @@ mod tests { let payload = send_message::message_payload( Default::default(), call.get_dispatch_info().weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, + bp_message_dispatch::CallOrigin::SourceRoot, &call, ); assert_eq!(Millau::verify_message(&payload), Ok(())); @@ -142,7 +142,7 @@ mod tests { let payload = send_message::message_payload( Default::default(), call.get_dispatch_info().weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, + bp_message_dispatch::CallOrigin::SourceRoot, &call, ); assert!(Millau::verify_message(&payload).is_err()); @@ -169,7 +169,7 @@ mod tests { let payload = send_message::message_payload( Default::default(), maximal_dispatch_weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, + bp_message_dispatch::CallOrigin::SourceRoot, &call, ); assert_eq!(Millau::verify_message(&payload), Ok(())); @@ -177,7 +177,7 @@ mod tests { let payload = send_message::message_payload( Default::default(), maximal_dispatch_weight + 1, - pallet_bridge_dispatch::CallOrigin::SourceRoot, + bp_message_dispatch::CallOrigin::SourceRoot, &call, ); assert!(Millau::verify_message(&payload).is_err()); @@ -194,7 +194,7 @@ mod tests { let payload = send_message::message_payload( Default::default(), maximal_dispatch_weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, + bp_message_dispatch::CallOrigin::SourceRoot, &call, ); assert_eq!(Rialto::verify_message(&payload), Ok(())); @@ -202,7 +202,7 @@ mod tests { let payload = send_message::message_payload( Default::default(), maximal_dispatch_weight + 1, - pallet_bridge_dispatch::CallOrigin::SourceRoot, + bp_message_dispatch::CallOrigin::SourceRoot, &call, ); assert!(Rialto::verify_message(&payload).is_err()); diff --git a/bridges/relays/bin-substrate/src/chains/rialto.rs b/bridges/relays/bin-substrate/src/chains/rialto.rs index 25c1ab04c9..77eeb06da0 100644 --- a/bridges/relays/bin-substrate/src/chains/rialto.rs +++ b/bridges/relays/bin-substrate/src/chains/rialto.rs @@ -21,9 +21,9 @@ use crate::cli::{ encode_call::{self, Call, CliEncodeCall}, encode_message, send_message, CliChain, }; +use bp_message_dispatch::{CallOrigin, MessagePayload}; use codec::Decode; use frame_support::weights::{GetDispatchInfo, Weight}; -use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; use relay_rialto_client::Rialto; use sp_version::RuntimeVersion; diff --git a/bridges/relays/bin-substrate/src/cli/send_message.rs b/bridges/relays/bin-substrate/src/cli/send_message.rs index 64448f0f1d..6fa82a8cdb 100644 --- a/bridges/relays/bin-substrate/src/cli/send_message.rs +++ b/bridges/relays/bin-substrate/src/cli/send_message.rs @@ -21,9 +21,9 @@ use crate::cli::{ Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams, TargetSigningParams, }; +use bp_message_dispatch::{CallOrigin, MessagePayload}; use codec::Encode; use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; -use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; use relay_substrate_client::{Chain, TransactionSignScheme}; use sp_core::{Bytes, Pair}; use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner};