1use core::marker::PhantomData;
17
18use codec::{Decode, DecodeLimit};
19use cumulus_pallet_parachain_system::parachain_inherent::{
20 deconstruct_parachain_inherent_data, InboundMessagesData,
21};
22use cumulus_primitives_core::{
23 relay_chain::Slot, AbridgedHrmpChannel, ParaId, PersistedValidationData,
24};
25use cumulus_primitives_parachain_inherent::ParachainInherentData;
26use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
27use frame_support::{
28 dispatch::{DispatchResult, GetDispatchInfo, RawOrigin},
29 inherent::{InherentData, ProvideInherent},
30 pallet_prelude::Get,
31 traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable},
32 weights::Weight,
33};
34use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor};
35use polkadot_parachain_primitives::primitives::{
36 HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat,
37};
38use sp_consensus_aura::{SlotDuration, AURA_ENGINE_ID};
39use sp_core::{Encode, U256};
40use sp_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 pallet_balances::Config>::Balance;
54pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
55pub type RuntimeCallOf<Runtime> = <Runtime as frame_system::Config>::RuntimeCall;
56pub type RuntimeOriginOf<Runtime> = <Runtime as frame_system::Config>::RuntimeOrigin;
57pub type ValidatorIdOf<Runtime> = <Runtime as pallet_session::Config>::ValidatorId;
58pub type SessionKeysOf<Runtime> = <Runtime as pallet_session::Config>::Keys;
59
60pub struct CollatorSessionKey<
61 Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config,
62> {
63 collator: AccountIdOf<Runtime>,
64 validator: ValidatorIdOf<Runtime>,
65 key: SessionKeysOf<Runtime>,
66}
67
68pub struct CollatorSessionKeys<
69 Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config,
70> {
71 items: Vec<CollatorSessionKey<Runtime>>,
72}
73
74impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_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: frame_system::Config + pallet_balances::Config + pallet_session::Config> Default
87 for CollatorSessionKeys<Runtime>
88{
89 fn default() -> Self {
90 Self { items: vec![] }
91 }
92}
93
94impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_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 BasicParachainRuntime:
132 frame_system::Config
133 + pallet_balances::Config
134 + pallet_session::Config
135 + pallet_xcm::Config
136 + parachain_info::Config
137 + pallet_collator_selection::Config
138 + cumulus_pallet_parachain_system::Config
139 + pallet_timestamp::Config
140{
141}
142
143impl<T> BasicParachainRuntime for T
144where
145 T: frame_system::Config
146 + pallet_balances::Config
147 + pallet_session::Config
148 + pallet_xcm::Config
149 + parachain_info::Config
150 + pallet_collator_selection::Config
151 + cumulus_pallet_parachain_system::Config
152 + pallet_timestamp::Config,
153 ValidatorIdOf<T>: From<AccountIdOf<T>>,
154{
155}
156
157pub struct ExtBuilder<Runtime: BasicParachainRuntime> {
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: BasicParachainRuntime> 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: BasicParachainRuntime> 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 sp_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) -> sp_io::TestExternalities {
222 let mut t = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
223
224 pallet_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 parachain_info::GenesisConfig::<Runtime> {
233 parachain_id: para_id,
234 ..Default::default()
235 }
236 .assimilate_storage(&mut t)
237 .unwrap();
238 }
239
240 pallet_balances::GenesisConfig::<Runtime> { balances: self.balances, ..Default::default() }
241 .assimilate_storage(&mut t)
242 .unwrap();
243
244 pallet_collator_selection::GenesisConfig::<Runtime> {
245 invulnerables: self.collators.clone(),
246 candidacy_bond: Default::default(),
247 desired_candidates: Default::default(),
248 }
249 .assimilate_storage(&mut t)
250 .unwrap();
251
252 pallet_session::GenesisConfig::<Runtime> { keys: self.keys, ..Default::default() }
253 .assimilate_storage(&mut t)
254 .unwrap();
255
256 let mut ext = sp_io::TestExternalities::new(t);
257
258 ext.execute_with(|| {
259 frame_system::Pallet::<Runtime>::set_block_number(1u32.into());
260 });
261
262 ext
263 }
264}
265
266pub struct RuntimeHelper<Runtime, AllPalletsWithoutSystem>(
267 PhantomData<(Runtime, AllPalletsWithoutSystem)>,
268);
269impl<
272 Runtime: frame_system::Config + cumulus_pallet_parachain_system::Config + pallet_timestamp::Config,
273 AllPalletsWithoutSystem,
274 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
275where
276 AccountIdOf<Runtime>:
277 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
278 AllPalletsWithoutSystem:
279 OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
280{
281 pub fn run_to_block(n: u32, author: AccountIdOf<Runtime>) -> HeaderFor<Runtime> {
282 let mut last_header = None;
283 loop {
284 let block_number = frame_system::Pallet::<Runtime>::block_number();
285 if block_number >= n.into() {
286 break
287 }
288 let header = frame_system::Pallet::<Runtime>::finalize();
293
294 let pre_digest =
295 Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, author.encode())] };
296 frame_system::Pallet::<Runtime>::reset_events();
297
298 let next_block_number = block_number + 1u32.into();
299 frame_system::Pallet::<Runtime>::initialize(
300 &next_block_number,
301 &header.hash(),
302 &pre_digest,
303 );
304 AllPalletsWithoutSystem::on_initialize(next_block_number);
305 last_header = Some(header);
306 }
307 last_header.expect("run_to_block empty block range")
308 }
309
310 pub fn run_to_block_with_finalize(n: u32) -> HeaderFor<Runtime> {
311 let mut last_header = None;
312 loop {
313 let block_number = frame_system::Pallet::<Runtime>::block_number();
314 if block_number >= n.into() {
315 break
316 }
317 let header = frame_system::Pallet::<Runtime>::finalize();
319
320 let pre_digest = Digest {
321 logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, block_number.encode())],
322 };
323 frame_system::Pallet::<Runtime>::reset_events();
324
325 let next_block_number = block_number + 1u32.into();
326 frame_system::Pallet::<Runtime>::initialize(
327 &next_block_number,
328 &header.hash(),
329 &pre_digest,
330 );
331 AllPalletsWithoutSystem::on_initialize(next_block_number);
332
333 let parent_head = HeadData(header.encode());
334 let sproof_builder = RelayStateSproofBuilder {
335 para_id: <Runtime>::SelfParaId::get(),
336 included_para_head: parent_head.clone().into(),
337 ..Default::default()
338 };
339
340 let (relay_parent_storage_root, relay_chain_state) =
341 sproof_builder.into_state_root_and_proof();
342 let inherent_data = ParachainInherentData {
343 validation_data: PersistedValidationData {
344 parent_head,
345 relay_parent_number: (block_number.saturated_into::<u32>() * 2 + 1).into(),
346 relay_parent_storage_root,
347 max_pov_size: 100_000_000,
348 },
349 relay_chain_state,
350 downward_messages: Default::default(),
351 horizontal_messages: Default::default(),
352 relay_parent_descendants: Default::default(),
353 collator_peer_id: None,
354 };
355
356 let (inherent_data, downward_messages, horizontal_messages) =
357 deconstruct_parachain_inherent_data(inherent_data);
358
359 let _ = cumulus_pallet_parachain_system::Pallet::<Runtime>::set_validation_data(
360 Runtime::RuntimeOrigin::none(),
361 inherent_data,
362 InboundMessagesData::new(
363 downward_messages.into_abridged(&mut usize::MAX.clone()),
364 horizontal_messages.into_abridged(&mut usize::MAX.clone()),
365 ),
366 );
367 let _ = pallet_timestamp::Pallet::<Runtime>::set(
368 Runtime::RuntimeOrigin::none(),
369 300_u32.into(),
370 );
371 AllPalletsWithoutSystem::on_finalize(next_block_number);
372 let header = frame_system::Pallet::<Runtime>::finalize();
373 last_header = Some(header);
374 }
375 last_header.expect("run_to_block empty block range")
376 }
377
378 pub fn root_origin() -> <Runtime as frame_system::Config>::RuntimeOrigin {
379 <Runtime as frame_system::Config>::RuntimeOrigin::root()
380 }
381
382 pub fn block_number() -> U256 {
383 frame_system::Pallet::<Runtime>::block_number().into()
384 }
385
386 pub fn origin_of(
387 account_id: AccountIdOf<Runtime>,
388 ) -> <Runtime as frame_system::Config>::RuntimeOrigin {
389 <Runtime as frame_system::Config>::RuntimeOrigin::signed(account_id.into())
390 }
391}
392
393impl<XcmConfig: xcm_executor::Config, AllPalletsWithoutSystem>
394 RuntimeHelper<XcmConfig, AllPalletsWithoutSystem>
395{
396 pub fn do_transfer(
397 from: Location,
398 to: Location,
399 (asset, amount): (Location, u128),
400 ) -> Result<AssetsInHolding, XcmError> {
401 <XcmConfig::AssetTransactor as TransactAsset>::transfer_asset(
402 &Asset { id: AssetId(asset), fun: Fungible(amount) },
403 &from,
404 &to,
405 &XcmContext::with_message_id([0; 32]),
408 )
409 }
410}
411
412impl<
413 Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config,
414 AllPalletsWithoutSystem,
415 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
416{
417 pub fn do_teleport_assets<HrmpChannelOpener>(
418 origin: <Runtime as frame_system::Config>::RuntimeOrigin,
419 dest: Location,
420 beneficiary: Location,
421 (asset, amount): (Location, u128),
422 open_hrmp_channel: Option<(u32, u32)>,
423 included_head: HeaderFor<Runtime>,
424 slot_digest: &[u8],
425 slot_durations: &SlotDurations,
426 ) -> DispatchResult
427 where
428 HrmpChannelOpener: frame_support::inherent::ProvideInherent<
429 Call = cumulus_pallet_parachain_system::Call<Runtime>,
430 >,
431 {
432 if let Some((source_para_id, target_para_id)) = open_hrmp_channel {
434 mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
435 source_para_id.into(),
436 target_para_id.into(),
437 included_head,
438 slot_digest,
439 slot_durations,
440 );
441 }
442
443 <pallet_xcm::Pallet<Runtime>>::limited_teleport_assets(
445 origin,
446 Box::new(dest.into()),
447 Box::new(beneficiary.into()),
448 Box::new((AssetId(asset), amount).into()),
449 0,
450 Unlimited,
451 )
452 }
453}
454
455impl<
456 Runtime: cumulus_pallet_parachain_system::Config + pallet_xcm::Config,
457 AllPalletsWithoutSystem,
458 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
459{
460 #[deprecated(
461 note = "Will be removed after Aug 2025; It uses hard-coded `Location::parent()`, \
462 use `execute_as_governance_call` instead."
463 )]
464 pub fn execute_as_governance(call: Vec<u8>) -> Outcome {
465 let xcm = Xcm(vec![
467 UnpaidExecution { weight_limit: Unlimited, check_origin: None },
468 Transact {
469 origin_kind: OriginKind::Superuser,
470 call: call.into(),
471 fallback_max_weight: None,
472 },
473 ExpectTransactStatus(MaybeErrorCode::Success),
474 ]);
475
476 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
478 <<Runtime as pallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
479 Location::parent(),
480 xcm,
481 &mut hash,
482 Self::xcm_max_weight(XcmReceivedFrom::Parent),
483 Weight::zero(),
484 )
485 }
486
487 pub fn execute_as_governance_call<Call: Dispatchable + Encode>(
488 call: Call,
489 governance_origin: GovernanceOrigin<Call::RuntimeOrigin>,
490 ) -> Result<(), Either<DispatchError, InstructionError>> {
491 let execute_xcm = |call: Call, governance_location, descend_origin| {
493 let xcm = if let Some(descend_origin) = descend_origin {
495 Xcm::builder_unsafe().descend_origin(descend_origin)
496 } else {
497 Xcm::builder_unsafe()
498 }
499 .unpaid_execution(Unlimited, None)
500 .transact(OriginKind::Superuser, None, call.encode())
501 .expect_transact_status(MaybeErrorCode::Success)
502 .build();
503
504 let xcm_max_weight = Self::xcm_max_weight_for_location(&governance_location);
505 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
506
507 <<Runtime as pallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
508 governance_location,
509 xcm,
510 &mut hash,
511 xcm_max_weight,
512 Weight::zero(),
513 )
514 };
515
516 match governance_origin {
517 GovernanceOrigin::Location(location) if location == Location::here() =>
520 panic!("Location::here() not supported, use GovernanceOrigin::Origin instead"),
521 GovernanceOrigin::Location(location) =>
522 execute_xcm(call, location, None).ensure_complete().map_err(Either::Right),
523 GovernanceOrigin::LocationAndDescendOrigin(location, descend_origin) =>
524 execute_xcm(call, location, Some(descend_origin))
525 .ensure_complete()
526 .map_err(Either::Right),
527 GovernanceOrigin::Origin(origin) =>
528 call.dispatch(origin).map(|_| ()).map_err(|e| Either::Left(e.error)),
529 }
530 }
531
532 pub fn execute_as_origin<Call: GetDispatchInfo + Encode>(
533 (origin, origin_kind): (Location, OriginKind),
534 call: Call,
535 maybe_buy_execution_fee: Option<Asset>,
536 ) -> Outcome {
537 let mut instructions = if let Some(buy_execution_fee) = maybe_buy_execution_fee {
538 vec![
539 WithdrawAsset(buy_execution_fee.clone().into()),
540 BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
541 ]
542 } else {
543 vec![UnpaidExecution { check_origin: None, weight_limit: Unlimited }]
544 };
545
546 instructions.extend(vec![
548 Transact { origin_kind, call: call.encode().into(), fallback_max_weight: None },
549 ExpectTransactStatus(MaybeErrorCode::Success),
550 ]);
551 let xcm = Xcm(instructions);
552 let xcm_max_weight = Self::xcm_max_weight_for_location(&origin);
553
554 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
556 <<Runtime as pallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
557 origin,
558 xcm,
559 &mut hash,
560 xcm_max_weight,
561 Weight::zero(),
562 )
563 }
564}
565
566#[derive(Clone)]
568pub enum GovernanceOrigin<RuntimeOrigin> {
569 Location(Location),
570 LocationAndDescendOrigin(Location, InteriorLocation),
571 Origin(RuntimeOrigin),
572}
573
574pub enum XcmReceivedFrom {
575 Parent,
576 Sibling,
577}
578
579impl<ParachainSystem: cumulus_pallet_parachain_system::Config, AllPalletsWithoutSystem>
580 RuntimeHelper<ParachainSystem, AllPalletsWithoutSystem>
581{
582 pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
583 match from {
584 XcmReceivedFrom::Parent => ParachainSystem::ReservedDmpWeight::get(),
585 XcmReceivedFrom::Sibling => ParachainSystem::ReservedXcmpWeight::get(),
586 }
587 }
588
589 pub fn xcm_max_weight_for_location(location: &Location) -> Weight {
590 Self::xcm_max_weight(if location == &Location::parent() {
591 XcmReceivedFrom::Parent
592 } else {
593 XcmReceivedFrom::Sibling
594 })
595 }
596}
597
598impl<Runtime: frame_system::Config + pallet_xcm::Config, AllPalletsWithoutSystem>
599 RuntimeHelper<Runtime, AllPalletsWithoutSystem>
600{
601 pub fn assert_pallet_xcm_event_outcome(
602 unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
603 assert_outcome: fn(Outcome),
604 ) {
605 assert_outcome(Self::get_pallet_xcm_event_outcome(unwrap_pallet_xcm_event));
606 }
607
608 pub fn get_pallet_xcm_event_outcome(
609 unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
610 ) -> Outcome {
611 <frame_system::Pallet<Runtime>>::events()
612 .into_iter()
613 .filter_map(|e| unwrap_pallet_xcm_event(e.event.encode()))
614 .find_map(|e| match e {
615 pallet_xcm::Event::Attempted { outcome } => Some(outcome),
616 _ => None,
617 })
618 .expect("No `pallet_xcm::Event::Attempted(outcome)` event found!")
619 }
620}
621
622impl<
623 Runtime: frame_system::Config + cumulus_pallet_xcmp_queue::Config,
624 AllPalletsWithoutSystem,
625 > RuntimeHelper<Runtime, AllPalletsWithoutSystem>
626{
627 pub fn xcmp_queue_message_sent(
628 unwrap_xcmp_queue_event: Box<
629 dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
630 >,
631 ) -> Option<XcmHash> {
632 <frame_system::Pallet<Runtime>>::events()
633 .into_iter()
634 .filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
635 .find_map(|e| match e {
636 cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } =>
637 Some(message_hash),
638 _ => None,
639 })
640 }
641}
642
643pub fn assert_metadata<Fungibles, AccountId>(
644 asset_id: impl Into<Fungibles::AssetId> + Clone,
645 expected_name: &str,
646 expected_symbol: &str,
647 expected_decimals: u8,
648) where
649 Fungibles: frame_support::traits::fungibles::metadata::Inspect<AccountId>
650 + frame_support::traits::fungibles::Inspect<AccountId>,
651{
652 assert_eq!(Fungibles::name(asset_id.clone().into()), Vec::from(expected_name),);
653 assert_eq!(Fungibles::symbol(asset_id.clone().into()), Vec::from(expected_symbol),);
654 assert_eq!(Fungibles::decimals(asset_id.into()), expected_decimals);
655}
656
657pub fn assert_total<Fungibles, AccountId>(
658 asset_id: impl Into<Fungibles::AssetId> + Clone,
659 expected_total_issuance: impl Into<Fungibles::Balance>,
660 expected_active_issuance: impl Into<Fungibles::Balance>,
661) where
662 Fungibles: frame_support::traits::fungibles::metadata::Inspect<AccountId>
663 + frame_support::traits::fungibles::Inspect<AccountId>,
664{
665 assert_eq!(Fungibles::total_issuance(asset_id.clone().into()), expected_total_issuance.into());
666 assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
667}
668
669pub fn mock_open_hrmp_channel<
678 C: cumulus_pallet_parachain_system::Config,
679 T: ProvideInherent<Call = cumulus_pallet_parachain_system::Call<C>>,
680>(
681 sender: ParaId,
682 recipient: ParaId,
683 included_head: HeaderFor<C>,
684 mut slot_digest: &[u8],
685 slot_durations: &SlotDurations,
686) {
687 let slot = Slot::decode(&mut slot_digest).expect("failed to decode digest");
688 let timestamp = slot.saturating_mul(slot_durations.para.as_millis());
690 let relay_slot = Slot::from_timestamp(timestamp.into(), slot_durations.relay);
691
692 let n = 1_u32;
693 let mut sproof_builder = RelayStateSproofBuilder {
694 para_id: sender,
695 included_para_head: Some(HeadData(included_head.encode())),
696 hrmp_egress_channel_index: Some(vec![recipient]),
697 current_slot: relay_slot,
698 ..Default::default()
699 };
700 sproof_builder.hrmp_channels.insert(
701 HrmpChannelId { sender, recipient },
702 AbridgedHrmpChannel {
703 max_capacity: 10,
704 max_total_size: 10_000_000_u32,
705 max_message_size: 10_000_000_u32,
706 msg_count: 0,
707 total_size: 0_u32,
708 mqc_head: None,
709 },
710 );
711
712 let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
713 let vfp = PersistedValidationData {
714 relay_parent_number: n as RelayChainBlockNumber,
715 relay_parent_storage_root,
716 ..Default::default()
717 };
718 let inherent_data = {
721 let mut inherent_data = InherentData::default();
722 let system_inherent_data = ParachainInherentData {
723 validation_data: vfp,
724 relay_chain_state,
725 downward_messages: Default::default(),
726 horizontal_messages: Default::default(),
727 relay_parent_descendants: Default::default(),
728 collator_peer_id: None,
729 };
730 inherent_data
731 .put_data(
732 cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
733 &system_inherent_data,
734 )
735 .expect("failed to put VFP inherent");
736 inherent_data
737 };
738
739 T::create_inherent(&inherent_data)
741 .expect("got an inherent")
742 .dispatch_bypass_filter(RawOrigin::None.into())
743 .expect("dispatch succeeded");
744}
745
746impl<HrmpChannelSource: cumulus_primitives_core::XcmpMessageSource, AllPalletsWithoutSystem>
747 RuntimeHelper<HrmpChannelSource, AllPalletsWithoutSystem>
748{
749 pub fn take_xcm(sent_to_para_id: ParaId) -> Option<VersionedXcm<()>> {
750 match HrmpChannelSource::take_outbound_messages(10)[..] {
751 [(para_id, ref mut xcm_message_data)] if para_id.eq(&sent_to_para_id.into()) => {
752 let mut xcm_message_data = &xcm_message_data[..];
753 let _ = XcmpMessageFormat::decode(&mut xcm_message_data).expect("valid format");
755 VersionedXcm::<()>::decode_with_depth_limit(
756 MAX_XCM_DECODE_DEPTH,
757 &mut xcm_message_data,
758 )
759 .map(|x| Some(x))
760 .expect("result with xcm")
761 },
762 _ => return None,
763 }
764 }
765}