diff --git a/Cargo.lock b/Cargo.lock index f74917b60650c..6bf1e8b576d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4491,7 +4491,7 @@ name = "cumulus-pallet-xcmp-queue" version = "0.7.0" dependencies = [ "bounded-collections", - "bp-xcm-bridge-hub-router", + "bp-xcm-bridge-hub", "cumulus-pallet-parachain-system", "cumulus-primitives-core", "frame-benchmarking", @@ -13276,6 +13276,7 @@ dependencies = [ name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ + "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "frame-benchmarking", "frame-support", diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 55824f6a7fe7b..1cda8893967e2 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -17,6 +17,7 @@ scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } # Bridge dependencies bp-xcm-bridge-hub-router = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } # Substrate Dependencies frame-benchmarking = { optional = true, workspace = true } @@ -38,6 +39,7 @@ sp-std = { workspace = true, default-features = true } default = ["std"] std = [ "bp-xcm-bridge-hub-router/std", + "bp-xcm-bridge-hub/std", "codec/std", "frame-benchmarking/std", "frame-support/std", diff --git a/bridges/modules/xcm-bridge-hub-router/src/impls.rs b/bridges/modules/xcm-bridge-hub-router/src/impls.rs index 99dac41f93c37..6114a0b75ca6b 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/impls.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/impls.rs @@ -15,14 +15,53 @@ // along with Parity Bridges Common. If not, see . //! Various implementations supporting easier configuration of the pallet. -use crate::{Config, Pallet, Bridges, LOG_TARGET}; +use crate::{Config, Pallet, Bridges, BridgeIdOf, LOG_TARGET}; use xcm_builder::ExporterFor; use bp_xcm_bridge_hub_router::ResolveBridgeId; use codec::Encode; use frame_support::pallet_prelude::PhantomData; use frame_support::traits::Get; +use frame_support::ensure; use xcm::prelude::*; +/// Implementation of `LocalXcmChannelManager` which tracks and updates `is_congested` for a given `BridgeId`. +/// This implementation is useful for managing congestion and dynamic fees with the local `ExportXcm` implementation. +impl, I: 'static> bp_xcm_bridge_hub::LocalXcmChannelManager> for Pallet { + type Error = (); + + /// Suspends the given bridge. + /// + /// This function ensures that the `local_origin` matches the expected `Location::here()`. If the check passes, it updates the bridge status to congested. + fn suspend_bridge(local_origin: &Location, bridge: BridgeIdOf) -> Result<(), Self::Error> { + log::trace!( + target: LOG_TARGET, + "LocalXcmChannelManager::suspend_bridge(local_origin: {local_origin:?}, bridge: {bridge:?})", + ); + ensure!(local_origin.eq(&Location::here()), ()); + + // update status + Self::update_bridge_status(bridge, true); + + Ok(()) + } + + /// Resumes the given bridge. + /// + /// This function ensures that the `local_origin` matches the expected `Location::here()`. If the check passes, it updates the bridge status to not congested. + fn resume_bridge(local_origin: &Location, bridge: BridgeIdOf) -> Result<(), Self::Error> { + log::trace!( + target: LOG_TARGET, + "LocalXcmChannelManager::resume_bridge(local_origin: {local_origin:?}, bridge: {bridge:?})", + ); + ensure!(local_origin.eq(&Location::here()), ()); + + // update status + Self::update_bridge_status(bridge, false); + + Ok(()) + } +} + pub struct ViaRemoteBridgeHubExporter(PhantomData<(T, I, E, BNF, BHLF)>); impl, I: 'static, E, BridgedNetworkIdFilter, BridgeHubLocationFilter> ExporterFor for ViaRemoteBridgeHubExporter diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 1d4a4c4fdcdbe..a6dfe20266f9b 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -31,7 +31,7 @@ use bp_xcm_bridge_hub_router::{BridgeState, ResolveBridgeId}; use codec::Encode; -use frame_support::traits::Get; +use frame_support::traits::{EnsureOriginWithArg, Get}; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; use sp_std::vec::Vec; use xcm::prelude::*; @@ -127,6 +127,10 @@ pub mod pallet { #[pallet::no_default] type BridgeIdResolver: ResolveBridgeId; + /// Origin of the sibling bridge hub that is allowed to report bridge status. + #[pallet::no_default] + type BridgeHubOrigin: EnsureOriginWithArg>; + /// Additional fee that is paid for every byte of the outbound message. /// See `calculate_message_size_fees` for more details. type ByteFee: Get; @@ -204,9 +208,35 @@ pub mod pallet { } } + #[pallet::call] + impl, I: 'static> Pallet { + /// Notification about congested bridge queue. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::report_bridge_status())] + pub fn report_bridge_status( + origin: OriginFor, + bridge_id: BridgeIdOf, + is_congested: bool, + ) -> DispatchResult { + let _ = T::BridgeHubOrigin::ensure_origin(origin, &bridge_id)?; + + log::info!( + target: LOG_TARGET, + "Received bridge status from {:?}: congested = {}", + bridge_id, + is_congested, + ); + + // update status + Self::update_bridge_status(bridge_id, is_congested); + + Ok(()) + } + } + /// Stores `BridgeState` for congestion control and dynamic fees for each resolved bridge ID associated with a destination. #[pallet::storage] - pub type Bridges, I: 'static = ()> = StorageMap<_, Identity, BridgeIdOf, BridgeState, OptionQuery>; + pub type Bridges, I: 'static = ()> = StorageMap<_, Blake2_128Concat, BridgeIdOf, BridgeState, OptionQuery>; impl, I: 'static> Pallet { /// Called when new message is sent to the `dest` (queued to local outbound XCM queue). @@ -276,6 +306,24 @@ pub mod pallet { } None } + /// Updates the congestion status of a bridge for a given `bridge_id`. + /// + /// If the bridge does not exist and: + /// - `is_congested` is true, a new `BridgeState` is created with a default `delivery_fee_factor`. + /// - `is_congested` is false, does nothing and no `BridgeState` is created. + pub(crate) fn update_bridge_status(bridge_id: BridgeIdOf, is_congested: bool) { + Bridges::::mutate(bridge_id, |bridge| match bridge { + Some(bridge) => bridge.is_congested = is_congested, + None => { + if is_congested { + *bridge = Some(BridgeState { + delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, + is_congested, + }) + } + } + }); + } } #[pallet::event] @@ -410,7 +458,7 @@ mod tests { use frame_support::traits::Hooks; use frame_system::{EventRecord, Phase}; - use sp_runtime::traits::One; + use sp_runtime::traits::{Dispatchable, One}; #[test] fn fee_factor_is_not_decreased_from_on_initialize_when_bridge_is_congested() { @@ -445,9 +493,9 @@ mod tests { })); // it should eventually decrease and remove - let mut old_delivery_fee_factor = initial_fee_factor; + let mut last_delivery_fee_factor = initial_fee_factor; while let Some(bridge_state) = get_bridge_state_for::(&dest) { - old_delivery_fee_factor = bridge_state.delivery_fee_factor; + last_delivery_fee_factor = bridge_state.delivery_fee_factor; XcmBridgeHubRouter::on_initialize(One::one()); } @@ -473,7 +521,7 @@ mod tests { Some(EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmBridgeHubRouter(Event::DeliveryFeeFactorDecreased { - previous_value: old_delivery_fee_factor, + previous_value: last_delivery_fee_factor, new_value: 0.into(), bridge_id, }), @@ -679,4 +727,37 @@ mod tests { assert_eq!(XcmBridgeHubRouter::get_messages(), vec![]); }); } + + #[test] + fn report_bridge_status_works() { + run_test(|| { + let dest = Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]); + let bridge_id = (); + let report_bridge_status = |bridge_id, is_congested| { + let call = RuntimeCall::XcmBridgeHubRouter(Call::report_bridge_status { + bridge_id, + is_congested, + }); + assert_ok!(call.dispatch(RuntimeOrigin::root())); + }; + + assert!(get_bridge_state_for::(&dest).is_none()); + report_bridge_status(bridge_id, false); + assert!(get_bridge_state_for::(&dest).is_none()); + + // make congested + report_bridge_status(bridge_id, true); + assert_eq!(get_bridge_state_for::(&dest), Some(BridgeState { + delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, + is_congested: true, + })); + + // make uncongested + report_bridge_status(bridge_id, false); + assert_eq!(get_bridge_state_for::(&dest), Some(BridgeState { + delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, + is_congested: false, + })); + }); + } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index a3b078c2c471f..9d9aabc16540c 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -24,6 +24,7 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{Contains, Equals}, }; +use frame_system::EnsureRoot; use sp_runtime::{traits::ConstU128, BuildStorage}; use sp_std::cell::RefCell; use xcm::prelude::*; @@ -43,8 +44,8 @@ pub const BYTE_FEE: u128 = 1_000; construct_runtime! { pub enum TestRuntime { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - XcmBridgeHubRouter: pallet_xcm_bridge_hub_router::{Pallet, Storage, Event}, + System: frame_system, + XcmBridgeHubRouter: pallet_xcm_bridge_hub_router, } } @@ -104,6 +105,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { >; type BridgeIdResolver = EveryDestinationToSameBridgeIdResolver; + type BridgeHubOrigin = EnsureRoot; type ByteFee = ConstU128; type FeeAsset = BridgeFeeAsset; diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index 2685d676d3850..dc5f1ea1a99ad 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -54,6 +54,7 @@ pub trait WeightInfo { fn on_initialize_when_bridge_state_updated() -> Weight; fn on_initialize_when_non_congested() -> Weight; fn on_initialize_when_congested() -> Weight; + fn report_bridge_status() -> Weight; } /// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets. @@ -94,6 +95,19 @@ impl WeightInfo for BridgeWeight { // Minimum execution time: 4_239 nanoseconds. Weight::from_parts(4_383_000, 3547).saturating_add(T::DbWeight::get().reads(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 @@ -137,4 +151,17 @@ impl WeightInfo for () { // Minimum execution time: 4_239 nanoseconds. Weight::from_parts(4_383_000, 3547).saturating_add(RocksDbWeight::get().reads(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/src/congestion.rs b/bridges/modules/xcm-bridge-hub/src/congestion.rs new file mode 100644 index 0000000000000..2307f692a0af2 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/congestion.rs @@ -0,0 +1,151 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! The module contains utilities for handling congestion between the bridge hub and routers. + +use sp_std::vec::Vec; +use sp_std::marker::PhantomData; +use codec::Encode; +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager, Receiver}; +use sp_runtime::traits::Convert; +use xcm::latest::{send_xcm, Location, SendXcm, Xcm}; +use crate::{Config, Bridges, LOG_TARGET}; + +/// Switches the implementation of `LocalXcmChannelManager` based on the `local_origin`. +/// +/// - `HereXcmChannelManager` is applied when the origin is `Here`. +/// - Otherwise, `LocalConsensusXcmChannelManager` is used. +/// +/// This is useful when the `pallet-xcm-bridge-hub` needs to support both: +/// - A local router deployed on the same chain as the `pallet-xcm-bridge-hub`. +/// - A remote router deployed on a different chain than the `pallet-xcm-bridge-hub`. +pub struct HereOrLocalConsensusXcmChannelManager(PhantomData<(Bridge, HereXcmChannelManager, LocalConsensusXcmChannelManager)>); +impl, LocalConsensusXcmChannelManager: LocalXcmChannelManager> LocalXcmChannelManager +for HereOrLocalConsensusXcmChannelManager { + type Error = (); + + fn suspend_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error> { + if local_origin.eq(&Location::here()) { + HereXcmChannelManager::suspend_bridge(local_origin, bridge).map_err(|e| { + log::error!( + target: LOG_TARGET, + "HereXcmChannelManager::suspend_bridge error: {e:?} for local_origin: {:?} and bridge: {:?}", + local_origin, + bridge, + ); + () + }) + } else { + LocalConsensusXcmChannelManager::suspend_bridge(local_origin, bridge).map_err(|e| { + log::error!( + target: LOG_TARGET, + "LocalConsensusXcmChannelManager::suspend_bridge error: {e:?} for local_origin: {:?} and bridge: {:?}", + local_origin, + bridge, + ); + () + }) + } + } + + fn resume_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error> { + if local_origin.eq(&Location::here()) { + HereXcmChannelManager::resume_bridge(local_origin, bridge).map_err(|e| { + log::error!( + target: LOG_TARGET, + "HereXcmChannelManager::resume_bridge error: {e:?} for local_origin: {:?} and bridge: {:?}", + local_origin, + bridge, + ); + () + }) + } else { + LocalConsensusXcmChannelManager::resume_bridge(local_origin, bridge).map_err(|e| { + log::error!( + target: LOG_TARGET, + "LocalConsensusXcmChannelManager::resume_bridge error: {e:?} for local_origin: {:?} and bridge: {:?}", + local_origin, + bridge, + ); + () + }) + } + } +} + +/// Manages the local XCM channels by sending XCM messages with the `report_bridge_status` extrinsic to the `local_origin`. +/// The `XcmProvider` type converts the encoded call to `XCM`, which is then sent by `XcmSender` to the `local_origin`. +/// This is useful, for example, when a router with `ExportMessage` is deployed on a different chain, and we want to control congestion by sending XCMs. +pub struct ReportBridgeStatusXcmChannelManager(PhantomData<(T, I, XcmProvider, XcmSender)>); +impl, I: 'static, XcmProvider: Convert, Xcm<()>>, XcmSender: SendXcm> ReportBridgeStatusXcmChannelManager { + fn report_bridge_status(local_origin: &Location, bridge_id: BridgeId, is_congested: bool) -> Result<(), ()> { + // check the bridge and get `maybe_notify` callback. + let bridge = Bridges::::get(&bridge_id).ok_or(())?; + let Some(Receiver { pallet_index, call_index }) = bridge.maybe_notify else { + // `local_origin` did not set `maybe_notify`, so nothing to notify, so it is ok. + return Ok(()) + }; + + // constructing expected call + let remote_runtime_call = (pallet_index, call_index, bridge_id, is_congested); + // construct XCM + let xcm = XcmProvider::convert(remote_runtime_call.encode()); + log::trace!( + target: LOG_TARGET, + "ReportBridgeStatusXcmChannelManager is going to send status with is_congested: {:?} to the local_origin: {:?} and bridge: {:?} as xcm: {:?}", + is_congested, + local_origin, + bridge, + xcm, + ); + + // send XCM + send_xcm::(local_origin.clone(), xcm) + .map(|result| { + log::warn!( + target: LOG_TARGET, + "ReportBridgeStatusXcmChannelManager successfully sent status with is_congested: {:?} to the local_origin: {:?} and bridge: {:?} with result: {:?}", + is_congested, + local_origin, + bridge, + result, + ); + () + }) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "ReportBridgeStatusXcmChannelManager failed to send status with is_congested: {:?} to the local_origin: {:?} and bridge: {:?} with error: {:?}", + is_congested, + local_origin, + bridge, + e, + ); + () + }) + } +} +impl, I: 'static, XcmProvider: Convert, Xcm<()>>, XcmSender: SendXcm> LocalXcmChannelManager for ReportBridgeStatusXcmChannelManager { + type Error = (); + + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + Self::report_bridge_status(local_origin, bridge, true) + } + + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + Self::report_bridge_status(local_origin, bridge, false) + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index daa49ed415d39..bbc9c8ae54d63 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -21,11 +21,11 @@ //! //! This code is executed at the target bridge hub. -use crate::{Config, Pallet, LOG_TARGET}; +use crate::{Config, Pallet, LOG_TARGET, DispatchChannelStatusProvider}; use bp_messages::target_chain::{DispatchMessage, MessageDispatch}; use bp_runtime::messages::MessageDispatchResult; -use bp_xcm_bridge_hub::{LocalXcmChannelManager, XcmAsPlainPayload}; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use codec::{Decode, Encode}; use frame_support::{weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; use pallet_bridge_messages::{Config as BridgeMessagesConfig, WeightInfoExt}; @@ -60,7 +60,7 @@ where fn is_active(lane: Self::LaneId) -> bool { Pallet::::bridge_by_lane_id(&lane) .and_then(|(_, bridge)| bridge.bridge_origin_relative_location.try_as().cloned().ok()) - .map(|recipient: Location| !T::LocalXcmChannelManager::is_congested(&recipient)) + .map(|recipient: Location| !T::BlobDispatcher::is_congested(&recipient)) .unwrap_or(false) } @@ -158,6 +158,7 @@ mod tests { state: BridgeState::Opened, deposit: None, lane_id, + maybe_notify: None, }, ); LaneToBridge::::insert(lane_id, bridge.bridge_id()); @@ -206,8 +207,11 @@ mod tests { #[test] fn dispatcher_is_inactive_when_channel_with_target_chain_is_congested() { run_test_with_opened_bridge(|| { - TestLocalXcmChannelManager::make_congested(); - assert!(!XcmOverBridge::is_active(bridge().1)); + let bridge = bridge(); + let with = bridge.0.bridge_origin_relative_location(); + let lane_id = bridge.1; + TestBlobDispatcher::make_congested(with); + assert!(!XcmOverBridge::is_active(lane_id)); }); } diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index bbdca5dd6dd9e..392fe44906425 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -233,7 +233,7 @@ impl, I: 'static> Pallet { { Ok(bridge_origin_relative_location) => bridge_origin_relative_location, Err(_) => { - log::debug!( + log::error!( target: LOG_TARGET, "Failed to convert the bridge {:?} origin location {:?}", bridge_id, @@ -255,7 +255,7 @@ impl, I: 'static> Pallet { ); }, Err(e) => { - log::debug!( + log::error!( target: LOG_TARGET, "Failed to suspended the bridge {:?}, originated by the {:?}: {:?}", bridge_id, @@ -298,7 +298,7 @@ impl, I: 'static> Pallet { let bridge_origin_relative_location = match bridge_origin_relative_location { Ok(bridge_origin_relative_location) => bridge_origin_relative_location, Err(e) => { - log::debug!( + log::error!( target: LOG_TARGET, "Failed to convert the bridge {:?} location for lane_id: {:?}, error {:?}", bridge_id, @@ -323,7 +323,7 @@ impl, I: 'static> Pallet { ); }, Err(e) => { - log::debug!( + log::error!( target: LOG_TARGET, "Failed to resume the bridge {:?} and lane_id: {:?}, originated by the {:?}: {:?}", bridge_id, @@ -364,7 +364,7 @@ mod tests { use crate::{mock::*, Bridges, LanesManagerOf}; use bp_runtime::RangeInclusiveExt; - use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState, Receiver}; use bp_xcm_bridge_hub_router::ResolveBridgeId; use frame_support::{ assert_ok, @@ -451,7 +451,7 @@ mod tests { run_test(|| { let (bridge_id, _) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -469,7 +469,7 @@ mod tests { } open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); }); } @@ -482,11 +482,11 @@ mod tests { open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); } - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); - assert!(TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); }); } @@ -504,7 +504,7 @@ mod tests { OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, ); - assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); }); } @@ -519,7 +519,7 @@ mod tests { OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); - assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -537,7 +537,7 @@ mod tests { OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); - assert!(TestLocalXcmChannelManager::is_bridge_resumed()); + assert!(TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -603,6 +603,7 @@ mod tests { state: BridgeState::Opened, deposit: None, lane_id: expected_lane_id, + maybe_notify: None, }, ); } @@ -843,12 +844,22 @@ mod tests { // we need to set `UniversalLocation` for `sibling_parachain_origin` for `XcmOverBridgeWrappedWithExportMessageRouterInstance`. ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get())); + // we need to update `maybe_notify` for `bridge_1` with `pallet_index` of `XcmOverBridgeWrappedWithExportMessageRouter`, + Bridges::::mutate_extant(bridge_1.bridge_id(), |bridge| { + bridge.maybe_notify = Some(Receiver::new(57, 0)); + }); + // check before + // bridges are opened assert_eq!(XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, BridgeState::Opened); assert_eq!(XcmOverBridge::bridge(bridge_2.bridge_id()).unwrap().state, BridgeState::Opened); // both routers are uncongested assert!(!router_bridge_state::(&dest).map(|bs| bs.is_congested).unwrap_or(false)); assert!(!router_bridge_state::(&dest).map(|bs| bs.is_congested).unwrap_or(false)); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(bridge_2.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_2.bridge_id())); // make bridges congested with sending too much messages for _ in 1..(OUTBOUND_LANE_CONGESTED_THRESHOLD + 2) { @@ -861,11 +872,35 @@ mod tests { } // checks after + // bridges are suspended assert_eq!(XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, BridgeState::Suspended); assert_eq!(XcmOverBridge::bridge(bridge_2.bridge_id()).unwrap().state, BridgeState::Suspended); // both routers are congested assert!(router_bridge_state::(&dest).unwrap().is_congested); assert!(router_bridge_state::(&dest).unwrap().is_congested); + assert!(TestLocalXcmChannelManager::is_bridge_suspened(bridge_1.bridge_id())); + assert!(TestLocalXcmChannelManager::is_bridge_suspened(bridge_2.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_2.bridge_id())); + + // make bridges uncongested to trigger resume signal + XcmOverBridge::on_bridge_messages_delivered( + expected_lane_id_1, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + XcmOverBridge::on_bridge_messages_delivered( + expected_lane_id_2, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + // bridges are again opened + assert_eq!(XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, BridgeState::Opened); + assert_eq!(XcmOverBridge::bridge(bridge_2.bridge_id()).unwrap().state, BridgeState::Opened); + // both routers are uncongested + assert!(!router_bridge_state::(&dest).unwrap().is_congested); + assert!(!router_bridge_state::(&dest).unwrap().is_congested); + assert!(TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + assert!(TestLocalXcmChannelManager::is_bridge_resumed(bridge_2.bridge_id())); }) } } diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 658ad279aa7a4..75e76bd11b2bd 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -148,6 +148,7 @@ use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use bp_xcm_bridge_hub::{ BridgeLocations, BridgeLocationsError, Deposit, DepositOf, LocalXcmChannelManager, + ChannelStatusProvider as DispatchChannelStatusProvider, }; use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; use frame_system::Config as SystemConfig; @@ -164,6 +165,7 @@ pub use pallet::*; mod dispatcher; mod exporter; +pub mod congestion; pub mod migration; mod mock; @@ -241,10 +243,10 @@ pub mod pallet { /// For example, it is possible to make an exception for a system parachain or relay. type AllowWithoutBridgeDeposit: Contains; - /// Local XCM channel manager. - type LocalXcmChannelManager: LocalXcmChannelManager; + /// Local XCM channel manager. Dedicated to exporting capabilities when handling congestion with the sending side. + type LocalXcmChannelManager: LocalXcmChannelManager; /// XCM-level dispatcher for inbound bridge messages. - type BlobDispatcher: DispatchBlob; + type BlobDispatcher: DispatchBlob + DispatchChannelStatusProvider; } /// An alias for the bridge metadata. @@ -510,6 +512,7 @@ pub mod pallet { state: BridgeState::Opened, deposit: deposit.clone(), lane_id, + maybe_notify: None, }); Ok(()) }, @@ -879,6 +882,7 @@ mod tests { state: BridgeState::Opened, deposit, lane_id, + maybe_notify: None, }; Bridges::::insert(locations.bridge_id(), bridge.clone()); LaneToBridge::::insert(bridge.lane_id, locations.bridge_id()); @@ -1034,6 +1038,7 @@ mod tests { state: BridgeState::Opened, deposit: None, lane_id, + maybe_notify: None, }, ); @@ -1166,7 +1171,8 @@ mod tests { ), state: BridgeState::Opened, deposit: expected_deposit.clone(), - lane_id + lane_id, + maybe_notify: None, }), ); assert_eq!( @@ -1521,6 +1527,7 @@ mod tests { state: BridgeState::Opened, deposit: Some(Deposit::new(bridge_owner_account.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id, lane_id), @@ -1546,6 +1553,7 @@ mod tests { state: BridgeState::Opened, deposit: Some(Deposit::new(bridge_owner_account.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id_mismatch), (lane_id, lane_id), @@ -1571,6 +1579,7 @@ mod tests { state: BridgeState::Opened, deposit: Some(Deposit::new(bridge_owner_account_mismatch.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id, lane_id), @@ -1595,6 +1604,7 @@ mod tests { state: BridgeState::Opened, deposit: Some(Deposit::new(bridge_owner_account_mismatch.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id_mismatch), (lane_id, lane_id), @@ -1620,6 +1630,7 @@ mod tests { state: BridgeState::Opened, deposit: Some(Deposit::new(bridge_owner_account.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id_mismatch, lane_id), @@ -1645,6 +1656,7 @@ mod tests { state: BridgeState::Opened, deposit: Some(Deposit::new(bridge_owner_account, Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id, lane_id_mismatch), diff --git a/bridges/modules/xcm-bridge-hub/src/migration.rs b/bridges/modules/xcm-bridge-hub/src/migration.rs index dc1a17d130727..c9474e6283007 100644 --- a/bridges/modules/xcm-bridge-hub/src/migration.rs +++ b/bridges/modules/xcm-bridge-hub/src/migration.rs @@ -222,6 +222,7 @@ pub mod v1 { state, deposit, lane_id, + maybe_notify: None, }) }; Bridges::::translate_values(translate); diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 63f767045cf54..1e4575c543114 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -18,7 +18,7 @@ use sp_std::marker::PhantomData; use crate as pallet_xcm_bridge_hub; - +use pallet_xcm_bridge_hub::{congestion::{HereOrLocalConsensusXcmChannelManager, ReportBridgeStatusXcmChannelManager}}; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, ChainWithMessages, HashedLaneId, MessageNonce, @@ -33,7 +33,7 @@ use frame_support::{ weights::RuntimeDbWeight, }; use frame_support::traits::Get; -use frame_system::EnsureRootWithSuccess; +use frame_system::{EnsureNever, EnsureRoot, EnsureRootWithSuccess}; use polkadot_parachain_primitives::primitives::Sibling; use sp_core::H256; use sp_runtime::{ @@ -41,6 +41,7 @@ use sp_runtime::{ traits::{BlakeTwo256, ConstU32, IdentityLookup}, AccountId32, BuildStorage, StateVersion, }; +use sp_runtime::traits::Convert; use sp_std::cell::RefCell; use xcm::prelude::*; use xcm_builder::{ @@ -48,7 +49,7 @@ use xcm_builder::{ InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, SiblingParachainConvertsVia, SovereignPaidRemoteExporter, UnpaidLocalExporter, ensure_is_remote, }; -use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +use xcm_executor::{traits::{ConvertLocation, ConvertOrigin}, XcmExecutor}; pub type AccountId = AccountId32; pub type Balance = u64; @@ -189,6 +190,22 @@ pub fn bridged_asset_hub_universal_location() -> InteriorLocation { BridgedUniversalDestination::get() } +pub(crate) type TestLocalXcmChannelManager = TestingLocalXcmChannelManager< + BridgeId, + HereOrLocalConsensusXcmChannelManager< + BridgeId, + // handles congestion for `XcmOverBridgeByExportXcmRouter` + XcmOverBridgeByExportXcmRouter, + // handles congestion for `XcmOverBridgeWrappedWithExportMessageRouter` + ReportBridgeStatusXcmChannelManager< + TestRuntime, + (), + ReportBridgeStatusXcmProvider, + FromBridgeHubLocationXcmSender + >, + > +>; + impl pallet_xcm_bridge_hub::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; @@ -199,7 +216,7 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type MessageExportPrice = (); type DestinationVersion = AlwaysLatest; - type ForceOrigin = frame_system::EnsureNever<()>; + type ForceOrigin = EnsureNever<()>; type OpenBridgeOrigin = EitherOf< // We want to translate `RuntimeOrigin::root()` to the `Location::here()` EnsureRootWithSuccess, @@ -241,6 +258,8 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { >; type BridgeIdResolver = EnsureIsRemoteBridgeIdResolver; + // We convert to root here `BridgeHubLocationXcmOriginAsRoot` + type BridgeHubOrigin = EnsureRoot; } /// A router instance simulates a scenario where the router is deployed on the same chain as the @@ -253,6 +272,8 @@ impl pallet_xcm_bridge_hub_router::Config; type BridgeIdResolver = EnsureIsRemoteBridgeIdResolver; + // We don't need to support here `report_bridge_status`. + type BridgeHubOrigin = EnsureNever<()>; } /// Implementation of `ResolveBridgeId` returning `BridgeId` based on the configured `UniversalLocation`. @@ -287,12 +308,29 @@ thread_local! { pub static EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION: RefCell> = RefCell::new(None); } +pub struct BridgeHubLocationXcmOriginAsRoot(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) + } + } +} + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); type AssetTransactor = (); - type OriginConverter = (); + type OriginConverter = BridgeHubLocationXcmOriginAsRoot; type IsReserve = (); type IsTeleporter = (); type UniversalLocation = UniversalLocation; @@ -461,37 +499,78 @@ pub(crate) fn fund_origin_sovereign_account( bridge_owner_account } -pub struct TestLocalXcmChannelManager; +/// Testing wrapper implementation of `LocalXcmChannelManager`, that supports storing flags in storage to facilitate testing of `LocalXcmChannelManager` implementation. +pub struct TestingLocalXcmChannelManager(PhantomData<(Bridge, Tested)>); -impl TestLocalXcmChannelManager { - pub fn make_congested() { - frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Congested", &true); +impl TestingLocalXcmChannelManager { + fn suspended_key(bridge: &Bridge) -> Vec { + [b"SwitchedLocalXcmChannelManager.Suspended", bridge.encode().as_slice()].concat() + } + fn resumed_key(bridge: &Bridge) -> Vec { + [b"SwitchedLocalXcmChannelManager.Resumed", bridge.encode().as_slice()].concat() } - pub fn is_bridge_suspened() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Suspended") + pub fn is_bridge_suspened(bridge: &Bridge) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::suspended_key(bridge)) } - pub fn is_bridge_resumed() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Resumed") + pub fn is_bridge_resumed(bridge: &Bridge) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::resumed_key(bridge)) } } -impl LocalXcmChannelManager for TestLocalXcmChannelManager { - type Error = (); +impl> LocalXcmChannelManager for TestingLocalXcmChannelManager { + type Error = Tested::Error; + + fn suspend_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error> { + let result = Tested::suspend_bridge(local_origin, bridge); + + if result.is_ok() { + frame_support::storage::unhashed::put(&Self::suspended_key(&bridge), &true); + } - fn is_congested(_with: &Location) -> bool { - frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Congested") + result } - fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Suspended", &true); - Ok(()) + fn resume_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error> { + let result = Tested::resume_bridge(local_origin, bridge); + + if result.is_ok() { + frame_support::storage::unhashed::put(&Self::resumed_key(&bridge), &true); + } + + result } +} - fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Resumed", &true); - Ok(()) +/// 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: Weight::from_parts(10_000_000_000, 8 * 1024), + call: encoded_call.into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]) + } +} + +/// `SendXcm` implementation which sets `BridgeHubLocation` as origin for `ExecuteXcmOverSendXcm`. +pub struct FromBridgeHubLocationXcmSender(PhantomData); +impl SendXcm for FromBridgeHubLocationXcmSender { + type Ticket = Inner::Ticket; + + fn validate(destination: &mut Option, message: &mut Option>) -> SendResult { + Inner::validate(destination, message) + } + + fn deliver(ticket: Self::Ticket) -> Result { + ExecuteXcmOverSendXcm::set_origin_for_execute(BridgeHubLocation::get()); + Inner::deliver(ticket) } } @@ -501,6 +580,20 @@ impl TestBlobDispatcher { pub fn is_dispatched() -> bool { frame_support::storage::unhashed::get_or_default(b"TestBlobDispatcher.Dispatched") } + + fn congestion_key(with: &Location) -> Vec { + [b"TestBlobDispatcher.Congested.", with.encode().as_slice()].concat() + } + + pub fn make_congested(with: &Location) { + frame_support::storage::unhashed::put(&Self::congestion_key(with), &true); + } +} + +impl pallet_xcm_bridge_hub::DispatchChannelStatusProvider for TestBlobDispatcher { + fn is_congested(with: &Location) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::congestion_key(with)) + } } impl DispatchBlob for TestBlobDispatcher { diff --git a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs index c894e577f6816..a87bec8e227ee 100644 --- a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs @@ -24,21 +24,6 @@ use sp_core::{H256, sp_std::fmt::Debug}; use sp_runtime::{FixedU128, RuntimeDebug}; use xcm::latest::prelude::{Location, NetworkId, InteriorLocation}; -/// XCM channel status provider that may report whether it is congested or not. -/// -/// By the channel we mean the physical channel that is used to deliver messages of one -/// of the bridge queues. -pub trait XcmChannelStatusProvider { - /// Returns true if the channel is currently congested. - fn is_congested(with: &Location) -> bool; -} - -impl XcmChannelStatusProvider for () { - fn is_congested(_with: &Location) -> bool { - false - } -} - /// Current status of the bridge. #[derive(Clone, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] pub struct BridgeState { diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index ac98efe72372d..ea52acfd10865 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -96,42 +96,45 @@ impl core::fmt::Debug for BridgeId { } /// Local XCM channel manager. -pub trait LocalXcmChannelManager { +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>; + fn suspend_bridge(local_origin: &Location, bridge: Bridge) -> 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>; + fn resume_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error>; } -impl LocalXcmChannelManager for () { +impl LocalXcmChannelManager for () { type Error = (); - fn is_congested(_with: &Location) -> bool { - false + fn suspend_bridge(_local_origin: &Location, _bridge: Bridge) -> Result<(), Self::Error> { + Ok(()) } - fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + fn resume_bridge(_local_origin: &Location, _bridge: Bridge) -> Result<(), Self::Error> { Ok(()) } +} - fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - Ok(()) +/// Channel status provider that may report whether it is congested or not. +pub trait ChannelStatusProvider { + /// Returns true if the channel is currently active and can be used. + fn is_congested(with: &Location) -> bool; +} + +/// Default implementation of `ChannelStatusProvider`, indicating no congestion. +impl ChannelStatusProvider for () { + fn is_congested(_with: &Location) -> bool { + false } } @@ -176,6 +179,30 @@ pub struct Bridge { /// Mapping to the unique `LaneId`. pub lane_id: LaneId, + + /// Holds data about the `bridge_origin_relative_location` where notifications can be sent for handling congestion. + pub maybe_notify: Option, +} + +/// Receiver metadata. +#[derive( + CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound, +)] +pub struct Receiver { + /// Pallet index. + pub pallet_index: u8, + /// Call/extrinsic index. + pub call_index: u8, +} + +impl Receiver { + /// Create a new receiver. + pub fn new(pallet_index: u8, call_index: u8) -> Self { + Self { + pallet_index, + call_index, + } + } } /// An alias for the bridge deposit of `ThisChain`. diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 9c7470eda6da4..cb33b8232ab27 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -37,7 +37,7 @@ frame-benchmarking = { optional = true, workspace = true } bounded-collections = { workspace = true } # Bridges -bp-xcm-bridge-hub-router = { optional = true, workspace = true } +bp-xcm-bridge-hub = { optional = true, workspace = true } [dev-dependencies] @@ -53,7 +53,7 @@ cumulus-pallet-parachain-system = { workspace = true, default-features = true } default = ["std"] std = [ "bounded-collections/std", - "bp-xcm-bridge-hub-router?/std", + "bp-xcm-bridge-hub?/std", "codec/std", "cumulus-primitives-core/std", "frame-benchmarking?/std", @@ -96,4 +96,4 @@ try-runtime = [ "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] -bridging = ["bp-xcm-bridge-hub-router"] +bridging = ["bp-xcm-bridge-hub"] diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 8ed11505a27a9..d896a40cb7052 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -17,11 +17,11 @@ use crate::{pallet, OutboundState}; use cumulus_primitives_core::ParaId; use xcm::latest::prelude::*; -/// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks +/// 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_router::XcmChannelStatusProvider +impl bp_xcm_bridge_hub::ChannelStatusProvider for InAndOutXcmpChannelStatusProvider { fn is_congested(with: &Location) -> bool { @@ -45,10 +45,10 @@ impl bp_xcm_bridge_hub_router::XcmChannelStatusProvider } } -/// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks +/// Adapter implementation for `bp_xcm_bridge_hub::ChannelStatusProvider` which checks /// only `OutboundXcmpStatus` for defined `SiblingParaId` if is suspended. pub struct OutXcmpChannelStatusProvider(core::marker::PhantomData); -impl bp_xcm_bridge_hub_router::XcmChannelStatusProvider +impl bp_xcm_bridge_hub::ChannelStatusProvider for OutXcmpChannelStatusProvider { fn is_congested(with: &Location) -> bool {