Skip to content
Snippets Groups Projects
Commit ba23521f authored by Branislav Kontur's avatar Branislav Kontur Committed by Serban Iorga
Browse files

Improved `ExportXcm::validate` implementation for BridgeHubs - step 1 (#2727)

* Improved `ExportXcm::validate` implementation for BridgeHubs

* spellcheck

* Fix try-runtime

* Fix try-runtime
parent ca20cad9
No related merge requests found
......@@ -22,6 +22,7 @@ bp-parachains = { path = "../../primitives/parachains", default-features = false
bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false }
bp-relayers = { path = "../../primitives/relayers", default-features = false }
bp-runtime = { path = "../../primitives/runtime", default-features = false }
bp-xcm-bridge-hub = { path = "../../primitives/xcm-bridge-hub", default-features = false }
bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false }
pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false }
pallet-bridge-messages = { path = "../../modules/messages", default-features = false }
......@@ -58,6 +59,7 @@ std = [
"bp-polkadot-core/std",
"bp-relayers/std",
"bp-runtime/std",
"bp-xcm-bridge-hub/std",
"bp-xcm-bridge-hub-router/std",
"codec/std",
"frame-support/std",
......
......@@ -22,26 +22,23 @@
//! `XcmRouter` <- `MessageDispatch` <- `InboundMessageQueue`
use bp_messages::{
source_chain::{MessagesBridge, OnMessagesDelivered},
source_chain::OnMessagesDelivered,
target_chain::{DispatchMessage, MessageDispatch},
LaneId, MessageNonce,
};
use bp_runtime::messages::MessageDispatchResult;
pub use bp_xcm_bridge_hub::XcmAsPlainPayload;
use bp_xcm_bridge_hub_router::XcmChannelStatusProvider;
use codec::{Decode, Encode};
use frame_support::{traits::Get, weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound};
use pallet_bridge_messages::{
Config as MessagesConfig, OutboundLanesCongestedSignals, Pallet as MessagesPallet,
WeightInfoExt as MessagesPalletWeights,
Config as MessagesConfig, OutboundLanesCongestedSignals, WeightInfoExt as MessagesPalletWeights,
};
use scale_info::TypeInfo;
use sp_runtime::SaturatedConversion;
use sp_std::{fmt::Debug, marker::PhantomData};
use xcm::prelude::*;
use xcm_builder::{DispatchBlob, DispatchBlobError, HaulBlob, HaulBlobError};
/// Plain "XCM" payload, which we transfer through bridge
pub type XcmAsPlainPayload = sp_std::prelude::Vec<u8>;
use xcm_builder::{DispatchBlob, DispatchBlobError};
/// Message dispatch result type for single message
#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)]
......@@ -123,6 +120,7 @@ impl<
/// A pair of sending chain location and message lane, used by this chain to send messages
/// over the bridge.
#[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))]
pub struct SenderAndLane {
/// Sending chain relative location.
pub location: MultiLocation,
......@@ -144,8 +142,6 @@ pub trait XcmBlobHauler {
type Runtime: MessagesConfig<Self::MessagesInstance>;
/// Instance of the messages pallet that is used to send messages.
type MessagesInstance: 'static;
/// Returns lane used by this hauler.
type SenderAndLane: Get<SenderAndLane>;
/// Actual XCM message sender (`HRMP` or `UMP`) to the source chain
/// location (`Self::SenderAndLane::get().location`).
......@@ -166,54 +162,25 @@ pub trait XcmBlobHauler {
/// makes sure that XCM blob is sent to the outbound lane to be relayed.
///
/// It needs to be used at the source bridge hub.
pub struct XcmBlobHaulerAdapter<XcmBlobHauler>(sp_std::marker::PhantomData<XcmBlobHauler>);
pub struct XcmBlobHaulerAdapter<XcmBlobHauler, Lanes>(
sp_std::marker::PhantomData<(XcmBlobHauler, Lanes)>,
);
impl<H: XcmBlobHauler> HaulBlob for XcmBlobHaulerAdapter<H>
where
H::Runtime: MessagesConfig<H::MessagesInstance, OutboundPayload = XcmAsPlainPayload>,
impl<
H: XcmBlobHauler,
Lanes: Get<sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))>>,
> OnMessagesDelivered for XcmBlobHaulerAdapter<H, Lanes>
{
fn haul_blob(blob: sp_std::prelude::Vec<u8>) -> Result<(), HaulBlobError> {
let sender_and_lane = H::SenderAndLane::get();
MessagesPallet::<H::Runtime, H::MessagesInstance>::send_message(sender_and_lane.lane, blob)
.map(|artifacts| {
log::info!(
target: crate::LOG_TARGET_BRIDGE_DISPATCH,
"haul_blob result - ok: {:?} on lane: {:?}. Enqueued messages: {}",
artifacts.nonce,
sender_and_lane.lane,
artifacts.enqueued_messages,
);
// notify XCM queue manager about updated lane state
LocalXcmQueueManager::<H>::on_bridge_message_enqueued(
&sender_and_lane,
artifacts.enqueued_messages,
);
})
.map_err(|error| {
log::error!(
target: crate::LOG_TARGET_BRIDGE_DISPATCH,
"haul_blob result - error: {:?} on lane: {:?}",
error,
sender_and_lane.lane,
);
HaulBlobError::Transport("MessageSenderError")
})
}
}
impl<H: XcmBlobHauler> OnMessagesDelivered for XcmBlobHaulerAdapter<H> {
fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) {
let sender_and_lane = H::SenderAndLane::get();
if sender_and_lane.lane != lane {
return
if let Some(sender_and_lane) =
Lanes::get().iter().find(|link| link.0.lane == lane).map(|link| &link.0)
{
// notify XCM queue manager about updated lane state
LocalXcmQueueManager::<H>::on_bridge_messages_delivered(
sender_and_lane,
enqueued_messages,
);
}
// notify XCM queue manager about updated lane state
LocalXcmQueueManager::<H>::on_bridge_messages_delivered(
&sender_and_lane,
enqueued_messages,
);
}
}
......@@ -356,6 +323,9 @@ mod tests {
location: MultiLocation::new(1, X1(Parachain(1000))),
lane: TEST_LANE_ID,
};
pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))> = sp_std::vec![
(TestSenderAndLane::get(), (NetworkId::ByGenesis([0; 32]), InteriorMultiLocation::Here))
];
pub DummyXcmMessage: Xcm<()> = Xcm::new();
}
......@@ -389,37 +359,44 @@ mod tests {
impl XcmBlobHauler for TestBlobHauler {
type Runtime = TestRuntime;
type MessagesInstance = ();
type SenderAndLane = TestSenderAndLane;
type ToSourceChainSender = DummySendXcm;
type CongestedMessage = DummyXcmMessage;
type UncongestedMessage = DummyXcmMessage;
}
type TestBlobHaulerAdapter = XcmBlobHaulerAdapter<TestBlobHauler>;
type TestBlobHaulerAdapter = XcmBlobHaulerAdapter<TestBlobHauler, TestLanes>;
fn fill_up_lane_to_congestion() {
fn fill_up_lane_to_congestion() -> MessageNonce {
let latest_generated_nonce = OUTBOUND_LANE_CONGESTED_THRESHOLD;
OutboundLanes::<TestRuntime, ()>::insert(
TEST_LANE_ID,
OutboundLaneData {
oldest_unpruned_nonce: 0,
latest_received_nonce: 0,
latest_generated_nonce: OUTBOUND_LANE_CONGESTED_THRESHOLD,
latest_generated_nonce,
},
);
latest_generated_nonce
}
#[test]
fn congested_signal_is_not_sent_twice() {
run_test(|| {
fill_up_lane_to_congestion();
let enqueued = fill_up_lane_to_congestion();
// next sent message leads to congested signal
TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap();
LocalXcmQueueManager::<TestBlobHauler>::on_bridge_message_enqueued(
&TestSenderAndLane::get(),
enqueued + 1,
);
assert_eq!(DummySendXcm::messages_sent(), 1);
// next sent message => we don't sent another congested signal
TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap();
LocalXcmQueueManager::<TestBlobHauler>::on_bridge_message_enqueued(
&TestSenderAndLane::get(),
enqueued,
);
assert_eq!(DummySendXcm::messages_sent(), 1);
});
}
......@@ -427,7 +404,10 @@ mod tests {
#[test]
fn congested_signal_is_not_sent_when_outbound_lane_is_not_congested() {
run_test(|| {
TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap();
LocalXcmQueueManager::<TestBlobHauler>::on_bridge_message_enqueued(
&TestSenderAndLane::get(),
1,
);
assert_eq!(DummySendXcm::messages_sent(), 0);
});
}
......@@ -435,10 +415,13 @@ mod tests {
#[test]
fn congested_signal_is_sent_when_outbound_lane_is_congested() {
run_test(|| {
fill_up_lane_to_congestion();
let enqueued = fill_up_lane_to_congestion();
// next sent message leads to congested signal
TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap();
LocalXcmQueueManager::<TestBlobHauler>::on_bridge_message_enqueued(
&TestSenderAndLane::get(),
enqueued + 1,
);
assert_eq!(DummySendXcm::messages_sent(), 1);
assert!(LocalXcmQueueManager::<TestBlobHauler>::is_congested_signal_sent(TEST_LANE_ID));
});
......
[package]
name = "pallet-xcm-bridge-hub"
description = "Module that adds dynamic bridges/lanes support to XCM infrastucture at the bridge hub."
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false }
log = { version = "0.4.20", default-features = false }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
# Bridge Dependencies
bp-messages = { path = "../../primitives/messages", default-features = false }
bp-runtime = { path = "../../primitives/runtime", default-features = false }
bp-xcm-bridge-hub = { path = "../../primitives/xcm-bridge-hub", default-features = false }
pallet-bridge-messages = { path = "../messages", default-features = false }
bridge-runtime-common = { path = "../../bin/runtime-common", default-features = false }
# Substrate Dependencies
frame-support = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
# Polkadot Dependencies
xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
[dev-dependencies]
bp-header-chain = { path = "../../primitives/header-chain" }
pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-io = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
[features]
default = ["std"]
std = [
"bp-messages/std",
"bp-runtime/std",
"bp-xcm-bridge-hub/std",
"bridge-runtime-common/std",
"codec/std",
"frame-support/std",
"frame-system/std",
"log/std",
"pallet-bridge-messages/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"xcm-builder/std",
"xcm-executor/std",
"xcm/std",
]
runtime-benchmarks = [
"bridge-runtime-common/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-bridge-messages/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-balances/try-runtime",
"pallet-bridge-messages/try-runtime",
"sp-runtime/try-runtime",
]
// Copyright 2019-2021 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/>.
//! The code that allows to use the pallet (`pallet-xcm-bridge-hub`) as XCM message
//! exporter at the sending bridge hub. Internally, it just enqueues outbound blob
//! in the messages pallet queue.
//!
//! This code is executed at the source bridge hub.
use crate::{Config, Pallet, LOG_TARGET};
use bp_messages::source_chain::MessagesBridge;
use bp_xcm_bridge_hub::XcmAsPlainPayload;
use bridge_runtime_common::messages_xcm_extension::{LocalXcmQueueManager, SenderAndLane};
use pallet_bridge_messages::{Config as BridgeMessagesConfig, Pallet as BridgeMessagesPallet};
use xcm::prelude::*;
use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter};
use xcm_executor::traits::ExportXcm;
/// An easy way to access `HaulBlobExporter`.
pub type PalletAsHaulBlobExporter<T, I> = HaulBlobExporter<
DummyHaulBlob,
<T as Config<I>>::BridgedNetworkId,
<T as Config<I>>::MessageExportPrice,
>;
/// An easy way to access associated messages pallet.
type MessagesPallet<T, I> = BridgeMessagesPallet<T, <T as Config<I>>::BridgeMessagesPalletInstance>;
impl<T: Config<I>, I: 'static> ExportXcm for Pallet<T, I>
where
T: BridgeMessagesConfig<
<T as Config<I>>::BridgeMessagesPalletInstance,
OutboundPayload = XcmAsPlainPayload,
>,
{
type Ticket = (SenderAndLane, XcmAsPlainPayload, XcmHash);
fn validate(
network: NetworkId,
channel: u32,
universal_source: &mut Option<InteriorMultiLocation>,
destination: &mut Option<InteriorMultiLocation>,
message: &mut Option<Xcm<()>>,
) -> Result<(Self::Ticket, MultiAssets), SendError> {
// Find supported lane_id.
let sender_and_lane = Self::lane_for(
universal_source.as_ref().ok_or(SendError::MissingArgument)?,
(&network, destination.as_ref().ok_or(SendError::MissingArgument)?),
)
.ok_or(SendError::NotApplicable)?;
// check if we are able to route the message. We use existing `HaulBlobExporter` for that.
// It will make all required changes and will encode message properly, so that the
// `DispatchBlob` at the bridged bridge hub will be able to decode it
let ((blob, id), price) = PalletAsHaulBlobExporter::<T, I>::validate(
network,
channel,
universal_source,
destination,
message,
)?;
Ok(((sender_and_lane, blob, id), price))
}
fn deliver(
(sender_and_lane, blob, id): (SenderAndLane, XcmAsPlainPayload, XcmHash),
) -> Result<XcmHash, SendError> {
let lane_id = sender_and_lane.lane;
let send_result = MessagesPallet::<T, I>::send_message(lane_id, blob);
match send_result {
Ok(artifacts) => {
log::info!(
target: LOG_TARGET,
"XCM message {:?} has been enqueued at bridge {:?} with nonce {}",
id,
lane_id,
artifacts.nonce,
);
// notify XCM queue manager about updated lane state
LocalXcmQueueManager::<T::LanesSupport>::on_bridge_message_enqueued(
&sender_and_lane,
artifacts.enqueued_messages,
);
},
Err(error) => {
log::debug!(
target: LOG_TARGET,
"XCM message {:?} has been dropped because of bridge error {:?} on bridge {:?}",
id,
error,
lane_id,
);
return Err(SendError::Transport("BridgeSendError"))
},
}
Ok(id)
}
}
/// Dummy implementation of the `HaulBlob` trait that is never called.
///
/// We are using `HaulBlobExporter`, which requires `HaulBlob` implementation. It assumes that
/// there's a single channel between two bridge hubs - `HaulBlob` only accepts the blob and nothing
/// else. But bridge messages pallet may have a dedicated channel (lane) for every pair of bridged
/// chains. So we are using our own `ExportXcm` implementation, but to utilize `HaulBlobExporter` we
/// still need this `DummyHaulBlob`.
pub struct DummyHaulBlob;
impl HaulBlob for DummyHaulBlob {
fn haul_blob(_blob: XcmAsPlainPayload) -> Result<(), HaulBlobError> {
Err(HaulBlobError::Transport("DummyHaulBlob"))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::*;
use frame_support::assert_ok;
use xcm_executor::traits::export_xcm;
fn universal_source() -> InteriorMultiLocation {
X2(GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID))
}
fn universal_destination() -> InteriorMultiLocation {
BridgedDestination::get()
}
#[test]
fn export_works() {
run_test(|| {
assert_ok!(export_xcm::<XcmOverBridge>(
BridgedRelayNetwork::get(),
0,
universal_source(),
universal_destination(),
vec![Instruction::ClearOrigin].into(),
));
})
}
#[test]
fn export_fails_if_argument_is_missing() {
run_test(|| {
assert_eq!(
XcmOverBridge::validate(
BridgedRelayNetwork::get(),
0,
&mut None,
&mut Some(universal_destination()),
&mut Some(Vec::new().into()),
),
Err(SendError::MissingArgument),
);
assert_eq!(
XcmOverBridge::validate(
BridgedRelayNetwork::get(),
0,
&mut Some(universal_source()),
&mut None,
&mut Some(Vec::new().into()),
),
Err(SendError::MissingArgument),
);
})
}
#[test]
fn exporter_computes_correct_lane_id() {
run_test(|| {
let expected_lane_id = TEST_LANE_ID;
assert_eq!(
XcmOverBridge::validate(
BridgedRelayNetwork::get(),
0,
&mut Some(universal_source()),
&mut Some(universal_destination()),
&mut Some(Vec::new().into()),
)
.unwrap()
.0
.0
.lane,
expected_lane_id,
);
})
}
}
// Copyright 2019-2021 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 that adds XCM support to bridge pallets.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use bridge_runtime_common::messages_xcm_extension::XcmBlobHauler;
use pallet_bridge_messages::Config as BridgeMessagesConfig;
use xcm::prelude::*;
pub use exporter::PalletAsHaulBlobExporter;
pub use pallet::*;
mod exporter;
mod mock;
/// The target that will be used when publishing logs related to this pallet.
pub const LOG_TARGET: &str = "runtime::bridge-xcm";
#[frame_support::pallet]
pub mod pallet {
use super::*;
use bridge_runtime_common::messages_xcm_extension::SenderAndLane;
use frame_support::pallet_prelude::*;
#[pallet::config]
#[pallet::disable_frame_system_supertrait_check]
pub trait Config<I: 'static = ()>:
BridgeMessagesConfig<Self::BridgeMessagesPalletInstance>
{
/// Runtime's universal location.
type UniversalLocation: Get<InteriorMultiLocation>;
// TODO: https://github.com/paritytech/parity-bridges-common/issues/1666 remove `ChainId` and
// replace it with the `NetworkId` - then we'll be able to use
// `T as pallet_bridge_messages::Config<T::BridgeMessagesPalletInstance>::BridgedChain::NetworkId`
/// Bridged network id.
#[pallet::constant]
type BridgedNetworkId: Get<NetworkId>;
/// Associated messages pallet instance that bridges us with the
/// `BridgedNetworkId` consensus.
type BridgeMessagesPalletInstance: 'static;
/// Price of single message export to the bridged consensus (`Self::BridgedNetworkId`).
type MessageExportPrice: Get<MultiAssets>;
/// Get point-to-point links with bridged consensus (`Self::BridgedNetworkId`).
/// (this will be replaced with dynamic on-chain bridges - `Bridges V2`)
type Lanes: Get<sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))>>;
/// Support for point-to-point links
/// (this will be replaced with dynamic on-chain bridges - `Bridges V2`)
type LanesSupport: XcmBlobHauler;
}
#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Returns dedicated/configured lane identifier.
pub(crate) fn lane_for(
source: &InteriorMultiLocation,
dest: (&NetworkId, &InteriorMultiLocation),
) -> Option<SenderAndLane> {
let source = source.relative_to(&T::UniversalLocation::get());
// Check that we have configured a point-to-point lane for 'source' and `dest`.
T::Lanes::get()
.into_iter()
.find_map(|(lane_source, (lane_dest_network, lane_dest))| {
if lane_source.location == source &&
&lane_dest_network == dest.0 &&
&T::BridgedNetworkId::get() == dest.0 &&
&lane_dest == dest.1
{
Some(lane_source)
} else {
None
}
})
}
}
}
// Copyright 2019-2021 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/>.
#![cfg(test)]
use crate as pallet_xcm_bridge_hub;
use bp_messages::{
source_chain::LaneMessageVerifier,
target_chain::{DispatchMessage, MessageDispatch},
LaneId, OutboundLaneData, VerificationError,
};
use bp_runtime::{messages::MessageDispatchResult, Chain, UnderlyingChainProvider};
use bridge_runtime_common::{
messages::{
source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter,
BridgedChainWithMessages, HashOf, MessageBridge, ThisChainWithMessages,
},
messages_xcm_extension::{SenderAndLane, XcmBlobHauler},
};
use codec::Encode;
use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::RuntimeDbWeight};
use sp_core::H256;
use sp_runtime::{
testing::Header as SubstrateHeader,
traits::{BlakeTwo256, IdentityLookup},
AccountId32, BuildStorage,
};
use xcm::prelude::*;
pub type AccountId = AccountId32;
pub type Balance = u64;
type Block = frame_system::mocking::MockBlock<TestRuntime>;
pub const SIBLING_ASSET_HUB_ID: u32 = 2001;
pub const THIS_BRIDGE_HUB_ID: u32 = 2002;
pub const BRIDGED_ASSET_HUB_ID: u32 = 1001;
pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]);
frame_support::construct_runtime! {
pub enum TestRuntime {
System: frame_system::{Pallet, Call, Config<T>, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Event<T>},
Messages: pallet_bridge_messages::{Pallet, Call, Event<T>},
XcmOverBridge: pallet_xcm_bridge_hub::{Pallet},
}
}
parameter_types! {
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 };
pub const ExistentialDeposit: Balance = 1;
}
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
impl frame_system::Config for TestRuntime {
type AccountId = AccountId;
type AccountData = pallet_balances::AccountData<Balance>;
type Block = Block;
type Lookup = IdentityLookup<Self::AccountId>;
}
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)]
impl pallet_balances::Config for TestRuntime {
type AccountStore = System;
}
/// Lane message verifier that is used in tests.
#[derive(Debug, Default)]
pub struct TestLaneMessageVerifier;
impl LaneMessageVerifier<Vec<u8>> for TestLaneMessageVerifier {
fn verify_message(
_lane: &LaneId,
_lane_outbound_data: &OutboundLaneData,
_payload: &Vec<u8>,
) -> Result<(), VerificationError> {
Ok(())
}
}
parameter_types! {
pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID];
}
impl pallet_bridge_messages::Config for TestRuntime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = TestMessagesWeights;
type BridgedChainId = ();
type ActiveOutboundLanes = ActiveOutboundLanes;
type MaxUnrewardedRelayerEntriesAtInboundLane = ();
type MaxUnconfirmedMessagesAtInboundLane = ();
type MaximalOutboundPayloadSize = ConstU32<2048>;
type OutboundPayload = Vec<u8>;
type InboundPayload = Vec<u8>;
type InboundRelayer = ();
type DeliveryPayments = ();
type TargetHeaderChain = TargetHeaderChainAdapter<OnThisChainBridge>;
type LaneMessageVerifier = TestLaneMessageVerifier;
type DeliveryConfirmationPayments = ();
type OnMessagesDelivered = ();
type SourceHeaderChain = SourceHeaderChainAdapter<OnThisChainBridge>;
type MessageDispatch = TestMessageDispatch;
}
pub struct TestMessagesWeights;
impl pallet_bridge_messages::WeightInfo for TestMessagesWeights {
fn receive_single_message_proof() -> Weight {
Weight::zero()
}
fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
Weight::zero()
}
fn receive_delivery_proof_for_single_message() -> Weight {
Weight::zero()
}
fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
Weight::zero()
}
fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
Weight::zero()
}
fn receive_two_messages_proof() -> Weight {
Weight::zero()
}
fn receive_single_message_proof_1_kb() -> Weight {
Weight::zero()
}
fn receive_single_message_proof_16_kb() -> Weight {
Weight::zero()
}
fn receive_single_message_proof_with_dispatch(_: u32) -> Weight {
Weight::from_parts(1, 0)
}
}
impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights {
fn expected_extra_storage_proof_size() -> u32 {
0
}
fn receive_messages_proof_overhead_from_runtime() -> Weight {
Weight::zero()
}
fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight {
Weight::zero()
}
}
parameter_types! {
pub const RelayNetwork: NetworkId = NetworkId::Kusama;
pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot;
pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo;
pub const BridgeReserve: Balance = 100_000;
pub UniversalLocation: InteriorMultiLocation = X2(
GlobalConsensus(RelayNetwork::get()),
Parachain(THIS_BRIDGE_HUB_ID),
);
pub const Penalty: Balance = 1_000;
}
impl pallet_xcm_bridge_hub::Config for TestRuntime {
type UniversalLocation = UniversalLocation;
type BridgedNetworkId = BridgedRelayNetwork;
type BridgeMessagesPalletInstance = ();
type MessageExportPrice = ();
type Lanes = TestLanes;
type LanesSupport = TestXcmBlobHauler;
}
parameter_types! {
pub TestSenderAndLane: SenderAndLane = SenderAndLane {
location: MultiLocation::new(1, X1(Parachain(SIBLING_ASSET_HUB_ID))),
lane: TEST_LANE_ID,
};
pub const BridgedDestination: InteriorMultiLocation = X1(
Parachain(BRIDGED_ASSET_HUB_ID)
);
pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))> = sp_std::vec![
(TestSenderAndLane::get(), (BridgedRelayNetwork::get(), BridgedDestination::get()))
];
}
pub struct TestXcmBlobHauler;
impl XcmBlobHauler for TestXcmBlobHauler {
type Runtime = TestRuntime;
type MessagesInstance = ();
type ToSourceChainSender = ();
type CongestedMessage = ();
type UncongestedMessage = ();
}
pub struct ThisChain;
impl Chain for ThisChain {
type BlockNumber = u64;
type Hash = H256;
type Hasher = BlakeTwo256;
type Header = SubstrateHeader;
type AccountId = AccountId;
type Balance = Balance;
type Nonce = u64;
type Signature = sp_runtime::MultiSignature;
fn max_extrinsic_size() -> u32 {
u32::MAX
}
fn max_extrinsic_weight() -> Weight {
Weight::MAX
}
}
pub struct BridgedChain;
pub type BridgedHeaderHash = H256;
pub type BridgedChainHeader = SubstrateHeader;
impl Chain for BridgedChain {
type BlockNumber = u64;
type Hash = BridgedHeaderHash;
type Hasher = BlakeTwo256;
type Header = BridgedChainHeader;
type AccountId = AccountId;
type Balance = Balance;
type Nonce = u64;
type Signature = sp_runtime::MultiSignature;
fn max_extrinsic_size() -> u32 {
4096
}
fn max_extrinsic_weight() -> Weight {
Weight::MAX
}
}
/// Test message dispatcher.
pub struct TestMessageDispatch;
impl TestMessageDispatch {
pub fn deactivate(lane: LaneId) {
frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false);
}
}
impl MessageDispatch for TestMessageDispatch {
type DispatchPayload = Vec<u8>;
type DispatchLevelResult = ();
fn is_active() -> bool {
frame_support::storage::unhashed::take::<bool>(&(b"inactive").encode()[..]) != Some(false)
}
fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight {
Weight::zero()
}
fn dispatch(
_: DispatchMessage<Self::DispatchPayload>,
) -> MessageDispatchResult<Self::DispatchLevelResult> {
MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () }
}
}
pub struct WrappedThisChain;
impl UnderlyingChainProvider for WrappedThisChain {
type Chain = ThisChain;
}
impl ThisChainWithMessages for WrappedThisChain {
type RuntimeOrigin = RuntimeOrigin;
}
pub struct WrappedBridgedChain;
impl UnderlyingChainProvider for WrappedBridgedChain {
type Chain = BridgedChain;
}
impl BridgedChainWithMessages for WrappedBridgedChain {}
pub struct BridgedHeaderChain;
impl bp_header_chain::HeaderChain<BridgedChain> for BridgedHeaderChain {
fn finalized_header_state_root(
_hash: HashOf<WrappedBridgedChain>,
) -> Option<HashOf<WrappedBridgedChain>> {
unreachable!()
}
}
/// Bridge that is deployed on `ThisChain` and allows sending/receiving messages to/from
/// `BridgedChain`.
#[derive(Debug, PartialEq, Eq)]
pub struct OnThisChainBridge;
impl MessageBridge for OnThisChainBridge {
const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
type ThisChain = WrappedThisChain;
type BridgedChain = WrappedBridgedChain;
type BridgedHeaderChain = BridgedHeaderChain;
}
/// Run pallet test.
pub fn run_test<T>(test: impl FnOnce() -> T) -> T {
sp_io::TestExternalities::new(
frame_system::GenesisConfig::<TestRuntime>::default().build_storage().unwrap(),
)
.execute_with(test)
}
[package]
name = "bp-xcm-bridge-hub"
description = "Primitives of the xcm-bridge-hub pallet."
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
# Substrate Dependencies
sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
[features]
default = ["std"]
std = ["sp-std/std"]
// Copyright 2019-2021 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/>.
//! Primitives of the xcm-bridge-hub pallet.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
/// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound
/// and outbound payloads.
pub type XcmAsPlainPayload = sp_std::vec::Vec<u8>;
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment