From 152389ab5474f88e53ca53e8bd1b073aaf2922b2 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 5 Nov 2024 13:31:59 +0100 Subject: [PATCH] Adapt testnet runtimes to latest congestion changes --- Cargo.lock | 1 - .../xcm-bridge-hub-router/src/impls.rs | 104 +++++++++++++++++- .../modules/xcm-bridge-hub-router/src/lib.rs | 4 +- .../modules/xcm-bridge-hub-router/src/mock.rs | 3 +- bridges/modules/xcm-bridge-hub/Cargo.toml | 1 - .../modules/xcm-bridge-hub/src/exporter.rs | 4 +- bridges/modules/xcm-bridge-hub/src/mock.rs | 23 +--- cumulus/pallets/xcmp-queue/src/bridging.rs | 28 ----- cumulus/pallets/xcmp-queue/src/lib.rs | 5 - .../assets/asset-hub-rococo/src/lib.rs | 26 +++-- .../weights/pallet_xcm_bridge_hub_router.rs | 20 ++++ .../assets/asset-hub-rococo/tests/tests.rs | 66 +++++++++-- .../assets/asset-hub-westend/src/lib.rs | 27 +++-- .../weights/pallet_xcm_bridge_hub_router.rs | 20 ++++ .../assets/asset-hub-westend/tests/tests.rs | 66 +++++++++-- .../test-utils/src/test_cases_over_bridge.rs | 26 +++-- .../src/bridge_to_bulletin_config.rs | 16 +-- .../src/bridge_to_westend_config.rs | 36 ++++-- .../src/bridge_to_rococo_config.rs | 36 ++++-- .../test-utils/src/test_cases/mod.rs | 3 +- 20 files changed, 384 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac4ab6e9e948c..828acec524783 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13241,7 +13241,6 @@ dependencies = [ "bp-messages", "bp-runtime", "bp-xcm-bridge-hub", - "bp-xcm-bridge-hub-router", "frame-support", "frame-system", "log", diff --git a/bridges/modules/xcm-bridge-hub-router/src/impls.rs b/bridges/modules/xcm-bridge-hub-router/src/impls.rs index 6114a0b75ca6b..85c5ed956f14b 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/impls.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/impls.rs @@ -16,7 +16,7 @@ //! Various implementations supporting easier configuration of the pallet. use crate::{Config, Pallet, Bridges, BridgeIdOf, LOG_TARGET}; -use xcm_builder::ExporterFor; +use xcm_builder::{ensure_is_remote, ExporterFor}; use bp_xcm_bridge_hub_router::ResolveBridgeId; use codec::Encode; use frame_support::pallet_prelude::PhantomData; @@ -164,3 +164,105 @@ where Some((bridge_hub_location, fees)) } } + +/// Implementation of `ResolveBridgeId` returning `bp_xcm_bridge_hub::BridgeId` based on the configured `UniversalLocation` and remote universal location. +pub struct EnsureIsRemoteBridgeIdResolver(PhantomData); +impl> ResolveBridgeId for EnsureIsRemoteBridgeIdResolver { + type BridgeId = bp_xcm_bridge_hub::BridgeId; + + fn resolve_for_dest(dest: &Location) -> Option { + let Ok((remote_network, remote_dest)) = ensure_is_remote(UniversalLocation::get(), dest.clone()) else { + log::trace!( + target: LOG_TARGET, + "EnsureIsRemoteBridgeIdResolver - does not recognize a remote destination for: {dest:?}!" + ); + return None + }; + Self::resolve_for(&remote_network, &remote_dest) + } + + fn resolve_for(bridged_network: &NetworkId, bridged_dest: &InteriorLocation) -> Option { + let bridged_universal_location = if let Ok(network) = bridged_dest.global_consensus() { + if network.ne(bridged_network) { + log::error!( + target: LOG_TARGET, + "EnsureIsRemoteBridgeIdResolver - bridged_dest: {bridged_dest:?} contains invalid network: {network:?}, expected bridged_network: {bridged_network:?}!" + ); + return None + } else { + bridged_dest.clone() + } + } else { + // if `bridged_dest` does not contain `GlobalConsensus`, let's prepend one + match bridged_dest.clone().pushed_front_with(bridged_network.clone()) { + Ok(bridged_universal_location) => bridged_universal_location, + Err((original, prepend_with)) => { + log::error!( + target: LOG_TARGET, + "EnsureIsRemoteBridgeIdResolver - bridged_dest: {original:?} cannot be prepended with: {prepend_with:?}!" + ); + return None + } + } + }; + + match (UniversalLocation::get().global_consensus(), bridged_universal_location.global_consensus()) { + (Ok(local), Ok(remote)) if local != remote => (), + (local, remote) => { + log::error!( + target: LOG_TARGET, + "EnsureIsRemoteBridgeIdResolver - local: {local:?} and remote: {remote:?} must be different!" + ); + return None + } + } + + // calculate `BridgeId` from universal locations + Some(Self::BridgeId::new(&UniversalLocation::get(), &bridged_universal_location)) + } +} + +#[cfg(test)] +mod tests { + use frame_support::__private::sp_tracing; + use super::*; + + #[test] + fn ensure_is_remote_bridge_id_resolver_works() { + sp_tracing::try_init_simple(); + frame_support::parameter_types! { + pub ThisNetwork: NetworkId = NetworkId::ByGenesis([0; 32]); + pub BridgedNetwork: NetworkId = NetworkId::ByGenesis([1; 32]); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(ThisNetwork::get()), Parachain(1000)].into(); + } + assert_ne!(ThisNetwork::get(), BridgedNetwork::get()); + + type Resolver = EnsureIsRemoteBridgeIdResolver; + + // not remote dest + assert!(Resolver::resolve_for_dest(&Location::new(1, Here)).is_none()); + // not a valid remote dest + assert!(Resolver::resolve_for_dest(&Location::new(2, Here)).is_none()); + // the same network for remote dest + assert!(Resolver::resolve_for_dest(&Location::new(2, GlobalConsensus(ThisNetwork::get()))).is_none()); + assert!(Resolver::resolve_for(&ThisNetwork::get(), &Here.into()).is_none()); + + // ok + assert!(Resolver::resolve_for_dest(&Location::new(2, GlobalConsensus(BridgedNetwork::get()))).is_some()); + assert!(Resolver::resolve_for_dest(&Location::new(2, [GlobalConsensus(BridgedNetwork::get()), Parachain(2013)])).is_some()); + + // ok - resolves the same + assert_eq!( + Resolver::resolve_for_dest(&Location::new(2, GlobalConsensus(BridgedNetwork::get()))), + Resolver::resolve_for(&BridgedNetwork::get(), &Here.into()), + ); + assert_eq!( + Resolver::resolve_for_dest(&Location::new(2, [GlobalConsensus(BridgedNetwork::get()), Parachain(2013)])), + Resolver::resolve_for(&BridgedNetwork::get(), &Parachain(2013).into()), + ); + assert_eq!( + Resolver::resolve_for_dest(&Location::new(2, [GlobalConsensus(BridgedNetwork::get()), Parachain(2013)])), + Resolver::resolve_for(&BridgedNetwork::get(), &[GlobalConsensus(BridgedNetwork::get()), Parachain(2013)].into()), + ); + } +} \ No newline at end of file diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index a6dfe20266f9b..568d0449510e1 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -29,7 +29,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use bp_xcm_bridge_hub_router::{BridgeState, ResolveBridgeId}; +pub use bp_xcm_bridge_hub_router::{BridgeState, ResolveBridgeId}; use codec::Encode; use frame_support::traits::{EnsureOriginWithArg, Get}; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; @@ -732,7 +732,7 @@ mod tests { fn report_bridge_status_works() { run_test(|| { let dest = Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]); - let bridge_id = (); + let bridge_id = bp_xcm_bridge_hub::BridgeId::new(&UniversalLocation::get(), dest.interior()); let report_bridge_status = |bridge_id, is_congested| { let call = RuntimeCall::XcmBridgeHubRouter(Call::report_bridge_status { bridge_id, diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 9d9aabc16540c..c3d8c57f739fc 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -31,6 +31,7 @@ use xcm::prelude::*; use xcm_builder::{ InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, SovereignPaidRemoteExporter, }; +use crate::impls::EnsureIsRemoteBridgeIdResolver; type Block = frame_system::mocking::MockBlock; @@ -104,7 +105,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { UniversalLocation, >; - type BridgeIdResolver = EveryDestinationToSameBridgeIdResolver; + type BridgeIdResolver = EnsureIsRemoteBridgeIdResolver; type BridgeHubOrigin = EnsureRoot; type ByteFee = ConstU128; diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 8bf76d8edcfc1..fe58b910a94ef 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -38,7 +38,6 @@ pallet-balances = { workspace = true } sp-io = { workspace = true } bp-runtime = { workspace = true } bp-header-chain = { workspace = true } -bp-xcm-bridge-hub-router = { workspace = true } pallet-xcm-bridge-hub-router = { workspace = true } polkadot-parachain-primitives = { workspace = true } diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 392fe44906425..09bb1f94ac354 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -365,7 +365,7 @@ mod tests { use bp_runtime::RangeInclusiveExt; use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState, Receiver}; - use bp_xcm_bridge_hub_router::ResolveBridgeId; + use pallet_xcm_bridge_hub_router::ResolveBridgeId; use frame_support::{ assert_ok, traits::{Contains, EnsureOrigin}, @@ -828,7 +828,7 @@ mod tests { // valid routable destination let dest = Location::new(2, BridgedUniversalDestination::get()); - fn router_bridge_state, I: 'static>(dest: &Location) -> Option { + fn router_bridge_state, I: 'static>(dest: &Location) -> Option { let bridge_id = ::resolve_for_dest(dest).unwrap(); pallet_xcm_bridge_hub_router::Bridges::::get(&bridge_id) } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 2dcda22b9454e..f5240f16575c6 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -26,7 +26,6 @@ use bp_messages::{ use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; use bp_xcm_bridge_hub::{BridgeId, BridgeLocations, LocalXcmChannelManager}; use codec::Encode; -use bp_xcm_bridge_hub_router::ResolveBridgeId; use frame_support::{ assert_ok, derive_impl, parameter_types, traits::{fungible::Mutate, EitherOf, EnsureOrigin, Equals, Everything, OriginTrait}, @@ -47,7 +46,7 @@ use xcm::prelude::*; use xcm_builder::{ AllowUnpaidExecutionFrom, DispatchBlob, DispatchBlobError, FixedWeightBounds, InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, - SiblingParachainConvertsVia, SovereignPaidRemoteExporter, UnpaidLocalExporter, ensure_is_remote, + SiblingParachainConvertsVia, SovereignPaidRemoteExporter, UnpaidLocalExporter, }; use xcm_executor::{traits::{ConvertLocation, ConvertOrigin}, XcmExecutor}; use crate::congestion::BlobDispatcherWithChannelStatus; @@ -258,7 +257,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { ExportMessageOriginUniversalLocation, >; - type BridgeIdResolver = EnsureIsRemoteBridgeIdResolver; + type BridgeIdResolver = pallet_xcm_bridge_hub_router::impls::EnsureIsRemoteBridgeIdResolver; // We convert to root here `BridgeHubLocationXcmOriginAsRoot` type BridgeHubOrigin = EnsureRoot; } @@ -272,27 +271,11 @@ impl pallet_xcm_bridge_hub_router::Config; - type BridgeIdResolver = EnsureIsRemoteBridgeIdResolver; + type BridgeIdResolver = pallet_xcm_bridge_hub_router::impls::EnsureIsRemoteBridgeIdResolver; // We don't need to support here `report_bridge_status`. type BridgeHubOrigin = EnsureNever<()>; } -/// Implementation of `ResolveBridgeId` returning `BridgeId` based on the configured `UniversalLocation`. -pub struct EnsureIsRemoteBridgeIdResolver(PhantomData); -impl> ResolveBridgeId for EnsureIsRemoteBridgeIdResolver { - type BridgeId = BridgeId; - - fn resolve_for_dest(dest: &Location) -> Option { - let (remote_network, remote_dest) = ensure_is_remote(UniversalLocation::get(), dest.clone()).unwrap(); - Self::resolve_for(&remote_network, &remote_dest) - } - - fn resolve_for(bridged_network: &NetworkId, bridged_dest: &InteriorLocation) -> Option { - let bridged_universal_location = bridged_dest.clone().pushed_front_with(bridged_network.clone()).unwrap(); - Some(BridgeId::new(&UniversalLocation::get(), &bridged_universal_location)) - } -} - /// A dynamic way to set different universal location for the origin which sends `ExportMessage`. pub struct ExportMessageOriginUniversalLocation; impl ExportMessageOriginUniversalLocation { diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index d896a40cb7052..69ffbd400166d 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -17,34 +17,6 @@ use crate::{pallet, OutboundState}; use cumulus_primitives_core::ParaId; use xcm::latest::prelude::*; -/// Adapter implementation for `bp_xcm_bridge_hub::ChannelStatusProvider` which checks -/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `Location` if any of those is -/// suspended. -pub struct InAndOutXcmpChannelStatusProvider(core::marker::PhantomData); -impl bp_xcm_bridge_hub::ChannelStatusProvider - for InAndOutXcmpChannelStatusProvider -{ - fn is_congested(with: &Location) -> bool { - // handle congestion only for a sibling parachain locations. - let sibling_para_id: ParaId = match with.unpack() { - (_, [Parachain(para_id)]) => (*para_id).into(), - _ => return false, - }; - - // if the inbound channel with recipient is suspended, it means that we are unable to - // receive congestion reports from the `with` location. So we assume the pipeline is - // congested too. - if pallet::Pallet::::is_inbound_channel_suspended(sibling_para_id) { - return true - } - - // if the outbound channel with recipient is suspended, it means that one of further - // queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall - // take larger fee for our outbound messages - OutXcmpChannelStatusProvider::::is_congested(with) - } -} - /// Adapter implementation for `bp_xcm_bridge_hub::ChannelStatusProvider` which checks /// only `OutboundXcmpStatus` for defined `SiblingParaId` if is suspended. pub struct OutXcmpChannelStatusProvider(core::marker::PhantomData); diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 6bb7395f6553b..dbb7a30471b58 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -691,11 +691,6 @@ impl Pallet { .max(::WeightInfo::on_idle_large_msg()) } - #[cfg(feature = "bridging")] - fn is_inbound_channel_suspended(sender: ParaId) -> bool { - >::get().iter().any(|c| c == &sender) - } - #[cfg(feature = "bridging")] /// Returns tuple of `OutboundState` and number of queued pages. fn outbound_channel_state(target: ParaId) -> Option<(OutboundState, u16)> { 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 cea8304d0d9a8..b56f8f5cd8a84 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -67,6 +67,7 @@ use frame_support::{ weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, }; +use frame_support::traits::Equals; use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, EnsureSignedBy, @@ -111,7 +112,7 @@ use xcm_runtime_apis::{ }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm_builder::SovereignPaidRemoteExporter; +use xcm_builder::{NetworkExportTable, SovereignPaidRemoteExporter}; impl_opaque_keys! { pub struct SessionKeys { @@ -928,22 +929,31 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; - type UniversalLocation = xcm_config::UniversalLocation; - type SiblingBridgeHubLocation = xcm_config::bridging::SiblingBridgeHub; - type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; type DestinationVersion = PolkadotXcm; // Let's use `SovereignPaidRemoteExporter`, which sends `ExportMessage` over HRMP to the sibling // BridgeHub. type ToBridgeHubSender = SovereignPaidRemoteExporter< - xcm_builder::NetworkExportTable, + // `ExporterFor` wrapper handling dynamic fees for congestion. + pallet_xcm_bridge_hub_router::impls::ViaRemoteBridgeHubExporter< + Runtime, + ToWestendXcmRouterInstance, + NetworkExportTable, + xcm_config::bridging::to_westend::WestendNetwork, + xcm_config::bridging::SiblingBridgeHub + >, XcmpQueue, - Self::UniversalLocation + xcm_config::UniversalLocation, >; - type LocalXcmChannelManager = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; + // For congestion - resolves `BridgeId` using the same algorithm as `pallet_xcm_bridge_hub` on the BH. + type BridgeIdResolver = pallet_xcm_bridge_hub_router::impls::EnsureIsRemoteBridgeIdResolver; + // For congestion - allow only calls from BH. + type BridgeHubOrigin = AsEnsureOriginWithArg>>; + + // For adding message size fees type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; + // For adding message size fees type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; } 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 00ecf239428f0..9fa2264fb8d97 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 @@ -44,10 +44,20 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; +use frame_support::weights::constants::RocksDbWeight; /// Weight functions for `pallet_xcm_bridge_hub_router`. pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { + // TODO: FAIL-CI + fn on_initialize_when_bridge_state_removed() -> Weight { + RocksDbWeight::get().writes(1) + } + + // TODO: FAIL-CI + fn on_initialize_when_bridge_state_updated() -> Weight { + RocksDbWeight::get().writes(1) + } /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) @@ -77,4 +87,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } + // TODO: FAIL-CI + 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)) + } } 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 814323135325f..4b06f720b41db 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -17,18 +17,11 @@ //! Tests for the Rococo Assets Hub chain. -use asset_hub_rococo_runtime::{ - xcm_config, - xcm_config::{ - bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, - TokenLocation, TrustBackedAssetsPalletLocation, XcmConfig, - }, - AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, - ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, - MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - SessionKeys, TrustBackedAssetsInstance, XcmpQueue, -}; +use asset_hub_rococo_runtime::{xcm_config, xcm_config::{ + bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, + TokenLocation, TrustBackedAssetsPalletLocation, XcmConfig, +}, AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue}; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, SlotDurations, @@ -1266,6 +1259,55 @@ mod asset_hub_rococo_tests { WeightLimit::Unlimited, ); } + + #[test] + fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ToWestendXcmRouterInstance, + >( + collator_session_keys(), + bridging_to_asset_hub_westend, + |bridge_id, is_congested| { + vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_bridge_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: RuntimeCall::ToWestendXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id, + is_congested, + }, + ) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success) + ] + .into() + }, + ) + } +} + +#[test] +fn check_sane_weight_report_bridge_status() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_bridge_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); } #[test] 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 1983c035990e7..aebfd18ad3311 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -94,6 +94,8 @@ use assets_common::{ foreign_creators::ForeignCreators, matching::{FromNetwork, FromSiblingParachain}, }; +use frame_support::traits::Equals; +use pallet_xcm::EnsureXcm; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::{ latest::prelude::AssetId, @@ -112,7 +114,7 @@ use xcm_runtime_apis::{ }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm_builder::SovereignPaidRemoteExporter; +use xcm_builder::{NetworkExportTable, SovereignPaidRemoteExporter}; impl_opaque_keys! { pub struct SessionKeys { @@ -925,22 +927,31 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; - type UniversalLocation = xcm_config::UniversalLocation; - type SiblingBridgeHubLocation = xcm_config::bridging::SiblingBridgeHub; - type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; type DestinationVersion = PolkadotXcm; // Let's use `SovereignPaidRemoteExporter`, which sends `ExportMessage` over HRMP to the sibling // BridgeHub. type ToBridgeHubSender = SovereignPaidRemoteExporter< - xcm_builder::NetworkExportTable, + // `ExporterFor` wrapper handling dynamic fees for congestion. + pallet_xcm_bridge_hub_router::impls::ViaRemoteBridgeHubExporter< + Runtime, + ToRococoXcmRouterInstance, + NetworkExportTable, + xcm_config::bridging::to_rococo::RococoNetwork, + xcm_config::bridging::SiblingBridgeHub + >, XcmpQueue, - Self::UniversalLocation + xcm_config::UniversalLocation, >; - type LocalXcmChannelManager = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; + // For congestion - resolves `BridgeId` using the same algorithm as `pallet_xcm_bridge_hub` on the BH. + type BridgeIdResolver = pallet_xcm_bridge_hub_router::impls::EnsureIsRemoteBridgeIdResolver; + // For congestion - allow only calls from BH. + type BridgeHubOrigin = AsEnsureOriginWithArg>>; + + // For adding message size fees type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; + // For adding message size fees type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; } 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 c0898012e9f32..9c1fe64ac16fc 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 @@ -44,10 +44,20 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; +use frame_support::weights::constants::RocksDbWeight; /// Weight functions for `pallet_xcm_bridge_hub_router`. pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { + // TODO: FAIL-CI + fn on_initialize_when_bridge_state_removed() -> Weight { + RocksDbWeight::get().writes(1) + } + + // TODO: FAIL-CI + fn on_initialize_when_bridge_state_updated() -> Weight { + RocksDbWeight::get().writes(1) + } /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) @@ -77,4 +87,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } + // TODO: FAIL-CI + 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)) + } } 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 6a48b19ce9468..521ffe79c124f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -17,18 +17,11 @@ //! Tests for the Westmint (Westend Assets Hub) chain. -use asset_hub_westend_runtime::{ - xcm_config, - xcm_config::{ - bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, - TrustBackedAssetsPalletLocation, WestendLocation, XcmConfig, - }, - AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, - PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - TrustBackedAssetsInstance, XcmpQueue, -}; +use asset_hub_westend_runtime::{xcm_config, xcm_config::{ + bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, + TrustBackedAssetsPalletLocation, WestendLocation, XcmConfig, +}, AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue}; pub use asset_hub_westend_runtime::{AssetConversion, AssetDeposit, CollatorSelection, System}; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -1243,6 +1236,55 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic ) } +#[test] +fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ToRococoXcmRouterInstance, + >( + collator_session_keys(), + bridging_to_asset_hub_rococo, + |bridge_id, is_congested| { + vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: + bp_bridge_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: RuntimeCall::ToRococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id, + is_congested, + }, + ) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success) + ] + .into() + }, + ) +} + +#[test] +fn check_sane_weight_report_bridge_status() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_bridge_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); +} + #[test] fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { asset_test_utils::test_cases::change_storage_constant_by_governance_works::< diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index d867611747402..328300538daff 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -498,8 +498,7 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< >( collator_session_keys: CollatorSessionKeys, prepare_configuration: fn() -> TestBridgingConfig, - congested_message: fn() -> Xcm, - uncongested_message: fn() -> Xcm, + congestion_message: fn(pallet_xcm_bridge_hub_router::BridgeIdOf, bool) -> Xcm, ) where Runtime: frame_system::Config + pallet_balances::Config @@ -534,10 +533,18 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< .execute_with(|| { let report_bridge_status = |is_congested: bool| { // prepare bridge config - let TestBridgingConfig { local_bridge_hub_location, .. } = prepare_configuration(); + let TestBridgingConfig { local_bridge_hub_location, bridged_target_location, .. } = prepare_configuration(); + + + use pallet_xcm_bridge_hub_router::ResolveBridgeId; + let bridge_id = <>::BridgeIdResolver>::resolve_for_dest(&bridged_target_location).expect("resolved BridgeId"); + + // check before + let bridge_state = pallet_xcm_bridge_hub_router::Bridges::::get(&bridge_id); + let is_congested_before = bridge_state.map(|bs| bs.is_congested).unwrap_or(false); // Call received XCM execution - let xcm = if is_congested { congested_message() } else { uncongested_message() }; + let xcm = congestion_message(bridge_id.clone(), is_congested); let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); // execute xcm as XcmpQueue would do @@ -551,9 +558,14 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< Weight::zero(), ); assert_ok!(outcome.ensure_complete()); - assert_eq!( - is_congested, - <>::LocalXcmChannelManager as pallet_xcm_bridge_hub_router::XcmChannelStatusProvider>::is_congested(&local_bridge_hub_location) + + // check after + let bridge_state = pallet_xcm_bridge_hub_router::Bridges::::get(&bridge_id); + let is_congested_after = bridge_state.map(|bs| bs.is_congested).unwrap_or(false); + assert_eq!(is_congested_after, is_congested); + assert_ne!( + is_congested_after, + is_congested_before, ); }; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index c226ed9c4fa06..2e785ecd12f43 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -40,6 +40,7 @@ use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; +use pallet_xcm_bridge_hub::congestion::BlobDispatcherWithChannelStatus; use pallet_xcm_bridge_hub::XcmAsPlainPayload; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; @@ -85,13 +86,6 @@ pub type FromRococoBulletinMessagesProof = pub type ToRococoBulletinMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>; -/// Dispatches received XCM messages from other bridge. -type FromRococoBulletinMessageBlobDispatcher = BridgeBlobDispatcher< - XcmRouter, - UniversalLocation, - BridgeRococoToRococoBulletinMessagesPalletInstance, ->; - /// Transaction extension that refunds relayers that are delivering messages from the Rococo /// Bulletin chain. pub type OnBridgeHubRococoRefundRococoBulletinMessages = BridgeRelayersTransactionExtension< @@ -156,7 +150,13 @@ impl pallet_xcm_bridge_hub::Config for Runtime type AllowWithoutBridgeDeposit = Equals; type LocalXcmChannelManager = (); - type BlobDispatcher = FromRococoBulletinMessageBlobDispatcher; + // Dispatching inbound messages from the bridge. + type BlobDispatcher = BlobDispatcherWithChannelStatus< + // Dispatches received XCM messages from other bridge + BridgeBlobDispatcher, + // no congestion checking + (), + >; } #[cfg(test)] 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 29ea4e05f29ee..92849d8e046bc 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 @@ -26,6 +26,7 @@ use crate::{ AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, }; +use alloc::{vec, vec::Vec}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, LegacyLaneId, @@ -39,8 +40,10 @@ use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; +use pallet_xcm_bridge_hub::congestion::{BlobDispatcherWithChannelStatus, ReportBridgeStatusXcmChannelManager}; use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; use polkadot_parachain_primitives::primitives::Sibling; +use sp_runtime::traits::Convert; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ latest::prelude::*, @@ -80,10 +83,6 @@ pub type FromWestendBridgeHubMessagesProof = pub type ToWestendBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>; -/// Dispatches received XCM messages from other bridge -type FromWestendMessageBlobDispatcher = - BridgeBlobDispatcher; - /// Transaction extension that refunds relayers that are delivering messages from the Westend /// parachain. pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersTransactionExtension< @@ -128,6 +127,22 @@ impl pallet_bridge_messages::Config for Ru type OnMessagesDelivered = XcmOverBridgeHubWestend; } +/// Converts encoded call to the unpaid XCM `Transact`. +pub struct ReportBridgeStatusXcmProvider; +impl Convert, Xcm<()>> for ReportBridgeStatusXcmProvider { + fn convert(encoded_call: Vec) -> Xcm<()> { + Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: bp_bridge_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: encoded_call.into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]) + } +} + /// Add support for the export and dispatch of XCM programs withing /// `WithBridgeHubWestendMessagesInstance`. pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; @@ -156,9 +171,16 @@ impl pallet_xcm_bridge_hub::Config for Runtime type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 - type LocalXcmChannelManager = (); - type BlobDispatcher = FromWestendMessageBlobDispatcher; + // This pallet is deployed on BH, so we expect a remote router with `ExportMessage`. We handle congestion with XCM using `report_bridge_status` sent to the sending chain. + // (congestion with local sending chain) + type LocalXcmChannelManager = ReportBridgeStatusXcmChannelManager; + // Dispatching inbound messages from the bridge and managing congestion with the local receiving/destination chain + type BlobDispatcher = BlobDispatcherWithChannelStatus< + // Dispatches received XCM messages from other bridge + BridgeBlobDispatcher, + // Provides the status of the XCMP queue's outbound queue, indicating whether messages can be dispatched to the sibling. + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider, + >; } #[cfg(feature = "runtime-benchmarks")] 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 aca51b320e9be..adac11d23f533 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 @@ -23,6 +23,7 @@ use crate::{ AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, }; +use alloc::{vec, vec::Vec}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, LegacyLaneId, @@ -40,8 +41,10 @@ use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; +use pallet_xcm_bridge_hub::congestion::{BlobDispatcherWithChannelStatus, ReportBridgeStatusXcmChannelManager}; use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; use polkadot_parachain_primitives::primitives::Sibling; +use sp_runtime::traits::Convert; use testnet_parachains_constants::westend::currency::UNITS as WND; use xcm::{ latest::prelude::*, @@ -87,10 +90,6 @@ pub type FromRococoBridgeHubMessagesProof = pub type ToRococoBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>; -/// Dispatches received XCM messages from other bridge -type FromRococoMessageBlobDispatcher = - BridgeBlobDispatcher; - /// Transaction extension that refunds relayers that are delivering messages from the Rococo /// parachain. pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersTransactionExtension< @@ -159,6 +158,22 @@ impl pallet_bridge_messages::Config for Run type OnMessagesDelivered = XcmOverBridgeHubRococo; } +/// Converts encoded call to the unpaid XCM `Transact`. +pub struct ReportBridgeStatusXcmProvider; +impl Convert, Xcm<()>> for ReportBridgeStatusXcmProvider { + fn convert(encoded_call: Vec) -> Xcm<()> { + Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: bp_bridge_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), + call: encoded_call.into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]) + } +} + /// Add support for the export and dispatch of XCM programs. pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { @@ -185,9 +200,16 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 - type LocalXcmChannelManager = (); - type BlobDispatcher = FromRococoMessageBlobDispatcher; + // This pallet is deployed on BH, so we expect a remote router with `ExportMessage`. We handle congestion with XCM using `report_bridge_status` sent to the sending chain. + // (congestion with local sending chain) + type LocalXcmChannelManager = ReportBridgeStatusXcmChannelManager; + // Dispatching inbound messages from the bridge and managing congestion with the local receiving/destination chain + type BlobDispatcher = BlobDispatcherWithChannelStatus< + // Dispatches received XCM messages from other bridge + BridgeBlobDispatcher, + // Provides the status of the XCMP queue's outbound queue, indicating whether messages can be dispatched to the sibling. + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider, + >; } #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index 9f105dbfd2dd9..b9818d004847b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -746,7 +746,8 @@ pub fn open_and_close_bridge_works