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 RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
26 type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
27 }
28
29 #[pallet::call]
30 impl<T: Config> Pallet<T> {}
31
32 #[pallet::pallet]
33 #[pallet::without_storage_info]
34 pub struct Pallet<T>(_);
35
36 #[pallet::storage]
37 #[pallet::getter(fn parachain_id)]
38 pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
39
40 #[pallet::storage]
41 #[pallet::getter(fn received_dmp)]
42 pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
44
45 impl<T: Config> Get<ParaId> for Pallet<T> {
46 fn get() -> ParaId {
47 Self::parachain_id()
48 }
49 }
50
51 pub type MessageId = [u8; 32];
52
53 #[pallet::event]
54 #[pallet::generate_deposit(pub(super) fn deposit_event)]
55 pub enum Event<T: Config> {
56 Success(Option<T::Hash>),
59 Fail(Option<T::Hash>, XcmError),
61 BadVersion(Option<T::Hash>),
63 BadFormat(Option<T::Hash>),
65
66 InvalidFormat(MessageId),
69 UnsupportedVersion(MessageId),
71 ExecutedDownward(MessageId, Outcome),
73 }
74
75 impl<T: Config> Pallet<T> {
76 pub fn set_para_id(para_id: ParaId) {
77 ParachainId::<T>::put(para_id);
78 }
79
80 fn handle_xcmp_message(
81 sender: ParaId,
82 _sent_at: RelayBlockNumber,
83 xcm: VersionedXcm<T::RuntimeCall>,
84 max_weight: Weight,
85 ) -> Result<Weight, XcmError> {
86 use sp_runtime::traits::Hash;
87 let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
88 let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
89 let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
90 Ok(xcm) => {
91 let location = (Parent, Parachain(sender.into()));
92 match T::XcmExecutor::prepare_and_execute(
93 location,
94 xcm,
95 &mut message_hash,
96 max_weight,
97 Weight::zero(),
98 ) {
99 Outcome::Error { error } => (Err(error), Event::Fail(Some(hash), error)),
100 Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
101 Outcome::Incomplete { used, error } => (Ok(used), Event::Fail(Some(hash), error)),
104 }
105 }
106 Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
107 };
108 Self::deposit_event(event);
109 result
110 }
111 }
112
113 impl<T: Config> XcmpMessageHandler for Pallet<T> {
114 fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
115 iter: I,
116 max_weight: Weight,
117 ) -> Weight {
118 for (sender, sent_at, data) in iter {
119 let mut data_ref = data;
120 let _ =
121 XcmpMessageFormat::decode(&mut data_ref).expect("Simulator encodes with versioned xcm format; qed");
122
123 let mut remaining_fragments = data_ref;
124 while !remaining_fragments.is_empty() {
125 if let Ok(xcm) = VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments) {
126 let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
127 } else {
128 debug_assert!(false, "Invalid incoming XCMP message data");
129 }
130 }
131 }
132 max_weight
133 }
134 }
135
136 impl<T: Config> DmpMessageHandler for Pallet<T> {
137 fn handle_dmp_messages(iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>, limit: Weight) -> Weight {
138 for (_sent_at, data) in iter {
139 let mut id = sp_io::hashing::blake2_256(&data[..]);
140 let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
141 match maybe_versioned {
142 Err(_) => {
143 Self::deposit_event(Event::InvalidFormat(id));
144 }
145 Ok(versioned) => match Xcm::try_from(versioned) {
146 Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
147 Ok(x) => {
148 let outcome =
149 T::XcmExecutor::prepare_and_execute(Parent, x.clone(), &mut id, limit, Weight::zero());
150 <ReceivedDmp<T>>::append(x);
151 Self::deposit_event(Event::ExecutedDownward(id, outcome));
152 }
153 },
154 }
155 }
156 limit
157 }
158 }
159}