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