From 5cf5bccba43f327a008567d331e46e6f31b71b3c Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 10 Dec 2024 06:37:57 +0100 Subject: [PATCH] BACKPORT-CONFLICT --- Cargo.lock | 62 ++ .../chains/chain-asset-hub-rococo/Cargo.toml | 15 + .../chains/chain-asset-hub-rococo/src/lib.rs | 25 + .../chains/chain-asset-hub-westend/Cargo.toml | 15 + .../chains/chain-asset-hub-westend/src/lib.rs | 25 + .../xcm-bridge-hub-router/src/benchmarking.rs | 10 + .../modules/xcm-bridge-hub-router/src/lib.rs | 127 +++- .../modules/xcm-bridge-hub-router/src/mock.rs | 4 + .../xcm-bridge-hub-router/src/weights.rs | 29 + bridges/modules/xcm-bridge-hub/Cargo.toml | 11 + .../modules/xcm-bridge-hub/src/exporter.rs | 467 ++++++++++++ bridges/modules/xcm-bridge-hub/src/lib.rs | 12 + bridges/modules/xcm-bridge-hub/src/mock.rs | 345 +++++++++ bridges/primitives/xcm-bridge-hub/src/lib.rs | 671 ++++++++++++++++++ .../assets/asset-hub-rococo/src/lib.rs | 7 + .../weights/pallet_xcm_bridge_hub_router.rs | 24 + .../assets/asset-hub-rococo/tests/tests.rs | 10 + .../assets/asset-hub-westend/src/lib.rs | 15 + .../weights/pallet_xcm_bridge_hub_router.rs | 28 +- .../assets/asset-hub-westend/tests/tests.rs | 10 + .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 41 ++ .../src/bridge_to_westend_config.rs | 115 +++ .../bridge-hubs/bridge-hub-westend/Cargo.toml | 39 + .../src/bridge_to_rococo_config.rs | 119 ++++ prdoc/pr_6781.prdoc | 28 + 25 files changed, 2252 insertions(+), 2 deletions(-) create mode 100644 prdoc/pr_6781.prdoc diff --git a/Cargo.lock b/Cargo.lock index d2d4535791e9..53a83a02e160 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1657,6 +1657,8 @@ dependencies = [ "frame-support", "parity-scale-codec", "scale-info", + "sp-core 28.0.0", + "staging-xcm 7.0.0", ] [[package]] @@ -1667,6 +1669,8 @@ dependencies = [ "frame-support", "parity-scale-codec", "scale-info", + "sp-core 28.0.0", + "staging-xcm 7.0.0", ] [[package]] @@ -2039,6 +2043,7 @@ dependencies = [ "bp-rococo", "bp-runtime", "bp-westend", +<<<<<<< HEAD "bridge-hub-common", "bridge-hub-test-utils", "bridge-runtime-common", @@ -2058,6 +2063,29 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", +======= + "bp-xcm-bridge-hub-router 0.6.0", + "bridge-hub-common 0.1.0", + "bridge-hub-test-utils 0.7.0", + "bridge-runtime-common 0.7.0", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) "hex-literal", "log", "pallet-aura", @@ -2213,6 +2241,7 @@ dependencies = [ "bp-rococo", "bp-runtime", "bp-westend", +<<<<<<< HEAD "bridge-hub-common", "bridge-hub-test-utils", "bridge-runtime-common", @@ -2232,6 +2261,29 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", +======= + "bp-xcm-bridge-hub-router 0.6.0", + "bridge-hub-common 0.1.0", + "bridge-hub-test-utils 0.7.0", + "bridge-runtime-common 0.7.0", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) "hex-literal", "log", "pallet-aura", @@ -11780,6 +11832,7 @@ dependencies = [ name = "pallet-xcm-bridge-hub" version = "0.12.1" dependencies = [ +<<<<<<< HEAD "bp-header-chain", "bp-messages", "bp-runtime", @@ -11787,6 +11840,15 @@ dependencies = [ "bridge-runtime-common", "frame-support", "frame-system", +======= + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "bp-xcm-bridge-hub-router 0.6.0", + "frame-support 28.0.0", + "frame-system 28.0.0", +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) "log", "pallet-balances", "pallet-bridge-messages", diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index e84bdc1004e5..fc5166d74405 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -13,8 +13,21 @@ workspace = true [dependencies] codec = { workspace = true } scale-info = { features = ["derive"], workspace = true } +<<<<<<< HEAD frame-support.workspace = true bp-xcm-bridge-hub-router.workspace = true +======= + +# Substrate Dependencies +frame-support = { workspace = true } +sp-core = { workspace = true } + +# Bridge Dependencies +bp-xcm-bridge-hub-router = { workspace = true } +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) + +# Polkadot dependencies +xcm = { workspace = true } [features] default = ["std"] @@ -23,4 +36,6 @@ std = [ "codec/std", "frame-support/std", "scale-info/std", + "sp-core/std", + "xcm/std", ] diff --git a/bridges/chains/chain-asset-hub-rococo/src/lib.rs b/bridges/chains/chain-asset-hub-rococo/src/lib.rs index de2e9ae856d1..4ff7b391acd0 100644 --- a/bridges/chains/chain-asset-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-asset-hub-rococo/src/lib.rs @@ -18,10 +18,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use codec::{Decode, Encode}; use scale_info::TypeInfo; pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; +use xcm::latest::prelude::*; /// `AssetHubRococo` Runtime `Call` enum. /// @@ -44,5 +47,27 @@ frame_support::parameter_types! { pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); } +/// Builds an (un)congestion XCM program with the `report_bridge_status` call for +/// `ToWestendXcmRouter`. +pub fn build_congestion_message( + bridge_id: sp_core::H256, + is_congested: bool, +) -> alloc::vec::Vec> { + alloc::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + fallback_max_weight: Some(XcmBridgeHubRouterTransactCallMaxWeight::get()), + call: Call::ToWestendXcmRouter(XcmBridgeHubRouterCall::report_bridge_status { + bridge_id, + is_congested, + }) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] +} + /// Identifier of AssetHubRococo in the Rococo relay chain. pub const ASSET_HUB_ROCOCO_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 776114b289db..26fda7a0ef15 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -13,8 +13,21 @@ workspace = true [dependencies] codec = { workspace = true } scale-info = { features = ["derive"], workspace = true } +<<<<<<< HEAD frame-support.workspace = true bp-xcm-bridge-hub-router.workspace = true +======= + +# Substrate Dependencies +frame-support = { workspace = true } +sp-core = { workspace = true } + +# Bridge Dependencies +bp-xcm-bridge-hub-router = { workspace = true } +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) + +# Polkadot dependencies +xcm = { workspace = true } [features] default = ["std"] @@ -23,4 +36,6 @@ std = [ "codec/std", "frame-support/std", "scale-info/std", + "sp-core/std", + "xcm/std", ] diff --git a/bridges/chains/chain-asset-hub-westend/src/lib.rs b/bridges/chains/chain-asset-hub-westend/src/lib.rs index 9de1c8809894..9d245e08f7cc 100644 --- a/bridges/chains/chain-asset-hub-westend/src/lib.rs +++ b/bridges/chains/chain-asset-hub-westend/src/lib.rs @@ -18,10 +18,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use codec::{Decode, Encode}; use scale_info::TypeInfo; pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; +use xcm::latest::prelude::*; /// `AssetHubWestend` Runtime `Call` enum. /// @@ -44,5 +47,27 @@ frame_support::parameter_types! { pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); } +/// Builds an (un)congestion XCM program with the `report_bridge_status` call for +/// `ToRococoXcmRouter`. +pub fn build_congestion_message( + bridge_id: sp_core::H256, + is_congested: bool, +) -> alloc::vec::Vec> { + alloc::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + fallback_max_weight: Some(XcmBridgeHubRouterTransactCallMaxWeight::get()), + call: Call::ToRococoXcmRouter(XcmBridgeHubRouterCall::report_bridge_status { + bridge_id, + is_congested, + }) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] +} + /// Identifier of AssetHubWestend in the Westend relay chain. pub const ASSET_HUB_WESTEND_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index c4f9f534c1a4..88a17b733f79 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -18,9 +18,13 @@ #![cfg(feature = "runtime-benchmarks")] +<<<<<<< HEAD use crate::{Bridge, Call}; use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR}; +======= +use crate::{Bridge, BridgeState, Call, MINIMAL_DELIVERY_FEE_FACTOR}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; use sp_runtime::traits::Zero; @@ -60,7 +64,10 @@ benchmarks_instance_pallet! { is_congested: false, delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, }); +<<<<<<< HEAD +======= +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) let _ = T::ensure_bridged_target_destination()?; T::make_congested(); }: { @@ -79,6 +86,7 @@ benchmarks_instance_pallet! { verify { assert!(Bridge::::get().is_congested); } +<<<<<<< HEAD send_message { let dest = T::ensure_bridged_target_destination()?; @@ -92,4 +100,6 @@ benchmarks_instance_pallet! { verify { assert!(Bridge::::get().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR); } +======= +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 3c56f54a72bc..39bba168b32e 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -30,9 +30,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +<<<<<<< HEAD use bp_xcm_bridge_hub_router::{ BridgeState, XcmChannelStatusProvider, MINIMAL_DELIVERY_FEE_FACTOR, }; +======= +pub use bp_xcm_bridge_hub_router::{BridgeState, XcmChannelStatusProvider}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use codec::Encode; use frame_support::traits::Get; use sp_core::H256; @@ -130,7 +134,11 @@ pub mod pallet { return T::WeightInfo::on_initialize_when_congested() } +<<<<<<< HEAD // if fee factor is already minimal, we don't change anything +======= + // if we can't decrease the delivery fee factor anymore, we don't change anything +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) if bridge.delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { return T::WeightInfo::on_initialize_when_congested() } @@ -138,12 +146,24 @@ pub mod pallet { let previous_factor = bridge.delivery_fee_factor; bridge.delivery_fee_factor = MINIMAL_DELIVERY_FEE_FACTOR.max(bridge.delivery_fee_factor / EXPONENTIAL_FEE_BASE); +<<<<<<< HEAD +======= + +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) log::info!( target: LOG_TARGET, "Bridge queue is uncongested. Decreased fee factor from {} to {}", previous_factor, bridge.delivery_fee_factor, ); +<<<<<<< HEAD +======= + Self::deposit_event(Event::DeliveryFeeFactorDecreased { + new_value: bridge.delivery_fee_factor, + }); + + Bridge::::put(bridge); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) Bridge::::put(bridge); T::WeightInfo::on_initialize_when_non_congested() @@ -197,7 +217,12 @@ pub mod pallet { "on_message_sent_to_bridge - message_size: {message_size:?}", ); let _ = Bridge::::try_mutate(|bridge| { +<<<<<<< HEAD let is_channel_with_bridge_hub_congested = T::WithBridgeHubChannel::is_congested(); +======= + let is_channel_with_bridge_hub_congested = + T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) let is_bridge_congested = bridge.is_congested; // if outbound queue is not congested AND bridge has not reported congestion, do @@ -220,7 +245,13 @@ pub mod pallet { previous_factor, bridge.delivery_fee_factor, ); +<<<<<<< HEAD +======= + Self::deposit_event(Event::DeliveryFeeFactorIncreased { + new_value: bridge.delivery_fee_factor, + }); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) Ok(()) }); } @@ -438,12 +469,22 @@ mod tests { fn fee_factor_is_not_decreased_from_on_initialize_when_xcm_channel_is_congested() { run_test(|| { Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); +<<<<<<< HEAD TestWithBridgeHubChannel::make_congested(); // it should not decrease, because xcm channel is congested let old_bridge = XcmBridgeHubRouter::bridge(); XcmBridgeHubRouter::on_initialize(One::one()); assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); +======= + TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); + + // it should not decrease, because queue is congested + let old_delivery = XcmBridgeHubRouter::bridge(); + XcmBridgeHubRouter::on_initialize(One::one()); + assert_eq!(XcmBridgeHubRouter::bridge(), old_delivery); + assert_eq!(System::events(), vec![]); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) }) } @@ -456,21 +497,42 @@ mod tests { let old_bridge = XcmBridgeHubRouter::bridge(); XcmBridgeHubRouter::on_initialize(One::one()); assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); +<<<<<<< HEAD +======= + assert_eq!(System::events(), vec![]); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) }) } #[test] fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() { run_test(|| { +<<<<<<< HEAD Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); // it should eventually decreased to one +======= + let initial_fee_factor = FixedU128::from_rational(125, 100); + Bridge::::put(uncongested_bridge(initial_fee_factor)); + + // it should eventually decrease to one +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) while XcmBridgeHubRouter::bridge().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR { XcmBridgeHubRouter::on_initialize(One::one()); } - // verify that it doesn't decreases anymore + // verify that it doesn't decrease anymore XcmBridgeHubRouter::on_initialize(One::one()); +<<<<<<< HEAD +======= + assert_eq!( + XcmBridgeHubRouter::bridge(), + uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR) + ); + + // check emitted event + let first_system_event = System::events().first().cloned(); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) assert_eq!( XcmBridgeHubRouter::bridge(), uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR) @@ -598,6 +660,31 @@ mod tests { fn sent_message_doesnt_increase_factor_if_xcm_channel_is_uncongested() { run_test(|| { let old_bridge = XcmBridgeHubRouter::bridge(); +<<<<<<< HEAD +======= + assert_eq!( + send_xcm::( + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), + vec![ClearOrigin].into(), + ) + .map(drop), + Ok(()), + ); + + assert!(TestToBridgeHubSender::is_message_sent()); + assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); + + assert_eq!(System::events(), vec![]); + }); + } + + #[test] + fn sent_message_increases_factor_if_xcm_channel_is_congested() { + run_test(|| { + TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); + + let old_bridge = XcmBridgeHubRouter::bridge(); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) assert_ok!(send_xcm::( Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), vec![ClearOrigin].into(), @@ -605,9 +692,47 @@ mod tests { .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); +<<<<<<< HEAD assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); }); } +======= + assert!( + old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor + ); + + // check emitted event + let first_system_event = System::events().first().cloned(); + assert!(matches!( + first_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter( + Event::DeliveryFeeFactorIncreased { .. } + ), + .. + }) + )); + }); + } + + #[test] + fn sent_message_increases_factor_if_bridge_has_reported_congestion() { + run_test(|| { + Bridge::::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)); + + let old_bridge = XcmBridgeHubRouter::bridge(); + assert_ok!(send_xcm::( + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), + vec![ClearOrigin].into(), + ) + .map(drop)); + + assert!(TestToBridgeHubSender::is_message_sent()); + assert!( + old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor + ); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) #[test] fn sent_message_increases_factor_if_xcm_channel_is_congested() { diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 276b9be5f743..1893d50f25fd 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -80,7 +80,11 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type DestinationVersion = LatestOrNoneForLocationVersionChecker>; +<<<<<<< HEAD type BridgeHubOrigin = EnsureRoot; +======= + type BridgeHubOrigin = frame_system::EnsureRoot; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) type ToBridgeHubSender = TestToBridgeHubSender; type WithBridgeHubChannel = TestWithBridgeHubChannel; diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index b0c8fc6252cd..af559b9d83eb 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -53,7 +53,10 @@ pub trait WeightInfo { fn on_initialize_when_non_congested() -> Weight; fn on_initialize_when_congested() -> Weight; fn report_bridge_status() -> Weight; +<<<<<<< HEAD fn send_message() -> Weight; +======= +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } /// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets. @@ -131,6 +134,19 @@ impl WeightInfo for BridgeWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) + /// + /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: + /// 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `53` + // Estimated: `1502` + // Minimum execution time: 10_427 nanoseconds. + Weight::from_parts(10_682_000, 1502) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -205,4 +221,17 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) + /// + /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: + /// 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `53` + // Estimated: `1502` + // Minimum execution time: 10_427 nanoseconds. + Weight::from_parts(10_682_000, 1502) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index fd08b3c600f7..a27030fd75f9 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -29,15 +29,26 @@ xcm-builder.workspace = true xcm-executor.workspace = true [dev-dependencies] +<<<<<<< HEAD bp-header-chain = { default-features = true, path = "../../primitives/header-chain" } pallet-balances = { default-features = true, path = "../../../substrate/frame/balances" } sp-io = { default-features = true, path = "../../../substrate/primitives/io" } +======= +pallet-balances = { workspace = true } +sp-io = { workspace = true } +bp-runtime = { workspace = true } +bp-header-chain = { workspace = true } +pallet-xcm-bridge-hub-router = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) [features] default = ["std"] std = [ "bp-messages/std", "bp-runtime/std", + "bp-xcm-bridge-hub-router/std", "bp-xcm-bridge-hub/std", "bridge-runtime-common/std", "codec/std", diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 94ec8b5f106f..3cefd18fbcbc 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -130,21 +130,114 @@ impl HaulBlob for DummyHaulBlob { #[cfg(test)] mod tests { use super::*; +<<<<<<< HEAD use crate::mock::*; use frame_support::assert_ok; use xcm_executor::traits::export_xcm; +======= + use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; + + use bp_runtime::RangeInclusiveExt; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; + use frame_support::{assert_ok, traits::EnsureOrigin}; + use pallet_bridge_messages::InboundLaneStorage; + use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; + use xcm_executor::traits::{export_xcm, ConvertLocation}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) fn universal_source() -> InteriorLocation { [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into() } +<<<<<<< HEAD fn universal_destination() -> InteriorLocation { BridgedDestination::get() +======= + fn bridged_relative_destination() -> InteriorLocation { + BridgedRelativeDestination::get() + } + + fn bridged_universal_destination() -> InteriorLocation { + BridgedUniversalDestination::get() + } + + fn open_lane(origin: RuntimeOrigin) -> (BridgeLocations, TestLaneIdType) { + // open expected outbound lane + let with = bridged_asset_hub_universal_location(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + + if !Bridges::::contains_key(locations.bridge_id()) { + // insert bridge + Bridges::::insert( + locations.bridge_id(), + Bridge { + bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location( + locations.bridge_origin_relative_location(), + ) + .expect("valid accountId"), + deposit: 0, + lane_id, + }, + ); + LaneToBridge::::insert(lane_id, locations.bridge_id()); + + // create lanes + let lanes_manager = LanesManagerOf::::new(); + if lanes_manager.create_inbound_lane(lane_id).is_ok() { + assert_eq!( + 0, + lanes_manager + .active_inbound_lane(lane_id) + .unwrap() + .storage() + .data() + .last_confirmed_nonce + ); + } + if lanes_manager.create_outbound_lane(lane_id).is_ok() { + assert!(lanes_manager + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + } + } + assert_ok!(XcmOverBridge::do_try_state()); + + (*locations, lane_id) + } + + fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) { + let (locations, lane_id) = open_lane(OpenBridgeOrigin::sibling_parachain_origin()); + + // now let's try to enqueue message using our `ExportXcm` implementation + export_xcm::( + BridgedRelayNetwork::get(), + 0, + locations.bridge_origin_universal_location().clone(), + locations.bridge_destination_universal_location().clone(), + vec![Instruction::ClearOrigin].into(), + ) + .unwrap(); + + (*locations.bridge_id(), lane_id) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } #[test] fn export_works() { run_test(|| { +<<<<<<< HEAD assert_ok!(export_xcm::( BridgedRelayNetwork::get(), 0, @@ -153,6 +246,108 @@ mod tests { vec![Instruction::ClearOrigin].into(), )); }) +======= + let (_, lane_id) = open_lane_and_send_regular_message(); + + // double check that the message has been pushed to the expected lane + // (it should already been checked during `send_message` call) + assert!(!LanesManagerOf::::new() + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + }); + } + + #[test] + fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() { + run_test(|| { + let (bridge_id, _) = open_lane_and_send_regular_message(); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + }); + } + + #[test] + fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() { + run_test(|| { + let (bridge_id, _) = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { + open_lane_and_send_regular_message(); + } + + open_lane_and_send_regular_message(); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); + }); + } + + #[test] + fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() { + run_test(|| { + let (bridge_id, _) = open_lane_and_send_regular_message(); + for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { + open_lane_and_send_regular_message(); + } + + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + + open_lane_and_send_regular_message(); + assert!(TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); + }); + } + + #[test] + fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() { + run_test(|| { + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, + ); + + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); + }); + } + + #[test] + fn bridge_is_not_resumed_if_it_was_not_suspended_before() { + run_test(|| { + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + }); + } + + #[test] + fn bridge_is_resumed_when_enough_messages_are_delivered() { + run_test(|| { + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + assert!(TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + }); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } #[test] @@ -187,6 +382,72 @@ mod tests { run_test(|| { let expected_lane_id = TEST_LANE_ID; +<<<<<<< HEAD +======= + let locations = BridgeLocations::bridge_locations( + UniversalLocation::get(), + SiblingLocation::get(), + bridged_universal_destination(), + BridgedRelayNetwork::get(), + ) + .unwrap(); + let expected_bridge_id = locations.bridge_id(); + let expected_lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + + if LanesManagerOf::::new() + .create_outbound_lane(expected_lane_id) + .is_ok() + { + Bridges::::insert( + expected_bridge_id, + Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + deposit: 0, + lane_id: expected_lane_id, + }, + ); + } + + let ticket = XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + // Note: The `ExportMessage` expects relative `InteriorLocation` in the + // `BridgedRelayNetwork`. + &mut Some(bridged_relative_destination()), + &mut Some(Vec::new().into()), + ) + .unwrap() + .0; + assert_eq!(&ticket.0, expected_bridge_id); + assert_eq!(ticket.1.lane_id, expected_lane_id); + }); + } + + #[test] + fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + + // open bridge + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let origin_as_location = + OpenBridgeOriginOf::::try_origin(origin.clone()).unwrap(); + let (_, expected_lane_id) = open_lane(origin); + + // check before - no messages +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) assert_eq!( XcmOverBridge::validate( BridgedRelayNetwork::get(), @@ -196,6 +457,7 @@ mod tests { &mut Some(Vec::new().into()), ) .unwrap() +<<<<<<< HEAD .0 .0 .lane, @@ -203,4 +465,209 @@ mod tests { ); }) } +======= + .queued_messages() + .saturating_len(), + 0 + ); + + // send `ExportMessage(message)` by `UnpaidRemoteExporter`. + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location); + assert_ok!(send_xcm::< + UnpaidRemoteExporter< + NetworkExportTable, + ExecuteXcmOverSendXcm, + UniversalLocation, + >, + >(dest.clone(), Xcm::<()>::default())); + + // we need to set `UniversalLocation` for `sibling_parachain_origin` for + // `XcmOverBridgeWrappedWithExportMessageRouterInstance`. + ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get())); + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. + ExecuteXcmOverSendXcm::set_origin_for_execute(SiblingLocation::get()); + assert_ok!(send_xcm::( + dest.clone(), + Xcm::<()>::default() + )); + + // check after - a message ready to be relayed + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .unwrap() + .queued_messages() + .saturating_len(), + 2 + ); + }) + } + + #[test] + fn validate_works() { + run_test(|| { + let xcm: Xcm<()> = vec![ClearOrigin].into(); + + // check that router does not consume when `NotApplicable` + let mut xcm_wrapper = Some(xcm.clone()); + let mut universal_source_wrapper = Some(universal_source()); + + // wrong `NetworkId` + let mut dest_wrapper = Some(bridged_relative_destination()); + assert_eq!( + XcmOverBridge::validate( + NetworkId::ByGenesis([0; 32]), + 0, + &mut universal_source_wrapper, + &mut dest_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!(&Some(bridged_relative_destination()), &dest_wrapper); + + // dest starts with wrong `NetworkId` + let mut invalid_dest_wrapper = Some( + [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(BRIDGED_ASSET_HUB_ID)] + .into(), + ); + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut invalid_dest_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!( + &Some( + [ + GlobalConsensus(NetworkId::ByGenesis([0; 32]),), + Parachain(BRIDGED_ASSET_HUB_ID) + ] + .into() + ), + &invalid_dest_wrapper + ); + + // no opened lane for dest + let mut dest_without_lane_wrapper = + Some([GlobalConsensus(BridgedRelayNetwork::get()), Parachain(5679)].into()); + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut dest_without_lane_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!( + &Some([GlobalConsensus(BridgedRelayNetwork::get(),), Parachain(5679)].into()), + &dest_without_lane_wrapper + ); + + // ok + let _ = open_lane(OpenBridgeOrigin::sibling_parachain_origin()); + let mut dest_wrapper = Some(bridged_relative_destination()); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut dest_wrapper, + &mut xcm_wrapper, + )); + // dest and xcm IS consumed + assert_eq!(None, xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!(None, dest_wrapper); + }); + } + + #[test] + fn congestion_with_pallet_xcm_bridge_hub_router_works() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + + fn router_bridge_state() -> pallet_xcm_bridge_hub_router::BridgeState { + pallet_xcm_bridge_hub_router::Bridge::< + TestRuntime, + XcmOverBridgeWrappedWithExportMessageRouterInstance, + >::get() + } + + // open two bridges + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let origin_as_location = + OpenBridgeOriginOf::::try_origin(origin.clone()).unwrap(); + let (bridge_1, expected_lane_id_1) = open_lane(origin); + + // we need to set `UniversalLocation` for `sibling_parachain_origin` for + // `XcmOverBridgeWrappedWithExportMessageRouterInstance`. + ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get())); + + // check before + // bridges are opened + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Opened + ); + + // the router is uncongested + assert!(!router_bridge_state().is_congested); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + + // make bridges congested with sending too much messages + for _ in 1..(OUTBOUND_LANE_CONGESTED_THRESHOLD + 2) { + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone()); + assert_ok!(send_xcm::( + dest.clone(), + Xcm::<()>::default() + )); + } + + // checks after + // bridges are suspended + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Suspended, + ); + // the router is congested + assert!(router_bridge_state().is_congested); + assert!(TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + + // make bridges uncongested to trigger resume signal + XcmOverBridge::on_bridge_messages_delivered( + expected_lane_id_1, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + // bridge is again opened + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Opened + ); + // the router is uncongested + assert!(!router_bridge_state().is_congested); + assert!(TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + }) + } +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 60b988497fc5..f7e09e372556 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -19,8 +19,20 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +<<<<<<< HEAD use bridge_runtime_common::messages_xcm_extension::XcmBlobHauler; use pallet_bridge_messages::Config as BridgeMessagesConfig; +======= +use bp_messages::{LaneState, MessageNonce}; +use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; +pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState, LocalXcmChannelManager}; +use bp_xcm_bridge_hub::{BridgeLocations, BridgeLocationsError}; +use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; +use frame_system::Config as SystemConfig; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; +use sp_runtime::traits::Zero; +use sp_std::{boxed::Box, vec::Vec}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use xcm::prelude::*; pub use exporter::PalletAsHaulBlobExporter; diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index df72e7a3c4fc..311abb5d95d2 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -23,16 +23,38 @@ use bp_messages::{ ChainWithMessages, LaneId, MessageNonce, }; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; +<<<<<<< HEAD use bridge_runtime_common::messages_xcm_extension::{SenderAndLane, XcmBlobHauler}; use codec::Encode; use frame_support::{derive_impl, parameter_types, weights::RuntimeDbWeight}; +======= +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; +use codec::{Decode, Encode}; +use frame_support::{ + assert_ok, derive_impl, parameter_types, + traits::{EnsureOrigin, Equals, Everything, Get, OriginTrait}, + weights::RuntimeDbWeight, +}; +use polkadot_parachain_primitives::primitives::Sibling; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use sp_core::H256; use sp_runtime::{ testing::Header as SubstrateHeader, traits::{BlakeTwo256, IdentityLookup}, AccountId32, BuildStorage, StateVersion, }; +<<<<<<< HEAD use xcm::prelude::*; +======= +use sp_std::cell::RefCell; +use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*}; +use xcm_builder::{ + AllowUnpaidExecutionFrom, DispatchBlob, DispatchBlobError, FixedWeightBounds, + InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, + SiblingParachainConvertsVia, +}; +use xcm_executor::{traits::ConvertOrigin, XcmExecutor}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) pub type AccountId = AccountId32; pub type Balance = u64; @@ -49,7 +71,12 @@ frame_support::construct_runtime! { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, +<<<<<<< HEAD XcmOverBridge: pallet_xcm_bridge_hub::{Pallet}, +======= + XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, HoldReason, Event}, + XcmOverBridgeWrappedWithExportMessageRouter: pallet_xcm_bridge_hub_router = 57, +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } } @@ -160,6 +187,173 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type LanesSupport = TestXcmBlobHauler; } +<<<<<<< HEAD +======= +/// A router instance simulates a scenario where the router is deployed on a different chain than +/// the `MessageExporter`. This means that the router sends an `ExportMessage`. +pub type XcmOverBridgeWrappedWithExportMessageRouterInstance = (); +impl pallet_xcm_bridge_hub_router::Config + for TestRuntime +{ + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + + type UniversalLocation = ExportMessageOriginUniversalLocation; + type SiblingBridgeHubLocation = BridgeHubLocation; + type BridgedNetworkId = BridgedRelayNetwork; + type Bridges = NetworkExportTable; + type DestinationVersion = AlwaysLatest; + + // We convert to root `here` location with `BridgeHubLocationXcmOriginAsRoot` + type BridgeHubOrigin = frame_system::EnsureRoot; + // **Note**: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which + // calls the `ExportXcm` implementation of `pallet_xcm_bridge_hub` as the + // `MessageExporter`. + type ToBridgeHubSender = ExecuteXcmOverSendXcm; + type LocalXcmChannelManager = TestLocalXcmChannelManager; + + type ByteFee = ConstU128<0>; + type FeeAsset = BridgeFeeAsset; +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = (); + type OriginConverter = BridgeHubLocationXcmOriginAsRoot; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = AllowUnpaidExecutionFrom; + type Weigher = FixedWeightBounds>; + type Trader = (); + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = (); + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + // We just set `MessageExporter` as our `pallet_xcm_bridge_hub` instance. + type MessageExporter = (XcmOverBridge,); + type UniversalAliases = (); + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = (); + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} + +thread_local! { + pub static EXECUTE_XCM_ORIGIN: RefCell> = RefCell::new(None); +} + +/// The `SendXcm` implementation directly executes XCM using `XcmExecutor`. +/// +/// We ensure that the `ExportMessage` produced by `pallet_xcm_bridge_hub_router` is compatible with +/// the `ExportXcm` implementation of `pallet_xcm_bridge_hub`. +/// +/// Note: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which calls the +/// `ExportXcm` implementation of `pallet_xcm_bridge_hub` as `MessageExporter`. +pub struct ExecuteXcmOverSendXcm; +impl SendXcm for ExecuteXcmOverSendXcm { + type Ticket = Xcm<()>; + + fn validate( + _: &mut Option, + message: &mut Option>, + ) -> SendResult { + Ok((message.take().unwrap(), Assets::new())) + } + + fn deliver(ticket: Self::Ticket) -> Result { + let xcm: Xcm = ticket.into(); + + let origin = EXECUTE_XCM_ORIGIN.with(|o| o.borrow().clone().unwrap()); + let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); + let outcome = XcmExecutor::::prepare_and_execute( + origin, + xcm, + &mut hash, + Weight::MAX, + Weight::zero(), + ); + assert_ok!(outcome.ensure_complete()); + + Ok(hash) + } +} +impl InspectMessageQueues for ExecuteXcmOverSendXcm { + fn clear_messages() { + todo!() + } + + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + todo!() + } +} +impl ExecuteXcmOverSendXcm { + pub fn set_origin_for_execute(origin: Location) { + EXECUTE_XCM_ORIGIN.with(|o| *o.borrow_mut() = Some(origin)); + } +} + +/// A dynamic way to set different universal location for the origin which sends `ExportMessage`. +pub struct ExportMessageOriginUniversalLocation; +impl ExportMessageOriginUniversalLocation { + pub(crate) fn set(universal_location: Option) { + EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION.with(|o| *o.borrow_mut() = universal_location); + } +} +impl Get for ExportMessageOriginUniversalLocation { + fn get() -> InteriorLocation { + EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION.with(|o| { + o.borrow() + .clone() + .expect("`EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION` is not set!") + }) + } +} +thread_local! { + pub static EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION: RefCell> = RefCell::new(None); +} + +pub struct BridgeHubLocationXcmOriginAsRoot( + sp_std::marker::PhantomData, +); +impl ConvertOrigin + for BridgeHubLocationXcmOriginAsRoot +{ + fn convert_origin( + origin: impl Into, + kind: OriginKind, + ) -> Result { + let origin = origin.into(); + if kind == OriginKind::Xcm && origin.eq(&BridgeHubLocation::get()) { + Ok(RuntimeOrigin::root()) + } else { + Err(origin) + } + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the parent `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, +); + +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) parameter_types! { pub TestSenderAndLane: SenderAndLane = SenderAndLane { location: Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]), @@ -173,6 +367,7 @@ parameter_types! { ]; } +<<<<<<< HEAD pub struct TestXcmBlobHauler; impl XcmBlobHauler for TestXcmBlobHauler { type Runtime = TestRuntime; @@ -180,6 +375,156 @@ impl XcmBlobHauler for TestXcmBlobHauler { type ToSourceChainSender = (); type CongestedMessage = (); type UncongestedMessage = (); +======= +impl EnsureOrigin for OpenBridgeOrigin { + type Success = Location; + + fn try_origin(o: RuntimeOrigin) -> Result { + let signer = o.clone().into_signer(); + if signer == Self::parent_relay_chain_origin().into_signer() { + return Ok(ParentRelayChainLocation::get()) + } else if signer == Self::parent_relay_chain_universal_origin().into_signer() { + return Ok(Location { + parents: 2, + interior: GlobalConsensus(RelayNetwork::get()).into(), + }) + } else if signer == Self::sibling_parachain_universal_origin().into_signer() { + return Ok(Location { + parents: 2, + interior: [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)] + .into(), + }) + } else if signer == Self::origin_without_sovereign_account().into_signer() { + return Ok(Location { + parents: 1, + interior: [Parachain(SIBLING_ASSET_HUB_ID), OnlyChild].into(), + }) + } + + let mut sibling_account = [0u8; 32]; + sibling_account[..4].copy_from_slice(&SIBLING_ASSET_HUB_ID.encode()[..4]); + if signer == Some(sibling_account.into()) { + return Ok(Location { parents: 1, interior: Parachain(SIBLING_ASSET_HUB_ID).into() }) + } + + Err(o) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(Self::parent_relay_chain_origin()) + } +} + +pub(crate) type OpenBridgeOriginOf = + >::OpenBridgeOrigin; + +pub struct TestLocalXcmChannelManager; + +impl TestLocalXcmChannelManager { + pub fn make_congested() { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Congested", &true); + } + + fn suspended_key(bridge: &BridgeId) -> Vec { + [b"TestLocalXcmChannelManager.Suspended", bridge.encode().as_slice()].concat() + } + fn resumed_key(bridge: &BridgeId) -> Vec { + [b"TestLocalXcmChannelManager.Resumed", bridge.encode().as_slice()].concat() + } + + pub fn is_bridge_suspended(bridge: &BridgeId) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::suspended_key(bridge)) + } + + pub fn is_bridge_resumed(bridge: &BridgeId) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::resumed_key(bridge)) + } + + fn build_congestion_message(bridge: &BridgeId, is_congested: bool) -> Vec> { + use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; + #[allow(clippy::large_enum_variant)] + #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, scale_info::TypeInfo)] + enum Call { + #[codec(index = 57)] + XcmOverBridgeWrappedWithExportMessageRouter(XcmBridgeHubRouterCall), + } + + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + fallback_max_weight: None, + call: Call::XcmOverBridgeWrappedWithExportMessageRouter( + XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: bridge.inner(), + is_congested, + } + ) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] + } + + fn report_bridge_status( + local_origin: &Location, + bridge: &BridgeId, + is_congested: bool, + key: Vec, + ) -> Result<(), SendError> { + // send as BridgeHub would send to sibling chain + ExecuteXcmOverSendXcm::set_origin_for_execute(BridgeHubLocation::get()); + let result = send_xcm::( + local_origin.clone(), + Self::build_congestion_message(&bridge, is_congested).into(), + ); + + if result.is_ok() { + frame_support::storage::unhashed::put(&key, &true); + } + + result.map(|_| ()) + } +} + +impl LocalXcmChannelManager for TestLocalXcmChannelManager { + type Error = SendError; + + fn is_congested(_with: &Location) -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Congested") + } + + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + Self::report_bridge_status(local_origin, &bridge, true, Self::suspended_key(&bridge)) + } + + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + Self::report_bridge_status(local_origin, &bridge, false, Self::resumed_key(&bridge)) + } +} + +impl pallet_xcm_bridge_hub_router::XcmChannelStatusProvider for TestLocalXcmChannelManager { + fn is_congested(with: &Location) -> bool { + ::is_congested(with) + } +} + +pub struct TestBlobDispatcher; + +impl TestBlobDispatcher { + pub fn is_dispatched() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestBlobDispatcher.Dispatched") + } +} + +impl DispatchBlob for TestBlobDispatcher { + fn dispatch_blob(_blob: Vec) -> Result<(), DispatchBlobError> { + frame_support::storage::unhashed::put(b"TestBlobDispatcher.Dispatched", &true); + Ok(()) + } +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } pub struct ThisUnderlyingChain; diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 9745011c902d..0ca8446b7cc9 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -22,3 +22,674 @@ /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. pub type XcmAsPlainPayload = sp_std::vec::Vec; +<<<<<<< HEAD +======= + +/// Bridge identifier - used **only** for communicating with sibling/parent chains in the same +/// consensus. +/// +/// For example, `SendXcm` implementations (which use the `latest` XCM) can use it to identify a +/// bridge and the corresponding `LaneId` that is used for over-consensus communication between +/// bridge hubs. +/// +/// This identifier is constructed from the `latest` XCM, so it is expected to ensure migration to +/// the `latest` XCM version. This could change the `BridgeId`, but it will not affect the `LaneId`. +/// In other words, `LaneId` will never change, while `BridgeId` could change with (every) XCM +/// upgrade. +#[derive( + Clone, + Copy, + Decode, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct BridgeId(H256); + +impl BridgeId { + /// Create bridge identifier from two universal locations. + /// + /// Note: The `BridgeId` is constructed from `latest` XCM, so if stored, you need to ensure + /// compatibility with newer XCM versions. + pub fn new( + universal_source: &InteriorLocation, + universal_destination: &InteriorLocation, + ) -> Self { + const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator"; + + BridgeId( + (universal_source, VALUES_SEPARATOR, universal_destination) + .using_encoded(blake2_256) + .into(), + ) + } + + /// Access the inner representation. + pub fn inner(&self) -> H256 { + self.0 + } +} + +impl core::fmt::Debug for BridgeId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.0, f) + } +} + +/// Local XCM channel manager. +pub trait LocalXcmChannelManager { + /// Error that may be returned when suspending/resuming the bridge. + type Error: sp_std::fmt::Debug; + + /// Returns true if the channel with given location is currently congested. + /// + /// The `with` is guaranteed to be in the same consensus. However, it may point to something + /// below the chain level - like the contract or pallet instance, for example. + fn is_congested(with: &Location) -> bool; + + /// Suspend the bridge, opened by given origin. + /// + /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to + /// something below the chain level - like the contract or pallet instance, for example. + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; + + /// Resume the previously suspended bridge, opened by given origin. + /// + /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to + /// something below the chain level - like the contract or pallet instance, for example. + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; +} + +impl LocalXcmChannelManager for () { + type Error = (); + + fn is_congested(_with: &Location) -> bool { + false + } + + fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) + } + + fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) + } +} + +/// Bridge state. +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum BridgeState { + /// Bridge is opened. Associated lanes are also opened. + Opened, + /// Bridge is suspended. Associated lanes are opened. + /// + /// We keep accepting messages to the bridge. The only difference with the `Opened` state + /// is that we have sent the "Suspended" message/signal to the local bridge origin. + Suspended, + /// Bridge is closed. Associated lanes are also closed. + /// After all outbound messages will be pruned, the bridge will vanish without any traces. + Closed, +} + +/// Bridge metadata. +#[derive( + CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(ThisChain, LaneId))] +pub struct Bridge { + /// Relative location of the bridge origin chain. This is expected to be **convertible** to the + /// `latest` XCM, so the check and migration needs to be ensured. + pub bridge_origin_relative_location: Box, + + /// See [`BridgeLocations::bridge_origin_universal_location`]. + /// Stored for `BridgeId` sanity check. + pub bridge_origin_universal_location: Box, + /// See [`BridgeLocations::bridge_destination_universal_location`]. + /// Stored for `BridgeId` sanity check. + pub bridge_destination_universal_location: Box, + + /// Current bridge state. + pub state: BridgeState, + /// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`. + pub bridge_owner_account: AccountIdOf, + /// Reserved amount on the sovereign account of the sibling bridge origin. + pub deposit: BalanceOf, + + /// Mapping to the unique `LaneId`. + pub lane_id: LaneId, +} + +/// Locations of bridge endpoints at both sides of the bridge. +#[derive(Clone, RuntimeDebug, PartialEq, Eq)] +pub struct BridgeLocations { + /// Relative (to this bridge hub) location of this side of the bridge. + bridge_origin_relative_location: Location, + /// Universal (unique) location of this side of the bridge. + bridge_origin_universal_location: InteriorLocation, + /// Universal (unique) location of other side of the bridge. + bridge_destination_universal_location: InteriorLocation, + /// An identifier of the dedicated bridge message lane. + bridge_id: BridgeId, +} + +/// Errors that may happen when we check bridge locations. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum BridgeLocationsError { + /// Origin or destination locations are not universal. + NonUniversalLocation, + /// Bridge origin location is not supported. + InvalidBridgeOrigin, + /// Bridge destination is not supported (in general). + InvalidBridgeDestination, + /// Destination location is within the same global consensus. + DestinationIsLocal, + /// Destination network is not the network we are bridged with. + UnreachableDestination, + /// Destination location is unsupported. We only support bridges with relay + /// chain or its parachains. + UnsupportedDestinationLocation, + /// The version of XCM location argument is unsupported. + UnsupportedXcmVersion, + /// The `LaneIdType` generator is not supported. + UnsupportedLaneIdType, +} + +impl BridgeLocations { + /// Given XCM locations, generate lane id and universal locations of bridge endpoints. + /// + /// The `here_universal_location` is the universal location of the bridge hub runtime. + /// + /// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`) + /// location of the bridge endpoint at this side of the bridge. It may be the parent relay + /// chain or the sibling parachain. All junctions below parachain level are dropped. + /// + /// The `bridge_destination_universal_location` is the universal location of the bridge + /// destination. It may be the parent relay or the sibling parachain of the **bridged** + /// bridge hub. All junctions below parachain level are dropped. + /// + /// Why we drop all junctions between parachain level - that's because the lane is a bridge + /// between two chains. All routing under this level happens when the message is delivered + /// to the bridge destination. So at bridge level we don't care about low level junctions. + /// + /// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location` + /// local consensus OR if `bridge_destination_universal_location` is not a universal location. + pub fn bridge_locations( + here_universal_location: InteriorLocation, + bridge_origin_relative_location: Location, + bridge_destination_universal_location: InteriorLocation, + expected_remote_network: NetworkId, + ) -> Result, BridgeLocationsError> { + fn strip_low_level_junctions( + location: InteriorLocation, + ) -> Result { + let mut junctions = location.into_iter(); + + let global_consensus = junctions + .next() + .filter(|junction| matches!(junction, GlobalConsensus(_))) + .ok_or(BridgeLocationsError::NonUniversalLocation)?; + + // we only expect `Parachain` junction here. There are other junctions that + // may need to be supported (like `GeneralKey` and `OnlyChild`), but now we + // only support bridges with relay and parachans + // + // if there's something other than parachain, let's strip it + let maybe_parachain = + junctions.next().filter(|junction| matches!(junction, Parachain(_))); + Ok(match maybe_parachain { + Some(parachain) => [global_consensus, parachain].into(), + None => [global_consensus].into(), + }) + } + + // ensure that the `here_universal_location` and `bridge_destination_universal_location` + // are universal locations within different consensus systems + let local_network = here_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + let remote_network = bridge_destination_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + ensure!(local_network != remote_network, BridgeLocationsError::DestinationIsLocal); + ensure!( + remote_network == expected_remote_network, + BridgeLocationsError::UnreachableDestination + ); + + // get universal location of endpoint, located at this side of the bridge + let bridge_origin_universal_location = here_universal_location + .within_global(bridge_origin_relative_location.clone()) + .map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?; + // strip low-level junctions within universal locations + let bridge_origin_universal_location = + strip_low_level_junctions(bridge_origin_universal_location)?; + let bridge_destination_universal_location = + strip_low_level_junctions(bridge_destination_universal_location)?; + + // we know that the `bridge_destination_universal_location` starts from the + // `GlobalConsensus` and we know that the `bridge_origin_universal_location` + // is also within the `GlobalConsensus`. So we know that the lane id will be + // the same on both ends of the bridge + let bridge_id = BridgeId::new( + &bridge_origin_universal_location, + &bridge_destination_universal_location, + ); + + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location, + bridge_origin_universal_location, + bridge_destination_universal_location, + bridge_id, + })) + } + + /// Getter for `bridge_origin_relative_location` + pub fn bridge_origin_relative_location(&self) -> &Location { + &self.bridge_origin_relative_location + } + + /// Getter for `bridge_origin_universal_location` + pub fn bridge_origin_universal_location(&self) -> &InteriorLocation { + &self.bridge_origin_universal_location + } + + /// Getter for `bridge_destination_universal_location` + pub fn bridge_destination_universal_location(&self) -> &InteriorLocation { + &self.bridge_destination_universal_location + } + + /// Getter for `bridge_id` + pub fn bridge_id(&self) -> &BridgeId { + &self.bridge_id + } + + /// Generates the exact same `LaneId` on the both bridge hubs. + /// + /// Note: Use this **only** when opening a new bridge. + pub fn calculate_lane_id( + &self, + xcm_version: XcmVersion, + ) -> Result { + // a tricky helper struct that adds required `Ord` support for + // `VersionedInteriorLocation` + #[derive(Eq, PartialEq, Ord, PartialOrd)] + struct EncodedVersionedInteriorLocation(sp_std::vec::Vec); + impl Encode for EncodedVersionedInteriorLocation { + fn encode(&self) -> sp_std::vec::Vec { + self.0.clone() + } + } + + let universal_location1 = + VersionedInteriorLocation::from(self.bridge_origin_universal_location.clone()) + .into_version(xcm_version) + .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); + let universal_location2 = + VersionedInteriorLocation::from(self.bridge_destination_universal_location.clone()) + .into_version(xcm_version) + .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); + + LaneId::try_new( + EncodedVersionedInteriorLocation(universal_location1.encode()), + EncodedVersionedInteriorLocation(universal_location2.encode()), + ) + .map_err(|_| BridgeLocationsError::UnsupportedLaneIdType) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use xcm::latest::ROCOCO_GENESIS_HASH; + + const LOCAL_NETWORK: NetworkId = Kusama; + const REMOTE_NETWORK: NetworkId = Polkadot; + const UNREACHABLE_NETWORK: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); + const SIBLING_PARACHAIN: u32 = 1000; + const LOCAL_BRIDGE_HUB: u32 = 1001; + const REMOTE_PARACHAIN: u32 = 2000; + + struct SuccessfulTest { + here_universal_location: InteriorLocation, + bridge_origin_relative_location: Location, + + bridge_origin_universal_location: InteriorLocation, + bridge_destination_universal_location: InteriorLocation, + + expected_remote_network: NetworkId, + } + + fn run_successful_test(test: SuccessfulTest) -> BridgeLocations { + let locations = BridgeLocations::bridge_locations( + test.here_universal_location, + test.bridge_origin_relative_location.clone(), + test.bridge_destination_universal_location.clone(), + test.expected_remote_network, + ); + assert_eq!( + locations, + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location: test.bridge_origin_relative_location, + bridge_origin_universal_location: test.bridge_origin_universal_location.clone(), + bridge_destination_universal_location: test + .bridge_destination_universal_location + .clone(), + bridge_id: BridgeId::new( + &test.bridge_origin_universal_location, + &test.bridge_destination_universal_location, + ), + })), + ); + + *locations.unwrap() + } + + // successful tests that with various origins and destinations + + #[test] + fn at_relay_from_local_relay_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_relay_from_sibling_parachain_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_relay_from_local_relay_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_relay_from_sibling_parachain_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_local_relay_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: Parent.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_sibling_parachain_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_local_relay_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: Parent.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_sibling_parachain_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + // successful tests that show that we are ignoring low-level junctions of bridge origins + + #[test] + fn low_level_junctions_at_bridge_origin_are_stripped() { + let locations1 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + let locations2 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [PalletInstance(0)].into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + assert_eq!(locations1.bridge_id, locations2.bridge_id); + } + + #[test] + fn low_level_junctions_at_bridge_destination_are_stripped() { + let locations1 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + let locations2 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + assert_eq!(locations1.bridge_id, locations2.bridge_id); + } + + #[test] + fn calculate_lane_id_works() { + type TestLaneId = bp_messages::HashedLaneId; + + let from_local_to_remote = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + let from_remote_to_local = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(REMOTE_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(REMOTE_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + + expected_remote_network: LOCAL_NETWORK, + }); + + assert_ne!( + from_local_to_remote.calculate_lane_id::(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id::(xcm::latest::VERSION - 1), + ); + assert_eq!( + from_local_to_remote.calculate_lane_id::(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id::(xcm::latest::VERSION), + ); + } + + // negative tests + + #[test] + fn bridge_locations_fails_when_here_is_not_universal_location() { + assert_eq!( + BridgeLocations::bridge_locations( + [Parachain(1000)].into(), + Here.into(), + [GlobalConsensus(REMOTE_NETWORK)].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::NonUniversalLocation), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_not_universal_location() { + assert_eq!( + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [OnlyChild].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::NonUniversalLocation), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_local() { + assert_eq!( + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [GlobalConsensus(LOCAL_NETWORK), OnlyChild].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::DestinationIsLocal), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_unreachable() { + assert_eq!( + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [GlobalConsensus(UNREACHABLE_NETWORK)].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::UnreachableDestination), + ); + } +} +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index ed1141a68eb9..a957af83e063 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -911,6 +911,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; +<<<<<<< HEAD #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; #[cfg(feature = "runtime-benchmarks")] @@ -921,6 +922,12 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim EnsureXcm>, >; +======= + type BridgeHubOrigin = frame_support::traits::EitherOfDiverse< + EnsureRoot, + EnsureXcm>, + >; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) type ToBridgeHubSender = XcmpQueue; type WithBridgeHubChannel = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 0a86037391b4..b21fa62ba15d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,15 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +<<<<<<< HEAD //! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +======= +//! DATE: 2024-12-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -58,8 +64,13 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `154` // Estimated: `5487` +<<<<<<< HEAD // Minimum execution time: 8_078_000 picoseconds. Weight::from_parts(8_455_000, 0) +======= + // Minimum execution time: 13_884_000 picoseconds. + Weight::from_parts(14_312_000, 0) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +83,13 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `5487` +<<<<<<< HEAD // Minimum execution time: 4_291_000 picoseconds. Weight::from_parts(4_548_000, 0) +======= + // Minimum execution time: 6_909_000 picoseconds. + Weight::from_parts(7_115_000, 0) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,12 +99,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` +<<<<<<< HEAD // Minimum execution time: 9_959_000 picoseconds. Weight::from_parts(10_372_000, 0) +======= + // Minimum execution time: 12_394_000 picoseconds. + Weight::from_parts(12_883_000, 0) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } +<<<<<<< HEAD /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) @@ -123,4 +145,6 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } +======= +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 5374a956bfac..4b8ddfbc556b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -27,7 +27,12 @@ use asset_hub_rococo_runtime::{ AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, Block, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, +<<<<<<< HEAD RuntimeEvent, RuntimeOrigin, SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, +======= + RuntimeEvent, RuntimeOrigin, SessionKeys, ToWestendXcmRouterInstance, + TrustBackedAssetsInstance, XcmpQueue, +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -1276,6 +1281,7 @@ mod asset_hub_rococo_tests { >( collator_session_keys(), bridging_to_asset_hub_westend, +<<<<<<< HEAD || { vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, @@ -1314,6 +1320,10 @@ mod asset_hub_rococo_tests { ] .into() }, +======= + || bp_asset_hub_rococo::build_congestion_message(Default::default(), true).into(), + || bp_asset_hub_rococo::build_congestion_message(Default::default(), false).into(), +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) ) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index ba7cf6528422..205c6295523f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -46,7 +46,11 @@ use frame_support::{ fungible, fungibles, tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Equals, +<<<<<<< HEAD InstanceFilter, TransformOrigin, +======= + InstanceFilter, Nothing, TransformOrigin, +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -57,6 +61,10 @@ use frame_system::{ }; use pallet_asset_conversion_tx_payment::AssetConversionAdapter; use pallet_nfts::{DestroyWitness, PalletFeatures}; +<<<<<<< HEAD +======= +use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use pallet_xcm::EnsureXcm; use parachains_common::{ impls::DealWithFees, message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, @@ -900,6 +908,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; +<<<<<<< HEAD #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; #[cfg(feature = "runtime-benchmarks")] @@ -910,6 +919,12 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime EnsureXcm>, >; +======= + type BridgeHubOrigin = frame_support::traits::EitherOfDiverse< + EnsureRoot, + EnsureXcm>, + >; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) type ToBridgeHubSender = XcmpQueue; type WithBridgeHubChannel = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index 21d15c75af55..88bb0e632a76 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,15 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +<<<<<<< HEAD //! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +======= +//! DATE: 2024-12-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -56,10 +62,17 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: +<<<<<<< HEAD // Measured: `226` // Estimated: `5487` // Minimum execution time: 8_363_000 picoseconds. Weight::from_parts(8_620_000, 0) +======= + // Measured: `259` + // Estimated: `5487` + // Minimum execution time: 14_643_000 picoseconds. + Weight::from_parts(14_992_000, 0) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -70,10 +83,15 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `111` + // Measured: `144` // Estimated: `5487` +<<<<<<< HEAD // Minimum execution time: 3_436_000 picoseconds. Weight::from_parts(3_586_000, 0) +======= + // Minimum execution time: 5_367_000 picoseconds. + Weight::from_parts(5_604_000, 0) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,12 +101,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` +<<<<<<< HEAD // Minimum execution time: 9_706_000 picoseconds. Weight::from_parts(10_139_000, 0) +======= + // Minimum execution time: 12_562_000 picoseconds. + Weight::from_parts(12_991_000, 0) +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } +<<<<<<< HEAD /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) @@ -123,4 +147,6 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } +======= +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 2620fc93992b..e26526d62c08 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -1257,6 +1257,7 @@ fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { >( collator_session_keys(), bridging_to_asset_hub_rococo, +<<<<<<< HEAD || { vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, @@ -1295,6 +1296,10 @@ fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { ] .into() }, +======= + || bp_asset_hub_westend::build_congestion_message(Default::default(), true).into(), + || bp_asset_hub_westend::build_congestion_message(Default::default(), false).into(), +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) ) } @@ -1321,8 +1326,13 @@ fn test_report_bridge_status_call_compatibility() { fn check_sane_weight_report_bridge_status() { use pallet_xcm_bridge_hub_router::WeightInfo; let actual = >::WeightInfo::report_bridge_status(); +======= + ToRococoXcmRouterInstance, + >>::WeightInfo::report_bridge_status(); +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) let max_weight = bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(); assert!( actual.all_lte(max_weight), diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index de5670093b0a..36fae43ba71b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -75,6 +75,7 @@ pallet-collator-selection.workspace = true parachain-info.workspace = true parachains-common.workspace = true testnet-parachains-constants = { features = ["rococo"], workspace = true } +<<<<<<< HEAD bp-asset-hub-rococo.workspace = true bp-asset-hub-westend.workspace = true bp-bridge-hub-polkadot.workspace = true @@ -106,6 +107,45 @@ snowbridge-outbound-queue-runtime-api.workspace = true snowbridge-router-primitives.workspace = true snowbridge-runtime-common.workspace = true bridge-hub-common.workspace = true +======= + +# Bridges +bp-asset-hub-rococo = { workspace = true } +bp-asset-hub-westend = { workspace = true } +bp-bridge-hub-polkadot = { workspace = true } +bp-bridge-hub-rococo = { workspace = true } +bp-bridge-hub-westend = { workspace = true } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-bulletin = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { workspace = true } +bp-rococo = { workspace = true } +bp-westend = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } +pallet-bridge-relayers = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } +bridge-runtime-common = { workspace = true } + +# Ethereum Bridge (Snowbridge) +snowbridge-beacon-primitives = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-system-runtime-api = { workspace = true } +snowbridge-core = { workspace = true } +snowbridge-pallet-ethereum-client = { workspace = true } +snowbridge-pallet-inbound-queue = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-outbound-queue-runtime-api = { workspace = true } +snowbridge-router-primitives = { workspace = true } +snowbridge-runtime-common = { workspace = true } + +bridge-hub-common = { workspace = true } +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) [dev-dependencies] bridge-hub-test-utils = { default-features = true, path = "../test-utils" } @@ -132,6 +172,7 @@ std = [ "bp-rococo/std", "bp-runtime/std", "bp-westend/std", + "bp-xcm-bridge-hub-router/std", "bridge-hub-common/std", "bridge-runtime-common/std", "codec/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index fe854e20c244..543883f26820 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -20,7 +20,12 @@ use crate::{ bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, weights, xcm_config::UniversalLocation, +<<<<<<< HEAD BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubWestend, XcmRouter, +======= + AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, XcmpQueue, +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, @@ -37,6 +42,11 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, }; +<<<<<<< HEAD +======= +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; +use pallet_xcm_bridge_hub::{BridgeId, XcmAsPlainPayload}; +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; @@ -199,8 +209,113 @@ impl pallet_xcm_bridge_hub::Config for Runtime type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; +<<<<<<< HEAD type Lanes = ActiveLanes; type LanesSupport = ToBridgeHubWestendXcmBlobHauler; +======= + + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance with `LegacyLaneId`. + type OpenBridgeOrigin = EnsureNever; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; + + type LocalXcmChannelManager = CongestionManager; + type BlobDispatcher = FromWestendMessageBlobDispatcher; +} + +/// Implementation of `bp_xcm_bridge_hub::LocalXcmChannelManager` for congestion management. +pub struct CongestionManager; +impl pallet_xcm_bridge_hub::LocalXcmChannelManager for CongestionManager { + type Error = SendError; + + fn is_congested(with: &Location) -> bool { + // This is used to check the inbound bridge queue/messages to determine if they can be + // dispatched and sent to the sibling parachain. Therefore, checking outbound `XcmpQueue` + // is sufficient here. + use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::::is_congested( + with, + ) + } + + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_rococo::build_congestion_message(bridge.inner(), true).into(), + ) + .map(|_| ()) + } + + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_rococo::build_congestion_message(bridge.inner(), false).into(), + ) + .map(|_| ()) + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, + sibling_para_id: u32, +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation}; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = + [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into(); + let universal_destination = + [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); + + universal_source +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } #[cfg(test)] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 7d71c45062a8..f7d1aef4a783 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -71,6 +71,7 @@ pallet-collator-selection.workspace = true parachain-info.workspace = true parachains-common.workspace = true testnet-parachains-constants = { features = ["westend"], workspace = true } +<<<<<<< HEAD bp-asset-hub-rococo.workspace = true bp-asset-hub-westend.workspace = true bp-bridge-hub-rococo.workspace = true @@ -90,6 +91,43 @@ pallet-bridge-relayers.workspace = true pallet-xcm-bridge-hub.workspace = true bridge-runtime-common.workspace = true bridge-hub-common.workspace = true +======= + +# Bridges +bp-asset-hub-rococo = { workspace = true } +bp-asset-hub-westend = { workspace = true } +bp-bridge-hub-rococo = { workspace = true } +bp-bridge-hub-westend = { workspace = true } +bp-header-chain = { workspace = true } +bp-messages = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-relayers = { workspace = true } +bp-runtime = { workspace = true } +bp-rococo = { workspace = true } +bp-westend = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +pallet-bridge-grandpa = { workspace = true } +pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } +pallet-bridge-relayers = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } +bridge-runtime-common = { workspace = true } +bridge-hub-common = { workspace = true } + +# Ethereum Bridge (Snowbridge) +snowbridge-beacon-primitives = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-system-runtime-api = { workspace = true } +snowbridge-core = { workspace = true } +snowbridge-pallet-ethereum-client = { workspace = true } +snowbridge-pallet-inbound-queue = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-outbound-queue-runtime-api = { workspace = true } +snowbridge-router-primitives = { workspace = true } +snowbridge-runtime-common = { workspace = true } + +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) [dev-dependencies] bridge-hub-test-utils = { default-features = true, path = "../test-utils" } @@ -114,6 +152,7 @@ std = [ "bp-rococo/std", "bp-runtime/std", "bp-westend/std", + "bp-xcm-bridge-hub-router/std", "bridge-hub-common/std", "bridge-runtime-common/std", "codec/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 42d5ef3eebdb..55eade9c05b7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -17,14 +17,23 @@ //! Bridge definitions used on BridgeHub with the Westend flavor. use crate::{ +<<<<<<< HEAD bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubRococo, XcmRouter, +======= + bridge_common_config::{DeliveryRewardInBalance, RelayersForLegacyLaneIdsMessagesInstance}, + weights, + xcm_config::UniversalLocation, + AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, XcmpQueue, +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, LaneId, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; +<<<<<<< HEAD use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ @@ -37,6 +46,11 @@ use bridge_runtime_common::{ }, }; use codec::Encode; +======= +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; +use pallet_xcm_bridge_hub::{BridgeId, XcmAsPlainPayload}; + +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) use frame_support::{ parameter_types, traits::{ConstU32, PalletInfoAccess}, @@ -229,8 +243,113 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance; type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; +<<<<<<< HEAD type Lanes = ActiveLanes; type LanesSupport = ToBridgeHubRococoXcmBlobHauler; +======= + + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance with `LegacyLaneId`. + type OpenBridgeOrigin = EnsureNever; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; + + type LocalXcmChannelManager = CongestionManager; + type BlobDispatcher = FromRococoMessageBlobDispatcher; +} + +/// Implementation of `bp_xcm_bridge_hub::LocalXcmChannelManager` for congestion management. +pub struct CongestionManager; +impl pallet_xcm_bridge_hub::LocalXcmChannelManager for CongestionManager { + type Error = SendError; + + fn is_congested(with: &Location) -> bool { + // This is used to check the inbound bridge queue/messages to determine if they can be + // dispatched and sent to the sibling parachain. Therefore, checking outbound `XcmpQueue` + // is sufficient here. + use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::::is_congested( + with, + ) + } + + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_westend::build_congestion_message(bridge.inner(), true).into(), + ) + .map(|_| ()) + } + + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_westend::build_congestion_message(bridge.inner(), false).into(), + ) + .map(|_| ()) + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, + sibling_para_id: u32, +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::{latest::WESTEND_GENESIS_HASH, VersionedInteriorLocation}; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = + [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(sibling_para_id)].into(); + let universal_destination = + [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); + + universal_source +>>>>>>> 8f4b99c (Bridges - revert-back congestion mechanism (#6781)) } #[cfg(test)] diff --git a/prdoc/pr_6781.prdoc b/prdoc/pr_6781.prdoc new file mode 100644 index 000000000000..8090be420341 --- /dev/null +++ b/prdoc/pr_6781.prdoc @@ -0,0 +1,28 @@ +title: Bridges - revert-back congestion mechanism + +doc: +- audience: Runtime Dev + description: |- + With [permissionless lanes PR#4949](https://github.com/paritytech/polkadot-sdk/pull/4949), the congestion mechanism based on sending `Transact(report_bridge_status(is_congested))` from `pallet-xcm-bridge-hub` to `pallet-xcm-bridge-hub-router` was replaced with a congestion mechanism that relied on monitoring XCMP queues. However, this approach could cause issues, such as suspending the entire XCMP queue instead of isolating the affected bridge. This PR reverts back to using `report_bridge_status` as before. + +crates: +- name: pallet-xcm-bridge-hub-router + bump: patch +- name: pallet-xcm-bridge-hub + bump: patch +- name: bp-xcm-bridge-hub + bump: patch +- name: bp-asset-hub-rococo + bump: patch +- name: bp-asset-hub-westend + bump: patch +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: asset-test-utils + bump: patch +- name: bridge-hub-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch