orml_xcm_mock_message_queue/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
4
5use cumulus_primitives_core::{ParaId, XcmpMessageFormat, XcmpMessageHandler};
6use frame_support::pallet_prelude::*;
7use parity_scale_codec::{Decode, Encode};
8use polkadot_parachain_primitives::primitives::DmpMessageHandler;
9use sp_std::prelude::*;
10use xcm::{
11 v5::{prelude::*, Weight},
12 VersionedXcm,
13};
14
15pub use module::*;
16
17#[frame_support::pallet]
18pub mod module {
19 use super::*;
20
21 type RelayBlockNumber = u32;
22
23 #[pallet::config]
24 pub trait Config: frame_system::Config {
25 type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
26 }
27
28 #[pallet::call]
29 impl<T: Config> Pallet<T> {}
30
31 #[pallet::pallet]
32 #[pallet::without_storage_info]
33 pub struct Pallet<T>(_);
34
35 #[pallet::storage]
36 #[pallet::getter(fn parachain_id)]
37 pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
38
39 #[pallet::storage]
40 #[pallet::getter(fn received_dmp)]
41 pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
43
44 impl<T: Config> Get<ParaId> for Pallet<T> {
45 fn get() -> ParaId {
46 Self::parachain_id()
47 }
48 }
49
50 pub type MessageId = [u8; 32];
51
52 #[pallet::event]
53 #[pallet::generate_deposit(pub(super) fn deposit_event)]
54 pub enum Event<T: Config> {
55 Success(Option<T::Hash>),
58 Fail(Option<T::Hash>, XcmError),
60 BadVersion(Option<T::Hash>),
62 BadFormat(Option<T::Hash>),
64
65 InvalidFormat(MessageId),
68 UnsupportedVersion(MessageId),
70 ExecutedDownward(MessageId, Outcome),
72 }
73
74 impl<T: Config> Pallet<T> {
75 pub fn set_para_id(para_id: ParaId) {
76 ParachainId::<T>::put(para_id);
77 }
78
79 fn handle_xcmp_message(
80 sender: ParaId,
81 _sent_at: RelayBlockNumber,
82 xcm: VersionedXcm<T::RuntimeCall>,
83 max_weight: Weight,
84 ) -> Result<Weight, XcmError> {
85 use sp_runtime::traits::Hash;
86 let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
87 let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
88 let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
89 Ok(xcm) => {
90 let location = (Parent, Parachain(sender.into()));
91 match T::XcmExecutor::prepare_and_execute(
92 location,
93 xcm,
94 &mut message_hash,
95 max_weight,
96 Weight::zero(),
97 ) {
98 Outcome::Error(InstructionError { error, .. }) => (Err(error), Event::Fail(Some(hash), error)),
99 Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
100 Outcome::Incomplete {
103 used,
104 error: InstructionError { error, .. },
105 } => (Ok(used), Event::Fail(Some(hash), error)),
106 }
107 }
108 Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
109 };
110 Self::deposit_event(event);
111 result
112 }
113 }
114
115 impl<T: Config> XcmpMessageHandler for Pallet<T> {
116 fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
117 iter: I,
118 max_weight: Weight,
119 ) -> Weight {
120 for (sender, sent_at, data) in iter {
121 let mut data_ref = data;
122 let _ =
123 XcmpMessageFormat::decode(&mut data_ref).expect("Simulator encodes with versioned xcm format; qed");
124
125 let mut remaining_fragments = data_ref;
126 while !remaining_fragments.is_empty() {
127 if let Ok(xcm) = VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments) {
128 let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
129 } else {
130 debug_assert!(false, "Invalid incoming XCMP message data");
131 }
132 }
133 }
134 max_weight
135 }
136 }
137
138 impl<T: Config> DmpMessageHandler for Pallet<T> {
139 fn handle_dmp_messages(iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>, limit: Weight) -> Weight {
140 for (_sent_at, data) in iter {
141 let mut id = sp_io::hashing::blake2_256(&data[..]);
142 let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
143 match maybe_versioned {
144 Err(_) => {
145 Self::deposit_event(Event::InvalidFormat(id));
146 }
147 Ok(versioned) => match Xcm::try_from(versioned) {
148 Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
149 Ok(x) => {
150 let outcome =
151 T::XcmExecutor::prepare_and_execute(Parent, x.clone(), &mut id, limit, Weight::zero());
152 <ReceivedDmp<T>>::append(x);
153 Self::deposit_event(Event::ExecutedDownward(id, outcome));
154 }
155 },
156 }
157 }
158 limit
159 }
160 }
161}