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 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 type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
51
52 #[pallet::storage]
53 pub 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 Success { message_id: Option<T::Hash> },
70 Fail { message_id: Option<T::Hash>, error: XcmError },
72 BadVersion { message_id: Option<T::Hash> },
74 BadFormat { message_id: Option<T::Hash> },
76
77 InvalidFormat { message_id: MessageId },
80 UnsupportedVersion { message_id: MessageId },
82 ExecutedDownward { message_id: MessageId, outcome: Outcome },
84 }
85
86 impl<T: Config> Pallet<T> {
87 pub fn set_para_id(para_id: ParaId) {
88 ParachainId::<T>::put(para_id);
89 }
90
91 fn handle_xcmp_message(
92 sender: ParaId,
93 _sent_at: RelayBlockNumber,
94 xcm: VersionedXcm<T::RuntimeCall>,
95 max_weight: xcm::latest::Weight,
96 ) -> Result<xcm::latest::Weight, XcmError> {
97 let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
98 let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
99 let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
100 Ok(xcm) => {
101 let location = (Parent, Parachain(sender.into()));
102 match T::XcmExecutor::prepare_and_execute(
103 location,
104 xcm,
105 &mut message_hash,
106 max_weight,
107 Weight::zero(),
108 ) {
109 Outcome::Error { error } =>
110 (Err(error), Event::Fail { message_id: Some(hash), error }),
111 Outcome::Complete { used } =>
112 (Ok(used), Event::Success { message_id: Some(hash) }),
113 Outcome::Incomplete { used, error } =>
116 (Ok(used), Event::Fail { message_id: Some(hash), error }),
117 }
118 },
119 Err(()) => (
120 Err(XcmError::UnhandledXcmVersion),
121 Event::BadVersion { message_id: Some(hash) },
122 ),
123 };
124 Self::deposit_event(event);
125 result
126 }
127 }
128
129 impl<T: Config> XcmpMessageHandler for Pallet<T> {
130 fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
131 iter: I,
132 max_weight: xcm::latest::Weight,
133 ) -> xcm::latest::Weight {
134 for (sender, sent_at, data) in iter {
135 let mut data_ref = data;
136 let _ = XcmpMessageFormat::decode(&mut data_ref)
137 .expect("Simulator encodes with versioned xcm format; qed");
138
139 let mut remaining_fragments = data_ref;
140 while !remaining_fragments.is_empty() {
141 if let Ok(xcm) =
142 VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
143 {
144 let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
145 } else {
146 debug_assert!(false, "Invalid incoming XCMP message data");
147 }
148 }
149 }
150 max_weight
151 }
152 }
153
154 impl<T: Config> DmpMessageHandler for Pallet<T> {
155 fn handle_dmp_messages(
156 iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
157 limit: Weight,
158 ) -> Weight {
159 for (_sent_at, data) in iter {
160 let mut id = sp_io::hashing::blake2_256(&data[..]);
161 let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
162 match maybe_versioned {
163 Err(_) => {
164 Self::deposit_event(Event::InvalidFormat { message_id: id });
165 },
166 Ok(versioned) => match Xcm::try_from(versioned) {
167 Err(()) =>
168 Self::deposit_event(Event::UnsupportedVersion { message_id: id }),
169 Ok(x) => {
170 let outcome = T::XcmExecutor::prepare_and_execute(
171 Parent,
172 x.clone(),
173 &mut id,
174 limit,
175 Weight::zero(),
176 );
177 ReceivedDmp::<T>::append(x);
178 Self::deposit_event(Event::ExecutedDownward {
179 message_id: id,
180 outcome,
181 });
182 },
183 },
184 }
185 }
186 limit
187 }
188 }
189}