1use crate::{Config, Pallet, LOG_TARGET};
24
25use crate::{BridgeOf, Bridges};
26
27use bp_messages::{
28 source_chain::{MessagesBridge, OnMessagesDelivered},
29 MessageNonce,
30};
31use bp_xcm_bridge_hub::{BridgeId, BridgeState, LocalXcmChannelManager, XcmAsPlainPayload};
32use frame_support::{ensure, traits::Get};
33use pallet_bridge_messages::{
34 Config as BridgeMessagesConfig, Error, Pallet as BridgeMessagesPallet,
35};
36use xcm::prelude::*;
37use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter};
38use xcm_executor::traits::ExportXcm;
39
40const OUTBOUND_LANE_CONGESTED_THRESHOLD: MessageNonce = 8_192;
43
44const OUTBOUND_LANE_UNCONGESTED_THRESHOLD: MessageNonce = 1_024;
47
48pub type PalletAsHaulBlobExporter<T, I> = HaulBlobExporter<
50 DummyHaulBlob,
51 <T as Config<I>>::BridgedNetwork,
52 <T as Config<I>>::DestinationVersion,
53 <T as Config<I>>::MessageExportPrice,
54>;
55type MessagesPallet<T, I> = BridgeMessagesPallet<T, <T as Config<I>>::BridgeMessagesPalletInstance>;
57
58impl<T: Config<I>, I: 'static> ExportXcm for Pallet<T, I>
59where
60 T: BridgeMessagesConfig<T::BridgeMessagesPalletInstance, OutboundPayload = XcmAsPlainPayload>,
61{
62 type Ticket = (
63 BridgeId,
64 BridgeOf<T, I>,
65 <MessagesPallet<T, I> as MessagesBridge<T::OutboundPayload, T::LaneId>>::SendMessageArgs,
66 XcmHash,
67 );
68
69 fn validate(
70 network: NetworkId,
71 channel: u32,
72 universal_source: &mut Option<InteriorLocation>,
73 destination: &mut Option<InteriorLocation>,
74 message: &mut Option<Xcm<()>>,
75 ) -> Result<(Self::Ticket, Assets), SendError> {
76 tracing::trace!(
77 target: LOG_TARGET,
78 ?network,
79 ?channel,
80 ?universal_source,
81 ?destination,
82 "Validate for network"
83 );
84
85 let bridge_origin_universal_location =
88 universal_source.clone().ok_or(SendError::MissingArgument)?;
89 let bridge_destination_universal_location = {
93 let dest = destination.clone().ok_or(SendError::MissingArgument)?;
94 match dest.global_consensus() {
95 Ok(dest_network) => {
96 tracing::trace!(
97 target: LOG_TARGET,
98 ?dest,
99 ?dest_network,
100 ?network,
101 "Destination is already universal, checking if matches: {:?}",
102 dest_network == network
103 );
104 ensure!(dest_network == network, SendError::NotApplicable);
105 dest
107 },
108 Err(_) => {
109 dest.pushed_front_with(GlobalConsensus(network)).map_err(|error_data| {
112 tracing::error!(
113 target: LOG_TARGET, error=?error_data,
114 "Destination is not a universal and prepending failed!"
115 );
116 SendError::NotApplicable
117 })?
118 },
119 }
120 };
121
122 let bridge_origin_relative_location =
124 bridge_origin_universal_location.relative_to(&T::UniversalLocation::get());
125
126 let locations = Self::bridge_locations(
128 bridge_origin_relative_location,
129 bridge_destination_universal_location.into(),
130 )
131 .map_err(|e| {
132 tracing::error!(
133 target: LOG_TARGET, error=?e,
134 "Validate `bridge_locations` with error"
135 );
136 SendError::NotApplicable
137 })?;
138 let bridge = Self::bridge(locations.bridge_id()).ok_or_else(|| {
139 tracing::error!(
140 target: LOG_TARGET,
141 bridge_origin_relative_location=?locations.bridge_origin_relative_location(),
142 bridge_destination_universal_location=?locations.bridge_destination_universal_location(),
143 "No opened bridge for requested"
144 );
145 SendError::NotApplicable
146 })?;
147
148 let ((blob, id), price) = PalletAsHaulBlobExporter::<T, I>::validate(
152 network,
153 channel,
154 universal_source,
155 destination,
156 message,
157 )?;
158
159 let bridge_message = MessagesPallet::<T, I>::validate_message(bridge.lane_id, &blob)
160 .map_err(|e| {
161 match e {
162 Error::LanesManager(ref ei) =>
163 tracing::error!(target: LOG_TARGET, error=?ei, "LanesManager"),
164 Error::MessageRejectedByPallet(ref ei) =>
165 tracing::error!(target: LOG_TARGET, error=?ei, "MessageRejectedByPallet"),
166 Error::ReceptionConfirmation(ref ei) =>
167 tracing::error!(target: LOG_TARGET, error=?ei, "ReceptionConfirmation"),
168 _ => (),
169 };
170
171 tracing::error!(
172 target: LOG_TARGET,
173 error=?e,
174 topic_id=?id,
175 bridge_id=?locations,
176 lane_id=?bridge.lane_id,
177 "XCM message cannot be exported"
178 );
179 SendError::Transport("BridgeValidateError")
180 })?;
181
182 Ok(((*locations.bridge_id(), bridge, bridge_message, id), price))
183 }
184
185 fn deliver(
186 (bridge_id, bridge, bridge_message, id): Self::Ticket,
187 ) -> Result<XcmHash, SendError> {
188 let artifacts = MessagesPallet::<T, I>::send_message(bridge_message);
189
190 tracing::info!(
191 target: LOG_TARGET,
192 topic_id=?id,
193 bridge_id=?bridge_id,
194 lane_id=?bridge.lane_id,
195 nonce=%artifacts.nonce,
196 "XCM message has been enqueued"
197 );
198
199 Self::on_bridge_message_enqueued(bridge_id, bridge, artifacts.enqueued_messages);
201
202 Ok(id)
203 }
204}
205
206impl<T: Config<I>, I: 'static> OnMessagesDelivered<T::LaneId> for Pallet<T, I> {
207 fn on_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) {
208 Self::on_bridge_messages_delivered(lane_id, enqueued_messages);
209 }
210}
211
212impl<T: Config<I>, I: 'static> Pallet<T, I> {
213 fn on_bridge_message_enqueued(
215 bridge_id: BridgeId,
216 bridge: BridgeOf<T, I>,
217 enqueued_messages: MessageNonce,
218 ) {
219 let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD;
221 if !is_congested {
222 return
223 }
224
225 if bridge.state == BridgeState::Suspended {
232 return
233 }
234
235 let result_bridge_origin_relative_location =
237 (*bridge.bridge_origin_relative_location).clone().try_into();
238 let bridge_origin_relative_location = match &result_bridge_origin_relative_location {
239 Ok(bridge_origin_relative_location) => bridge_origin_relative_location,
240 Err(_) => {
241 tracing::debug!(
242 target: LOG_TARGET,
243 ?bridge_id,
244 origin_location=?bridge.bridge_origin_relative_location,
245 "Failed to convert"
246 );
247
248 return
249 },
250 };
251 let suspend_result =
252 T::LocalXcmChannelManager::suspend_bridge(bridge_origin_relative_location, bridge_id);
253 match suspend_result {
254 Ok(_) => {
255 tracing::debug!(
256 target: LOG_TARGET,
257 ?bridge_id,
258 originated_by=?bridge.bridge_origin_relative_location,
259 "Suspended"
260 );
261 },
262 Err(e) => {
263 tracing::debug!(
264 target: LOG_TARGET,
265 error=?e,
266 ?bridge_id,
267 originated_by=?bridge.bridge_origin_relative_location,
268 "Failed to suspended"
269 );
270
271 return
272 },
273 }
274
275 Bridges::<T, I>::mutate_extant(bridge_id, |bridge| {
277 bridge.state = BridgeState::Suspended;
278 });
279 }
280
281 fn on_bridge_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) {
283 let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD;
285 if is_congested {
286 return
287 }
288
289 let (bridge_id, bridge) = match Self::bridge_by_lane_id(&lane_id) {
292 Some(bridge) if bridge.1.state == BridgeState::Suspended => bridge,
293 _ => {
294 return
298 },
299 };
300
301 let bridge_origin_relative_location = (*bridge.bridge_origin_relative_location).try_into();
303 let bridge_origin_relative_location = match bridge_origin_relative_location {
304 Ok(bridge_origin_relative_location) => bridge_origin_relative_location,
305 Err(e) => {
306 tracing::debug!(
307 target: LOG_TARGET,
308 error=?e,
309 ?bridge_id,
310 ?lane_id,
311 "Failed to convert",
312 );
313
314 return
315 },
316 };
317
318 let resume_result =
319 T::LocalXcmChannelManager::resume_bridge(&bridge_origin_relative_location, bridge_id);
320 match resume_result {
321 Ok(_) => {
322 tracing::debug!(
323 target: LOG_TARGET,
324 ?bridge_id,
325 ?lane_id,
326 originated_by=?bridge_origin_relative_location,
327 "Resumed",
328 );
329 },
330 Err(e) => {
331 tracing::debug!(
332 target: LOG_TARGET,
333 error=?e,
334 ?bridge_id,
335 ?lane_id,
336 originated_by=?bridge_origin_relative_location,
337 "Failed to resume"
338 );
339
340 return
341 },
342 }
343
344 Bridges::<T, I>::mutate_extant(bridge_id, |bridge| {
346 bridge.state = BridgeState::Opened;
347 });
348 }
349}
350
351pub struct DummyHaulBlob;
359
360impl HaulBlob for DummyHaulBlob {
361 fn haul_blob(_blob: XcmAsPlainPayload) -> Result<(), HaulBlobError> {
362 Err(HaulBlobError::Transport("DummyHaulBlob"))
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369 use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf};
370
371 use bp_runtime::RangeInclusiveExt;
372 use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState};
373 use frame_support::{assert_ok, traits::EnsureOrigin};
374 use pallet_bridge_messages::InboundLaneStorage;
375 use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter};
376 use xcm_executor::traits::{export_xcm, ConvertLocation};
377
378 fn universal_source() -> InteriorLocation {
379 SiblingUniversalLocation::get()
380 }
381
382 fn bridged_relative_destination() -> InteriorLocation {
383 BridgedRelativeDestination::get()
384 }
385
386 fn bridged_universal_destination() -> InteriorLocation {
387 BridgedUniversalDestination::get()
388 }
389
390 fn open_lane(origin: RuntimeOrigin) -> (BridgeLocations, TestLaneIdType) {
391 let with = bridged_asset_hub_universal_location();
393 let locations =
394 XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap();
395 let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap();
396
397 if !Bridges::<TestRuntime, ()>::contains_key(locations.bridge_id()) {
398 Bridges::<TestRuntime, ()>::insert(
400 locations.bridge_id(),
401 Bridge {
402 bridge_origin_relative_location: Box::new(SiblingLocation::get().into()),
403 bridge_origin_universal_location: Box::new(
404 locations.bridge_origin_universal_location().clone().into(),
405 ),
406 bridge_destination_universal_location: Box::new(
407 locations.bridge_destination_universal_location().clone().into(),
408 ),
409 state: BridgeState::Opened,
410 bridge_owner_account: LocationToAccountId::convert_location(
411 locations.bridge_origin_relative_location(),
412 )
413 .expect("valid accountId"),
414 deposit: 0,
415 lane_id,
416 },
417 );
418 LaneToBridge::<TestRuntime, ()>::insert(lane_id, locations.bridge_id());
419
420 let lanes_manager = LanesManagerOf::<TestRuntime, ()>::new();
422 if lanes_manager.create_inbound_lane(lane_id).is_ok() {
423 assert_eq!(
424 0,
425 lanes_manager
426 .active_inbound_lane(lane_id)
427 .unwrap()
428 .storage()
429 .data()
430 .last_confirmed_nonce
431 );
432 }
433 if lanes_manager.create_outbound_lane(lane_id).is_ok() {
434 assert!(lanes_manager
435 .active_outbound_lane(lane_id)
436 .unwrap()
437 .queued_messages()
438 .is_empty());
439 }
440 }
441 assert_ok!(XcmOverBridge::do_try_state());
442
443 (*locations, lane_id)
444 }
445
446 fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) {
447 let (locations, lane_id) = open_lane(OpenBridgeOrigin::sibling_parachain_origin());
448
449 export_xcm::<XcmOverBridge>(
451 BridgedRelayNetwork::get(),
452 0,
453 locations.bridge_origin_universal_location().clone(),
454 locations.bridge_destination_universal_location().clone(),
455 vec![Instruction::ClearOrigin].into(),
456 )
457 .unwrap();
458
459 (*locations.bridge_id(), lane_id)
460 }
461
462 #[test]
463 fn exporter_works() {
464 run_test(|| {
465 let (_, lane_id) = open_lane_and_send_regular_message();
466
467 assert!(!LanesManagerOf::<TestRuntime, ()>::new()
470 .active_outbound_lane(lane_id)
471 .unwrap()
472 .queued_messages()
473 .is_empty());
474 });
475 }
476
477 #[test]
478 fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() {
479 run_test(|| {
480 let (bridge_id, _) = open_lane_and_send_regular_message();
481 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
482 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
483 });
484 }
485
486 #[test]
487 fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() {
488 run_test(|| {
489 let (bridge_id, _) = open_lane_and_send_regular_message();
490 Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
491 bridge.state = BridgeState::Suspended;
492 });
493 for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD {
494 open_lane_and_send_regular_message();
495 }
496
497 open_lane_and_send_regular_message();
498 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
499 });
500 }
501
502 #[test]
503 fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() {
504 run_test(|| {
505 let (bridge_id, _) = open_lane_and_send_regular_message();
506 for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD {
507 open_lane_and_send_regular_message();
508 }
509
510 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
511 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
512
513 open_lane_and_send_regular_message();
514 assert!(TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
515 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended);
516 });
517 }
518
519 #[test]
520 fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() {
521 run_test(|| {
522 let (bridge_id, lane_id) = open_lane_and_send_regular_message();
523 Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
524 bridge.state = BridgeState::Suspended;
525 });
526 XcmOverBridge::on_bridge_messages_delivered(
527 lane_id,
528 OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1,
529 );
530
531 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id));
532 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended);
533 });
534 }
535
536 #[test]
537 fn bridge_is_not_resumed_if_it_was_not_suspended_before() {
538 run_test(|| {
539 let (bridge_id, lane_id) = open_lane_and_send_regular_message();
540 XcmOverBridge::on_bridge_messages_delivered(
541 lane_id,
542 OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
543 );
544
545 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id));
546 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
547 });
548 }
549
550 #[test]
551 fn bridge_is_resumed_when_enough_messages_are_delivered() {
552 run_test(|| {
553 let (bridge_id, lane_id) = open_lane_and_send_regular_message();
554 Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
555 bridge.state = BridgeState::Suspended;
556 });
557 XcmOverBridge::on_bridge_messages_delivered(
558 lane_id,
559 OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
560 );
561
562 assert!(TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id));
563 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
564 });
565 }
566
567 #[test]
568 fn export_fails_if_argument_is_missing() {
569 run_test(|| {
570 assert_eq!(
571 XcmOverBridge::validate(
572 BridgedRelayNetwork::get(),
573 0,
574 &mut None,
575 &mut Some(bridged_relative_destination()),
576 &mut Some(Vec::new().into()),
577 ),
578 Err(SendError::MissingArgument),
579 );
580
581 assert_eq!(
582 XcmOverBridge::validate(
583 BridgedRelayNetwork::get(),
584 0,
585 &mut Some(universal_source()),
586 &mut None,
587 &mut Some(Vec::new().into()),
588 ),
589 Err(SendError::MissingArgument),
590 );
591 })
592 }
593
594 #[test]
595 fn exporter_computes_correct_lane_id() {
596 run_test(|| {
597 assert_ne!(bridged_universal_destination(), bridged_relative_destination());
598
599 let locations = BridgeLocations::bridge_locations(
600 UniversalLocation::get(),
601 SiblingLocation::get(),
602 bridged_universal_destination(),
603 BridgedRelayNetwork::get(),
604 )
605 .unwrap();
606 let expected_bridge_id = locations.bridge_id();
607 let expected_lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap();
608
609 if LanesManagerOf::<TestRuntime, ()>::new()
610 .create_outbound_lane(expected_lane_id)
611 .is_ok()
612 {
613 Bridges::<TestRuntime, ()>::insert(
614 expected_bridge_id,
615 Bridge {
616 bridge_origin_relative_location: Box::new(
617 locations.bridge_origin_relative_location().clone().into(),
618 ),
619 bridge_origin_universal_location: Box::new(
620 locations.bridge_origin_universal_location().clone().into(),
621 ),
622 bridge_destination_universal_location: Box::new(
623 locations.bridge_destination_universal_location().clone().into(),
624 ),
625 state: BridgeState::Opened,
626 bridge_owner_account: [0u8; 32].into(),
627 deposit: 0,
628 lane_id: expected_lane_id,
629 },
630 );
631 }
632
633 let ticket = XcmOverBridge::validate(
634 BridgedRelayNetwork::get(),
635 0,
636 &mut Some(universal_source()),
637 &mut Some(bridged_relative_destination()),
640 &mut Some(Vec::new().into()),
641 )
642 .unwrap()
643 .0;
644 assert_eq!(&ticket.0, expected_bridge_id);
645 assert_eq!(ticket.1.lane_id, expected_lane_id);
646 });
647 }
648
649 #[test]
650 fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() {
651 run_test(|| {
652 let dest = Location::new(2, BridgedUniversalDestination::get());
654
655 let origin = OpenBridgeOrigin::sibling_parachain_origin();
657 let origin_as_location =
658 OpenBridgeOriginOf::<TestRuntime, ()>::try_origin(origin.clone()).unwrap();
659 let (_, expected_lane_id) = open_lane(origin);
660
661 assert_eq!(
663 pallet_bridge_messages::Pallet::<TestRuntime, ()>::outbound_lane_data(
664 expected_lane_id
665 )
666 .unwrap()
667 .queued_messages()
668 .saturating_len(),
669 0
670 );
671
672 ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location);
674 assert_ok!(send_xcm::<
675 UnpaidRemoteExporter<
676 NetworkExportTable<BridgeTable>,
677 ExecuteXcmOverSendXcm,
678 UniversalLocation,
679 >,
680 >(dest.clone(), Xcm::<()>::default()));
681
682 ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get()));
685 ExecuteXcmOverSendXcm::set_origin_for_execute(SiblingLocation::get());
687 assert_ok!(send_xcm::<XcmOverBridgeWrappedWithExportMessageRouter>(
688 dest.clone(),
689 Xcm::<()>::default()
690 ));
691
692 assert_eq!(
694 pallet_bridge_messages::Pallet::<TestRuntime, ()>::outbound_lane_data(
695 expected_lane_id
696 )
697 .unwrap()
698 .queued_messages()
699 .saturating_len(),
700 2
701 );
702 })
703 }
704
705 #[test]
706 fn validate_works() {
707 run_test(|| {
708 let xcm: Xcm<()> = vec![ClearOrigin].into();
709
710 let mut xcm_wrapper = Some(xcm.clone());
712 let mut universal_source_wrapper = Some(universal_source());
713
714 let mut dest_wrapper = Some(bridged_relative_destination());
716 assert_eq!(
717 XcmOverBridge::validate(
718 NetworkId::ByGenesis([0; 32]),
719 0,
720 &mut universal_source_wrapper,
721 &mut dest_wrapper,
722 &mut xcm_wrapper,
723 ),
724 Err(SendError::NotApplicable),
725 );
726 assert_eq!(&Some(xcm.clone()), &xcm_wrapper);
728 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
729 assert_eq!(&Some(bridged_relative_destination()), &dest_wrapper);
730
731 let mut invalid_dest_wrapper = Some(
733 [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(BRIDGED_ASSET_HUB_ID)]
734 .into(),
735 );
736 assert_eq!(
737 XcmOverBridge::validate(
738 BridgedRelayNetwork::get(),
739 0,
740 &mut Some(universal_source()),
741 &mut invalid_dest_wrapper,
742 &mut xcm_wrapper,
743 ),
744 Err(SendError::NotApplicable),
745 );
746 assert_eq!(&Some(xcm.clone()), &xcm_wrapper);
748 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
749 assert_eq!(
750 &Some(
751 [
752 GlobalConsensus(NetworkId::ByGenesis([0; 32]),),
753 Parachain(BRIDGED_ASSET_HUB_ID)
754 ]
755 .into()
756 ),
757 &invalid_dest_wrapper
758 );
759
760 let mut dest_without_lane_wrapper =
762 Some([GlobalConsensus(BridgedRelayNetwork::get()), Parachain(5679)].into());
763 assert_eq!(
764 XcmOverBridge::validate(
765 BridgedRelayNetwork::get(),
766 0,
767 &mut Some(universal_source()),
768 &mut dest_without_lane_wrapper,
769 &mut xcm_wrapper,
770 ),
771 Err(SendError::NotApplicable),
772 );
773 assert_eq!(&Some(xcm.clone()), &xcm_wrapper);
775 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
776 assert_eq!(
777 &Some([GlobalConsensus(BridgedRelayNetwork::get(),), Parachain(5679)].into()),
778 &dest_without_lane_wrapper
779 );
780
781 let _ = open_lane(OpenBridgeOrigin::sibling_parachain_origin());
783 let mut dest_wrapper = Some(bridged_relative_destination());
784 assert_ok!(XcmOverBridge::validate(
785 BridgedRelayNetwork::get(),
786 0,
787 &mut Some(universal_source()),
788 &mut dest_wrapper,
789 &mut xcm_wrapper,
790 ));
791 assert_eq!(None, xcm_wrapper);
793 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
794 assert_eq!(None, dest_wrapper);
795 });
796 }
797
798 #[test]
799 fn congestion_with_pallet_xcm_bridge_hub_router_works() {
800 run_test(|| {
801 let dest = Location::new(2, BridgedUniversalDestination::get());
803
804 fn router_bridge_state() -> pallet_xcm_bridge_hub_router::BridgeState {
805 pallet_xcm_bridge_hub_router::Bridge::<
806 TestRuntime,
807 XcmOverBridgeWrappedWithExportMessageRouterInstance,
808 >::get()
809 }
810
811 let origin = OpenBridgeOrigin::sibling_parachain_origin();
813 let origin_as_location =
814 OpenBridgeOriginOf::<TestRuntime, ()>::try_origin(origin.clone()).unwrap();
815 let (bridge_1, expected_lane_id_1) = open_lane(origin);
816
817 ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get()));
820
821 assert_eq!(
824 XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state,
825 BridgeState::Opened
826 );
827
828 assert!(!router_bridge_state().is_congested);
830 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id()));
831 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id()));
832
833 for _ in 1..(OUTBOUND_LANE_CONGESTED_THRESHOLD + 2) {
835 ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone());
837 assert_ok!(send_xcm::<XcmOverBridgeWrappedWithExportMessageRouter>(
838 dest.clone(),
839 Xcm::<()>::default()
840 ));
841 }
842
843 assert_eq!(
846 XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state,
847 BridgeState::Suspended,
848 );
849 assert!(router_bridge_state().is_congested);
851 assert!(TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id()));
852 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id()));
853
854 XcmOverBridge::on_bridge_messages_delivered(
856 expected_lane_id_1,
857 OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
858 );
859
860 assert_eq!(
862 XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state,
863 BridgeState::Opened
864 );
865 assert!(!router_bridge_state().is_congested);
867 assert!(TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id()));
868 })
869 }
870}