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 },
165 Error::MessageRejectedByPallet(ref ei) => {
166 tracing::error!(target: LOG_TARGET, error=?ei, "MessageRejectedByPallet")
167 },
168 Error::ReceptionConfirmation(ref ei) => {
169 tracing::error!(target: LOG_TARGET, error=?ei, "ReceptionConfirmation")
170 },
171 _ => (),
172 };
173
174 tracing::error!(
175 target: LOG_TARGET,
176 error=?e,
177 topic_id=?id,
178 bridge_id=?locations,
179 lane_id=?bridge.lane_id,
180 "XCM message cannot be exported"
181 );
182 SendError::Transport("BridgeValidateError")
183 })?;
184
185 Ok(((*locations.bridge_id(), bridge, bridge_message, id), price))
186 }
187
188 fn deliver(
189 (bridge_id, bridge, bridge_message, id): Self::Ticket,
190 ) -> Result<XcmHash, SendError> {
191 let artifacts = MessagesPallet::<T, I>::send_message(bridge_message);
192
193 tracing::info!(
194 target: LOG_TARGET,
195 topic_id=?id,
196 bridge_id=?bridge_id,
197 lane_id=?bridge.lane_id,
198 nonce=%artifacts.nonce,
199 "XCM message has been enqueued"
200 );
201
202 Self::on_bridge_message_enqueued(bridge_id, bridge, artifacts.enqueued_messages);
204
205 Ok(id)
206 }
207}
208
209impl<T: Config<I>, I: 'static> OnMessagesDelivered<T::LaneId> for Pallet<T, I> {
210 fn on_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) {
211 Self::on_bridge_messages_delivered(lane_id, enqueued_messages);
212 }
213}
214
215impl<T: Config<I>, I: 'static> Pallet<T, I> {
216 fn on_bridge_message_enqueued(
218 bridge_id: BridgeId,
219 bridge: BridgeOf<T, I>,
220 enqueued_messages: MessageNonce,
221 ) {
222 let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD;
224 if !is_congested {
225 return;
226 }
227
228 if bridge.state == BridgeState::Suspended {
235 return;
236 }
237
238 let result_bridge_origin_relative_location =
240 (*bridge.bridge_origin_relative_location).clone().try_into();
241 let bridge_origin_relative_location = match &result_bridge_origin_relative_location {
242 Ok(bridge_origin_relative_location) => bridge_origin_relative_location,
243 Err(_) => {
244 tracing::debug!(
245 target: LOG_TARGET,
246 ?bridge_id,
247 origin_location=?bridge.bridge_origin_relative_location,
248 "Failed to convert"
249 );
250
251 return;
252 },
253 };
254 let suspend_result =
255 T::LocalXcmChannelManager::suspend_bridge(bridge_origin_relative_location, bridge_id);
256 match suspend_result {
257 Ok(_) => {
258 tracing::debug!(
259 target: LOG_TARGET,
260 ?bridge_id,
261 originated_by=?bridge.bridge_origin_relative_location,
262 "Suspended"
263 );
264 },
265 Err(e) => {
266 tracing::debug!(
267 target: LOG_TARGET,
268 error=?e,
269 ?bridge_id,
270 originated_by=?bridge.bridge_origin_relative_location,
271 "Failed to suspended"
272 );
273
274 return;
275 },
276 }
277
278 Bridges::<T, I>::mutate_extant(bridge_id, |bridge| {
280 bridge.state = BridgeState::Suspended;
281 });
282 }
283
284 fn on_bridge_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) {
286 let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD;
288 if is_congested {
289 return;
290 }
291
292 let (bridge_id, bridge) = match Self::bridge_by_lane_id(&lane_id) {
295 Some(bridge) if bridge.1.state == BridgeState::Suspended => bridge,
296 _ => {
297 return;
301 },
302 };
303
304 let bridge_origin_relative_location = (*bridge.bridge_origin_relative_location).try_into();
306 let bridge_origin_relative_location = match bridge_origin_relative_location {
307 Ok(bridge_origin_relative_location) => bridge_origin_relative_location,
308 Err(e) => {
309 tracing::debug!(
310 target: LOG_TARGET,
311 error=?e,
312 ?bridge_id,
313 ?lane_id,
314 "Failed to convert",
315 );
316
317 return;
318 },
319 };
320
321 let resume_result =
322 T::LocalXcmChannelManager::resume_bridge(&bridge_origin_relative_location, bridge_id);
323 match resume_result {
324 Ok(_) => {
325 tracing::debug!(
326 target: LOG_TARGET,
327 ?bridge_id,
328 ?lane_id,
329 originated_by=?bridge_origin_relative_location,
330 "Resumed",
331 );
332 },
333 Err(e) => {
334 tracing::debug!(
335 target: LOG_TARGET,
336 error=?e,
337 ?bridge_id,
338 ?lane_id,
339 originated_by=?bridge_origin_relative_location,
340 "Failed to resume"
341 );
342
343 return;
344 },
345 }
346
347 Bridges::<T, I>::mutate_extant(bridge_id, |bridge| {
349 bridge.state = BridgeState::Opened;
350 });
351 }
352}
353
354pub struct DummyHaulBlob;
362
363impl HaulBlob for DummyHaulBlob {
364 fn haul_blob(_blob: XcmAsPlainPayload) -> Result<(), HaulBlobError> {
365 Err(HaulBlobError::Transport("DummyHaulBlob"))
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372 use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf};
373
374 use bp_runtime::RangeInclusiveExt;
375 use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState};
376 use frame_support::{assert_ok, traits::EnsureOrigin};
377 use pallet_bridge_messages::InboundLaneStorage;
378 use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter};
379 use xcm_executor::traits::{export_xcm, ConvertLocation};
380
381 fn universal_source() -> InteriorLocation {
382 SiblingUniversalLocation::get()
383 }
384
385 fn bridged_relative_destination() -> InteriorLocation {
386 BridgedRelativeDestination::get()
387 }
388
389 fn bridged_universal_destination() -> InteriorLocation {
390 BridgedUniversalDestination::get()
391 }
392
393 fn open_lane(origin: RuntimeOrigin) -> (BridgeLocations, TestLaneIdType) {
394 let with = bridged_asset_hub_universal_location();
396 let locations =
397 XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap();
398 let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap();
399
400 if !Bridges::<TestRuntime, ()>::contains_key(locations.bridge_id()) {
401 Bridges::<TestRuntime, ()>::insert(
403 locations.bridge_id(),
404 Bridge {
405 bridge_origin_relative_location: Box::new(SiblingLocation::get().into()),
406 bridge_origin_universal_location: Box::new(
407 locations.bridge_origin_universal_location().clone().into(),
408 ),
409 bridge_destination_universal_location: Box::new(
410 locations.bridge_destination_universal_location().clone().into(),
411 ),
412 state: BridgeState::Opened,
413 bridge_owner_account: LocationToAccountId::convert_location(
414 locations.bridge_origin_relative_location(),
415 )
416 .expect("valid accountId"),
417 deposit: 0,
418 lane_id,
419 },
420 );
421 LaneToBridge::<TestRuntime, ()>::insert(lane_id, locations.bridge_id());
422
423 let lanes_manager = LanesManagerOf::<TestRuntime, ()>::new();
425 if lanes_manager.create_inbound_lane(lane_id).is_ok() {
426 assert_eq!(
427 0,
428 lanes_manager
429 .active_inbound_lane(lane_id)
430 .unwrap()
431 .storage()
432 .data()
433 .last_confirmed_nonce
434 );
435 }
436 if lanes_manager.create_outbound_lane(lane_id).is_ok() {
437 assert!(lanes_manager
438 .active_outbound_lane(lane_id)
439 .unwrap()
440 .queued_messages()
441 .is_empty());
442 }
443 }
444 assert_ok!(XcmOverBridge::do_try_state());
445
446 (*locations, lane_id)
447 }
448
449 fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) {
450 let (locations, lane_id) = open_lane(OpenBridgeOrigin::sibling_parachain_origin());
451
452 export_xcm::<XcmOverBridge>(
454 BridgedRelayNetwork::get(),
455 0,
456 locations.bridge_origin_universal_location().clone(),
457 locations.bridge_destination_universal_location().clone(),
458 vec![Instruction::ClearOrigin].into(),
459 )
460 .unwrap();
461
462 (*locations.bridge_id(), lane_id)
463 }
464
465 #[test]
466 fn exporter_works() {
467 run_test(|| {
468 let (_, lane_id) = open_lane_and_send_regular_message();
469
470 assert!(!LanesManagerOf::<TestRuntime, ()>::new()
473 .active_outbound_lane(lane_id)
474 .unwrap()
475 .queued_messages()
476 .is_empty());
477 });
478 }
479
480 #[test]
481 fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() {
482 run_test(|| {
483 let (bridge_id, _) = open_lane_and_send_regular_message();
484 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
485 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
486 });
487 }
488
489 #[test]
490 fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() {
491 run_test(|| {
492 let (bridge_id, _) = open_lane_and_send_regular_message();
493 Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
494 bridge.state = BridgeState::Suspended;
495 });
496 for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD {
497 open_lane_and_send_regular_message();
498 }
499
500 open_lane_and_send_regular_message();
501 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
502 });
503 }
504
505 #[test]
506 fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() {
507 run_test(|| {
508 let (bridge_id, _) = open_lane_and_send_regular_message();
509 for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD {
510 open_lane_and_send_regular_message();
511 }
512
513 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
514 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
515
516 open_lane_and_send_regular_message();
517 assert!(TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id));
518 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended);
519 });
520 }
521
522 #[test]
523 fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() {
524 run_test(|| {
525 let (bridge_id, lane_id) = open_lane_and_send_regular_message();
526 Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
527 bridge.state = BridgeState::Suspended;
528 });
529 XcmOverBridge::on_bridge_messages_delivered(
530 lane_id,
531 OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1,
532 );
533
534 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id));
535 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended);
536 });
537 }
538
539 #[test]
540 fn bridge_is_not_resumed_if_it_was_not_suspended_before() {
541 run_test(|| {
542 let (bridge_id, lane_id) = open_lane_and_send_regular_message();
543 XcmOverBridge::on_bridge_messages_delivered(
544 lane_id,
545 OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
546 );
547
548 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id));
549 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
550 });
551 }
552
553 #[test]
554 fn bridge_is_resumed_when_enough_messages_are_delivered() {
555 run_test(|| {
556 let (bridge_id, lane_id) = open_lane_and_send_regular_message();
557 Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
558 bridge.state = BridgeState::Suspended;
559 });
560 XcmOverBridge::on_bridge_messages_delivered(
561 lane_id,
562 OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
563 );
564
565 assert!(TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id));
566 assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
567 });
568 }
569
570 #[test]
571 fn export_fails_if_argument_is_missing() {
572 run_test(|| {
573 assert_eq!(
574 XcmOverBridge::validate(
575 BridgedRelayNetwork::get(),
576 0,
577 &mut None,
578 &mut Some(bridged_relative_destination()),
579 &mut Some(Vec::new().into()),
580 ),
581 Err(SendError::MissingArgument),
582 );
583
584 assert_eq!(
585 XcmOverBridge::validate(
586 BridgedRelayNetwork::get(),
587 0,
588 &mut Some(universal_source()),
589 &mut None,
590 &mut Some(Vec::new().into()),
591 ),
592 Err(SendError::MissingArgument),
593 );
594 })
595 }
596
597 #[test]
598 fn exporter_computes_correct_lane_id() {
599 run_test(|| {
600 assert_ne!(bridged_universal_destination(), bridged_relative_destination());
601
602 let locations = BridgeLocations::bridge_locations(
603 UniversalLocation::get(),
604 SiblingLocation::get(),
605 bridged_universal_destination(),
606 BridgedRelayNetwork::get(),
607 )
608 .unwrap();
609 let expected_bridge_id = locations.bridge_id();
610 let expected_lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap();
611
612 if LanesManagerOf::<TestRuntime, ()>::new()
613 .create_outbound_lane(expected_lane_id)
614 .is_ok()
615 {
616 Bridges::<TestRuntime, ()>::insert(
617 expected_bridge_id,
618 Bridge {
619 bridge_origin_relative_location: Box::new(
620 locations.bridge_origin_relative_location().clone().into(),
621 ),
622 bridge_origin_universal_location: Box::new(
623 locations.bridge_origin_universal_location().clone().into(),
624 ),
625 bridge_destination_universal_location: Box::new(
626 locations.bridge_destination_universal_location().clone().into(),
627 ),
628 state: BridgeState::Opened,
629 bridge_owner_account: [0u8; 32].into(),
630 deposit: 0,
631 lane_id: expected_lane_id,
632 },
633 );
634 }
635
636 let ticket = XcmOverBridge::validate(
637 BridgedRelayNetwork::get(),
638 0,
639 &mut Some(universal_source()),
640 &mut Some(bridged_relative_destination()),
643 &mut Some(Vec::new().into()),
644 )
645 .unwrap()
646 .0;
647 assert_eq!(&ticket.0, expected_bridge_id);
648 assert_eq!(ticket.1.lane_id, expected_lane_id);
649 });
650 }
651
652 #[test]
653 fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() {
654 run_test(|| {
655 let dest = Location::new(2, BridgedUniversalDestination::get());
657
658 let origin = OpenBridgeOrigin::sibling_parachain_origin();
660 let origin_as_location =
661 OpenBridgeOriginOf::<TestRuntime, ()>::try_origin(origin.clone()).unwrap();
662 let (_, expected_lane_id) = open_lane(origin);
663
664 assert_eq!(
666 pallet_bridge_messages::Pallet::<TestRuntime, ()>::outbound_lane_data(
667 expected_lane_id
668 )
669 .unwrap()
670 .queued_messages()
671 .saturating_len(),
672 0
673 );
674
675 ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location);
677 assert_ok!(send_xcm::<
678 UnpaidRemoteExporter<
679 NetworkExportTable<BridgeTable>,
680 ExecuteXcmOverSendXcm,
681 UniversalLocation,
682 >,
683 >(dest.clone(), Xcm::<()>::default()));
684
685 ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get()));
688 ExecuteXcmOverSendXcm::set_origin_for_execute(SiblingLocation::get());
690 assert_ok!(send_xcm::<XcmOverBridgeWrappedWithExportMessageRouter>(
691 dest.clone(),
692 Xcm::<()>::default()
693 ));
694
695 assert_eq!(
697 pallet_bridge_messages::Pallet::<TestRuntime, ()>::outbound_lane_data(
698 expected_lane_id
699 )
700 .unwrap()
701 .queued_messages()
702 .saturating_len(),
703 2
704 );
705 })
706 }
707
708 #[test]
709 fn validate_works() {
710 run_test(|| {
711 let xcm: Xcm<()> = vec![ClearOrigin].into();
712
713 let mut xcm_wrapper = Some(xcm.clone());
715 let mut universal_source_wrapper = Some(universal_source());
716
717 let mut dest_wrapper = Some(bridged_relative_destination());
719 assert_eq!(
720 XcmOverBridge::validate(
721 NetworkId::ByGenesis([0; 32]),
722 0,
723 &mut universal_source_wrapper,
724 &mut dest_wrapper,
725 &mut xcm_wrapper,
726 ),
727 Err(SendError::NotApplicable),
728 );
729 assert_eq!(&Some(xcm.clone()), &xcm_wrapper);
731 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
732 assert_eq!(&Some(bridged_relative_destination()), &dest_wrapper);
733
734 let mut invalid_dest_wrapper = Some(
736 [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(BRIDGED_ASSET_HUB_ID)]
737 .into(),
738 );
739 assert_eq!(
740 XcmOverBridge::validate(
741 BridgedRelayNetwork::get(),
742 0,
743 &mut Some(universal_source()),
744 &mut invalid_dest_wrapper,
745 &mut xcm_wrapper,
746 ),
747 Err(SendError::NotApplicable),
748 );
749 assert_eq!(&Some(xcm.clone()), &xcm_wrapper);
751 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
752 assert_eq!(
753 &Some(
754 [
755 GlobalConsensus(NetworkId::ByGenesis([0; 32]),),
756 Parachain(BRIDGED_ASSET_HUB_ID)
757 ]
758 .into()
759 ),
760 &invalid_dest_wrapper
761 );
762
763 let mut dest_without_lane_wrapper =
765 Some([GlobalConsensus(BridgedRelayNetwork::get()), Parachain(5679)].into());
766 assert_eq!(
767 XcmOverBridge::validate(
768 BridgedRelayNetwork::get(),
769 0,
770 &mut Some(universal_source()),
771 &mut dest_without_lane_wrapper,
772 &mut xcm_wrapper,
773 ),
774 Err(SendError::NotApplicable),
775 );
776 assert_eq!(&Some(xcm.clone()), &xcm_wrapper);
778 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
779 assert_eq!(
780 &Some([GlobalConsensus(BridgedRelayNetwork::get(),), Parachain(5679)].into()),
781 &dest_without_lane_wrapper
782 );
783
784 let _ = open_lane(OpenBridgeOrigin::sibling_parachain_origin());
786 let mut dest_wrapper = Some(bridged_relative_destination());
787 assert_ok!(XcmOverBridge::validate(
788 BridgedRelayNetwork::get(),
789 0,
790 &mut Some(universal_source()),
791 &mut dest_wrapper,
792 &mut xcm_wrapper,
793 ));
794 assert_eq!(None, xcm_wrapper);
796 assert_eq!(&Some(universal_source()), &universal_source_wrapper);
797 assert_eq!(None, dest_wrapper);
798 });
799 }
800
801 #[test]
802 fn congestion_with_pallet_xcm_bridge_hub_router_works() {
803 run_test(|| {
804 let dest = Location::new(2, BridgedUniversalDestination::get());
806
807 fn router_bridge_state() -> pallet_xcm_bridge_hub_router::BridgeState {
808 pallet_xcm_bridge_hub_router::Bridge::<
809 TestRuntime,
810 XcmOverBridgeWrappedWithExportMessageRouterInstance,
811 >::get()
812 }
813
814 let origin = OpenBridgeOrigin::sibling_parachain_origin();
816 let origin_as_location =
817 OpenBridgeOriginOf::<TestRuntime, ()>::try_origin(origin.clone()).unwrap();
818 let (bridge_1, expected_lane_id_1) = open_lane(origin);
819
820 ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get()));
823
824 assert_eq!(
827 XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state,
828 BridgeState::Opened
829 );
830
831 assert!(!router_bridge_state().is_congested);
833 assert!(!TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id()));
834 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id()));
835
836 for _ in 1..(OUTBOUND_LANE_CONGESTED_THRESHOLD + 2) {
838 ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone());
840 assert_ok!(send_xcm::<XcmOverBridgeWrappedWithExportMessageRouter>(
841 dest.clone(),
842 Xcm::<()>::default()
843 ));
844 }
845
846 assert_eq!(
849 XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state,
850 BridgeState::Suspended,
851 );
852 assert!(router_bridge_state().is_congested);
854 assert!(TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id()));
855 assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id()));
856
857 XcmOverBridge::on_bridge_messages_delivered(
859 expected_lane_id_1,
860 OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
861 );
862
863 assert_eq!(
865 XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state,
866 BridgeState::Opened
867 );
868 assert!(!router_bridge_state().is_congested);
870 assert!(TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id()));
871 })
872 }
873}