1#[cfg(feature = "runtime-benchmarks")]
4pub mod benchmarking_between_domains;
5#[cfg(feature = "runtime-benchmarks")]
6pub mod benchmarking_from_consensus;
7#[cfg(feature = "runtime-benchmarks")]
8pub mod benchmarking_from_domains;
9pub mod weights;
10mod weights_from_consensus;
11mod weights_from_domains;
12
13pub use crate::extensions::weights::{FromConsensusWeightInfo, FromDomainWeightInfo};
14pub use crate::extensions::weights_from_consensus::WeightInfo as WeightsFromConsensus;
15pub use crate::extensions::weights_from_domains::WeightInfo as WeightsFromDomains;
16use crate::pallet::Call as MessengerCall;
17use crate::{
18 Call, Config, ExtensionWeightInfo, Origin, Pallet as Messenger, ValidatedRelayMessage,
19 XDM_TRANSACTION_LONGEVITY,
20};
21use core::cmp::Ordering;
22use frame_support::RuntimeDebugNoBound;
23use frame_support::pallet_prelude::{PhantomData, TypeInfo, Weight};
24use frame_system::pallet_prelude::RuntimeCallFor;
25use parity_scale_codec::{Decode, Encode};
26use scale_info::prelude::fmt;
27use sp_messenger::MAX_FUTURE_ALLOWED_NONCES;
28use sp_messenger::messages::{Message, Nonce, Proof};
29use sp_runtime::DispatchResult;
30use sp_runtime::traits::{
31 AsSystemOriginSigner, DispatchInfoOf, DispatchOriginOf, Dispatchable, Implication,
32 PostDispatchInfoOf, TransactionExtension, ValidateResult,
33};
34use sp_runtime::transaction_validity::{
35 InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction,
36 ValidTransactionBuilder,
37};
38use sp_subspace_mmr::MmrProofVerifier;
39
40pub trait MaybeMessengerCall<Runtime>
42where
43 Runtime: Config,
44{
45 fn maybe_messenger_call(&self) -> Option<&MessengerCall<Runtime>>;
46}
47
48#[derive(RuntimeDebugNoBound)]
50pub enum Val<T: Config + fmt::Debug> {
51 None,
53 ValidatedRelayMessage(ValidatedRelayMessage<T>),
55}
56
57#[derive(RuntimeDebugNoBound)]
59pub enum Pre {
60 Refund(Weight),
61}
62
63#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
65pub struct MessengerExtension<Runtime>(PhantomData<Runtime>);
66
67impl<Runtime> MessengerExtension<Runtime> {
68 pub fn new() -> Self {
69 Self(PhantomData)
70 }
71}
72
73impl<Runtime> Default for MessengerExtension<Runtime> {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl<T: Config> fmt::Debug for MessengerExtension<T> {
80 #[cfg(feature = "std")]
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "MessengerExtension",)
83 }
84
85 #[cfg(not(feature = "std"))]
86 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
87 Ok(())
88 }
89}
90
91impl<Runtime> MessengerExtension<Runtime>
92where
93 Runtime: Config + scale_info::TypeInfo + fmt::Debug + Send + Sync,
94{
95 fn check_future_nonce_and_add_requires(
96 mut valid_tx_builder: ValidTransactionBuilder,
97 validated_relay_message: &ValidatedRelayMessage<Runtime>,
98 ) -> Result<ValidTransactionBuilder, TransactionValidityError> {
99 let Message {
100 dst_chain_id,
101 channel_id,
102 nonce: msg_nonce,
103 ..
104 } = &validated_relay_message.message;
105
106 let next_nonce = validated_relay_message.next_nonce;
107 if *msg_nonce > next_nonce {
109 let max_future_nonce = next_nonce.saturating_add(MAX_FUTURE_ALLOWED_NONCES.into());
110 if *msg_nonce > max_future_nonce {
111 return Err(InvalidTransaction::Custom(
112 crate::verification_errors::IN_FUTURE_NONCE,
113 )
114 .into());
115 }
116
117 valid_tx_builder =
118 valid_tx_builder.and_requires((dst_chain_id, channel_id, msg_nonce - Nonce::one()));
119 };
120
121 Ok(valid_tx_builder)
122 }
123
124 fn do_validate(
125 call: &MessengerCall<Runtime>,
126 ) -> Result<(ValidTransaction, ValidatedRelayMessage<Runtime>), TransactionValidityError> {
127 match call {
128 Call::relay_message { msg: xdm } => {
129 let consensus_state_root =
130 Runtime::MmrProofVerifier::verify_proof_and_extract_leaf(
131 xdm.proof.consensus_mmr_proof(),
132 )
133 .ok_or(InvalidTransaction::BadProof)?
134 .state_root();
135
136 let validated_message =
137 Messenger::<Runtime>::validate_relay_message(xdm, consensus_state_root)?;
138
139 let Message {
140 dst_chain_id,
141 channel_id,
142 nonce: msg_nonce,
143 ..
144 } = &validated_message.message;
145
146 let valid_tx_builder = Self::check_future_nonce_and_add_requires(
147 ValidTransaction::with_tag_prefix("MessengerInbox"),
148 &validated_message,
149 )?;
150
151 let validity = valid_tx_builder
152 .priority(1)
155 .longevity(XDM_TRANSACTION_LONGEVITY)
156 .and_provides((dst_chain_id, channel_id, msg_nonce))
157 .propagate(true)
158 .build()?;
159
160 Ok((validity, validated_message))
161 }
162 Call::relay_message_response { msg: xdm } => {
163 let consensus_state_root =
164 Runtime::MmrProofVerifier::verify_proof_and_extract_leaf(
165 xdm.proof.consensus_mmr_proof(),
166 )
167 .ok_or(InvalidTransaction::BadProof)?
168 .state_root();
169
170 let validated_message = Messenger::<Runtime>::validate_relay_message_response(
171 xdm,
172 consensus_state_root,
173 )?;
174
175 let Message {
176 dst_chain_id,
177 channel_id,
178 nonce: msg_nonce,
179 ..
180 } = &validated_message.message;
181
182 let valid_tx_builder = Self::check_future_nonce_and_add_requires(
183 ValidTransaction::with_tag_prefix("MessengerOutboxResponse"),
184 &validated_message,
185 )?;
186
187 let validity = valid_tx_builder
188 .priority(1)
191 .longevity(XDM_TRANSACTION_LONGEVITY)
192 .and_provides((dst_chain_id, channel_id, msg_nonce))
193 .propagate(true)
194 .build()?;
195
196 Ok((validity, validated_message))
197 }
198 _ => Err(InvalidTransaction::Call.into()),
199 }
200 }
201
202 fn do_prepare(
203 call: &MessengerCall<Runtime>,
204 val: ValidatedRelayMessage<Runtime>,
205 ) -> Result<Pre, TransactionValidityError> {
206 let ValidatedRelayMessage {
207 message,
208 should_init_channel,
209 next_nonce,
210 } = val;
211
212 if message.nonce.cmp(&next_nonce) == Ordering::Greater {
214 return Err(InvalidTransaction::Future.into());
215 }
216
217 let pre = match call {
218 Call::relay_message { msg } => {
219 Messenger::<Runtime>::pre_dispatch_relay_message(message, should_init_channel)?;
220 if should_init_channel {
221 Pre::Refund(Weight::zero())
224 } else {
225 match msg.proof {
226 Proof::Consensus { .. } => Pre::Refund(Self::refund_weight_for_consensus()),
227 Proof::Domain { .. } => Pre::Refund(Self::refund_weight_for_domains()),
228 }
229 }
230 }
231 Call::relay_message_response { .. } => {
232 Messenger::<Runtime>::pre_dispatch_relay_message_response(message)?;
233 Pre::Refund(Weight::zero())
235 }
236 _ => return Err(InvalidTransaction::Call.into()),
237 };
238
239 Ok(pre)
240 }
241
242 fn do_calculate_weight(call: &RuntimeCallFor<Runtime>) -> Weight
243 where
244 RuntimeCallFor<Runtime>: MaybeMessengerCall<Runtime>,
245 Runtime: Config,
246 {
247 let messenger_call = match call.maybe_messenger_call() {
248 Some(messenger_call) => messenger_call,
249 None => return Weight::zero(),
250 };
251
252 let (dst_chain_id, verification_weight) = match messenger_call {
253 Call::relay_message { msg } => (
254 msg.dst_chain_id,
255 match msg.proof {
256 Proof::Consensus { .. } => {
257 Runtime::ExtensionWeightInfo::from_consensus_relay_message().max(
258 Runtime::ExtensionWeightInfo::from_consensus_relay_message_channel_open(
259 ),
260 )
261 }
262 Proof::Domain { .. } => {
263 Runtime::ExtensionWeightInfo::from_domains_relay_message_channel_open()
264 .max(Runtime::ExtensionWeightInfo::from_domains_relay_message())
265 }
266 },
267 ),
268 Call::relay_message_response { msg } => (
269 msg.dst_chain_id,
270 match msg.proof {
271 Proof::Consensus { .. } => {
272 Runtime::ExtensionWeightInfo::from_consensus_relay_message_response()
273 }
274 Proof::Domain { .. } => {
275 Runtime::ExtensionWeightInfo::from_domains_relay_message_response()
276 }
277 },
278 ),
279 _ => return Weight::zero(),
280 };
281
282 let mmr_proof_weight = if dst_chain_id.is_consensus_chain() {
283 Runtime::ExtensionWeightInfo::mmr_proof_verification_on_consensus()
284 } else {
285 Runtime::ExtensionWeightInfo::mmr_proof_verification_on_domain()
286 };
287
288 mmr_proof_weight.saturating_add(verification_weight)
289 }
290
291 fn refund_weight_for_consensus() -> Weight {
292 let min = Runtime::ExtensionWeightInfo::from_consensus_relay_message_channel_open()
293 .min(Runtime::ExtensionWeightInfo::from_consensus_relay_message());
294 let max = Runtime::ExtensionWeightInfo::from_consensus_relay_message_channel_open()
295 .max(Runtime::ExtensionWeightInfo::from_consensus_relay_message());
296 max.saturating_sub(min)
297 }
298
299 fn refund_weight_for_domains() -> Weight {
300 let min = Runtime::ExtensionWeightInfo::from_domains_relay_message_channel_open()
301 .min(Runtime::ExtensionWeightInfo::from_domains_relay_message());
302 let max = Runtime::ExtensionWeightInfo::from_domains_relay_message_channel_open()
303 .max(Runtime::ExtensionWeightInfo::from_domains_relay_message());
304 max.saturating_sub(min)
305 }
306}
307
308impl<Runtime> TransactionExtension<RuntimeCallFor<Runtime>> for MessengerExtension<Runtime>
309where
310 Runtime: Config + scale_info::TypeInfo + fmt::Debug + Send + Sync,
311 <RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
312 AsSystemOriginSigner<<Runtime as frame_system::Config>::AccountId> + From<Origin> + Clone,
313 RuntimeCallFor<Runtime>: MaybeMessengerCall<Runtime>,
314{
315 const IDENTIFIER: &'static str = "MessengerExtension";
316 type Implicit = ();
317 type Val = Val<Runtime>;
318 type Pre = Pre;
319
320 fn weight(&self, call: &RuntimeCallFor<Runtime>) -> Weight {
321 Self::do_calculate_weight(call)
322 }
323
324 fn validate(
325 &self,
326 origin: DispatchOriginOf<RuntimeCallFor<Runtime>>,
327 call: &RuntimeCallFor<Runtime>,
328 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
329 _len: usize,
330 _self_implicit: Self::Implicit,
331 _inherited_implication: &impl Implication,
332 _source: TransactionSource,
333 ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
334 if origin.as_system_origin_signer().is_some() {
336 return Ok((ValidTransaction::default(), Val::None, origin));
337 };
338
339 let messenger_call = match call.maybe_messenger_call() {
340 Some(messenger_call) => messenger_call,
341 None => return Ok((ValidTransaction::default(), Val::None, origin)),
342 };
343
344 let (validity, validated_relay_message) = Self::do_validate(messenger_call)?;
345 Ok((
346 validity,
347 Val::ValidatedRelayMessage(validated_relay_message),
348 Origin::ValidatedUnsigned.into(),
349 ))
350 }
351
352 fn prepare(
353 self,
354 val: Self::Val,
355 _origin: &DispatchOriginOf<RuntimeCallFor<Runtime>>,
356 call: &RuntimeCallFor<Runtime>,
357 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
358 _len: usize,
359 ) -> Result<Self::Pre, TransactionValidityError> {
360 match (call.maybe_messenger_call(), val) {
361 (Some(messenger_call), Val::ValidatedRelayMessage(validated_relay_message)) => {
363 Self::do_prepare(messenger_call, validated_relay_message)
364 }
365 (_, _) => Ok(Pre::Refund(Weight::zero())),
368 }
369 }
370
371 fn post_dispatch_details(
372 pre: Self::Pre,
373 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
374 _post_info: &PostDispatchInfoOf<RuntimeCallFor<Runtime>>,
375 _len: usize,
376 _result: &DispatchResult,
377 ) -> Result<Weight, TransactionValidityError> {
378 let Pre::Refund(weight) = pre;
379 Ok(weight)
380 }
381}
382
383#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
385pub struct MessengerTrustedMmrExtension<Runtime>(PhantomData<Runtime>);
386
387impl<Runtime> MessengerTrustedMmrExtension<Runtime> {
388 pub fn new() -> Self {
389 Self(PhantomData)
390 }
391}
392
393impl<Runtime> Default for MessengerTrustedMmrExtension<Runtime> {
394 fn default() -> Self {
395 Self::new()
396 }
397}
398
399impl<T: Config> fmt::Debug for MessengerTrustedMmrExtension<T> {
400 #[cfg(feature = "std")]
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 write!(f, "MessengerTrustedMmrExtension",)
403 }
404
405 #[cfg(not(feature = "std"))]
406 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
407 Ok(())
408 }
409}
410
411impl<Runtime> MessengerTrustedMmrExtension<Runtime>
412where
413 Runtime: Config + scale_info::TypeInfo + fmt::Debug + Send + Sync,
414{
415 fn do_validate(
416 call: &MessengerCall<Runtime>,
417 ) -> Result<(ValidTransaction, ValidatedRelayMessage<Runtime>), TransactionValidityError> {
418 match call {
419 Call::relay_message { msg: xdm } => {
420 let consensus_state_root =
421 Runtime::MmrProofVerifier::extract_leaf_without_verifying(
422 xdm.proof.consensus_mmr_proof(),
423 )
424 .ok_or(InvalidTransaction::BadProof)?
425 .state_root();
426
427 let validated_relay_message =
428 Messenger::<Runtime>::validate_relay_message(xdm, consensus_state_root)?;
429
430 Ok((ValidTransaction::default(), validated_relay_message))
431 }
432 Call::relay_message_response { msg: xdm } => {
433 let consensus_state_root =
434 Runtime::MmrProofVerifier::extract_leaf_without_verifying(
435 xdm.proof.consensus_mmr_proof(),
436 )
437 .ok_or(InvalidTransaction::BadProof)?
438 .state_root();
439
440 let validated_relay_message =
441 Messenger::<Runtime>::validate_relay_message_response(
442 xdm,
443 consensus_state_root,
444 )?;
445
446 Ok((ValidTransaction::default(), validated_relay_message))
447 }
448 _ => Err(InvalidTransaction::Call.into()),
449 }
450 }
451}
452
453impl<Runtime> TransactionExtension<RuntimeCallFor<Runtime>>
454 for MessengerTrustedMmrExtension<Runtime>
455where
456 Runtime: Config + scale_info::TypeInfo + fmt::Debug + Send + Sync,
457 <RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
458 AsSystemOriginSigner<<Runtime as frame_system::Config>::AccountId> + From<Origin> + Clone,
459 RuntimeCallFor<Runtime>: MaybeMessengerCall<Runtime>,
460{
461 const IDENTIFIER: &'static str = "MessengerTrustedMmrExtension";
462 type Implicit = ();
463 type Val = Val<Runtime>;
464 type Pre = Pre;
465
466 fn weight(&self, call: &RuntimeCallFor<Runtime>) -> Weight {
467 MessengerExtension::<Runtime>::do_calculate_weight(call)
468 }
469
470 fn validate(
471 &self,
472 origin: DispatchOriginOf<RuntimeCallFor<Runtime>>,
473 call: &RuntimeCallFor<Runtime>,
474 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
475 _len: usize,
476 _self_implicit: Self::Implicit,
477 _inherited_implication: &impl Implication,
478 _source: TransactionSource,
479 ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
480 if origin.as_system_origin_signer().is_some() {
482 return Ok((ValidTransaction::default(), Val::None, origin));
483 };
484
485 let messenger_call = match call.maybe_messenger_call() {
486 Some(messenger_call) => messenger_call,
487 None => return Ok((ValidTransaction::default(), Val::None, origin)),
488 };
489
490 let (validity, validated_relay_message) = Self::do_validate(messenger_call)?;
491 Ok((
492 validity,
493 Val::ValidatedRelayMessage(validated_relay_message),
494 Origin::ValidatedUnsigned.into(),
495 ))
496 }
497
498 fn prepare(
499 self,
500 val: Self::Val,
501 _origin: &DispatchOriginOf<RuntimeCallFor<Runtime>>,
502 call: &RuntimeCallFor<Runtime>,
503 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
504 _len: usize,
505 ) -> Result<Self::Pre, TransactionValidityError> {
506 match (call.maybe_messenger_call(), val) {
507 (Some(messenger_call), Val::ValidatedRelayMessage(validated_relay_message)) => {
509 MessengerExtension::<Runtime>::do_prepare(messenger_call, validated_relay_message)
510 }
511 (_, _) => Ok(Pre::Refund(Weight::zero())),
513 }
514 }
515
516 fn post_dispatch_details(
517 pre: Self::Pre,
518 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
519 _post_info: &PostDispatchInfoOf<RuntimeCallFor<Runtime>>,
520 _len: usize,
521 _result: &DispatchResult,
522 ) -> Result<Weight, TransactionValidityError> {
523 let Pre::Refund(weight) = pre;
524 Ok(weight)
525 }
526}