1use 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 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 Success(Option<T::Hash>),
193 Fail(Option<T::Hash>, XcmError),
195 BadVersion(Option<T::Hash>),
197 BadFormat(Option<T::Hash>),
199
200 InvalidFormat(MessageId),
203 UnsupportedVersion(MessageId),
205 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 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);