xcm_emulator/
lib.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
17extern crate alloc;
18
19pub use array_bytes;
20pub use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
21pub use log;
22pub use paste;
23pub use std::{
24	any::type_name,
25	collections::HashMap,
26	error::Error,
27	fmt,
28	marker::PhantomData,
29	ops::Deref,
30	sync::{Arc, LazyLock, Mutex},
31};
32
33// Substrate
34pub use alloc::collections::vec_deque::VecDeque;
35pub use core::{cell::RefCell, fmt::Debug};
36pub use cumulus_primitives_core::AggregateMessageOrigin as CumulusAggregateMessageOrigin;
37pub use frame_support::{
38	assert_ok,
39	sp_runtime::{
40		traits::{Convert, Dispatchable, Header as HeaderT, Zero},
41		Digest, DispatchResult,
42	},
43	traits::{
44		EnqueueMessage, ExecuteOverweightError, Get, Hooks, OnFinalize, OnIdle, OnInitialize,
45		OriginTrait, ProcessMessage, ProcessMessageError, ServiceQueues,
46	},
47	weights::{Weight, WeightMeter},
48};
49pub use frame_system::{
50	limits::BlockWeights as BlockWeightsLimits, pallet_prelude::BlockNumberFor,
51	Config as SystemConfig, Pallet as SystemPallet,
52};
53pub use pallet_balances::AccountData;
54pub use pallet_message_queue;
55pub use pallet_timestamp::Call as TimestampCall;
56pub use sp_arithmetic::traits::Bounded;
57pub use sp_core::{
58	crypto::get_public_from_string_or_panic, parameter_types, sr25519, storage::Storage, Pair,
59};
60pub use sp_crypto_hashing::blake2_256;
61pub use sp_io::TestExternalities;
62pub use sp_runtime::BoundedSlice;
63pub use sp_tracing;
64
65// Cumulus
66pub use cumulus_pallet_parachain_system::{
67	parachain_inherent::{deconstruct_parachain_inherent_data, InboundMessagesData},
68	Call as ParachainSystemCall, Config as ParachainSystemConfig, Pallet as ParachainSystemPallet,
69};
70pub use cumulus_primitives_core::{
71	relay_chain::{BlockNumber as RelayBlockNumber, HeadData, HrmpChannelId},
72	AbridgedHrmpChannel, DmpMessageHandler, ParaId, PersistedValidationData, XcmpMessageHandler,
73};
74pub use cumulus_primitives_parachain_inherent::ParachainInherentData;
75pub use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
76pub use pallet_message_queue::{Config as MessageQueueConfig, Pallet as MessageQueuePallet};
77pub use parachains_common::{AccountId, Balance};
78pub use polkadot_primitives;
79pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId};
80
81// Polkadot
82pub use polkadot_parachain_primitives::primitives::RelayChainBlockNumber;
83use sp_core::{crypto::AccountId32, H256};
84pub use xcm::latest::prelude::{
85	AccountId32 as AccountId32Junction, Ancestor, Assets, Here, Location,
86	Parachain as ParachainJunction, Parent, WeightLimit, XcmHash,
87};
88pub use xcm_executor::traits::ConvertLocation;
89use xcm_simulator::helpers::TopicIdTracker;
90
91pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
92
93thread_local! {
94	/// Downward messages, each message is: `(to_para_id, [(relay_block_number, msg)])`
95	#[allow(clippy::type_complexity)]
96	pub static DOWNWARD_MESSAGES: RefCell<HashMap<String, VecDeque<(u32, Vec<(RelayBlockNumber, Vec<u8>)>)>>>
97		= RefCell::new(HashMap::new());
98	/// Downward messages that already processed by parachains, each message is: `(to_para_id, relay_block_number, Vec<u8>)`
99	#[allow(clippy::type_complexity)]
100	pub static DMP_DONE: RefCell<HashMap<String, VecDeque<(u32, RelayBlockNumber, Vec<u8>)>>>
101		= RefCell::new(HashMap::new());
102	/// Horizontal messages, each message is: `(to_para_id, [(from_para_id, relay_block_number, msg)])`
103	#[allow(clippy::type_complexity)]
104	pub static HORIZONTAL_MESSAGES: RefCell<HashMap<String, VecDeque<(u32, Vec<(ParaId, RelayBlockNumber, Vec<u8>)>)>>>
105		= RefCell::new(HashMap::new());
106	/// Upward messages, each message is: `(from_para_id, msg)`
107	pub static UPWARD_MESSAGES: RefCell<HashMap<String, VecDeque<(u32, Vec<u8>)>>> = RefCell::new(HashMap::new());
108	/// Bridged messages, each message is: `BridgeMessage`
109	pub static BRIDGED_MESSAGES: RefCell<HashMap<String, VecDeque<BridgeMessage>>> = RefCell::new(HashMap::new());
110	/// Parachains Ids a the Network
111	pub static PARA_IDS: RefCell<HashMap<String, Vec<u32>>> = RefCell::new(HashMap::new());
112	/// Flag indicating if global variables have been initialized for a certain Network
113	pub static INITIALIZED: RefCell<HashMap<String, bool>> = RefCell::new(HashMap::new());
114	/// Most recent `HeadData` of each parachain, encoded.
115	pub static LAST_HEAD: RefCell<HashMap<String, HashMap<u32, HeadData>>> = RefCell::new(HashMap::new());
116}
117pub trait CheckAssertion<Origin, Destination, Hops, Args>
118where
119	Origin: Chain + Clone,
120	Destination: Chain + Clone,
121	Origin::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Origin::Runtime>> + Clone,
122	Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
123	Hops: Clone,
124	Args: Clone,
125{
126	fn check_assertion(test: Test<Origin, Destination, Hops, Args>);
127}
128
129#[impl_trait_for_tuples::impl_for_tuples(5)]
130impl<Origin, Destination, Hops, Args> CheckAssertion<Origin, Destination, Hops, Args> for Tuple
131where
132	Origin: Chain + Clone,
133	Destination: Chain + Clone,
134	Origin::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Origin::Runtime>> + Clone,
135	Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
136	Hops: Clone,
137	Args: Clone,
138{
139	fn check_assertion(test: Test<Origin, Destination, Hops, Args>) {
140		for_tuples!( #(
141			Tuple::check_assertion(test.clone());
142		)* );
143	}
144}
145
146// Implement optional inherent code to be executed
147// This will be executed after on-initialize and before on-finalize
148pub trait AdditionalInherentCode {
149	fn on_new_block() -> DispatchResult {
150		Ok(())
151	}
152}
153
154impl AdditionalInherentCode for () {}
155
156pub trait TestExt {
157	fn build_new_ext(storage: Storage) -> TestExternalities;
158	fn new_ext() -> TestExternalities;
159	fn move_ext_out(id: &'static str);
160	fn move_ext_in(id: &'static str);
161	fn reset_ext();
162	fn execute_with<R>(execute: impl FnOnce() -> R) -> R;
163	fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R;
164}
165
166impl TestExt for () {
167	fn build_new_ext(_storage: Storage) -> TestExternalities {
168		TestExternalities::default()
169	}
170	fn new_ext() -> TestExternalities {
171		TestExternalities::default()
172	}
173	fn move_ext_out(_id: &'static str) {}
174	fn move_ext_in(_id: &'static str) {}
175	fn reset_ext() {}
176	fn execute_with<R>(execute: impl FnOnce() -> R) -> R {
177		execute()
178	}
179	fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R {
180		func()
181	}
182}
183
184pub trait Network {
185	type Relay: RelayChain;
186	type Bridge: Bridge;
187
188	fn name() -> &'static str;
189	fn init();
190	fn reset();
191	fn para_ids() -> Vec<u32>;
192	fn relay_block_number() -> u32;
193	fn set_relay_block_number(number: u32);
194	fn process_messages();
195	fn has_unprocessed_messages() -> bool;
196	fn process_downward_messages();
197	fn process_horizontal_messages();
198	fn process_upward_messages();
199	fn process_bridged_messages();
200	fn hrmp_channel_parachain_inherent_data(
201		para_id: u32,
202		relay_parent_number: u32,
203		parent_head_data: HeadData,
204		relay_parent_offset: u64,
205	) -> ParachainInherentData;
206	fn send_horizontal_messages<I: Iterator<Item = (ParaId, RelayBlockNumber, Vec<u8>)>>(
207		to_para_id: u32,
208		iter: I,
209	) {
210		HORIZONTAL_MESSAGES.with(|b| {
211			b.borrow_mut()
212				.get_mut(Self::name())
213				.unwrap()
214				.push_back((to_para_id, iter.collect()))
215		});
216	}
217
218	fn send_upward_message(from_para_id: u32, msg: Vec<u8>) {
219		UPWARD_MESSAGES
220			.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((from_para_id, msg)));
221	}
222
223	fn send_downward_messages(
224		to_para_id: u32,
225		iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
226	) {
227		DOWNWARD_MESSAGES.with(|b| {
228			b.borrow_mut()
229				.get_mut(Self::name())
230				.unwrap()
231				.push_back((to_para_id, iter.collect()))
232		});
233	}
234
235	fn send_bridged_messages(msg: BridgeMessage) {
236		BRIDGED_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back(msg));
237	}
238}
239
240pub trait Chain: TestExt {
241	type Network: Network;
242	type Runtime: SystemConfig;
243	type RuntimeCall: Clone + Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>;
244	type RuntimeOrigin;
245	type RuntimeEvent;
246	type System;
247	type OriginCaller;
248
249	fn account_id_of(seed: &str) -> AccountId {
250		get_public_from_string_or_panic::<sr25519::Public>(seed).into()
251	}
252
253	fn account_data_of(account: AccountIdOf<Self::Runtime>) -> AccountData<Balance>;
254
255	fn events() -> Vec<<Self as Chain>::RuntimeEvent>;
256}
257
258pub trait RelayChain: Chain {
259	type SovereignAccountOf: ConvertLocation<AccountIdOf<Self::Runtime>>;
260	type MessageProcessor: ProcessMessage<Origin = ParaId> + ServiceQueues;
261
262	fn init();
263
264	fn child_location_of(id: ParaId) -> Location {
265		(Ancestor(0), ParachainJunction(id.into())).into()
266	}
267
268	fn sovereign_account_id_of(location: Location) -> AccountIdOf<Self::Runtime> {
269		Self::SovereignAccountOf::convert_location(&location).unwrap()
270	}
271
272	fn sovereign_account_id_of_child_para(id: ParaId) -> AccountIdOf<Self::Runtime> {
273		Self::sovereign_account_id_of(Self::child_location_of(id))
274	}
275}
276
277pub trait Parachain: Chain {
278	type XcmpMessageHandler: XcmpMessageHandler;
279	type LocationToAccountId: ConvertLocation<AccountIdOf<Self::Runtime>>;
280	type ParachainInfo: Get<ParaId>;
281	type ParachainSystem;
282	type MessageProcessor: ProcessMessage + ServiceQueues;
283	type DigestProvider: Convert<BlockNumberFor<Self::Runtime>, Digest>;
284	type AdditionalInherentCode: AdditionalInherentCode;
285
286	fn init();
287
288	fn new_block();
289
290	fn finalize_block();
291
292	fn set_last_head();
293
294	fn para_id() -> ParaId {
295		Self::ext_wrapper(|| Self::ParachainInfo::get())
296	}
297
298	fn parent_location() -> Location {
299		(Parent).into()
300	}
301
302	fn sibling_location_of(para_id: ParaId) -> Location {
303		(Parent, ParachainJunction(para_id.into())).into()
304	}
305
306	fn sovereign_account_id_of(location: Location) -> AccountIdOf<Self::Runtime> {
307		Self::LocationToAccountId::convert_location(&location).unwrap()
308	}
309}
310
311pub trait Bridge {
312	type Source: TestExt;
313	type Target: TestExt;
314	type Handler: BridgeMessageHandler;
315
316	fn init();
317}
318
319impl Bridge for () {
320	type Source = ();
321	type Target = ();
322	type Handler = ();
323
324	fn init() {}
325}
326
327pub type BridgeLaneId = Vec<u8>;
328
329#[derive(Clone, Default, Debug)]
330pub struct BridgeMessage {
331	pub lane_id: BridgeLaneId,
332	pub nonce: u64,
333	pub payload: Vec<u8>,
334}
335
336pub trait BridgeMessageHandler {
337	fn get_source_outbound_messages() -> Vec<BridgeMessage>;
338
339	fn dispatch_target_inbound_message(
340		message: BridgeMessage,
341	) -> Result<(), BridgeMessageDispatchError>;
342
343	fn notify_source_message_delivery(lane_id: BridgeLaneId);
344}
345
346impl BridgeMessageHandler for () {
347	fn get_source_outbound_messages() -> Vec<BridgeMessage> {
348		Default::default()
349	}
350
351	fn dispatch_target_inbound_message(
352		_message: BridgeMessage,
353	) -> Result<(), BridgeMessageDispatchError> {
354		Err(BridgeMessageDispatchError(Box::new("Not a bridge")))
355	}
356
357	fn notify_source_message_delivery(_lane_id: BridgeLaneId) {}
358}
359
360#[derive(Debug)]
361pub struct BridgeMessageDispatchError(pub Box<dyn Debug>);
362
363impl Error for BridgeMessageDispatchError {}
364
365impl fmt::Display for BridgeMessageDispatchError {
366	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367		write!(f, "{:?}", self.0)
368	}
369}
370
371// Relay Chain Implementation
372#[macro_export]
373macro_rules! decl_test_relay_chains {
374	(
375		$(
376			#[api_version($api_version:tt)]
377			pub struct $name:ident {
378				genesis = $genesis:expr,
379				on_init = $on_init:expr,
380				runtime = $runtime:ident,
381				core = {
382					SovereignAccountOf: $sovereign_acc_of:path,
383				},
384				pallets = {
385					$($pallet_name:ident: $pallet_path:path,)*
386				}
387			}
388		),
389		+
390		$(,)?
391	) => {
392		$(
393			#[derive(Clone)]
394			pub struct $name<N>($crate::PhantomData<N>);
395
396			impl<N: $crate::Network> $crate::Chain for $name<N> {
397				type Network = N;
398				type Runtime = $runtime::Runtime;
399				type RuntimeCall = $runtime::RuntimeCall;
400				type RuntimeOrigin = $runtime::RuntimeOrigin;
401				type RuntimeEvent = $runtime::RuntimeEvent;
402				type System = $crate::SystemPallet::<Self::Runtime>;
403				type OriginCaller = $runtime::OriginCaller;
404
405				fn account_data_of(account: $crate::AccountIdOf<Self::Runtime>) -> $crate::AccountData<$crate::Balance> {
406					<Self as $crate::TestExt>::ext_wrapper(|| $crate::SystemPallet::<Self::Runtime>::account(account).data.into())
407				}
408
409				fn events() -> Vec<<Self as $crate::Chain>::RuntimeEvent> {
410					Self::System::events()
411						.iter()
412						.map(|record| record.event.clone())
413						.collect()
414				}
415			}
416
417			impl<N: $crate::Network> $crate::RelayChain for $name<N> {
418				type SovereignAccountOf = $sovereign_acc_of;
419				type MessageProcessor = $crate::DefaultRelayMessageProcessor<$name<N>>;
420
421				fn init() {
422					use $crate::TestExt;
423					// Initialize the thread local variable
424					$crate::paste::paste! {
425						[<LOCAL_EXT_ $name:upper>].with(|v| *v.borrow_mut() = Self::build_new_ext($genesis));
426					}
427				}
428			}
429
430			$crate::paste::paste! {
431				pub trait [<$name RelayPallet>] {
432					$(
433						type $pallet_name;
434					)?
435				}
436
437				impl<N: $crate::Network> [<$name RelayPallet>] for $name<N> {
438					$(
439						type $pallet_name = $pallet_path;
440					)?
441				}
442			}
443
444			$crate::__impl_test_ext_for_relay_chain!($name, N, $genesis, $on_init, $api_version);
445			$crate::__impl_check_assertion!($name, N);
446		)+
447	};
448}
449
450#[macro_export]
451macro_rules! __impl_test_ext_for_relay_chain {
452	// entry point: generate ext name
453	($name:ident, $network:ident, $genesis:expr, $on_init:expr, $api_version:tt) => {
454		$crate::paste::paste! {
455			$crate::__impl_test_ext_for_relay_chain!(
456				@impl $name,
457				$network,
458				$genesis,
459				$on_init,
460				[<ParachainHostV $api_version>],
461				[<LOCAL_EXT_ $name:upper>],
462				[<GLOBAL_EXT_ $name:upper>]
463			);
464		}
465	};
466	// impl
467	(@impl $name:ident, $network:ident, $genesis:expr, $on_init:expr, $api_version:ident, $local_ext:ident, $global_ext:ident) => {
468		thread_local! {
469			pub static $local_ext: $crate::RefCell<$crate::TestExternalities>
470				= $crate::RefCell::new($crate::TestExternalities::new($genesis));
471		}
472
473		pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>>>
474			= $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())));
475
476		impl<$network: $crate::Network> $crate::TestExt for $name<$network> {
477			fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities {
478				use $crate::{sp_tracing, Network, Chain, TestExternalities};
479
480				let mut ext = TestExternalities::new(storage);
481
482				ext.execute_with(|| {
483					#[allow(clippy::no_effect)]
484					$on_init;
485					sp_tracing::try_init_simple();
486
487					let mut block_number = <Self as Chain>::System::block_number();
488					block_number = std::cmp::max(1, block_number);
489					<Self as Chain>::System::set_block_number(block_number);
490				});
491				ext
492			}
493
494			fn new_ext() -> $crate::TestExternalities {
495				Self::build_new_ext($genesis)
496			}
497
498			fn move_ext_out(id: &'static str) {
499				use $crate::Deref;
500
501				// Take TestExternality from thread_local
502				let local_ext = $local_ext.with(|v| {
503					v.take()
504				});
505
506				// Get TestExternality from LazyLock
507				let global_ext_guard = $global_ext.lock().unwrap();
508
509				// Replace TestExternality in LazyLock by TestExternality from thread_local
510				global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext);
511			}
512
513			fn move_ext_in(id: &'static str) {
514				use $crate::Deref;
515
516				let mut global_ext_unlocked = false;
517
518				// Keep the mutex unlocked until TesExternality from LazyLock
519				// has been updated
520				while !global_ext_unlocked {
521					// Get TesExternality from LazyLock
522					let global_ext_result = $global_ext.try_lock();
523
524					if let Ok(global_ext_guard) = global_ext_result {
525						// Unlock the mutex as long as the condition is not met
526						if !global_ext_guard.deref().borrow().contains_key(id) {
527							drop(global_ext_guard);
528						} else {
529							global_ext_unlocked = true;
530						}
531					}
532				}
533
534				// Now that we know that TestExt has been updated, we lock its mutex
535				let mut global_ext_guard = $global_ext.lock().unwrap();
536
537				// and set TesExternality from LazyLock into TesExternality for local_thread
538				let global_ext = global_ext_guard.deref();
539
540				$local_ext.with(|v| {
541					v.replace(global_ext.take().remove(id).unwrap());
542				});
543			}
544
545			fn reset_ext() {
546				$local_ext.with(|v| *v.borrow_mut() = Self::build_new_ext($genesis));
547			}
548
549			fn execute_with<R>(execute: impl FnOnce() -> R) -> R {
550				use $crate::{Chain, Network};
551				// Make sure the Network is initialized
552				<$network>::init();
553
554				// Execute
555				let r = $local_ext.with(|v| {
556					$crate::log::info!(target: "xcm::emulator::execute_with", "Executing as {}", stringify!($name));
557					v.borrow_mut().execute_with(execute)
558				});
559
560				// Send messages if needed
561				$local_ext.with(|v| {
562					v.borrow_mut().execute_with(|| {
563						use $crate::polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::$api_version;
564
565						//TODO: mark sent count & filter out sent msg
566						for para_id in <$network>::para_ids() {
567							// downward messages
568							let downward_messages = <Self as $crate::Chain>::Runtime::dmq_contents(para_id.into())
569								.into_iter()
570								.map(|inbound| (inbound.sent_at, inbound.msg));
571							if downward_messages.len() == 0 {
572								continue;
573							}
574							<$network>::send_downward_messages(para_id, downward_messages.into_iter());
575
576							// Note: no need to handle horizontal messages, as the
577							// simulator directly sends them to dest (not relayed).
578						}
579
580						// log events
581						Self::events().iter().for_each(|event| {
582							$crate::log::info!(target: concat!("events::", stringify!($name)), "{:?}", event);
583						});
584
585						// clean events
586						<Self as Chain>::System::reset_events();
587					})
588				});
589
590				<$network>::process_messages();
591
592				r
593			}
594
595			fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R {
596				$local_ext.with(|v| {
597					v.borrow_mut().execute_with(|| {
598						func()
599					})
600				})
601			}
602		}
603	};
604}
605
606// Parachain Implementation
607#[macro_export]
608macro_rules! decl_test_parachains {
609	(
610		$(
611			pub struct $name:ident {
612				genesis = $genesis:expr,
613				on_init = $on_init:expr,
614				runtime = $runtime:ident,
615				core = {
616					XcmpMessageHandler: $xcmp_message_handler:path,
617					LocationToAccountId: $location_to_account:path,
618					ParachainInfo: $parachain_info:path,
619					MessageOrigin: $message_origin:path,
620					$( DigestProvider: $digest_provider:ty,)?
621					$( AdditionalInherentCode: $additional_inherent_code:ty,)?
622				},
623				pallets = {
624					$($pallet_name:ident: $pallet_path:path,)*
625				}
626			}
627		),
628		+
629		$(,)?
630	) => {
631		$(
632			#[derive(Clone)]
633			pub struct $name<N>($crate::PhantomData<N>);
634
635			impl<N: $crate::Network> $crate::Chain for $name<N> {
636				type Runtime = $runtime::Runtime;
637				type RuntimeCall = $runtime::RuntimeCall;
638				type RuntimeOrigin = $runtime::RuntimeOrigin;
639				type RuntimeEvent = $runtime::RuntimeEvent;
640				type System = $crate::SystemPallet::<Self::Runtime>;
641				type OriginCaller = $runtime::OriginCaller;
642				type Network = N;
643
644				fn account_data_of(account: $crate::AccountIdOf<Self::Runtime>) -> $crate::AccountData<$crate::Balance> {
645					<Self as $crate::TestExt>::ext_wrapper(|| $crate::SystemPallet::<Self::Runtime>::account(account).data.into())
646				}
647
648				fn events() -> Vec<<Self as $crate::Chain>::RuntimeEvent> {
649					Self::System::events()
650						.iter()
651						.map(|record| record.event.clone())
652						.collect()
653				}
654			}
655
656			impl<N: $crate::Network> $crate::Parachain for $name<N> {
657				type XcmpMessageHandler = $xcmp_message_handler;
658				type LocationToAccountId = $location_to_account;
659				type ParachainSystem = $crate::ParachainSystemPallet<<Self as $crate::Chain>::Runtime>;
660				type ParachainInfo = $parachain_info;
661				type MessageProcessor = $crate::DefaultParaMessageProcessor<$name<N>, $message_origin>;
662				$crate::decl_test_parachains!(@inner_digest_provider $($digest_provider)?);
663				$crate::decl_test_parachains!(@inner_additional_inherent_code $($additional_inherent_code)?);
664
665				// We run an empty block during initialisation to open HRMP channels
666				// and have them ready for the next block
667				fn init() {
668					use $crate::{Chain, TestExt};
669
670					// Initialize the thread local variable
671					$crate::paste::paste! {
672						[<LOCAL_EXT_ $name:upper>].with(|v| *v.borrow_mut() = Self::build_new_ext($genesis));
673					}
674					// Set the last block head for later use in the next block
675					Self::set_last_head();
676					// Initialize a new block
677					Self::new_block();
678					// Finalize the new block
679					Self::finalize_block();
680				}
681
682				fn new_block() {
683					use $crate::{
684						Dispatchable, Chain, Convert, TestExt, Zero, AdditionalInherentCode
685					};
686
687					let para_id = Self::para_id().into();
688
689					Self::ext_wrapper(|| {
690						// Increase Relay Chain block number
691						let mut relay_block_number = N::relay_block_number();
692						relay_block_number += 1;
693						N::set_relay_block_number(relay_block_number);
694
695						// Initialize a new Parachain block
696						let mut block_number = <Self as Chain>::System::block_number();
697						block_number += 1;
698						let parent_head_data = $crate::LAST_HEAD.with(|b| b.borrow_mut()
699							.get_mut(N::name())
700							.expect("network not initialized?")
701							.get(&para_id)
702							.expect("network not initialized?")
703							.clone()
704						);
705
706						// Initialze `System`.
707						let digest = <Self as Parachain>::DigestProvider::convert(block_number);
708						<Self as Chain>::System::initialize(&block_number, &parent_head_data.hash(), &digest);
709
710						// Process `on_initialize` for all pallets except `System`.
711						let _ = $runtime::AllPalletsWithoutSystem::on_initialize(block_number);
712
713						// Process parachain inherents:
714
715						// Get RelayParentOffset from the runtime
716						let relay_parent_offset = <<<Self as $crate::Chain>::Runtime as $crate::ParachainSystemConfig>::RelayParentOffset as $crate::Get<u32>>::get();
717						// 1. inherent: cumulus_pallet_parachain_system::Call::set_validation_data
718						let data = N::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data, relay_parent_offset as u64);
719						let (data, mut downward_messages, mut horizontal_messages) =
720							$crate::deconstruct_parachain_inherent_data(data);
721						let inbound_messages_data = $crate::InboundMessagesData::new(
722							downward_messages.into_abridged(&mut usize::MAX.clone()),
723							horizontal_messages.into_abridged(&mut usize::MAX.clone()),
724						);
725						let set_validation_data: <Self as Chain>::RuntimeCall = $crate::ParachainSystemCall::set_validation_data {
726							data,
727							inbound_messages_data
728						}.into();
729						$crate::assert_ok!(
730							set_validation_data.dispatch(<Self as Chain>::RuntimeOrigin::none())
731						);
732
733						// 2. inherent: pallet_timestamp::Call::set (we expect the parachain has `pallet_timestamp`)
734						let timestamp_set: <Self as Chain>::RuntimeCall = $crate::TimestampCall::set {
735							// We need to satisfy `pallet_timestamp::on_finalize`.
736							now: Zero::zero(),
737						}.into();
738						$crate::assert_ok!(
739							timestamp_set.dispatch(<Self as Chain>::RuntimeOrigin::none())
740						);
741
742
743						$crate::assert_ok!(
744							<Self as Parachain>::AdditionalInherentCode::on_new_block()
745						);
746					});
747				}
748
749				fn finalize_block() {
750					use $crate::{BlockWeightsLimits, Chain, OnFinalize, OnIdle, SystemConfig, TestExt, Weight};
751
752					Self::ext_wrapper(|| {
753						let block_number = <Self as Chain>::System::block_number();
754
755						// Process `on_idle` for all pallets.
756						let weight = <Self as Chain>::System::block_weight();
757						let max_weight: Weight = <<<Self as Chain>::Runtime as SystemConfig>::BlockWeights as frame_support::traits::Get<BlockWeightsLimits>>::get().max_block;
758						let remaining_weight = max_weight.saturating_sub(weight.total());
759						if remaining_weight.all_gt(Weight::zero()) {
760							let _ = $runtime::AllPalletsWithSystem::on_idle(block_number, remaining_weight);
761						}
762
763						// Process `on_finalize` for all pallets except `System`.
764						$runtime::AllPalletsWithoutSystem::on_finalize(block_number);
765					});
766
767					Self::set_last_head();
768				}
769
770
771				fn set_last_head() {
772					use $crate::{Chain, Encode, HeadData, TestExt};
773
774					let para_id = Self::para_id().into();
775
776					Self::ext_wrapper(|| {
777						// Store parent head data for use later.
778						let created_header = <Self as Chain>::System::finalize();
779						$crate::LAST_HEAD.with(|b| b.borrow_mut()
780							.get_mut(N::name())
781							.expect("network not initialized?")
782							.insert(para_id, HeadData(created_header.encode()))
783						);
784					});
785				}
786			}
787
788			$crate::paste::paste! {
789				pub trait [<$name ParaPallet>] {
790					$(
791						type $pallet_name;
792					)*
793				}
794
795				impl<N: $crate::Network> [<$name ParaPallet>] for $name<N> {
796					$(
797						type $pallet_name = $pallet_path;
798					)*
799				}
800			}
801
802			$crate::__impl_test_ext_for_parachain!($name, N, $genesis, $on_init);
803			$crate::__impl_check_assertion!($name, N);
804		)+
805	};
806	( @inner_digest_provider $digest_provider:ty ) => { type DigestProvider = $digest_provider; };
807	( @inner_digest_provider /* none */ ) => { type DigestProvider = (); };
808	( @inner_additional_inherent_code $additional_inherent_code:ty ) => { type AdditionalInherentCode = $additional_inherent_code; };
809	( @inner_additional_inherent_code /* none */ ) => { type AdditionalInherentCode = (); };
810}
811
812#[macro_export]
813macro_rules! __impl_test_ext_for_parachain {
814	// entry point: generate ext name
815	($name:ident, $network:ident, $genesis:expr, $on_init:expr) => {
816		$crate::paste::paste! {
817			$crate::__impl_test_ext_for_parachain!(@impl $name, $network, $genesis, $on_init, [<LOCAL_EXT_ $name:upper>], [<GLOBAL_EXT_ $name:upper>]);
818		}
819	};
820	// impl
821	(@impl $name:ident, $network:ident, $genesis:expr, $on_init:expr, $local_ext:ident, $global_ext:ident) => {
822		thread_local! {
823			pub static $local_ext: $crate::RefCell<$crate::TestExternalities>
824				= $crate::RefCell::new($crate::TestExternalities::new($genesis));
825		}
826
827		pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>>>
828			= $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())));
829
830		impl<$network: $crate::Network> $crate::TestExt for $name<$network> {
831			fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities {
832				let mut ext = $crate::TestExternalities::new(storage);
833
834				ext.execute_with(|| {
835					#[allow(clippy::no_effect)]
836					$on_init;
837					$crate::sp_tracing::try_init_simple();
838
839					let mut block_number = <Self as $crate::Chain>::System::block_number();
840					block_number = std::cmp::max(1, block_number);
841					<Self as $crate::Chain>::System::set_block_number(block_number);
842				});
843				ext
844			}
845
846			fn new_ext() -> $crate::TestExternalities {
847				Self::build_new_ext($genesis)
848			}
849
850			fn move_ext_out(id: &'static str) {
851				use $crate::Deref;
852
853				// Take TestExternality from thread_local
854				let local_ext = $local_ext.with(|v| {
855					v.take()
856				});
857
858				// Get TestExternality from LazyLock
859				let global_ext_guard = $global_ext.lock().unwrap();
860
861				// Replace TestExternality in LazyLock by TestExternality from thread_local
862				global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext);
863			}
864
865			fn move_ext_in(id: &'static str) {
866				use $crate::Deref;
867
868				let mut global_ext_unlocked = false;
869
870				// Keep the mutex unlocked until TesExternality from LazyLock
871				// has been updated
872				while !global_ext_unlocked {
873					// Get TesExternality from LazyLock
874					let global_ext_result = $global_ext.try_lock();
875
876					if let Ok(global_ext_guard) = global_ext_result {
877						// Unlock the mutex as long as the condition is not met
878						if !global_ext_guard.deref().borrow().contains_key(id) {
879							drop(global_ext_guard);
880						} else {
881							global_ext_unlocked = true;
882						}
883					}
884				}
885
886				// Now that we know that TestExt has been updated, we lock its mutex
887				let mut global_ext_guard = $global_ext.lock().unwrap();
888
889				// and set TesExternality from LazyLock into TesExternality for local_thread
890				let global_ext = global_ext_guard.deref();
891
892				$local_ext.with(|v| {
893					v.replace(global_ext.take().remove(id).unwrap());
894				});
895			}
896
897			fn reset_ext() {
898				$local_ext.with(|v| *v.borrow_mut() = Self::build_new_ext($genesis));
899			}
900
901			fn execute_with<R>(execute: impl FnOnce() -> R) -> R {
902				use $crate::{Chain, Get, Hooks, Network, Parachain, Encode};
903
904				// Make sure the Network is initialized
905				<$network>::init();
906
907				// Initialize a new block
908				Self::new_block();
909
910				// Execute
911				let r = $local_ext.with(|v| {
912					$crate::log::info!(target: "xcm::emulator::execute_with", "Executing as {}", stringify!($name));
913					v.borrow_mut().execute_with(execute)
914				});
915
916				// Finalize the block
917				Self::finalize_block();
918
919				let para_id = Self::para_id().into();
920
921				// Send messages if needed
922				$local_ext.with(|v| {
923					v.borrow_mut().execute_with(|| {
924						let mock_header = $crate::HeaderT::new(
925							0,
926							Default::default(),
927							Default::default(),
928							Default::default(),
929							Default::default(),
930						);
931
932						let collation_info = <Self as Parachain>::ParachainSystem::collect_collation_info(&mock_header);
933
934						// send upward messages
935						let relay_block_number = <$network>::relay_block_number();
936						for msg in collation_info.upward_messages.clone() {
937							<$network>::send_upward_message(para_id, msg);
938						}
939
940						// send horizontal messages
941						for msg in collation_info.horizontal_messages {
942							<$network>::send_horizontal_messages(
943								msg.recipient.into(),
944								vec![(para_id.into(), relay_block_number, msg.data)].into_iter(),
945							);
946						}
947
948						// get bridge messages
949						type NetworkBridge<$network> = <$network as $crate::Network>::Bridge;
950
951						let bridge_messages = <<NetworkBridge<$network> as $crate::Bridge>::Handler as $crate::BridgeMessageHandler>::get_source_outbound_messages();
952
953						// send bridged messages
954						for msg in bridge_messages {
955							<$network>::send_bridged_messages(msg);
956						}
957
958						// log events
959						<Self as $crate::Chain>::events().iter().for_each(|event| {
960							$crate::log::info!(target: concat!("events::", stringify!($name)), "{:?}", event);
961						});
962
963						// clean events
964						<Self as $crate::Chain>::System::reset_events();
965					})
966				});
967
968				// provide inbound DMP/HRMP messages through a side-channel.
969				// normally this would come through the `set_validation_data`,
970				// but we go around that.
971				<$network>::process_messages();
972
973				r
974			}
975
976			fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R {
977				$local_ext.with(|v| {
978					v.borrow_mut().execute_with(|| {
979						func()
980					})
981				})
982			}
983		}
984	};
985}
986
987// Network Implementation
988#[macro_export]
989macro_rules! decl_test_networks {
990	(
991		$(
992			pub struct $name:ident {
993				relay_chain = $relay_chain:ident,
994				parachains = vec![ $( $parachain:ident, )* ],
995				bridge = $bridge:ty
996			}
997		),
998		+
999		$(,)?
1000	) => {
1001		$(
1002			#[derive(Clone)]
1003			pub struct $name;
1004
1005			impl $crate::Network for $name {
1006				type Relay = $relay_chain<Self>;
1007				type Bridge = $bridge;
1008
1009				fn name() -> &'static str {
1010					$crate::type_name::<Self>()
1011				}
1012
1013				fn reset() {
1014					use $crate::{TestExt};
1015
1016					$crate::INITIALIZED.with(|b| b.borrow_mut().remove(Self::name()));
1017					$crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().remove(Self::name()));
1018					$crate::DMP_DONE.with(|b| b.borrow_mut().remove(Self::name()));
1019					$crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().remove(Self::name()));
1020					$crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().remove(Self::name()));
1021					$crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().remove(Self::name()));
1022					$crate::LAST_HEAD.with(|b| b.borrow_mut().remove(Self::name()));
1023
1024					<$relay_chain<Self>>::reset_ext();
1025					$( <$parachain<Self>>::reset_ext(); )*
1026				}
1027
1028				fn init() {
1029					// If Network has not been initialized yet, it gets initialized
1030					if $crate::INITIALIZED.with(|b| b.borrow_mut().get(Self::name()).is_none()) {
1031						$crate::INITIALIZED.with(|b| b.borrow_mut().insert(Self::name().to_string(), true));
1032						$crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new()));
1033						$crate::DMP_DONE.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new()));
1034						$crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new()));
1035						$crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new()));
1036						$crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new()));
1037						$crate::PARA_IDS.with(|b| b.borrow_mut().insert(Self::name().to_string(), Self::para_ids()));
1038						$crate::LAST_HEAD.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::HashMap::new()));
1039
1040						<$relay_chain<Self> as $crate::RelayChain>::init();
1041						$( <$parachain<Self> as $crate::Parachain>::init(); )*
1042					}
1043				}
1044
1045				fn para_ids() -> Vec<u32> {
1046					vec![$(
1047						<$parachain<Self> as $crate::Parachain>::para_id().into(),
1048					)*]
1049				}
1050
1051				fn relay_block_number() -> u32 {
1052					<Self::Relay as $crate::TestExt>::ext_wrapper(|| {
1053						<Self::Relay as $crate::Chain>::System::block_number()
1054					})
1055				}
1056
1057				fn set_relay_block_number(number: u32) {
1058					<Self::Relay as $crate::TestExt>::ext_wrapper(|| {
1059						<Self::Relay as $crate::Chain>::System::set_block_number(number);
1060					})
1061				}
1062
1063				fn process_messages() {
1064					while Self::has_unprocessed_messages() {
1065						Self::process_upward_messages();
1066						Self::process_horizontal_messages();
1067						Self::process_downward_messages();
1068						Self::process_bridged_messages();
1069					}
1070				}
1071
1072				fn has_unprocessed_messages() -> bool {
1073					$crate::DOWNWARD_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty())
1074					|| $crate::HORIZONTAL_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty())
1075					|| $crate::UPWARD_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty())
1076					|| $crate::BRIDGED_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty())
1077				}
1078
1079				fn process_downward_messages() {
1080					use $crate::{DmpMessageHandler, Bounded, Parachain, RelayChainBlockNumber, TestExt, Encode};
1081
1082					while let Some((to_para_id, messages))
1083						= $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) {
1084						$(
1085							let para_id: u32 = <$parachain<Self>>::para_id().into();
1086
1087							if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id {
1088								let mut msg_dedup: Vec<(RelayChainBlockNumber, Vec<u8>)> = Vec::new();
1089								for m in &messages {
1090									msg_dedup.push((m.0, m.1.clone()));
1091								}
1092								msg_dedup.dedup();
1093
1094								let msgs = msg_dedup.clone().into_iter().filter(|m| {
1095									!$crate::DMP_DONE.with(|b| b.borrow().get(Self::name())
1096										.unwrap_or(&mut $crate::VecDeque::new())
1097										.contains(&(to_para_id, m.0, m.1.clone()))
1098									)
1099								}).collect::<Vec<(RelayChainBlockNumber, Vec<u8>)>>();
1100
1101								use $crate::{ProcessMessage, CumulusAggregateMessageOrigin, BoundedSlice, WeightMeter};
1102								for (block, msg) in msgs.clone().into_iter() {
1103									let mut weight_meter = WeightMeter::new();
1104									<$parachain<Self>>::ext_wrapper(|| {
1105										let _ =  <$parachain<Self> as Parachain>::MessageProcessor::process_message(
1106											&msg[..],
1107											$crate::CumulusAggregateMessageOrigin::Parent.into(),
1108											&mut weight_meter,
1109											&mut msg.using_encoded($crate::blake2_256),
1110										);
1111									});
1112									let messages = msgs.clone().iter().map(|(block, message)| {
1113										(*block, $crate::array_bytes::bytes2hex("0x", message))
1114									}).collect::<Vec<_>>();
1115									$crate::log::info!(target: concat!("xcm::dmp::", stringify!($name)) , "Downward messages processed by para_id {:?}: {:?}", &to_para_id, messages);
1116									$crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((to_para_id, block, msg)));
1117								}
1118							}
1119						)*
1120					}
1121				}
1122
1123				fn process_horizontal_messages() {
1124					use $crate::{XcmpMessageHandler, ServiceQueues, Bounded, Parachain, TestExt};
1125
1126					while let Some((to_para_id, messages))
1127						= $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) {
1128						let iter = messages.iter().map(|(para_id, relay_block_number, message)| (*para_id, *relay_block_number, &message[..])).collect::<Vec<_>>().into_iter();
1129						$(
1130							let para_id: u32 = <$parachain<Self>>::para_id().into();
1131
1132							if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id {
1133								<$parachain<Self>>::ext_wrapper(|| {
1134									<$parachain<Self> as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter.clone(), $crate::Weight::MAX);
1135									// Nudge the MQ pallet to process immediately instead of in the next block.
1136									let _ =  <$parachain<Self> as Parachain>::MessageProcessor::service_queues($crate::Weight::MAX);
1137								});
1138								let messages = messages.clone().iter().map(|(para_id, relay_block_number, message)| {
1139									(*para_id, *relay_block_number, $crate::array_bytes::bytes2hex("0x", message))
1140								}).collect::<Vec<_>>();
1141								$crate::log::info!(target: concat!("xcm::hrmp::", stringify!($name)), "Horizontal messages processed by para_id {:?}: {:?}", &to_para_id, &messages);
1142							}
1143						)*
1144					}
1145				}
1146
1147				fn process_upward_messages() {
1148					use $crate::{Encode, ProcessMessage, TestExt, WeightMeter};
1149
1150					while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) {
1151						let mut weight_meter = WeightMeter::new();
1152						<$relay_chain<Self>>::ext_wrapper(|| {
1153							let _ =  <$relay_chain<Self> as $crate::RelayChain>::MessageProcessor::process_message(
1154								&msg[..],
1155								from_para_id.into(),
1156								&mut weight_meter,
1157								&mut msg.using_encoded($crate::blake2_256),
1158							);
1159						});
1160						let message = $crate::array_bytes::bytes2hex("0x", msg.clone());
1161						$crate::log::info!(target: concat!("xcm::ump::", stringify!($name)) , "Upward message processed from para_id {:?}: {:?}", &from_para_id, &message);
1162					}
1163				}
1164
1165				fn process_bridged_messages() {
1166					use $crate::{Bridge, BridgeMessageHandler, TestExt};
1167					// Make sure both, including the target `Network` are initialized
1168					<Self::Bridge as Bridge>::init();
1169
1170					while let Some(msg) = $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) {
1171						let dispatch_result = <<Self::Bridge as Bridge>::Target as TestExt>::ext_wrapper(|| {
1172							<<Self::Bridge as Bridge>::Handler as BridgeMessageHandler>::dispatch_target_inbound_message(msg.clone())
1173						});
1174
1175						match dispatch_result {
1176							Err(e) => panic!("Error {:?} processing bridged message: {:?}", e, msg),
1177							Ok(()) => {
1178								<<Self::Bridge as Bridge>::Source as TestExt>::ext_wrapper(|| {
1179									<<Self::Bridge as Bridge>::Handler as BridgeMessageHandler>::notify_source_message_delivery(msg.lane_id.clone());
1180								});
1181								$crate::log::info!(target: concat!("bridge::", stringify!($name)) , "Bridged message processed {:?}", msg);
1182							}
1183						}
1184					}
1185				}
1186
1187				fn hrmp_channel_parachain_inherent_data(
1188					para_id: u32,
1189					relay_parent_number: u32,
1190					parent_head_data: $crate::HeadData,
1191					relay_parent_offset: u64,
1192				) -> $crate::ParachainInherentData {
1193					let mut sproof = $crate::RelayStateSproofBuilder::default();
1194					sproof.para_id = para_id.into();
1195					sproof.current_slot = $crate::polkadot_primitives::Slot::from(relay_parent_number as u64);
1196					sproof.host_config.max_upward_message_size = 1024 * 1024;
1197					sproof.num_authorities = relay_parent_offset + 1;
1198
1199					// egress channel
1200					let e_index = sproof.hrmp_egress_channel_index.get_or_insert_with(Vec::new);
1201					for recipient_para_id in $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().clone()) {
1202						let recipient_para_id = $crate::ParaId::from(recipient_para_id);
1203						if let Err(idx) = e_index.binary_search(&recipient_para_id) {
1204							e_index.insert(idx, recipient_para_id);
1205						}
1206
1207						sproof.included_para_head = parent_head_data.clone().into();
1208
1209						sproof
1210							.hrmp_channels
1211							.entry($crate::HrmpChannelId {
1212								sender: sproof.para_id,
1213								recipient: recipient_para_id,
1214							})
1215							.or_insert_with(|| $crate::AbridgedHrmpChannel {
1216								max_capacity: 1024,
1217								max_total_size: 1024 * 1024,
1218								max_message_size: 1024 * 1024,
1219								msg_count: 0,
1220								total_size: 0,
1221								mqc_head: Option::None,
1222							});
1223					}
1224
1225					let (relay_storage_root, proof, relay_parent_descendants) =
1226						sproof.into_state_root_proof_and_descendants(relay_parent_offset);
1227
1228					$crate::ParachainInherentData {
1229						validation_data: $crate::PersistedValidationData {
1230							parent_head: parent_head_data.clone(),
1231							relay_parent_number,
1232							relay_parent_storage_root: relay_storage_root,
1233							max_pov_size: Default::default(),
1234						},
1235						relay_chain_state: proof,
1236						downward_messages: Default::default(),
1237						horizontal_messages: Default::default(),
1238						relay_parent_descendants,
1239						collator_peer_id: None,
1240					}
1241				}
1242			}
1243
1244			$crate::paste::paste! {
1245				pub type [<$relay_chain Relay>] = $relay_chain<$name>;
1246			}
1247
1248			$(
1249				$crate::paste::paste! {
1250					pub type [<$parachain Para>] = $parachain<$name>;
1251				}
1252			)*
1253		)+
1254	};
1255}
1256
1257#[macro_export]
1258macro_rules! decl_test_bridges {
1259	(
1260		$(
1261			pub struct $name:ident {
1262				source = $source:ident,
1263				target = $target:ident,
1264				handler = $handler:ident
1265			}
1266		),
1267		+
1268		$(,)?
1269	) => {
1270		$(
1271			#[derive(Debug)]
1272			pub struct $name;
1273
1274			impl $crate::Bridge for $name {
1275				type Source = $source;
1276				type Target = $target;
1277				type Handler = $handler;
1278
1279				fn init() {
1280					use $crate::{Network, Parachain};
1281					// Make sure source and target `Network` have been initialized
1282					<$source as Chain>::Network::init();
1283					<$target as Chain>::Network::init();
1284				}
1285			}
1286		)+
1287	};
1288}
1289
1290#[macro_export]
1291macro_rules! __impl_check_assertion {
1292	($chain:ident, $network:ident) => {
1293		impl<$network, Origin, Destination, Hops, Args>
1294			$crate::CheckAssertion<Origin, Destination, Hops, Args> for $chain<$network>
1295		where
1296			$network: $crate::Network,
1297			Origin: $crate::Chain + Clone,
1298			Destination: $crate::Chain + Clone,
1299			Origin::RuntimeOrigin:
1300				$crate::OriginTrait<AccountId = $crate::AccountIdOf<Origin::Runtime>> + Clone,
1301			Destination::RuntimeOrigin:
1302				$crate::OriginTrait<AccountId = $crate::AccountIdOf<Destination::Runtime>> + Clone,
1303			Hops: Clone,
1304			Args: Clone,
1305		{
1306			fn check_assertion(test: $crate::Test<Origin, Destination, Hops, Args>) {
1307				use $crate::{Dispatchable, TestExt};
1308
1309				let chain_name = std::any::type_name::<$chain<$network>>();
1310
1311				<$chain<$network>>::execute_with(|| {
1312					if let Some(dispatchable) = test.hops_dispatchable.get(chain_name) {
1313						$crate::assert_ok!(dispatchable(test.clone()));
1314					}
1315					if let Some(call) = test.hops_calls.get(chain_name) {
1316						$crate::assert_ok!(
1317							match call.clone().dispatch(test.signed_origin.clone()) {
1318								// We get rid of `post_info`.
1319								Ok(_) => Ok(()),
1320								Err(error_with_post_info) => Err(error_with_post_info.error),
1321							}
1322						);
1323					}
1324					if let Some(assertion) = test.hops_assertion.get(chain_name) {
1325						assertion(test);
1326					}
1327				});
1328			}
1329		}
1330	};
1331}
1332
1333#[macro_export]
1334macro_rules! assert_expected_events {
1335    ( $chain:ident, vec![$( $event_pat:pat => { $($attr:ident : $condition:expr, )* }, )*] ) => {
1336		let mut messages: Vec<String> = Vec::new();
1337		let mut events = <$chain as $crate::Chain>::events();
1338
1339		// For each event pattern, we try to find a matching event.
1340		$(
1341			// We'll store a string representation of the first partially matching event.
1342			let mut failure_message: Option<String> = None;
1343			let mut event_received = false;
1344			for index in 0..events.len() {
1345				let event = &events[index];
1346				match event {
1347					$event_pat => {
1348						let mut event_meets_conditions = true;
1349						let mut conditions_message: Vec<String> = Vec::new();
1350						event_received = true;
1351
1352						$(
1353							if !$condition {
1354								conditions_message.push(
1355									format!(
1356										" - The attribute {} = {:?} did not meet the condition {}\n",
1357										stringify!($attr),
1358										$attr,
1359										stringify!($condition)
1360									)
1361								);
1362							}
1363							event_meets_conditions &= $condition;
1364						)*
1365
1366						if failure_message.is_none() && !conditions_message.is_empty() {
1367							// Record the failure message.
1368							failure_message = Some(format!(
1369								"\n\n{}::\x1b[31m{}\x1b[0m was received but some of its attributes did not meet the conditions.\n\
1370								 Actual event:\n{:#?}\n\
1371								 Failures:\n{}",
1372								stringify!($chain),
1373								stringify!($event_pat),
1374								event,
1375								conditions_message.concat()
1376							));
1377						}
1378
1379						if event_meets_conditions {
1380							// Found an event where all conditions hold.
1381							failure_message = None;
1382							events.remove(index);
1383							break;
1384						}
1385					},
1386					_ => {}
1387				}
1388			}
1389
1390			if !event_received || failure_message.is_some() {
1391				// No event matching the pattern was found.
1392				messages.push(
1393					format!(
1394						"\n\n{}::\x1b[31m{}\x1b[0m was never received. All events:\n{:#?}",
1395						stringify!($chain),
1396						stringify!($event_pat),
1397						<$chain as $crate::Chain>::events(),
1398					)
1399				);
1400			}
1401		)*
1402
1403		if !messages.is_empty() {
1404			// Log all events (since they won't be logged after the panic).
1405			<$chain as $crate::Chain>::events().iter().for_each(|event| {
1406				$crate::log::info!(target: concat!("events::", stringify!($chain)), "{:?}", event);
1407			});
1408			panic!("{}", messages.concat())
1409		}
1410	}
1411}
1412
1413#[macro_export]
1414macro_rules! bx {
1415	($e:expr) => {
1416		Box::new($e)
1417	};
1418}
1419
1420#[macro_export]
1421macro_rules! decl_test_sender_receiver_accounts_parameter_types {
1422	( $( $chain:ident { sender: $sender:expr, receiver: $receiver:expr }),+ ) => {
1423		$crate::paste::paste! {
1424			$crate::parameter_types! {
1425				$(
1426					pub [<$chain Sender>]: $crate::AccountId = <$chain as $crate::Chain>::account_id_of($sender);
1427					pub [<$chain Receiver>]: $crate::AccountId = <$chain as $crate::Chain>::account_id_of($receiver);
1428				)+
1429			}
1430		}
1431	};
1432}
1433
1434pub struct DefaultParaMessageProcessor<T, M>(PhantomData<(T, M)>);
1435// Process HRMP messages from sibling paraids
1436impl<T, M> ProcessMessage for DefaultParaMessageProcessor<T, M>
1437where
1438	M: codec::FullCodec
1439		+ MaxEncodedLen
1440		+ Clone
1441		+ Eq
1442		+ PartialEq
1443		+ frame_support::pallet_prelude::TypeInfo
1444		+ Debug,
1445	T: Parachain,
1446	T::Runtime: MessageQueueConfig,
1447	<<T::Runtime as MessageQueueConfig>::MessageProcessor as ProcessMessage>::Origin: PartialEq<M>,
1448	MessageQueuePallet<T::Runtime>: EnqueueMessage<M> + ServiceQueues,
1449{
1450	type Origin = M;
1451
1452	fn process_message(
1453		msg: &[u8],
1454		orig: Self::Origin,
1455		_meter: &mut WeightMeter,
1456		_id: &mut XcmHash,
1457	) -> Result<bool, ProcessMessageError> {
1458		MessageQueuePallet::<T::Runtime>::enqueue_message(
1459			msg.try_into().expect("Message too long"),
1460			orig.clone(),
1461		);
1462		MessageQueuePallet::<T::Runtime>::service_queues(Weight::MAX);
1463
1464		Ok(true)
1465	}
1466}
1467impl<T, M> ServiceQueues for DefaultParaMessageProcessor<T, M>
1468where
1469	M: MaxEncodedLen,
1470	T: Parachain,
1471	T::Runtime: MessageQueueConfig,
1472	<<T::Runtime as MessageQueueConfig>::MessageProcessor as ProcessMessage>::Origin: PartialEq<M>,
1473	MessageQueuePallet<T::Runtime>: EnqueueMessage<M> + ServiceQueues,
1474{
1475	type OverweightMessageAddress = ();
1476
1477	fn service_queues(weight_limit: Weight) -> Weight {
1478		MessageQueuePallet::<T::Runtime>::service_queues(weight_limit)
1479	}
1480
1481	fn execute_overweight(
1482		_weight_limit: Weight,
1483		_address: Self::OverweightMessageAddress,
1484	) -> Result<Weight, ExecuteOverweightError> {
1485		unimplemented!()
1486	}
1487}
1488
1489pub struct DefaultRelayMessageProcessor<T>(PhantomData<T>);
1490// Process UMP messages on the relay
1491impl<T> ProcessMessage for DefaultRelayMessageProcessor<T>
1492where
1493	T: RelayChain,
1494	T::Runtime: MessageQueueConfig,
1495	<<T::Runtime as MessageQueueConfig>::MessageProcessor as ProcessMessage>::Origin:
1496		PartialEq<AggregateMessageOrigin>,
1497	MessageQueuePallet<T::Runtime>: EnqueueMessage<AggregateMessageOrigin> + ServiceQueues,
1498{
1499	type Origin = ParaId;
1500
1501	fn process_message(
1502		msg: &[u8],
1503		para: Self::Origin,
1504		_meter: &mut WeightMeter,
1505		_id: &mut XcmHash,
1506	) -> Result<bool, ProcessMessageError> {
1507		MessageQueuePallet::<T::Runtime>::enqueue_message(
1508			msg.try_into().expect("Message too long"),
1509			AggregateMessageOrigin::Ump(UmpQueueId::Para(para)),
1510		);
1511		MessageQueuePallet::<T::Runtime>::service_queues(Weight::MAX);
1512
1513		Ok(true)
1514	}
1515}
1516
1517impl<T> ServiceQueues for DefaultRelayMessageProcessor<T>
1518where
1519	T: RelayChain,
1520	T::Runtime: MessageQueueConfig,
1521	<<T::Runtime as MessageQueueConfig>::MessageProcessor as ProcessMessage>::Origin:
1522		PartialEq<AggregateMessageOrigin>,
1523	MessageQueuePallet<T::Runtime>: EnqueueMessage<AggregateMessageOrigin> + ServiceQueues,
1524{
1525	type OverweightMessageAddress = ();
1526
1527	fn service_queues(weight_limit: Weight) -> Weight {
1528		MessageQueuePallet::<T::Runtime>::service_queues(weight_limit)
1529	}
1530
1531	fn execute_overweight(
1532		_weight_limit: Weight,
1533		_address: Self::OverweightMessageAddress,
1534	) -> Result<Weight, ExecuteOverweightError> {
1535		unimplemented!()
1536	}
1537}
1538
1539/// Struct that keeps account's id and balance
1540#[derive(Clone)]
1541pub struct TestAccount<R: Chain> {
1542	pub account_id: AccountIdOf<R::Runtime>,
1543	pub balance: Balance,
1544}
1545
1546/// Default `Args` provided by xcm-emulator to be stored in a `Test` instance
1547#[derive(Clone)]
1548pub struct TestArgs {
1549	pub dest: Location,
1550	pub beneficiary: Location,
1551	pub amount: Balance,
1552	pub assets: Assets,
1553	pub asset_id: Option<u32>,
1554	pub fee_asset_item: u32,
1555	pub weight_limit: WeightLimit,
1556}
1557
1558impl TestArgs {
1559	/// Returns a [`TestArgs`] instance to be used for the Relay Chain across integration tests.
1560	pub fn new_relay(dest: Location, beneficiary_id: AccountId32, amount: Balance) -> Self {
1561		Self {
1562			dest,
1563			beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(),
1564			amount,
1565			assets: (Here, amount).into(),
1566			asset_id: None,
1567			fee_asset_item: 0,
1568			weight_limit: WeightLimit::Unlimited,
1569		}
1570	}
1571
1572	/// Returns a [`TestArgs`] instance to be used for parachains across integration tests.
1573	pub fn new_para(
1574		dest: Location,
1575		beneficiary_id: AccountId32,
1576		amount: Balance,
1577		assets: Assets,
1578		asset_id: Option<u32>,
1579		fee_asset_item: u32,
1580	) -> Self {
1581		Self {
1582			dest,
1583			beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(),
1584			amount,
1585			assets,
1586			asset_id,
1587			fee_asset_item,
1588			weight_limit: WeightLimit::Unlimited,
1589		}
1590	}
1591}
1592
1593/// Auxiliar struct to help creating a new `Test` instance
1594pub struct TestContext<T, Origin: Chain, Destination: Chain> {
1595	pub sender: AccountIdOf<Origin::Runtime>,
1596	pub receiver: AccountIdOf<Destination::Runtime>,
1597	pub args: T,
1598}
1599
1600/// Struct that helps with tests where either dispatchables or assertions need
1601/// to be reused. The struct keeps the test's arguments of your choice in the generic `Args`.
1602/// These arguments can be easily reused and shared between the assertion functions
1603/// and dispatchable functions, which are also stored in `Test`.
1604/// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution.
1605/// `Destination` corresponds to the last chain where an effect of the initial execution is expected
1606/// to happen. `Hops` refer to all the ordered intermediary chains an initial XCM execution can
1607/// provoke some effect on.
1608#[derive(Clone)]
1609pub struct Test<Origin, Destination, Hops = (), Args = TestArgs>
1610where
1611	Origin: Chain + Clone,
1612	Destination: Chain + Clone,
1613	Origin::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Origin::Runtime>> + Clone,
1614	Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
1615	Hops: Clone,
1616{
1617	pub sender: TestAccount<Origin>,
1618	pub receiver: TestAccount<Destination>,
1619	pub signed_origin: Origin::RuntimeOrigin,
1620	pub root_origin: Origin::RuntimeOrigin,
1621	pub hops_assertion: HashMap<String, fn(Self)>,
1622	pub hops_dispatchable: HashMap<String, fn(Self) -> DispatchResult>,
1623	pub hops_calls: HashMap<String, Origin::RuntimeCall>,
1624	pub args: Args,
1625	pub topic_id_tracker: Arc<Mutex<TopicIdTracker>>,
1626	_marker: PhantomData<(Destination, Hops)>,
1627}
1628
1629/// `Test` implementation.
1630impl<Origin, Destination, Hops, Args> Test<Origin, Destination, Hops, Args>
1631where
1632	Args: Clone,
1633	Origin: Chain + Clone,
1634	Destination: Chain + Clone,
1635	Origin::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Origin::Runtime>> + Clone,
1636	Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
1637	Hops: Clone,
1638{
1639	/// Asserts that a single unique topic ID exists across all chains.
1640	pub fn assert_unique_topic_id(&self) {
1641		self.topic_id_tracker.lock().unwrap().assert_unique();
1642	}
1643	/// Inserts a topic ID for a specific chain and asserts it remains globally unique.
1644	pub fn insert_unique_topic_id(&mut self, chain: &str, id: H256) {
1645		self.topic_id_tracker.lock().unwrap().insert_and_assert_unique(chain, id);
1646	}
1647}
1648impl<Origin, Destination, Hops, Args> Test<Origin, Destination, Hops, Args>
1649where
1650	Args: Clone,
1651	Origin: Chain + Clone + CheckAssertion<Origin, Destination, Hops, Args>,
1652	Destination: Chain + Clone + CheckAssertion<Origin, Destination, Hops, Args>,
1653	Origin::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Origin::Runtime>> + Clone,
1654	Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
1655	Hops: Clone + CheckAssertion<Origin, Destination, Hops, Args>,
1656{
1657	/// Creates a new `Test` instance.
1658	pub fn new(test_args: TestContext<Args, Origin, Destination>) -> Self {
1659		Test {
1660			sender: TestAccount {
1661				account_id: test_args.sender.clone(),
1662				balance: Origin::account_data_of(test_args.sender.clone()).free,
1663			},
1664			receiver: TestAccount {
1665				account_id: test_args.receiver.clone(),
1666				balance: Destination::account_data_of(test_args.receiver.clone()).free,
1667			},
1668			signed_origin: <Origin as Chain>::RuntimeOrigin::signed(test_args.sender),
1669			root_origin: <Origin as Chain>::RuntimeOrigin::root(),
1670			hops_assertion: Default::default(),
1671			hops_dispatchable: Default::default(),
1672			hops_calls: Default::default(),
1673			args: test_args.args,
1674			topic_id_tracker: Arc::new(Mutex::new(TopicIdTracker::new())),
1675			_marker: Default::default(),
1676		}
1677	}
1678	/// Stores an assertion in a particular Chain
1679	pub fn set_assertion<Hop>(&mut self, assertion: fn(Self)) {
1680		let chain_name = std::any::type_name::<Hop>();
1681		self.hops_assertion.insert(chain_name.to_string(), assertion);
1682	}
1683	/// Stores a dispatchable in a particular Chain
1684	pub fn set_dispatchable<Hop>(&mut self, dispatchable: fn(Self) -> DispatchResult) {
1685		let chain_name = std::any::type_name::<Hop>();
1686		self.hops_dispatchable.insert(chain_name.to_string(), dispatchable);
1687	}
1688	/// Stores a call in a particular Chain, this will later be dispatched.
1689	pub fn set_call(&mut self, call: Origin::RuntimeCall) {
1690		let chain_name = std::any::type_name::<Origin>();
1691		self.hops_calls.insert(chain_name.to_string(), call);
1692	}
1693	/// Executes all dispatchables and assertions in order from `Origin` to `Destination`
1694	pub fn assert(&mut self) {
1695		Origin::check_assertion(self.clone());
1696		Hops::check_assertion(self.clone());
1697		Destination::check_assertion(self.clone());
1698		Self::update_balances(self);
1699	}
1700	/// Updates sender and receiver balances
1701	fn update_balances(&mut self) {
1702		self.sender.balance = Origin::account_data_of(self.sender.account_id.clone()).free;
1703		self.receiver.balance = Destination::account_data_of(self.receiver.account_id.clone()).free;
1704	}
1705}
1706
1707pub mod helpers {
1708	use super::*;
1709
1710	pub fn within_threshold(threshold: u64, expected_value: u64, current_value: u64) -> bool {
1711		let margin = (current_value * threshold) / 100;
1712		let lower_limit = expected_value.checked_sub(margin).unwrap_or(u64::MIN);
1713		let upper_limit = expected_value.checked_add(margin).unwrap_or(u64::MAX);
1714
1715		current_value >= lower_limit && current_value <= upper_limit
1716	}
1717
1718	pub fn weight_within_threshold(
1719		(threshold_time, threshold_size): (u64, u64),
1720		expected_weight: Weight,
1721		weight: Weight,
1722	) -> bool {
1723		let ref_time_within =
1724			within_threshold(threshold_time, expected_weight.ref_time(), weight.ref_time());
1725		let proof_size_within =
1726			within_threshold(threshold_size, expected_weight.proof_size(), weight.proof_size());
1727
1728		ref_time_within && proof_size_within
1729	}
1730}