referrerpolicy=no-referrer-when-downgrade

bridge_hub_test_utils/test_cases/
mod.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities.
18//!
19//! This file contains tests, suitable for all bridge runtimes. See `from_parachain` and
20//! `from_grandpa_chain` submodules for tests, that are specific to the bridged chain type.
21
22pub mod from_grandpa_chain;
23pub mod from_parachain;
24
25pub(crate) mod helpers;
26
27use crate::{test_cases::bridges_prelude::*, test_data};
28
29use asset_test_utils::BasicParachainRuntime;
30use bp_messages::{
31	target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
32	LaneState, MessageKey, MessagesOperatingMode, OutboundLaneData,
33};
34use bp_runtime::BasicOperatingMode;
35use codec::Encode;
36use frame_support::{
37	assert_ok,
38	dispatch::GetDispatchInfo,
39	traits::{Contains, Get, OnFinalize, OnInitialize, OriginTrait},
40};
41use frame_system::pallet_prelude::BlockNumberFor;
42use parachains_common::AccountId;
43use parachains_runtimes_test_utils::{
44	mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder,
45	GovernanceOrigin, RuntimeCallOf, RuntimeOriginOf, SlotDurations, XcmReceivedFrom,
46};
47use sp_runtime::{traits::Zero, AccountId32};
48use xcm::{latest::prelude::*, AlwaysLatest};
49use xcm_builder::DispatchBlobError;
50use xcm_executor::{
51	traits::{ConvertLocation, TransactAsset, WeightBounds},
52	XcmExecutor,
53};
54
55/// Common bridges exports.
56pub(crate) mod bridges_prelude {
57	pub use bp_parachains::{RelayBlockHash, RelayBlockNumber};
58	pub use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig};
59	pub use pallet_bridge_messages::{
60		Call as BridgeMessagesCall, Config as BridgeMessagesConfig, LanesManagerError,
61	};
62	pub use pallet_bridge_parachains::{
63		Call as BridgeParachainsCall, Config as BridgeParachainsConfig,
64	};
65}
66
67// Re-export test-case
68pub use for_pallet_xcm_bridge_hub::open_and_close_bridge_works;
69
70// Re-export test_case from assets
71pub use asset_test_utils::include_teleports_for_native_asset_works;
72use pallet_bridge_messages::LaneIdOf;
73
74pub type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
75	parachains_runtimes_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
76
77// Re-export test_case from `parachains-runtimes-test-utils`
78pub use parachains_runtimes_test_utils::test_cases::{
79	change_storage_constant_by_governance_works, set_storage_keys_by_governance_works,
80};
81
82/// Prepare default runtime storage and run test within this context.
83pub fn run_test<Runtime, T>(
84	collator_session_key: CollatorSessionKeys<Runtime>,
85	runtime_para_id: u32,
86	balances: Vec<(Runtime::AccountId, Runtime::Balance)>,
87	test: impl FnOnce() -> T,
88) -> T
89where
90	Runtime: BasicParachainRuntime,
91{
92	ExtBuilder::<Runtime>::default()
93		.with_collators(collator_session_key.collators())
94		.with_session_keys(collator_session_key.session_keys())
95		.with_safe_xcm_version(XCM_VERSION)
96		.with_para_id(runtime_para_id.into())
97		.with_balances(balances)
98		.with_tracing()
99		.build()
100		.execute_with(|| test())
101}
102
103/// Test-case makes sure that `Runtime` can process bridging initialize via governance-like call
104pub fn initialize_bridge_by_governance_works<Runtime, GrandpaPalletInstance>(
105	collator_session_key: CollatorSessionKeys<Runtime>,
106	runtime_para_id: u32,
107	governance_origin: GovernanceOrigin<RuntimeOriginOf<Runtime>>,
108) where
109	Runtime: BasicParachainRuntime + BridgeGrandpaConfig<GrandpaPalletInstance>,
110	GrandpaPalletInstance: 'static,
111	RuntimeCallOf<Runtime>:
112		GetDispatchInfo + From<BridgeGrandpaCall<Runtime, GrandpaPalletInstance>>,
113{
114	run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
115		// check mode before
116		assert_eq!(
117			pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::try_get(),
118			Err(())
119		);
120
121		// prepare the `initialize` call
122		let initialize_call = RuntimeCallOf::<Runtime>::from(BridgeGrandpaCall::<
123			Runtime,
124			GrandpaPalletInstance,
125		>::initialize {
126			init_data: test_data::initialization_data::<Runtime, GrandpaPalletInstance>(12345),
127		});
128
129		// execute XCM with Transacts to `initialize bridge` as governance does
130		assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance_call(
131			initialize_call,
132			governance_origin
133		));
134
135		// check mode after
136		assert_eq!(
137			pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::try_get(),
138			Ok(BasicOperatingMode::Normal)
139		);
140	})
141}
142
143/// Test-case makes sure that `Runtime` can change bridge GRANDPA pallet operating mode via
144/// governance-like call.
145pub fn change_bridge_grandpa_pallet_mode_by_governance_works<Runtime, GrandpaPalletInstance>(
146	collator_session_key: CollatorSessionKeys<Runtime>,
147	runtime_para_id: u32,
148	governance_origin: GovernanceOrigin<RuntimeOriginOf<Runtime>>,
149) where
150	Runtime: BasicParachainRuntime + BridgeGrandpaConfig<GrandpaPalletInstance>,
151	GrandpaPalletInstance: 'static,
152	RuntimeCallOf<Runtime>:
153		GetDispatchInfo + From<BridgeGrandpaCall<Runtime, GrandpaPalletInstance>>,
154{
155	run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
156		let dispatch_set_operating_mode_call = |old_mode, new_mode| {
157			// check old mode
158			assert_eq!(
159				pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::get(),
160				old_mode,
161			);
162
163			// prepare the `set_operating_mode` call
164			let set_operating_mode_call = <Runtime as frame_system::Config>::RuntimeCall::from(
165				pallet_bridge_grandpa::Call::<Runtime, GrandpaPalletInstance>::set_operating_mode {
166					operating_mode: new_mode,
167				},
168			);
169
170			// execute XCM with Transacts to `initialize bridge` as governance does
171			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance_call(
172				set_operating_mode_call,
173				governance_origin.clone()
174			));
175
176			// check mode after
177			assert_eq!(
178				pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::try_get(),
179				Ok(new_mode)
180			);
181		};
182
183		// check mode before
184		assert_eq!(
185			pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::try_get(),
186			Err(())
187		);
188
189		dispatch_set_operating_mode_call(BasicOperatingMode::Normal, BasicOperatingMode::Halted);
190		dispatch_set_operating_mode_call(BasicOperatingMode::Halted, BasicOperatingMode::Normal);
191	});
192}
193
194/// Test-case makes sure that `Runtime` can change bridge parachains pallet operating mode via
195/// governance-like call.
196pub fn change_bridge_parachains_pallet_mode_by_governance_works<Runtime, ParachainsPalletInstance>(
197	collator_session_key: CollatorSessionKeys<Runtime>,
198	runtime_para_id: u32,
199	governance_origin: GovernanceOrigin<RuntimeOriginOf<Runtime>>,
200) where
201	Runtime: BasicParachainRuntime + BridgeParachainsConfig<ParachainsPalletInstance>,
202	ParachainsPalletInstance: 'static,
203	RuntimeCallOf<Runtime>:
204		GetDispatchInfo + From<BridgeParachainsCall<Runtime, ParachainsPalletInstance>>,
205{
206	run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
207		let dispatch_set_operating_mode_call = |old_mode, new_mode| {
208			// check old mode
209			assert_eq!(
210				pallet_bridge_parachains::PalletOperatingMode::<Runtime, ParachainsPalletInstance>::get(),
211				old_mode,
212			);
213
214			// prepare the `set_operating_mode` call
215			let set_operating_mode_call =
216				RuntimeCallOf::<Runtime>::from(pallet_bridge_parachains::Call::<
217					Runtime,
218					ParachainsPalletInstance,
219				>::set_operating_mode {
220					operating_mode: new_mode,
221				});
222
223			// execute XCM with Transacts to `initialize bridge` as governance does
224			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance_call(
225				set_operating_mode_call,
226				governance_origin.clone()
227			));
228
229			// check mode after
230			assert_eq!(
231				pallet_bridge_parachains::PalletOperatingMode::<Runtime, ParachainsPalletInstance>::try_get(),
232				Ok(new_mode)
233			);
234		};
235
236		// check mode before
237		assert_eq!(
238			pallet_bridge_parachains::PalletOperatingMode::<Runtime, ParachainsPalletInstance>::try_get(),
239			Err(())
240		);
241
242		dispatch_set_operating_mode_call(BasicOperatingMode::Normal, BasicOperatingMode::Halted);
243		dispatch_set_operating_mode_call(BasicOperatingMode::Halted, BasicOperatingMode::Normal);
244	});
245}
246
247/// Test-case makes sure that `Runtime` can change bridge messaging pallet operating mode via
248/// governance-like call.
249pub fn change_bridge_messages_pallet_mode_by_governance_works<Runtime, MessagesPalletInstance>(
250	collator_session_key: CollatorSessionKeys<Runtime>,
251	runtime_para_id: u32,
252	governance_origin: GovernanceOrigin<RuntimeOriginOf<Runtime>>,
253) where
254	Runtime: BasicParachainRuntime + BridgeMessagesConfig<MessagesPalletInstance>,
255	MessagesPalletInstance: 'static,
256	RuntimeCallOf<Runtime>:
257		GetDispatchInfo + From<BridgeMessagesCall<Runtime, MessagesPalletInstance>>,
258{
259	run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
260		let dispatch_set_operating_mode_call = |old_mode, new_mode| {
261			// check old mode
262			assert_eq!(
263				pallet_bridge_messages::PalletOperatingMode::<Runtime, MessagesPalletInstance>::get(
264				),
265				old_mode,
266			);
267
268			// encode `set_operating_mode` call
269			let set_operating_mode_call = RuntimeCallOf::<Runtime>::from(BridgeMessagesCall::<
270				Runtime,
271				MessagesPalletInstance,
272			>::set_operating_mode {
273				operating_mode: new_mode,
274			});
275
276			// execute XCM with Transacts to `initialize bridge` as governance does
277			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance_call(
278				set_operating_mode_call,
279				governance_origin.clone()
280			));
281
282			// check mode after
283			assert_eq!(
284				pallet_bridge_messages::PalletOperatingMode::<Runtime, MessagesPalletInstance>::try_get(),
285				Ok(new_mode)
286			);
287		};
288
289		// check mode before
290		assert_eq!(
291			pallet_bridge_messages::PalletOperatingMode::<Runtime, MessagesPalletInstance>::try_get(
292			),
293			Err(())
294		);
295
296		dispatch_set_operating_mode_call(
297			MessagesOperatingMode::Basic(BasicOperatingMode::Normal),
298			MessagesOperatingMode::RejectingOutboundMessages,
299		);
300		dispatch_set_operating_mode_call(
301			MessagesOperatingMode::RejectingOutboundMessages,
302			MessagesOperatingMode::Basic(BasicOperatingMode::Halted),
303		);
304		dispatch_set_operating_mode_call(
305			MessagesOperatingMode::Basic(BasicOperatingMode::Halted),
306			MessagesOperatingMode::Basic(BasicOperatingMode::Normal),
307		);
308	});
309}
310
311/// Test-case makes sure that `Runtime` can handle xcm `ExportMessage`:
312/// Checks if received XCM messages is correctly added to the message outbound queue for delivery.
313/// For SystemParachains we expect unpaid execution.
314pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
315	Runtime,
316	XcmConfig,
317	MessagesPalletInstance,
318>(
319	collator_session_key: CollatorSessionKeys<Runtime>,
320	runtime_para_id: u32,
321	sibling_parachain_id: u32,
322	unwrap_pallet_bridge_messages_event: Box<
323		dyn Fn(Vec<u8>) -> Option<pallet_bridge_messages::Event<Runtime, MessagesPalletInstance>>,
324	>,
325	export_message_instruction: fn() -> Instruction<XcmConfig::RuntimeCall>,
326	existential_deposit: Option<Asset>,
327	maybe_paid_export_message: Option<Asset>,
328	prepare_configuration: impl Fn() -> LaneIdOf<Runtime, MessagesPalletInstance>,
329) where
330	Runtime: BasicParachainRuntime + BridgeMessagesConfig<MessagesPalletInstance>,
331	XcmConfig: xcm_executor::Config,
332	MessagesPalletInstance: 'static,
333{
334	assert_ne!(runtime_para_id, sibling_parachain_id);
335	let sibling_parachain_location = Location::new(1, [Parachain(sibling_parachain_id)]);
336
337	run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
338		let expected_lane_id = prepare_configuration();
339
340		// check queue before
341		assert_eq!(
342			pallet_bridge_messages::OutboundLanes::<Runtime, MessagesPalletInstance>::try_get(
343				expected_lane_id
344			),
345			Ok(OutboundLaneData {
346				state: LaneState::Opened,
347				oldest_unpruned_nonce: 1,
348				latest_received_nonce: 0,
349				latest_generated_nonce: 0
350			})
351		);
352
353		// prepare `ExportMessage`
354		let xcm = if let Some(fee) = maybe_paid_export_message {
355			// deposit ED to origin (if needed)
356			if let Some(ed) = existential_deposit {
357				XcmConfig::AssetTransactor::deposit_asset(
358					&ed,
359					&sibling_parachain_location,
360					Some(&XcmContext::with_message_id([0; 32])),
361				)
362				.expect("deposited ed");
363			}
364			// deposit fee to origin
365			XcmConfig::AssetTransactor::deposit_asset(
366				&fee,
367				&sibling_parachain_location,
368				Some(&XcmContext::with_message_id([0; 32])),
369			)
370			.expect("deposited fee");
371
372			Xcm(vec![
373				WithdrawAsset(Assets::from(vec![fee.clone()])),
374				BuyExecution { fees: fee, weight_limit: Unlimited },
375				export_message_instruction(),
376			])
377		} else {
378			Xcm(vec![
379				UnpaidExecution { weight_limit: Unlimited, check_origin: None },
380				export_message_instruction(),
381			])
382		};
383
384		// execute XCM
385		let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
386		assert_ok!(XcmExecutor::<XcmConfig>::prepare_and_execute(
387			sibling_parachain_location,
388			xcm,
389			&mut hash,
390			RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
391			Weight::zero(),
392		)
393		.ensure_complete());
394
395		// check queue after
396		assert_eq!(
397			pallet_bridge_messages::OutboundLanes::<Runtime, MessagesPalletInstance>::try_get(
398				expected_lane_id
399			),
400			Ok(OutboundLaneData {
401				state: LaneState::Opened,
402				oldest_unpruned_nonce: 1,
403				latest_received_nonce: 0,
404				latest_generated_nonce: 1,
405			})
406		);
407
408		// check events
409		let mut events = <frame_system::Pallet<Runtime>>::events()
410			.into_iter()
411			.filter_map(|e| unwrap_pallet_bridge_messages_event(e.event.encode()));
412		assert!(events.any(|e| matches!(e, pallet_bridge_messages::Event::MessageAccepted { .. })));
413	})
414}
415
416/// Test-case makes sure that Runtime can route XCM messages received in inbound queue,
417/// We just test here `MessageDispatch` configuration.
418/// We expect that runtime can route messages:
419///     1. to Parent (relay chain)
420///     2. to Sibling parachain
421pub fn message_dispatch_routing_works<
422	Runtime,
423	AllPalletsWithoutSystem,
424	XcmConfig,
425	HrmpChannelOpener,
426	MessagesPalletInstance,
427	RuntimeNetwork,
428	BridgedNetwork,
429	NetworkDistanceAsParentCount,
430>(
431	collator_session_key: CollatorSessionKeys<Runtime>,
432	slot_durations: SlotDurations,
433	runtime_para_id: u32,
434	sibling_parachain_id: u32,
435	unwrap_cumulus_pallet_parachain_system_event: Box<
436		dyn Fn(Vec<u8>) -> Option<cumulus_pallet_parachain_system::Event<Runtime>>,
437	>,
438	unwrap_cumulus_pallet_xcmp_queue_event: Box<
439		dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
440	>,
441	prepare_configuration: impl Fn(),
442) where
443	Runtime: BasicParachainRuntime
444		+ cumulus_pallet_xcmp_queue::Config
445		+ BridgeMessagesConfig<MessagesPalletInstance, InboundPayload = test_data::XcmAsPlainPayload>,
446	AllPalletsWithoutSystem:
447		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
448	AccountIdOf<Runtime>: From<AccountId32>
449		+ Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
450	XcmConfig: xcm_executor::Config,
451	MessagesPalletInstance: 'static,
452	HrmpChannelOpener: frame_support::inherent::ProvideInherent<
453		Call = cumulus_pallet_parachain_system::Call<Runtime>,
454	>,
455	RuntimeNetwork: Get<NetworkId>,
456	BridgedNetwork: Get<NetworkId>,
457	NetworkDistanceAsParentCount: Get<u8>,
458{
459	struct NetworkWithParentCount<N, C>(core::marker::PhantomData<(N, C)>);
460	impl<N: Get<NetworkId>, C: Get<u8>> Get<Location> for NetworkWithParentCount<N, C> {
461		fn get() -> Location {
462			Location::new(C::get(), [GlobalConsensus(N::get())])
463		}
464	}
465	assert_ne!(runtime_para_id, sibling_parachain_id);
466
467	#[derive(Debug)]
468	enum XcmBlobMessageDispatchResult {
469		Dispatched,
470		#[allow(dead_code)]
471		NotDispatched(Option<DispatchBlobError>),
472	}
473
474	run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
475		prepare_configuration();
476
477		let dummy_lane_id = LaneIdOf::<Runtime, MessagesPalletInstance>::default();
478		let mut alice = [0u8; 32];
479		alice[0] = 1;
480
481		let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
482			2,
483			AccountId::from(alice).into(),
484		);
485		// 1. this message is sent from other global consensus with destination of this Runtime
486		//    relay chain (UMP)
487		let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::<
488			BridgedNetwork,
489			NetworkWithParentCount<RuntimeNetwork, NetworkDistanceAsParentCount>,
490			AlwaysLatest,
491		>((RuntimeNetwork::get(), Here));
492		let result =
493			<<Runtime as BridgeMessagesConfig<MessagesPalletInstance>>::MessageDispatch>::dispatch(
494				test_data::dispatch_message(dummy_lane_id, 1, bridging_message),
495			);
496		assert_eq!(
497			format!("{:?}", result.dispatch_level_result),
498			format!("{:?}", XcmBlobMessageDispatchResult::Dispatched)
499		);
500
501		// check events - UpwardMessageSent
502		let mut events = <frame_system::Pallet<Runtime>>::events()
503			.into_iter()
504			.filter_map(|e| unwrap_cumulus_pallet_parachain_system_event(e.event.encode()));
505		assert!(events.any(|e| matches!(
506			e,
507			cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
508		)));
509
510		// 2. this message is sent from other global consensus with destination of this Runtime
511		//    sibling parachain (HRMP)
512		let bridging_message =
513			test_data::simulate_message_exporter_on_bridged_chain::<
514				BridgedNetwork,
515				NetworkWithParentCount<RuntimeNetwork, NetworkDistanceAsParentCount>,
516				AlwaysLatest,
517			>((RuntimeNetwork::get(), [Parachain(sibling_parachain_id)].into()));
518
519		// 2.1. WITHOUT opened hrmp channel -> RoutingError
520		let result =
521			<<Runtime as BridgeMessagesConfig<MessagesPalletInstance>>::MessageDispatch>::dispatch(
522				DispatchMessage {
523					key: MessageKey { lane_id: dummy_lane_id, nonce: 1 },
524					data: DispatchMessageData { payload: Ok(bridging_message.clone()) },
525				},
526			);
527		assert_eq!(
528			format!("{:?}", result.dispatch_level_result),
529			format!(
530				"{:?}",
531				XcmBlobMessageDispatchResult::NotDispatched(Some(DispatchBlobError::RoutingError))
532			)
533		);
534
535		// check events - no XcmpMessageSent
536		assert_eq!(
537			<frame_system::Pallet<Runtime>>::events()
538				.into_iter()
539				.filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode()))
540				.count(),
541			0
542		);
543
544		// 2.1. WITH hrmp channel -> Ok
545		mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
546			runtime_para_id.into(),
547			sibling_parachain_id.into(),
548			included_head,
549			&alice,
550			&slot_durations,
551		);
552		let result =
553			<<Runtime as BridgeMessagesConfig<MessagesPalletInstance>>::MessageDispatch>::dispatch(
554				DispatchMessage {
555					key: MessageKey { lane_id: dummy_lane_id, nonce: 1 },
556					data: DispatchMessageData { payload: Ok(bridging_message) },
557				},
558			);
559		assert_eq!(
560			format!("{:?}", result.dispatch_level_result),
561			format!("{:?}", XcmBlobMessageDispatchResult::Dispatched)
562		);
563
564		// check events - XcmpMessageSent
565		let mut events = <frame_system::Pallet<Runtime>>::events()
566			.into_iter()
567			.filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode()));
568		assert!(
569			events.any(|e| matches!(e, cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }))
570		);
571	})
572}
573
574/// Estimates XCM execution fee for paid `ExportMessage` processing.
575pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer<
576	Runtime,
577	XcmConfig,
578	WeightToFee,
579>() -> u128
580where
581	Runtime: frame_system::Config + pallet_balances::Config,
582	XcmConfig: xcm_executor::Config,
583	WeightToFee: frame_support::weights::WeightToFee<Balance = BalanceOf<Runtime>>,
584	<WeightToFee as frame_support::weights::WeightToFee>::Balance: From<u128> + Into<u128>,
585{
586	// data here are not relevant for weighing
587	let mut xcm = Xcm(vec![
588		WithdrawAsset(Assets::from(vec![Asset {
589			id: AssetId(Location::new(1, [])),
590			fun: Fungible(34333299),
591		}])),
592		BuyExecution {
593			fees: Asset { id: AssetId(Location::new(1, [])), fun: Fungible(34333299) },
594			weight_limit: Unlimited,
595		},
596		SetAppendix(Xcm(vec![DepositAsset {
597			assets: Wild(AllCounted(1)),
598			beneficiary: Location::new(1, [Parachain(1000)]),
599		}])),
600		ExportMessage {
601			network: Polkadot,
602			destination: [Parachain(1000)].into(),
603			xcm: Xcm(vec![
604				ReserveAssetDeposited(Assets::from(vec![Asset {
605					id: AssetId(Location::new(2, [GlobalConsensus(Kusama)])),
606					fun: Fungible(1000000000000),
607				}])),
608				ClearOrigin,
609				BuyExecution {
610					fees: Asset {
611						id: AssetId(Location::new(2, [GlobalConsensus(Kusama)])),
612						fun: Fungible(1000000000000),
613					},
614					weight_limit: Unlimited,
615				},
616				DepositAsset {
617					assets: Wild(AllCounted(1)),
618					beneficiary: Location::new(
619						0,
620						[xcm::latest::prelude::AccountId32 {
621							network: None,
622							id: [
623								212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159,
624								214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165,
625								109, 162, 125,
626							],
627						}],
628					),
629				},
630				SetTopic([
631					116, 82, 194, 132, 171, 114, 217, 165, 23, 37, 161, 177, 165, 179, 247, 114,
632					137, 101, 147, 70, 28, 157, 168, 32, 154, 63, 74, 228, 152, 180, 5, 63,
633				]),
634			]),
635		},
636		SetTopic([
637			36, 224, 250, 165, 82, 195, 67, 110, 160, 170, 140, 87, 217, 62, 201, 164, 42, 98, 219,
638			157, 124, 105, 248, 25, 131, 218, 199, 36, 109, 173, 100, 122,
639		]),
640	]);
641
642	// get weight
643	let weight = XcmConfig::Weigher::weight(&mut xcm, Weight::MAX);
644	assert_ok!(weight);
645	let weight = weight.unwrap();
646	// check if sane
647	let max_expected = Runtime::BlockWeights::get().max_block / 10;
648	assert!(
649		weight.all_lte(max_expected),
650		"calculated weight: {:?}, max_expected: {:?}",
651		weight,
652		max_expected
653	);
654
655	// check fee, should not be 0
656	let estimated_fee = WeightToFee::weight_to_fee(&weight);
657	assert!(estimated_fee > BalanceOf::<Runtime>::zero());
658
659	estimated_fee.into()
660}
661
662pub(crate) mod for_pallet_xcm_bridge_hub {
663	use super::*;
664	use crate::test_cases::helpers::for_pallet_xcm_bridge_hub::{
665		close_bridge, ensure_opened_bridge, open_bridge_with_extrinsic,
666	};
667	pub(crate) use pallet_xcm_bridge_hub::{
668		Bridge, BridgeState, Call as BridgeXcmOverBridgeCall, Config as BridgeXcmOverBridgeConfig,
669		LanesManagerOf,
670	};
671
672	/// Test-case makes sure that `Runtime` can open/close bridges.
673	pub fn open_and_close_bridge_works<Runtime, XcmOverBridgePalletInstance, LocationToAccountId, TokenLocation>(
674		collator_session_key: CollatorSessionKeys<Runtime>,
675		runtime_para_id: u32,
676		expected_source: Location,
677		destination: InteriorLocation,
678		origin_with_origin_kind: (Location, OriginKind),
679		is_paid_xcm_execution: bool,
680	) where
681		Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig<XcmOverBridgePalletInstance>,
682		XcmOverBridgePalletInstance: 'static,
683		<Runtime as frame_system::Config>::RuntimeCall: GetDispatchInfo + From<BridgeXcmOverBridgeCall<Runtime, XcmOverBridgePalletInstance>>,
684		<Runtime as pallet_balances::Config>::Balance: From<<<Runtime as pallet_bridge_messages::Config<<Runtime as pallet_xcm_bridge_hub::Config<XcmOverBridgePalletInstance>>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>,
685		<Runtime as pallet_balances::Config>::Balance: From<u128>,
686		<<Runtime as pallet_bridge_messages::Config<<Runtime as pallet_xcm_bridge_hub::Config<XcmOverBridgePalletInstance>>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::AccountId: From<<Runtime as frame_system::Config>::AccountId>,
687		LocationToAccountId: ConvertLocation<AccountIdOf<Runtime>>,
688		TokenLocation: Get<Location>,
689	{
690		run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
691			// construct expected bridge configuration
692			let locations = pallet_xcm_bridge_hub::Pallet::<Runtime, XcmOverBridgePalletInstance>::bridge_locations(
693				expected_source.clone().into(),
694				destination.clone().into(),
695			).expect("valid bridge locations");
696			let expected_lane_id =
697				locations.calculate_lane_id(xcm::latest::VERSION).expect("valid laneId");
698			let lanes_manager = LanesManagerOf::<Runtime, XcmOverBridgePalletInstance>::new();
699
700			let expected_deposit = if <Runtime as pallet_xcm_bridge_hub::Config<
701				XcmOverBridgePalletInstance,
702			>>::AllowWithoutBridgeDeposit::contains(
703				locations.bridge_origin_relative_location()
704			) {
705				Zero::zero()
706			} else {
707				<Runtime as pallet_xcm_bridge_hub::Config<
708					XcmOverBridgePalletInstance,
709				>>::BridgeDeposit::get()
710			};
711
712			// check bridge/lane DOES not exist
713			assert_eq!(
714				pallet_xcm_bridge_hub::Bridges::<Runtime, XcmOverBridgePalletInstance>::get(
715					locations.bridge_id()
716				),
717				None
718			);
719			assert_eq!(
720				lanes_manager.active_inbound_lane(expected_lane_id).map(drop),
721				Err(LanesManagerError::UnknownInboundLane)
722			);
723			assert_eq!(
724				lanes_manager.active_outbound_lane(expected_lane_id).map(drop),
725				Err(LanesManagerError::UnknownOutboundLane)
726			);
727
728			// open bridge with Transact call
729			assert_eq!(
730				ensure_opened_bridge::<
731					Runtime,
732					XcmOverBridgePalletInstance,
733					LocationToAccountId,
734					TokenLocation,
735				>(
736					expected_source.clone(),
737					destination.clone(),
738					is_paid_xcm_execution,
739					|locations, maybe_paid_execution| open_bridge_with_extrinsic::<
740						Runtime,
741						XcmOverBridgePalletInstance,
742					>(
743						origin_with_origin_kind.clone(),
744						locations.bridge_destination_universal_location().clone(),
745						maybe_paid_execution
746					)
747				)
748				.0
749				.bridge_id(),
750				locations.bridge_id()
751			);
752
753			// check bridge/lane DOES exist
754			assert_eq!(
755				pallet_xcm_bridge_hub::Bridges::<Runtime, XcmOverBridgePalletInstance>::get(
756					locations.bridge_id()
757				),
758				Some(Bridge {
759					bridge_origin_relative_location: Box::new(expected_source.clone().into()),
760					bridge_origin_universal_location: Box::new(
761						locations.bridge_origin_universal_location().clone().into()
762					),
763					bridge_destination_universal_location: Box::new(
764						locations.bridge_destination_universal_location().clone().into()
765					),
766					state: BridgeState::Opened,
767					bridge_owner_account: LocationToAccountId::convert_location(&expected_source)
768						.expect("valid location")
769						.into(),
770					deposit: expected_deposit,
771					lane_id: expected_lane_id,
772				})
773			);
774			assert_eq!(
775				lanes_manager.active_inbound_lane(expected_lane_id).map(|lane| lane.state()),
776				Ok(LaneState::Opened)
777			);
778			assert_eq!(
779				lanes_manager.active_outbound_lane(expected_lane_id).map(|lane| lane.state()),
780				Ok(LaneState::Opened)
781			);
782
783			// close bridge with Transact call
784			close_bridge::<Runtime, XcmOverBridgePalletInstance, LocationToAccountId, TokenLocation>(
785				expected_source,
786				destination,
787				origin_with_origin_kind,
788				is_paid_xcm_execution,
789			);
790
791			// check bridge/lane DOES not exist
792			assert_eq!(
793				pallet_xcm_bridge_hub::Bridges::<Runtime, XcmOverBridgePalletInstance>::get(
794					locations.bridge_id()
795				),
796				None
797			);
798			assert_eq!(
799				lanes_manager.active_inbound_lane(expected_lane_id).map(drop),
800				Err(LanesManagerError::UnknownInboundLane)
801			);
802			assert_eq!(
803				lanes_manager.active_outbound_lane(expected_lane_id).map(drop),
804				Err(LanesManagerError::UnknownOutboundLane)
805			);
806		});
807	}
808}