diff --git a/Cargo.lock b/Cargo.lock index 02d7da8f7657..94b218b457ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1929,22 +1929,10 @@ dependencies = [ [[package]] name = "bp-asset-hub-rococo" version = "0.4.0" -dependencies = [ - "bp-xcm-bridge-hub-router 0.6.0", - "frame-support 28.0.0", - "parity-scale-codec", - "scale-info", -] [[package]] name = "bp-asset-hub-westend" version = "0.3.0" -dependencies = [ - "bp-xcm-bridge-hub-router 0.6.0", - "frame-support 28.0.0", - "parity-scale-codec", - "scale-info", -] [[package]] name = "bp-beefy" @@ -4969,7 +4957,7 @@ name = "cumulus-pallet-xcmp-queue" version = "0.7.0" dependencies = [ "bounded-collections", - "bp-xcm-bridge-hub-router 0.6.0", + "bp-xcm-bridge-hub 0.2.0", "cumulus-pallet-parachain-system 0.7.0", "cumulus-primitives-core 0.7.0", "frame-benchmarking 28.0.0", @@ -15956,6 +15944,7 @@ dependencies = [ "bp-messages 0.7.0", "bp-runtime 0.7.0", "bp-xcm-bridge-hub 0.2.0", + "frame-benchmarking 28.0.0", "frame-support 28.0.0", "frame-system 28.0.0", "log", @@ -16001,6 +15990,7 @@ dependencies = [ name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ + "bp-xcm-bridge-hub 0.2.0", "bp-xcm-bridge-hub-router 0.6.0", "frame-benchmarking 28.0.0", "frame-support 28.0.0", diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index 363a869048aa..7a83bba87481 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -14,20 +14,7 @@ exclude-from-umbrella = true workspace = true [dependencies] -codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } - -# Substrate Dependencies -frame-support = { workspace = true } - -# Bridge Dependencies -bp-xcm-bridge-hub-router = { workspace = true } [features] default = ["std"] -std = [ - "bp-xcm-bridge-hub-router/std", - "codec/std", - "frame-support/std", - "scale-info/std", -] +std = [] diff --git a/bridges/chains/chain-asset-hub-rococo/src/lib.rs b/bridges/chains/chain-asset-hub-rococo/src/lib.rs index de2e9ae856d1..3504be9bb0f8 100644 --- a/bridges/chains/chain-asset-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-asset-hub-rococo/src/lib.rs @@ -18,31 +18,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; -use scale_info::TypeInfo; - -pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; - -/// `AssetHubRococo` Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to `AssetHubRococo` chain. -/// Ideally this code would be auto-generated from metadata, because we want to -/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. -/// -/// All entries here (like pretty much in the entire file) must be kept in sync with -/// `AssetHubRococo` `construct_runtime`, so that we maintain SCALE-compatibility. -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// `ToWestendXcmRouter` bridge pallet. - #[codec(index = 45)] - ToWestendXcmRouter(XcmBridgeHubRouterCall), -} - -frame_support::parameter_types! { - /// Some sane weight to execute `xcm::Transact(pallet-xcm-bridge-hub-router::Call::report_bridge_status)`. - pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); -} - /// Identifier of AssetHubRococo in the Rococo relay chain. pub const ASSET_HUB_ROCOCO_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 430d9b6116cf..ad8d2778a4bc 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -14,20 +14,7 @@ exclude-from-umbrella = true workspace = true [dependencies] -codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } - -# Substrate Dependencies -frame-support = { workspace = true } - -# Bridge Dependencies -bp-xcm-bridge-hub-router = { workspace = true } [features] default = ["std"] -std = [ - "bp-xcm-bridge-hub-router/std", - "codec/std", - "frame-support/std", - "scale-info/std", -] +std = [] diff --git a/bridges/chains/chain-asset-hub-westend/src/lib.rs b/bridges/chains/chain-asset-hub-westend/src/lib.rs index 9de1c8809894..c21bdff45934 100644 --- a/bridges/chains/chain-asset-hub-westend/src/lib.rs +++ b/bridges/chains/chain-asset-hub-westend/src/lib.rs @@ -18,31 +18,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; -use scale_info::TypeInfo; - -pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; - -/// `AssetHubWestend` Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to `AssetHubWestend` chain. -/// Ideally this code would be auto-generated from metadata, because we want to -/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. -/// -/// All entries here (like pretty much in the entire file) must be kept in sync with -/// `AssetHubWestend` `construct_runtime`, so that we maintain SCALE-compatibility. -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// `ToRococoXcmRouter` bridge pallet. - #[codec(index = 34)] - ToRococoXcmRouter(XcmBridgeHubRouterCall), -} - -frame_support::parameter_types! { - /// Some sane weight to execute `xcm::Transact(pallet-xcm-bridge-hub-router::Call::report_bridge_status)`. - pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); -} - /// Identifier of AssetHubWestend in the Westend relay chain. pub const ASSET_HUB_WESTEND_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index fda6a5f0b722..8683fb31037d 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -105,7 +105,7 @@ frame_support::parameter_types! { /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Rococo /// BridgeHub. /// (initially was calculated by test `BridgeHubRococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) - pub const BridgeHubRococoBaseXcmFeeInRocs: u128 = 57_145_832; + pub const BridgeHubRococoBaseXcmFeeInRocs: u128 = 57_325_000; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index e941b5840238..9456089593c6 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -94,7 +94,7 @@ frame_support::parameter_types! { /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Westend /// BridgeHub. /// (initially was calculated by test `BridgeHubWestend::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) - pub const BridgeHubWestendBaseXcmFeeInWnds: u128 = 18_191_740_000; + pub const BridgeHubWestendBaseXcmFeeInWnds: u128 = 18_248_930_000; /// Transaction fee that is paid at the Westend BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index 34d280d26d6e..bfabfe3c3ed5 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -454,7 +454,6 @@ mod tests { use bp_runtime::{BasicOperatingMode, HeaderId, Parachain}; use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID}; use frame_support::{ - __private::sp_tracing, assert_storage_noop, parameter_types, traits::{fungible::Mutate, ReservableCurrency}, weights::Weight, @@ -1127,7 +1126,6 @@ mod tests { Option>, TransactionValidityError, > { - sp_tracing::try_init_simple(); let extension: TestExtension = BridgeRelayersTransactionExtension(PhantomData); extension .validate_and_prepare( diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 55824f6a7fe7..1cda8893967e 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/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index 3c4a10f82e7d..a44d478a5b7a 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -18,10 +18,10 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{DeliveryFeeFactor, MINIMAL_DELIVERY_FEE_FACTOR}; -use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; -use frame_support::traits::{Get, Hooks}; -use sp_runtime::traits::Zero; +use crate::{BridgeState, Bridges, Call, ResolveBridgeId, MINIMAL_DELIVERY_FEE_FACTOR}; +use frame_benchmarking::v2::*; +use frame_support::traits::{EnsureOriginWithArg, Hooks}; +use sp_runtime::{traits::Zero, Saturating}; use xcm::prelude::*; /// Pallet we're benchmarking here. @@ -29,32 +29,84 @@ pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Trait that must be implemented by runtime to be able to benchmark pallet properly. pub trait Config: crate::Config { - /// Fill up queue so it becomes congested. - fn make_congested(); - /// Returns destination which is valid for this router instance. - /// (Needs to pass `T::Bridges`) - /// Make sure that `SendXcm` will pass. - fn ensure_bridged_target_destination() -> Result { - Ok(Location::new( - Self::UniversalLocation::get().len() as u8, - [GlobalConsensus(Self::BridgedNetworkId::get().unwrap())], - )) - } + fn ensure_bridged_target_destination() -> Result; + /// Returns valid origin for `report_bridge_status` (if `T::BridgeHubOrigin` is supported). + fn report_bridge_status_origin() -> Option; } -benchmarks_instance_pallet! { - on_initialize_when_non_congested { - DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); - }: { - crate::Pallet::::on_initialize(Zero::zero()) +#[instance_benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn on_idle_when_bridge_state_removed() -> Result<(), BenchmarkError> { + let bridge_id = + T::BridgeIdResolver::resolve_for_dest(&T::ensure_bridged_target_destination()?) + .ok_or(BenchmarkError::Weightless)?; + + // uncongested and less than a minimal factor is removed + Bridges::::insert( + &bridge_id, + BridgeState { delivery_fee_factor: 0.into(), is_congested: false }, + ); + assert!(Bridges::::get(&bridge_id).is_some()); + + #[block] + { + let _ = crate::Pallet::::on_idle(Zero::zero(), Weight::MAX); + } + + assert!(Bridges::::get(bridge_id).is_none()); + + Ok(()) } - on_initialize_when_congested { - DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); - let _ = T::ensure_bridged_target_destination()?; - T::make_congested(); - }: { - crate::Pallet::::on_initialize(Zero::zero()) + #[benchmark] + fn on_indle_when_bridge_state_updated() -> Result<(), BenchmarkError> { + let bridge_id = + T::BridgeIdResolver::resolve_for_dest(&T::ensure_bridged_target_destination()?) + .ok_or(BenchmarkError::Weightless)?; + + // uncongested and higher than a minimal factor is decreased + let old_delivery_fee_factor = MINIMAL_DELIVERY_FEE_FACTOR.saturating_mul(1000.into()); + Bridges::::insert( + &bridge_id, + BridgeState { delivery_fee_factor: old_delivery_fee_factor, is_congested: false }, + ); + assert!(Bridges::::get(&bridge_id).is_some()); + + #[block] + { + let _ = crate::Pallet::::on_idle(Zero::zero(), Weight::MAX); + } + + assert!( + Bridges::::get(bridge_id).unwrap().delivery_fee_factor < old_delivery_fee_factor + ); + Ok(()) } + + #[benchmark] + fn report_bridge_status() -> Result<(), BenchmarkError> { + let bridge_id = + T::BridgeIdResolver::resolve_for_dest(&T::ensure_bridged_target_destination()?) + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let origin = T::report_bridge_status_origin() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let _ = T::BridgeHubOrigin::try_origin(origin.clone(), &bridge_id) + .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let is_congested = true; + + #[extrinsic_call] + report_bridge_status(origin as T::RuntimeOrigin, bridge_id.clone(), is_congested); + + assert_eq!( + Bridges::::get(&bridge_id), + Some(BridgeState { delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, is_congested }) + ); + Ok(()) + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime); } diff --git a/bridges/modules/xcm-bridge-hub-router/src/impls.rs b/bridges/modules/xcm-bridge-hub-router/src/impls.rs new file mode 100644 index 000000000000..255c2f37ff81 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub-router/src/impls.rs @@ -0,0 +1,366 @@ +// Copyright (C) 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 . + +//! Various implementations supporting easier configuration of the pallet. + +use crate::{BridgeIdOf, Bridges, Config, Pallet, LOG_TARGET}; +use bp_xcm_bridge_hub_router::ResolveBridgeId; +use codec::Encode; +use frame_support::{ensure, pallet_prelude::PhantomData, traits::Get}; +use xcm::prelude::*; +use xcm_builder::{ensure_is_remote, ExporterFor}; + +/// Implementation of [`bp_xcm_bridge_hub::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(()) + } +} + +/// Adapter implementation for [`ExporterFor`] that allows exporting message size fee and/or dynamic +/// fees based on the `BridgeId` resolved by the `T::BridgeIdResolver` resolver, if and only if the +/// `E` exporter supports bridging. This adapter acts as an [`ExporterFor`], for example, for the +/// [`xcm_builder::SovereignPaidRemoteExporter`], enabling it to compute message and/or dynamic fees +/// using a fee factor. +pub struct ViaRemoteBridgeHubExporter(PhantomData<(T, I, E, BNF, BHLF)>); +impl, I: 'static, E, BridgedNetworkIdFilter, BridgeHubLocationFilter> ExporterFor + for ViaRemoteBridgeHubExporter +where + E: ExporterFor, + BridgedNetworkIdFilter: Get>, + BridgeHubLocationFilter: Get>, +{ + fn exporter_for( + network: &NetworkId, + remote_location: &InteriorLocation, + message: &Xcm<()>, + ) -> Option<(Location, Option)> { + log::trace!( + target: LOG_TARGET, + "exporter_for - network: {network:?}, remote_location: {remote_location:?}, msg: {message:?}", + ); + // ensure that the message is sent to the expected bridged network (if specified). + if let Some(bridged_network) = BridgedNetworkIdFilter::get() { + if *network != bridged_network { + log::trace!( + target: LOG_TARGET, + "Router with bridged_network_id filter({bridged_network:?}) does not support bridging to network {network:?}!", + ); + return None + } + } + + // ensure that the message is sent to the expected bridged network and location. + let (bridge_hub_location, maybe_payment) = match E::exporter_for( + network, + remote_location, + message, + ) { + Some((bridge_hub_location, maybe_payment)) => match BridgeHubLocationFilter::get() { + Some(expected_bridge_hub_location) + if expected_bridge_hub_location.eq(&bridge_hub_location) => + (bridge_hub_location, maybe_payment), + None => (bridge_hub_location, maybe_payment), + _ => { + log::trace!( + target: LOG_TARGET, + "Resolved bridge_hub_location: {:?} does not match expected one: {:?} for bridging to network {:?} and remote_location {:?}!", + bridge_hub_location, + BridgeHubLocationFilter::get(), + network, + remote_location, + ); + return None + }, + }, + _ => { + log::trace!( + target: LOG_TARGET, + "Inner `E` router does not support bridging to network {:?} and remote_location {:?}!", + network, + remote_location, + ); + return None + }, + }; + + // calculate message size fees (if configured) + let maybe_message_size_fees = + Pallet::::calculate_message_size_fee(|| message.encoded_size() as _); + + // compute actual fees - sum(actual payment, message size fees) if possible + let mut fees = match (maybe_payment, maybe_message_size_fees) { + (Some(payment), None) => Some(payment), + (None, Some(message_size_fees)) => Some(message_size_fees), + (None, None) => None, + ( + Some(Asset { id: payment_asset_id, fun: Fungible(payment_amount) }), + Some(Asset { + id: message_size_fees_asset_id, + fun: Fungible(message_size_fees_amount), + }), + ) if payment_asset_id.eq(&message_size_fees_asset_id) => { + // we can subsume two assets with the same asset_id and fungibility. + Some( + (payment_asset_id, payment_amount.saturating_add(message_size_fees_amount)) + .into(), + ) + }, + (Some(payment), Some(message_size_fees)) => { + log::error!( + target: LOG_TARGET, + "Router is configured for `T::FeeAsset` {:?} \ + but we have two different assets which cannot be calculated as one result asset: payment: {:?} and message_size_fees: {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!", + T::FeeAsset::get(), + payment, + message_size_fees, + bridge_hub_location, + network, + remote_location, + ); + return None + }, + }; + + // Here, we have the actual result fees covering bridge fees, so now we need to check/apply + // the congestion and dynamic_fees features (if possible). + if let Some(bridge_id) = T::BridgeIdResolver::resolve_for(network, remote_location) { + if let Some(bridge_state) = Bridges::::get(bridge_id) { + fees = fees.map(|f| Pallet::::calculate_dynamic_fee(&bridge_state, f)); + } + } + + Some((bridge_hub_location, fees)) + } +} + +/// Adapter implementation for [`SendXcm`] that allows adding a message size fee and/or dynamic fees +/// based on the `BridgeId` resolved by the `T::BridgeIdResolver` resolver, if and only if `E` +/// supports routing. This adapter can be used, for example, as a wrapper over +/// [`xcm_builder::UnpaidLocalExporter`], enabling it to compute message and/or dynamic fees using a +/// fee factor. +pub struct ViaLocalBridgeHubExporter(PhantomData<(T, I, E)>); +impl, I: 'static, E: SendXcm> SendXcm for ViaLocalBridgeHubExporter { + type Ticket = E::Ticket; + + fn validate( + destination: &mut Option, + message: &mut Option>, + ) -> SendResult { + let dest_clone = destination.clone().ok_or(SendError::MissingArgument)?; + let message_size = message.as_ref().map_or(0, |message| message.encoded_size()) as _; + + match E::validate(destination, message) { + Ok((ticket, mut fees)) => { + // calculate message size fees (if configured) + let maybe_message_size_fees = + Pallet::::calculate_message_size_fee(|| message_size); + if let Some(message_size_fees) = maybe_message_size_fees { + fees.push(message_size_fees); + } + + // Here, we have the actual result fees covering bridge fees, so now we need to + // check/apply the congestion and dynamic_fees features (if possible). + if let Some(bridge_id) = T::BridgeIdResolver::resolve_for_dest(&dest_clone) { + if let Some(bridge_state) = Bridges::::get(bridge_id) { + let mut dynamic_fees = sp_std::vec::Vec::with_capacity(fees.len()); + for fee in fees.into_inner() { + dynamic_fees + .push(Pallet::::calculate_dynamic_fee(&bridge_state, fee)); + } + fees = Assets::from(dynamic_fees); + } + } + + // return original ticket with possibly extended fees + Ok((ticket, fees)) + }, + error => error, + } + } + + fn deliver(ticket: Self::Ticket) -> Result { + E::deliver(ticket) + } +} + +/// 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) { + 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 super::*; + + #[test] + fn ensure_is_remote_bridge_id_resolver_works() { + 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() + ), + ); + } +} diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index fe8f5a2efdfb..ae708fd0d6e4 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -14,34 +14,67 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Pallet that may be used instead of `SovereignPaidRemoteExporter` in the XCM router -//! configuration. The main thing that the pallet offers is the dynamic message fee, -//! that is computed based on the bridge queues state. It starts exponentially increasing -//! if the queue between this chain and the sibling/child bridge hub is congested. +//! A pallet that can be used as an alternative in the XCM router configuration — see the `SendXcm` +//! implementation for details. //! -//! All other bridge hub queues offer some backpressure mechanisms. So if at least one -//! of all queues is congested, it will eventually lead to the growth of the queue at -//! this chain. +//! ## Features //! -//! **A note on terminology**: when we mention the bridge hub here, we mean the chain that -//! has the messages pallet deployed (`pallet-bridge-grandpa`, `pallet-bridge-messages`, -//! `pallet-xcm-bridge-hub`, ...). It may be the system bridge hub parachain or any other -//! chain. +//! This pallet offers several optional features to customize functionality: +//! +//! ### Message Size Fee +//! An optional fee based on `T::FeeAsset` and `T::ByteFee`. If `T::FeeAsset` is not specified, this +//! fee is not calculated. +//! +//! ### Dynamic Fees and Congestion +//! +//! This pallet supports storing the congestion status of bridge outbound queues. The fee increases +//! exponentially if the queue between this chain and a sibling or child bridge hub becomes +//! congested. All other bridge hub queues provide backpressure mechanisms, so if any of these +//! queues are congested, it will eventually lead to increased queuing on this chain. +//! +//! There are two methods for storing congestion status: +//! 1. A dedicated extrinsic `report_bridge_status`, which relies on `T::BridgeHubOrigin`. This +//! allows the message exporter to send, for example, an XCM `Transact`. +//! 2. An implementation of `bp_xcm_bridge_hub::LocalXcmChannelManager`. +//! +//! ## Usage +//! +//! This pallet provides several implementations, such as `ViaLocalBridgeHubExporter` and +//! `ViaRemoteBridgeHubExporter`, which can expose or access these features. +//! +//! This router can be used in two main scenarios, depending on where the router and message +//! exporter (e.g., `pallet_xcm_bridge_hub` or another pallet with an `ExportXcm` implementation) +//! are deployed: +//! +//! ### On the Same Chain as the Message Exporter +//! In this setup, the router directly calls an `ExportXcm` implementation. In this case, +//! `ViaLocalBridgeHubExporter` can be used as a wrapper with `T::ToBridgeHubSender`. +//! +//! ### On a Different Chain than the Message Exporter +//! In this setup, we need to provide a `SendXcm` implementation for `T::ToBridgeHubSender`, which +//! sends `ExportMessage`. For example, `SovereignPaidRemoteExporter` can be used with +//! `ViaRemoteBridgeHubExporter`. +//! +//! **Note on Terminology**: When we refer to the bridge hub, we mean the chain that has the +//! `pallet-bridge-messages` with an `ExportXcm` implementation deployed, such as +//! `pallet-xcm-bridge-hub`. Depending on the deployment setup, `T::ToBridgeHubSender` can be +//! configured accordingly — see `T::ToBridgeHubSender` for additional documentation. #![cfg_attr(not(feature = "std"), no_std)] -pub use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; +pub 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::*; -use xcm_builder::{ExporterFor, InspectMessageQueues, SovereignPaidRemoteExporter}; +use xcm_builder::InspectMessageQueues; pub use pallet::*; pub use weights::WeightInfo; pub mod benchmarking; +pub mod impls; pub mod weights; mod mock; @@ -62,153 +95,276 @@ const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0 pub const HARD_MESSAGE_SIZE_LIMIT: u32 = 32 * 1024; /// The target that will be used when publishing logs related to this pallet. -/// -/// This doesn't match the pattern used by other bridge pallets (`runtime::bridge-*`). But this -/// pallet has significant differences with those pallets. The main one is that is intended to -/// be deployed at sending chains. Other bridge pallets are likely to be deployed at the separate -/// bridge hub parachain. -pub const LOG_TARGET: &str = "xcm::bridge-hub-router"; +pub const LOG_TARGET: &str = "runtime::bridge-xcm-router"; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, weights::WeightMeter}; use frame_system::pallet_prelude::*; - #[pallet::config] + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. + pub mod config_preludes { + use super::*; + use frame_support::{derive_impl, traits::ConstU128}; + + /// A type providing default configurations for this pallet in testing environment. + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + #[inject_runtime_type] + type RuntimeEvent = (); + type WeightInfo = (); + type DestinationVersion = AlwaysLatest; + + // We don't need (optional) message_size fees. + type ByteFee = ConstU128<0>; + // We don't need (optional) message_size fees. + type FeeAsset = (); + } + } + + #[pallet::config(with_default)] pub trait Config: frame_system::Config { /// The overarching event type. + #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Benchmarks results from runtime we're plugged into. type WeightInfo: WeightInfo; - /// Universal location of this runtime. - type UniversalLocation: Get; - /// Relative location of the supported sibling bridge hub. - type SiblingBridgeHubLocation: Get; - /// The bridged network that this config is for if specified. - /// Also used for filtering `Bridges` by `BridgedNetworkId`. - /// If not specified, allows all networks pass through. - type BridgedNetworkId: Get>; - /// Configuration for supported **bridged networks/locations** with **bridge location** and - /// **possible fee**. Allows to externalize better control over allowed **bridged - /// networks/locations**. - type Bridges: ExporterFor; /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; - /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. + /// The bridge hub may be: + /// - A system (sibling) bridge hub parachain (or another chain), in which case we need an + /// implementation for `T::ToBridgeHubSender` that sends `ExportMessage`, e.g., + /// `SovereignPaidRemoteExporter`. + /// - The local chain, in which case we need an implementation for `T::ToBridgeHubSender` + /// that does not use `ExportMessage` but instead directly calls the `ExportXcm` + /// implementation. + #[pallet::no_default] type ToBridgeHubSender: SendXcm; - /// Local XCM channel manager. - type LocalXcmChannelManager: XcmChannelStatusProvider; + + /// Resolves a specific `BridgeId` for `dest`, used for identifying the bridge in cases of + /// congestion and dynamic fees. If it resolves to `None`, it means no congestion or + /// dynamic fees are handled for `dest`. + #[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_fee` for more details. type ByteFee: Get; - /// Asset that is used to paid bridge fee. - type FeeAsset: Get; + /// Asset used to pay the `ByteFee`. + /// If not specified, the `ByteFee` is ignored. + /// See `calculate_fees` for more details. + type FeeAsset: Get>; } + /// An alias for the `BridgeId` of configured `T::BridgeIdResolver`. + pub type BridgeIdOf = <>::BridgeIdResolver as ResolveBridgeId>::BridgeId; + #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { - fn on_initialize(_n: BlockNumberFor) -> Weight { - // if XCM channel is still congested, we don't change anything - if T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { - return T::WeightInfo::on_initialize_when_congested() + fn on_idle(_n: BlockNumberFor, remaining_weight: Weight) -> Weight { + let mut meter = WeightMeter::with_limit(remaining_weight); + + // Iterate all congested bridges + let mut bridges_to_update = Vec::new(); + let mut bridges_to_remove = Vec::new(); + for (bridge_id, mut bridge_state) in Bridges::::iter() { + meter.consume(T::DbWeight::get().reads(1)); + + // If no longer congested, we can start decreasing the fee factor. + if !bridge_state.is_congested { + let previous_factor = bridge_state.delivery_fee_factor; + let new_factor = previous_factor / EXPONENTIAL_FEE_BASE; + if new_factor >= MINIMAL_DELIVERY_FEE_FACTOR { + bridge_state.delivery_fee_factor = new_factor; + if meter + .try_consume(T::WeightInfo::on_idle_when_bridge_state_updated()) + .is_err() + { + break; + } + bridges_to_update.push((bridge_id, previous_factor, bridge_state)); + } else { + if meter + .try_consume(T::WeightInfo::on_idle_when_bridge_state_removed()) + .is_err() + { + break; + } + bridges_to_remove.push((bridge_id, previous_factor)); + } + } } - // if we can't decrease the delivery fee factor anymore, we don't change anything - let mut delivery_fee_factor = Self::delivery_fee_factor(); - if delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { - return T::WeightInfo::on_initialize_when_congested() + // remove + for (bridge_id, previous_value) in bridges_to_remove.into_iter() { + log::info!( + target: LOG_TARGET, + "Bridge channel with id {:?} is uncongested. Removing fee factor!", + bridge_id, + ); + Bridges::::remove(&bridge_id); + Self::deposit_event(Event::DeliveryFeeFactorDecreased { + previous_value, + new_value: 0.into(), + bridge_id, + }); + } + // update + for (bridge_id, previous_value, bridge_state) in bridges_to_update.into_iter() { + let new_value = bridge_state.delivery_fee_factor; + log::info!( + target: LOG_TARGET, + "Bridge channel with id {:?} is uncongested. Decreasing fee factor from {} to {}!", + bridge_id, + previous_value, + new_value, + ); + Bridges::::insert(&bridge_id, bridge_state); + Self::deposit_event(Event::DeliveryFeeFactorDecreased { + previous_value, + new_value, + bridge_id, + }); } - let previous_factor = delivery_fee_factor; - delivery_fee_factor = - MINIMAL_DELIVERY_FEE_FACTOR.max(delivery_fee_factor / EXPONENTIAL_FEE_BASE); + meter.consumed() + } + } + + #[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, - "Bridge channel is uncongested. Decreased fee factor from {} to {}", - previous_factor, - delivery_fee_factor, + "Received bridge status from {:?}: congested = {}", + bridge_id, + is_congested, ); - Self::deposit_event(Event::DeliveryFeeFactorDecreased { - new_value: delivery_fee_factor, - }); - DeliveryFeeFactor::::put(delivery_fee_factor); + // update status + Self::update_bridge_status(bridge_id, is_congested); - T::WeightInfo::on_initialize_when_non_congested() + Ok(()) } } - /// Initialization value for the delivery fee factor. - #[pallet::type_value] - pub fn InitialFactor() -> FixedU128 { - MINIMAL_DELIVERY_FEE_FACTOR - } - - /// The number to multiply the base delivery fee by. - /// - /// This factor is shared by all bridges, served by this pallet. For example, if this - /// chain (`Config::UniversalLocation`) opens two bridges ( - /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(1000))` and - /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(2000))`), then they - /// both will be sharing the same fee factor. This is because both bridges are sharing - /// the same local XCM channel with the child/sibling bridge hub, which we are using - /// to detect congestion: - /// - /// ```nocompile - /// ThisChain --- Local XCM channel --> Sibling Bridge Hub ------ - /// | | - /// | | - /// | | - /// Lane1 Lane2 - /// | | - /// | | - /// | | - /// \ / | - /// Parachain1 <-- Local XCM channel --- Remote Bridge Hub <------ - /// | - /// | - /// Parachain1 <-- Local XCM channel --------- - /// ``` - /// - /// If at least one of other channels is congested, the local XCM channel with sibling - /// bridge hub eventually becomes congested too. And we have no means to detect - which - /// bridge exactly causes the congestion. So the best solution here is not to make - /// any differences between all bridges, started by this chain. + /// Stores `BridgeState` for congestion control and dynamic fees for each resolved bridge ID + /// associated with a destination. #[pallet::storage] - #[pallet::getter(fn delivery_fee_factor)] - pub type DeliveryFeeFactor, I: 'static = ()> = - StorageValue<_, FixedU128, ValueQuery, InitialFactor>; + pub type Bridges, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, BridgeIdOf, BridgeState, OptionQuery>; impl, I: 'static> Pallet { - /// Called when new message is sent (queued to local outbound XCM queue) over the bridge. - pub(crate) fn on_message_sent_to_bridge(message_size: u32) { - // if outbound channel is not congested, do nothing - if !T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { + /// Called when new message is sent to the `dest` (queued to local outbound XCM queue). + pub(crate) fn on_message_sent_to(message_size: u32, dest: Location) { + let Some(bridge_id) = T::BridgeIdResolver::resolve_for_dest(&dest) else { + // not supported bridge id, so do nothing return + }; + + // handle congestion and fee factor (if detected) + Bridges::::mutate_exists(&bridge_id, |bridge_state| match bridge_state { + Some(ref mut bridge_state) if bridge_state.is_congested => { + // found congested bridge + // ok - we need to increase the fee factor, let's do that + let message_size_factor = + FixedU128::from_u32(message_size.saturating_div(1024)) + .saturating_mul(MESSAGE_SIZE_FEE_BASE); + let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); + + let previous_factor = bridge_state.delivery_fee_factor; + bridge_state.delivery_fee_factor = + bridge_state.delivery_fee_factor.saturating_mul(total_factor); + + log::info!( + target: LOG_TARGET, + "Bridge channel with id {:?} is congested. Increased fee factor from {} to {} for {:?}", + bridge_id, + previous_factor, + bridge_state.delivery_fee_factor, + dest + ); + Self::deposit_event(Event::DeliveryFeeFactorIncreased { + previous_value: previous_factor, + new_value: bridge_state.delivery_fee_factor, + bridge_id: bridge_id.clone(), + dest, + }); + }, + _ => { + // not congested, do nothing + }, + }); + } + + /// Returns the recalculated dynamic fee for a given asset based on the bridge state. + /// + /// This function adjusts the amount of a fungible asset according to the delivery fee + /// factor specified in the `bridge_state`. If the asset is fungible, the + /// `delivery_fee_factor` is applied to the asset’s amount, potentially altering its + /// value. + pub(crate) fn calculate_dynamic_fee(bridge_state: &BridgeState, mut asset: Asset) -> Asset { + if let Fungibility::Fungible(ref mut amount) = asset.fun { + *amount = bridge_state.delivery_fee_factor.saturating_mul_int(*amount); } + asset + } - // ok - we need to increase the fee factor, let's do that - let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) - .saturating_mul(MESSAGE_SIZE_FEE_BASE); - let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); - DeliveryFeeFactor::::mutate(|f| { - let previous_factor = *f; - *f = f.saturating_mul(total_factor); - log::info!( - target: LOG_TARGET, - "Bridge channel is congested. Increased fee factor from {} to {}", - previous_factor, - f, - ); - Self::deposit_event(Event::DeliveryFeeFactorIncreased { new_value: *f }); - *f + /// Calculates an (optional) fee for message size based on `T::ByteFee` and `T::FeeAsset`. + pub(crate) fn calculate_message_size_fee( + message_size: impl FnOnce() -> u32, + ) -> Option { + // Apply message size `T::ByteFee/T::FeeAsset` feature (if configured). + if let Some(asset_id) = T::FeeAsset::get() { + let message_fee = (message_size() as u128).saturating_mul(T::ByteFee::get()); + if message_fee > 0 { + return Some((asset_id, message_fee).into()); + } + } + 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, + }) + }, }); } } @@ -218,121 +374,32 @@ pub mod pallet { pub enum Event, I: 'static = ()> { /// Delivery fee factor has been decreased. DeliveryFeeFactorDecreased { + /// Previous value of the `DeliveryFeeFactor`. + previous_value: FixedU128, /// New value of the `DeliveryFeeFactor`. new_value: FixedU128, + /// Bridge identifier. + bridge_id: BridgeIdOf, }, /// Delivery fee factor has been increased. DeliveryFeeFactorIncreased { + /// Previous value of the `DeliveryFeeFactor`. + previous_value: FixedU128, /// New value of the `DeliveryFeeFactor`. new_value: FixedU128, + /// Bridge identifier. + bridge_id: BridgeIdOf, + /// The destination to which the router sends the message. + dest: Location, }, } } -/// We'll be using `SovereignPaidRemoteExporter` to send remote messages over the sibling/child -/// bridge hub. -type ViaBridgeHubExporter = SovereignPaidRemoteExporter< - Pallet, - >::ToBridgeHubSender, - >::UniversalLocation, ->; - -// This pallet acts as the `ExporterFor` for the `SovereignPaidRemoteExporter` to compute -// message fee using fee factor. -impl, I: 'static> ExporterFor for Pallet { - fn exporter_for( - network: &NetworkId, - remote_location: &InteriorLocation, - message: &Xcm<()>, - ) -> Option<(Location, Option)> { - log::trace!( - target: LOG_TARGET, - "exporter_for - network: {network:?}, remote_location: {remote_location:?}, msg: {message:?}", - ); - // ensure that the message is sent to the expected bridged network (if specified). - if let Some(bridged_network) = T::BridgedNetworkId::get() { - if *network != bridged_network { - log::trace!( - target: LOG_TARGET, - "Router with bridged_network_id {bridged_network:?} does not support bridging to network {network:?}!", - ); - return None - } - } - - // ensure that the message is sent to the expected bridged network and location. - let (bridge_hub_location, maybe_payment) = match T::Bridges::exporter_for( - network, - remote_location, - message, - ) { - Some((bridge_hub_location, maybe_payment)) - if bridge_hub_location.eq(&T::SiblingBridgeHubLocation::get()) => - (bridge_hub_location, maybe_payment), - _ => { - log::trace!( - target: LOG_TARGET, - "Router configured with bridged_network_id {:?} and sibling_bridge_hub_location: {:?} does not support bridging to network {:?} and remote_location {:?}!", - T::BridgedNetworkId::get(), - T::SiblingBridgeHubLocation::get(), - network, - remote_location, - ); - return None - }, - }; - - // take `base_fee` from `T::Brides`, but it has to be the same `T::FeeAsset` - let base_fee = match maybe_payment { - Some(payment) => match payment { - Asset { fun: Fungible(amount), id } if id.eq(&T::FeeAsset::get()) => amount, - invalid_asset => { - log::error!( - target: LOG_TARGET, - "Router with bridged_network_id {:?} is configured for `T::FeeAsset` {:?} \ - which is not compatible with {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!", - T::BridgedNetworkId::get(), - T::FeeAsset::get(), - invalid_asset, - bridge_hub_location, - network, - remote_location, - ); - return None - }, - }, - None => 0, - }; - - // compute fee amount. Keep in mind that this is only the bridge fee. The fee for sending - // message from this chain to child/sibling bridge hub is determined by the - // `Config::ToBridgeHubSender` - let message_size = message.encoded_size(); - let message_fee = (message_size as u128).saturating_mul(T::ByteFee::get()); - let fee_sum = base_fee.saturating_add(message_fee); - - let fee_factor = Self::delivery_fee_factor(); - let fee = fee_factor.saturating_mul_int(fee_sum); - let fee = if fee > 0 { Some((T::FeeAsset::get(), fee).into()) } else { None }; - - log::info!( - target: LOG_TARGET, - "Going to send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", - (network, remote_location), - message_size, - fee, - fee_factor, - ); - - Some((bridge_hub_location, fee)) - } -} - // This pallet acts as the `SendXcm` to the sibling/child bridge hub instead of regular // XCMP/DMP transport. This allows injecting dynamic message fees into XCM programs that // are going to the bridged network. impl, I: 'static> SendXcm for Pallet { - type Ticket = (u32, ::Ticket); + type Ticket = (u32, Location, ::Ticket); fn validate( dest: &mut Option, @@ -340,7 +407,7 @@ impl, I: 'static> SendXcm for Pallet { ) -> SendResult { log::trace!(target: LOG_TARGET, "validate - msg: {xcm:?}, destination: {dest:?}"); - // In case of success, the `ViaBridgeHubExporter` can modify XCM instructions and consume + // In case of success, the `T::ToBridgeHubSender` can modify XCM instructions and consume // `dest` / `xcm`, so we retain the clone of original message and the destination for later // `DestinationVersion` validation. let xcm_to_dest_clone = xcm.clone(); @@ -352,7 +419,7 @@ impl, I: 'static> SendXcm for Pallet { // include both the cost of (1) delivery to the sibling bridge hub (returned by // `Config::ToBridgeHubSender`) and (2) delivery to the bridged bridge hub (returned by // `Self::exporter_for`). - match ViaBridgeHubExporter::::validate(dest, xcm) { + match T::ToBridgeHubSender::validate(dest, xcm) { Ok((ticket, cost)) => { // If the ticket is ok, it means we are routing with this router, so we need to // apply more validations to the cloned `dest` and `xcm`, which are required here. @@ -361,19 +428,19 @@ impl, I: 'static> SendXcm for Pallet { // We won't have access to `dest` and `xcm` in the `deliver` method, so we need to // precompute everything required here. However, `dest` and `xcm` were consumed by - // `ViaBridgeHubExporter`, so we need to use their clones. + // `T::ToBridgeHubSender`, so we need to use their clones. let message_size = xcm_to_dest_clone.encoded_size() as _; // The bridge doesn't support oversized or overweight messages. Therefore, it's // better to drop such messages here rather than at the bridge hub. Let's check the - // message size." + // message size. if message_size > HARD_MESSAGE_SIZE_LIMIT { return Err(SendError::ExceedsMaxMessageSize) } // We need to ensure that the known `dest`'s XCM version can comprehend the current // `xcm` program. This may seem like an additional, unnecessary check, but it is - // not. A similar check is probably performed by the `ViaBridgeHubExporter`, which + // not. A similar check is probably performed by the `T::ToBridgeHubSender`, which // attempts to send a versioned message to the sibling bridge hub. However, the // local bridge hub may have a higher XCM version than the remote `dest`. Once // again, it is better to discard such messages here than at the bridge hub (e.g., @@ -384,10 +451,15 @@ impl, I: 'static> SendXcm for Pallet { .into_version(destination_version) .map_err(|()| SendError::DestinationUnsupported)?; - Ok(((message_size, ticket), cost)) + log::info!( + target: LOG_TARGET, + "Going to send message to {dest_clone:?} ({message_size:?} bytes) with actual cost: {cost:?}" + ); + + Ok(((message_size, dest_clone, ticket), cost)) }, Err(e) => { - log::trace!(target: LOG_TARGET, "validate - ViaBridgeHubExporter - error: {e:?}"); + log::trace!(target: LOG_TARGET, "`T::ToBridgeHubSender` validates for dest: {dest_clone:?} with error: {e:?}"); Err(e) }, } @@ -396,13 +468,17 @@ impl, I: 'static> SendXcm for Pallet { fn deliver(ticket: Self::Ticket) -> Result { // use router to enqueue message to the sibling/child bridge hub. This also should handle // payment for passing through this queue. - let (message_size, ticket) = ticket; - let xcm_hash = ViaBridgeHubExporter::::deliver(ticket)?; + let (message_size, dest, ticket) = ticket; + let xcm_hash = T::ToBridgeHubSender::deliver(ticket)?; + + log::trace!( + target: LOG_TARGET, + "deliver - message (size: {message_size:?}) sent to the dest: {dest:?}, xcm_hash: {xcm_hash:?}" + ); - // increase delivery fee factor if required - Self::on_message_sent_to_bridge(message_size); + // increase delivery fee factor (if required) + Self::on_message_sent_to(message_size, dest); - log::trace!(target: LOG_TARGET, "deliver - message sent, xcm_hash: {xcm_hash:?}"); Ok(xcm_hash) } } @@ -425,53 +501,85 @@ mod tests { use frame_support::traits::Hooks; use frame_system::{EventRecord, Phase}; - use sp_runtime::traits::One; - - #[test] - fn initial_fee_factor_is_one() { - run_test(|| { - assert_eq!(DeliveryFeeFactor::::get(), MINIMAL_DELIVERY_FEE_FACTOR); - }) - } + use sp_runtime::traits::{Dispatchable, One}; #[test] - fn fee_factor_is_not_decreased_from_on_initialize_when_xcm_channel_is_congested() { + fn fee_factor_is_not_decreased_from_on_initialize_when_bridge_is_congested() { run_test(|| { - DeliveryFeeFactor::::put(FixedU128::from_rational(125, 100)); - TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); + let dest = Location::new(2, [GlobalConsensus(BridgedNetworkId::get())]); + let old_delivery_fee_factor = FixedU128::from_rational(125, 100); + + // make bridge congested + update fee factor + set_bridge_state_for::( + &dest, + Some(BridgeState { + delivery_fee_factor: old_delivery_fee_factor, + is_congested: true, + }), + ); // it should not decrease, because queue is congested - let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), old_delivery_fee_factor); + assert_eq!( + get_bridge_state_for::(&dest).unwrap().delivery_fee_factor, + old_delivery_fee_factor + ); assert_eq!(System::events(), vec![]); }) } #[test] - fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() { + fn fee_factor_decreased_from_on_initialize_when_bridge_is_uncongested() { run_test(|| { + let dest = Location::new(2, [GlobalConsensus(BridgedNetworkId::get())]); let initial_fee_factor = FixedU128::from_rational(125, 100); - DeliveryFeeFactor::::put(initial_fee_factor); + let mut remaining_weight = Weight::MAX; - // it shold eventually decreased to one - while XcmBridgeHubRouter::delivery_fee_factor() > MINIMAL_DELIVERY_FEE_FACTOR { - XcmBridgeHubRouter::on_initialize(One::one()); - } + // make bridge uncongested + update fee factor + let bridge_id = set_bridge_state_for::( + &dest, + Some(BridgeState { delivery_fee_factor: initial_fee_factor, is_congested: false }), + ); - // verify that it doesn't decreases anymore - XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), MINIMAL_DELIVERY_FEE_FACTOR); + // it should eventually decrease and remove + let mut last_delivery_fee_factor = initial_fee_factor; + while let Some(bridge_state) = get_bridge_state_for::(&dest) { + last_delivery_fee_factor = bridge_state.delivery_fee_factor; + remaining_weight = XcmBridgeHubRouter::on_idle(One::one(), remaining_weight); + + // avoid infinite loops (decreasing is expected) + if let Some(bridge_state) = get_bridge_state_for::(&dest) { + assert!(bridge_state.delivery_fee_factor < last_delivery_fee_factor); + } + } + assert!(remaining_weight.all_lt(Weight::MAX)); // check emitted event + // (first one for updating) let first_system_event = System::events().first().cloned(); assert_eq!( first_system_event, Some(EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmBridgeHubRouter(Event::DeliveryFeeFactorDecreased { + previous_value: initial_fee_factor, new_value: initial_fee_factor / EXPONENTIAL_FEE_BASE, + bridge_id, + }), + topics: vec![], + }) + ); + // (last one for removing) + let last_system_event = System::events().last().cloned(); + assert_eq!( + last_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter(Event::DeliveryFeeFactorDecreased { + previous_value: last_delivery_fee_factor, + new_value: 0.into(), + bridge_id, }), topics: vec![], }) @@ -510,7 +618,7 @@ mod tests { let xcm: Xcm<()> = vec![ClearOrigin; HARD_MESSAGE_SIZE_LIMIT as usize].into(); // dest is routable with the inner router - assert_ok!(ViaBridgeHubExporter::::validate( + assert_ok!(>::ToBridgeHubSender::validate( &mut Some(dest.clone()), &mut Some(xcm.clone()) )); @@ -540,7 +648,7 @@ mod tests { let xcm: Xcm<()> = vec![ClearOrigin].into(); // dest is routable with the inner router - assert_ok!(ViaBridgeHubExporter::::validate( + assert_ok!(>::ToBridgeHubSender::validate( &mut Some(dest.clone()), &mut Some(xcm.clone()) )); @@ -569,8 +677,11 @@ mod tests { let xcm: Xcm<()> = vec![ClearOrigin].into(); let msg_size = xcm.encoded_size(); - // initially the base fee is used: `BASE_FEE + BYTE_FEE * msg_size + HRMP_FEE` - let expected_fee = BASE_FEE + BYTE_FEE * (msg_size as u128) + HRMP_FEE; + // `BASE_FEE + BYTE_FEE * msg_size` (without `HRMP_FEE`) + let base_cost_formula = || BASE_FEE + BYTE_FEE * (msg_size as u128); + + // initially the base fee is used + let expected_fee = base_cost_formula() + HRMP_FEE; assert_eq!( XcmBridgeHubRouter::validate(&mut Some(dest.clone()), &mut Some(xcm.clone())) .unwrap() @@ -580,14 +691,18 @@ mod tests { ); // but when factor is larger than one, it increases the fee, so it becomes: - // `(BASE_FEE + BYTE_FEE * msg_size) * F + HRMP_FEE` + // `base_cost_formula() * F` let factor = FixedU128::from_rational(125, 100); - DeliveryFeeFactor::::put(factor); + + // make bridge congested + update fee factor + set_bridge_state_for::( + &dest, + Some(BridgeState { delivery_fee_factor: factor, is_congested: true }), + ); + let expected_fee = - (FixedU128::saturating_from_integer(BASE_FEE + BYTE_FEE * (msg_size as u128)) * - factor) - .into_inner() / FixedU128::DIV + - HRMP_FEE; + (FixedU128::saturating_from_integer(base_cost_formula()) * factor).into_inner() / + FixedU128::DIV + HRMP_FEE; assert_eq!( XcmBridgeHubRouter::validate(&mut Some(dest), &mut Some(xcm)).unwrap().1.get(0), Some(&(BridgeFeeAsset::get(), expected_fee).into()), @@ -596,39 +711,61 @@ mod tests { } #[test] - fn sent_message_doesnt_increase_factor_if_queue_is_uncongested() { + fn sent_message_doesnt_increase_factor_if_bridge_is_uncongested() { run_test(|| { - let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); + let dest = + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]); + + // make bridge congested + update fee factor + let old_delivery_fee_factor = FixedU128::from_rational(125, 100); + set_bridge_state_for::( + &dest, + Some(BridgeState { + delivery_fee_factor: old_delivery_fee_factor, + is_congested: false, + }), + ); + assert_eq!( - send_xcm::( - Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), - vec![ClearOrigin].into(), - ) - .map(drop), + send_xcm::(dest.clone(), vec![ClearOrigin].into(),).map(drop), Ok(()), ); assert!(TestToBridgeHubSender::is_message_sent()); - assert_eq!(old_delivery_fee_factor, XcmBridgeHubRouter::delivery_fee_factor()); + assert_eq!( + old_delivery_fee_factor, + get_bridge_state_for::(&dest).unwrap().delivery_fee_factor + ); assert_eq!(System::events(), vec![]); }); } #[test] - fn sent_message_increases_factor_if_xcm_channel_is_congested() { + fn sent_message_increases_factor_if_bridge_is_congested() { run_test(|| { - TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); + let dest = + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]); - let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); - assert_ok!(send_xcm::( - Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), - vec![ClearOrigin].into(), - ) - .map(drop)); + // make bridge congested + update fee factor + let old_delivery_fee_factor = FixedU128::from_rational(125, 100); + set_bridge_state_for::( + &dest, + Some(BridgeState { + delivery_fee_factor: old_delivery_fee_factor, + is_congested: true, + }), + ); + + assert_ok!( + send_xcm::(dest.clone(), vec![ClearOrigin].into(),).map(drop) + ); assert!(TestToBridgeHubSender::is_message_sent()); - assert!(old_delivery_fee_factor < XcmBridgeHubRouter::delivery_fee_factor()); + assert!( + old_delivery_fee_factor < + get_bridge_state_for::(&dest).unwrap().delivery_fee_factor + ); // check emitted event let first_system_event = System::events().first().cloned(); @@ -655,4 +792,79 @@ 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 = + 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, + 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, + }) + ); + }); + } + + #[test] + fn update_bridge_status_works() { + run_test(|| { + let dest = Location::new(2, [GlobalConsensus(BridgedNetworkId::get())]); + let bridge_id = + bp_xcm_bridge_hub::BridgeId::new(&UniversalLocation::get(), dest.interior()); + assert!(get_bridge_state_for::(&dest).is_none()); + + // update as is_congested=false when `None` + Pallet::::update_bridge_status(bridge_id, false); + assert!(get_bridge_state_for::(&dest).is_none()); + + // update as is_congested=true + Pallet::::update_bridge_status(bridge_id, true); + assert_eq!( + get_bridge_state_for::(&dest), + Some(BridgeState { + delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, + is_congested: true, + }) + ); + + // update as is_congested=false when `Some(..)` + Pallet::::update_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 095572883920..16dd9b09629f 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -18,16 +18,20 @@ use crate as pallet_xcm_bridge_hub_router; -use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; +use crate::impls::EnsureIsRemoteBridgeIdResolver; +use bp_xcm_bridge_hub_router::{BridgeState, ResolveBridgeId}; use codec::Encode; 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::*; -use xcm_builder::{InspectMessageQueues, NetworkExportTable, NetworkExportTableItem}; +use xcm_builder::{ + InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, SovereignPaidRemoteExporter, +}; type Block = frame_system::mocking::MockBlock; @@ -41,8 +45,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, } } @@ -69,19 +73,45 @@ impl frame_system::Config for TestRuntime { type Block = Block; } -impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); +/// Simple implementation where every dest resolves to the exact one `BridgeId`. +pub struct EveryDestinationToSameBridgeIdResolver; +impl ResolveBridgeId for EveryDestinationToSameBridgeIdResolver { + type BridgeId = (); + + fn resolve_for_dest(_dest: &Location) -> Option { + Some(()) + } + + fn resolve_for( + _bridged_network: &NetworkId, + _bridged_dest: &InteriorLocation, + ) -> Option { + Some(()) + } +} - type UniversalLocation = UniversalLocation; - type SiblingBridgeHubLocation = SiblingBridgeHubLocation; - type BridgedNetworkId = BridgedNetworkId; - type Bridges = NetworkExportTable; +/// An instance of `pallet_xcm_bridge_hub_router` configured to use a remote exporter with the +/// `ExportMessage` instruction, which will be delivered to a sibling parachain using +/// `SiblingBridgeHubLocation`. +#[derive_impl(pallet_xcm_bridge_hub_router::config_preludes::TestDefaultConfig)] +impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type DestinationVersion = LatestOrNoneForLocationVersionChecker>; - type ToBridgeHubSender = TestToBridgeHubSender; - type LocalXcmChannelManager = TestLocalXcmChannelManager; + type ToBridgeHubSender = SovereignPaidRemoteExporter< + pallet_xcm_bridge_hub_router::impls::ViaRemoteBridgeHubExporter< + TestRuntime, + (), + NetworkExportTable, + BridgedNetworkId, + SiblingBridgeHubLocation, + >, + TestToBridgeHubSender, + UniversalLocation, + >; + + type BridgeIdResolver = EnsureIsRemoteBridgeIdResolver; + type BridgeHubOrigin = EnsureRoot; type ByteFee = ConstU128; type FeeAsset = BridgeFeeAsset; @@ -150,25 +180,6 @@ impl InspectMessageQueues for TestToBridgeHubSender { } } -pub struct TestLocalXcmChannelManager; - -impl TestLocalXcmChannelManager { - pub fn make_congested(with: &Location) { - frame_support::storage::unhashed::put( - &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], - &true, - ); - } -} - -impl XcmChannelStatusProvider for TestLocalXcmChannelManager { - fn is_congested(with: &Location) -> bool { - frame_support::storage::unhashed::get_or_default( - &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], - ) - } -} - /// Return test externalities to use in tests. pub fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -188,3 +199,33 @@ pub fn run_test(test: impl FnOnce() -> T) -> T { pub(crate) fn fake_message_hash(message: &Xcm) -> XcmHash { message.using_encoded(sp_io::hashing::blake2_256) } + +pub(crate) fn set_bridge_state_for, I: 'static>( + dest: &Location, + bridge_state: Option, +) -> pallet_xcm_bridge_hub_router::BridgeIdOf { + let bridge_id = ::resolve_for_dest(dest).unwrap(); + if let Some(bridge_state) = bridge_state { + pallet_xcm_bridge_hub_router::Bridges::::insert(&bridge_id, bridge_state); + } else { + pallet_xcm_bridge_hub_router::Bridges::::remove(&bridge_id); + } + bridge_id +} + +pub(crate) fn get_bridge_state_for, I: 'static>( + dest: &Location, +) -> Option { + let bridge_id = ::resolve_for_dest(dest).unwrap(); + pallet_xcm_bridge_hub_router::Bridges::::get(bridge_id) +} + +#[cfg(feature = "runtime-benchmarks")] +impl crate::benchmarking::Config<()> for TestRuntime { + fn ensure_bridged_target_destination() -> Result { + Ok(Location::new(2, [GlobalConsensus(BridgedNetworkId::get())])) + } + fn report_bridge_status_origin() -> Option { + Some(RuntimeOrigin::root()) + } +} diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index d9a0426fecaf..a4eef004cb4e 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -50,74 +50,50 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_xcm_bridge_hub_router. pub trait WeightInfo { - fn on_initialize_when_non_congested() -> Weight; - fn on_initialize_when_congested() -> Weight; -} - -/// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets. -/// -/// Those weights are test only and must never be used in production. -pub struct BridgeWeight(PhantomData); -impl WeightInfo for BridgeWeight { - /// - /// Storage: `XcmBridgeHubRouter::DeliveryFeeFactor` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), - /// added: 511, mode: `MaxEncodedLen`) - fn on_initialize_when_non_congested() -> Weight { - // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 11_141 nanoseconds. - Weight::from_parts(11_339_000, 3517) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - fn on_initialize_when_congested() -> Weight { - // Proof Size summary in bytes: - // Measured: `82` - // Estimated: `3547` - // Minimum execution time: 4_239 nanoseconds. - Weight::from_parts(4_383_000, 3547).saturating_add(T::DbWeight::get().reads(1_u64)) - } + fn on_idle_when_bridge_state_removed() -> Weight; + fn on_idle_when_bridge_state_updated() -> Weight; + fn report_bridge_status() -> Weight; } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - /// - /// Storage: `XcmBridgeHubRouter::DeliveryFeeFactor` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), - /// added: 511, mode: `MaxEncodedLen`) - fn on_initialize_when_non_congested() -> Weight { + /// Storage: `ToUnknownXcmRouter::Bridges` (r:2 w:1) + /// Proof: `ToUnknownXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, + /// mode: `MaxEncodedLen`) + fn on_idle_when_bridge_state_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 19_370_000 picoseconds. + Weight::from_parts(19_928_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + /// Storage: `ToUnknownXcmRouter::Bridges` (r:2 w:1) + /// Proof: `ToUnknownXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, + /// mode: `MaxEncodedLen`) + fn on_idle_when_bridge_state_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 11_141 nanoseconds. - Weight::from_parts(11_339_000, 3517) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 20_045_000 picoseconds. + Weight::from_parts(20_861_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - fn on_initialize_when_congested() -> Weight { + /// Storage: `ToUnknownXcmRouter::Bridges` (r:1 w:1) + /// Proof: `ToUnknownXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, + /// mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { // Proof Size summary in bytes: - // Measured: `82` - // Estimated: `3547` - // Minimum execution time: 4_239 nanoseconds. - Weight::from_parts(4_383_000, 3547).saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `109` + // Estimated: `3530` + // Minimum execution time: 12_179_000 picoseconds. + Weight::from_parts(12_679_000, 0) + .saturating_add(Weight::from_parts(0, 3530)) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index fe58b910a94e..209c5b6d38fa 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -22,6 +22,7 @@ bp-xcm-bridge-hub = { workspace = true } pallet-bridge-messages = { workspace = true } # Substrate Dependencies +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } sp-core = { workspace = true } @@ -49,6 +50,7 @@ std = [ "bp-runtime/std", "bp-xcm-bridge-hub/std", "codec/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", @@ -66,6 +68,7 @@ std = [ "xcm/std", ] runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", diff --git a/bridges/modules/xcm-bridge-hub/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub/src/benchmarking.rs new file mode 100644 index 000000000000..eeeed993c55c --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/benchmarking.rs @@ -0,0 +1,147 @@ +// Copyright (C) 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 . + +//! XCM bridge hub pallet benchmarks. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{Call, Receiver, ThisChainOf}; +use bp_runtime::BalanceOf; +use bp_xcm_bridge_hub::BridgeLocations; +use frame_benchmarking::v2::*; +use frame_support::{ + assert_ok, + traits::{fungible::Unbalanced, tokens::Precision, Contains, Get}, +}; +use sp_std::boxed::Box; +use xcm_executor::traits::ConvertLocation; + +use sp_runtime::Saturating; +use xcm::prelude::*; + +/// Pallet we're benchmarking here. +pub struct Pallet, I: 'static = ()>(crate::Pallet); + +/// Trait that must be implemented by runtime to be able to benchmark pallet properly. +pub trait Config: crate::Config { + /// Returns a valid origin along with the initial balance (e.g., existential deposit), + /// required for operation `open_bridge`. + /// If `None`, that means that `open_bridge` is not supported. + fn open_bridge_origin() -> Option<(Self::RuntimeOrigin, BalanceOf>)>; +} + +#[instance_benchmarks] +mod benchmarks { + use super::*; + + fn prepare_for_open_bridge, I: 'static>( + ) -> Result<(T::RuntimeOrigin, Box), BenchmarkError> { + let (origin, initial_balance) = T::open_bridge_origin() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let bridge_destination_universal_location: Box = + Box::new([GlobalConsensus(crate::Pallet::::bridged_network_id()?)].into()); + let expected = crate::Pallet::::bridge_locations_from_origin( + origin.clone(), + bridge_destination_universal_location, + )?; + + if !T::AllowWithoutBridgeDeposit::contains(expected.bridge_origin_relative_location()) { + // fund origin's sovereign account + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + expected.bridge_origin_relative_location(), + ) + .ok_or(BenchmarkError::Stop("InvalidBridgeOriginAccount"))?; + + T::Currency::increase_balance( + &bridge_owner_account, + initial_balance.saturating_add(T::BridgeDeposit::get()), + Precision::BestEffort, + )?; + } + + Ok((origin, expected)) + } + + #[benchmark] + fn open_bridge() -> Result<(), BenchmarkError> { + let (origin, locations) = prepare_for_open_bridge::()?; + let bridge_destination_universal_location: Box = + Box::new(locations.bridge_destination_universal_location().clone().into()); + assert!(crate::Pallet::::bridge(locations.bridge_id()).is_none()); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, bridge_destination_universal_location, None); + + assert!(crate::Pallet::::bridge(locations.bridge_id()).is_some()); + Ok(()) + } + + #[benchmark] + fn close_bridge() -> Result<(), BenchmarkError> { + let (origin, locations) = prepare_for_open_bridge::()?; + let bridge_destination_universal_location: Box = + Box::new(locations.bridge_destination_universal_location().clone().into()); + assert!(crate::Pallet::::bridge(locations.bridge_id()).is_none()); + + // open bridge + assert_ok!(crate::Pallet::::open_bridge( + origin.clone(), + bridge_destination_universal_location.clone(), + None, + )); + assert!(crate::Pallet::::bridge(locations.bridge_id()).is_some()); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, bridge_destination_universal_location, 10); + + assert!(crate::Pallet::::bridge(locations.bridge_id()).is_none()); + Ok(()) + } + + #[benchmark] + fn update_notification_receiver() -> Result<(), BenchmarkError> { + let (origin, locations) = prepare_for_open_bridge::()?; + let bridge_destination_universal_location: Box = + Box::new(locations.bridge_destination_universal_location().clone().into()); + assert!(crate::Pallet::::bridge(locations.bridge_id()).is_none()); + + // open bridge with None + assert_ok!(crate::Pallet::::open_bridge( + origin.clone(), + bridge_destination_universal_location.clone(), + None, + )); + assert_eq!( + crate::Pallet::::bridge(locations.bridge_id()).map(|b| b.maybe_notify), + Some(None) + ); + + #[extrinsic_call] + _( + origin as T::RuntimeOrigin, + bridge_destination_universal_location, + Some(Receiver::new(1, 5)), + ); + + assert_eq!( + crate::Pallet::::bridge(locations.bridge_id()).map(|b| b.maybe_notify), + Some(Some(Receiver::new(1, 5))) + ); + Ok(()) + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime); +} 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 000000000000..e570fbde6060 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/congestion.rs @@ -0,0 +1,231 @@ +// 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 crate::{Bridges, Config, DispatchChannelStatusProvider, LOG_TARGET}; +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager, Receiver}; +use codec::{Decode, Encode}; +use sp_runtime::traits::Convert; +use sp_std::{marker::PhantomData, vec::Vec}; +use xcm::latest::{send_xcm, Location, SendXcm, Xcm}; +use xcm_builder::{DispatchBlob, DispatchBlobError}; + +/// Limits for handling congestion. +#[derive(Debug, Decode, Encode)] +pub struct CongestionLimits { + /// Maximal number of messages in the outbound bridge queue. Once we reach this limit, we + /// suspend a bridge. + pub outbound_lane_congested_threshold: bp_messages::MessageNonce, + /// After we have suspended the bridge, we wait until number of messages in the outbound bridge + /// queue drops to this count, before sending resuming the bridge. + pub outbound_lane_uncongested_threshold: bp_messages::MessageNonce, + /// Maximal number of messages in the outbound bridge queue after we have suspended the bridge. + /// Once we reach this limit, we stop exporting more messages. + pub outbound_lane_stop_threshold: bp_messages::MessageNonce, +} + +impl CongestionLimits { + /// Checks if limits are valid. + pub fn is_valid(&self) -> bool { + self.outbound_lane_uncongested_threshold < self.outbound_lane_congested_threshold && + self.outbound_lane_stop_threshold > self.outbound_lane_congested_threshold + } +} + +impl Default for CongestionLimits { + fn default() -> Self { + Self { + outbound_lane_congested_threshold: 8_192, + outbound_lane_uncongested_threshold: 1_024, + outbound_lane_stop_threshold: 12_288, + } + } +} + +/// 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< + Bridge, + HereXcmChannelManager, + LocalConsensusXcmChannelManager, +>(PhantomData<(Bridge, HereXcmChannelManager, LocalConsensusXcmChannelManager)>); +impl< + Bridge: Encode + sp_std::fmt::Debug + Copy, + HereXcmChannelManager: LocalXcmChannelManager, + LocalConsensusXcmChannelManager: LocalXcmChannelManager, + > LocalXcmChannelManager + for HereOrLocalConsensusXcmChannelManager< + Bridge, + HereXcmChannelManager, + LocalConsensusXcmChannelManager, + > +{ + 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 +/// [`xcm::prelude::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) + } +} + +/// Adapter that ties together the [`DispatchBlob`] trait with the [`DispatchChannelStatusProvider`] +/// trait. The idea is that [`DispatchBlob`] triggers message dispatch/delivery on the receiver +/// side, while [`DispatchChannelStatusProvider`] provides a status check to ensure the dispatch +/// channel is active (not congested). +pub struct BlobDispatcherWithChannelStatus( + PhantomData<(ChannelDispatch, ChannelStatus)>, +); +impl DispatchBlob + for BlobDispatcherWithChannelStatus +{ + fn dispatch_blob(blob: Vec) -> Result<(), DispatchBlobError> { + ChannelDispatch::dispatch_blob(blob) + } +} +impl DispatchChannelStatusProvider + for BlobDispatcherWithChannelStatus +{ + fn is_congested(with: &Location) -> bool { + ChannelStatus::is_congested(with) + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index dd855c7069aa..b93bd63d011b 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, DispatchChannelStatusProvider, Pallet, LOG_TARGET}; 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) } @@ -127,7 +127,6 @@ mod tests { use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; use pallet_bridge_messages::InboundLaneStorage; - use xcm_executor::traits::ConvertLocation; fn bridge() -> (Box, TestLaneIdType) { let origin = OpenBridgeOrigin::sibling_parachain_origin(); @@ -157,12 +156,9 @@ mod tests { bridge.bridge_destination_universal_location().clone().into(), ), state: BridgeState::Opened, - bridge_owner_account: LocationToAccountId::convert_location( - bridge.bridge_origin_relative_location(), - ) - .expect("valid accountId"), - deposit: 0, + deposit: None, lane_id, + maybe_notify: None, }, ); LaneToBridge::::insert(lane_id, bridge.bridge_id()); @@ -211,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 5afb9f36bc94..134a5c3ad804 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -37,14 +37,6 @@ use xcm::prelude::*; use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::ExportXcm; -/// Maximal number of messages in the outbound bridge queue. Once we reach this limit, we -/// suspend a bridge. -const OUTBOUND_LANE_CONGESTED_THRESHOLD: MessageNonce = 8_192; - -/// After we have suspended the bridge, we wait until number of messages in the outbound bridge -/// queue drops to this count, before sending resuming the bridge. -const OUTBOUND_LANE_UNCONGESTED_THRESHOLD: MessageNonce = 1_024; - /// An easy way to access `HaulBlobExporter`. pub type PalletAsHaulBlobExporter = HaulBlobExporter< DummyHaulBlob, @@ -133,8 +125,9 @@ where let bridge = Self::bridge(locations.bridge_id()).ok_or_else(|| { log::error!( target: LOG_TARGET, - "No opened bridge for requested bridge_origin_relative_location: {:?} and bridge_destination_universal_location: {:?}", + "No opened bridge for requested bridge_origin_relative_location: {:?} (bridge_origin_universal_location: {:?}) and bridge_destination_universal_location: {:?}", locations.bridge_origin_relative_location(), + locations.bridge_origin_universal_location(), locations.bridge_destination_universal_location(), ); SendError::NotApplicable @@ -151,6 +144,20 @@ where message, )?; + // Here, we know that the message is relevant to this pallet instance, so let's check for + // congestion defense. + if bridge.state == BridgeState::Suspended(false) { + log::error!( + target: LOG_TARGET, + "Bridge for requested bridge_origin_relative_location: {:?} (bridge_origin_universal_location: {:?}) and bridge_destination_universal_location: {:?} \ + is suspended and does not accept more messages!", + locations.bridge_origin_relative_location(), + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), + ); + return Err(SendError::Transport("Exporter is suspended!")); + } + let bridge_message = MessagesPallet::::validate_message(bridge.lane_id, &blob) .map_err(|e| { match e { @@ -212,19 +219,36 @@ impl, I: 'static> Pallet { enqueued_messages: MessageNonce, ) { // if the bridge queue is not congested, we don't want to do anything - let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD; + let is_congested = + enqueued_messages > T::CongestionLimits::get().outbound_lane_congested_threshold; if !is_congested { return } - // TODO: https://github.com/paritytech/parity-bridges-common/issues/2006 we either need fishermens - // to watch this rule violation (suspended, but keep sending new messages), or we need a - // hard limit for that like other XCM queues have - - // check if the lane is already suspended. If it is, do nothing. We still accept new - // messages to the suspended bridge, hoping that it'll be actually resumed soon - if bridge.state == BridgeState::Suspended { - return + // check if the lane is already suspended or not. + match bridge.state { + BridgeState::Suspended(true) => { + if enqueued_messages > T::CongestionLimits::get().outbound_lane_stop_threshold { + // If its suspended and reached `outbound_lane_stop_threshold`, we stop + // accepting new messages (a.k.a. start dropping). + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended(false); + }); + return + } else { + // We still can accept new messages to the suspended bridge, hoping that it'll + // be actually resumed soon + return + } + }, + BridgeState::Suspended(false) => { + // We cannot accept new messages to the suspended bridge, hoping that it'll be + // actually resumed soon + return + }, + _ => { + // otherwise, continue handling the suspension + }, } // else - suspend the bridge @@ -232,7 +256,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, @@ -254,7 +278,7 @@ impl, I: 'static> Pallet { ); }, Err(e) => { - log::debug!( + log::error!( target: LOG_TARGET, "Failed to suspended the bridge {:?}, originated by the {:?}: {:?}", bridge_id, @@ -268,26 +292,41 @@ impl, I: 'static> Pallet { // and remember that we have suspended the bridge Bridges::::mutate_extant(bridge_id, |bridge| { - bridge.state = BridgeState::Suspended; + bridge.state = BridgeState::Suspended(true); }); } /// Must be called whenever we receive a message delivery confirmation. fn on_bridge_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) { // if the bridge queue is still congested, we don't want to do anything - let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD; + let is_congested = + enqueued_messages > T::CongestionLimits::get().outbound_lane_uncongested_threshold; if is_congested { + // and if it is bellow the `stop_threshold` + if enqueued_messages < T::CongestionLimits::get().outbound_lane_stop_threshold { + if let Some((bridge_id, bridge)) = Self::bridge_by_lane_id(&lane_id) { + if let BridgeState::Suspended(false) = bridge.state { + // we allow exporting again + Bridges::::mutate_extant(bridge_id, |b| { + b.state = BridgeState::Suspended(true); + }); + } + } + } return } // if we have not suspended the bridge before (or it is closed), we don't want to do // anything let (bridge_id, bridge) = match Self::bridge_by_lane_id(&lane_id) { - Some(bridge) if bridge.1.state == BridgeState::Suspended => bridge, + Some(bridge) + if bridge.1.state == BridgeState::Suspended(true) || + bridge.1.state == BridgeState::Suspended(false) => + bridge, _ => { // if there is no bridge or it has been closed, then we don't need to send resume // signal to the local origin - it has closed bridge itself, so it should have - // alrady pruned everything else + // already pruned everything else return }, }; @@ -297,7 +336,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, @@ -322,7 +361,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, @@ -360,14 +399,17 @@ impl HaulBlob for DummyHaulBlob { #[cfg(test)] mod tests { use super::*; - use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; + use crate::{mock::*, Bridges, LanesManagerOf}; use bp_runtime::RangeInclusiveExt; - use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; - use frame_support::assert_ok; - use pallet_bridge_messages::InboundLaneStorage; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState, Receiver}; + use frame_support::{ + assert_err, assert_ok, + traits::{Contains, EnsureOrigin}, + }; + use pallet_xcm_bridge_hub_router::ResolveBridgeId; use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; - use xcm_executor::traits::{export_xcm, ConvertLocation}; + use xcm_executor::traits::export_xcm; fn universal_source() -> InteriorLocation { SiblingUniversalLocation::get() @@ -381,65 +423,37 @@ mod tests { BridgedUniversalDestination::get() } - fn open_lane() -> (BridgeLocations, TestLaneIdType) { + fn open_lane(origin: RuntimeOrigin) -> (BridgeLocations, TestLaneIdType) { // open expected outbound lane - let origin = OpenBridgeOrigin::sibling_parachain_origin(); let with = bridged_asset_hub_universal_location(); let locations = - XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + XcmOverBridge::bridge_locations_from_origin(origin.clone(), Box::new(with.into())) + .unwrap(); let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); if !Bridges::::contains_key(locations.bridge_id()) { - // insert bridge - Bridges::::insert( - locations.bridge_id(), - Bridge { - bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), - bridge_origin_universal_location: Box::new( - locations.bridge_origin_universal_location().clone().into(), - ), - bridge_destination_universal_location: Box::new( - locations.bridge_destination_universal_location().clone().into(), - ), - state: BridgeState::Opened, - bridge_owner_account: LocationToAccountId::convert_location( - locations.bridge_origin_relative_location(), - ) - .expect("valid accountId"), - deposit: 0, - lane_id, - }, - ); - LaneToBridge::::insert(lane_id, locations.bridge_id()); - - // create lanes - let lanes_manager = LanesManagerOf::::new(); - if lanes_manager.create_inbound_lane(lane_id).is_ok() { - assert_eq!( - 0, - lanes_manager - .active_inbound_lane(lane_id) - .unwrap() - .storage() - .data() - .last_confirmed_nonce + // fund origin (if needed) + if !>::AllowWithoutBridgeDeposit::contains( + locations.bridge_origin_relative_location(), + ) { + fund_origin_sovereign_account( + &locations, + BridgeDeposit::get() + ExistentialDeposit::get(), ); } - if lanes_manager.create_outbound_lane(lane_id).is_ok() { - assert!(lanes_manager - .active_outbound_lane(lane_id) - .unwrap() - .queued_messages() - .is_empty()); - } + + // open bridge + assert_ok!(XcmOverBridge::do_open_bridge(locations.clone(), lane_id, true, None)); } assert_ok!(XcmOverBridge::do_try_state()); (*locations, lane_id) } - fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) { - let (locations, lane_id) = open_lane(); + fn open_lane_and_send_regular_message( + source_origin: RuntimeOrigin, + ) -> (BridgeId, TestLaneIdType) { + let (locations, lane_id) = open_lane(source_origin); // now let's try to enqueue message using our `ExportXcm` implementation export_xcm::( @@ -457,7 +471,8 @@ mod tests { #[test] fn exporter_works() { run_test(|| { - let (_, lane_id) = open_lane_and_send_regular_message(); + let (_, lane_id) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); // double check that the message has been pushed to the expected lane // (it should already been checked during `send_message` call) @@ -472,8 +487,9 @@ mod tests { #[test] fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() { run_test(|| { - let (bridge_id, _) = open_lane_and_send_regular_message(); - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + let (bridge_id, _) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -481,80 +497,191 @@ mod tests { #[test] fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() { run_test(|| { - let (bridge_id, _) = open_lane_and_send_regular_message(); + let (bridge_id, _) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); Bridges::::mutate_extant(bridge_id, |bridge| { - bridge.state = BridgeState::Suspended; + bridge.state = BridgeState::Suspended(true); }); - for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { - open_lane_and_send_regular_message(); + for _ in 1..TestCongestionLimits::get().outbound_lane_congested_threshold { + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); } - open_lane_and_send_regular_message(); - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); }); } #[test] fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() { run_test(|| { - let (bridge_id, _) = open_lane_and_send_regular_message(); - for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { - open_lane_and_send_regular_message(); + let (bridge_id, _) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + for _ in 1..TestCongestionLimits::get().outbound_lane_congested_threshold { + 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(); - assert!(TestLocalXcmChannelManager::is_bridge_suspened()); - assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + assert!(TestLocalXcmChannelManager::is_bridge_suspened(&bridge_id)); + assert_eq!( + XcmOverBridge::bridge(&bridge_id).unwrap().state, + BridgeState::Suspended(true) + ); + + // send more messages to reach `outbound_lane_stop_threshold` + for _ in TestCongestionLimits::get().outbound_lane_congested_threshold.. + TestCongestionLimits::get().outbound_lane_stop_threshold + { + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + } + assert_eq!( + XcmOverBridge::bridge(&bridge_id).unwrap().state, + BridgeState::Suspended(false) + ); }); } #[test] fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() { run_test(|| { - let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + let (bridge_id, lane_id) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); Bridges::::mutate_extant(bridge_id, |bridge| { - bridge.state = BridgeState::Suspended; + bridge.state = BridgeState::Suspended(true); }); XcmOverBridge::on_bridge_messages_delivered( lane_id, - OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, + TestCongestionLimits::get().outbound_lane_uncongested_threshold + 1, ); - assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); - assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); + assert_eq!( + XcmOverBridge::bridge(&bridge_id).unwrap().state, + BridgeState::Suspended(true) + ); }); } #[test] fn bridge_is_not_resumed_if_it_was_not_suspended_before() { run_test(|| { - let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + let (bridge_id, lane_id) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); XcmOverBridge::on_bridge_messages_delivered( lane_id, - OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + TestCongestionLimits::get().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); }); } + #[test] + fn exporter_respects_stop_threshold() { + run_test(|| { + let (bridge_id, lane_id) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + let xcm: Xcm<()> = vec![ClearOrigin].into(); + + // Opened - exporter works + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + ),); + + // Suspended(true) - exporter still works + XcmOverBridge::on_bridge_message_enqueued( + bridge_id, + XcmOverBridge::bridge(&bridge_id).unwrap(), + TestCongestionLimits::get().outbound_lane_congested_threshold + 1, + ); + assert_eq!( + XcmOverBridge::bridge(&bridge_id).unwrap().state, + BridgeState::Suspended(true) + ); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + ),); + + // Suspended(false) - exporter stops working + XcmOverBridge::on_bridge_message_enqueued( + bridge_id, + XcmOverBridge::bridge(&bridge_id).unwrap(), + TestCongestionLimits::get().outbound_lane_stop_threshold + 1, + ); + assert_eq!( + XcmOverBridge::bridge(&bridge_id).unwrap().state, + BridgeState::Suspended(false) + ); + assert_err!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + ), + SendError::Transport("Exporter is suspended!"), + ); + + // Back to Suspended(true) - exporter again works + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + TestCongestionLimits::get().outbound_lane_stop_threshold - 1, + ); + assert_eq!( + XcmOverBridge::bridge(&bridge_id).unwrap().state, + BridgeState::Suspended(true) + ); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + ),); + + // Back to Opened - exporter works + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + TestCongestionLimits::get().outbound_lane_uncongested_threshold - 1, + ); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + ),); + }); + } + #[test] fn bridge_is_resumed_when_enough_messages_are_delivered() { run_test(|| { - let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + let (bridge_id, lane_id) = + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); Bridges::::mutate_extant(bridge_id, |bridge| { - bridge.state = BridgeState::Suspended; + bridge.state = BridgeState::Suspended(true); }); XcmOverBridge::on_bridge_messages_delivered( lane_id, - OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + TestCongestionLimits::get().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); }); } @@ -618,9 +745,9 @@ mod tests { locations.bridge_destination_universal_location().clone().into(), ), state: BridgeState::Opened, - bridge_owner_account: [0u8; 32].into(), - deposit: 0, + deposit: None, lane_id: expected_lane_id, + maybe_notify: None, }, ); } @@ -642,13 +769,29 @@ mod tests { } #[test] - fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() { + fn pallet_as_exporter_is_compatible_with_pallet_xcm_bridge_hub_router_for_export_message() { run_test(|| { // valid routable destination let dest = Location::new(2, BridgedUniversalDestination::get()); // open bridge - let (_, expected_lane_id) = open_lane(); + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let origin_as_location = + OpenBridgeOriginOf::::try_origin(origin.clone()).unwrap(); + let (bridge, expected_lane_id) = open_lane(origin); + + // we need to set `UniversalLocation` for `sibling_parachain_origin` for + // `XcmOverBridgeWrappedWithExportMessageRouterInstance`. + ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get())); + + // check compatible bridge_id + assert_eq!( + bridge.bridge_id(), + &>::BridgeIdResolver::resolve_for_dest(&dest) + .unwrap() + ); // check before - no messages assert_eq!( @@ -662,18 +805,21 @@ mod tests { ); // send `ExportMessage(message)` by `UnpaidRemoteExporter`. - TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone()); assert_ok!(send_xcm::< UnpaidRemoteExporter< NetworkExportTable, - TestExportXcmWithXcmOverBridge, + ExecuteXcmOverSendXcm, UniversalLocation, >, >(dest.clone(), Xcm::<()>::default())); // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. - TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); - assert_ok!(send_xcm::(dest.clone(), Xcm::<()>::default())); + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location); + assert_ok!(send_xcm::( + dest, + Xcm::<()>::default() + )); // check after - a message ready to be relayed assert_eq!( @@ -688,6 +834,52 @@ mod tests { }) } + #[test] + fn pallet_as_exporter_is_compatible_with_pallet_xcm_bridge_hub_router_for_export_xcm() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + + // open bridge as a root on the local chain, which should be converted as + // `Location::here()` + let (bridge, expected_lane_id) = open_lane(RuntimeOrigin::root()); + + // check compatible bridge_id + assert_eq!( + bridge.bridge_id(), + &>::BridgeIdResolver::resolve_for_dest(&dest) + .unwrap() + ); + + // check before - no messages + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .unwrap() + .queued_messages() + .saturating_len(), + 0 + ); + + // trigger `ExportXcm` by `pallet_xcm_bridge_hub_router`. + assert_ok!(send_xcm::(dest, Xcm::<()>::default())); + + // check after - a message ready to be relayed + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .unwrap() + .queued_messages() + .saturating_len(), + 1 + ); + }) + } + #[test] fn validate_works() { run_test(|| { @@ -765,7 +957,7 @@ mod tests { ); // ok - let _ = open_lane(); + let (locations, _) = open_lane(OpenBridgeOrigin::sibling_parachain_origin()); let mut dest_wrapper = Some(bridged_relative_destination()); assert_ok!(XcmOverBridge::validate( BridgedRelayNetwork::get(), @@ -778,6 +970,193 @@ mod tests { assert_eq!(None, xcm_wrapper); assert_eq!(&Some(universal_source()), &universal_source_wrapper); assert_eq!(None, dest_wrapper); + + // send more messages to reach `outbound_lane_congested_threshold` + for _ in 0..=TestCongestionLimits::get().outbound_lane_congested_threshold { + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + } + // bridge is suspended but exporter accepts more messages + assert_eq!( + XcmOverBridge::bridge(locations.bridge_id()).unwrap().state, + BridgeState::Suspended(true) + ); + + // export still can accept more messages + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + )); + + // send more messages to reach `outbound_lane_stop_threshold` + for _ in TestCongestionLimits::get().outbound_lane_congested_threshold.. + TestCongestionLimits::get().outbound_lane_stop_threshold + { + open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin()); + } + + // bridge is suspended but exporter CANNOT accept more messages + assert_eq!( + XcmOverBridge::bridge(locations.bridge_id()).unwrap().state, + BridgeState::Suspended(false) + ); + + // export still can accept more messages + assert_err!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(bridged_relative_destination()), + &mut Some(xcm.clone()), + ), + SendError::Transport("Exporter is suspended!"), + ); }); } + + #[test] + fn congestion_with_pallet_xcm_bridge_hub_router_works() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + + fn router_bridge_state, I: 'static>( + dest: &Location, + ) -> Option { + let bridge_id = + ::resolve_for_dest(dest).unwrap(); + pallet_xcm_bridge_hub_router::Bridges::::get(&bridge_id) + } + + // open two bridges + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let origin_as_location = + OpenBridgeOriginOf::::try_origin(origin.clone()).unwrap(); + let (bridge_1, expected_lane_id_1) = open_lane(origin); + let (bridge_2, expected_lane_id_2) = open_lane(RuntimeOrigin::root()); + assert_ne!(expected_lane_id_1, expected_lane_id_2); + assert_ne!(bridge_1.bridge_id(), bridge_2.bridge_id()); + + // 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::< + TestRuntime, + XcmOverBridgeWrappedWithExportMessageRouterInstance, + >(&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..(TestCongestionLimits::get().outbound_lane_congested_threshold + 2) { + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone()); + assert_ok!(send_xcm::( + dest.clone(), + Xcm::<()>::default() + )); + + // call direct `ExportXcm` by `pallet_xcm_bridge_hub_router`. + assert_ok!(send_xcm::( + dest.clone(), + Xcm::<()>::default() + )); + } + + // checks after + // bridges are suspended + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Suspended(true) + ); + assert_eq!( + XcmOverBridge::bridge(bridge_2.bridge_id()).unwrap().state, + BridgeState::Suspended(true) + ); + // both routers are congested + assert!( + router_bridge_state::< + TestRuntime, + XcmOverBridgeWrappedWithExportMessageRouterInstance, + >(&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, + TestCongestionLimits::get().outbound_lane_uncongested_threshold, + ); + XcmOverBridge::on_bridge_messages_delivered( + expected_lane_id_2, + TestCongestionLimits::get().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::< + TestRuntime, + XcmOverBridgeWrappedWithExportMessageRouterInstance, + >(&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 1b2536598a20..435a6d273abc 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -145,12 +145,14 @@ use bp_messages::{LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; -pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; -use bp_xcm_bridge_hub::{BridgeLocations, BridgeLocationsError, LocalXcmChannelManager}; +pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState, Receiver}; +use bp_xcm_bridge_hub::{ + BridgeLocations, BridgeLocationsError, ChannelStatusProvider as DispatchChannelStatusProvider, + Deposit, DepositOf, LocalXcmChannelManager, +}; use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; use frame_system::Config as SystemConfig; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; -use sp_runtime::traits::Zero; use sp_std::{boxed::Box, vec::Vec}; use xcm::prelude::*; use xcm_builder::DispatchBlob; @@ -161,10 +163,14 @@ pub use dispatcher::XcmBlobMessageDispatchResult; pub use exporter::PalletAsHaulBlobExporter; pub use pallet::*; +pub mod benchmarking; +pub mod congestion; mod dispatcher; mod exporter; pub mod migration; mod mock; +pub use weights::WeightInfo; +pub mod weights; /// The target that will be used when publishing logs related to this pallet. pub const LOG_TARGET: &str = "runtime::bridge-xcm"; @@ -194,6 +200,8 @@ pub mod pallet { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Benchmarks results from runtime we're plugged into. + type WeightInfo: WeightInfo; /// Runtime's universal location. type UniversalLocation: Get; @@ -240,10 +248,13 @@ 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; + /// Limits for handling congestion. + type CongestionLimits: Get; } /// An alias for the bridge metadata. @@ -257,6 +268,8 @@ pub mod pallet { /// An alias for the associated lanes manager. pub type LanesManagerOf = pallet_bridge_messages::LanesManager>::BridgeMessagesPalletInstance>; + /// Weight info of the given pallet. + pub type WeightInfoOf = >::WeightInfo; #[pallet::pallet] #[pallet::storage_version(migration::STORAGE_VERSION)] @@ -267,9 +280,14 @@ pub mod pallet { fn integrity_test() { assert!( Self::bridged_network_id().is_ok(), - "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", + "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`!", T::BridgedNetwork::get() - ) + ); + assert!( + T::CongestionLimits::get().is_valid(), + "Configured `T::CongestionLimits`: {:?} are not valid!", + T::CongestionLimits::get() + ); } #[cfg(feature = "try-runtime")] @@ -291,11 +309,16 @@ pub mod pallet { /// /// The states after this call: bridge is `Opened`, outbound lane is `Opened`, inbound lane /// is `Opened`. + /// + /// Optional `maybe_notify` holds data about the `bridge_origin_relative_location` where + /// notifications can be sent to handle congestion. The notification contains an encoded + /// tuple `(BridgeId, bool)`, where `bool` is the `is_congested` flag. #[pallet::call_index(0)] - #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/parity-bridges-common/issues/3046 - add benchmarks impl + #[pallet::weight(WeightInfoOf::::open_bridge())] pub fn open_bridge( origin: OriginFor, bridge_destination_universal_location: Box, + maybe_notify: Option, ) -> DispatchResult { // check and compute required bridge locations and laneId let xcm_version = bridge_destination_universal_location.identify_version(); @@ -309,7 +332,7 @@ pub mod pallet { Error::::BridgeLocations(e) })?; - Self::do_open_bridge(locations, lane_id, true) + Self::do_open_bridge(locations, lane_id, true, maybe_notify) } /// Try to close the bridge. @@ -330,7 +353,7 @@ pub mod pallet { /// The states after this call: everything is either `Closed`, or purged from the /// runtime storage. #[pallet::call_index(1)] - #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/parity-bridges-common/issues/3046 - add benchmarks impl + #[pallet::weight(WeightInfoOf::::close_bridge())] pub fn close_bridge( origin: OriginFor, bridge_destination_universal_location: Box, @@ -409,23 +432,28 @@ pub mod pallet { LaneToBridge::::remove(bridge.lane_id); // return deposit - let released_deposit = T::Currency::release( - &HoldReason::BridgeDeposit.into(), - &bridge.bridge_owner_account, - bridge.deposit, - Precision::BestEffort, - ) - .inspect_err(|e| { - // we can't do anything here - looks like funds have been (partially) unreserved - // before by someone else. Let's not fail, though - it'll be worse for the caller - log::error!( - target: LOG_TARGET, - "Failed to unreserve during the bridge {:?} closure with error: {e:?}", - locations.bridge_id(), - ); - }) - .ok() - .unwrap_or(BalanceOf::>::zero()); + let released_deposit = if let Some(deposit) = bridge.deposit { + T::Currency::release( + &HoldReason::BridgeDeposit.into(), + &deposit.account, + deposit.amount, + Precision::BestEffort, + ) + .inspect_err(|e| { + // we can't do anything here - looks like funds have been (partially) unreserved + // before by someone else. Let's not fail, though - it'll be worse for the + // caller + log::error!( + target: LOG_TARGET, + "Failed to unreserve during the bridge {:?} closure with error: {e:?}", + locations.bridge_id(), + ); + }) + .map(|released| Deposit::new(deposit.account, released)) + .ok() + } else { + None + }; // write something to log log::trace!( @@ -447,6 +475,33 @@ pub mod pallet { Ok(()) } + + /// Attempts to update the `maybe_notify` callback for receiving congestion notifications. + /// + /// This can only be called by the "owner" of this side of the bridge, which means that the + /// inbound XCM channel with the local origin chain is functional. + #[pallet::call_index(2)] + #[pallet::weight(WeightInfoOf::::update_notification_receiver())] + pub fn update_notification_receiver( + origin: OriginFor, + bridge_destination_universal_location: Box, + maybe_notify: Option, + ) -> DispatchResult { + let locations = + Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; + Bridges::::try_mutate_exists(locations.bridge_id(), |bridge| match bridge { + Some(b) => { + b.maybe_notify = maybe_notify; + + Self::deposit_event(Event::::NotificationReceiverUpdated { + bridge_id: *locations.bridge_id(), + maybe_notify: b.maybe_notify.clone(), + }); + Ok(()) + }, + None => Err(Error::::UnknownBridge.into()), + }) + } } impl, I: 'static> Pallet { @@ -455,17 +510,20 @@ pub mod pallet { locations: Box, lane_id: T::LaneId, create_lanes: bool, + maybe_notify: Option, ) -> Result<(), DispatchError> { - // reserve balance on the origin's sovereign account (if needed) - let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( - locations.bridge_origin_relative_location(), - ) - .ok_or(Error::::InvalidBridgeOriginAccount)?; + // reserve balance (if needed) let deposit = if T::AllowWithoutBridgeDeposit::contains( locations.bridge_origin_relative_location(), ) { - BalanceOf::>::zero() + None } else { + // get origin's sovereign account + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + locations.bridge_origin_relative_location(), + ) + .ok_or(Error::::InvalidBridgeOriginAccount)?; + let deposit = T::BridgeDeposit::get(); T::Currency::hold( &HoldReason::BridgeDeposit.into(), @@ -482,7 +540,7 @@ pub mod pallet { ); Error::::FailedToReserveBridgeDeposit })?; - deposit + Some(Deposit::new(bridge_owner_account, deposit)) }; // save bridge metadata @@ -500,9 +558,9 @@ pub mod pallet { locations.bridge_destination_universal_location().clone().into(), ), state: BridgeState::Opened, - bridge_owner_account, - deposit, + deposit: deposit.clone(), lane_id, + maybe_notify, }); Ok(()) }, @@ -601,7 +659,7 @@ pub mod pallet { impl, I: 'static> Pallet { /// Returns some `NetworkId` if contains `GlobalConsensus` junction. - fn bridged_network_id() -> Result { + pub fn bridged_network_id() -> Result { match T::BridgedNetwork::get().take_first_interior() { Some(GlobalConsensus(network)) => Ok(network), _ => Err(Error::::BridgeLocations( @@ -612,6 +670,44 @@ pub mod pallet { } } + #[cfg(feature = "runtime-benchmarks")] + impl, I: 'static> Pallet { + /// Open bridge for lane. + pub fn open_bridge_for_benchmarks( + lane_id: LaneIdOf, + bridge_origin_relative_location: Location, + bridge_destination_universal_location: InteriorLocation, + create_lanes: bool, + maybe_notify: Option, + initial_balance: impl Fn() -> BalanceOf>, + ) -> Result, sp_runtime::DispatchError> { + let locations = Pallet::::bridge_locations( + bridge_origin_relative_location.into(), + bridge_destination_universal_location.into(), + )?; + + if !T::AllowWithoutBridgeDeposit::contains(locations.bridge_origin_relative_location()) + { + let account_id = T::BridgeOriginAccountIdConverter::convert_location( + locations.bridge_origin_relative_location(), + ) + .ok_or(Error::::InvalidBridgeOriginAccount)?; + + use frame_support::traits::fungible::Unbalanced; + use sp_runtime::Saturating; + T::Currency::increase_balance( + &account_id, + initial_balance().saturating_add(T::BridgeDeposit::get()), + Precision::BestEffort, + )?; + } + + Pallet::::do_open_bridge(locations.clone(), lane_id, create_lanes, maybe_notify)?; + + Ok(locations) + } + } + #[cfg(any(test, feature = "try-runtime", feature = "std"))] impl, I: 'static> Pallet { /// Ensure the correctness of the state of this pallet. @@ -680,10 +776,12 @@ pub mod pallet { ); // check bridge account owner - ensure!( - T::BridgeOriginAccountIdConverter::convert_location(bridge_origin_relative_location_as_latest) == Some(bridge.bridge_owner_account), - "`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!" - ); + if let Some(deposit) = bridge.deposit { + ensure!( + T::BridgeOriginAccountIdConverter::convert_location(bridge_origin_relative_location_as_latest) == Some(deposit.account), + "`bridge.deposit.account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!" + ); + } Ok(bridge.lane_id) } @@ -729,7 +827,7 @@ pub mod pallet { /// Keep in mind that we are **NOT** reserving any amount for the bridges opened at /// genesis. We are **NOT** opening lanes, used by this bridge. It all must be done using /// other pallets genesis configuration or some other means. - pub opened_bridges: Vec<(Location, InteriorLocation, Option)>, + pub opened_bridges: Vec<(Location, InteriorLocation, Option, Option)>, /// Dummy marker. #[serde(skip)] pub _phantom: sp_std::marker::PhantomData<(T, I)>, @@ -745,6 +843,7 @@ pub mod pallet { bridge_origin_relative_location, bridge_destination_universal_location, maybe_lane_id, + maybe_notify, ) in &self.opened_bridges { let locations = Pallet::::bridge_locations( @@ -759,7 +858,7 @@ pub mod pallet { locations.calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"), }; - Pallet::::do_open_bridge(locations, lane_id, true) + Pallet::::do_open_bridge(locations, lane_id, true, maybe_notify.clone()) .expect("Valid opened bridge!"); } } @@ -772,8 +871,8 @@ pub mod pallet { BridgeOpened { /// Bridge identifier. bridge_id: BridgeId, - /// Amount of deposit held. - bridge_deposit: BalanceOf>, + /// Bridge deposit held. + bridge_deposit: Option>>, /// Universal location of local bridge endpoint. local_endpoint: Box, @@ -801,10 +900,17 @@ pub mod pallet { /// Lane identifier. lane_id: T::LaneId, /// Amount of deposit released. - bridge_deposit: BalanceOf>, + bridge_deposit: Option>>, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, }, + /// The bridge has been updated with a new notification receiver. + NotificationReceiverUpdated { + /// Bridge identifier. + bridge_id: BridgeId, + /// Updated notification receiver. + maybe_notify: Option, + }, } #[pallet::error] @@ -836,29 +942,26 @@ mod tests { use bp_messages::LaneIdType; use mock::*; - use frame_support::{assert_err, assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; + use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec}; use frame_system::{EventRecord, Phase}; - use sp_runtime::TryRuntimeError; - - fn fund_origin_sovereign_account(locations: &BridgeLocations, balance: Balance) -> AccountId { - let bridge_owner_account = - LocationToAccountId::convert_location(locations.bridge_origin_relative_location()) - .unwrap(); - assert_ok!(Balances::mint_into(&bridge_owner_account, balance)); - bridge_owner_account - } + use sp_runtime::{traits::Zero, TryRuntimeError}; fn mock_open_bridge_from_with( origin: RuntimeOrigin, - deposit: Balance, + deposit: Option, with: InteriorLocation, ) -> (BridgeOf, BridgeLocations) { let locations = XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); - let bridge_owner_account = - fund_origin_sovereign_account(&locations, deposit + ExistentialDeposit::get()); - Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit).unwrap(); + + let deposit = deposit.map(|deposit| { + let bridge_owner_account = + fund_origin_sovereign_account(&locations, deposit + ExistentialDeposit::get()); + Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit) + .unwrap(); + Deposit::new(bridge_owner_account, deposit) + }); let bridge = Bridge { bridge_origin_relative_location: Box::new( @@ -871,9 +974,9 @@ mod tests { locations.bridge_destination_universal_location().clone().into(), ), state: BridgeState::Opened, - bridge_owner_account, deposit, lane_id, + maybe_notify: None, }; Bridges::::insert(locations.bridge_id(), bridge.clone()); LaneToBridge::::insert(bridge.lane_id, locations.bridge_id()); @@ -889,7 +992,7 @@ mod tests { fn mock_open_bridge_from( origin: RuntimeOrigin, - deposit: Balance, + deposit: Option, ) -> (BridgeOf, BridgeLocations) { mock_open_bridge_from_with(origin, deposit, bridged_asset_hub_universal_location()) } @@ -909,6 +1012,7 @@ mod tests { XcmOverBridge::open_bridge( OpenBridgeOrigin::disallowed_origin(), Box::new(bridged_asset_hub_universal_location().into()), + None, ), sp_runtime::DispatchError::BadOrigin, ); @@ -922,6 +1026,7 @@ mod tests { XcmOverBridge::open_bridge( OpenBridgeOrigin::parent_relay_chain_universal_origin(), Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::BridgeLocations( BridgeLocationsError::InvalidBridgeOrigin @@ -932,6 +1037,7 @@ mod tests { XcmOverBridge::open_bridge( OpenBridgeOrigin::sibling_parachain_universal_origin(), Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::BridgeLocations( BridgeLocationsError::InvalidBridgeOrigin @@ -950,6 +1056,7 @@ mod tests { [GlobalConsensus(RelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)] .into() ), + None, ), Error::::BridgeLocations(BridgeLocationsError::DestinationIsLocal), ); @@ -969,6 +1076,7 @@ mod tests { ] .into() ), + None, ), Error::::BridgeLocations( BridgeLocationsError::UnreachableDestination @@ -984,6 +1092,7 @@ mod tests { XcmOverBridge::open_bridge( OpenBridgeOrigin::origin_without_sovereign_account(), Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::InvalidBridgeOriginAccount, ); @@ -997,6 +1106,7 @@ mod tests { XcmOverBridge::open_bridge( OpenBridgeOrigin::sibling_parachain_origin(), Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::FailedToReserveBridgeDeposit, ); @@ -1013,10 +1123,6 @@ mod tests { ) .unwrap(); let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); - fund_origin_sovereign_account( - &locations, - BridgeDeposit::get() + ExistentialDeposit::get(), - ); Bridges::::insert( locations.bridge_id(), @@ -1031,9 +1137,9 @@ mod tests { locations.bridge_destination_universal_location().clone().into(), ), state: BridgeState::Opened, - bridge_owner_account: [0u8; 32].into(), - deposit: 0, + deposit: None, lane_id, + maybe_notify: None, }, ); @@ -1041,6 +1147,7 @@ mod tests { XcmOverBridge::open_bridge( origin, Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::BridgeAlreadyExists, ); @@ -1069,6 +1176,7 @@ mod tests { XcmOverBridge::open_bridge( origin.clone(), Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::LanesManager(LanesManagerError::InboundLaneAlreadyExists), ); @@ -1079,6 +1187,7 @@ mod tests { XcmOverBridge::open_bridge( origin, Box::new(bridged_asset_hub_universal_location().into()), + None, ), Error::::LanesManager( LanesManagerError::OutboundLaneAlreadyExists @@ -1090,17 +1199,18 @@ mod tests { #[test] fn open_bridge_works() { run_test(|| { - // in our test runtime, we expect that bridge may be opened by parent relay chain - // and any sibling parachain + // in our test runtime, we expect that bridge may be opened by parent relay chain, + // any sibling parachain or local root let origins = [ - (OpenBridgeOrigin::parent_relay_chain_origin(), 0), - (OpenBridgeOrigin::sibling_parachain_origin(), BridgeDeposit::get()), + (OpenBridgeOrigin::parent_relay_chain_origin(), None), + (OpenBridgeOrigin::sibling_parachain_origin(), Some(BridgeDeposit::get())), + (RuntimeOrigin::root(), None), ]; // check that every origin may open the bridge let lanes_manager = LanesManagerOf::::new(); let existential_deposit = ExistentialDeposit::get(); - for (origin, expected_deposit) in origins { + for (origin, expected_deposit_amount) in origins { // reset events System::set_block_number(1); System::reset_events(); @@ -1131,20 +1241,26 @@ mod tests { assert_eq!(LaneToBridge::::get(lane_id), None); // give enough funds to the sovereign account of the bridge origin - let bridge_owner_account = fund_origin_sovereign_account( - &locations, - expected_deposit + existential_deposit, - ); - assert_eq!( - Balances::free_balance(&bridge_owner_account), - expected_deposit + existential_deposit - ); - assert_eq!(Balances::reserved_balance(&bridge_owner_account), 0); + let expected_deposit = expected_deposit_amount.map(|deposit_amount| { + let bridge_owner_account = fund_origin_sovereign_account( + &locations, + deposit_amount + existential_deposit, + ); + assert_eq!( + Balances::free_balance(&bridge_owner_account), + deposit_amount + existential_deposit + ); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), 0); + Deposit::new(bridge_owner_account, deposit_amount) + }); + + let maybe_notify = Some(Receiver::new(13, 15)); // now open the bridge assert_ok!(XcmOverBridge::open_bridge( origin, Box::new(locations.bridge_destination_universal_location().clone().into()), + maybe_notify.clone(), )); // ensure that everything has been set up in the runtime storage @@ -1161,9 +1277,9 @@ mod tests { locations.bridge_destination_universal_location().clone().into(), ), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account.clone(), - deposit: expected_deposit, - lane_id + deposit: expected_deposit.clone(), + lane_id, + maybe_notify, }), ); assert_eq!( @@ -1178,8 +1294,16 @@ mod tests { LaneToBridge::::get(lane_id), Some(*locations.bridge_id()) ); - assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); - assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_deposit); + if let Some(expected_deposit) = expected_deposit.as_ref() { + assert_eq!( + Balances::free_balance(&expected_deposit.account), + existential_deposit + ); + assert_eq!( + Balances::reserved_balance(&expected_deposit.account), + expected_deposit.amount + ); + } // ensure that the proper event is deposited assert_eq!( @@ -1252,7 +1376,7 @@ mod tests { fn close_bridge_fails_if_its_lanes_are_unknown() { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); - let (bridge, locations) = mock_open_bridge_from(origin.clone(), 0); + let (bridge, locations) = mock_open_bridge_from(origin.clone(), None); let lanes_manager = LanesManagerOf::::new(); lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().purge(); @@ -1266,7 +1390,7 @@ mod tests { ); lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); - let (_, locations) = mock_open_bridge_from(origin.clone(), 0); + let (_, locations) = mock_open_bridge_from(origin.clone(), None); lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); assert_noop!( XcmOverBridge::close_bridge( @@ -1284,12 +1408,13 @@ mod tests { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); let expected_deposit = BridgeDeposit::get(); - let (bridge, locations) = mock_open_bridge_from(origin.clone(), expected_deposit); + let (bridge, locations) = mock_open_bridge_from(origin.clone(), Some(expected_deposit)); System::set_block_number(1); + let bridge_owner_account = bridge.deposit.unwrap().account; // remember owner balances - let free_balance = Balances::free_balance(&bridge.bridge_owner_account); - let reserved_balance = Balances::reserved_balance(&bridge.bridge_owner_account); + let free_balance = Balances::free_balance(&bridge_owner_account); + let reserved_balance = Balances::reserved_balance(&bridge_owner_account); // enqueue some messages for _ in 0..32 { @@ -1330,8 +1455,8 @@ mod tests { LaneToBridge::::get(bridge.lane_id), Some(*locations.bridge_id()) ); - assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); - assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); + assert_eq!(Balances::free_balance(&bridge_owner_account), free_balance); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), reserved_balance); assert_eq!( System::events().last(), Some(&EventRecord { @@ -1378,8 +1503,8 @@ mod tests { LaneToBridge::::get(bridge.lane_id), Some(*locations.bridge_id()) ); - assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); - assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); + assert_eq!(Balances::free_balance(&bridge_owner_account), free_balance); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), reserved_balance); assert_eq!( System::events().last(), Some(&EventRecord { @@ -1417,10 +1542,10 @@ mod tests { ); assert_eq!(LaneToBridge::::get(bridge.lane_id), None); assert_eq!( - Balances::free_balance(&bridge.bridge_owner_account), + Balances::free_balance(&bridge_owner_account), free_balance + reserved_balance ); - assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), 0); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), 0); assert_eq!( System::events().last(), Some(&EventRecord { @@ -1428,7 +1553,7 @@ mod tests { event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { bridge_id: *locations.bridge_id(), lane_id: bridge.lane_id.into(), - bridge_deposit: expected_deposit, + bridge_deposit: Some(Deposit::new(bridge_owner_account, expected_deposit)), pruned_messages: 8, }), topics: vec![], @@ -1437,6 +1562,69 @@ mod tests { }); } + #[test] + fn update_notification_receiver_works() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let locations = XcmOverBridge::bridge_locations_from_origin( + origin.clone(), + Box::new(VersionedInteriorLocation::from(bridged_asset_hub_universal_location())), + ) + .unwrap(); + + // open the bridge + assert_ok!(XcmOverBridge::open_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + Some(Receiver::new(13, 15)), + )); + assert_eq!( + Bridges::::get(locations.bridge_id()) + .map(|b| b.maybe_notify) + .unwrap(), + Some(Receiver::new(13, 15)) + ); + + // update the notification receiver to `None` + assert_ok!(XcmOverBridge::update_notification_receiver( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + None, + )); + assert_eq!( + Bridges::::get(locations.bridge_id()) + .map(|b| b.maybe_notify) + .unwrap(), + None, + ); + + // update the notification receiver to `Some(..)` + assert_ok!(XcmOverBridge::update_notification_receiver( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + Some(Receiver::new(29, 43)), + )); + assert_eq!( + Bridges::::get(locations.bridge_id()) + .map(|b| b.maybe_notify) + .unwrap(), + Some(Receiver::new(29, 43)) + ); + // update the notification receiver to `Some(..)` + assert_ok!(XcmOverBridge::update_notification_receiver( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + Some(Receiver::new(29, 79)), + )); + assert_eq!( + Bridges::::get(locations.bridge_id()) + .map(|b| b.maybe_notify) + .unwrap(), + Some(Receiver::new(29, 79)) + ); + }); + } + #[test] fn do_try_state_works() { let bridge_origin_relative_location = SiblingLocation::get(); @@ -1507,9 +1695,9 @@ mod tests { ), ), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account.clone(), - deposit: Zero::zero(), + deposit: Some(Deposit::new(bridge_owner_account.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id, lane_id), @@ -1533,9 +1721,9 @@ mod tests { ), ), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account.clone(), - deposit: Zero::zero(), + deposit: Some(Deposit::new(bridge_owner_account.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id_mismatch), (lane_id, lane_id), @@ -1559,13 +1747,13 @@ mod tests { bridge_destination_universal_location.clone(), )), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account_mismatch.clone(), - deposit: Zero::zero(), + deposit: Some(Deposit::new(bridge_owner_account_mismatch.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id, lane_id), - Some(TryRuntimeError::Other("`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!")), + Some(TryRuntimeError::Other("`bridge.deposit.account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!")), ); cleanup(bridge_id, vec![lane_id]); @@ -1584,9 +1772,9 @@ mod tests { bridge_destination_universal_location.clone(), )), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account_mismatch.clone(), - deposit: Zero::zero(), + 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), @@ -1610,9 +1798,9 @@ mod tests { ), ), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account.clone(), - deposit: Zero::zero(), + deposit: Some(Deposit::new(bridge_owner_account.clone(), Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id_mismatch, lane_id), @@ -1636,9 +1824,9 @@ mod tests { ), ), state: BridgeState::Opened, - bridge_owner_account: bridge_owner_account.clone(), - deposit: Zero::zero(), + deposit: Some(Deposit::new(bridge_owner_account, Zero::zero())), lane_id, + maybe_notify: None, }, (lane_id, bridge_id), (lane_id, lane_id_mismatch), @@ -1666,18 +1854,21 @@ mod tests { let bridge_destination_universal_location = BridgedUniversalDestination::get(); let may_prune_messages = 13; + let receiver = Receiver::new(13, 15); assert_eq!( bp_xcm_bridge_hub::XcmBridgeHubCall::open_bridge { bridge_destination_universal_location: Box::new( bridge_destination_universal_location.clone().into() - ) + ), + maybe_notify: Some(receiver.clone()), } .encode(), Call::::open_bridge { bridge_destination_universal_location: Box::new( bridge_destination_universal_location.clone().into() - ) + ), + maybe_notify: Some(receiver), } .encode() ); diff --git a/bridges/modules/xcm-bridge-hub/src/migration.rs b/bridges/modules/xcm-bridge-hub/src/migration.rs index ffd5233a917b..32761a1cfa5a 100644 --- a/bridges/modules/xcm-bridge-hub/src/migration.rs +++ b/bridges/modules/xcm-bridge-hub/src/migration.rs @@ -16,7 +16,7 @@ //! A module that is responsible for migration of storage. -use crate::{Config, Pallet, LOG_TARGET}; +use crate::{Config, Pallet, Receiver, LOG_TARGET}; use frame_support::{ traits::{Get, OnRuntimeUpgrade, StorageVersion}, weights::Weight, @@ -24,7 +24,7 @@ use frame_support::{ use xcm::prelude::{InteriorLocation, Location}; /// The in-code storage version. -pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); /// This migration does not modify storage but can be used to open a bridge and link it to the /// specified LaneId. This is useful when we want to open a bridge and use a custom LaneId instead @@ -38,6 +38,7 @@ pub struct OpenBridgeForLane< CreateLane, SourceRelativeLocation, BridgedUniversalLocation, + MaybeNotifyRelativeLocation, >( core::marker::PhantomData<( T, @@ -46,6 +47,7 @@ pub struct OpenBridgeForLane< CreateLane, SourceRelativeLocation, BridgedUniversalLocation, + MaybeNotifyRelativeLocation, )>, ); impl< @@ -55,19 +57,30 @@ impl< CreateLane: Get, SourceRelativeLocation: Get, BridgedUniversalLocation: Get, + MaybeNotifyRelativeLocation: Get>, > OnRuntimeUpgrade - for OpenBridgeForLane + for OpenBridgeForLane< + T, + I, + Lane, + CreateLane, + SourceRelativeLocation, + BridgedUniversalLocation, + MaybeNotifyRelativeLocation, + > { fn on_runtime_upgrade() -> Weight { let bridge_origin_relative_location = SourceRelativeLocation::get(); let bridge_destination_universal_location = BridgedUniversalLocation::get(); let lane_id = Lane::get(); let create_lane = CreateLane::get(); + let maybe_notify = MaybeNotifyRelativeLocation::get(); log::info!( target: LOG_TARGET, "OpenBridgeForLane - going to open bridge with lane_id: {lane_id:?} (create_lane: {create_lane:?}) \ between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ - bridge_destination_universal_location: {bridge_destination_universal_location:?}", + bridge_destination_universal_location: {bridge_destination_universal_location:?} \ + maybe_notify: {maybe_notify:?}", ); let locations = match Pallet::::bridge_locations( @@ -103,7 +116,9 @@ impl< return T::DbWeight::get().reads(2) } - if let Err(e) = Pallet::::do_open_bridge(locations, lane_id, create_lane) { + if let Err(e) = + Pallet::::do_open_bridge(locations, lane_id, create_lane, maybe_notify) + { log::error!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge failed with error: {e:?}"); T::DbWeight::get().reads(6) } else { @@ -143,3 +158,102 @@ impl< Ok(()) } } + +/// This module contains data structures that are valid for the initial state of `0`. +/// (used with v1 migration). +pub mod v0 { + use crate::{LaneIdOf, ThisChainOf}; + use bp_messages::LaneIdType; + use bp_runtime::{AccountIdOf, BalanceOf, Chain}; + use bp_xcm_bridge_hub::BridgeState; + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound}; + use scale_info::TypeInfo; + use sp_std::boxed::Box; + use xcm::{VersionedInteriorLocation, VersionedLocation}; + + #[derive( + CloneNoBound, + Decode, + Encode, + Eq, + PartialEqNoBound, + TypeInfo, + MaxEncodedLen, + RuntimeDebugNoBound, + )] + #[scale_info(skip_type_params(ThisChain, LaneId))] + pub(crate) struct Bridge { + pub bridge_origin_relative_location: Box, + pub bridge_origin_universal_location: Box, + pub bridge_destination_universal_location: Box, + pub state: BridgeState, + pub bridge_owner_account: AccountIdOf, + pub deposit: BalanceOf, + pub lane_id: LaneId, + } + + pub(crate) type BridgeOf = Bridge, LaneIdOf>; +} + +/// This migration to `1` updates the metadata of `Bridge`. +pub mod v1 { + use super::*; + use crate::{BalanceOf, Bridge, BridgeOf, Bridges, Deposit, ThisChainOf}; + use frame_support::{pallet_prelude::Zero, traits::UncheckedOnRuntimeUpgrade}; + use sp_std::marker::PhantomData; + + /// Migrates the pallet storage to v1. + pub struct UncheckedMigrationV0ToV1(PhantomData<(T, I)>); + + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrationV0ToV1 { + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // Migrate account/deposit to the `Deposit` struct. + let translate = |pre: v0::BridgeOf| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + let v0::Bridge { + bridge_origin_relative_location, + bridge_origin_universal_location, + bridge_destination_universal_location, + state, + bridge_owner_account, + deposit, + lane_id, + } = pre; + + // map deposit to the `Deposit` + let deposit = if deposit > BalanceOf::>::zero() { + Some(Deposit::new(bridge_owner_account, deposit)) + } else { + None + }; + + Some(v1::Bridge { + bridge_origin_relative_location, + bridge_origin_universal_location, + bridge_destination_universal_location, + state, + deposit, + lane_id, + maybe_notify: None, + }) + }; + Bridges::::translate_values(translate); + + weight + } + } + + /// [`UncheckedMigrationV0ToV1`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. + pub type MigrationToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + UncheckedMigrationV0ToV1, + Pallet, + ::DbWeight, + >; +} diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 9f06b99ef6d5..2b638ba3eb7d 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -17,34 +17,41 @@ #![cfg(test)] use crate as pallet_xcm_bridge_hub; - use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, ChainWithMessages, HashedLaneId, MessageNonce, }; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; -use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; +use bp_xcm_bridge_hub::{BridgeId, BridgeLocations, LocalXcmChannelManager}; use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{EnsureOrigin, Equals, Everything, OriginTrait}, + traits::{fungible::Mutate, EitherOf, EnsureOrigin, Equals, Everything, Get, OriginTrait}, weights::RuntimeDbWeight, }; +use frame_system::{EnsureNever, EnsureRoot, EnsureRootWithSuccess}; +use pallet_xcm_bridge_hub::congestion::{ + BlobDispatcherWithChannelStatus, CongestionLimits, HereOrLocalConsensusXcmChannelManager, + ReportBridgeStatusXcmChannelManager, +}; use polkadot_parachain_primitives::primitives::Sibling; use sp_core::H256; use sp_runtime::{ testing::Header as SubstrateHeader, - traits::{BlakeTwo256, ConstU128, ConstU32, IdentityLookup}, + traits::{BlakeTwo256, ConstU32, Convert, IdentityLookup}, AccountId32, BuildStorage, StateVersion, }; -use sp_std::cell::RefCell; +use sp_std::{cell::RefCell, marker::PhantomData}; use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*}; use xcm_builder::{ AllowUnpaidExecutionFrom, DispatchBlob, DispatchBlobError, FixedWeightBounds, InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, - SiblingParachainConvertsVia, + SiblingParachainConvertsVia, SovereignPaidRemoteExporter, UnpaidLocalExporter, +}; +use xcm_executor::{ + traits::{ConvertLocation, ConvertOrigin}, + XcmExecutor, }; -use xcm_executor::XcmExecutor; pub type AccountId = AccountId32; pub type Balance = u64; @@ -59,11 +66,12 @@ pub const BRIDGED_ASSET_HUB_ID: u32 = 1001; frame_support::construct_runtime! { pub enum TestRuntime { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Event}, - Messages: pallet_bridge_messages::{Pallet, Call, Event}, - XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, HoldReason, Event}, - XcmOverBridgeRouter: pallet_xcm_bridge_hub_router, + System: frame_system, + Balances: pallet_balances, + Messages: pallet_bridge_messages, + XcmOverBridge: pallet_xcm_bridge_hub, + XcmOverBridgeWrappedWithExportMessageRouter: pallet_xcm_bridge_hub_router = 57, + XcmOverBridgeByExportXcmRouter: pallet_xcm_bridge_hub_router:: = 69, } } @@ -148,6 +156,7 @@ impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights { } parameter_types! { + pub const HereLocation: Location = Location::here(); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub UniversalLocation: InteriorLocation = [ GlobalConsensus(RelayNetwork::get()), @@ -166,7 +175,6 @@ parameter_types! { // configuration for pallet_xcm_bridge_hub_router pub BridgeHubLocation: Location = Here.into(); - pub BridgeFeeAsset: AssetId = Location::here().into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( @@ -177,6 +185,7 @@ parameter_types! { ) ]; pub UnitWeightCost: Weight = Weight::from_parts(10, 10); + pub storage TestCongestionLimits: CongestionLimits = CongestionLimits::default(); } /// **Universal** `InteriorLocation` of bridged asset hub. @@ -184,8 +193,25 @@ 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; + type WeightInfo = (); type UniversalLocation = UniversalLocation; type BridgedNetwork = BridgedRelayNetworkLocation; @@ -194,35 +220,116 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type MessageExportPrice = (); type DestinationVersion = AlwaysLatest; - type ForceOrigin = frame_system::EnsureNever<()>; - type OpenBridgeOrigin = OpenBridgeOrigin; + type ForceOrigin = EnsureNever<()>; + type OpenBridgeOrigin = EitherOf< + // We want to translate `RuntimeOrigin::root()` to the `Location::here()` + EnsureRootWithSuccess, + OpenBridgeOrigin, + >; type BridgeOriginAccountIdConverter = LocationToAccountId; type BridgeDeposit = BridgeDeposit; type Currency = Balances; type RuntimeHoldReason = RuntimeHoldReason; - type AllowWithoutBridgeDeposit = Equals; + type AllowWithoutBridgeDeposit = (Equals, Equals); type LocalXcmChannelManager = TestLocalXcmChannelManager; + type BlobDispatcher = BlobDispatcherWithChannelStatus; + type CongestionLimits = TestCongestionLimits; +} - type BlobDispatcher = TestBlobDispatcher; +#[cfg(feature = "runtime-benchmarks")] +impl crate::benchmarking::Config<()> for TestRuntime { + fn open_bridge_origin() -> Option<(RuntimeOrigin, Balance)> { + Some((OpenBridgeOrigin::sibling_parachain_origin(), ExistentialDeposit::get())) + } } +/// A router instance simulates a scenario where the router is deployed on a different chain than +/// the `MessageExporter`. This means that the router sends an `ExportMessage`. +pub type XcmOverBridgeWrappedWithExportMessageRouterInstance = (); +#[derive_impl(pallet_xcm_bridge_hub_router::config_preludes::TestDefaultConfig)] impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - - type UniversalLocation = UniversalLocation; - type SiblingBridgeHubLocation = BridgeHubLocation; - type BridgedNetworkId = BridgedRelayNetwork; - type Bridges = NetworkExportTable; - type DestinationVersion = AlwaysLatest; - - type ToBridgeHubSender = TestExportXcmWithXcmOverBridge; - type LocalXcmChannelManager = TestLocalXcmChannelManager; - - type ByteFee = ConstU128<0>; - type FeeAsset = BridgeFeeAsset; + // We use `SovereignPaidRemoteExporter` here to test and ensure that the `ExportMessage` + // produced by `pallet_xcm_bridge_hub_router` is compatible with the `ExportXcm` implementation + // of `pallet_xcm_bridge_hub`. + type ToBridgeHubSender = SovereignPaidRemoteExporter< + pallet_xcm_bridge_hub_router::impls::ViaRemoteBridgeHubExporter< + TestRuntime, + // () - means `pallet_xcm_bridge_hub_router::Config<()>` + (), + NetworkExportTable, + BridgedRelayNetwork, + BridgeHubLocation, + >, + // **Note**: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which + // calls the `ExportXcm` implementation of `pallet_xcm_bridge_hub` as the + // `MessageExporter`. + ExecuteXcmOverSendXcm, + ExportMessageOriginUniversalLocation, + >; + + type BridgeIdResolver = pallet_xcm_bridge_hub_router::impls::EnsureIsRemoteBridgeIdResolver< + ExportMessageOriginUniversalLocation, + >; + // 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 +/// `MessageExporter`. This means that the router triggers `ExportXcm` trait directly. +pub type XcmOverBridgeByExportXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance2; +#[derive_impl(pallet_xcm_bridge_hub_router::config_preludes::TestDefaultConfig)] +impl pallet_xcm_bridge_hub_router::Config for TestRuntime { + // We use `UnpaidLocalExporter` with `ViaLocalBridgeHubExporter` here to test and ensure that + // `pallet_xcm_bridge_hub_router` can trigger directly `pallet_xcm_bridge_hub` as exporter. + type ToBridgeHubSender = pallet_xcm_bridge_hub_router::impls::ViaLocalBridgeHubExporter< + TestRuntime, + XcmOverBridgeByExportXcmRouterInstance, + UnpaidLocalExporter, + >; + + type BridgeIdResolver = + pallet_xcm_bridge_hub_router::impls::EnsureIsRemoteBridgeIdResolver; + // We don't need to support here `report_bridge_status`. + type BridgeHubOrigin = EnsureNever<()>; +} + +/// A dynamic way to set different universal location for the origin which sends `ExportMessage`. +pub struct ExportMessageOriginUniversalLocation; +impl ExportMessageOriginUniversalLocation { + pub(crate) fn set(universal_location: Option) { + EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION.with(|o| *o.borrow_mut() = universal_location); + } +} +impl Get for ExportMessageOriginUniversalLocation { + fn get() -> InteriorLocation { + EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION.with(|o| { + o.borrow() + .clone() + .expect("`EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION` is not set!") + }) + } +} +thread_local! { + pub static EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION: RefCell> = RefCell::new(None); +} + +pub struct BridgeHubLocationXcmOriginAsRoot(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; @@ -230,7 +337,7 @@ 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; @@ -264,14 +371,8 @@ thread_local! { } /// The `SendXcm` implementation directly executes XCM using `XcmExecutor`. -/// -/// We ensure that the `ExportMessage` produced by `pallet_xcm_bridge_hub_router` is compatible with -/// the `ExportXcm` implementation of `pallet_xcm_bridge_hub`. -/// -/// Note: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which calls the -/// `ExportXcm` implementation of `pallet_xcm_bridge_hub` as `MessageExporter`. -pub struct TestExportXcmWithXcmOverBridge; -impl SendXcm for TestExportXcmWithXcmOverBridge { +pub struct ExecuteXcmOverSendXcm; +impl SendXcm for ExecuteXcmOverSendXcm { type Ticket = Xcm<()>; fn validate( @@ -298,7 +399,7 @@ impl SendXcm for TestExportXcmWithXcmOverBridge { Ok(hash) } } -impl InspectMessageQueues for TestExportXcmWithXcmOverBridge { +impl InspectMessageQueues for ExecuteXcmOverSendXcm { fn clear_messages() { todo!() } @@ -307,7 +408,7 @@ impl InspectMessageQueues for TestExportXcmWithXcmOverBridge { todo!() } } -impl TestExportXcmWithXcmOverBridge { +impl ExecuteXcmOverSendXcm { pub fn set_origin_for_execute(origin: Location) { EXECUTE_XCM_ORIGIN.with(|o| *o.borrow_mut() = Some(origin)); } @@ -378,13 +479,9 @@ impl EnsureOrigin for OpenBridgeOrigin { return Ok(Location { parents: 1, interior: [Parachain(SIBLING_ASSET_HUB_ID), OnlyChild].into(), - }) - } - - let mut sibling_account = [0u8; 32]; - sibling_account[..4].copy_from_slice(&SIBLING_ASSET_HUB_ID.encode()[..4]); - if signer == Some(sibling_account.into()) { - return Ok(Location { parents: 1, interior: Parachain(SIBLING_ASSET_HUB_ID).into() }) + }); + } else if signer == Self::sibling_parachain_origin().into_signer() { + return Ok(SiblingLocation::get()); } Err(o) @@ -396,43 +493,93 @@ impl EnsureOrigin for OpenBridgeOrigin { } } -pub struct TestLocalXcmChannelManager; +pub(crate) type OpenBridgeOriginOf = + >::OpenBridgeOrigin; + +pub(crate) fn fund_origin_sovereign_account( + locations: &BridgeLocations, + balance: Balance, +) -> AccountId { + let bridge_owner_account = + LocationToAccountId::convert_location(locations.bridge_origin_relative_location()).unwrap(); + assert_ok!(Balances::mint_into(&bridge_owner_account, balance)); + bridge_owner_account +} + +/// 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 is_congested(_with: &Location) -> bool { - frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Congested") + 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); + } + + 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, call: encoded_call.into() }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]) } } -impl pallet_xcm_bridge_hub_router::XcmChannelStatusProvider for TestLocalXcmChannelManager { - fn is_congested(with: &Location) -> bool { - ::is_congested(with) +/// `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) } } @@ -442,6 +589,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 { @@ -555,10 +716,13 @@ impl MessageDispatch for TestMessageDispatch { } } +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + sp_io::TestExternalities::new(t) +} + /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - sp_io::TestExternalities::new( - frame_system::GenesisConfig::::default().build_storage().unwrap(), - ) - .execute_with(test) + new_test_ext().execute_with(test) } diff --git a/bridges/modules/xcm-bridge-hub/src/weights.rs b/bridges/modules/xcm-bridge-hub/src/weights.rs new file mode 100644 index 000000000000..c0bab87ef727 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/weights.rs @@ -0,0 +1,90 @@ +// Copyright (C) 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 . + +//! Autogenerated weights for pallet_xcm_bridge_hub +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/rip-bridge-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm_bridge_hub_router +// --extrinsic=* +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --output=./modules/xcm-bridge-hub-router/src/weights.rs +// --template=./.maintain/bridge-weight-template.hbs + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_xcm_bridge_hub_router. +pub trait WeightInfo { + fn open_bridge() -> Weight; + fn close_bridge() -> Weight; + fn update_notification_receiver() -> Weight; +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn open_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 19_370_000 picoseconds. + Weight::from_parts(19_928_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn close_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 20_045_000 picoseconds. + Weight::from_parts(20_861_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn update_notification_receiver() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3530` + // Minimum execution time: 12_179_000 picoseconds. + Weight::from_parts(12_679_000, 0) + .saturating_add(Weight::from_parts(0, 3530)) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } +} diff --git a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs index 89123b51ef2f..f2e4a794c0ad 100644 --- a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs @@ -18,29 +18,11 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::H256; +use sp_core::sp_std::fmt::Debug; use sp_runtime::{FixedU128, RuntimeDebug}; -use xcm::latest::prelude::Location; - -/// Minimal delivery fee factor. -pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); - -/// XCM channel status provider that may report whether it is congested or not. -/// -/// By 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 - } -} +use xcm::latest::prelude::{InteriorLocation, Location, NetworkId}; /// Current status of the bridge. #[derive(Clone, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] @@ -51,17 +33,33 @@ pub struct BridgeState { pub is_congested: bool, } -impl Default for BridgeState { - fn default() -> BridgeState { - BridgeState { delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR, is_congested: false } - } +/// Trait that resolves a specific `BridgeId` for `dest`. +pub trait ResolveBridgeId { + /// Bridge identifier. + type BridgeId: FullCodec + MaxEncodedLen + TypeInfo + Debug + Clone + PartialEq + Eq; + /// Resolves `Self::BridgeId` for `dest`. If `None`, it means there is no supported bridge ID. + fn resolve_for_dest(bridged_dest: &Location) -> Option; + + /// Resolves `Self::BridgeId` for `bridged_network` and `bridged_dest`. If `None`, it means + /// there is no supported bridge ID. + fn resolve_for( + bridged_network: &NetworkId, + bridged_dest: &InteriorLocation, + ) -> Option; } -/// A minimized version of `pallet-xcm-bridge-hub-router::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum XcmBridgeHubRouterCall { - /// `pallet-xcm-bridge-hub-router::Call::report_bridge_status` - #[codec(index = 0)] - report_bridge_status { bridge_id: H256, is_congested: bool }, +/// The default implementation of `ResolveBridgeId` for `()` returns `None`. +impl ResolveBridgeId for () { + type BridgeId = (); + + fn resolve_for_dest(_dest: &Location) -> Option { + None + } + + fn resolve_for( + _bridged_network: &NetworkId, + _bridged_dest: &InteriorLocation, + ) -> Option { + None + } } diff --git a/bridges/primitives/xcm-bridge-hub/src/call_info.rs b/bridges/primitives/xcm-bridge-hub/src/call_info.rs index fd4fc67822fe..28323dbeed07 100644 --- a/bridges/primitives/xcm-bridge-hub/src/call_info.rs +++ b/bridges/primitives/xcm-bridge-hub/src/call_info.rs @@ -16,6 +16,7 @@ //! Defines structures related to calls of the `pallet-xcm-bridge-hub` pallet. +use crate::Receiver; use bp_messages::MessageNonce; use codec::{Decode, Encode}; use scale_info::TypeInfo; @@ -31,6 +32,9 @@ pub enum XcmBridgeHubCall { open_bridge { /// Universal `InteriorLocation` from the bridged consensus. bridge_destination_universal_location: Box, + /// Optional `maybe_notify` holds data about the `bridge_origin_relative_location` where + /// notifications can be sent to handle congestion. + maybe_notify: Option, }, /// `pallet_xcm_bridge_hub::Call::close_bridge` #[codec(index = 1)] diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 63beb1bc3041..7511f3c7e3bd 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 } } @@ -141,10 +144,11 @@ pub enum BridgeState { /// Bridge is opened. Associated lanes are also opened. Opened, /// Bridge is suspended. Associated lanes are opened. + /// *suspended* means that we have sent the "Suspended" message/signal to the local bridge + /// origin. /// - /// We keep accepting messages to the bridge. The only difference with the `Opened` state - /// is that we have sent the "Suspended" message/signal to the local bridge origin. - Suspended, + /// `bool` - `true` means that we keep accepting messages to the bridge. + Suspended(bool), /// Bridge is closed. Associated lanes are also closed. /// After all outbound messages will be pruned, the bridge will vanish without any traces. Closed, @@ -169,13 +173,63 @@ pub struct Bridge { /// Current bridge state. pub state: BridgeState, - /// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`. - pub bridge_owner_account: AccountIdOf, + /// Reserved amount on the sovereign account of the sibling bridge origin. - pub deposit: BalanceOf, + /// The account is derived from `self.bridge_origin_relative_location`. + pub deposit: Option>, /// 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, + Serialize, + Deserialize, +)] +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`. +pub type DepositOf = Deposit, BalanceOf>; + +/// A structure containing information about from whom the deposit is reserved. +#[derive(Clone, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub struct Deposit { + /// Account with the reserved funds. + pub account: AccountId, + /// Reserved amount. + pub amount: Balance, +} + +impl Deposit { + /// Create new deposit. + pub fn new(account: AccountId, amount: Balance) -> Self { + Self { account, amount } + } } /// Locations of bridge endpoints at both sides of the bridge. diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 9c7470eda6da..cb33b8232ab2 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 8ed11505a27a..69ffbd400166 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -17,38 +17,10 @@ use crate::{pallet, OutboundState}; use cumulus_primitives_core::ParaId; use xcm::latest::prelude::*; -/// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` 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 - 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_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 { diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 91f71558b54a..80ba902539be 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/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs index 575017f88bb5..752bd3af05d1 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs @@ -75,6 +75,7 @@ pub fn genesis() -> Storage { Location::new(1, [Parachain(1000)]), Junctions::from([ByGenesis(WESTEND_GENESIS_HASH).into(), Parachain(1000)]), Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + None, ), ], ..Default::default() diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs index eb4623084f85..794762566bda 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs @@ -78,6 +78,7 @@ pub fn genesis() -> Storage { Parachain(1000), ]), Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + None, ), ], ..Default::default() diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index c0d42cf2758e..78fa12619e08 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -63,7 +63,7 @@ use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, MessageKey, OutboundLaneData, }; -pub use bp_xcm_bridge_hub::XcmBridgeHubCall; +pub use bp_xcm_bridge_hub::{Receiver, XcmBridgeHubCall}; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LaneIdOf, OutboundLanes, Pallet}; pub use pallet_bridge_messages::{ Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2, @@ -938,7 +938,8 @@ macro_rules! impl_bridge_helpers_for_chain { pub fn open_bridge( bridge_location: $crate::impls::Location, bridge_destination_universal_location: $crate::impls::InteriorLocation, - maybe_paid: Option<($crate::impls::Asset, $crate::impls::AccountId)> + maybe_paid: Option<($crate::impls::Asset, $crate::impls::AccountId)>, + maybe_notify: Option<$crate::impls::Receiver>, ) { ::execute_with(|| { use $crate::impls::{bx, Chain}; @@ -952,7 +953,8 @@ macro_rules! impl_bridge_helpers_for_chain { let call: $crate::impls::DoubleEncoded<()> = $runtime_call_wrapper(XcmBridgeHubCall::open_bridge { bridge_destination_universal_location: bx!( bridge_destination_universal_location.clone().into() - ) + ), + maybe_notify, }).encode().into(); let xcm = if let Some((fee_asset, beneficiary)) = maybe_paid { diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index 8aff87755961..ca951e9becab 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -261,6 +261,7 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { AssetHubRococo::para_id(), )), )), + None, ); // open AHW -> AHR @@ -278,5 +279,6 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { AssetHubWestend::para_id(), )), )), + None, ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index 6c1cdb98e8b2..643ec83a7bfd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -271,6 +271,7 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { AssetHubRococo::para_id(), )), )), + None, ); // open AHW -> AHR @@ -288,5 +289,6 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { AssetHubWestend::para_id(), )), )), + None, ); } 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 2f9d83bd9d0b..342f1a506e35 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -62,7 +62,8 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, - ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, TransformOrigin, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, + TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -99,7 +100,7 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; #[cfg(feature = "runtime-benchmarks")] use xcm::latest::prelude::{ Asset, Assets as XcmAssets, Fungible, Here, InteriorLocation, Junction, Junction::*, Location, - NetworkId, NonFungible, Parent, ParentThen, Response, XCM_VERSION, + NetworkId, NonFungible, Parent, ParentThen, Response, }; use xcm::{ latest::prelude::{AssetId, BodyId}, @@ -111,6 +112,7 @@ use xcm_runtime_apis::{ }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; +use xcm_builder::{NetworkExportTable, SovereignPaidRemoteExporter}; impl_opaque_keys! { pub struct SessionKeys { @@ -927,17 +929,35 @@ 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 Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; - type ToBridgeHubSender = XcmpQueue; - type LocalXcmChannelManager = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; + // Let's use `SovereignPaidRemoteExporter`, which sends `ExportMessage` over HRMP to the sibling + // BridgeHub. + type ToBridgeHubSender = SovereignPaidRemoteExporter< + // `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, + xcm_config::UniversalLocation, + >; + + // 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< + xcm_config::UniversalLocation, + >; + // 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; } @@ -1690,31 +1710,11 @@ impl_runtime_apis! { } impl XcmBridgeHubRouterConfig for Runtime { - fn make_congested() { - cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( - xcm_config::bridging::SiblingBridgeHubParaId::get().into() - ); - } fn ensure_bridged_target_destination() -> Result { - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - xcm_config::bridging::SiblingBridgeHubParaId::get().into() - ); - let bridged_asset_hub = xcm_config::bridging::to_westend::AssetHubWestend::get(); - let _ = PolkadotXcm::force_xcm_version( - RuntimeOrigin::root(), - alloc::boxed::Box::new(bridged_asset_hub.clone()), - XCM_VERSION, - ).map_err(|e| { - log::error!( - "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", - RuntimeOrigin::root(), - bridged_asset_hub, - XCM_VERSION, - e - ); - BenchmarkError::Stop("XcmVersion was not stored!") - })?; - Ok(bridged_asset_hub) + Ok(xcm_config::bridging::to_westend::AssetHubWestend::get()) + } + fn report_bridge_status_origin() -> Option { + Some(pallet_xcm::Origin::Xcm(xcm_config::bridging::SiblingBridgeHub::get()).into()) } } 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 00ecf239428f..3a5f55864c08 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -48,33 +48,40 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm_bridge_hub_router`. pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { - /// 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) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToWestendXcmRouter::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - fn on_initialize_when_non_congested() -> Weight { + /// Storage: `ToWestendXcmRouter::Bridges` (r:2 w:1) + /// Proof: `ToWestendXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn on_idle_when_bridge_state_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `153` - // Estimated: `5487` - // Minimum execution time: 12_993_000 picoseconds. - Weight::from_parts(13_428_000, 0) - .saturating_add(Weight::from_parts(0, 5487)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 19_038_000 picoseconds. + Weight::from_parts(19_659_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::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) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - fn on_initialize_when_congested() -> Weight { + /// Storage: `ToWestendXcmRouter::Bridges` (r:2 w:1) + /// Proof: `ToWestendXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn on_idle_when_bridge_state_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `5487` - // Minimum execution time: 6_305_000 picoseconds. - Weight::from_parts(6_536_000, 0) - .saturating_add(Weight::from_parts(0, 5487)) + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 20_051_000 picoseconds. + Weight::from_parts(20_698_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ToWestendXcmRouter::Bridges` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3530` + // Minimum execution time: 12_193_000 picoseconds. + Weight::from_parts(12_658_000, 0) + .saturating_add(Weight::from_parts(0, 3530)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 08b2f520c4b9..1e3ad688072e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -558,19 +558,12 @@ pub mod bridging { /// (`AssetId` has to be aligned with `BridgeTable`) pub XcmBridgeHubRouterFeeAssetId: AssetId = TokenLocation::get().into(); - pub BridgeTable: alloc::vec::Vec = - alloc::vec::Vec::new().into_iter() - .chain(to_westend::BridgeTable::get()) - .collect(); - pub EthereumBridgeTable: alloc::vec::Vec = alloc::vec::Vec::new().into_iter() .chain(to_ethereum::BridgeTable::get()) .collect(); } - pub type NetworkExportTable = xcm_builder::NetworkExportTable; - pub type EthereumNetworkExportTable = xcm_builder::NetworkExportTable; pub mod to_westend { 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 5da8b45417a3..2c2ca229c495 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -27,7 +27,7 @@ use asset_hub_rococo_runtime::{ AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - SessionKeys, TrustBackedAssetsInstance, XcmpQueue, + SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -1271,6 +1271,34 @@ 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, + call: RuntimeCall::ToWestendXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id, + is_congested, + }, + ) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] + .into() + }) + } } #[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 2206aea78ec2..48d3823f9022 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -91,6 +91,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, @@ -100,7 +102,7 @@ use xcm::{ #[cfg(feature = "runtime-benchmarks")] use xcm::latest::prelude::{ Asset, Assets as XcmAssets, Fungible, Here, InteriorLocation, Junction, Junction::*, Location, - NetworkId, NonFungible, Parent, ParentThen, Response, XCM_VERSION, + NetworkId, NonFungible, Parent, ParentThen, Response, }; use xcm_runtime_apis::{ @@ -109,6 +111,7 @@ use xcm_runtime_apis::{ }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; +use xcm_builder::{NetworkExportTable, SovereignPaidRemoteExporter}; impl_opaque_keys! { pub struct SessionKeys { @@ -921,17 +924,35 @@ 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 Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; - type ToBridgeHubSender = XcmpQueue; - type LocalXcmChannelManager = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; + // Let's use `SovereignPaidRemoteExporter`, which sends `ExportMessage` over HRMP to the sibling + // BridgeHub. + type ToBridgeHubSender = SovereignPaidRemoteExporter< + // `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, + xcm_config::UniversalLocation, + >; + + // 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< + xcm_config::UniversalLocation, + >; + // 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; } @@ -1867,31 +1888,11 @@ impl_runtime_apis! { }; impl XcmBridgeHubRouterConfig for Runtime { - fn make_congested() { - cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::( - xcm_config::bridging::SiblingBridgeHubParaId::get().into() - ); - } fn ensure_bridged_target_destination() -> Result { - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - xcm_config::bridging::SiblingBridgeHubParaId::get().into() - ); - let bridged_asset_hub = xcm_config::bridging::to_rococo::AssetHubRococo::get(); - let _ = PolkadotXcm::force_xcm_version( - RuntimeOrigin::root(), - alloc::boxed::Box::new(bridged_asset_hub.clone()), - XCM_VERSION, - ).map_err(|e| { - log::error!( - "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", - RuntimeOrigin::root(), - bridged_asset_hub, - XCM_VERSION, - e - ); - BenchmarkError::Stop("XcmVersion was not stored!") - })?; - Ok(bridged_asset_hub) + Ok(xcm_config::bridging::to_rococo::AssetHubRococo::get()) + } + fn report_bridge_status_origin() -> Option { + Some(pallet_xcm::Origin::Xcm(xcm_config::bridging::SiblingBridgeHub::get()).into()) } } 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 c0898012e9f3..5089e21b91cb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -48,33 +48,40 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm_bridge_hub_router`. pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { - /// 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) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToRococoXcmRouter::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - fn on_initialize_when_non_congested() -> Weight { + /// Storage: `ToRococoXcmRouter::Bridges` (r:2 w:1) + /// Proof: `ToRococoXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn on_idle_when_bridge_state_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `225` - // Estimated: `5487` - // Minimum execution time: 13_483_000 picoseconds. - Weight::from_parts(13_862_000, 0) - .saturating_add(Weight::from_parts(0, 5487)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 19_382_000 picoseconds. + Weight::from_parts(20_031_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::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) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - fn on_initialize_when_congested() -> Weight { + /// Storage: `ToRococoXcmRouter::Bridges` (r:2 w:1) + /// Proof: `ToRococoXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn on_idle_when_bridge_state_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `5487` - // Minimum execution time: 5_078_000 picoseconds. - Weight::from_parts(5_233_000, 0) - .saturating_add(Weight::from_parts(0, 5487)) + // Measured: `204` + // Estimated: `6070` + // Minimum execution time: 19_869_000 picoseconds. + Weight::from_parts(20_528_000, 0) + .saturating_add(Weight::from_parts(0, 6070)) .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ToRococoXcmRouter::Bridges` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::Bridges` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3530` + // Minimum execution time: 10_800_000 picoseconds. + Weight::from_parts(11_171_000, 0) + .saturating_add(Weight::from_parts(0, 3530)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index b4e938f1f8b5..2a1d7898591d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -579,15 +579,8 @@ pub mod bridging { /// Router expects payment with this `AssetId`. /// (`AssetId` has to be aligned with `BridgeTable`) pub XcmBridgeHubRouterFeeAssetId: AssetId = WestendLocation::get().into(); - - pub BridgeTable: alloc::vec::Vec = - alloc::vec::Vec::new().into_iter() - .chain(to_rococo::BridgeTable::get()) - .collect(); } - pub type NetworkExportTable = xcm_builder::NetworkExportTable; - pub mod to_rococo { use super::*; 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 5d0f843554a1..987edda652f2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -27,7 +27,7 @@ use asset_hub_westend_runtime::{ AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - TrustBackedAssetsInstance, XcmpQueue, + ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; pub use asset_hub_westend_runtime::{AssetConversion, AssetDeposit, CollatorSelection, System}; use asset_test_utils::{ @@ -1250,6 +1250,34 @@ 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, + call: RuntimeCall::ToRococoXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id, + is_congested, + }, + ) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] + .into() + }) +} + #[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 4f144e24aa30..14470c5d49a9 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,10 @@ 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 +536,27 @@ 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::< + Runtime, + XcmBridgeHubRouterInstance, + >::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,10 +570,15 @@ 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::< + Runtime, + XcmBridgeHubRouterInstance, + >::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,); }; report_bridge_status(true); 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 7e0385692375..38792b88eee3 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,7 +40,7 @@ use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; -use pallet_xcm_bridge_hub::XcmAsPlainPayload; +use pallet_xcm_bridge_hub::{congestion::BlobDispatcherWithChannelStatus, XcmAsPlainPayload}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ @@ -85,13 +85,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< @@ -133,6 +126,7 @@ impl pallet_bridge_messages::Config for Runt pub type XcmOverPolkadotBulletinInstance = pallet_xcm_bridge_hub::Instance2; impl pallet_xcm_bridge_hub::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_xcm_bridge_hub_over_bulletin::WeightInfo; type UniversalLocation = UniversalLocation; type BridgedNetwork = RococoBulletinGlobalConsensusNetworkLocation; @@ -156,7 +150,18 @@ 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< + XcmRouter, + UniversalLocation, + BridgeRococoToRococoBulletinMessagesPalletInstance, + >, + // no congestion checking + (), + >; + type CongestionLimits = (); } #[cfg(test)] @@ -232,55 +237,6 @@ mod tests { } } -#[cfg(feature = "runtime-benchmarks")] -pub(crate) fn open_bridge_for_benchmarks( - with: pallet_xcm_bridge_hub::LaneIdOf, - sibling_para_id: u32, -) -> InteriorLocation -where - R: pallet_xcm_bridge_hub::Config, - XBHI: 'static, - C: xcm_executor::traits::ConvertLocation< - bp_runtime::AccountIdOf>, - >, -{ - use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; - use sp_runtime::traits::Zero; - use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation}; - - // insert bridge metadata - let lane_id = with; - let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); - let universal_source = - [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into(); - let universal_destination = - [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get()), Parachain(2075)].into(); - let bridge_id = BridgeId::new(&universal_source, &universal_destination); - - // insert only bridge metadata, because the benchmarks create lanes - pallet_xcm_bridge_hub::Bridges::::insert( - bridge_id, - Bridge { - bridge_origin_relative_location: alloc::boxed::Box::new( - sibling_parachain.clone().into(), - ), - bridge_origin_universal_location: alloc::boxed::Box::new( - VersionedInteriorLocation::from(universal_source.clone()), - ), - bridge_destination_universal_location: alloc::boxed::Box::new( - VersionedInteriorLocation::from(universal_destination), - ), - state: BridgeState::Opened, - bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), - deposit: Zero::zero(), - lane_id, - }, - ); - pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); - - universal_source -} - /// Contains the migration for the PeopleRococo<>RococoBulletin bridge. pub mod migration { use super::*; @@ -304,5 +260,6 @@ pub mod migration { ConstBool, PeopleRococoLocation, BulletinRococoLocation, + (), >; } 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 0eab3c74a7e2..3e5b73d258dd 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,12 @@ 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::*, WESTEND_GENESIS_HASH}, @@ -80,10 +85,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,11 +129,24 @@ 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, 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; impl pallet_xcm_bridge_hub::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_xcm_bridge_hub_over_westend::WeightInfo; type UniversalLocation = UniversalLocation; type BridgedNetwork = WestendGlobalConsensusNetworkLocation; @@ -156,58 +170,29 @@ 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; -} - -#[cfg(feature = "runtime-benchmarks")] -pub(crate) fn open_bridge_for_benchmarks( - with: pallet_xcm_bridge_hub::LaneIdOf, - sibling_para_id: u32, -) -> InteriorLocation -where - R: pallet_xcm_bridge_hub::Config, - XBHI: 'static, - C: xcm_executor::traits::ConvertLocation< - bp_runtime::AccountIdOf>, - >, -{ - use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; - use sp_runtime::traits::Zero; - use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation}; - - // insert bridge metadata - let lane_id = with; - let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); - let universal_source = - [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into(); - let universal_destination = - [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2075)].into(); - let bridge_id = BridgeId::new(&universal_source, &universal_destination); - - // insert only bridge metadata, because the benchmarks create lanes - pallet_xcm_bridge_hub::Bridges::::insert( - bridge_id, - Bridge { - bridge_origin_relative_location: alloc::boxed::Box::new( - sibling_parachain.clone().into(), - ), - bridge_origin_universal_location: alloc::boxed::Box::new( - VersionedInteriorLocation::from(universal_source.clone()), - ), - bridge_destination_universal_location: alloc::boxed::Box::new( - VersionedInteriorLocation::from(universal_destination), - ), - state: BridgeState::Opened, - bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), - deposit: Zero::zero(), - lane_id, - }, - ); - pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); - - universal_source + // 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< + Runtime, + XcmOverBridgeHubWestendInstance, + ReportBridgeStatusXcmProvider, + XcmRouter, + >; + // 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< + XcmRouter, + UniversalLocation, + BridgeRococoToWestendMessagesPalletInstance, + >, + // 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, + >; + type CongestionLimits = (); } #[cfg(test)] @@ -323,6 +308,7 @@ pub mod migration { ConstBool, AssetHubRococoLocation, AssetHubWestendUniversalLocation, + (), >; mod v1_wrong { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs index 98e2450ee832..3a5a0c69a4a4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs @@ -33,7 +33,12 @@ fn bridge_hub_rococo_genesis( id: ParaId, bridges_pallet_owner: Option, asset_hub_para_id: ParaId, - opened_bridges: Vec<(Location, InteriorLocation, Option)>, + opened_bridges: Vec<( + Location, + InteriorLocation, + Option, + Option, + )>, ) -> serde_json::Value { build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { @@ -87,6 +92,7 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option bridge_hub_rococo_genesis( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index ff7af475f5e2..4dc38e553d0e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -181,6 +181,10 @@ pub type Migrations = ( RocksDbWeight, >, pallet_bridge_relayers::migration::v1::MigrationToV1, + pallet_xcm_bridge_hub::migration::v1::MigrationToV1< + Runtime, + bridge_to_westend_config::XcmOverBridgeHubWestendInstance, + >, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -679,6 +683,8 @@ mod benches { [pallet_bridge_messages, RococoToRococoBulletin] [pallet_bridge_relayers, Legacy] [pallet_bridge_relayers, PermissionlessLanes] + [pallet_xcm_bridge_hub, OverWestend] + [pallet_xcm_bridge_hub, OverBulletin] // Ethereum Bridge [snowbridge_pallet_inbound_queue, EthereumInboundQueue] [snowbridge_pallet_outbound_queue, EthereumOutboundQueue] @@ -1059,10 +1065,12 @@ impl_runtime_apis! { // Change weight file names. type WestendFinality = BridgeWestendGrandpa; type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; - type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; - type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet ::; + type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet::; + type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet::; type Legacy = BridgeRelayersBench::; type PermissionlessLanes = BridgeRelayersBench::; + type OverWestend = pallet_xcm_bridge_hub::benchmarking::Pallet::; + type OverBulletin = pallet_xcm_bridge_hub::benchmarking::Pallet::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1258,30 +1266,16 @@ impl_runtime_apis! { BenchmarkError::Stop("XcmVersion was not stored!") })?; - let sibling_parachain_location = Location::new(1, [Parachain(5678)]); - - // fund SA - use frame_support::traits::fungible::Mutate; - use xcm_executor::traits::ConvertLocation; - frame_support::assert_ok!( - Balances::mint_into( - &xcm_config::LocationToAccountId::convert_location(&sibling_parachain_location).expect("valid AccountId"), - bridge_to_westend_config::BridgeDeposit::get() - .saturating_add(ExistentialDeposit::get()) - .saturating_add(UNITS * 5) - ) - ); - // open bridge + let sibling_parachain_location = Location::new(1, [Parachain(5678)]); let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)), Parachain(8765)].into(); - let locations = XcmOverBridgeHubWestend::bridge_locations( + let _ = XcmOverBridgeHubWestend::open_bridge_for_benchmarks( + bp_messages::LegacyLaneId([1, 2, 3, 4]), sibling_parachain_location.clone(), bridge_destination_universal_location.clone(), - )?; - XcmOverBridgeHubWestend::do_open_bridge( - locations, - bp_messages::LegacyLaneId([1, 2, 3, 4]), true, + None, + || ExistentialDeposit::get(), ).map_err(|e| { log::error!( "Failed to `XcmOverBridgeHubWestend::open_bridge`({:?}, {:?})`, error: {:?}", @@ -1315,6 +1309,8 @@ impl_runtime_apis! { type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet ::; type Legacy = BridgeRelayersBench::; type PermissionlessLanes = BridgeRelayersBench::; + type OverWestend = pallet_xcm_bridge_hub::benchmarking::Pallet::; + type OverBulletin = pallet_xcm_bridge_hub::benchmarking::Pallet::; use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_grandpa_chain, @@ -1329,6 +1325,18 @@ impl_runtime_apis! { MessageProofParams, }; + impl pallet_xcm_bridge_hub::benchmarking::Config for Runtime { + fn open_bridge_origin() -> Option<(RuntimeOrigin, Balance)> { + None + } + } + + impl pallet_xcm_bridge_hub::benchmarking::Config for Runtime { + fn open_bridge_origin() -> Option<(RuntimeOrigin, Balance)> { + None + } + } + impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); @@ -1350,26 +1358,34 @@ impl_runtime_apis! { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - let universal_source = bridge_to_westend_config::open_bridge_for_benchmarks::< - Runtime, - bridge_to_westend_config::XcmOverBridgeHubWestendInstance, - xcm_config::LocationToAccountId, - >(params.lane, 42); + let bridge_locations = XcmOverBridgeHubWestend::open_bridge_for_benchmarks( + params.lane, + Location::new(1, [Parachain(42)]), + [GlobalConsensus(bridge_to_westend_config::WestendGlobalConsensusNetwork::get()), Parachain(2075)].into(), + // do not create lanes, because they are already created `params.lane` + false, + None, + || ExistentialDeposit::get(), + ).expect("valid bridge opened"); prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample(universal_source)) + >(params, generate_xcm_builder_bridge_message_sample(bridge_locations.bridge_origin_universal_location().clone())) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams>, ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { - let _ = bridge_to_westend_config::open_bridge_for_benchmarks::< - Runtime, - bridge_to_westend_config::XcmOverBridgeHubWestendInstance, - xcm_config::LocationToAccountId, - >(params.lane, 42); + let _ = XcmOverBridgeHubWestend::open_bridge_for_benchmarks( + params.lane, + Location::new(1, [Parachain(42)]), + [GlobalConsensus(bridge_to_westend_config::WestendGlobalConsensusNetwork::get()), Parachain(2075)].into(), + // do not create lanes, because they are already created `params.lane` + false, + None, + || ExistentialDeposit::get(), + ); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, @@ -1395,26 +1411,34 @@ impl_runtime_apis! { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - let universal_source = bridge_to_bulletin_config::open_bridge_for_benchmarks::< - Runtime, - bridge_to_bulletin_config::XcmOverPolkadotBulletinInstance, - xcm_config::LocationToAccountId, - >(params.lane, 42); + let bridge_locations = XcmOverPolkadotBulletin::open_bridge_for_benchmarks( + params.lane, + Location::new(1, [Parachain(42)]), + [GlobalConsensus(bridge_to_bulletin_config::RococoBulletinGlobalConsensusNetwork::get())].into(), + // do not create lanes, because they are already created `params.lane` + false, + None, + || ExistentialDeposit::get(), + ).expect("valid bridge opened"); prepare_message_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample(universal_source)) + >(params, generate_xcm_builder_bridge_message_sample(bridge_locations.bridge_origin_universal_location().clone())) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams>, ) -> bridge_to_bulletin_config::ToRococoBulletinMessagesDeliveryProof { - let _ = bridge_to_bulletin_config::open_bridge_for_benchmarks::< - Runtime, - bridge_to_bulletin_config::XcmOverPolkadotBulletinInstance, - xcm_config::LocationToAccountId, - >(params.lane, 42); + let _ = XcmOverPolkadotBulletin::open_bridge_for_benchmarks( + params.lane, + Location::new(1, [Parachain(42)]), + [GlobalConsensus(bridge_to_bulletin_config::RococoBulletinGlobalConsensusNetwork::get())].into(), + // do not create lanes, because they are already created `params.lane` + false, + None, + || ExistentialDeposit::get(), + ).expect("valid bridge opened"); prepare_message_delivery_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index 74796e626a2e..1dd689cde4e8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -42,6 +42,8 @@ pub mod pallet_timestamp; pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; +pub mod pallet_xcm_bridge_hub_over_bulletin; +pub mod pallet_xcm_bridge_hub_over_westend; pub mod paritydb_weights; pub mod rocksdb_weights; pub mod snowbridge_pallet_ethereum_client; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs index cde511fc749d..e99b5c529d6f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -53,20 +53,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49208), added: 51683, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `933` - // Estimated: `52674` - // Minimum execution time: 61_893_000 picoseconds. - Weight::from_parts(63_358_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) + // Measured: `963` + // Estimated: `52673` + // Minimum execution time: 63_162_000 picoseconds. + Weight::from_parts(64_800_000, 0) + .saturating_add(Weight::from_parts(0, 52673)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,24 +75,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49208), added: 51683, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `933` - // Estimated: `52674` - // Minimum execution time: 61_612_000 picoseconds. - Weight::from_parts(62_758_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 13_521 - .saturating_add(Weight::from_parts(14_530_846, 0).saturating_mul(n.into())) + // Measured: `963` + // Estimated: `52673` + // Minimum execution time: 62_746_000 picoseconds. + Weight::from_parts(64_378_000, 0) + .saturating_add(Weight::from_parts(0, 52673)) + // Standard Error: 18_595 + .saturating_add(Weight::from_parts(15_438_479, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -101,20 +101,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49208), added: 51683, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `933` - // Estimated: `52674` - // Minimum execution time: 66_862_000 picoseconds. - Weight::from_parts(69_531_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) + // Measured: `963` + // Estimated: `52673` + // Minimum execution time: 68_757_000 picoseconds. + Weight::from_parts(71_599_000, 0) + .saturating_add(Weight::from_parts(0, 52673)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -123,24 +123,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49208), added: 51683, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `933` - // Estimated: `52674` - // Minimum execution time: 58_971_000 picoseconds. - Weight::from_parts(62_999_984, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(2_050, 0).saturating_mul(n.into())) + // Measured: `963` + // Estimated: `52673` + // Minimum execution time: 60_861_000 picoseconds. + Weight::from_parts(65_303_205, 0) + .saturating_add(Weight::from_parts(0, 52673)) + // Standard Error: 9 + .saturating_add(Weight::from_parts(2_156, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,20 +149,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65596), added: 68071, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `900` - // Estimated: `5383` - // Minimum execution time: 43_066_000 picoseconds. - Weight::from_parts(43_878_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `930` + // Estimated: `5386` + // Minimum execution time: 44_686_000 picoseconds. + Weight::from_parts(46_494_000, 0) + .saturating_add(Weight::from_parts(0, 5386)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -171,20 +171,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65596), added: 68071, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `900` - // Estimated: `5383` - // Minimum execution time: 44_120_000 picoseconds. - Weight::from_parts(45_914_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `930` + // Estimated: `5386` + // Minimum execution time: 46_167_000 picoseconds. + Weight::from_parts(47_728_000, 0) + .saturating_add(Weight::from_parts(0, 5386)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -193,20 +193,20 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65596), added: 68071, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `900` - // Estimated: `5383` - // Minimum execution time: 44_930_000 picoseconds. - Weight::from_parts(46_111_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `930` + // Estimated: `5386` + // Minimum execution time: 46_285_000 picoseconds. + Weight::from_parts(48_097_000, 0) + .saturating_add(Weight::from_parts(0, 5386)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -215,11 +215,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49208), added: 51683, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) - /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1921), added: 4396, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -240,13 +240,13 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1092` - // Estimated: `52674` - // Minimum execution time: 81_911_000 picoseconds. - Weight::from_parts(88_170_136, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(7_233, 0).saturating_mul(n.into())) + // Measured: `1122` + // Estimated: `52673` + // Minimum execution time: 86_225_000 picoseconds. + Weight::from_parts(91_787_938, 0) + .saturating_add(Weight::from_parts(0, 52673)) + // Standard Error: 10 + .saturating_add(Weight::from_parts(7_223, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs index b27bbf4ff6c6..2243d02adbd2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -53,21 +53,23 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `810` - // Estimated: `52674` - // Minimum execution time: 62_750_000 picoseconds. - Weight::from_parts(65_328_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `940` + // Estimated: `52645` + // Minimum execution time: 62_868_000 picoseconds. + Weight::from_parts(65_210_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -75,25 +77,27 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `810` - // Estimated: `52674` - // Minimum execution time: 62_275_000 picoseconds. - Weight::from_parts(63_714_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 13_139 - .saturating_add(Weight::from_parts(14_630_892, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `940` + // Estimated: `52645` + // Minimum execution time: 62_893_000 picoseconds. + Weight::from_parts(63_992_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 13_856 + .saturating_add(Weight::from_parts(12_332_627, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -101,21 +105,23 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `810` - // Estimated: `52674` - // Minimum execution time: 68_950_000 picoseconds. - Weight::from_parts(71_420_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `940` + // Estimated: `52645` + // Minimum execution time: 68_193_000 picoseconds. + Weight::from_parts(70_799_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -123,25 +129,27 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `810` - // Estimated: `52674` - // Minimum execution time: 60_477_000 picoseconds. - Weight::from_parts(64_935_758, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 8 - .saturating_add(Weight::from_parts(2_008, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `940` + // Estimated: `52645` + // Minimum execution time: 61_230_000 picoseconds. + Weight::from_parts(65_437_770, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 9 + .saturating_add(Weight::from_parts(2_168, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -149,24 +157,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) - /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `779` - // Estimated: `5383` - // Minimum execution time: 52_939_000 picoseconds. - Weight::from_parts(54_637_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `711` + // Estimated: `5358` + // Minimum execution time: 51_650_000 picoseconds. + Weight::from_parts(53_190_000, 0) + .saturating_add(Weight::from_parts(0, 5358)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -175,24 +183,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `779` - // Estimated: `5383` - // Minimum execution time: 54_645_000 picoseconds. - Weight::from_parts(57_391_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `711` + // Estimated: `5358` + // Minimum execution time: 51_836_000 picoseconds. + Weight::from_parts(53_960_000, 0) + .saturating_add(Weight::from_parts(0, 5358)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -201,24 +209,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `779` - // Estimated: `6144` - // Minimum execution time: 59_581_000 picoseconds. - Weight::from_parts(61_657_000, 0) - .saturating_add(Weight::from_parts(0, 6144)) + // Measured: `711` + // Estimated: `6086` + // Minimum execution time: 56_606_000 picoseconds. + Weight::from_parts(58_528_000, 0) + .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -227,11 +235,13 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -244,21 +254,19 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1140` - // Estimated: `52674` - // Minimum execution time: 83_530_000 picoseconds. - Weight::from_parts(91_297_344, 0) - .saturating_add(Weight::from_parts(0, 52674)) + // Measured: `1071` + // Estimated: `52645` + // Minimum execution time: 85_179_000 picoseconds. + Weight::from_parts(91_600_892, 0) + .saturating_add(Weight::from_parts(0, 52645)) // Standard Error: 11 - .saturating_add(Weight::from_parts(7_197, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(7_210, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm_bridge_hub_over_bulletin.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm_bridge_hub_over_bulletin.rs new file mode 100644 index 000000000000..048dd45d06ff --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm_bridge_hub_over_bulletin.rs @@ -0,0 +1,81 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +//! Autogenerated weights for `pallet_xcm_bridge_hub` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_bridge_hub +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_xcm_bridge_hub`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_bridge_hub::WeightInfo for WeightInfo { + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn open_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn close_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_notification_receiver() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm_bridge_hub_over_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm_bridge_hub_over_westend.rs new file mode 100644 index 000000000000..048dd45d06ff --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm_bridge_hub_over_westend.rs @@ -0,0 +1,81 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +//! Autogenerated weights for `pallet_xcm_bridge_hub` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_bridge_hub +// --chain=bridge-hub-rococo-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_xcm_bridge_hub`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_bridge_hub::WeightInfo for WeightInfo { + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn open_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn close_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_notification_receiver() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index bac73e0e0567..b37450814de3 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 69_010_000 picoseconds. - Weight::from_parts(70_067_000, 6196) + // Minimum execution time: 73_985_000 picoseconds. + Weight::from_parts(75_642_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,15 +77,26 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_069_000 picoseconds. - Weight::from_parts(1_116_000, 0) + // Minimum execution time: 946_000 picoseconds. + Weight::from_parts(1_025_000, 0) } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 3_881_000 picoseconds. + Weight::from_parts(4_137_000, 3593) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + pub fn set_asset_claimer() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_011_000 picoseconds. - Weight::from_parts(2_095_000, 0) + // Minimum execution time: 960_000 picoseconds. + Weight::from_parts(1_023_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -93,58 +104,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_630_000 picoseconds. - Weight::from_parts(7_992_000, 3497) + // Minimum execution time: 7_926_000 picoseconds. + Weight::from_parts(8_167_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_909_000 picoseconds. - Weight::from_parts(8_100_000, 0) + // Minimum execution time: 7_878_000 picoseconds. + Weight::from_parts(8_181_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_749_000 picoseconds. - Weight::from_parts(1_841_000, 0) + // Minimum execution time: 1_580_000 picoseconds. + Weight::from_parts(1_738_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_109_000 picoseconds. - Weight::from_parts(1_156_000, 0) + // Minimum execution time: 967_000 picoseconds. + Weight::from_parts(1_028_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_073_000 picoseconds. - Weight::from_parts(1_143_000, 0) + // Minimum execution time: 990_000 picoseconds. + Weight::from_parts(1_043_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_050_000 picoseconds. - Weight::from_parts(1_084_000, 0) + // Minimum execution time: 924_000 picoseconds. + Weight::from_parts(1_001_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_060_000 picoseconds. - Weight::from_parts(1_114_000, 0) + // Minimum execution time: 971_000 picoseconds. + Weight::from_parts(1_016_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_112_000, 0) + // Minimum execution time: 953_000 picoseconds. + Weight::from_parts(1_023_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -166,8 +177,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 65_538_000 picoseconds. - Weight::from_parts(66_943_000, 6196) + // Minimum execution time: 69_178_000 picoseconds. + Weight::from_parts(71_090_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -177,8 +188,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 10_898_000 picoseconds. - Weight::from_parts(11_262_000, 3555) + // Minimum execution time: 11_211_000 picoseconds. + Weight::from_parts(11_590_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +197,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_026_000 picoseconds. - Weight::from_parts(1_104_000, 0) + // Minimum execution time: 925_000 picoseconds. + Weight::from_parts(995_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -207,8 +218,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_133_000 picoseconds. - Weight::from_parts(25_526_000, 3503) + // Minimum execution time: 25_942_000 picoseconds. + Weight::from_parts(26_756_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -218,44 +229,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_946_000 picoseconds. - Weight::from_parts(3_074_000, 0) + // Minimum execution time: 3_019_000 picoseconds. + Weight::from_parts(3_245_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_428_000 picoseconds. - Weight::from_parts(1_490_000, 0) + // Minimum execution time: 1_359_000 picoseconds. + Weight::from_parts(1_442_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_158_000 picoseconds. - Weight::from_parts(1_222_000, 0) + // Minimum execution time: 1_053_000 picoseconds. + Weight::from_parts(1_169_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_056_000 picoseconds. - Weight::from_parts(1_117_000, 0) + // Minimum execution time: 953_000 picoseconds. + Weight::from_parts(1_039_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_045_000 picoseconds. - Weight::from_parts(1_084_000, 0) + // Minimum execution time: 957_000 picoseconds. + Weight::from_parts(1_005_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_224_000 picoseconds. - Weight::from_parts(1_268_000, 0) + // Minimum execution time: 1_151_000 picoseconds. + Weight::from_parts(1_198_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -277,8 +288,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 70_789_000 picoseconds. - Weight::from_parts(72_321_000, 6196) + // Minimum execution time: 75_598_000 picoseconds. + Weight::from_parts(78_209_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -286,8 +297,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_521_000 picoseconds. - Weight::from_parts(4_649_000, 0) + // Minimum execution time: 4_954_000 picoseconds. + Weight::from_parts(5_198_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -309,8 +320,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 66_129_000 picoseconds. - Weight::from_parts(68_089_000, 6196) + // Minimum execution time: 69_330_000 picoseconds. + Weight::from_parts(71_245_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -318,44 +329,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_094_000 picoseconds. - Weight::from_parts(1_157_000, 0) + // Minimum execution time: 993_000 picoseconds. + Weight::from_parts(1_078_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_109_000, 0) + // Minimum execution time: 942_000 picoseconds. + Weight::from_parts(1_017_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_053_000 picoseconds. - Weight::from_parts(1_080_000, 0) + // Minimum execution time: 928_000 picoseconds. + Weight::from_parts(1_005_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + // Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - // Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) - // Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `190` - // Estimated: `6130` - // Minimum execution time: 42_081_000 picoseconds. - Weight::from_parts(42_977_658, 6130) - // Standard Error: 77 - .saturating_add(Weight::from_parts(44_912, 0).saturating_mul(x.into())) + // Measured: `632` + // Estimated: `6572` + // Minimum execution time: 58_042_000 picoseconds. + Weight::from_parts(59_689_657, 6572) + // Standard Error: 212 + .saturating_add(Weight::from_parts(49_274, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -363,22 +374,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_041_000 picoseconds. - Weight::from_parts(1_084_000, 0) + // Minimum execution time: 947_000 picoseconds. + Weight::from_parts(1_018_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_085_000 picoseconds. - Weight::from_parts(1_161_000, 0) - } - pub fn set_asset_claimer() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 707_000 picoseconds. - Weight::from_parts(749_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(1_050_000, 0) } pub fn execute_with_origin() -> Weight { // Proof Size summary in bytes: diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 2e7dd98e9dce..b9b083ebf2a9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -328,7 +328,7 @@ mod bridge_hub_westend_tests { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubWestendInstance - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, fee, LegacyLaneId([0, 0, 0, 1]), None) } ).1 }, @@ -392,7 +392,7 @@ mod bridge_hub_westend_tests { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubWestendInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, fee, LegacyLaneId([0, 0, 0, 1]), None) }, ) .1 @@ -426,7 +426,7 @@ mod bridge_hub_westend_tests { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubWestendInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, fee, LegacyLaneId([0, 0, 0, 1]), None) }, ) .1 @@ -595,7 +595,7 @@ mod bridge_hub_bulletin_tests { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverPolkadotBulletinInstance - >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap(), None) } ).1 }, @@ -658,7 +658,7 @@ mod bridge_hub_bulletin_tests { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverPolkadotBulletinInstance, - >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap(), None) }, ) .1 @@ -691,7 +691,7 @@ mod bridge_hub_bulletin_tests { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverPolkadotBulletinInstance, - >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap(), None) }, ) .1 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 62c93da7c831..bccd2dced40e 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,12 @@ 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::*, ROCOCO_GENESIS_HASH}, @@ -87,10 +92,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,10 +160,23 @@ 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, 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 { type RuntimeEvent = RuntimeEvent; + type WeightInfo = weights::pallet_xcm_bridge_hub::WeightInfo; type UniversalLocation = UniversalLocation; type BridgedNetwork = RococoGlobalConsensusNetworkLocation; @@ -185,58 +199,29 @@ 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; -} - -#[cfg(feature = "runtime-benchmarks")] -pub(crate) fn open_bridge_for_benchmarks( - with: pallet_xcm_bridge_hub::LaneIdOf, - sibling_para_id: u32, -) -> InteriorLocation -where - R: pallet_xcm_bridge_hub::Config, - XBHI: 'static, - C: xcm_executor::traits::ConvertLocation< - bp_runtime::AccountIdOf>, - >, -{ - use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; - use sp_runtime::traits::Zero; - use xcm::{latest::WESTEND_GENESIS_HASH, VersionedInteriorLocation}; - - // insert bridge metadata - let lane_id = with; - let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); - let universal_source = - [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(sibling_para_id)].into(); - let universal_destination = - [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(2075)].into(); - let bridge_id = BridgeId::new(&universal_source, &universal_destination); - - // insert only bridge metadata, because the benchmarks create lanes - pallet_xcm_bridge_hub::Bridges::::insert( - bridge_id, - Bridge { - bridge_origin_relative_location: alloc::boxed::Box::new( - sibling_parachain.clone().into(), - ), - bridge_origin_universal_location: alloc::boxed::Box::new( - VersionedInteriorLocation::from(universal_source.clone()), - ), - bridge_destination_universal_location: alloc::boxed::Box::new( - VersionedInteriorLocation::from(universal_destination), - ), - state: BridgeState::Opened, - bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), - deposit: Zero::zero(), - lane_id, - }, - ); - pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); - - universal_source + // 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< + Runtime, + XcmOverBridgeHubRococoInstance, + ReportBridgeStatusXcmProvider, + XcmRouter, + >; + // 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< + XcmRouter, + UniversalLocation, + BridgeWestendToRococoMessagesPalletInstance, + >, + // 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, + >; + type CongestionLimits = (); } #[cfg(test)] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs index 69ba9ca9ece7..6dee7463c218 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs @@ -33,7 +33,12 @@ fn bridge_hub_westend_genesis( id: ParaId, bridges_pallet_owner: Option, asset_hub_para_id: ParaId, - opened_bridges: Vec<(Location, InteriorLocation, Option)>, + opened_bridges: Vec<( + Location, + InteriorLocation, + Option, + Option, + )>, ) -> serde_json::Value { build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { @@ -88,6 +93,7 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option bridge_hub_westend_genesis( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 065400016791..1998058938a9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -161,6 +161,10 @@ pub type Migrations = ( RocksDbWeight, >, pallet_bridge_relayers::migration::v1::MigrationToV1, + pallet_xcm_bridge_hub::migration::v1::MigrationToV1< + Runtime, + bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, + >, snowbridge_pallet_system::migration::v0::InitializeOnUpgrade< Runtime, ConstU32, @@ -616,6 +620,7 @@ mod benches { [pallet_bridge_grandpa, RococoFinality] [pallet_bridge_parachains, WithinRococo] [pallet_bridge_messages, WestendToRococo] + [pallet_xcm_bridge_hub, OverRococo] // Ethereum Bridge [snowbridge_pallet_inbound_queue, EthereumInboundQueue] [snowbridge_pallet_outbound_queue, EthereumOutboundQueue] @@ -948,6 +953,7 @@ impl_runtime_apis! { type RococoFinality = BridgeRococoGrandpa; type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; type WestendToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + type OverRococo = pallet_xcm_bridge_hub::benchmarking::Pallet::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1143,30 +1149,16 @@ impl_runtime_apis! { BenchmarkError::Stop("XcmVersion was not stored!") })?; - let sibling_parachain_location = Location::new(1, [Parachain(5678)]); - - // fund SA - use frame_support::traits::fungible::Mutate; - use xcm_executor::traits::ConvertLocation; - frame_support::assert_ok!( - Balances::mint_into( - &xcm_config::LocationToAccountId::convert_location(&sibling_parachain_location).expect("valid AccountId"), - bridge_to_rococo_config::BridgeDeposit::get() - .saturating_add(ExistentialDeposit::get()) - .saturating_add(UNITS * 5) - ) - ); - // open bridge + let sibling_parachain_location = Location::new(1, [Parachain(5678)]); let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(8765)].into(); - let locations = XcmOverBridgeHubRococo::bridge_locations( + let _ = XcmOverBridgeHubRococo::open_bridge_for_benchmarks( + bp_messages::LegacyLaneId([1, 2, 3, 4]), sibling_parachain_location.clone(), bridge_destination_universal_location.clone(), - )?; - XcmOverBridgeHubRococo::do_open_bridge( - locations, - bp_messages::LegacyLaneId([1, 2, 3, 4]), true, + None, + || ExistentialDeposit::get(), ).map_err(|e| { log::error!( "Failed to `XcmOverBridgeHubRococo::open_bridge`({:?}, {:?})`, error: {:?}", @@ -1197,6 +1189,7 @@ impl_runtime_apis! { type RococoFinality = BridgeRococoGrandpa; type WithinRococo = pallet_bridge_parachains::benchmarking::Pallet::; type WestendToRococo = pallet_bridge_messages::benchmarking::Pallet ::; + type OverRococo = pallet_xcm_bridge_hub::benchmarking::Pallet::; use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_parachain, @@ -1209,6 +1202,12 @@ impl_runtime_apis! { MessageProofParams, }; + impl pallet_xcm_bridge_hub::benchmarking::Config for Runtime { + fn open_bridge_origin() -> Option<(RuntimeOrigin, Balance)> { + None + } + } + impl BridgeMessagesConfig for Runtime { fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { let bench_lane_id = >::bench_lane_id(); @@ -1230,26 +1229,34 @@ impl_runtime_apis! { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - let universal_source = bridge_to_rococo_config::open_bridge_for_benchmarks::< - Runtime, - bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, - xcm_config::LocationToAccountId, - >(params.lane, 42); + let bridge_locations = XcmOverBridgeHubRococo::open_bridge_for_benchmarks( + params.lane, + Location::new(1, [Parachain(42)]), + [GlobalConsensus(bridge_to_rococo_config::RococoGlobalConsensusNetwork::get()), Parachain(2075)].into(), + // do not create lanes, because they are already created `params.lane` + false, + None, + || ExistentialDeposit::get(), + ).expect("valid bridge opened"); prepare_message_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample(universal_source)) + >(params, generate_xcm_builder_bridge_message_sample(bridge_locations.bridge_origin_universal_location().clone())) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams>, ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { - let _ = bridge_to_rococo_config::open_bridge_for_benchmarks::< - Runtime, - bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, - xcm_config::LocationToAccountId, - >(params.lane, 42); + let _ = XcmOverBridgeHubRococo::open_bridge_for_benchmarks( + params.lane, + Location::new(1, [Parachain(42)]), + [GlobalConsensus(bridge_to_rococo_config::RococoGlobalConsensusNetwork::get()), Parachain(2075)].into(), + // do not create lanes, because they are already created `params.lane` + false, + None, + || ExistentialDeposit::get(), + ); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs index c1c5c337aca8..952a97f9d12d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -41,6 +41,7 @@ pub mod pallet_timestamp; pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; +pub mod pallet_xcm_bridge_hub; pub mod paritydb_weights; pub mod rocksdb_weights; pub mod xcm; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs index 492226d3ec2b..b16f00706657 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -53,21 +53,23 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `701` - // Estimated: `52674` - // Minimum execution time: 62_015_000 picoseconds. - Weight::from_parts(63_891_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `765` + // Estimated: `52645` + // Minimum execution time: 61_826_000 picoseconds. + Weight::from_parts(65_518_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -75,24 +77,26 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `701` - // Estimated: `52674` - // Minimum execution time: 62_034_000 picoseconds. - Weight::from_parts(63_355_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 8_231 - .saturating_add(Weight::from_parts(14_096_117, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `765` + // Estimated: `52645` + // Minimum execution time: 62_597_000 picoseconds. + Weight::from_parts(64_453_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 12_681 + .saturating_add(Weight::from_parts(12_812_446, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -100,21 +104,23 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `701` - // Estimated: `52674` - // Minimum execution time: 65_063_000 picoseconds. - Weight::from_parts(67_125_000, 0) - .saturating_add(Weight::from_parts(0, 52674)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `765` + // Estimated: `52645` + // Minimum execution time: 69_093_000 picoseconds. + Weight::from_parts(72_845_000, 0) + .saturating_add(Weight::from_parts(0, 52645)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -122,24 +128,26 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `701` - // Estimated: `52674` - // Minimum execution time: 58_688_000 picoseconds. - Weight::from_parts(61_404_716, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(2_249, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `765` + // Estimated: `52645` + // Minimum execution time: 60_938_000 picoseconds. + Weight::from_parts(65_548_162, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 21 + .saturating_add(Weight::from_parts(2_344, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -147,24 +155,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) - /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `710` - // Estimated: `5383` - // Minimum execution time: 53_123_000 picoseconds. - Weight::from_parts(54_417_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `642` + // Estimated: `5358` + // Minimum execution time: 51_254_000 picoseconds. + Weight::from_parts(52_130_000, 0) + .saturating_add(Weight::from_parts(0, 5358)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -173,24 +181,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `710` - // Estimated: `5383` - // Minimum execution time: 55_140_000 picoseconds. - Weight::from_parts(56_456_000, 0) - .saturating_add(Weight::from_parts(0, 5383)) + // Measured: `642` + // Estimated: `5358` + // Minimum execution time: 51_764_000 picoseconds. + Weight::from_parts(53_507_000, 0) + .saturating_add(Weight::from_parts(0, 5358)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -199,24 +207,24 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `710` - // Estimated: `6144` - // Minimum execution time: 60_415_000 picoseconds. - Weight::from_parts(62_057_000, 0) - .saturating_add(Weight::from_parts(0, 6144)) + // Measured: `642` + // Estimated: `6086` + // Minimum execution time: 56_972_000 picoseconds. + Weight::from_parts(58_619_000, 0) + .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -225,11 +233,13 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -242,20 +252,18 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `965` - // Estimated: `52674` - // Minimum execution time: 84_340_000 picoseconds. - Weight::from_parts(89_615_003, 0) - .saturating_add(Weight::from_parts(0, 52674)) - // Standard Error: 15 - .saturating_add(Weight::from_parts(7_574, 0).saturating_mul(n.into())) + // Measured: `896` + // Estimated: `52645` + // Minimum execution time: 85_043_000 picoseconds. + Weight::from_parts(89_141_726, 0) + .saturating_add(Weight::from_parts(0, 52645)) + // Standard Error: 14 + .saturating_add(Weight::from_parts(7_597, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm_bridge_hub.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm_bridge_hub.rs new file mode 100644 index 000000000000..dec909a57015 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm_bridge_hub.rs @@ -0,0 +1,81 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +//! Autogenerated weights for `pallet_xcm_bridge_hub` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm_bridge_hub +// --chain=bridge-hub-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_xcm_bridge_hub`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_bridge_hub::WeightInfo for WeightInfo { + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn open_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn close_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_notification_receiver() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 6434f6206fbe..f9d1152e6f9e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 70_353_000 picoseconds. - Weight::from_parts(72_257_000, 6196) + // Minimum execution time: 73_953_000 picoseconds. + Weight::from_parts(77_340_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,15 +77,26 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 996_000 picoseconds. - Weight::from_parts(1_027_000, 0) + // Minimum execution time: 1_087_000 picoseconds. + Weight::from_parts(1_144_000, 0) } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 3_908_000 picoseconds. + Weight::from_parts(4_071_000, 3593) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + pub fn set_asset_claimer() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_926_000 picoseconds. - Weight::from_parts(2_033_000, 0) + // Minimum execution time: 1_066_000 picoseconds. + Weight::from_parts(1_121_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -93,58 +104,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_961_000 picoseconds. - Weight::from_parts(8_256_000, 3497) + // Minimum execution time: 8_100_000 picoseconds. + Weight::from_parts(8_237_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_589_000 picoseconds. - Weight::from_parts(7_867_000, 0) + // Minimum execution time: 7_861_000 picoseconds. + Weight::from_parts(8_196_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_602_000 picoseconds. - Weight::from_parts(1_660_000, 0) + // Minimum execution time: 1_757_000 picoseconds. + Weight::from_parts(1_841_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_056_000 picoseconds. - Weight::from_parts(1_096_000, 0) + // Minimum execution time: 1_057_000 picoseconds. + Weight::from_parts(1_123_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_014_000 picoseconds. - Weight::from_parts(1_075_000, 0) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_119_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 986_000 picoseconds. - Weight::from_parts(1_031_000, 0) + // Minimum execution time: 1_030_000 picoseconds. + Weight::from_parts(1_102_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_015_000 picoseconds. - Weight::from_parts(1_069_000, 0) + // Minimum execution time: 1_052_000 picoseconds. + Weight::from_parts(1_138_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 993_000 picoseconds. - Weight::from_parts(1_063_000, 0) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_169_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -166,8 +177,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 66_350_000 picoseconds. - Weight::from_parts(68_248_000, 6196) + // Minimum execution time: 69_990_000 picoseconds. + Weight::from_parts(72_086_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -177,8 +188,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_247_000 picoseconds. - Weight::from_parts(11_468_000, 3555) + // Minimum execution time: 11_270_000 picoseconds. + Weight::from_parts(11_624_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +197,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_060_000 picoseconds. - Weight::from_parts(1_103_000, 0) + // Minimum execution time: 1_025_000 picoseconds. + Weight::from_parts(1_112_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -207,8 +218,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_599_000 picoseconds. - Weight::from_parts(26_336_000, 3503) + // Minimum execution time: 25_768_000 picoseconds. + Weight::from_parts(26_467_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -218,44 +229,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_863_000 picoseconds. - Weight::from_parts(3_090_000, 0) + // Minimum execution time: 3_020_000 picoseconds. + Weight::from_parts(3_199_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_385_000 picoseconds. - Weight::from_parts(1_468_000, 0) + // Minimum execution time: 1_533_000 picoseconds. + Weight::from_parts(1_598_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_087_000 picoseconds. - Weight::from_parts(1_164_000, 0) + // Minimum execution time: 1_109_000 picoseconds. + Weight::from_parts(1_181_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_022_000 picoseconds. - Weight::from_parts(1_066_000, 0) + // Minimum execution time: 1_062_000 picoseconds. + Weight::from_parts(1_121_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_015_000 picoseconds. - Weight::from_parts(1_070_000, 0) + // Minimum execution time: 1_094_000 picoseconds. + Weight::from_parts(1_120_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_203_000 picoseconds. - Weight::from_parts(1_241_000, 0) + // Minimum execution time: 1_254_000 picoseconds. + Weight::from_parts(1_327_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -277,8 +288,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 70_773_000 picoseconds. - Weight::from_parts(72_730_000, 6196) + // Minimum execution time: 75_152_000 picoseconds. + Weight::from_parts(77_164_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -286,8 +297,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_173_000 picoseconds. - Weight::from_parts(4_445_000, 0) + // Minimum execution time: 4_454_000 picoseconds. + Weight::from_parts(4_613_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -309,8 +320,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 66_471_000 picoseconds. - Weight::from_parts(68_362_000, 6196) + // Minimum execution time: 70_387_000 picoseconds. + Weight::from_parts(71_863_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -318,44 +329,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_067_000 picoseconds. - Weight::from_parts(1_108_000, 0) + // Minimum execution time: 1_108_000 picoseconds. + Weight::from_parts(1_150_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 997_000 picoseconds. - Weight::from_parts(1_043_000, 0) + // Minimum execution time: 1_051_000 picoseconds. + Weight::from_parts(1_108_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_056_000, 0) + // Minimum execution time: 1_041_000 picoseconds. + Weight::from_parts(1_110_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + // Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1893), added: 4368, mode: `MaxEncodedLen`) // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - // Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) - // Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `225` - // Estimated: `6165` - // Minimum execution time: 43_316_000 picoseconds. - Weight::from_parts(45_220_843, 6165) - // Standard Error: 169 - .saturating_add(Weight::from_parts(44_459, 0).saturating_mul(x.into())) + // Measured: `595` + // Estimated: `6535` + // Minimum execution time: 56_987_000 picoseconds. + Weight::from_parts(58_914_389, 6535) + // Standard Error: 154 + .saturating_add(Weight::from_parts(52_548, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -363,22 +374,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 998_000 picoseconds. - Weight::from_parts(1_054_000, 0) + // Minimum execution time: 1_019_000 picoseconds. + Weight::from_parts(1_090_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 995_000 picoseconds. - Weight::from_parts(1_060_000, 0) - } - pub fn set_asset_claimer() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 707_000 picoseconds. - Weight::from_parts(749_000, 0) + // Minimum execution time: 1_053_000 picoseconds. + Weight::from_parts(1_112_000, 0) } pub fn execute_with_origin() -> Weight { // Proof Size summary in bytes: diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 69301b34fe6b..8698c9bc935b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -249,7 +249,7 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { |locations, fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubRococoInstance - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, fee, LegacyLaneId([0, 0, 0, 1]), None) } ).1 }, @@ -311,7 +311,7 @@ fn relayed_incoming_message_works() { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubRococoInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, fee, LegacyLaneId([0, 0, 0, 1]), None) }, ) .1 @@ -345,7 +345,7 @@ fn free_relay_extrinsic_works() { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubRococoInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, fee, LegacyLaneId([0, 0, 0, 1]), None) }, ) .1 diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index aac60bba0b53..35e81c2cdc23 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -471,6 +471,7 @@ pub fn open_bridge_with_extrinsic( bridge_destination_universal_location: Box::new( locations.bridge_destination_universal_location().clone().into(), ), + maybe_notify: None, }); // execute XCM as source origin would do with `Transact -> Origin::Xcm` @@ -488,6 +489,7 @@ pub fn open_bridge_with_storage( locations: BridgeLocations, _buy_execution_fee: Asset, lane_id: pallet_xcm_bridge_hub::LaneIdOf, + maybe_notify: Option, ) where Runtime: pallet_xcm_bridge_hub::Config, XcmOverBridgePalletInstance: 'static, @@ -497,7 +499,8 @@ pub fn open_bridge_with_storage( pallet_xcm_bridge_hub::Pallet::::do_open_bridge( Box::new(locations), lane_id, - true + true, + maybe_notify, ) ); } 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 ad6db0b83e80..2b8ea84bc861 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 @@ -681,11 +681,15 @@ pub fn open_and_close_bridge_works>::AllowWithoutBridgeDeposit::contains( locations.bridge_origin_relative_location() ) { - Zero::zero() + None } else { - >::BridgeDeposit::get() + >>::BridgeDeposit::get(); + + Some(bp_xcm_bridge_hub::Deposit::new(bridge_owner_account, deposit)) }; // check bridge/lane DOES not exist @@ -735,11 +739,9 @@ pub fn open_and_close_bridge_works