Unit-tests for dispatch bridging messages and XCM routing on BridgeHubs + HRMP

This commit is contained in:
Branislav Kontur
2022-12-05 14:05:39 +01:00
parent 0d69b256ad
commit 96b567a3d9
7 changed files with 494 additions and 0 deletions
Generated
+62
View File
@@ -965,6 +965,7 @@ dependencies = [
"bp-rococo",
"bp-runtime",
"bp-wococo",
"bridge-hub-test-utils",
"bridge-runtime-common",
"cumulus-pallet-aura-ext",
"cumulus-pallet-dmp-queue",
@@ -1008,6 +1009,7 @@ dependencies = [
"polkadot-runtime-constants",
"scale-info",
"serde",
"serial_test",
"smallvec",
"sp-api",
"sp-block-builder",
@@ -1027,6 +1029,27 @@ dependencies = [
"xcm-executor",
]
[[package]]
name = "bridge-hub-test-utils"
version = "0.1.0"
dependencies = [
"bp-messages",
"cumulus-pallet-parachain-system",
"cumulus-primitives-core",
"cumulus-primitives-parachain-inherent",
"cumulus-test-relay-sproof-builder",
"frame-support",
"frame-system",
"pallet-xcm",
"pallet-xcm-benchmarks",
"parachain-info",
"parachains-common",
"polkadot-parachain 0.9.31",
"xcm",
"xcm-builder",
"xcm-executor",
]
[[package]]
name = "bridge-runtime-common"
version = "0.1.0"
@@ -2652,6 +2675,19 @@ dependencies = [
"syn",
]
[[package]]
name = "dashmap"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
dependencies = [
"cfg-if 1.0.0",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core 0.9.3",
]
[[package]]
name = "data-encoding"
version = "2.3.2"
@@ -11078,6 +11114,32 @@ dependencies = [
"serde",
]
[[package]]
name = "serial_test"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92761393ee4dc3ff8f4af487bd58f4307c9329bbedea02cac0089ad9c411e153"
dependencies = [
"dashmap",
"futures",
"lazy_static",
"log",
"parking_lot 0.12.1",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sha-1"
version = "0.9.8"
@@ -83,6 +83,10 @@ pallet-bridge-relayers = { path = "../../../../bridges/modules/relayers", defaul
pallet-shift-session-manager = { path = "../../../../bridges/modules/shift-session-manager", default-features = false }
bridge-runtime-common = { path = "../../../../bridges/bin/runtime-common", default-features = false }
[dev-dependencies]
serial_test = "0.9.0"
bridge-hub-test-utils = { path = "../test-utils"}
[features]
default = [
"std",
@@ -0,0 +1,183 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus 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.
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
use bp_messages::target_chain::MessageDispatch;
use bp_runtime::messages::MessageDispatchResult;
use bridge_hub_rococo_runtime::bridge_common_config::XcmBlobMessageDispatchResult;
pub use bridge_hub_rococo_runtime::{
runtime_api,
xcm_config::{XcmConfig, XcmRouter},
Runtime, *,
};
use xcm::latest::prelude::*;
use bridge_hub_test_utils::*;
fn execute_on_runtime<R>(
with_para_id: u32,
open_hrmp_to_para_id: Option<u32>,
execute: impl FnOnce() -> R,
) -> R {
new_test_ext::<Runtime>(with_para_id.into(), 3).execute_with(|| {
if let Some(open_hrmp_to_para_id) = open_hrmp_to_para_id {
mock_open_hrmp_channel::<Runtime, ParachainSystem>(
with_para_id.into(),
open_hrmp_to_para_id.into(),
);
}
execute()
})
}
#[test]
#[serial_test::serial]
fn test_bridge_hub_wococo_dispatch_blob_and_xcm_routing_works() {
let universal_source_as_senders =
vec![X1(GlobalConsensus(Rococo)), X2(GlobalConsensus(Rococo), Parachain(1000))];
let runtime_para_id = bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID;
let destination_network_id = Wococo;
let destination_para_id = 1000;
for univeral_source_as_sender in universal_source_as_senders {
// 1. message is sent to other global consensus - Wococo(Here)
let bridging_message =
simulate_export_message::<bridge_hub_rococo_config::WococoGlobalConsensusNetwork>(
univeral_source_as_sender,
destination_network_id,
Here,
dummy_xcm(),
);
let result: MessageDispatchResult<XcmBlobMessageDispatchResult> = execute_on_runtime(
runtime_para_id,
None,
|| {
<<Runtime as pallet_bridge_messages::Config<WithBridgeHubRococoMessagesInstance>>::MessageDispatch as MessageDispatch<_>>::dispatch(
&dummy_account(),
wrap_as_dispatch_message(bridging_message)
)
},
);
assert_eq!(result.dispatch_level_result, XcmBlobMessageDispatchResult::Dispatched);
// 2. message is sent to other global consensus and its parachains - Wococo(Here)
let bridging_message =
simulate_export_message::<bridge_hub_rococo_config::WococoGlobalConsensusNetwork>(
univeral_source_as_sender,
destination_network_id,
X1(Parachain(destination_para_id)),
dummy_xcm(),
);
// 2.1. WITHOUT hrmp channel -> RoutingError
let result: MessageDispatchResult<XcmBlobMessageDispatchResult> = execute_on_runtime(
runtime_para_id,
None,
|| {
<<Runtime as pallet_bridge_messages::Config<WithBridgeHubRococoMessagesInstance>>::MessageDispatch as MessageDispatch<_>>::dispatch(
&dummy_account(),
wrap_as_dispatch_message(bridging_message.clone())
)
},
);
assert_eq!(
result.dispatch_level_result,
XcmBlobMessageDispatchResult::NotDispatched("DispatchBlobError::RoutingError")
);
// 2.1. WITH hrmp channel -> Ok
let result: MessageDispatchResult<XcmBlobMessageDispatchResult> = execute_on_runtime(
runtime_para_id,
Some(destination_para_id),
|| {
<<Runtime as pallet_bridge_messages::Config<WithBridgeHubRococoMessagesInstance>>::MessageDispatch as MessageDispatch<_>>::dispatch(
&dummy_account(),
wrap_as_dispatch_message(bridging_message.clone())
)
},
);
assert_eq!(result.dispatch_level_result, XcmBlobMessageDispatchResult::Dispatched);
}
}
#[test]
#[serial_test::serial]
fn test_bridge_hub_rococo_dispatch_blob_and_xcm_routing_works() {
let universal_source_as_senders =
vec![X1(GlobalConsensus(Wococo)), X2(GlobalConsensus(Wococo), Parachain(1000))];
let runtime_para_id = bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID;
let destination_network_id = Rococo;
let destination_para_id = 1000;
for univeral_source_as_sender in universal_source_as_senders {
// 1. message is sent to other global consensus - Wococo(Here)
let bridging_message =
simulate_export_message::<bridge_hub_wococo_config::RococoGlobalConsensusNetwork>(
univeral_source_as_sender,
destination_network_id,
Here,
dummy_xcm(),
);
let result: MessageDispatchResult<XcmBlobMessageDispatchResult> = execute_on_runtime(
runtime_para_id,
None,
|| {
<<Runtime as pallet_bridge_messages::Config<WithBridgeHubWococoMessagesInstance>>::MessageDispatch as MessageDispatch<_>>::dispatch(
&dummy_account(),
wrap_as_dispatch_message(bridging_message)
)
},
);
assert_eq!(result.dispatch_level_result, XcmBlobMessageDispatchResult::Dispatched);
// 2. message is sent to other global consensus and its parachains - Wococo(Here)
let bridging_message =
simulate_export_message::<bridge_hub_wococo_config::RococoGlobalConsensusNetwork>(
univeral_source_as_sender,
destination_network_id,
X1(Parachain(destination_para_id)),
dummy_xcm(),
);
// 2.1. WITHOUT hrmp channel -> RoutingError
let result: MessageDispatchResult<XcmBlobMessageDispatchResult> = execute_on_runtime(
runtime_para_id,
None,
|| {
<<Runtime as pallet_bridge_messages::Config<WithBridgeHubWococoMessagesInstance>>::MessageDispatch as MessageDispatch<_>>::dispatch(
&dummy_account(),
wrap_as_dispatch_message(bridging_message.clone())
)
},
);
assert_eq!(
result.dispatch_level_result,
XcmBlobMessageDispatchResult::NotDispatched("DispatchBlobError::RoutingError")
);
// 2.1. WITH hrmp channel -> Ok
let result: MessageDispatchResult<XcmBlobMessageDispatchResult> = execute_on_runtime(
runtime_para_id,
Some(destination_para_id),
|| {
<<Runtime as pallet_bridge_messages::Config<WithBridgeHubWococoMessagesInstance>>::MessageDispatch as MessageDispatch<_>>::dispatch(
&dummy_account(),
wrap_as_dispatch_message(bridging_message.clone())
)
},
);
assert_eq!(result.dispatch_level_result, XcmBlobMessageDispatchResult::Dispatched);
}
}
@@ -0,0 +1,50 @@
[package]
name = "bridge-hub-test-utils"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
description = "Utils for BridgeHub testing"
[dependencies]
# Substrate
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Cumulus
parachains-common = { path = "../../../common", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-primitives-parachain-inherent = { path = "../../../../primitives/parachain-inherent", default-features = false }
cumulus-test-relay-sproof-builder = { path = "../../../../test/relay-sproof-builder", default-features = false }
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
# Polkadot
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
# Bridges
bp-messages = { path = "../../../../bridges/primitives/messages", default-features = false }
[features]
default = [ "std" ]
std = [
"frame-support/std",
"frame-system/std",
"bp-messages/std",
"parachains-common/std",
"parachain-info/std",
"cumulus-primitives-core/std",
"cumulus-pallet-parachain-system/std",
"cumulus-primitives-parachain-inherent/std",
"cumulus-test-relay-sproof-builder/std",
"polkadot-parachain/std",
"pallet-xcm/std",
"xcm/std",
"xcm-builder/std",
"xcm-executor/std",
]
@@ -0,0 +1,171 @@
// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus 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.
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
use bp_messages::{
target_chain::{DispatchMessage, DispatchMessageData},
MessageKey,
};
use cumulus_primitives_core::{AbridgedHrmpChannel, ParaId, PersistedValidationData};
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use frame_support::{
dispatch::{RawOrigin, UnfilteredDispatchable},
inherent::{InherentData, ProvideInherent},
sp_io,
traits::Get,
};
use parachains_common::AccountId;
use polkadot_parachain::primitives::{HrmpChannelId, RelayChainBlockNumber};
use xcm::{latest::prelude::*, prelude::XcmVersion};
use xcm_builder::{HaulBlob, HaulBlobExporter};
use xcm_executor::traits::{validate_export, ExportXcm};
/// Dummy xcm
pub fn dummy_xcm() -> Xcm<()> {
vec![Trap(42)].into()
}
pub fn wrap_as_dispatch_message(payload: Vec<u8>) -> DispatchMessage<Vec<u8>> {
DispatchMessage {
key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
data: DispatchMessageData { payload: Ok(payload) },
}
}
/// Dummy account
pub fn dummy_account() -> AccountId {
AccountId::from([0u8; 32])
}
/// Macro used for simulate_export_message and capturing bytes
macro_rules! grab_haul_blob (
($name:ident, $grabbed_payload:ident) => {
static mut $grabbed_payload: Option<Vec<u8>> = None;
struct $name;
impl HaulBlob for $name {
fn haul_blob(blob: Vec<u8>) {
unsafe {
$grabbed_payload = Some(blob);
}
}
}
}
);
/// Simulates HaulBlobExporter and all its wrapping and captures generated plain bytes
pub fn simulate_export_message<BridgedNetwork: Get<NetworkId>>(
sender: Junctions,
destination_network: NetworkId,
destination: Junctions,
xcm: xcm::v3::Xcm<()>,
) -> Vec<u8> {
grab_haul_blob!(GrabbingHaulBlob, GRABBED_HAUL_BLOB_PAYLOAD);
let channel = 1_u32;
let universal_source = sender;
// simulate XCM message export
let (ticket, fee) = validate_export::<HaulBlobExporter<GrabbingHaulBlob, BridgedNetwork, ()>>(
destination_network,
channel,
universal_source,
destination,
xcm,
)
.expect("validate_export error");
println!("[MessageExporter::fee] {:?}", fee);
let result = HaulBlobExporter::<GrabbingHaulBlob, BridgedNetwork, ()>::deliver(ticket)
.expect("deliver error");
println!("[MessageExporter::deliver] {:?}", result);
unsafe { GRABBED_HAUL_BLOB_PAYLOAD.as_ref().unwrap().clone() }
}
/// Initialize runtime/externalities
pub fn new_test_ext<T: frame_system::Config + pallet_xcm::Config + parachain_info::Config>(
para_id: ParaId,
xcm_version: XcmVersion,
) -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<T>().unwrap();
<pallet_xcm::GenesisConfig as frame_support::traits::GenesisBuild<T>>::assimilate_storage(
&pallet_xcm::GenesisConfig { safe_xcm_version: Some(xcm_version) },
&mut t,
)
.unwrap();
<parachain_info::GenesisConfig as frame_support::traits::GenesisBuild<T>>::assimilate_storage(
&parachain_info::GenesisConfig { parachain_id: para_id },
&mut t,
)
.unwrap();
sp_io::TestExternalities::new(t)
}
/// Helper function which emulates opening HRMP channel which is needed for XcmpQueue xcm router to pass
pub fn mock_open_hrmp_channel<
C: cumulus_pallet_parachain_system::Config,
T: ProvideInherent<Call = cumulus_pallet_parachain_system::Call<C>>,
>(
sender: ParaId,
recipient: ParaId,
) {
let n = 1_u32;
let mut sproof_builder = RelayStateSproofBuilder::default();
sproof_builder.para_id = sender;
sproof_builder.hrmp_channels.insert(
HrmpChannelId { sender, recipient },
AbridgedHrmpChannel {
max_capacity: 10,
max_total_size: 10_000_000_u32,
max_message_size: 10_000_000_u32,
msg_count: 10,
total_size: 10_000_000_u32,
mqc_head: None,
},
);
sproof_builder.hrmp_egress_channel_index = Some(vec![recipient]);
let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
let vfp = PersistedValidationData {
relay_parent_number: n as RelayChainBlockNumber,
relay_parent_storage_root,
..Default::default()
};
// It is insufficient to push the validation function params
// to storage; they must also be included in the inherent data.
let inherent_data = {
let mut inherent_data = InherentData::default();
let system_inherent_data = ParachainInherentData {
validation_data: vfp.clone(),
relay_chain_state,
downward_messages: Default::default(),
horizontal_messages: Default::default(),
};
inherent_data
.put_data(
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
&system_inherent_data,
)
.expect("failed to put VFP inherent");
inherent_data
};
// execute the block
T::create_inherent(&inherent_data)
.expect("got an inherent")
.dispatch_bypass_filter(RawOrigin::None.into())
.expect("dispatch succeeded");
}
@@ -79,3 +79,15 @@ cumulus_based = true
"--no-mdns", "--bootnodes {{'rockmine-collator1'|zombie('multiAddress')}}",
"-- --port 51433 --rpc-port 58833 --ws-port 58843 --no-mdns", "--bootnodes {{'alice-validator'|zombie('multiAddress')}}"
]
[[hrmp_channels]]
sender = 1000
recipient = 1013
max_capacity = 4
max_message_size = 524288
[[hrmp_channels]]
sender = 1013
recipient = 1000
max_capacity = 4
max_message_size = 524288
@@ -79,3 +79,15 @@ cumulus_based = true
"--no-mdns", "--bootnodes {{'wockmint-collator1'|zombie('multiAddress')}}",
"-- --port 31433 --rpc-port 38833 --ws-port 38843 --no-mdns", "--bootnodes {{'alice-validator-wo'|zombie('multiAddress')}}"
]
[[hrmp_channels]]
sender = 1000
recipient = 1014
max_capacity = 4
max_message_size = 524288
[[hrmp_channels]]
sender = 1014
recipient = 1000
max_capacity = 4
max_message_size = 524288