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