1use crate::{
20 messages::{
21 source::{SubstrateMessagesProof, SubstrateMessagesSource},
22 target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget},
23 },
24 on_demand::OnDemandRelay,
25 BatchCallBuilder, BatchCallBuilderConstructor, TransactionParams,
26};
27
28use async_std::sync::Arc;
29use bp_messages::{
30 target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, MessageNonce,
31};
32use bp_runtime::{AccountIdOf, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps};
33use codec::{Codec, Encode, EncodeLike};
34use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
35use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction, Labeled};
36use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig};
37use relay_substrate_client::{
38 transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain,
39 ChainBase, ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf,
40 SignParam, UnsignedTransaction,
41};
42use relay_utils::{
43 metrics::{GlobalMetrics, MetricsParams, StandaloneMetric},
44 STALL_TIMEOUT,
45};
46use sp_core::Pair;
47use sp_runtime::traits::Zero;
48use std::{fmt::Debug, marker::PhantomData, ops::RangeInclusive};
49
50pub mod metrics;
51pub mod source;
52pub mod target;
53
54pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync {
56 type SourceChain: ChainWithMessages + ChainWithTransactions;
58 type TargetChain: ChainWithMessages + ChainWithTransactions;
60
61 type LaneId: Clone
63 + Copy
64 + Debug
65 + Codec
66 + EncodeLike
67 + Send
68 + Sync
69 + Labeled
70 + TryFrom<Vec<u8>>
71 + Default;
72
73 type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder<Self>;
75 type ReceiveMessagesDeliveryProofCallBuilder: ReceiveMessagesDeliveryProofCallBuilder<Self>;
77
78 type SourceBatchCallBuilder: BatchCallBuilderConstructor<CallOf<Self::SourceChain>>;
80 type TargetBatchCallBuilder: BatchCallBuilderConstructor<CallOf<Self::TargetChain>>;
82}
83
84#[derive(Clone, Debug)]
86pub struct MessageLaneAdapter<P: SubstrateMessageLane> {
87 _phantom: PhantomData<P>,
88}
89
90impl<P: SubstrateMessageLane> MessageLane for MessageLaneAdapter<P> {
91 const SOURCE_NAME: &'static str = P::SourceChain::NAME;
92 const TARGET_NAME: &'static str = P::TargetChain::NAME;
93
94 type LaneId = P::LaneId;
95
96 type MessagesProof = SubstrateMessagesProof<P::SourceChain, P::LaneId>;
97 type MessagesReceivingProof = SubstrateMessagesDeliveryProof<P::TargetChain, P::LaneId>;
98
99 type SourceChainBalance = BalanceOf<P::SourceChain>;
100 type SourceHeaderNumber = BlockNumberOf<P::SourceChain>;
101 type SourceHeaderHash = HashOf<P::SourceChain>;
102
103 type TargetHeaderNumber = BlockNumberOf<P::TargetChain>;
104 type TargetHeaderHash = HashOf<P::TargetChain>;
105}
106
107pub struct MessagesRelayParams<P: SubstrateMessageLane, SourceClnt, TargetClnt> {
109 pub source_client: SourceClnt,
111 pub source_transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
113 pub target_client: TargetClnt,
115 pub target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
117 pub source_to_target_headers_relay:
119 Option<Arc<dyn OnDemandRelay<P::SourceChain, P::TargetChain>>>,
120 pub target_to_source_headers_relay:
122 Option<Arc<dyn OnDemandRelay<P::TargetChain, P::SourceChain>>>,
123 pub lane_id: P::LaneId,
125 pub limits: Option<MessagesRelayLimits>,
128 pub metrics_params: MetricsParams,
130}
131
132pub struct MessagesRelayLimits {
134 pub max_messages_in_single_batch: MessageNonce,
136 pub max_messages_weight_in_single_batch: Weight,
138}
139
140#[derive(Clone)]
143pub struct BatchProofTransaction<SC: Chain, TC: Chain, B: BatchCallBuilderConstructor<CallOf<SC>>> {
144 builder: B::CallBuilder,
145 proved_header: HeaderIdOf<TC>,
146 prove_calls: Vec<CallOf<SC>>,
147
148 _phantom: PhantomData<fn() -> B>,
150}
151
152impl<SC: Chain, TC: Chain, B: BatchCallBuilderConstructor<CallOf<SC>>> std::fmt::Debug
153 for BatchProofTransaction<SC, TC, B>
154{
155 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
156 fmt.debug_struct("BatchProofTransaction")
157 .field("proved_header", &self.proved_header)
158 .finish()
159 }
160}
161
162impl<SC: Chain, TC: Chain, B: BatchCallBuilderConstructor<CallOf<SC>>>
163 BatchProofTransaction<SC, TC, B>
164{
165 pub async fn new(
167 relay: Arc<dyn OnDemandRelay<TC, SC>>,
168 block_num: BlockNumberOf<TC>,
169 ) -> Result<Option<Self>, SubstrateError> {
170 if let Some(builder) = B::new_builder() {
171 let (proved_header, prove_calls) = relay.prove_header(block_num).await?;
172 return Ok(Some(Self {
173 builder,
174 proved_header,
175 prove_calls,
176 _phantom: Default::default(),
177 }))
178 }
179
180 Ok(None)
181 }
182
183 pub fn append_call_and_build(mut self, call: CallOf<SC>) -> CallOf<SC> {
185 self.prove_calls.push(call);
186 self.builder.build_batch_call(self.prove_calls)
187 }
188}
189
190impl<SC: Chain, TC: Chain, B: BatchCallBuilderConstructor<CallOf<SC>>>
191 BatchTransaction<HeaderIdOf<TC>> for BatchProofTransaction<SC, TC, B>
192{
193 fn required_header_id(&self) -> HeaderIdOf<TC> {
194 self.proved_header
195 }
196}
197
198pub async fn run<P, SourceClnt, TargetClnt>(
200 params: MessagesRelayParams<P, SourceClnt, TargetClnt>,
201) -> anyhow::Result<()>
202where
203 P: SubstrateMessageLane,
204 SourceClnt: Client<P::SourceChain>,
205 TargetClnt: Client<P::TargetChain>,
206 AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
207 AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>,
208 BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
209{
210 let max_messages_size_in_single_batch = P::TargetChain::max_extrinsic_size() / 3;
212 let limits = match params.limits {
213 Some(limits) => limits,
214 None =>
215 select_delivery_transaction_limits_rpc(
216 ¶ms,
217 P::TargetChain::max_extrinsic_weight(),
218 P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
219 )
220 .await?,
221 };
222 let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
223 (limits.max_messages_in_single_batch / 2, limits.max_messages_weight_in_single_batch / 2);
224
225 let source_client = params.source_client;
226 let target_client = params.target_client;
227 let relayer_id_at_source: AccountIdOf<P::SourceChain> =
228 params.source_transaction_params.signer.public().into();
229
230 log::info!(
231 target: "bridge",
232 "Starting {} -> {} messages relay.\n\t\
233 {} relayer account id: {:?}\n\t\
234 Max messages in single transaction: {}\n\t\
235 Max messages size in single transaction: {}\n\t\
236 Max messages weight in single transaction: {}\n\t\
237 Tx mortality: {:?} (~{}m)/{:?} (~{}m)",
238 P::SourceChain::NAME,
239 P::TargetChain::NAME,
240 P::SourceChain::NAME,
241 relayer_id_at_source,
242 max_messages_in_single_batch,
243 max_messages_size_in_single_batch,
244 max_messages_weight_in_single_batch,
245 params.source_transaction_params.mortality,
246 transaction_stall_timeout(
247 params.source_transaction_params.mortality,
248 P::SourceChain::AVERAGE_BLOCK_INTERVAL,
249 STALL_TIMEOUT,
250 ).as_secs_f64() / 60.0f64,
251 params.target_transaction_params.mortality,
252 transaction_stall_timeout(
253 params.target_transaction_params.mortality,
254 P::TargetChain::AVERAGE_BLOCK_INTERVAL,
255 STALL_TIMEOUT,
256 ).as_secs_f64() / 60.0f64,
257 );
258
259 messages_relay::message_lane_loop::run(
260 messages_relay::message_lane_loop::Params {
261 lane: params.lane_id,
262 source_tick: P::SourceChain::AVERAGE_BLOCK_INTERVAL,
263 target_tick: P::TargetChain::AVERAGE_BLOCK_INTERVAL,
264 reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
265 delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
266 max_unrewarded_relayer_entries_at_target:
267 P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
268 max_unconfirmed_nonces_at_target:
269 P::SourceChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
270 max_messages_in_single_batch,
271 max_messages_weight_in_single_batch,
272 max_messages_size_in_single_batch,
273 },
274 },
275 SubstrateMessagesSource::<P, _, _>::new(
276 source_client.clone(),
277 target_client.clone(),
278 params.lane_id,
279 params.source_transaction_params,
280 params.target_to_source_headers_relay,
281 ),
282 SubstrateMessagesTarget::<P, _, _>::new(
283 target_client,
284 source_client,
285 params.lane_id,
286 relayer_id_at_source,
287 Some(params.target_transaction_params),
288 params.source_to_target_headers_relay,
289 ),
290 {
291 GlobalMetrics::new()?.register_and_spawn(¶ms.metrics_params.registry)?;
292 params.metrics_params
293 },
294 futures::future::pending(),
295 )
296 .await
297 .map_err(Into::into)
298}
299
300pub async fn relay_messages_range<P: SubstrateMessageLane>(
303 source_client: impl Client<P::SourceChain>,
304 target_client: impl Client<P::TargetChain>,
305 source_transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
306 target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
307 at_source_block: HeaderIdOf<P::SourceChain>,
308 lane_id: P::LaneId,
309 range: RangeInclusive<MessageNonce>,
310 outbound_state_proof_required: bool,
311) -> anyhow::Result<()>
312where
313 AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
314 AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>,
315 BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
316{
317 let relayer_id_at_source: AccountIdOf<P::SourceChain> =
318 source_transaction_params.signer.public().into();
319 messages_relay::relay_messages_range(
320 SubstrateMessagesSource::<P, _, _>::new(
321 source_client.clone(),
322 target_client.clone(),
323 lane_id,
324 source_transaction_params,
325 None,
326 ),
327 SubstrateMessagesTarget::<P, _, _>::new(
328 target_client,
329 source_client,
330 lane_id,
331 relayer_id_at_source,
332 Some(target_transaction_params),
333 None,
334 ),
335 at_source_block,
336 range,
337 outbound_state_proof_required,
338 )
339 .await
340 .map_err(|_| anyhow::format_err!("The command has failed"))
341}
342
343pub async fn relay_messages_delivery_confirmation<P: SubstrateMessageLane>(
346 source_client: impl Client<P::SourceChain>,
347 target_client: impl Client<P::TargetChain>,
348 source_transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
349 at_target_block: HeaderIdOf<P::TargetChain>,
350 lane_id: P::LaneId,
351) -> anyhow::Result<()>
352where
353 AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
354 AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>,
355 BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
356{
357 let relayer_id_at_source: AccountIdOf<P::SourceChain> =
358 source_transaction_params.signer.public().into();
359 messages_relay::relay_messages_delivery_confirmation(
360 SubstrateMessagesSource::<P, _, _>::new(
361 source_client.clone(),
362 target_client.clone(),
363 lane_id,
364 source_transaction_params,
365 None,
366 ),
367 SubstrateMessagesTarget::<P, _, _>::new(
368 target_client,
369 source_client,
370 lane_id,
371 relayer_id_at_source,
372 None,
373 None,
374 ),
375 at_target_block,
376 )
377 .await
378 .map_err(|_| anyhow::format_err!("The command has failed"))
379}
380
381pub trait ReceiveMessagesProofCallBuilder<P: SubstrateMessageLane> {
383 fn build_receive_messages_proof_call(
386 relayer_id_at_source: AccountIdOf<P::SourceChain>,
387 proof: SubstrateMessagesProof<P::SourceChain, P::LaneId>,
388 messages_count: u32,
389 dispatch_weight: Weight,
390 trace_call: bool,
391 ) -> CallOf<P::TargetChain>;
392}
393
394pub struct DirectReceiveMessagesProofCallBuilder<P, R, I> {
397 _phantom: PhantomData<(P, R, I)>,
398}
399
400impl<P, R, I> ReceiveMessagesProofCallBuilder<P> for DirectReceiveMessagesProofCallBuilder<P, R, I>
401where
402 P: SubstrateMessageLane,
403 R: BridgeMessagesConfig<I, LaneId = P::LaneId>,
404 I: 'static,
405 R::BridgedChain:
406 bp_runtime::Chain<AccountId = AccountIdOf<P::SourceChain>, Hash = HashOf<P::SourceChain>>,
407 CallOf<P::TargetChain>: From<BridgeMessagesCall<R, I>> + GetDispatchInfo,
408{
409 fn build_receive_messages_proof_call(
410 relayer_id_at_source: AccountIdOf<P::SourceChain>,
411 proof: SubstrateMessagesProof<P::SourceChain, P::LaneId>,
412 messages_count: u32,
413 dispatch_weight: Weight,
414 trace_call: bool,
415 ) -> CallOf<P::TargetChain> {
416 let call: CallOf<P::TargetChain> = BridgeMessagesCall::<R, I>::receive_messages_proof {
417 relayer_id_at_bridged_chain: relayer_id_at_source,
418 proof: proof.1.into(),
419 messages_count,
420 dispatch_weight,
421 }
422 .into();
423 if trace_call {
424 log::trace!(
427 target: "bridge",
428 "Prepared {} -> {} messages delivery call. Weight: {}/{}, size: {}/{}",
429 P::SourceChain::NAME,
430 P::TargetChain::NAME,
431 call.get_dispatch_info().call_weight,
432 P::TargetChain::max_extrinsic_weight(),
433 call.encode().len(),
434 P::TargetChain::max_extrinsic_size(),
435 );
436 }
437 call
438 }
439}
440
441#[rustfmt::skip]
446#[macro_export]
447macro_rules! generate_receive_message_proof_call_builder {
448 ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_proof:path) => {
449 pub struct $mocked_builder;
450
451 impl $crate::messages::ReceiveMessagesProofCallBuilder<$pipeline>
452 for $mocked_builder
453 {
454 fn build_receive_messages_proof_call(
455 relayer_id_at_source: relay_substrate_client::AccountIdOf<
456 <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain
457 >,
458 proof: $crate::messages::source::SubstrateMessagesProof<
459 <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain,
460 <$pipeline as $crate::messages::SubstrateMessageLane>::LaneId
461 >,
462 messages_count: u32,
463 dispatch_weight: bp_messages::Weight,
464 _trace_call: bool,
465 ) -> relay_substrate_client::CallOf<
466 <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain
467 > {
468 bp_runtime::paste::item! {
469 $bridge_messages($receive_messages_proof {
470 relayer_id_at_bridged_chain: relayer_id_at_source,
471 proof: proof.1.into(),
472 messages_count: messages_count,
473 dispatch_weight: dispatch_weight,
474 })
475 }
476 }
477 }
478 };
479}
480
481pub trait ReceiveMessagesDeliveryProofCallBuilder<P: SubstrateMessageLane> {
483 fn build_receive_messages_delivery_proof_call(
486 proof: SubstrateMessagesDeliveryProof<P::TargetChain, P::LaneId>,
487 trace_call: bool,
488 ) -> CallOf<P::SourceChain>;
489}
490
491pub struct DirectReceiveMessagesDeliveryProofCallBuilder<P, R, I> {
494 _phantom: PhantomData<(P, R, I)>,
495}
496
497impl<P, R, I> ReceiveMessagesDeliveryProofCallBuilder<P>
498 for DirectReceiveMessagesDeliveryProofCallBuilder<P, R, I>
499where
500 P: SubstrateMessageLane,
501 R: BridgeMessagesConfig<I, LaneId = P::LaneId>,
502 I: 'static,
503 R::BridgedChain: bp_runtime::Chain<Hash = HashOf<P::TargetChain>>,
504 CallOf<P::SourceChain>: From<BridgeMessagesCall<R, I>> + GetDispatchInfo,
505{
506 fn build_receive_messages_delivery_proof_call(
507 proof: SubstrateMessagesDeliveryProof<P::TargetChain, P::LaneId>,
508 trace_call: bool,
509 ) -> CallOf<P::SourceChain> {
510 let call: CallOf<P::SourceChain> =
511 BridgeMessagesCall::<R, I>::receive_messages_delivery_proof {
512 proof: proof.1.into(),
513 relayers_state: proof.0,
514 }
515 .into();
516 if trace_call {
517 log::trace!(
520 target: "bridge",
521 "Prepared {} -> {} delivery confirmation transaction. Weight: {}/{}, size: {}/{}",
522 P::TargetChain::NAME,
523 P::SourceChain::NAME,
524 call.get_dispatch_info().call_weight,
525 P::SourceChain::max_extrinsic_weight(),
526 call.encode().len(),
527 P::SourceChain::max_extrinsic_size(),
528 );
529 }
530 call
531 }
532}
533
534#[rustfmt::skip]
539#[macro_export]
540macro_rules! generate_receive_message_delivery_proof_call_builder {
541 ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_delivery_proof:path) => {
542 pub struct $mocked_builder;
543
544 impl $crate::messages::ReceiveMessagesDeliveryProofCallBuilder<$pipeline>
545 for $mocked_builder
546 {
547 fn build_receive_messages_delivery_proof_call(
548 proof: $crate::messages::target::SubstrateMessagesDeliveryProof<
549 <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain,
550 <$pipeline as $crate::messages::SubstrateMessageLane>::LaneId
551 >,
552 _trace_call: bool,
553 ) -> relay_substrate_client::CallOf<
554 <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain
555 > {
556 bp_runtime::paste::item! {
557 $bridge_messages($receive_messages_delivery_proof {
558 proof: proof.1,
559 relayers_state: proof.0
560 })
561 }
562 }
563 }
564 };
565}
566
567async fn select_delivery_transaction_limits_rpc<P, SourceClnt, TargetClnt>(
569 params: &MessagesRelayParams<P, SourceClnt, TargetClnt>,
570 max_extrinsic_weight: Weight,
571 max_unconfirmed_messages_at_inbound_lane: MessageNonce,
572) -> anyhow::Result<MessagesRelayLimits>
573where
574 P: SubstrateMessageLane,
575 SourceClnt: Client<P::SourceChain>,
576 TargetClnt: Client<P::TargetChain>,
577 AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
578{
579 let weight_for_delivery_tx = max_extrinsic_weight / 3;
589 let weight_for_messages_dispatch = max_extrinsic_weight - weight_for_delivery_tx;
590
591 let best_target_block_hash = params.target_client.best_header_hash().await?;
593 let delivery_tx_with_zero_messages = dummy_messages_delivery_transaction::<P, _, _>(params, 0)?;
594 let delivery_tx_with_zero_messages_weight = params
595 .target_client
596 .estimate_extrinsic_weight(best_target_block_hash, delivery_tx_with_zero_messages)
597 .await
598 .map_err(|e| {
599 anyhow::format_err!("Failed to estimate delivery extrinsic weight: {:?}", e)
600 })?;
601
602 let delivery_tx_with_one_message = dummy_messages_delivery_transaction::<P, _, _>(params, 1)?;
604 let delivery_tx_with_one_message_weight = params
605 .target_client
606 .estimate_extrinsic_weight(best_target_block_hash, delivery_tx_with_one_message)
607 .await
608 .map_err(|e| {
609 anyhow::format_err!("Failed to estimate delivery extrinsic weight: {:?}", e)
610 })?;
611
612 let delivery_tx_weight_rest = weight_for_delivery_tx - delivery_tx_with_zero_messages_weight;
615 let delivery_tx_message_overhead =
616 delivery_tx_with_one_message_weight.saturating_sub(delivery_tx_with_zero_messages_weight);
617
618 let max_number_of_messages = std::cmp::min(
619 delivery_tx_weight_rest
620 .min_components_checked_div(delivery_tx_message_overhead)
621 .unwrap_or(u64::MAX),
622 max_unconfirmed_messages_at_inbound_lane,
623 );
624
625 assert!(
626 max_number_of_messages > 0,
627 "Relay should fit at least one message in every delivery transaction",
628 );
629 assert!(
630 weight_for_messages_dispatch.ref_time() >= max_extrinsic_weight.ref_time() / 2,
631 "Relay shall be able to deliver messages with dispatch weight = max_extrinsic_weight / 2",
632 );
633
634 Ok(MessagesRelayLimits {
635 max_messages_in_single_batch: max_number_of_messages,
636 max_messages_weight_in_single_batch: weight_for_messages_dispatch,
637 })
638}
639
640fn dummy_messages_delivery_transaction<P: SubstrateMessageLane, SourceClnt, TargetClnt>(
642 params: &MessagesRelayParams<P, SourceClnt, TargetClnt>,
643 messages: u32,
644) -> anyhow::Result<<P::TargetChain as ChainWithTransactions>::SignedTransaction>
645where
646 AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
647{
648 let dummy_messages_delivery_call =
654 P::ReceiveMessagesProofCallBuilder::build_receive_messages_proof_call(
655 params.source_transaction_params.signer.public().into(),
656 (
657 Weight::zero(),
658 FromBridgedChainMessagesProof {
659 bridged_header_hash: Default::default(),
660 storage_proof: Default::default(),
661 lane: P::LaneId::default(),
662 nonces_start: 1,
663 nonces_end: messages as u64,
664 },
665 ),
666 messages,
667 Weight::zero(),
668 false,
669 );
670 P::TargetChain::sign_transaction(
671 SignParam {
672 spec_version: 0,
673 transaction_version: 0,
674 genesis_hash: Default::default(),
675 signer: params.target_transaction_params.signer.clone(),
676 },
677 UnsignedTransaction {
678 call: EncodedOrDecodedCall::Decoded(dummy_messages_delivery_call),
679 nonce: Zero::zero(),
680 tip: Zero::zero(),
681 era: TransactionEra::Immortal,
682 },
683 )
684 .map_err(Into::into)
685}
686
687#[cfg(test)]
688mod tests {
689 use super::*;
690 use bp_messages::{
691 source_chain::FromBridgedChainMessagesDeliveryProof, LaneIdType, UnrewardedRelayersState,
692 };
693 use relay_substrate_client::calls::{UtilityCall as MockUtilityCall, UtilityCall};
694
695 #[derive(codec::Decode, codec::Encode, Clone, Debug, PartialEq)]
696 pub enum RuntimeCall {
697 #[codec(index = 53)]
698 BridgeMessages(CodegenBridgeMessagesCall),
699 #[codec(index = 123)]
700 Utility(UtilityCall<RuntimeCall>),
701 }
702 pub type CodegenBridgeMessagesCall = bp_messages::BridgeMessagesCall<
703 u64,
704 Box<FromBridgedChainMessagesProof<mock::BridgedHeaderHash, mock::TestLaneIdType>>,
705 FromBridgedChainMessagesDeliveryProof<mock::BridgedHeaderHash, mock::TestLaneIdType>,
706 >;
707
708 impl From<MockUtilityCall<RuntimeCall>> for RuntimeCall {
709 fn from(value: MockUtilityCall<RuntimeCall>) -> RuntimeCall {
710 match value {
711 MockUtilityCall::batch_all(calls) =>
712 RuntimeCall::Utility(UtilityCall::<RuntimeCall>::batch_all(calls)),
713 }
714 }
715 }
716
717 #[test]
718 fn ensure_macro_compatibility_for_generate_receive_message_proof_call_builder() {
719 let receive_messages_proof = FromBridgedChainMessagesProof {
721 bridged_header_hash: Default::default(),
722 storage_proof: Default::default(),
723 lane: mock::TestLaneIdType::try_new(1, 2).unwrap(),
724 nonces_start: 0,
725 nonces_end: 0,
726 };
727 let account = 1234;
728 let messages_count = 0;
729 let dispatch_weight = Default::default();
730
731 let pallet_receive_messages_proof =
733 pallet_bridge_messages::Call::<mock::TestRuntime>::receive_messages_proof {
734 relayer_id_at_bridged_chain: account,
735 proof: receive_messages_proof.clone().into(),
736 messages_count,
737 dispatch_weight,
738 };
739
740 let mock_enum_receive_messages_proof = CodegenBridgeMessagesCall::receive_messages_proof {
742 relayer_id_at_bridged_chain: account,
743 proof: receive_messages_proof.clone().into(),
744 messages_count,
745 dispatch_weight,
746 };
747
748 let relayer_call_builder_receive_messages_proof = relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder::build_receive_messages_proof_call(
750 account,
751 (Default::default(), receive_messages_proof),
752 messages_count,
753 dispatch_weight,
754 false,
755 );
756
757 assert_eq!(
759 pallet_receive_messages_proof.encode(),
760 mock_enum_receive_messages_proof.encode()
761 );
762 match relayer_call_builder_receive_messages_proof {
763 RuntimeCall::BridgeMessages(call) => match call {
764 call @ CodegenBridgeMessagesCall::receive_messages_proof { .. } =>
765 assert_eq!(pallet_receive_messages_proof.encode(), call.encode()),
766 _ => panic!("Unexpected CodegenBridgeMessagesCall type"),
767 },
768 _ => panic!("Unexpected RuntimeCall type"),
769 };
770 }
771
772 #[test]
773 fn ensure_macro_compatibility_for_generate_receive_message_delivery_proof_call_builder() {
774 let receive_messages_delivery_proof = FromBridgedChainMessagesDeliveryProof {
776 bridged_header_hash: Default::default(),
777 storage_proof: Default::default(),
778 lane: mock::TestLaneIdType::try_new(1, 2).unwrap(),
779 };
780 let relayers_state = UnrewardedRelayersState {
781 unrewarded_relayer_entries: 0,
782 messages_in_oldest_entry: 0,
783 total_messages: 0,
784 last_delivered_nonce: 0,
785 };
786
787 let pallet_receive_messages_delivery_proof =
789 pallet_bridge_messages::Call::<mock::TestRuntime>::receive_messages_delivery_proof {
790 proof: receive_messages_delivery_proof.clone(),
791 relayers_state: relayers_state.clone(),
792 };
793
794 let mock_enum_receive_messages_delivery_proof =
796 CodegenBridgeMessagesCall::receive_messages_delivery_proof {
797 proof: receive_messages_delivery_proof.clone(),
798 relayers_state: relayers_state.clone(),
799 };
800
801 let relayer_call_builder_receive_messages_delivery_proof = relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call(
803 (relayers_state, receive_messages_delivery_proof),
804 false,
805 );
806
807 assert_eq!(
809 pallet_receive_messages_delivery_proof.encode(),
810 mock_enum_receive_messages_delivery_proof.encode()
811 );
812 match relayer_call_builder_receive_messages_delivery_proof {
813 RuntimeCall::BridgeMessages(call) => match call {
814 call @ CodegenBridgeMessagesCall::receive_messages_delivery_proof { .. } =>
815 assert_eq!(pallet_receive_messages_delivery_proof.encode(), call.encode()),
816 _ => panic!("Unexpected CodegenBridgeMessagesCall type"),
817 },
818 _ => panic!("Unexpected RuntimeCall type"),
819 };
820 }
821
822 #[allow(unexpected_cfgs)]
824 mod mock {
825 use super::super::*;
826 use bp_messages::{target_chain::ForbidInboundMessages, HashedLaneId};
827 use bp_runtime::ChainId;
828 use frame_support::derive_impl;
829 use sp_core::H256;
830 use sp_runtime::{
831 generic, testing::Header as SubstrateHeader, traits::BlakeTwo256, StateVersion,
832 };
833
834 type Block = frame_system::mocking::MockBlock<TestRuntime>;
835 pub type SignedBlock = generic::SignedBlock<Block>;
836
837 pub type TestLaneIdType = HashedLaneId;
839
840 frame_support::construct_runtime! {
841 pub enum TestRuntime
842 {
843 System: frame_system,
844 Messages: pallet_bridge_messages,
845 }
846 }
847
848 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
849 impl frame_system::Config for TestRuntime {
850 type Block = Block;
851 }
852
853 impl pallet_bridge_messages::Config for TestRuntime {
854 type RuntimeEvent = RuntimeEvent;
855 type WeightInfo = ();
856 type ThisChain = ThisUnderlyingChain;
857 type BridgedChain = BridgedUnderlyingChain;
858 type BridgedHeaderChain = BridgedHeaderChain;
859 type OutboundPayload = Vec<u8>;
860 type InboundPayload = Vec<u8>;
861 type LaneId = TestLaneIdType;
862 type DeliveryPayments = ();
863 type DeliveryConfirmationPayments = ();
864 type OnMessagesDelivered = ();
865 type MessageDispatch = ForbidInboundMessages<Vec<u8>, Self::LaneId>;
866 }
867
868 pub struct ThisUnderlyingChain;
869
870 impl bp_runtime::Chain for ThisUnderlyingChain {
871 const ID: ChainId = *b"tuch";
872 type BlockNumber = u64;
873 type Hash = H256;
874 type Hasher = BlakeTwo256;
875 type Header = SubstrateHeader;
876 type AccountId = u64;
877 type Balance = u64;
878 type Nonce = u64;
879 type Signature = sp_runtime::MultiSignature;
880 const STATE_VERSION: StateVersion = StateVersion::V1;
881 fn max_extrinsic_size() -> u32 {
882 u32::MAX
883 }
884 fn max_extrinsic_weight() -> Weight {
885 Weight::MAX
886 }
887 }
888
889 impl bp_messages::ChainWithMessages for ThisUnderlyingChain {
890 const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "";
891 const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16;
892 const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000;
893 }
894
895 pub struct BridgedUnderlyingChain;
896
897 pub type BridgedHeaderHash = H256;
898 pub type BridgedChainHeader = SubstrateHeader;
899
900 impl bp_runtime::Chain for BridgedUnderlyingChain {
901 const ID: ChainId = *b"bgdc";
902 type BlockNumber = u64;
903 type Hash = BridgedHeaderHash;
904 type Hasher = BlakeTwo256;
905 type Header = BridgedChainHeader;
906 type AccountId = u64;
907 type Balance = u64;
908 type Nonce = u64;
909 type Signature = sp_runtime::MultiSignature;
910 const STATE_VERSION: StateVersion = StateVersion::V1;
911 fn max_extrinsic_size() -> u32 {
912 4096
913 }
914 fn max_extrinsic_weight() -> Weight {
915 Weight::MAX
916 }
917 }
918
919 impl bp_messages::ChainWithMessages for BridgedUnderlyingChain {
920 const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "";
921 const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16;
922 const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000;
923 }
924
925 pub struct BridgedHeaderChain;
926
927 impl bp_header_chain::HeaderChain<BridgedUnderlyingChain> for BridgedHeaderChain {
928 fn finalized_header_state_root(
929 _hash: HashOf<BridgedUnderlyingChain>,
930 ) -> Option<HashOf<BridgedUnderlyingChain>> {
931 unreachable!()
932 }
933 }
934 }
935
936 mod relayer {
938 use super::*;
939 use crate::{
940 messages::{
941 tests::{mock, RuntimeCall},
942 SubstrateMessageLane,
943 },
944 UtilityPalletBatchCallBuilder,
945 };
946 use bp_runtime::UnderlyingChainProvider;
947 use relay_substrate_client::{MockedRuntimeUtilityPallet, SignParam, UnsignedTransaction};
948 use std::time::Duration;
949
950 #[derive(Clone)]
951 pub struct ThisChain;
952 impl UnderlyingChainProvider for ThisChain {
953 type Chain = mock::ThisUnderlyingChain;
954 }
955 impl relay_substrate_client::Chain for ThisChain {
956 const NAME: &'static str = "";
957 const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "";
958 const FREE_HEADERS_INTERVAL_METHOD: &'static str = "";
959 const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0);
960 type SignedBlock = mock::SignedBlock;
961 type Call = RuntimeCall;
962 }
963 impl relay_substrate_client::ChainWithTransactions for ThisChain {
964 type AccountKeyPair = sp_core::sr25519::Pair;
965 type SignedTransaction = ();
966
967 fn sign_transaction(
968 _: SignParam<Self>,
969 _: UnsignedTransaction<Self>,
970 ) -> Result<Self::SignedTransaction, SubstrateError>
971 where
972 Self: Sized,
973 {
974 todo!()
975 }
976 }
977 impl relay_substrate_client::ChainWithMessages for ThisChain {
978 const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = "";
979 const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = "";
980 }
981 impl relay_substrate_client::ChainWithUtilityPallet for ThisChain {
982 type UtilityPallet = MockedRuntimeUtilityPallet<RuntimeCall>;
983 }
984
985 #[derive(Clone)]
986 pub struct BridgedChain;
987 impl UnderlyingChainProvider for BridgedChain {
988 type Chain = mock::BridgedUnderlyingChain;
989 }
990 impl relay_substrate_client::Chain for BridgedChain {
991 const NAME: &'static str = "";
992 const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "";
993 const FREE_HEADERS_INTERVAL_METHOD: &'static str = "";
994 const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0);
995 type SignedBlock = mock::SignedBlock;
996 type Call = RuntimeCall;
997 }
998 impl relay_substrate_client::ChainWithTransactions for BridgedChain {
999 type AccountKeyPair = sp_core::sr25519::Pair;
1000 type SignedTransaction = ();
1001
1002 fn sign_transaction(
1003 _: SignParam<Self>,
1004 _: UnsignedTransaction<Self>,
1005 ) -> Result<Self::SignedTransaction, SubstrateError>
1006 where
1007 Self: Sized,
1008 {
1009 todo!()
1010 }
1011 }
1012 impl relay_substrate_client::ChainWithMessages for BridgedChain {
1013 const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = "";
1014 const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = "";
1015 }
1016 impl relay_substrate_client::ChainWithUtilityPallet for BridgedChain {
1017 type UtilityPallet = MockedRuntimeUtilityPallet<RuntimeCall>;
1018 }
1019
1020 #[derive(Clone, Debug)]
1021 pub struct ThisChainToBridgedChainMessageLane;
1022 impl SubstrateMessageLane for ThisChainToBridgedChainMessageLane {
1023 type SourceChain = ThisChain;
1024 type TargetChain = BridgedChain;
1025 type LaneId = mock::TestLaneIdType;
1026 type ReceiveMessagesProofCallBuilder =
1027 ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder;
1028 type ReceiveMessagesDeliveryProofCallBuilder =
1029 ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder;
1030 type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder<ThisChain>;
1031 type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder<BridgedChain>;
1032 }
1033
1034 generate_receive_message_proof_call_builder!(
1035 ThisChainToBridgedChainMessageLane,
1036 ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder,
1037 RuntimeCall::BridgeMessages,
1038 CodegenBridgeMessagesCall::receive_messages_proof
1039 );
1040 generate_receive_message_delivery_proof_call_builder!(
1041 ThisChainToBridgedChainMessageLane,
1042 ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder,
1043 RuntimeCall::BridgeMessages,
1044 CodegenBridgeMessagesCall::receive_messages_delivery_proof
1045 );
1046 }
1047}