referrerpolicy=no-referrer-when-downgrade

xcm_fuzzer/
parachain.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Parachain runtime mock.
18
19use codec::{Decode, Encode};
20use frame_support::{
21	construct_runtime, derive_impl, parameter_types,
22	traits::{Disabled, Everything, Nothing},
23	weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
24};
25
26use frame_system::EnsureRoot;
27use sp_runtime::{
28	generic,
29	traits::{AccountIdLookup, BlakeTwo256, Hash, IdentifyAccount, Verify},
30	MultiAddress, MultiSignature,
31};
32
33use pallet_xcm::XcmPassthrough;
34use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
35use polkadot_parachain_primitives::primitives::{
36	DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler,
37};
38use xcm::{latest::prelude::*, VersionedXcm};
39use xcm_builder::{
40	AccountId32Aliases, AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedRateOfFungible,
41	FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset,
42	ParentIsPreset, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
43	SovereignSignedViaLocation,
44};
45use xcm_executor::{Config, XcmExecutor};
46
47pub type TxExtension = (frame_system::CheckNonZeroSender<Runtime>,);
48
49pub type BlockNumber = u64;
50pub type Address = MultiAddress<AccountId, ()>;
51pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
52pub type UncheckedExtrinsic =
53	generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
54pub type Block = generic::Block<Header, UncheckedExtrinsic>;
55
56pub type Signature = MultiSignature;
57pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
58pub type Balance = u128;
59
60parameter_types! {
61	pub const BlockHashCount: u32 = 250;
62}
63
64#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
65impl frame_system::Config for Runtime {
66	type AccountId = AccountId;
67	type Lookup = AccountIdLookup<AccountId, ()>;
68	type Block = Block;
69	type AccountData = pallet_balances::AccountData<Balance>;
70}
71
72parameter_types! {
73	pub ExistentialDeposit: Balance = 1;
74}
75
76#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
77impl pallet_balances::Config for Runtime {
78	type Balance = Balance;
79	type ExistentialDeposit = ExistentialDeposit;
80	type AccountStore = System;
81}
82
83parameter_types! {
84	pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
85	pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
86}
87
88parameter_types! {
89	pub const KsmLocation: Location = Location::parent();
90	pub const RelayNetwork: NetworkId = NetworkId::Kusama;
91	pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into();
92}
93
94pub type LocationToAccountId = (
95	ParentIsPreset<AccountId>,
96	SiblingParachainConvertsVia<Sibling, AccountId>,
97	AccountId32Aliases<RelayNetwork, AccountId>,
98);
99
100pub type XcmOriginToCallOrigin = (
101	SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
102	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
103	XcmPassthrough<RuntimeOrigin>,
104);
105
106parameter_types! {
107	pub const UnitWeightCost: Weight = Weight::from_parts(1, 1);
108	pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1);
109	pub const MaxInstructions: u32 = 100;
110	pub const MaxAssetsIntoHolding: u32 = 64;
111}
112
113pub type LocalAssetTransactor =
114	FungibleAdapter<Balances, IsConcrete<KsmLocation>, LocationToAccountId, AccountId, ()>;
115
116pub type XcmRouter = super::ParachainXcmRouter<MsgQueue>;
117pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
118
119pub struct XcmConfig;
120impl Config for XcmConfig {
121	type RuntimeCall = RuntimeCall;
122	type XcmSender = XcmRouter;
123	type XcmEventEmitter = ();
124	type AssetTransactor = LocalAssetTransactor;
125	type OriginConverter = XcmOriginToCallOrigin;
126	type IsReserve = NativeAsset;
127	type IsTeleporter = ();
128	type UniversalLocation = UniversalLocation;
129	type Barrier = Barrier;
130	type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
131	type Trader = FixedRateOfFungible<KsmPerSecondPerByte, ()>;
132	type ResponseHandler = ();
133	type AssetTrap = ();
134	type AssetLocker = ();
135	type AssetExchanger = ();
136	type AssetClaims = ();
137	type SubscriptionService = ();
138	type PalletInstancesInfo = ();
139	type FeeManager = ();
140	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
141	type MessageExporter = ();
142	type UniversalAliases = Nothing;
143	type CallDispatcher = RuntimeCall;
144	type SafeCallFilter = Everything;
145	type Aliasers = Nothing;
146	type TransactionalProcessor = FrameTransactionalProcessor;
147	type HrmpNewChannelOpenRequestHandler = ();
148	type HrmpChannelAcceptedHandler = ();
149	type HrmpChannelClosingHandler = ();
150	type XcmRecorder = ();
151}
152
153#[frame_support::pallet]
154pub mod mock_msg_queue {
155	use super::*;
156	use frame_support::pallet_prelude::*;
157
158	#[pallet::config]
159	pub trait Config: frame_system::Config {
160		#[allow(deprecated)]
161		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
162		type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
163	}
164
165	#[pallet::pallet]
166	#[pallet::without_storage_info]
167	pub struct Pallet<T>(_);
168
169	#[pallet::call]
170	impl<T: Config> Pallet<T> {}
171
172	#[pallet::storage]
173	pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
174
175	#[pallet::storage]
176	/// A queue of received DMP messages
177	pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
178
179	impl<T: Config> Get<ParaId> for Pallet<T> {
180		fn get() -> ParaId {
181			Self::parachain_id()
182		}
183	}
184
185	pub type MessageId = [u8; 32];
186
187	#[pallet::event]
188	#[pallet::generate_deposit(pub(super) fn deposit_event)]
189	pub enum Event<T: Config> {
190		// XCMP
191		/// Some XCM was executed OK.
192		Success(Option<T::Hash>),
193		/// Some XCM failed.
194		Fail(Option<T::Hash>, XcmError),
195		/// Bad XCM version used.
196		BadVersion(Option<T::Hash>),
197		/// Bad XCM format used.
198		BadFormat(Option<T::Hash>),
199
200		// DMP
201		/// Downward message is invalid XCM.
202		InvalidFormat(MessageId),
203		/// Downward message is unsupported version of XCM.
204		UnsupportedVersion(MessageId),
205		/// Downward message executed with the given outcome.
206		ExecutedDownward(MessageId, Outcome),
207	}
208
209	impl<T: Config> Pallet<T> {
210		pub fn parachain_id() -> ParaId {
211			ParachainId::<T>::get()
212		}
213
214		pub fn received_dmp() -> Vec<Xcm<T::RuntimeCall>> {
215			ReceivedDmp::<T>::get()
216		}
217
218		pub fn set_para_id(para_id: ParaId) {
219			ParachainId::<T>::put(para_id);
220		}
221
222		fn handle_xcmp_message(
223			sender: ParaId,
224			_sent_at: RelayBlockNumber,
225			xcm: VersionedXcm<T::RuntimeCall>,
226			max_weight: Weight,
227		) -> Result<Weight, XcmError> {
228			let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
229			let mut message_hash = xcm.using_encoded(sp_io::hashing::blake2_256);
230			let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
231				Ok(xcm) => {
232					let location = Location::new(1, [Parachain(sender.into())]);
233					match T::XcmExecutor::prepare_and_execute(
234						location,
235						xcm,
236						&mut message_hash,
237						max_weight,
238						Weight::zero(),
239					) {
240						Outcome::Error(InstructionError { error, .. }) =>
241							(Err(error), Event::Fail(Some(hash), error)),
242						Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
243						// As far as the caller is concerned, this was dispatched without error, so
244						// we just report the weight used.
245						Outcome::Incomplete {
246							used, error: InstructionError { error, .. }, ..
247						} => (Ok(used), Event::Fail(Some(hash), error)),
248					}
249				},
250				Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
251			};
252			Self::deposit_event(event);
253			result
254		}
255	}
256
257	impl<T: Config> XcmpMessageHandler for Pallet<T> {
258		fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
259			iter: I,
260			max_weight: Weight,
261		) -> Weight {
262			for (sender, sent_at, data) in iter {
263				let mut data_ref = data;
264				let _ = XcmpMessageFormat::decode(&mut data_ref)
265					.expect("Simulator encodes with versioned xcm format; qed");
266
267				let mut remaining_fragments = data_ref;
268				while !remaining_fragments.is_empty() {
269					if let Ok(xcm) =
270						VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
271					{
272						let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
273					} else {
274						debug_assert!(false, "Invalid incoming XCMP message data");
275					}
276				}
277			}
278			max_weight
279		}
280	}
281
282	impl<T: Config> DmpMessageHandler for Pallet<T> {
283		fn handle_dmp_messages(
284			iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
285			limit: Weight,
286		) -> Weight {
287			for (_i, (_sent_at, data)) in iter.enumerate() {
288				let mut id = sp_io::hashing::blake2_256(&data[..]);
289				let maybe_msg = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..])
290					.map(Xcm::<T::RuntimeCall>::try_from);
291				match maybe_msg {
292					Err(_) => {
293						Self::deposit_event(Event::InvalidFormat(id));
294					},
295					Ok(Err(())) => {
296						Self::deposit_event(Event::UnsupportedVersion(id));
297					},
298					Ok(Ok(x)) => {
299						let outcome = T::XcmExecutor::prepare_and_execute(
300							Parent,
301							x.clone(),
302							&mut id,
303							limit,
304							Weight::zero(),
305						);
306						<ReceivedDmp<T>>::append(x);
307						Self::deposit_event(Event::ExecutedDownward(id, outcome));
308					},
309				}
310			}
311			limit
312		}
313	}
314}
315
316impl mock_msg_queue::Config for Runtime {
317	type RuntimeEvent = RuntimeEvent;
318	type XcmExecutor = XcmExecutor<XcmConfig>;
319}
320
321pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
322
323impl pallet_xcm::Config for Runtime {
324	type RuntimeEvent = RuntimeEvent;
325	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
326	type XcmRouter = XcmRouter;
327	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
328	type XcmExecuteFilter = Everything;
329	type XcmExecutor = XcmExecutor<XcmConfig>;
330	type XcmTeleportFilter = Nothing;
331	type XcmReserveTransferFilter = Everything;
332	type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
333	type UniversalLocation = UniversalLocation;
334	type RuntimeOrigin = RuntimeOrigin;
335	type RuntimeCall = RuntimeCall;
336	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
337	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
338	type Currency = Balances;
339	type CurrencyMatcher = ();
340	type TrustedLockers = ();
341	type SovereignAccountOf = LocationToAccountId;
342	type MaxLockers = frame_support::traits::ConstU32<8>;
343	type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>;
344	type RemoteLockConsumerIdentifier = ();
345	type WeightInfo = pallet_xcm::TestWeightInfo;
346	type AdminOrigin = EnsureRoot<AccountId>;
347	type AuthorizedAliasConsideration = Disabled;
348}
349
350construct_runtime!(
351	pub enum Runtime
352	{
353		System: frame_system,
354		Balances: pallet_balances,
355		MsgQueue: mock_msg_queue,
356		PolkadotXcm: pallet_xcm,
357	}
358);