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						Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
119						// As far as the caller is concerned, this was dispatched without error, so
120						// we just report the weight used.
121						Outcome::Incomplete {
122							used, error: InstructionError { error, .. }, ..
123						} => (Ok(used), Event::Fail(Some(hash), error)),
124					}
125				},
126				Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
127			};
128			Self::deposit_event(event);
129			result
130		}
131	}
132
133	impl<T: Config> XcmpMessageHandler for Pallet<T> {
134		fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
135			iter: I,
136			max_weight: Weight,
137		) -> Weight {
138			for (sender, sent_at, data) in iter {
139				let mut data_ref = data;
140				let _ = XcmpMessageFormat::decode(&mut data_ref)
141					.expect("Simulator encodes with versioned xcm format; qed");
142
143				let mut remaining_fragments = data_ref;
144				while !remaining_fragments.is_empty() {
145					if let Ok(xcm) =
146						VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
147					{
148						let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
149					} else {
150						debug_assert!(false, "Invalid incoming XCMP message data");
151					}
152				}
153			}
154			max_weight
155		}
156	}
157
158	impl<T: Config> DmpMessageHandler for Pallet<T> {
159		fn handle_dmp_messages(
160			iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
161			limit: Weight,
162		) -> Weight {
163			for (_i, (_sent_at, data)) in iter.enumerate() {
164				let mut id = sp_io::hashing::blake2_256(&data[..]);
165				let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
166				match maybe_versioned {
167					Err(_) => {
168						Self::deposit_event(Event::InvalidFormat(id));
169					},
170					Ok(versioned) => match Xcm::try_from(versioned) {
171						Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
172						Ok(x) => {
173							let outcome = T::XcmExecutor::prepare_and_execute(
174								Parent,
175								x.clone(),
176								&mut id,
177								limit,
178								Weight::zero(),
179							);
180							ReceivedDmp::<T>::append(x);
181							Self::deposit_event(Event::ExecutedDownward(id, outcome));
182						},
183					},
184				}
185			}
186			limit
187		}
188	}
189}