Skip to main content

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