diff --git a/Cargo.lock b/Cargo.lock index 14d6b177ef..3fa4042205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1755,6 +1755,8 @@ dependencies = [ "bp-polkadot-core", "bp-relayers", "bp-runtime", + "bp-xcm-bridge-hub", + "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-hub-test-utils", "bridge-runtime-common", @@ -1899,6 +1901,8 @@ dependencies = [ "bp-polkadot-core", "bp-relayers", "bp-runtime", + "bp-xcm-bridge-hub", + "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-hub-test-utils", "bridge-runtime-common", diff --git a/Cargo.toml b/Cargo.toml index 8f44675da1..3c91060a80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ bp-polkadot-bulletin = { version = "0.15.0", default-features = false } bp-polkadot-core = { version = "0.18.0", default-features = false } bp-relayers = { version = "0.18.0", default-features = false } bp-runtime = { version = "0.18.0", default-features = false } +bp-xcm-bridge-hub = { version = "0.4.0", default-features = false } bp-xcm-bridge-hub-router = { version = "0.14.1", default-features = false } bridge-hub-common = { version = "0.10.0", default-features = false } bridge-hub-kusama-emulated-chain = { path = "integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama" } diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs index d399b81ba6..c0898617be 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs @@ -860,7 +860,6 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; - // TODO: @bkontur - change to `report_bridge_status` when patched - FAIL-CI type LocalXcmChannelManager = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; } diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml b/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml index c2b201ff7f..e61468c8de 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -96,6 +96,8 @@ bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-kusama = { workspace = true } bp-polkadot = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } bridge-hub-common = { workspace = true } bridge-runtime-common = { workspace = true } pallet-bridge-grandpa = { workspace = true } @@ -129,6 +131,8 @@ std = [ "bp-polkadot/std", "bp-relayers/std", "bp-runtime/std", + "bp-xcm-bridge-hub-router/std", + "bp-xcm-bridge-hub/std", "bridge-hub-common/std", "bridge-runtime-common/std", "codec/std", diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/src/bridge_to_polkadot_config.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/src/bridge_to_polkadot_config.rs index c1fca39d40..d67280ecc2 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/src/bridge_to_polkadot_config.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/src/bridge_to_polkadot_config.rs @@ -253,12 +253,134 @@ impl pallet_xcm_bridge_hub::Config for Runtime type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO: @acatangiu (bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 - // @acatangiu - type LocalXcmChannelManager = (); + type LocalXcmChannelManager = XcmpQueueChannelManager; type BlobDispatcher = FromPolkadotMessageBlobDispatcher; } +/// Implementation `bp_xcm_bridge_hub::LocalXcmChannelManager`. +pub struct XcmpQueueChannelManager; +impl bp_xcm_bridge_hub::LocalXcmChannelManager for XcmpQueueChannelManager { + type Error = (); + + fn is_congested(with: &Location) -> bool { + // This is used to check the inbound queue/messages to determine if they can be dispatched and sent to the sibling parachain. Therefore, checking `OutXcmp` is sufficient. + use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::::is_congested(with) + } + + fn suspend_bridge(_local_origin: &Location, _: pallet_xcm_bridge_hub::BridgeId) -> Result<(), Self::Error> { + // IMPORTANT NOTE: + // + // Unfortunately, `https://github.com/paritytech/polkadot-sdk/pull/6231` reworked congestion is not yet released. + // + // And unfortunately, we don't have access to `XcmpQueue::send_signal(para, ChannelSignal::Suspend)` here (which would require patch release), + // we can add this hacky workaround/tmp/implementation that should trigger `ChannelSignal::Suspend`, e.g.: + /* + use crate::{MessageQueue, XcmpQueue}; + use bridge_hub_common::message_queue::AggregateMessageOrigin; + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::traits::EnqueueMessage; + use frame_support::pallet_prelude::OptionQuery; + use pallet_message_queue::OnQueueChanged; + use scale_info::TypeInfo; + + // get sibling para id + let local_origin_para_id: crate::ParaId = match local_origin.unpack() { + (1, [Parachain(id)]) => (*id).into(), + _ => return Err(()) + }; + + // read `suspend_threshold` from `XcmpQueue` storage + #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] + struct QueueConfigData { + suspend_threshold: u32, + drop_threshold: u32, + resume_threshold: u32, + } + #[frame_support::storage_alias] + type QueueConfig = StorageValue; + let suspend_threshold = match QueueConfig::get() { + Some(qc) => qc.suspend_threshold, + None => return Err(()) + }; + + // Now, this should trigger `XcmpQueue::send_signal(para, ChannelSignal::Suspend)` + let mut qf = MessageQueue::footprint(AggregateMessageOrigin::Sibling(local_origin_para_id)); + qf.ready_pages = suspend_threshold; + XcmpQueue::on_queue_changed(local_origin_para_id.into(), qf); + */ + + // IMPORTANT NOTE2: + // + // In the current setup, this code is likely triggered only for the hard-coded AHK<>AHP lane, as we do not support any other bridge lanes on BridgeHubs. + // It is triggered only when `pallet_bridge_messages::OutboundMessages` reaches 8,192 undelivered messages. + // The potential risk of keeping `Ok(())` or `Err(())` here is that `pallet_bridge_messages::OutboundMessages` may continue to grow: + // + // ``` + // #[pallet::storage] + // pub type OutboundMessages, I: 'static = ()> = + // StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; + // ``` + + // TODO: decide: + // 1. wait for patch-release stable2409-3 2024-12-12 + // 2. go with `Ok(())` / `Err(())` + // 3. go with `XcmpQueue::send_signal` temporary workaround till patch release + + Ok(()) + } + + fn resume_bridge(_local_origin: &Location, _: pallet_xcm_bridge_hub::BridgeId) -> Result<(), Self::Error> { + // IMPORTANT NOTE: + // + // Unfortunately, `https://github.com/paritytech/polkadot-sdk/pull/6231` reworked congestion is not yet released. + // + // And unfortunately, we don't have access to `XcmpQueue::send_signal(para, ChannelSignal::Resume)` here (which would require patch release), + // we can add this hacky workaround/tmp/implementation that should trigger `ChannelSignal::Resume`, e.g.: + /* + use crate::{MessageQueue, XcmpQueue}; + use bridge_hub_common::message_queue::AggregateMessageOrigin; + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::traits::EnqueueMessage; + use frame_support::pallet_prelude::OptionQuery; + use pallet_message_queue::OnQueueChanged; + use scale_info::TypeInfo; + + // get sibling para id + let local_origin_para_id: crate::ParaId = match local_origin.unpack() { + (1, [Parachain(id)]) => (*id).into(), + _ => return Err(()) + }; + + // read `resume_threshold` from `XcmpQueue` storage + #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] + struct QueueConfigData { + suspend_threshold: u32, + drop_threshold: u32, + resume_threshold: u32, + } + #[frame_support::storage_alias] + type QueueConfig = StorageValue; + let resume_threshold = match QueueConfig::get() { + Some(qc) => qc.resume_threshold, + None => return Err(()) + }; + + // Now, this should trigger `XcmpQueue::send_signal(para, ChannelSignal::Resume)` + let mut qf = MessageQueue::footprint(AggregateMessageOrigin::Sibling(local_origin_para_id)); + qf.ready_pages = resume_threshold; + XcmpQueue::on_queue_changed(local_origin_para_id.into(), qf); + */ + + // TODO: decide: + // 1. wait for patch-release stable2409-3 2024-12-12 + // 2. go with `Ok(())` / `Err(())` + // 3. go with `XcmpQueue::send_signal` temporary workaround till patch release + + Ok(()) + } +} + #[cfg(feature = "runtime-benchmarks")] pub(crate) fn open_bridge_for_benchmarks( with: pallet_xcm_bridge_hub::LaneIdOf, diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml index a5d12b7637..75598dc389 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -96,6 +96,8 @@ bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-kusama = { workspace = true } bp-polkadot = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } bridge-hub-common = { workspace = true } bridge-runtime-common = { workspace = true } pallet-bridge-grandpa = { workspace = true } @@ -143,6 +145,8 @@ std = [ "bp-polkadot/std", "bp-relayers/std", "bp-runtime/std", + "bp-xcm-bridge-hub-router/std", + "bp-xcm-bridge-hub/std", "bridge-hub-common/std", "bridge-runtime-common/std", "codec/std", diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_kusama_config.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_kusama_config.rs index 7d21d4acfe..3c14b4f201 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_kusama_config.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_kusama_config.rs @@ -253,11 +253,134 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO: @acatangiu (bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 - type LocalXcmChannelManager = (); + type LocalXcmChannelManager = XcmpQueueChannelManager; type BlobDispatcher = FromKusamaMessageBlobDispatcher; } +/// Implementation `bp_xcm_bridge_hub::LocalXcmChannelManager`. +pub struct XcmpQueueChannelManager; +impl bp_xcm_bridge_hub::LocalXcmChannelManager for XcmpQueueChannelManager { + type Error = (); + + fn is_congested(with: &Location) -> bool { + // This is used to check the inbound queue/messages to determine if they can be dispatched and sent to the sibling parachain. Therefore, checking `OutXcmp` is sufficient. + use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::::is_congested(with) + } + + fn suspend_bridge(_local_origin: &Location, _: pallet_xcm_bridge_hub::BridgeId) -> Result<(), Self::Error> { + // IMPORTANT NOTE: + // + // Unfortunately, `https://github.com/paritytech/polkadot-sdk/pull/6231` reworked congestion is not yet released. + // + // And unfortunately, we don't have access to `XcmpQueue::send_signal(para, ChannelSignal::Suspend)` here (which would require patch release), + // we can add this hacky workaround/tmp/implementation that should trigger `ChannelSignal::Suspend`, e.g.: + /* + use crate::{MessageQueue, XcmpQueue}; + use bridge_hub_common::message_queue::AggregateMessageOrigin; + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::traits::EnqueueMessage; + use frame_support::pallet_prelude::OptionQuery; + use pallet_message_queue::OnQueueChanged; + use scale_info::TypeInfo; + + // get sibling para id + let local_origin_para_id: crate::ParaId = match _local_origin.unpack() { + (1, [Parachain(id)]) => (*id).into(), + _ => return Err(()) + }; + + // read `suspend_threshold` from `XcmpQueue` storage + #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] + struct QueueConfigData { + suspend_threshold: u32, + drop_threshold: u32, + resume_threshold: u32, + } + #[frame_support::storage_alias] + type QueueConfig = StorageValue; + let suspend_threshold = match QueueConfig::get() { + Some(qc) => qc.suspend_threshold, + None => return Err(()) + }; + + // Now, this should trigger `XcmpQueue::send_signal(para, ChannelSignal::Suspend)` + let mut qf = MessageQueue::footprint(AggregateMessageOrigin::Sibling(local_origin_para_id)); + qf.ready_pages = suspend_threshold; + XcmpQueue::on_queue_changed(local_origin_para_id.into(), qf); + */ + + // IMPORTANT NOTE2: + // + // In the current setup, this code is likely triggered only for the hard-coded AHK<>AHP lane, as we do not support any other bridge lanes on BridgeHubs. + // It is triggered only when `pallet_bridge_messages::OutboundMessages` reaches 8,192 undelivered messages. + // The potential risk of keeping `Ok(())` or `Err(())` here is that `pallet_bridge_messages::OutboundMessages` may continue to grow: + // + // ``` + // #[pallet::storage] + // pub type OutboundMessages, I: 'static = ()> = + // StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; + // ``` + + // TODO: decide: + // 1. wait for patch-release stable2409-3 2024-12-12 + // 2. go with `Ok(())` / `Err(())` + // 3. go with `XcmpQueue::send_signal` temporary workaround till patch release + + Ok(()) + } + + fn resume_bridge(_local_origin: &Location, _: pallet_xcm_bridge_hub::BridgeId) -> Result<(), Self::Error> { + // IMPORTANT NOTE: + // + // Unfortunately, `https://github.com/paritytech/polkadot-sdk/pull/6231` reworked congestion is not yet released. + // + // And unfortunately, we don't have access to `XcmpQueue::send_signal(para, ChannelSignal::Resume)` here (which would require patch release), + // we can add this hacky workaround/tmp/implementation that should trigger `ChannelSignal::Resume`, e.g.: + /* + use crate::{MessageQueue, XcmpQueue}; + use bridge_hub_common::message_queue::AggregateMessageOrigin; + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::traits::EnqueueMessage; + use frame_support::pallet_prelude::OptionQuery; + use pallet_message_queue::OnQueueChanged; + use scale_info::TypeInfo; + + // get sibling para id + let local_origin_para_id: crate::ParaId = match _local_origin.unpack() { + (1, [Parachain(id)]) => (*id).into(), + _ => return Err(()) + }; + + // read `resume_threshold` from `XcmpQueue` storage + #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] + struct QueueConfigData { + suspend_threshold: u32, + drop_threshold: u32, + resume_threshold: u32, + } + #[frame_support::storage_alias] + type QueueConfig = StorageValue; + let resume_threshold = match QueueConfig::get() { + Some(qc) => qc.resume_threshold, + None => return Err(()) + }; + + // Now, this should trigger `XcmpQueue::send_signal(para, ChannelSignal::Resume)` + let mut qf = MessageQueue::footprint(AggregateMessageOrigin::Sibling(local_origin_para_id)); + qf.ready_pages = resume_threshold; + XcmpQueue::on_queue_changed(local_origin_para_id.into(), qf); + */ + + // TODO: decide: + // 1. wait for patch-release stable2409-3 2024-12-12 + // 2. go with `Ok(())` / `Err(())` + // 3. go with `XcmpQueue::send_signal` temporary workaround till patch release + + Ok(()) + } +} + #[cfg(feature = "runtime-benchmarks")] pub(crate) fn open_bridge_for_benchmarks( with: pallet_xcm_bridge_hub::LaneIdOf,