referrerpolicy=no-referrer-when-downgrade

xcm_emulator/
lib.rs

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