referrerpolicy=no-referrer-when-downgrade

pallet_contracts_mock_network/mocks/
msg_queue.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Substrate.
3
4// Substrate 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// Substrate 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 Substrate.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Parachain runtime mock.
18
19use codec::{Decode, Encode};
20
21use frame_support::weights::Weight;
22use polkadot_parachain_primitives::primitives::{
23	DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler,
24};
25use polkadot_primitives::BlockNumber as RelayBlockNumber;
26use sp_runtime::traits::{Get, Hash};
27
28use xcm::{latest::prelude::*, VersionedXcm};
29
30#[frame_support::pallet]
31pub mod pallet {
32	use super::*;
33	use frame_support::pallet_prelude::*;
34
35	#[pallet::config]
36	pub trait Config: frame_system::Config {
37		#[allow(deprecated)]
38		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
39		type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
40	}
41
42	#[pallet::call]
43	impl<T: Config> Pallet<T> {}
44
45	#[pallet::pallet]
46	#[pallet::without_storage_info]
47	pub struct Pallet<T>(_);
48
49	#[pallet::storage]
50	pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
51
52	#[pallet::storage]
53	/// A queue of received DMP messages
54	pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
55
56	impl<T: Config> Get<ParaId> for Pallet<T> {
57		fn get() -> ParaId {
58			ParachainId::<T>::get()
59		}
60	}
61
62	pub type MessageId = [u8; 32];
63
64	#[pallet::event]
65	#[pallet::generate_deposit(pub(super) fn deposit_event)]
66	pub enum Event<T: Config> {
67		/// Some XCM was executed OK.
68		Success(Option<T::Hash>),
69		/// Some XCM failed.
70		Fail(Option<T::Hash>, XcmError),
71		/// Bad XCM version used.
72		BadVersion(Option<T::Hash>),
73		/// Bad XCM format used.
74		BadFormat(Option<T::Hash>),
75
76		// DMP
77		/// Downward message is invalid XCM.
78		InvalidFormat(MessageId),
79		/// Downward message is unsupported version of XCM.
80		UnsupportedVersion(MessageId),
81		/// Downward message executed with the given outcome.
82		ExecutedDownward(MessageId, Outcome),
83	}
84
85	impl<T: Config> Pallet<T> {
86		pub fn set_para_id(para_id: ParaId) {
87			ParachainId::<T>::put(para_id);
88		}
89
90		pub fn parachain_id() -> ParaId {
91			ParachainId::<T>::get()
92		}
93
94		pub fn received_dmp() -> Vec<Xcm<T::RuntimeCall>> {
95			ReceivedDmp::<T>::get()
96		}
97
98		fn handle_xcmp_message(
99			sender: ParaId,
100			_sent_at: RelayBlockNumber,
101			xcm: VersionedXcm<T::RuntimeCall>,
102			max_weight: Weight,
103		) -> Result<Weight, XcmError> {
104			let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
105			let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
106			let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
107				Ok(xcm) => {
108					let location = (Parent, Parachain(sender.into()));
109					match T::XcmExecutor::prepare_and_execute(
110						location,
111						xcm,
112						&mut message_hash,
113						max_weight,
114						Weight::zero(),
115					) {
116						Outcome::Error(InstructionError { error, .. }) => {
117							(Err(error), Event::Fail(Some(hash), error))
118						},
119						Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
120						// As far as the caller is concerned, this was dispatched without error, so
121						// we just report the weight used.
122						Outcome::Incomplete {
123							used, error: InstructionError { error, .. }, ..
124						} => (Ok(used), Event::Fail(Some(hash), error)),
125					}
126				},
127				Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
128			};
129			Self::deposit_event(event);
130			result
131		}
132	}
133
134	impl<T: Config> XcmpMessageHandler for Pallet<T> {
135		fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
136			iter: I,
137			max_weight: Weight,
138		) -> Weight {
139			for (sender, sent_at, data) in iter {
140				let mut data_ref = data;
141				let _ = XcmpMessageFormat::decode(&mut data_ref)
142					.expect("Simulator encodes with versioned xcm format; qed");
143
144				let mut remaining_fragments = data_ref;
145				while !remaining_fragments.is_empty() {
146					if let Ok(xcm) =
147						VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
148					{
149						let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
150					} else {
151						debug_assert!(false, "Invalid incoming XCMP message data");
152					}
153				}
154			}
155			max_weight
156		}
157	}
158
159	impl<T: Config> DmpMessageHandler for Pallet<T> {
160		fn handle_dmp_messages(
161			iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
162			limit: Weight,
163		) -> Weight {
164			for (_i, (_sent_at, data)) in iter.enumerate() {
165				let mut id = sp_io::hashing::blake2_256(&data[..]);
166				let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
167				match maybe_versioned {
168					Err(_) => {
169						Self::deposit_event(Event::InvalidFormat(id));
170					},
171					Ok(versioned) => match Xcm::try_from(versioned) {
172						Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
173						Ok(x) => {
174							let outcome = T::XcmExecutor::prepare_and_execute(
175								Parent,
176								x.clone(),
177								&mut id,
178								limit,
179								Weight::zero(),
180							);
181							ReceivedDmp::<T>::append(x);
182							Self::deposit_event(Event::ExecutedDownward(id, outcome));
183						},
184					},
185				}
186			}
187			limit
188		}
189	}
190}