xcm_simulator/
mock_message_queue.rs1use codec::{Decode, Encode};
20
21use polkadot_parachain_primitives::primitives::{
22 DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler,
23};
24use polkadot_primitives::BlockNumber as RelayBlockNumber;
25use sp_runtime::traits::{Get, Hash};
26
27use xcm::{latest::prelude::*, VersionedXcm};
28
29pub use pallet::*;
30
31#[frame_support::pallet]
32pub mod pallet {
33 use super::*;
34 use frame_support::pallet_prelude::*;
35
36 #[pallet::config]
37 pub trait Config: frame_system::Config<RuntimeCall: Decode> {
38 #[allow(deprecated)]
39 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
40 type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
41 }
42
43 #[pallet::call]
44 impl<T: Config> Pallet<T> {}
45
46 #[pallet::pallet]
47 #[pallet::without_storage_info]
48 pub struct Pallet<T>(_);
49
50 #[pallet::storage]
51 pub type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
52
53 #[pallet::storage]
54 pub type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
56
57 impl<T: Config> Get<ParaId> for Pallet<T> {
58 fn get() -> ParaId {
59 ParachainId::<T>::get()
60 }
61 }
62
63 pub type MessageId = [u8; 32];
64
65 #[pallet::event]
66 #[pallet::generate_deposit(pub(super) fn deposit_event)]
67 pub enum Event<T: Config> {
68 Success { message_id: Option<T::Hash> },
71 Fail { message_id: Option<T::Hash>, error: XcmError },
73 BadVersion { message_id: Option<T::Hash> },
75 BadFormat { message_id: Option<T::Hash> },
77
78 InvalidFormat { message_id: MessageId },
81 UnsupportedVersion { message_id: MessageId },
83 ExecutedDownward { message_id: MessageId, outcome: Outcome },
85 }
86
87 impl<T: Config> Pallet<T> {
88 pub fn set_para_id(para_id: ParaId) {
89 ParachainId::<T>::put(para_id);
90 }
91
92 fn handle_xcmp_message(
93 sender: ParaId,
94 _sent_at: RelayBlockNumber,
95 xcm: VersionedXcm<T::RuntimeCall>,
96 max_weight: xcm::latest::Weight,
97 ) -> Result<xcm::latest::Weight, XcmError> {
98 let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
99 let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
100 let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
101 Ok(xcm) => {
102 let location = (Parent, Parachain(sender.into()));
103 match T::XcmExecutor::prepare_and_execute(
104 location,
105 xcm,
106 &mut message_hash,
107 max_weight,
108 Weight::zero(),
109 ) {
110 Outcome::Error(InstructionError { error, .. }) => {
111 (Err(error), Event::Fail { message_id: Some(hash), error })
112 },
113 Outcome::Complete { used } => {
114 (Ok(used), Event::Success { message_id: Some(hash) })
115 },
116 Outcome::Incomplete {
119 used, error: InstructionError { error, .. }, ..
120 } => (Ok(used), Event::Fail { message_id: Some(hash), error }),
121 }
122 },
123 Err(()) => (
124 Err(XcmError::UnhandledXcmVersion),
125 Event::BadVersion { message_id: Some(hash) },
126 ),
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: xcm::latest::Weight,
137 ) -> (usize, Weight) {
138 let mut num_processed_pages = 0;
139 for (sender, sent_at, data) in iter {
140 num_processed_pages += 1;
141 let mut data_ref = data;
142 let _ = XcmpMessageFormat::decode(&mut data_ref)
143 .expect("Simulator encodes with versioned xcm format; qed");
144
145 let mut remaining_fragments = data_ref;
146 while !remaining_fragments.is_empty() {
147 if let Ok(xcm) =
148 VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
149 {
150 let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
151 } else {
152 debug_assert!(false, "Invalid incoming XCMP message data");
153 }
154 }
155 }
156 (num_processed_pages, max_weight)
157 }
158 }
159
160 impl<T: Config> DmpMessageHandler for Pallet<T> {
161 fn handle_dmp_messages(
162 iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
163 limit: Weight,
164 ) -> Weight {
165 for (_sent_at, data) in iter {
166 let mut id = sp_io::hashing::blake2_256(&data[..]);
167 let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
168 match maybe_versioned {
169 Err(_) => {
170 Self::deposit_event(Event::InvalidFormat { message_id: id });
171 },
172 Ok(versioned) => match Xcm::try_from(versioned) {
173 Err(()) => {
174 Self::deposit_event(Event::UnsupportedVersion { message_id: id })
175 },
176 Ok(x) => {
177 let outcome = T::XcmExecutor::prepare_and_execute(
178 Parent,
179 x.clone(),
180 &mut id,
181 limit,
182 Weight::zero(),
183 );
184 ReceivedDmp::<T>::append(x);
185 Self::deposit_event(Event::ExecutedDownward {
186 message_id: id,
187 outcome,
188 });
189 },
190 },
191 }
192 }
193 limit
194 }
195 }
196}