parachains_runtimes_test_utils/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use core::marker::PhantomData;
17
18use codec::{Decode, DecodeLimit};
19use cumulus_primitives_core::{
20	relay_chain::Slot, AbridgedHrmpChannel, ParaId, PersistedValidationData,
21};
22use cumulus_primitives_parachain_inherent::ParachainInherentData;
23use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
24use frame_support::{
25	dispatch::{DispatchResult, GetDispatchInfo, RawOrigin},
26	inherent::{InherentData, ProvideInherent},
27	pallet_prelude::Get,
28	traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable},
29	weights::Weight,
30};
31use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor};
32use polkadot_parachain_primitives::primitives::{
33	HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat,
34};
35use sp_consensus_aura::{SlotDuration, AURA_ENGINE_ID};
36use sp_core::{Encode, U256};
37use sp_runtime::{traits::Header, BuildStorage, Digest, DigestItem, SaturatedConversion};
38use xcm::{
39	latest::{Asset, Location, XcmContext, XcmHash},
40	prelude::*,
41	VersionedXcm, MAX_XCM_DECODE_DEPTH,
42};
43use xcm_executor::{traits::TransactAsset, AssetsInHolding};
44
45pub mod test_cases;
46
47pub type BalanceOf<Runtime> = <Runtime as pallet_balances::Config>::Balance;
48pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
49pub type RuntimeCallOf<Runtime> = <Runtime as frame_system::Config>::RuntimeCall;
50pub type ValidatorIdOf<Runtime> = <Runtime as pallet_session::Config>::ValidatorId;
51pub type SessionKeysOf<Runtime> = <Runtime as pallet_session::Config>::Keys;
52
53pub struct CollatorSessionKey<
54	Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config,
55> {
56	collator: AccountIdOf<Runtime>,
57	validator: ValidatorIdOf<Runtime>,
58	key: SessionKeysOf<Runtime>,
59}
60
61pub struct CollatorSessionKeys<
62	Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config,
63> {
64	items: Vec<CollatorSessionKey<Runtime>>,
65}
66
67impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config>
68	CollatorSessionKey<Runtime>
69{
70	pub fn new(
71		collator: AccountIdOf<Runtime>,
72		validator: ValidatorIdOf<Runtime>,
73		key: SessionKeysOf<Runtime>,
74	) -> Self {
75		Self { collator, validator, key }
76	}
77}
78
79impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config> Default
80	for CollatorSessionKeys<Runtime>
81{
82	fn default() -> Self {
83		Self { items: vec![] }
84	}
85}
86
87impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config>
88	CollatorSessionKeys<Runtime>
89{
90	pub fn new(
91		collator: AccountIdOf<Runtime>,
92		validator: ValidatorIdOf<Runtime>,
93		key: SessionKeysOf<Runtime>,
94	) -> Self {
95		Self { items: vec![CollatorSessionKey::new(collator, validator, key)] }
96	}
97
98	pub fn add(mut self, item: CollatorSessionKey<Runtime>) -> Self {
99		self.items.push(item);
100		self
101	}
102
103	pub fn collators(&self) -> Vec<AccountIdOf<Runtime>> {
104		self.items.iter().map(|item| item.collator.clone()).collect::<Vec<_>>()
105	}
106
107	pub fn session_keys(
108		&self,
109	) -> Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)> {
110		self.items
111			.iter()
112			.map(|item| (item.collator.clone(), item.validator.clone(), item.key.clone()))
113			.collect::<Vec<_>>()
114	}
115}
116
117pub struct SlotDurations {
118	pub relay: SlotDuration,
119	pub para: SlotDuration,
120}
121
122/// A set of traits for a minimal parachain runtime, that may be used in conjunction with the
123/// `ExtBuilder` and the `RuntimeHelper`.
124pub trait BasicParachainRuntime:
125	frame_system::Config
126	+ pallet_balances::Config
127	+ pallet_session::Config
128	+ pallet_xcm::Config
129	+ parachain_info::Config
130	+ pallet_collator_selection::Config
131	+ cumulus_pallet_parachain_system::Config
132	+ pallet_timestamp::Config
133{
134}
135
136impl<T> BasicParachainRuntime for T
137where
138	T: frame_system::Config
139		+ pallet_balances::Config
140		+ pallet_session::Config
141		+ pallet_xcm::Config
142		+ parachain_info::Config
143		+ pallet_collator_selection::Config
144		+ cumulus_pallet_parachain_system::Config
145		+ pallet_timestamp::Config,
146	ValidatorIdOf<T>: From<AccountIdOf<T>>,
147{
148}
149
150/// Basic builder based on balances, collators and pallet_session.
151pub struct ExtBuilder<Runtime: BasicParachainRuntime> {
152	// endowed accounts with balances
153	balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
154	// collators to test block prod
155	collators: Vec<AccountIdOf<Runtime>>,
156	// keys added to pallet session
157	keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
158	// safe XCM version for pallet_xcm
159	safe_xcm_version: Option<XcmVersion>,
160	// para id
161	para_id: Option<ParaId>,
162	_runtime: PhantomData<Runtime>,
163}
164
165impl<Runtime: BasicParachainRuntime> Default for ExtBuilder<Runtime> {
166	fn default() -> ExtBuilder<Runtime> {
167		ExtBuilder {
168			balances: vec![],
169			collators: vec![],
170			keys: vec![],
171			safe_xcm_version: None,
172			para_id: None,
173			_runtime: PhantomData,
174		}
175	}
176}
177
178impl<Runtime: BasicParachainRuntime> ExtBuilder<Runtime> {
179	pub fn with_balances(
180		mut self,
181		balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
182	) -> Self {
183		self.balances = balances;
184		self
185	}
186	pub fn with_collators(mut self, collators: Vec<AccountIdOf<Runtime>>) -> Self {
187		self.collators = collators;
188		self
189	}
190
191	pub fn with_session_keys(
192		mut self,
193		keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
194	) -> Self {
195		self.keys = keys;
196		self
197	}
198
199	pub fn with_tracing(self) -> Self {
200		sp_tracing::try_init_simple();
201		self
202	}
203
204	pub fn with_safe_xcm_version(mut self, safe_xcm_version: XcmVersion) -> Self {
205		self.safe_xcm_version = Some(safe_xcm_version);
206		self
207	}
208
209	pub fn with_para_id(mut self, para_id: ParaId) -> Self {
210		self.para_id = Some(para_id);
211		self
212	}
213
214	pub fn build(self) -> sp_io::TestExternalities {
215		let mut t = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
216
217		pallet_xcm::GenesisConfig::<Runtime> {
218			safe_xcm_version: self.safe_xcm_version,
219			..Default::default()
220		}
221		.assimilate_storage(&mut t)
222		.unwrap();
223
224		if let Some(para_id) = self.para_id {
225			parachain_info::GenesisConfig::<Runtime> {
226				parachain_id: para_id,
227				..Default::default()
228			}
229			.assimilate_storage(&mut t)
230			.unwrap();
231		}
232
233		pallet_balances::GenesisConfig::<Runtime> { balances: self.balances }
234			.assimilate_storage(&mut t)
235			.unwrap();
236
237		pallet_collator_selection::GenesisConfig::<Runtime> {
238			invulnerables: self.collators.clone(),
239			candidacy_bond: Default::default(),
240			desired_candidates: Default::default(),
241		}
242		.assimilate_storage(&mut t)
243		.unwrap();
244
245		pallet_session::GenesisConfig::<Runtime> { keys: self.keys, ..Default::default() }
246			.assimilate_storage(&mut t)
247			.unwrap();
248
249		let mut ext = sp_io::TestExternalities::new(t);
250
251		ext.execute_with(|| {
252			frame_system::Pallet::<Runtime>::set_block_number(1u32.into());
253		});
254
255		ext
256	}
257}
258
259pub struct RuntimeHelper<Runtime, AllPalletsWithoutSystem>(
260	PhantomData<(Runtime, AllPalletsWithoutSystem)>,
261);
262/// Utility function that advances the chain to the desired block number.
263/// If an author is provided, that author information is injected to all the blocks in the meantime.
264impl<
265		Runtime: frame_system::Config + cumulus_pallet_parachain_system::Config + pallet_timestamp::Config,
266		AllPalletsWithoutSystem,
267	> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
268where
269	AccountIdOf<Runtime>:
270		Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
271	AllPalletsWithoutSystem:
272		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
273{
274	pub fn run_to_block(n: u32, author: AccountIdOf<Runtime>) -> HeaderFor<Runtime> {
275		let mut last_header = None;
276		loop {
277			let block_number = frame_system::Pallet::<Runtime>::block_number();
278			if block_number >= n.into() {
279				break
280			}
281			// Set the new block number and author
282
283			// Inherent is not created at every block, don't finalize parachain
284			// system to avoid panicking.
285			let header = frame_system::Pallet::<Runtime>::finalize();
286
287			let pre_digest =
288				Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, author.encode())] };
289			frame_system::Pallet::<Runtime>::reset_events();
290
291			let next_block_number = block_number + 1u32.into();
292			frame_system::Pallet::<Runtime>::initialize(
293				&next_block_number,
294				&header.hash(),
295				&pre_digest,
296			);
297			AllPalletsWithoutSystem::on_initialize(next_block_number);
298			last_header = Some(header);
299		}
300		last_header.expect("run_to_block empty block range")
301	}
302
303	pub fn run_to_block_with_finalize(n: u32) -> HeaderFor<Runtime> {
304		let mut last_header = None;
305		loop {
306			let block_number = frame_system::Pallet::<Runtime>::block_number();
307			if block_number >= n.into() {
308				break
309			}
310			// Set the new block number and author
311			let header = frame_system::Pallet::<Runtime>::finalize();
312
313			let pre_digest = Digest {
314				logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, block_number.encode())],
315			};
316			frame_system::Pallet::<Runtime>::reset_events();
317
318			let next_block_number = block_number + 1u32.into();
319			frame_system::Pallet::<Runtime>::initialize(
320				&next_block_number,
321				&header.hash(),
322				&pre_digest,
323			);
324			AllPalletsWithoutSystem::on_initialize(next_block_number);
325
326			let parent_head = HeadData(header.encode());
327			let sproof_builder = RelayStateSproofBuilder {
328				para_id: <Runtime>::SelfParaId::get(),
329				included_para_head: parent_head.clone().into(),
330				..Default::default()
331			};
332
333			let (relay_parent_storage_root, relay_chain_state) =
334				sproof_builder.into_state_root_and_proof();
335			let inherent_data = ParachainInherentData {
336				validation_data: PersistedValidationData {
337					parent_head,
338					relay_parent_number: (block_number.saturated_into::<u32>() * 2 + 1).into(),
339					relay_parent_storage_root,
340					max_pov_size: 100_000_000,
341				},
342				relay_chain_state,
343				downward_messages: Default::default(),
344				horizontal_messages: Default::default(),
345			};
346
347			let _ = cumulus_pallet_parachain_system::Pallet::<Runtime>::set_validation_data(
348				Runtime::RuntimeOrigin::none(),
349				inherent_data,
350			);
351			let _ = pallet_timestamp::Pallet::<Runtime>::set(
352				Runtime::RuntimeOrigin::none(),
353				300_u32.into(),
354			);
355			AllPalletsWithoutSystem::on_finalize(next_block_number);
356			let header = frame_system::Pallet::<Runtime>::finalize();
357			last_header = Some(header);
358		}
359		last_header.expect("run_to_block empty block range")
360	}
361
362	pub fn root_origin() -> <Runtime as frame_system::Config>::RuntimeOrigin {
363		<Runtime as frame_system::Config>::RuntimeOrigin::root()
364	}
365
366	pub fn block_number() -> U256 {
367		frame_system::Pallet::<Runtime>::block_number().into()
368	}
369
370	pub fn origin_of(
371		account_id: AccountIdOf<Runtime>,
372	) -> <Runtime as frame_system::Config>::RuntimeOrigin {
373		<Runtime as frame_system::Config>::RuntimeOrigin::signed(account_id.into())
374	}
375}
376
377impl<XcmConfig: xcm_executor::Config, AllPalletsWithoutSystem>
378	RuntimeHelper<XcmConfig, AllPalletsWithoutSystem>
379{
380	pub fn do_transfer(
381		from: Location,
382		to: Location,
383		(asset, amount): (Location, u128),
384	) -> Result<AssetsInHolding, XcmError> {
385		<XcmConfig::AssetTransactor as TransactAsset>::transfer_asset(
386			&Asset { id: AssetId(asset), fun: Fungible(amount) },
387			&from,
388			&to,
389			// We aren't able to track the XCM that initiated the fee deposit, so we create a
390			// fake message hash here
391			&XcmContext::with_message_id([0; 32]),
392		)
393	}
394}
395
396impl<
397		Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config,
398		AllPalletsWithoutSystem,
399	> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
400{
401	pub fn do_teleport_assets<HrmpChannelOpener>(
402		origin: <Runtime as frame_system::Config>::RuntimeOrigin,
403		dest: Location,
404		beneficiary: Location,
405		(asset, amount): (Location, u128),
406		open_hrmp_channel: Option<(u32, u32)>,
407		included_head: HeaderFor<Runtime>,
408		slot_digest: &[u8],
409		slot_durations: &SlotDurations,
410	) -> DispatchResult
411	where
412		HrmpChannelOpener: frame_support::inherent::ProvideInherent<
413			Call = cumulus_pallet_parachain_system::Call<Runtime>,
414		>,
415	{
416		// open hrmp (if needed)
417		if let Some((source_para_id, target_para_id)) = open_hrmp_channel {
418			mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
419				source_para_id.into(),
420				target_para_id.into(),
421				included_head,
422				slot_digest,
423				slot_durations,
424			);
425		}
426
427		// do teleport
428		<pallet_xcm::Pallet<Runtime>>::limited_teleport_assets(
429			origin,
430			Box::new(dest.into()),
431			Box::new(beneficiary.into()),
432			Box::new((AssetId(asset), amount).into()),
433			0,
434			Unlimited,
435		)
436	}
437}
438
439impl<
440		Runtime: cumulus_pallet_parachain_system::Config + pallet_xcm::Config,
441		AllPalletsWithoutSystem,
442	> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
443{
444	pub fn execute_as_governance(call: Vec<u8>) -> Outcome {
445		// prepare xcm as governance will do
446		let xcm = Xcm(vec![
447			UnpaidExecution { weight_limit: Unlimited, check_origin: None },
448			Transact {
449				origin_kind: OriginKind::Superuser,
450				call: call.into(),
451				fallback_max_weight: None,
452			},
453			ExpectTransactStatus(MaybeErrorCode::Success),
454		]);
455
456		// execute xcm as parent origin
457		let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
458		<<Runtime as pallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
459			Location::parent(),
460			xcm,
461			&mut hash,
462			Self::xcm_max_weight(XcmReceivedFrom::Parent),
463			Weight::zero(),
464		)
465	}
466
467	pub fn execute_as_origin<Call: GetDispatchInfo + Encode>(
468		(origin, origin_kind): (Location, OriginKind),
469		call: Call,
470		maybe_buy_execution_fee: Option<Asset>,
471	) -> Outcome {
472		let mut instructions = if let Some(buy_execution_fee) = maybe_buy_execution_fee {
473			vec![
474				WithdrawAsset(buy_execution_fee.clone().into()),
475				BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
476			]
477		} else {
478			vec![UnpaidExecution { check_origin: None, weight_limit: Unlimited }]
479		};
480
481		// prepare `Transact` xcm
482		instructions.extend(vec![
483			Transact { origin_kind, call: call.encode().into(), fallback_max_weight: None },
484			ExpectTransactStatus(MaybeErrorCode::Success),
485		]);
486		let xcm = Xcm(instructions);
487
488		// execute xcm as parent origin
489		let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
490		<<Runtime as pallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
491			origin.clone(),
492			xcm,
493			&mut hash,
494			Self::xcm_max_weight(if origin == Location::parent() {
495				XcmReceivedFrom::Parent
496			} else {
497				XcmReceivedFrom::Sibling
498			}),
499			Weight::zero(),
500		)
501	}
502}
503
504pub enum XcmReceivedFrom {
505	Parent,
506	Sibling,
507}
508
509impl<ParachainSystem: cumulus_pallet_parachain_system::Config, AllPalletsWithoutSystem>
510	RuntimeHelper<ParachainSystem, AllPalletsWithoutSystem>
511{
512	pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
513		match from {
514			XcmReceivedFrom::Parent => ParachainSystem::ReservedDmpWeight::get(),
515			XcmReceivedFrom::Sibling => ParachainSystem::ReservedXcmpWeight::get(),
516		}
517	}
518}
519
520impl<Runtime: frame_system::Config + pallet_xcm::Config, AllPalletsWithoutSystem>
521	RuntimeHelper<Runtime, AllPalletsWithoutSystem>
522{
523	pub fn assert_pallet_xcm_event_outcome(
524		unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
525		assert_outcome: fn(Outcome),
526	) {
527		assert_outcome(Self::get_pallet_xcm_event_outcome(unwrap_pallet_xcm_event));
528	}
529
530	pub fn get_pallet_xcm_event_outcome(
531		unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
532	) -> Outcome {
533		<frame_system::Pallet<Runtime>>::events()
534			.into_iter()
535			.filter_map(|e| unwrap_pallet_xcm_event(e.event.encode()))
536			.find_map(|e| match e {
537				pallet_xcm::Event::Attempted { outcome } => Some(outcome),
538				_ => None,
539			})
540			.expect("No `pallet_xcm::Event::Attempted(outcome)` event found!")
541	}
542}
543
544impl<
545		Runtime: frame_system::Config + cumulus_pallet_xcmp_queue::Config,
546		AllPalletsWithoutSystem,
547	> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
548{
549	pub fn xcmp_queue_message_sent(
550		unwrap_xcmp_queue_event: Box<
551			dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
552		>,
553	) -> Option<XcmHash> {
554		<frame_system::Pallet<Runtime>>::events()
555			.into_iter()
556			.filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
557			.find_map(|e| match e {
558				cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } =>
559					Some(message_hash),
560				_ => None,
561			})
562	}
563}
564
565pub fn assert_metadata<Fungibles, AccountId>(
566	asset_id: impl Into<Fungibles::AssetId> + Clone,
567	expected_name: &str,
568	expected_symbol: &str,
569	expected_decimals: u8,
570) where
571	Fungibles: frame_support::traits::fungibles::metadata::Inspect<AccountId>
572		+ frame_support::traits::fungibles::Inspect<AccountId>,
573{
574	assert_eq!(Fungibles::name(asset_id.clone().into()), Vec::from(expected_name),);
575	assert_eq!(Fungibles::symbol(asset_id.clone().into()), Vec::from(expected_symbol),);
576	assert_eq!(Fungibles::decimals(asset_id.into()), expected_decimals);
577}
578
579pub fn assert_total<Fungibles, AccountId>(
580	asset_id: impl Into<Fungibles::AssetId> + Clone,
581	expected_total_issuance: impl Into<Fungibles::Balance>,
582	expected_active_issuance: impl Into<Fungibles::Balance>,
583) where
584	Fungibles: frame_support::traits::fungibles::metadata::Inspect<AccountId>
585		+ frame_support::traits::fungibles::Inspect<AccountId>,
586{
587	assert_eq!(Fungibles::total_issuance(asset_id.clone().into()), expected_total_issuance.into());
588	assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
589}
590
591/// Helper function which emulates opening HRMP channel which is needed for `XcmpQueue` to pass.
592///
593/// Calls parachain-system's `create_inherent` in case the channel hasn't been opened before, and
594/// thus requires additional parameters for validating it: latest included parachain head and
595/// parachain AuRa-slot.
596///
597/// AuRa consensus hook expects pallets to be initialized, before calling this function make sure to
598/// `run_to_block` at least once.
599pub fn mock_open_hrmp_channel<
600	C: cumulus_pallet_parachain_system::Config,
601	T: ProvideInherent<Call = cumulus_pallet_parachain_system::Call<C>>,
602>(
603	sender: ParaId,
604	recipient: ParaId,
605	included_head: HeaderFor<C>,
606	mut slot_digest: &[u8],
607	slot_durations: &SlotDurations,
608) {
609	let slot = Slot::decode(&mut slot_digest).expect("failed to decode digest");
610	// Convert para slot to relay chain.
611	let timestamp = slot.saturating_mul(slot_durations.para.as_millis());
612	let relay_slot = Slot::from_timestamp(timestamp.into(), slot_durations.relay);
613
614	let n = 1_u32;
615	let mut sproof_builder = RelayStateSproofBuilder {
616		para_id: sender,
617		included_para_head: Some(HeadData(included_head.encode())),
618		hrmp_egress_channel_index: Some(vec![recipient]),
619		current_slot: relay_slot,
620		..Default::default()
621	};
622	sproof_builder.hrmp_channels.insert(
623		HrmpChannelId { sender, recipient },
624		AbridgedHrmpChannel {
625			max_capacity: 10,
626			max_total_size: 10_000_000_u32,
627			max_message_size: 10_000_000_u32,
628			msg_count: 0,
629			total_size: 0_u32,
630			mqc_head: None,
631		},
632	);
633
634	let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
635	let vfp = PersistedValidationData {
636		relay_parent_number: n as RelayChainBlockNumber,
637		relay_parent_storage_root,
638		..Default::default()
639	};
640	// It is insufficient to push the validation function params
641	// to storage; they must also be included in the inherent data.
642	let inherent_data = {
643		let mut inherent_data = InherentData::default();
644		let system_inherent_data = ParachainInherentData {
645			validation_data: vfp,
646			relay_chain_state,
647			downward_messages: Default::default(),
648			horizontal_messages: Default::default(),
649		};
650		inherent_data
651			.put_data(
652				cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
653				&system_inherent_data,
654			)
655			.expect("failed to put VFP inherent");
656		inherent_data
657	};
658
659	// execute the block
660	T::create_inherent(&inherent_data)
661		.expect("got an inherent")
662		.dispatch_bypass_filter(RawOrigin::None.into())
663		.expect("dispatch succeeded");
664}
665
666impl<HrmpChannelSource: cumulus_primitives_core::XcmpMessageSource, AllPalletsWithoutSystem>
667	RuntimeHelper<HrmpChannelSource, AllPalletsWithoutSystem>
668{
669	pub fn take_xcm(sent_to_para_id: ParaId) -> Option<VersionedXcm<()>> {
670		match HrmpChannelSource::take_outbound_messages(10)[..] {
671			[(para_id, ref mut xcm_message_data)] if para_id.eq(&sent_to_para_id.into()) => {
672				let mut xcm_message_data = &xcm_message_data[..];
673				// decode
674				let _ = XcmpMessageFormat::decode(&mut xcm_message_data).expect("valid format");
675				VersionedXcm::<()>::decode_with_depth_limit(
676					MAX_XCM_DECODE_DEPTH,
677					&mut xcm_message_data,
678				)
679				.map(|x| Some(x))
680				.expect("result with xcm")
681			},
682			_ => return None,
683		}
684	}
685}