1extern 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
33pub 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
65pub 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
81pub 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 #[allow(clippy::type_complexity)]
96 pub static DOWNWARD_MESSAGES: RefCell<HashMap<String, VecDeque<(u32, Vec<(RelayBlockNumber, Vec<u8>)>)>>>
97 = RefCell::new(HashMap::new());
98 #[allow(clippy::type_complexity)]
100 pub static DMP_DONE: RefCell<HashMap<String, VecDeque<(u32, RelayBlockNumber, Vec<u8>)>>>
101 = RefCell::new(HashMap::new());
102 #[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 pub static UPWARD_MESSAGES: RefCell<HashMap<String, VecDeque<(u32, Vec<u8>)>>> = RefCell::new(HashMap::new());
108 pub static BRIDGED_MESSAGES: RefCell<HashMap<String, VecDeque<BridgeMessage>>> = RefCell::new(HashMap::new());
110 pub static PARA_IDS: RefCell<HashMap<String, Vec<u32>>> = RefCell::new(HashMap::new());
112 pub static INITIALIZED: RefCell<HashMap<String, bool>> = RefCell::new(HashMap::new());
114 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
146pub 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#[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 $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 ($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 $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 let local_ext = $local_ext.with(|v| {
502 v.take()
503 });
504
505 let global_ext_guard = $global_ext.lock().unwrap();
507
508 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 while !global_ext_unlocked {
520 let global_ext_result = $global_ext.try_lock();
522
523 if let Ok(global_ext_guard) = global_ext_result {
524 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 let mut global_ext_guard = $global_ext.lock().unwrap();
535
536 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 <$network>::init();
552
553 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 $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 for para_id in <$network>::para_ids() {
566 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 }
578
579 Self::events().iter().for_each(|event| {
581 $crate::log::info!(target: concat!("events::", stringify!($name)), "{:?}", event);
582 });
583
584 <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#[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 fn init() {
667 use $crate::{Chain, TestExt};
668
669 $crate::paste::paste! {
671 [<LOCAL_EXT_ $name:upper>].with(|v| *v.borrow_mut() = Self::build_new_ext($genesis));
672 }
673 Self::set_last_head();
675 Self::new_block();
677 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 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 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(¶_id)
701 .expect("network not initialized?")
702 .clone()
703 );
704
705 let digest = <Self as Parachain>::DigestProvider::convert(block_number);
707 <Self as Chain>::System::initialize(&block_number, &parent_head_data.hash(), &digest);
708
709 let _ = $runtime::AllPalletsWithoutSystem::on_initialize(block_number);
711
712 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 let timestamp_set: <Self as Chain>::RuntimeCall = $crate::TimestampCall::set {
732 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 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 $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 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 ) => { type DigestProvider = (); };
803 ( @inner_additional_inherent_code $additional_inherent_code:ty ) => { type AdditionalInherentCode = $additional_inherent_code; };
804 ( @inner_additional_inherent_code ) => { type AdditionalInherentCode = (); };
805}
806
807#[macro_export]
808macro_rules! __impl_test_ext_for_parachain {
809 ($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 $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 let local_ext = $local_ext.with(|v| {
850 v.take()
851 });
852
853 let global_ext_guard = $global_ext.lock().unwrap();
855
856 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 while !global_ext_unlocked {
868 let global_ext_result = $global_ext.try_lock();
870
871 if let Ok(global_ext_guard) = global_ext_result {
872 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 let mut global_ext_guard = $global_ext.lock().unwrap();
883
884 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 <$network>::init();
901
902 Self::new_block();
904
905 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 Self::finalize_block();
913
914 let para_id = Self::para_id().into();
915
916 $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 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 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 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 for msg in bridge_messages {
950 <$network>::send_bridged_messages(msg);
951 }
952
953 <Self as $crate::Chain>::events().iter().for_each(|event| {
955 $crate::log::info!(target: concat!("events::", stringify!($name)), "{:?}", event);
956 });
957
958 <Self as $crate::Chain>::System::reset_events();
960 })
961 });
962
963 <$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#[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 $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 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 <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 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 <$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 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 $(
1332 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 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 failure_message = None;
1373 events.remove(index);
1374 break;
1375 }
1376 },
1377 _ => {}
1378 }
1379 }
1380
1381 if !event_received || failure_message.is_some() {
1382 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 <$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)>);
1426impl<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>);
1481impl<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#[derive(Clone)]
1532pub struct TestAccount<R: Chain> {
1533 pub account_id: AccountIdOf<R::Runtime>,
1534 pub balance: Balance,
1535}
1536
1537#[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 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 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
1584pub 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#[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
1620impl<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 pub fn assert_unique_topic_id(&self) {
1632 self.topic_id_tracker.lock().unwrap().assert_unique();
1633 }
1634 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 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 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 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 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 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 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}