1use core::marker::PhantomData;
17
18use codec::{Decode, DecodeLimit};
19use pezcumulus_pezpallet_teyrchain_system::teyrchain_inherent::{
20 deconstruct_teyrchain_inherent_data, InboundMessagesData,
21};
22use pezcumulus_primitives_core::{
23 relay_chain::Slot, AbridgedHrmpChannel, ParaId, PersistedValidationData,
24};
25use pezcumulus_primitives_teyrchain_inherent::TeyrchainInherentData;
26use pezcumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
27use pezframe_support::{
28 dispatch::{DispatchResult, GetDispatchInfo, RawOrigin},
29 inherent::{InherentData, ProvideInherent},
30 pezpallet_prelude::Get,
31 traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable},
32 weights::Weight,
33};
34use pezframe_system::pezpallet_prelude::{BlockNumberFor, HeaderFor};
35use pezkuwi_teyrchain_primitives::primitives::{
36 HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat,
37};
38use pezsp_consensus_aura::{SlotDuration, AURA_ENGINE_ID};
39use pezsp_core::{Encode, U256};
40use pezsp_runtime::{
41 traits::{Dispatchable, Header},
42 BuildStorage, Digest, DigestItem, DispatchError, Either, SaturatedConversion,
43};
44use xcm::{
45 latest::{Asset, Location, XcmContext, XcmHash},
46 prelude::*,
47 VersionedXcm, MAX_XCM_DECODE_DEPTH,
48};
49use xcm_executor::{traits::TransactAsset, AssetsInHolding};
50
51pub mod test_cases;
52
53pub type BalanceOf<Runtime> = <Runtime as pezpallet_balances::Config>::Balance;
54pub type AccountIdOf<Runtime> = <Runtime as pezframe_system::Config>::AccountId;
55pub type RuntimeCallOf<Runtime> = <Runtime as pezframe_system::Config>::RuntimeCall;
56pub type RuntimeOriginOf<Runtime> = <Runtime as pezframe_system::Config>::RuntimeOrigin;
57pub type ValidatorIdOf<Runtime> = <Runtime as pezpallet_session::Config>::ValidatorId;
58pub type SessionKeysOf<Runtime> = <Runtime as pezpallet_session::Config>::Keys;
59
60pub struct CollatorSessionKey<
61 Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config,
62> {
63 collator: AccountIdOf<Runtime>,
64 validator: ValidatorIdOf<Runtime>,
65 key: SessionKeysOf<Runtime>,
66}
67
68pub struct CollatorSessionKeys<
69 Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config,
70> {
71 items: Vec<CollatorSessionKey<Runtime>>,
72}
73
74impl<Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config>
75 CollatorSessionKey<Runtime>
76{
77 pub fn new(
78 collator: AccountIdOf<Runtime>,
79 validator: ValidatorIdOf<Runtime>,
80 key: SessionKeysOf<Runtime>,
81 ) -> Self {
82 Self { collator, validator, key }
83 }
84}
85
86impl<Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config>
87 Default for CollatorSessionKeys<Runtime>
88{
89 fn default() -> Self {
90 Self { items: vec![] }
91 }
92}
93
94impl<Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config>
95 CollatorSessionKeys<Runtime>
96{
97 pub fn new(
98 collator: AccountIdOf<Runtime>,
99 validator: ValidatorIdOf<Runtime>,
100 key: SessionKeysOf<Runtime>,
101 ) -> Self {
102 Self { items: vec![CollatorSessionKey::new(collator, validator, key)] }
103 }
104
105 pub fn add(mut self, item: CollatorSessionKey<Runtime>) -> Self {
106 self.items.push(item);
107 self
108 }
109
110 pub fn collators(&self) -> Vec<AccountIdOf<Runtime>> {
111 self.items.iter().map(|item| item.collator.clone()).collect::<Vec<_>>()
112 }
113
114 pub fn session_keys(
115 &self,
116 ) -> Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)> {
117 self.items
118 .iter()
119 .map(|item| (item.collator.clone(), item.validator.clone(), item.key.clone()))
120 .collect::<Vec<_>>()
121 }
122}
123
124pub struct SlotDurations {
125 pub relay: SlotDuration,
126 pub para: SlotDuration,
127}
128
129pub trait BasicTeyrchainRuntime:
132 pezframe_system::Config
133 + pezpallet_balances::Config
134 + pezpallet_session::Config
135 + pezpallet_xcm::Config
136 + teyrchain_info::Config
137 + pezpallet_collator_selection::Config
138 + pezcumulus_pezpallet_teyrchain_system::Config
139 + pezpallet_timestamp::Config
140{
141}
142
143impl<T> BasicTeyrchainRuntime for T
144where
145 T: pezframe_system::Config
146 + pezpallet_balances::Config
147 + pezpallet_session::Config
148 + pezpallet_xcm::Config
149 + teyrchain_info::Config
150 + pezpallet_collator_selection::Config
151 + pezcumulus_pezpallet_teyrchain_system::Config
152 + pezpallet_timestamp::Config,
153 ValidatorIdOf<T>: From<AccountIdOf<T>>,
154{
155}
156
157pub struct ExtBuilder<Runtime: BasicTeyrchainRuntime> {
159 balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
161 collators: Vec<AccountIdOf<Runtime>>,
163 keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
165 safe_xcm_version: Option<XcmVersion>,
167 para_id: Option<ParaId>,
169 _runtime: PhantomData<Runtime>,
170}
171
172impl<Runtime: BasicTeyrchainRuntime> Default for ExtBuilder<Runtime> {
173 fn default() -> ExtBuilder<Runtime> {
174 ExtBuilder {
175 balances: vec![],
176 collators: vec![],
177 keys: vec![],
178 safe_xcm_version: None,
179 para_id: None,
180 _runtime: PhantomData,
181 }
182 }
183}
184
185impl<Runtime: BasicTeyrchainRuntime> ExtBuilder<Runtime> {
186 pub fn with_balances(
187 mut self,
188 balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
189 ) -> Self {
190 self.balances = balances;
191 self
192 }
193 pub fn with_collators(mut self, collators: Vec<AccountIdOf<Runtime>>) -> Self {
194 self.collators = collators;
195 self
196 }
197
198 pub fn with_session_keys(
199 mut self,
200 keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
201 ) -> Self {
202 self.keys = keys;
203 self
204 }
205
206 pub fn with_tracing(self) -> Self {
207 pezsp_tracing::try_init_simple();
208 self
209 }
210
211 pub fn with_safe_xcm_version(mut self, safe_xcm_version: XcmVersion) -> Self {
212 self.safe_xcm_version = Some(safe_xcm_version);
213 self
214 }
215
216 pub fn with_para_id(mut self, para_id: ParaId) -> Self {
217 self.para_id = Some(para_id);
218 self
219 }
220
221 pub fn build(self) -> pezsp_io::TestExternalities {
222 let mut t = pezframe_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
223
224 pezpallet_xcm::GenesisConfig::<Runtime> {
225 safe_xcm_version: self.safe_xcm_version,
226 ..Default::default()
227 }
228 .assimilate_storage(&mut t)
229 .unwrap();
230
231 if let Some(para_id) = self.para_id {
232 teyrchain_info::GenesisConfig::<Runtime> {
233 teyrchain_id: para_id,
234 ..Default::default()
235 }
236 .assimilate_storage(&mut t)
237 .unwrap();
238 }
239
240 pezpallet_balances::GenesisConfig::<Runtime> {
241 balances: self.balances,
242 ..Default::default()
243 }
244 .assimilate_storage(&mut t)
245 .unwrap();
246
247 pezpallet_collator_selection::GenesisConfig::<Runtime> {
248 invulnerables: self.collators.clone(),
249 candidacy_bond: Default::default(),
250 desired_candidates: Default::default(),
251 }
252 .assimilate_storage(&mut t)
253 .unwrap();
254
255 pezpallet_session::GenesisConfig::<Runtime> { keys: self.keys, ..Default::default() }
256 .assimilate_storage(&mut t)
257 .unwrap();
258
259 let mut ext = pezsp_io::TestExternalities::new(t);
260
261 ext.execute_with(|| {
262 pezframe_system::Pezpallet::<Runtime>::set_block_number(1u32.into());
263 });
264
265 ext
266 }
267}
268
269pub struct RuntimeHelper<Runtime, AllPalletsWithoutSystem>(
270 PhantomData<(Runtime, AllPalletsWithoutSystem)>,
271);
272impl<
275 Runtime: pezframe_system::Config
276 + pezcumulus_pezpallet_teyrchain_system::Config
277 + pezpallet_timestamp::Config,
278 AllPalletsWithoutSystem,
279 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
280where
281 AccountIdOf<Runtime>:
282 Into<<<Runtime as pezframe_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
283 AllPalletsWithoutSystem:
284 OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
285{
286 pub fn run_to_block(n: u32, author: AccountIdOf<Runtime>) -> HeaderFor<Runtime> {
287 let mut last_header = None;
288 loop {
289 let block_number = pezframe_system::Pezpallet::<Runtime>::block_number();
290 if block_number >= n.into() {
291 break;
292 }
293 let header = pezframe_system::Pezpallet::<Runtime>::finalize();
298
299 let pre_digest =
300 Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, author.encode())] };
301 pezframe_system::Pezpallet::<Runtime>::reset_events();
302
303 let next_block_number = block_number + 1u32.into();
304 pezframe_system::Pezpallet::<Runtime>::initialize(
305 &next_block_number,
306 &header.hash(),
307 &pre_digest,
308 );
309 AllPalletsWithoutSystem::on_initialize(next_block_number);
310 last_header = Some(header);
311 }
312 last_header.expect("run_to_block empty block range")
313 }
314
315 pub fn run_to_block_with_finalize(n: u32) -> HeaderFor<Runtime> {
316 let mut last_header = None;
317 loop {
318 let block_number = pezframe_system::Pezpallet::<Runtime>::block_number();
319 if block_number >= n.into() {
320 break;
321 }
322 let header = pezframe_system::Pezpallet::<Runtime>::finalize();
324
325 let pre_digest = Digest {
326 logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, block_number.encode())],
327 };
328 pezframe_system::Pezpallet::<Runtime>::reset_events();
329
330 let next_block_number = block_number + 1u32.into();
331 pezframe_system::Pezpallet::<Runtime>::initialize(
332 &next_block_number,
333 &header.hash(),
334 &pre_digest,
335 );
336 AllPalletsWithoutSystem::on_initialize(next_block_number);
337
338 let parent_head = HeadData(header.encode());
339 let sproof_builder = RelayStateSproofBuilder {
340 para_id: <Runtime>::SelfParaId::get(),
341 included_para_head: parent_head.clone().into(),
342 ..Default::default()
343 };
344
345 let (relay_parent_storage_root, relay_chain_state) =
346 sproof_builder.into_state_root_and_proof();
347 let inherent_data = TeyrchainInherentData {
348 validation_data: PersistedValidationData {
349 parent_head,
350 relay_parent_number: (block_number.saturated_into::<u32>() * 2 + 1).into(),
351 relay_parent_storage_root,
352 max_pov_size: 100_000_000,
353 },
354 relay_chain_state,
355 downward_messages: Default::default(),
356 horizontal_messages: Default::default(),
357 relay_parent_descendants: Default::default(),
358 collator_peer_id: None,
359 };
360
361 let (inherent_data, downward_messages, horizontal_messages) =
362 deconstruct_teyrchain_inherent_data(inherent_data);
363
364 let _ =
365 pezcumulus_pezpallet_teyrchain_system::Pezpallet::<Runtime>::set_validation_data(
366 Runtime::RuntimeOrigin::none(),
367 inherent_data,
368 InboundMessagesData::new(
369 downward_messages.into_abridged(&mut usize::MAX.clone()),
370 horizontal_messages.into_abridged(&mut usize::MAX.clone()),
371 ),
372 );
373 let _ = pezpallet_timestamp::Pezpallet::<Runtime>::set(
374 Runtime::RuntimeOrigin::none(),
375 300_u32.into(),
376 );
377 AllPalletsWithoutSystem::on_finalize(next_block_number);
378 let header = pezframe_system::Pezpallet::<Runtime>::finalize();
379 last_header = Some(header);
380 }
381 last_header.expect("run_to_block empty block range")
382 }
383
384 pub fn root_origin() -> <Runtime as pezframe_system::Config>::RuntimeOrigin {
385 <Runtime as pezframe_system::Config>::RuntimeOrigin::root()
386 }
387
388 pub fn block_number() -> U256 {
389 pezframe_system::Pezpallet::<Runtime>::block_number().into()
390 }
391
392 pub fn origin_of(
393 account_id: AccountIdOf<Runtime>,
394 ) -> <Runtime as pezframe_system::Config>::RuntimeOrigin {
395 <Runtime as pezframe_system::Config>::RuntimeOrigin::signed(account_id.into())
396 }
397}
398
399impl<XcmConfig: xcm_executor::Config, AllPalletsWithoutSystem>
400 RuntimeHelper<XcmConfig, AllPalletsWithoutSystem>
401{
402 pub fn do_transfer(
403 from: Location,
404 to: Location,
405 (asset, amount): (Location, u128),
406 ) -> Result<AssetsInHolding, XcmError> {
407 <XcmConfig::AssetTransactor as TransactAsset>::transfer_asset(
408 &Asset { id: AssetId(asset), fun: Fungible(amount) },
409 &from,
410 &to,
411 &XcmContext::with_message_id([0; 32]),
414 )
415 }
416}
417
418impl<
419 Runtime: pezpallet_xcm::Config + pezcumulus_pezpallet_teyrchain_system::Config,
420 AllPalletsWithoutSystem,
421 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
422{
423 pub fn do_teleport_assets<HrmpChannelOpener>(
424 origin: <Runtime as pezframe_system::Config>::RuntimeOrigin,
425 dest: Location,
426 beneficiary: Location,
427 (asset, amount): (Location, u128),
428 open_hrmp_channel: Option<(u32, u32)>,
429 included_head: HeaderFor<Runtime>,
430 slot_digest: &[u8],
431 slot_durations: &SlotDurations,
432 ) -> DispatchResult
433 where
434 HrmpChannelOpener: pezframe_support::inherent::ProvideInherent<
435 Call = pezcumulus_pezpallet_teyrchain_system::Call<Runtime>,
436 >,
437 {
438 if let Some((source_para_id, target_para_id)) = open_hrmp_channel {
440 mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
441 source_para_id.into(),
442 target_para_id.into(),
443 included_head,
444 slot_digest,
445 slot_durations,
446 );
447 }
448
449 <pezpallet_xcm::Pezpallet<Runtime>>::limited_teleport_assets(
451 origin,
452 Box::new(dest.into()),
453 Box::new(beneficiary.into()),
454 Box::new((AssetId(asset.clone()), amount).into()),
455 Box::new(AssetId(asset).into()),
456 Unlimited,
457 )
458 }
459}
460
461impl<
462 Runtime: pezcumulus_pezpallet_teyrchain_system::Config + pezpallet_xcm::Config,
463 AllPalletsWithoutSystem,
464 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
465{
466 #[deprecated(
467 note = "Will be removed after Aug 2025; It uses hard-coded `Location::parent()`, \
468 use `execute_as_governance_call` instead."
469 )]
470 pub fn execute_as_governance(call: Vec<u8>) -> Outcome {
471 let xcm = Xcm(vec![
473 UnpaidExecution { weight_limit: Unlimited, check_origin: None },
474 Transact {
475 origin_kind: OriginKind::Superuser,
476 call: call.into(),
477 fallback_max_weight: None,
478 },
479 ExpectTransactStatus(MaybeErrorCode::Success),
480 ]);
481
482 let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
484 <<Runtime as pezpallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
485 Location::parent(),
486 xcm,
487 &mut hash,
488 Self::xcm_max_weight(XcmReceivedFrom::Parent),
489 Weight::zero(),
490 )
491 }
492
493 pub fn execute_as_governance_call<Call: Dispatchable + Encode>(
494 call: Call,
495 governance_origin: GovernanceOrigin<Call::RuntimeOrigin>,
496 ) -> Result<(), Either<DispatchError, InstructionError>> {
497 let execute_xcm = |call: Call, governance_location, descend_origin| {
499 let xcm = if let Some(descend_origin) = descend_origin {
501 Xcm::builder_unsafe().descend_origin(descend_origin)
502 } else {
503 Xcm::builder_unsafe()
504 }
505 .unpaid_execution(Unlimited, None)
506 .transact(OriginKind::Superuser, None, call.encode())
507 .expect_transact_status(MaybeErrorCode::Success)
508 .build();
509
510 let xcm_max_weight = Self::xcm_max_weight_for_location(&governance_location);
511 let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
512
513 <<Runtime as pezpallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
514 governance_location,
515 xcm,
516 &mut hash,
517 xcm_max_weight,
518 Weight::zero(),
519 )
520 };
521
522 match governance_origin {
523 GovernanceOrigin::Location(location) if location == Location::here() => {
526 panic!("Location::here() not supported, use GovernanceOrigin::Origin instead")
527 },
528 GovernanceOrigin::Location(location) => {
529 execute_xcm(call, location, None).ensure_complete().map_err(Either::Right)
530 },
531 GovernanceOrigin::LocationAndDescendOrigin(location, descend_origin) => {
532 execute_xcm(call, location, Some(descend_origin))
533 .ensure_complete()
534 .map_err(Either::Right)
535 },
536 GovernanceOrigin::Origin(origin) => {
537 call.dispatch(origin).map(|_| ()).map_err(|e| Either::Left(e.error))
538 },
539 }
540 }
541
542 pub fn execute_as_origin<Call: GetDispatchInfo + Encode>(
543 (origin, origin_kind): (Location, OriginKind),
544 call: Call,
545 maybe_buy_execution_fee: Option<Asset>,
546 ) -> Outcome {
547 let mut instructions = if let Some(buy_execution_fee) = maybe_buy_execution_fee {
548 vec![
549 WithdrawAsset(buy_execution_fee.clone().into()),
550 BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
551 ]
552 } else {
553 vec![UnpaidExecution { check_origin: None, weight_limit: Unlimited }]
554 };
555
556 instructions.extend(vec![
558 Transact { origin_kind, call: call.encode().into(), fallback_max_weight: None },
559 ExpectTransactStatus(MaybeErrorCode::Success),
560 ]);
561 let xcm = Xcm(instructions);
562 let xcm_max_weight = Self::xcm_max_weight_for_location(&origin);
563
564 let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
566 <<Runtime as pezpallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
567 origin,
568 xcm,
569 &mut hash,
570 xcm_max_weight,
571 Weight::zero(),
572 )
573 }
574}
575
576#[derive(Clone)]
578pub enum GovernanceOrigin<RuntimeOrigin> {
579 Location(Location),
580 LocationAndDescendOrigin(Location, InteriorLocation),
581 Origin(RuntimeOrigin),
582}
583
584pub enum XcmReceivedFrom {
585 Parent,
586 Sibling,
587}
588
589impl<TeyrchainSystem: pezcumulus_pezpallet_teyrchain_system::Config, AllPalletsWithoutSystem>
590 RuntimeHelper<TeyrchainSystem, AllPalletsWithoutSystem>
591{
592 pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
593 match from {
594 XcmReceivedFrom::Parent => TeyrchainSystem::ReservedDmpWeight::get(),
595 XcmReceivedFrom::Sibling => TeyrchainSystem::ReservedXcmpWeight::get(),
596 }
597 }
598
599 pub fn xcm_max_weight_for_location(location: &Location) -> Weight {
600 Self::xcm_max_weight(if location == &Location::parent() {
601 XcmReceivedFrom::Parent
602 } else {
603 XcmReceivedFrom::Sibling
604 })
605 }
606}
607
608impl<Runtime: pezframe_system::Config + pezpallet_xcm::Config, AllPalletsWithoutSystem>
609 RuntimeHelper<Runtime, AllPalletsWithoutSystem>
610{
611 pub fn assert_pallet_xcm_event_outcome(
612 unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pezpallet_xcm::Event<Runtime>>>,
613 assert_outcome: fn(Outcome),
614 ) {
615 assert_outcome(Self::get_pallet_xcm_event_outcome(unwrap_pallet_xcm_event));
616 }
617
618 pub fn get_pallet_xcm_event_outcome(
619 unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pezpallet_xcm::Event<Runtime>>>,
620 ) -> Outcome {
621 <pezframe_system::Pezpallet<Runtime>>::events()
622 .into_iter()
623 .filter_map(|e| unwrap_pallet_xcm_event(e.event.encode()))
624 .find_map(|e| match e {
625 pezpallet_xcm::Event::Attempted { outcome } => Some(outcome),
626 _ => None,
627 })
628 .expect("No `pezpallet_xcm::Event::Attempted(outcome)` event found!")
629 }
630}
631
632impl<
633 Runtime: pezframe_system::Config + pezcumulus_pezpallet_xcmp_queue::Config,
634 AllPalletsWithoutSystem,
635 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
636{
637 pub fn xcmp_queue_message_sent(
638 unwrap_xcmp_queue_event: Box<
639 dyn Fn(Vec<u8>) -> Option<pezcumulus_pezpallet_xcmp_queue::Event<Runtime>>,
640 >,
641 ) -> Option<XcmHash> {
642 <pezframe_system::Pezpallet<Runtime>>::events()
643 .into_iter()
644 .filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
645 .find_map(|e| match e {
646 pezcumulus_pezpallet_xcmp_queue::Event::XcmpMessageSent { message_hash } => {
647 Some(message_hash)
648 },
649 _ => None,
650 })
651 }
652}
653
654pub fn assert_metadata<Fungibles, AccountId>(
655 asset_id: impl Into<Fungibles::AssetId> + Clone,
656 expected_name: &str,
657 expected_symbol: &str,
658 expected_decimals: u8,
659) where
660 Fungibles: pezframe_support::traits::fungibles::metadata::Inspect<AccountId>
661 + pezframe_support::traits::fungibles::Inspect<AccountId>,
662{
663 assert_eq!(Fungibles::name(asset_id.clone().into()), Vec::from(expected_name),);
664 assert_eq!(Fungibles::symbol(asset_id.clone().into()), Vec::from(expected_symbol),);
665 assert_eq!(Fungibles::decimals(asset_id.into()), expected_decimals);
666}
667
668pub fn assert_total<Fungibles, AccountId>(
669 asset_id: impl Into<Fungibles::AssetId> + Clone,
670 expected_total_issuance: impl Into<Fungibles::Balance>,
671 expected_active_issuance: impl Into<Fungibles::Balance>,
672) where
673 Fungibles: pezframe_support::traits::fungibles::metadata::Inspect<AccountId>
674 + pezframe_support::traits::fungibles::Inspect<AccountId>,
675{
676 assert_eq!(Fungibles::total_issuance(asset_id.clone().into()), expected_total_issuance.into());
677 assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
678}
679
680pub fn mock_open_hrmp_channel<
689 C: pezcumulus_pezpallet_teyrchain_system::Config,
690 T: ProvideInherent<Call = pezcumulus_pezpallet_teyrchain_system::Call<C>>,
691>(
692 sender: ParaId,
693 recipient: ParaId,
694 included_head: HeaderFor<C>,
695 mut slot_digest: &[u8],
696 slot_durations: &SlotDurations,
697) {
698 let slot = Slot::decode(&mut slot_digest).expect("failed to decode digest");
699 let timestamp = slot.saturating_mul(slot_durations.para.as_millis());
701 let relay_slot = Slot::from_timestamp(timestamp.into(), slot_durations.relay);
702
703 let n = 1_u32;
704 let mut sproof_builder = RelayStateSproofBuilder {
705 para_id: sender,
706 included_para_head: Some(HeadData(included_head.encode())),
707 hrmp_egress_channel_index: Some(vec![recipient]),
708 current_slot: relay_slot,
709 ..Default::default()
710 };
711 sproof_builder.hrmp_channels.insert(
712 HrmpChannelId { sender, recipient },
713 AbridgedHrmpChannel {
714 max_capacity: 10,
715 max_total_size: 10_000_000_u32,
716 max_message_size: 10_000_000_u32,
717 msg_count: 0,
718 total_size: 0_u32,
719 mqc_head: None,
720 },
721 );
722
723 let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
724 let vfp = PersistedValidationData {
725 relay_parent_number: n as RelayChainBlockNumber,
726 relay_parent_storage_root,
727 ..Default::default()
728 };
729 let inherent_data = {
732 let mut inherent_data = InherentData::default();
733 let system_inherent_data = TeyrchainInherentData {
734 validation_data: vfp,
735 relay_chain_state,
736 downward_messages: Default::default(),
737 horizontal_messages: Default::default(),
738 relay_parent_descendants: Default::default(),
739 collator_peer_id: None,
740 };
741 inherent_data
742 .put_data(
743 pezcumulus_primitives_teyrchain_inherent::INHERENT_IDENTIFIER,
744 &system_inherent_data,
745 )
746 .expect("failed to put VFP inherent");
747 inherent_data
748 };
749
750 T::create_inherent(&inherent_data)
752 .expect("got an inherent")
753 .dispatch_bypass_filter(RawOrigin::None.into())
754 .expect("dispatch succeeded");
755}
756
757impl<HrmpChannelSource: pezcumulus_primitives_core::XcmpMessageSource, AllPalletsWithoutSystem>
758 RuntimeHelper<HrmpChannelSource, AllPalletsWithoutSystem>
759{
760 pub fn take_xcm(sent_to_para_id: ParaId) -> Option<VersionedXcm<()>> {
761 match HrmpChannelSource::take_outbound_messages(10)[..] {
762 [(para_id, ref mut xcm_message_data)] if para_id.eq(&sent_to_para_id.into()) => {
763 let mut xcm_message_data = &xcm_message_data[..];
764 let _ = XcmpMessageFormat::decode(&mut xcm_message_data).expect("valid format");
766 VersionedXcm::<()>::decode_with_depth_limit(
767 MAX_XCM_DECODE_DEPTH,
768 &mut xcm_message_data,
769 )
770 .map(|x| Some(x))
771 .expect("result with xcm")
772 },
773 _ => return None,
774 }
775 }
776}