diff --git a/Cargo.lock b/Cargo.lock index 72fa4a8e2bc7..5598a2099842 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1883,6 +1883,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "rococo-westend-system-emulated-network", + "sp-runtime", "staging-xcm", "staging-xcm-executor", ] @@ -2048,6 +2049,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "rococo-westend-system-emulated-network", + "sp-runtime", "staging-xcm", "staging-xcm-executor", ] diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs index 0159ede64813..53c0579c4cd0 100644 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -309,6 +309,28 @@ impl LocalXcmQueueManager { } } +/// Adapter for the implementation of `GetVersion`, which attempts to find the minimal +/// configured XCM version between the destination `dest` and the bridge hub location provided as +/// `Get`. +pub struct XcmVersionOfDestAndRemoteBridge( + sp_std::marker::PhantomData<(Version, RemoteBridge)>, +); +impl> GetVersion + for XcmVersionOfDestAndRemoteBridge +{ + fn get_version_for(dest: &MultiLocation) -> Option { + let dest_version = Version::get_version_for(dest); + let bridge_hub_version = Version::get_version_for(&RemoteBridge::get()); + + match (dest_version, bridge_hub_version) { + (Some(dv), Some(bhv)) => Some(sp_std::cmp::min(dv, bhv)), + (Some(dv), None) => Some(dv), + (None, Some(bhv)) => Some(bhv), + (None, None) => None, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index c4d1e3971e74..922e4bf94ba8 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -21,7 +21,7 @@ use crate::{Bridge, Call}; use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR}; -use frame_benchmarking::benchmarks_instance_pallet; +use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; use sp_runtime::traits::Zero; use xcm::prelude::*; @@ -37,11 +37,11 @@ pub trait Config: crate::Config { /// 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() -> MultiLocation { - MultiLocation::new( + fn ensure_bridged_target_destination() -> Result { + Ok(MultiLocation::new( Self::UniversalLocation::get().len() as u8, X1(GlobalConsensus(Self::BridgedNetworkId::get().unwrap())), - ) + )) } } @@ -61,7 +61,7 @@ benchmarks_instance_pallet! { delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, }); - let _ = T::ensure_bridged_target_destination(); + let _ = T::ensure_bridged_target_destination()?; T::make_congested(); }: { crate::Pallet::::on_initialize(Zero::zero()) @@ -81,7 +81,7 @@ benchmarks_instance_pallet! { } send_message { - let dest = T::ensure_bridged_target_destination(); + let dest = T::ensure_bridged_target_destination()?; let xcm = sp_std::vec![].into(); // make local queue congested, because it means additional db write diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index cf51ef82412f..229628aedcb8 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -89,6 +89,8 @@ pub mod pallet { /// **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; /// Origin of the sibling bridge hub that is allowed to report bridge status. type BridgeHubOrigin: EnsureOrigin; @@ -319,12 +321,13 @@ impl, I: 'static> SendXcm for Pallet { dest: &mut Option, xcm: &mut Option>, ) -> SendResult { - // we won't have an access to `dest` and `xcm` in the `delvier` method, so precompute + // `dest` and `xcm` are required here + let dest_ref = dest.as_ref().ok_or(SendError::MissingArgument)?; + let xcm_ref = xcm.as_ref().ok_or(SendError::MissingArgument)?; + + // we won't have an access to `dest` and `xcm` in the `deliver` method, so precompute // everything required here - let message_size = xcm - .as_ref() - .map(|xcm| xcm.encoded_size() as _) - .ok_or(SendError::MissingArgument)?; + let message_size = xcm_ref.encoded_size() as _; // bridge doesn't support oversized/overweight messages now. So it is better to drop such // messages here than at the bridge hub. Let's check the message size. @@ -332,6 +335,18 @@ impl, I: 'static> SendXcm for Pallet { 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 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., to avoid losing funds). + let destination_version = T::DestinationVersion::get_version_for(dest_ref) + .ok_or(SendError::DestinationUnsupported)?; + let _ = VersionedXcm::from(xcm_ref.clone()) + .into_version(destination_version) + .map_err(|()| SendError::DestinationUnsupported)?; + // just use exporter to validate destination and insert instructions to pay message fee // at the sibling/child bridge hub // @@ -358,6 +373,7 @@ impl, I: 'static> SendXcm for Pallet { #[cfg(test)] mod tests { use super::*; + use frame_support::assert_ok; use mock::*; use frame_support::traits::Hooks; @@ -451,6 +467,19 @@ mod tests { }); } + #[test] + fn destination_unsupported_if_wrap_version_fails() { + run_test(|| { + assert_eq!( + send_xcm::( + UnknownXcmVersionLocation::get(), + vec![ClearOrigin].into(), + ), + Err(SendError::DestinationUnsupported), + ); + }); + } + #[test] fn returns_proper_delivery_price() { run_test(|| { @@ -488,17 +517,14 @@ mod tests { fn sent_message_doesnt_increase_factor_if_xcm_channel_is_uncongested() { run_test(|| { let old_bridge = XcmBridgeHubRouter::bridge(); - assert_eq!( - send_xcm::( - MultiLocation::new( - 2, - X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) - ), - vec![ClearOrigin].into(), - ) - .map(drop), - Ok(()), - ); + assert_ok!(send_xcm::( + MultiLocation::new( + 2, + X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) + ), + vec![ClearOrigin].into(), + ) + .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); @@ -511,17 +537,14 @@ mod tests { TestWithBridgeHubChannel::make_congested(); let old_bridge = XcmBridgeHubRouter::bridge(); - assert_eq!( - send_xcm::( - MultiLocation::new( - 2, - X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) - ), - vec![ClearOrigin].into(), - ) - .map(drop), - Ok(()), - ); + assert_ok!(send_xcm::( + MultiLocation::new( + 2, + X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) + ), + vec![ClearOrigin].into(), + ) + .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); assert!( @@ -536,17 +559,14 @@ mod tests { Bridge::::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)); let old_bridge = XcmBridgeHubRouter::bridge(); - assert_eq!( - send_xcm::( - MultiLocation::new( - 2, - X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) - ), - vec![ClearOrigin].into(), - ) - .map(drop), - Ok(()), - ); + assert_ok!(send_xcm::( + MultiLocation::new( + 2, + X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) + ), + vec![ClearOrigin].into(), + ) + .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); assert!( diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 2d173ebc0457..9079f4b9c4c6 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -19,7 +19,10 @@ use crate as pallet_xcm_bridge_hub_router; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; -use frame_support::{construct_runtime, derive_impl, parameter_types}; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{Contains, Equals}, +}; use frame_system::EnsureRoot; use sp_runtime::{traits::ConstU128, BuildStorage}; use xcm::prelude::*; @@ -58,6 +61,7 @@ parameter_types! { Some((BridgeFeeAsset::get(), BASE_FEE).into()) ) ]; + pub UnknownXcmVersionLocation: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(9999))); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] @@ -71,6 +75,8 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type UniversalLocation = UniversalLocation; type BridgedNetworkId = BridgedNetworkId; type Bridges = NetworkExportTable; + type DestinationVersion = + LatestOrNoneForLocationVersionChecker>; type BridgeHubOrigin = EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; @@ -80,6 +86,18 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type FeeAsset = BridgeFeeAsset; } +pub struct LatestOrNoneForLocationVersionChecker(sp_std::marker::PhantomData); +impl> GetVersion + for LatestOrNoneForLocationVersionChecker +{ + fn get_version_for(dest: &MultiLocation) -> Option { + if Location::contains(dest) { + return None + } + Some(XCM_VERSION) + } +} + pub struct TestToBridgeHubSender; impl TestToBridgeHubSender { diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 445551d69343..5318b222c545 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -33,7 +33,8 @@ use xcm_executor::traits::ExportXcm; /// An easy way to access `HaulBlobExporter`. pub type PalletAsHaulBlobExporter = HaulBlobExporter< DummyHaulBlob, - >::BridgedNetworkId, + >::BridgedNetwork, + >::DestinationVersion, >::MessageExportPrice, >; /// An easy way to access associated messages pallet. diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 14439a4d8ffe..44f6903b018b 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -37,6 +37,7 @@ pub mod pallet { use super::*; use bridge_runtime_common::messages_xcm_extension::SenderAndLane; use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] #[pallet::disable_frame_system_supertrait_check] @@ -48,15 +49,17 @@ pub mod pallet { // TODO: https://github.com/paritytech/parity-bridges-common/issues/1666 remove `ChainId` and // replace it with the `NetworkId` - then we'll be able to use // `T as pallet_bridge_messages::Config::BridgedChain::NetworkId` - /// Bridged network id. + /// Bridged network as relative location of bridged `GlobalConsensus`. #[pallet::constant] - type BridgedNetworkId: Get; + type BridgedNetwork: Get; /// Associated messages pallet instance that bridges us with the /// `BridgedNetworkId` consensus. type BridgeMessagesPalletInstance: 'static; /// Price of single message export to the bridged consensus (`Self::BridgedNetworkId`). type MessageExportPrice: Get; + /// Checks the XCM version for the destination. + type DestinationVersion: GetVersion; /// Get point-to-point links with bridged consensus (`Self::BridgedNetworkId`). /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) @@ -69,6 +72,17 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + fn integrity_test() { + assert!( + Self::bridged_network_id().is_some(), + "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", + T::BridgedNetwork::get() + ) + } + } + impl, I: 'static> Pallet { /// Returns dedicated/configured lane identifier. pub(crate) fn lane_for( @@ -83,7 +97,7 @@ pub mod pallet { .find_map(|(lane_source, (lane_dest_network, lane_dest))| { if lane_source.location == source && &lane_dest_network == dest.0 && - &T::BridgedNetworkId::get() == dest.0 && + Self::bridged_network_id().as_ref() == Some(dest.0) && &lane_dest == dest.1 { Some(lane_source) @@ -92,5 +106,13 @@ pub mod pallet { } }) } + + /// Returns some `NetworkId` if contains `GlobalConsensus` junction. + fn bridged_network_id() -> Option { + match T::BridgedNetwork::get().take_first_interior() { + Some(GlobalConsensus(network)) => Some(network), + _ => None, + } + } } } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 7766aac1fb73..8edd4b1f7aa9 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -170,6 +170,10 @@ impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights { parameter_types! { pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; + pub const BridgedRelayNetworkLocation: MultiLocation = MultiLocation { + parents: 1, + interior: X1(GlobalConsensus(BridgedRelayNetwork::get())) + }; pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; pub const BridgeReserve: Balance = 100_000; pub UniversalLocation: InteriorMultiLocation = X2( @@ -181,10 +185,12 @@ parameter_types! { impl pallet_xcm_bridge_hub::Config for TestRuntime { type UniversalLocation = UniversalLocation; - type BridgedNetworkId = BridgedRelayNetwork; + type BridgedNetwork = BridgedRelayNetworkLocation; type BridgeMessagesPalletInstance = (); type MessageExportPrice = (); + type DestinationVersion = AlwaysLatest; + type Lanes = TestLanes; type LanesSupport = TestXcmBlobHauler; } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 877edceae326..05454a2e5736 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -21,8 +21,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -55,3 +55,4 @@ impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, Rococo); +impl_xcm_helpers_for_parachain!(AssetHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 1c017c63c6fe..56382fad5641 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -21,8 +21,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -55,3 +55,4 @@ impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, Westend); +impl_xcm_helpers_for_parachain!(AssetHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index 8e5b29e65616..8162823dfceb 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; // BridgeHubRococo Parachain declaration @@ -47,3 +47,4 @@ decl_test_parachains! { // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +impl_xcm_helpers_for_parachain!(BridgeHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index a774f31b0fbc..c996b8045e7e 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; // BridgeHubWestend Parachain declaration @@ -47,3 +47,4 @@ decl_test_parachains! { // BridgeHubWestend implementation impl_accounts_helpers_for_parachain!(BridgeHubWestend); impl_assert_events_helpers_for_parachain!(BridgeHubWestend); +impl_xcm_helpers_for_parachain!(BridgeHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 768784ac0670..42b5847d17c4 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -38,7 +38,7 @@ pub use polkadot_runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, }; pub use xcm::{ - prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm}, + prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm, XcmVersion}, v3::Error, DoubleEncoded, }; @@ -173,10 +173,14 @@ macro_rules! impl_accounts_helpers_for_relay_chain { pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { ::execute_with(|| { for account in accounts { + let who = account.0; + let actual = ]>::Balances::free_balance(&who); + let actual = actual.saturating_add(]>::Balances::reserved_balance(&who)); + $crate::impls::assert_ok!(]>::Balances::force_set_balance( ::RuntimeOrigin::root(), - account.0.into(), - account.1, + who.into(), + actual.saturating_add(account.1), )); } }); @@ -386,15 +390,26 @@ macro_rules! impl_accounts_helpers_for_parachain { pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { ::execute_with(|| { for account in accounts { + let who = account.0; + let actual = ]>::Balances::free_balance(&who); + let actual = actual.saturating_add(]>::Balances::reserved_balance(&who)); + $crate::impls::assert_ok!(]>::Balances::force_set_balance( ::RuntimeOrigin::root(), - account.0.into(), - account.1, + who.into(), + actual.saturating_add(account.1), )); } }); } + /// Fund a sovereign account of sibling para. + pub fn fund_para_sovereign(sibling_para_id: $crate::impls::ParaId, balance: $crate::impls::Balance) { + let sibling_location = Self::sibling_location_of(sibling_para_id); + let sovereign_account = Self::sovereign_account_id_of(sibling_location); + Self::fund_accounts(vec![(sovereign_account.into(), balance)]) + } + /// Return local sovereign account of `para_id` on other `network_id` pub fn sovereign_account_of_parachain_on_other_global_consensus( network_id: $crate::impls::NetworkId, @@ -790,3 +805,33 @@ macro_rules! impl_foreign_assets_helpers_for_parachain { } }; } + +#[macro_export] +macro_rules! impl_xcm_helpers_for_parachain { + ( $chain:ident ) => { + $crate::impls::paste::paste! { + impl $chain { + /// Set XCM version for destination. + pub fn force_xcm_version(dest: $crate::impls::MultiLocation, version: $crate::impls::XcmVersion) { + ::execute_with(|| { + $crate::impls::assert_ok!(]>::PolkadotXcm::force_xcm_version( + ::RuntimeOrigin::root(), + $crate::impls::bx!(dest), + version, + )); + }); + } + + /// Set default/safe XCM version for runtime. + pub fn force_default_xcm_version(version: Option<$crate::impls::XcmVersion>) { + ::execute_with(|| { + $crate::impls::assert_ok!(]>::PolkadotXcm::force_default_xcm_version( + ::RuntimeOrigin::root(), + version, + )); + }); + } + } + } + } +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 826b55507ed3..4f33505f9a70 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -15,6 +15,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 53665437887c..4ae2c6cc9025 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -14,10 +14,12 @@ // limitations under the License. // Substrate -pub use frame_support::assert_ok; +pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; +pub use sp_runtime::DispatchError; // Polkadot pub use xcm::{ + latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, v3::{ Error, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index c55613f2826f..5a2111a9be94 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -13,70 +13,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: MultiLocation, amount: u128) { - let signed_origin = - ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); - let asset_hub_westend_para_id = AssetHubWestend::para_id().into(); - let destination = MultiLocation { - parents: 2, - interior: X2(GlobalConsensus(NetworkId::Westend), Parachain(asset_hub_westend_para_id)), - }; - let beneficiary_id = AssetHubWestendReceiver::get(); - let beneficiary: MultiLocation = - AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); - let assets: MultiAssets = (id, amount).into(); - let fee_asset_item = 0; + let destination = asset_hub_westend_location(); // fund the AHR's SA on BHR for paying bridge transport fees - let ahr_as_seen_by_bhr = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); - let sov_ahr_on_bhr = BridgeHubRococo::sovereign_account_id_of(ahr_as_seen_by_bhr); - BridgeHubRococo::fund_accounts(vec![(sov_ahr_on_bhr.into(), 10_000_000_000_000u128)]); - - AssetHubRococo::execute_with(|| { - assert_ok!( - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ) - ); - }); + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubRococo, - vec![ - // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, - // message exported - RuntimeEvent::BridgeWestendMessages( - pallet_bridge_messages::Event::MessageAccepted { .. } - ) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubWestend, - vec![ - // message dispatched successfully - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }); + // set XCM versions + AssetHubRococo::force_xcm_version(destination, XCM_VERSION); + BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + + // send message over bridge + assert_ok!(send_asset_from_asset_hub_rococo(destination, (id, amount))); + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); } #[test] 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 4e2ef1434fdf..d102dd2e5d69 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 @@ -13,6 +13,102 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::*; + mod asset_transfers; mod send_xcm; mod teleport; + +pub(crate) fn asset_hub_westend_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Westend), + Parachain(AssetHubWestend::para_id().into()), + ), + } +} + +pub(crate) fn bridge_hub_westend_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Westend), + Parachain(BridgeHubWestend::para_id().into()), + ), + } +} + +pub(crate) fn send_asset_from_asset_hub_rococo( + destination: MultiLocation, + (id, amount): (MultiLocation, u128), +) -> DispatchResult { + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); + + let assets: MultiAssets = (id, amount).into(); + let fee_asset_item = 0; + + AssetHubRococo::execute_with(|| { + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + }) +} + +pub(crate) fn assert_bridge_hub_rococo_message_accepted(expected_processed: bool) { + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + if expected_processed { + assert_expected_events!( + BridgeHubRococo, + vec![ + // pay for bridge fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + // message exported + RuntimeEvent::BridgeWestendMessages( + pallet_bridge_messages::Event::MessageAccepted { .. } + ) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } else { + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { + success: false, + .. + }) => {}, + ] + ); + } + }); +} + +pub(crate) fn assert_bridge_hub_westend_message_received() { + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWestend, + vec![ + // message sent to destination + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }) +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index b31a17034b9f..a3a7d96a14ae 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; #[test] fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable() { @@ -55,17 +55,123 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable }); // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have // opened bridge/lane. - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + assert_bridge_hub_rococo_message_accepted(false); +} + +#[test] +fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { + // Initially set only default version on all runtimes + AssetHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + AssetHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + + // prepare data + let destination = asset_hub_westend_location(); + let native_token = MultiLocation::parent(); + let amount = ASSET_HUB_ROCOCO_ED * 1_000; + + // fund the AHR's SA on BHR for paying bridge transport fees + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); + // fund sender + AssetHubRococo::fund_accounts(vec![(AssetHubRococoSender::get().into(), amount * 10)]); + + // send XCM from AssetHubRococo - fails - destination version not known + assert_err!( + send_asset_from_asset_hub_rococo(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + + // set destination version + AssetHubRococo::force_xcm_version(destination, xcm::v3::prelude::XCM_VERSION); + + // TODO: remove this block, when removing `xcm:v2` + { + // send XCM from AssetHubRococo - fails - AssetHubRococo is set to the default/safe `2` + // version, which does not have the `ExportMessage` instruction. If the default `2` is + // changed to `3`, then this assert can go away" + assert_err!( + send_asset_from_asset_hub_rococo(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + // set exact version for BridgeHubWestend to `2` without `ExportMessage` instruction + AssetHubRococo::force_xcm_version( + ParentThen(Parachain(BridgeHubRococo::para_id().into()).into()).into(), + xcm::v2::prelude::XCM_VERSION, + ); + // send XCM from AssetHubRococo - fails - `ExportMessage` is not in `2` + assert_err!( + send_asset_from_asset_hub_rococo(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + } + + // set version with `ExportMessage` for BridgeHubRococo + AssetHubRococo::force_xcm_version( + ParentThen(Parachain(BridgeHubRococo::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + // send XCM from AssetHubRococo - ok + assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount))); + + // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known + assert_bridge_hub_rococo_message_accepted(false); + + // set version for remote BridgeHub on BridgeHubRococo + BridgeHubRococo::force_xcm_version( + bridge_hub_westend_location(), + xcm::v3::prelude::XCM_VERSION, + ); + // set version for AssetHubWestend on BridgeHubWestend + BridgeHubWestend::force_xcm_version( + ParentThen(Parachain(AssetHubWestend::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubRococo - ok + assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount))); + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + // message delivered and processed at destination + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - BridgeHubRococo, + AssetHubWestend, vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: false, - .. - }) => {}, + // message processed with failure, but for this scenario it is ok, important is that was delivered + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: false, .. } + ) => {}, ] ); }); + + // TODO: remove this block, when removing `xcm:v2` + { + // set `2` version for remote BridgeHub on BridgeHubRococo, which does not have + // `UniversalOrigin` and `DescendOrigin` + BridgeHubRococo::force_xcm_version( + bridge_hub_westend_location(), + xcm::v2::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubRococo - ok + assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount))); + // message is not accepted on the local BridgeHub (`DestinationUnsupported`) because we + // cannot add `UniversalOrigin` and `DescendOrigin` + assert_bridge_hub_rococo_message_accepted(false); + } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index cb53d7fc0e1c..00cf54b6541d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -15,6 +15,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 04746aa86705..90a11d38f777 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -14,10 +14,12 @@ // limitations under the License. // Substrate -pub use frame_support::assert_ok; +pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; +pub use sp_runtime::DispatchError; // Polkadot pub use xcm::{ + latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, v3::{ Error, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index f90514f80c3e..21f4b4ee2356 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -12,70 +12,22 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; fn send_asset_from_asset_hub_westend_to_asset_hub_rococo(id: MultiLocation, amount: u128) { - let signed_origin = - ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); - let asset_hub_rococo_para_id = AssetHubRococo::para_id().into(); - let destination = MultiLocation { - parents: 2, - interior: X2(GlobalConsensus(NetworkId::Rococo), Parachain(asset_hub_rococo_para_id)), - }; - let beneficiary_id = AssetHubRococoReceiver::get(); - let beneficiary: MultiLocation = - AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); - let assets: MultiAssets = (id, amount).into(); - let fee_asset_item = 0; + let destination = asset_hub_rococo_location(); // fund the AHW's SA on BHW for paying bridge transport fees - let ahw_as_seen_by_bhw = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()); - let sov_ahw_on_bhw = BridgeHubWestend::sovereign_account_id_of(ahw_as_seen_by_bhw); - BridgeHubWestend::fund_accounts(vec![(sov_ahw_on_bhw.into(), 10_000_000_000_000u128)]); - - AssetHubWestend::execute_with(|| { - assert_ok!( - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ) - ); - }); + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubWestend, - vec![ - // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, - // message exported - RuntimeEvent::BridgeRococoMessages( - pallet_bridge_messages::Event::MessageAccepted { .. } - ) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubRococo, - vec![ - // message dispatched successfully - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }); + // set XCM versions + AssetHubWestend::force_xcm_version(destination, XCM_VERSION); + BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + + // send message over bridge + assert_ok!(send_asset_from_asset_hub_westend(destination, (id, amount))); + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); } #[test] 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 4e2ef1434fdf..ec2e68fc8894 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 @@ -13,6 +13,102 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::*; + mod asset_transfers; mod send_xcm; mod teleport; + +pub(crate) fn asset_hub_rococo_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Rococo), + Parachain(AssetHubRococo::para_id().into()), + ), + } +} + +pub(crate) fn bridge_hub_rococo_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Rococo), + Parachain(BridgeHubRococo::para_id().into()), + ), + } +} + +pub(crate) fn send_asset_from_asset_hub_westend( + destination: MultiLocation, + (id, amount): (MultiLocation, u128), +) -> DispatchResult { + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); + + let assets: MultiAssets = (id, amount).into(); + let fee_asset_item = 0; + + AssetHubWestend::execute_with(|| { + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + }) +} + +pub(crate) fn assert_bridge_hub_westend_message_accepted(expected_processed: bool) { + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + if expected_processed { + assert_expected_events!( + BridgeHubWestend, + vec![ + // pay for bridge fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + // message exported + RuntimeEvent::BridgeRococoMessages( + pallet_bridge_messages::Event::MessageAccepted { .. } + ) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } else { + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { + success: false, + .. + }) => {}, + ] + ); + } + }); +} + +pub(crate) fn assert_bridge_hub_rococo_message_received() { + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubRococo, + vec![ + // message sent to destination + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }) +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index f5c2ac3677fb..0773cbb05992 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; #[test] fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable() { @@ -55,17 +55,123 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable }); // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have // opened bridge/lane. - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + assert_bridge_hub_westend_message_accepted(false); +} + +#[test] +fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { + // Initially set only default version on all runtimes + AssetHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + AssetHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + + // prepare data + let destination = asset_hub_rococo_location(); + let native_token = MultiLocation::parent(); + let amount = ASSET_HUB_WESTEND_ED * 1_000; + + // fund the AHR's SA on BHR for paying bridge transport fees + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); + // fund sender + AssetHubWestend::fund_accounts(vec![(AssetHubWestendSender::get().into(), amount * 10)]); + + // send XCM from AssetHubWestend - fails - destination version not known + assert_err!( + send_asset_from_asset_hub_westend(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + + // set destination version + AssetHubWestend::force_xcm_version(destination, xcm::v3::prelude::XCM_VERSION); + + // TODO: remove this block, when removing `xcm:v2` + { + // send XCM from AssetHubRococo - fails - AssetHubRococo is set to the default/safe `2` + // version, which does not have the `ExportMessage` instruction. If the default `2` is + // changed to `3`, then this assert can go away" + assert_err!( + send_asset_from_asset_hub_westend(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + // set exact version for BridgeHubWestend to `2` without `ExportMessage` instruction + AssetHubWestend::force_xcm_version( + ParentThen(Parachain(BridgeHubWestend::para_id().into()).into()).into(), + xcm::v2::prelude::XCM_VERSION, + ); + // send XCM from AssetHubWestend - fails - `ExportMessage` is not in `2` + assert_err!( + send_asset_from_asset_hub_westend(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + } + + // set version with `ExportMessage` for BridgeHubWestend + AssetHubWestend::force_xcm_version( + ParentThen(Parachain(BridgeHubWestend::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + // send XCM from AssetHubWestend - ok + assert_ok!(send_asset_from_asset_hub_westend(destination, (native_token, amount))); + + // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known + assert_bridge_hub_westend_message_accepted(false); + + // set version for remote BridgeHub on BridgeHubWestend + BridgeHubWestend::force_xcm_version( + bridge_hub_rococo_location(), + xcm::v3::prelude::XCM_VERSION, + ); + // set version for AssetHubRococo on BridgeHubRococo + BridgeHubRococo::force_xcm_version( + ParentThen(Parachain(AssetHubRococo::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubWestend - ok + assert_ok!(send_asset_from_asset_hub_westend(destination, (native_token, amount))); + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + // message delivered and processed at destination + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - BridgeHubWestend, + AssetHubRococo, vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: false, - .. - }) => {}, + // message processed with failure, but for this scenario it is ok, important is that was delivered + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: false, .. } + ) => {}, ] ); }); + + // TODO: remove this block, when removing `xcm:v2` + { + // set `2` version for remote BridgeHub on BridgeHubRococo, which does not have + // `UniversalOrigin` and `DescendOrigin` + BridgeHubWestend::force_xcm_version( + bridge_hub_rococo_location(), + xcm::v2::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubWestend - ok + assert_ok!(send_asset_from_asset_hub_westend(destination, (native_token, amount))); + // message is not accepted on the local BridgeHub (`DestinationUnsupported`) because we + // cannot add `UniversalOrigin` and `DescendOrigin` + assert_bridge_hub_westend_message_accepted(false); + } } 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 86000a20b5b9..5bddebf6b0eb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -846,6 +846,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; + type DestinationVersion = PolkadotXcm; #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; @@ -1416,11 +1417,26 @@ impl_runtime_apis! { xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); } - fn ensure_bridged_target_destination() -> MultiLocation { + fn ensure_bridged_target_destination() -> Result { ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); - xcm_config::bridging::to_westend::AssetHubWestend::get() + let bridged_asset_hub = xcm_config::bridging::to_westend::AssetHubWestend::get(); + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridged_asset_hub), + 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) } } @@ -1439,7 +1455,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; 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 7e12453583d4..aeaaed454525 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 4.0.0-dev -//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-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: @@ -58,8 +58,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `154` // Estimated: `1639` - // Minimum execution time: 7_924_000 picoseconds. - Weight::from_parts(8_199_000, 0) + // Minimum execution time: 8_110_000 picoseconds. + Weight::from_parts(8_373_000, 0) .saturating_add(Weight::from_parts(0, 1639)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +72,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `1629` - // Minimum execution time: 4_265_000 picoseconds. - Weight::from_parts(4_417_000, 0) + // Minimum execution time: 4_459_000 picoseconds. + Weight::from_parts(4_663_000, 0) .saturating_add(Weight::from_parts(0, 1629)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,12 +83,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` - // Minimum execution time: 10_292_000 picoseconds. - Weight::from_parts(10_797_000, 0) + // Minimum execution time: 10_153_000 picoseconds. + Weight::from_parts(10_737_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) @@ -99,8 +101,6 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) @@ -115,12 +115,12 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send_message() -> Weight { // Proof Size summary in bytes: - // Measured: `387` - // Estimated: `3852` - // Minimum execution time: 61_995_000 picoseconds. - Weight::from_parts(65_137_000, 0) - .saturating_add(Weight::from_parts(0, 3852)) - .saturating_add(T::DbWeight::get().reads(11)) + // Measured: `448` + // Estimated: `6388` + // Minimum execution time: 61_258_000 picoseconds. + Weight::from_parts(63_679_000, 0) + .saturating_add(Weight::from_parts(0, 6388)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } 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 7bb71a77de7d..030a3723319b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -673,9 +673,16 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works( mod asset_hub_rococo_tests { use super::*; + use asset_hub_rococo_runtime::{PolkadotXcm, RuntimeOrigin}; fn bridging_to_asset_hub_westend() -> TestBridgingConfig { - asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridging::to_westend::AssetHubWestend::get()), + XCM_VERSION, + ) + .expect("version saved!"); + TestBridgingConfig { bridged_network: bridging::to_westend::WestendNetwork::get(), local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), local_bridge_hub_location: bridging::SiblingBridgeHub::get(), 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 6709a20b275e..6956e9b78c94 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -822,6 +822,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; + type DestinationVersion = PolkadotXcm; #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; @@ -1493,11 +1494,26 @@ impl_runtime_apis! { xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); } - fn ensure_bridged_target_destination() -> MultiLocation { + fn ensure_bridged_target_destination() -> Result { ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); - xcm_config::bridging::to_rococo::AssetHubRococo::get() + let bridged_asset_hub = xcm_config::bridging::to_rococo::AssetHubRococo::get(); + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridged_asset_hub), + 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) } } 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 9d0d0cbc6555..ee8d0ae3c45c 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 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-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,8 +48,8 @@ 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::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) @@ -58,22 +58,22 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `193` // Estimated: `1678` - // Minimum execution time: 8_157_000 picoseconds. - Weight::from_parts(8_481_000, 0) + // Minimum execution time: 8_460_000 picoseconds. + Weight::from_parts(8_730_000, 0) .saturating_add(Weight::from_parts(0, 1678)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: // Measured: `111` // Estimated: `1596` - // Minimum execution time: 3_319_000 picoseconds. - Weight::from_parts(3_445_000, 0) + // Minimum execution time: 3_469_000 picoseconds. + Weight::from_parts(3_696_000, 0) .saturating_add(Weight::from_parts(0, 1596)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,22 +83,24 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `117` // Estimated: `1502` - // Minimum execution time: 10_396_000 picoseconds. - Weight::from_parts(10_914_000, 0) + // Minimum execution time: 10_315_000 picoseconds. + Weight::from_parts(10_651_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) @@ -107,18 +109,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// 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`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send_message() -> Weight { // Proof Size summary in bytes: - // Measured: `426` - // Estimated: `3891` - // Minimum execution time: 45_902_000 picoseconds. - Weight::from_parts(46_887_000, 0) - .saturating_add(Weight::from_parts(0, 3891)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `487` + // Estimated: `6427` + // Minimum execution time: 64_532_000 picoseconds. + Weight::from_parts(66_901_000, 0) + .saturating_add(Weight::from_parts(0, 6427)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } 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 7922b04e8077..0aaf1d91879a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -24,9 +24,9 @@ use asset_hub_westend_runtime::{ WestendLocation, XcmConfig, }, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, ToRococoXcmRouterInstance, TrustBackedAssetsInstance, - XcmpQueue, + ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, + PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, @@ -635,6 +635,12 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p ); fn bridging_to_asset_hub_rococo() -> TestBridgingConfig { + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridging::to_rococo::AssetHubRococo::get()), + XCM_VERSION, + ) + .expect("version saved!"); TestBridgingConfig { bridged_network: bridging::to_rococo::RococoNetwork::get(), local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), 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 ec9b2646c883..546b032e4f20 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -20,7 +20,7 @@ use crate::{ bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, weights, xcm_config::UniversalLocation, - AccountId, BridgeWestendMessages, Runtime, RuntimeEvent, RuntimeOrigin, + AccountId, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeOrigin, XcmOverBridgeHubWestend, XcmRouter, }; use bp_messages::LaneId; @@ -33,7 +33,7 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, + XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, @@ -58,6 +58,10 @@ parameter_types! { pub const BridgeHubWestendChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WESTEND_CHAIN_ID; pub BridgeRococoToWestendMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; + pub WestendGlobalConsensusNetworkLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(WestendGlobalConsensusNetwork::get())) + }; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; @@ -80,6 +84,14 @@ parameter_types! { pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); + + pub BridgeHubWestendLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(WestendGlobalConsensusNetwork::get()), + Parachain(::PARACHAIN_ID) + ) + }; } pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); @@ -120,7 +132,6 @@ pub struct ToBridgeHubWestendXcmBlobHauler; impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { type Runtime = Runtime; type MessagesInstance = WithBridgeHubWestendMessagesInstance; - type ToSourceChainSender = XcmRouter; type CongestedMessage = CongestedMessage; type UncongestedMessage = UncongestedMessage; @@ -234,9 +245,11 @@ impl pallet_bridge_messages::Config for Ru pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { type UniversalLocation = UniversalLocation; - type BridgedNetworkId = WestendGlobalConsensusNetwork; + type BridgedNetwork = WestendGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubWestendMessagesInstance; type MessageExportPrice = (); + type DestinationVersion = + XcmVersionOfDestAndRemoteBridge; type Lanes = ActiveLanes; type LanesSupport = ToBridgeHubWestendXcmBlobHauler; } 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 8bd5c196016a..8c24d8687b49 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 @@ -853,7 +853,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; @@ -933,6 +933,21 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { + // save XCM version for remote bridge hub + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridge_to_westend_config::BridgeHubWestendLocation::get()), + XCM_VERSION, + ).map_err(|e| { + log::error!( + "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", + RuntimeOrigin::root(), + bridge_to_westend_config::BridgeHubWestendLocation::get(), + XCM_VERSION, + e + ); + BenchmarkError::Stop("XcmVersion was not stored!") + })?; Ok( ( bridge_to_westend_config::FromAssetHubRococoToAssetHubWestendRoute::get().location, 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 0ae6d0b5623f..606e47457d21 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 4.0.0-dev -//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-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: 63_453_000 picoseconds. - Weight::from_parts(64_220_000, 6196) + // Minimum execution time: 61_049_000 picoseconds. + Weight::from_parts(62_672_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_238_000 picoseconds. - Weight::from_parts(2_351_000, 0) + // Minimum execution time: 1_972_000 picoseconds. + Weight::from_parts(2_095_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_953_000 picoseconds. - Weight::from_parts(8_162_000, 3497) + // Minimum execution time: 7_541_000 picoseconds. + Weight::from_parts(7_875_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: 9_080_000 picoseconds. - Weight::from_parts(9_333_000, 0) + // Minimum execution time: 8_467_000 picoseconds. + Weight::from_parts(8_653_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_415_000 picoseconds. - Weight::from_parts(2_519_000, 0) + // Minimum execution time: 2_141_000 picoseconds. + Weight::from_parts(2_231_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_045_000 picoseconds. - Weight::from_parts(2_184_000, 0) + // Minimum execution time: 1_881_000 picoseconds. + Weight::from_parts(1_941_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_065_000 picoseconds. - Weight::from_parts(2_125_000, 0) + // Minimum execution time: 1_846_000 picoseconds. + Weight::from_parts(1_916_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_077_000 picoseconds. - Weight::from_parts(2_164_000, 0) + // Minimum execution time: 1_857_000 picoseconds. + Weight::from_parts(1_910_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_868_000 picoseconds. - Weight::from_parts(2_933_000, 0) + // Minimum execution time: 2_493_000 picoseconds. + Weight::from_parts(2_570_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_058_000 picoseconds. - Weight::from_parts(2_164_000, 0) + // Minimum execution time: 1_857_000 picoseconds. + Weight::from_parts(1_930_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 55_971_000 picoseconds. - Weight::from_parts(56_869_000, 6196) + // Minimum execution time: 54_805_000 picoseconds. + Weight::from_parts(55_690_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_382_000 picoseconds. - Weight::from_parts(11_672_000, 3555) + // Minimum execution time: 11_062_000 picoseconds. + Weight::from_parts(11_505_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_071_000 picoseconds. - Weight::from_parts(2_193_000, 0) + // Minimum execution time: 1_873_000 picoseconds. + Weight::from_parts(1_962_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 22_573_000 picoseconds. - Weight::from_parts(23_423_000, 3503) + // Minimum execution time: 22_356_000 picoseconds. + Weight::from_parts(23_066_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_870_000 picoseconds. - Weight::from_parts(3_993_000, 0) + // Minimum execution time: 3_819_000 picoseconds. + Weight::from_parts(3_992_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: 3_483_000 picoseconds. - Weight::from_parts(3_598_000, 0) + // Minimum execution time: 3_033_000 picoseconds. + Weight::from_parts(3_157_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_241_000 picoseconds. - Weight::from_parts(2_297_000, 0) + // Minimum execution time: 1_994_000 picoseconds. + Weight::from_parts(2_056_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_230_000 picoseconds. - Weight::from_parts(2_318_000, 0) + // Minimum execution time: 1_978_000 picoseconds. + Weight::from_parts(2_069_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_051_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 1_894_000 picoseconds. + Weight::from_parts(1_977_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_306_000 picoseconds. - Weight::from_parts(2_380_000, 0) + // Minimum execution time: 2_114_000 picoseconds. + Weight::from_parts(2_223_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 60_201_000 picoseconds. - Weight::from_parts(61_132_000, 6196) + // Minimum execution time: 58_704_000 picoseconds. + Weight::from_parts(59_677_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_554_000 picoseconds. - Weight::from_parts(4_704_000, 0) + // Minimum execution time: 4_506_000 picoseconds. + Weight::from_parts(4_672_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_071_000 picoseconds. - Weight::from_parts(56_889_000, 6196) + // Minimum execution time: 54_896_000 picoseconds. + Weight::from_parts(56_331_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,25 +311,29 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_093_000 picoseconds. - Weight::from_parts(2_169_000, 0) + // Minimum execution time: 1_946_000 picoseconds. + Weight::from_parts(2_002_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_027_000 picoseconds. - Weight::from_parts(2_172_000, 0) + // Minimum execution time: 1_898_000 picoseconds. + Weight::from_parts(1_961_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_035_000 picoseconds. - Weight::from_parts(2_164_000, 0) + // Minimum execution time: 1_895_000 picoseconds. + Weight::from_parts(1_964_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: `PolkadotXcm::SupportedVersion` (r:2 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // 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) @@ -341,27 +345,27 @@ impl WeightInfo { /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `96` - // Estimated: `1529` - // Minimum execution time: 25_636_000 picoseconds. - Weight::from_parts(25_405_640, 1529) - // Standard Error: 321 - .saturating_add(Weight::from_parts(365_002, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `190` + // Estimated: `6130` + // Minimum execution time: 36_547_000 picoseconds. + Weight::from_parts(37_623_117, 6130) + // Standard Error: 735 + .saturating_add(Weight::from_parts(315_274, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_036_000 picoseconds. - Weight::from_parts(2_136_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(1_910_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_147_000 picoseconds. - Weight::from_parts(2_276_000, 0) + // Minimum execution time: 1_998_000 picoseconds. + Weight::from_parts(2_069_000, 0) } } 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 c1af369cdf80..1d544a9dcfa2 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 @@ -21,11 +21,11 @@ use bridge_hub_rococo_runtime::{ bridge_common_config, bridge_to_westend_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - TransactionPayment, UncheckedExtrinsic, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use codec::{Decode, Encode}; -use frame_support::{dispatch::GetDispatchInfo, parameter_types}; +use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; use frame_system::pallet_prelude::HeaderFor; use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; @@ -104,8 +104,9 @@ mod bridge_hub_rococo_tests { RequiredStakeForStakeAndSlash, }; use bridge_to_westend_config::{ - BridgeHubWestendChainId, WestendGlobalConsensusNetwork, WithBridgeHubWestendMessageBridge, - WithBridgeHubWestendMessagesInstance, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + BridgeHubWestendChainId, BridgeHubWestendLocation, WestendGlobalConsensusNetwork, + WithBridgeHubWestendMessageBridge, WithBridgeHubWestendMessagesInstance, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, }; bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( @@ -196,7 +197,7 @@ mod bridge_hub_rococo_tests { Some((TokenLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((TokenLocation::get(), bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), - || (), + || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubWestendLocation::get()), XCM_VERSION).expect("version saved!"), ) } @@ -211,6 +212,7 @@ mod bridge_hub_rococo_tests { WithBridgeHubWestendMessagesInstance, RelayNetwork, WestendGlobalConsensusNetwork, + ConstU8<2>, >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, 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 3b773947b471..eb5493872b40 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 @@ -18,8 +18,8 @@ use crate::{ bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, - AccountId, BridgeRococoMessages, Runtime, RuntimeEvent, RuntimeOrigin, XcmOverBridgeHubRococo, - XcmRouter, + AccountId, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeOrigin, + XcmOverBridgeHubRococo, XcmRouter, }; use bp_messages::LaneId; use bp_parachains::SingleParaStoredHeaderDataBuilder; @@ -32,7 +32,7 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, + XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, @@ -65,6 +65,10 @@ parameter_types! { pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; pub BridgeWestendToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; + pub RococoGlobalConsensusNetworkLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(RococoGlobalConsensusNetwork::get())) + }; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; @@ -87,6 +91,14 @@ parameter_types! { pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); + + pub BridgeHubRococoLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(RococoGlobalConsensusNetwork::get()), + Parachain(::PARACHAIN_ID) + ) + }; } pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); @@ -260,9 +272,10 @@ impl pallet_bridge_messages::Config for Run pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { type UniversalLocation = UniversalLocation; - type BridgedNetworkId = RococoGlobalConsensusNetwork; + type BridgedNetwork = RococoGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance; type MessageExportPrice = (); + type DestinationVersion = XcmVersionOfDestAndRemoteBridge; type Lanes = ActiveLanes; type LanesSupport = ToBridgeHubRococoXcmBlobHauler; } 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 07e664d67be6..a11456b07ca8 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 @@ -922,6 +922,21 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { + // save XCM version for remote bridge hub + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridge_to_rococo_config::BridgeHubRococoLocation::get()), + XCM_VERSION, + ).map_err(|e| { + log::error!( + "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", + RuntimeOrigin::root(), + bridge_to_rococo_config::BridgeHubRococoLocation::get(), + XCM_VERSION, + e + ); + BenchmarkError::Stop("XcmVersion was not stored!") + })?; Ok( ( bridge_to_rococo_config::FromAssetHubWestendToAssetHubRococoRoute::get().location, 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 7c686190208f..8f2834034009 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,10 +17,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-r43aesjn-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 @@ -33,10 +33,10 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::generic -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt // --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,8 +48,6 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -68,81 +66,79 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 62_732_000 picoseconds. - Weight::from_parts(64_581_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 61_383_000 picoseconds. + Weight::from_parts(62_382_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_987_000 picoseconds. - Weight::from_parts(2_107_000, 0) + // Minimum execution time: 2_057_000 picoseconds. + Weight::from_parts(2_153_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn query_response() -> Weight { // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3568` - // Minimum execution time: 8_098_000 picoseconds. - Weight::from_parts(8_564_000, 3568) + // Measured: `32` + // Estimated: `3497` + // Minimum execution time: 7_949_000 picoseconds. + Weight::from_parts(8_250_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: 8_539_000 picoseconds. - Weight::from_parts(9_085_000, 0) + // Minimum execution time: 8_608_000 picoseconds. + Weight::from_parts(9_086_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_205_000 picoseconds. - Weight::from_parts(2_369_000, 0) + // Minimum execution time: 2_240_000 picoseconds. + Weight::from_parts(2_348_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_828_000 picoseconds. - Weight::from_parts(1_994_000, 0) + // Minimum execution time: 1_969_000 picoseconds. + Weight::from_parts(2_017_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(1_946_000, 0) + // Minimum execution time: 1_907_000 picoseconds. + Weight::from_parts(2_001_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_842_000 picoseconds. - Weight::from_parts(1_949_000, 0) + // Minimum execution time: 1_880_000 picoseconds. + Weight::from_parts(1_975_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_460_000 picoseconds. - Weight::from_parts(2_593_000, 0) + // Minimum execution time: 2_549_000 picoseconds. + Weight::from_parts(2_624_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 1_895_000 picoseconds. + Weight::from_parts(1_963_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -161,21 +157,21 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_813_000 picoseconds. - Weight::from_parts(57_728_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 54_447_000 picoseconds. + Weight::from_parts(55_629_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn claim_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `160` - // Estimated: `3625` - // Minimum execution time: 11_364_000 picoseconds. - Weight::from_parts(11_872_000, 3625) + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 11_597_000 picoseconds. + Weight::from_parts(11_809_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -183,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_821_000 picoseconds. - Weight::from_parts(1_936_000, 0) + // Minimum execution time: 1_895_000 picoseconds. + Weight::from_parts(1_977_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -202,10 +198,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 23_081_000 picoseconds. - Weight::from_parts(23_512_000, 3574) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 23_314_000 picoseconds. + Weight::from_parts(23_905_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -215,47 +211,45 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_747_000 picoseconds. - Weight::from_parts(4_068_000, 0) + // Minimum execution time: 3_948_000 picoseconds. + Weight::from_parts(4_084_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: 3_045_000 picoseconds. - Weight::from_parts(3_208_000, 0) + // Minimum execution time: 3_196_000 picoseconds. + Weight::from_parts(3_285_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_962_000 picoseconds. - Weight::from_parts(2_284_000, 0) + // Minimum execution time: 2_040_000 picoseconds. + Weight::from_parts(2_162_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_951_000 picoseconds. - Weight::from_parts(2_026_000, 0) + // Minimum execution time: 1_980_000 picoseconds. + Weight::from_parts(2_082_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_837_000 picoseconds. - Weight::from_parts(2_084_000, 0) + // Minimum execution time: 1_890_000 picoseconds. + Weight::from_parts(1_971_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_042_000 picoseconds. - Weight::from_parts(2_145_000, 0) + // Minimum execution time: 2_131_000 picoseconds. + Weight::from_parts(2_187_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -274,22 +268,20 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 61_350_000 picoseconds. - Weight::from_parts(62_440_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 59_548_000 picoseconds. + Weight::from_parts(60_842_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_993_000 picoseconds. - Weight::from_parts(5_309_000, 0) + // Minimum execution time: 4_665_000 picoseconds. + Weight::from_parts(4_844_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -308,70 +300,72 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 57_133_000 picoseconds. - Weight::from_parts(58_100_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 55_044_000 picoseconds. + Weight::from_parts(56_103_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_899_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 1_904_000 picoseconds. + Weight::from_parts(1_984_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_880_000 picoseconds. - Weight::from_parts(1_960_000, 0) + // Minimum execution time: 1_889_000 picoseconds. + Weight::from_parts(1_950_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_825_000 picoseconds. - Weight::from_parts(1_960_000, 0) + // Minimum execution time: 1_878_000 picoseconds. + Weight::from_parts(1_963_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - // Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoToWococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // 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`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) + // Proof: `BridgeRococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) + // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `139` - // Estimated: `3604` - // Minimum execution time: 28_419_000 picoseconds. - Weight::from_parts(29_387_791, 3604) - // Standard Error: 552 - .saturating_add(Weight::from_parts(316_277, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `188` + // Estimated: `6128` + // Minimum execution time: 36_960_000 picoseconds. + Weight::from_parts(38_104_333, 6128) + // Standard Error: 510 + .saturating_add(Weight::from_parts(316_499, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_903_000 picoseconds. - Weight::from_parts(2_023_000, 0) + // Minimum execution time: 1_833_000 picoseconds. + Weight::from_parts(1_950_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_963_000 picoseconds. - Weight::from_parts(2_143_000, 0) + // Minimum execution time: 1_980_000 picoseconds. + Weight::from_parts(2_065_000, 0) } } 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 822dc2340d40..73bddb16369f 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 @@ -22,16 +22,16 @@ use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - TransactionPayment, UncheckedExtrinsic, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ - BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeParachainRococoInstance, - WithBridgeHubRococoMessageBridge, WithBridgeHubRococoMessagesInstance, - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeHubRococoLocation, + BridgeParachainRococoInstance, WithBridgeHubRococoMessageBridge, + WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, }; use codec::{Decode, Encode}; -use frame_support::{dispatch::GetDispatchInfo, parameter_types}; +use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; use frame_system::pallet_prelude::HeaderFor; use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; @@ -184,7 +184,7 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { Some((WestendLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((WestendLocation::get(), bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()).into()), - || (), + || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubRococoLocation::get()), XCM_VERSION).expect("version saved!"), ) } @@ -198,6 +198,7 @@ fn message_dispatch_routing_works() { WithBridgeHubRococoMessagesInstance, RelayNetwork, bridge_to_rococo_config::RococoGlobalConsensusNetwork, + ConstU8<2>, >( collator_session_keys(), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs index fee95a382887..ddcba3b03990 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs @@ -55,7 +55,10 @@ use sp_runtime::{ traits::{Header as HeaderT, Zero}, AccountId32, }; -use xcm::latest::prelude::*; +use xcm::{ + latest::prelude::*, + prelude::{AlwaysLatest, GetVersion}, +}; use xcm_builder::DispatchBlobError; use xcm_executor::{ traits::{TransactAsset, WeightBounds}, @@ -258,6 +261,7 @@ pub fn message_dispatch_routing_works< MessagesPalletInstance, RuntimeNetwork, BridgedNetwork, + NetworkDistanceAsParentCount, >( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, @@ -291,13 +295,19 @@ pub fn message_dispatch_routing_works< HrmpChannelOpener: frame_support::inherent::ProvideInherent< Call = cumulus_pallet_parachain_system::Call, >, - // MessageDispatcher: MessageDispatch, DispatchLevelResult = - // XcmBlobMessageDispatchResult, DispatchPayload = XcmAsPlainPayload>, RuntimeNetwork: Get, BridgedNetwork: Get, + NetworkDistanceAsParentCount: Get, { assert_ne!(runtime_para_id, sibling_parachain_id); + struct NetworkWithParentCount(core::marker::PhantomData<(N, C)>); + impl, C: Get> Get for NetworkWithParentCount { + fn get() -> MultiLocation { + MultiLocation { parents: C::get(), interior: X1(GlobalConsensus(N::get())) } + } + } + ExtBuilder::::default() .with_collators(collator_session_key.collators()) .with_session_keys(collator_session_key.session_keys()) @@ -317,7 +327,11 @@ pub fn message_dispatch_routing_works< ); // 1. this message is sent from other global consensus with destination of this Runtime relay chain (UMP) let bridging_message = - test_data::simulate_message_exporter_on_bridged_chain::( + test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >( (RuntimeNetwork::get(), Here) ); let result = <>::MessageDispatch>::dispatch( @@ -335,7 +349,11 @@ pub fn message_dispatch_routing_works< // 2. this message is sent from other global consensus with destination of this Runtime sibling parachain (HRMP) let bridging_message = - test_data::simulate_message_exporter_on_bridged_chain::( + test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >( (RuntimeNetwork::get(), X1(Parachain(sibling_parachain_id))), ); @@ -1524,7 +1542,8 @@ pub mod test_data { /// which are transferred over bridge. pub(crate) fn simulate_message_exporter_on_bridged_chain< SourceNetwork: Get, - DestinationNetwork: Get, + DestinationNetwork: Get, + DestinationVersion: GetVersion, >( (destination_network, destination_junctions): (NetworkId, Junctions), ) -> Vec { @@ -1536,23 +1555,28 @@ pub mod test_data { let channel = 1_u32; // simulate XCM message export - let (ticket, fee) = - validate_export::>( - destination_network, - channel, - universal_source_on_bridged_chain, - destination_junctions, - dummy_xcm(), - ) - .expect("validate_export to pass"); + let (ticket, fee) = validate_export::< + HaulBlobExporter, + >( + destination_network, + channel, + universal_source_on_bridged_chain, + destination_junctions, + dummy_xcm(), + ) + .expect("validate_export to pass"); log::info!( target: "simulate_message_exporter_on_bridged_chain", "HaulBlobExporter::validate fee: {:?}", fee ); - let xcm_hash = - HaulBlobExporter::::deliver(ticket) - .expect("deliver to pass"); + let xcm_hash = HaulBlobExporter::< + GrabbingHaulBlob, + DestinationNetwork, + DestinationVersion, + (), + >::deliver(ticket) + .expect("deliver to pass"); log::info!( target: "simulate_message_exporter_on_bridged_chain", "HaulBlobExporter::deliver xcm_hash: {:?}", diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index e2a6fb45aec3..a8ae63b250a6 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -128,7 +128,7 @@ pub struct ExtBuilder< collators: Vec>, // keys added to pallet session keys: Vec<(AccountIdOf, ValidatorIdOf, SessionKeysOf)>, - // safe xcm version for pallet_xcm + // safe XCM version for pallet_xcm safe_xcm_version: Option, // para id para_id: Option, diff --git a/cumulus/scripts/bridges_common.sh b/cumulus/scripts/bridges_common.sh index 8d64c5ede52a..97ef8aa12595 100755 --- a/cumulus/scripts/bridges_common.sh +++ b/cumulus/scripts/bridges_common.sh @@ -187,23 +187,25 @@ function open_hrmp_channels() { ${max_message_size} } -function set_storage() { +function force_xcm_version() { local relay_url=$1 local relay_chain_seed=$2 local runtime_para_id=$3 local runtime_para_endpoint=$4 - local items=$5 - echo " calling set_storage:" + local dest=$5 + local xcm_version=$6 + echo " calling force_xcm_version:" echo " relay_url: ${relay_url}" echo " relay_chain_seed: ${relay_chain_seed}" echo " runtime_para_id: ${runtime_para_id}" echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " items: ${items}" + echo " dest: ${dest}" + echo " xcm_version: ${xcm_version}" echo " params:" - # 1. generate data for Transact (System::set_storage) + # 1. generate data for Transact (PolkadotXcm::force_xcm_version) local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "set-storage" "${runtime_para_endpoint}" "${tmp_output_file}" "$items" + generate_hex_encoded_call_data "force-xcm-version" "${runtime_para_endpoint}" "${tmp_output_file}" "$dest" "$xcm_version" local hex_encoded_data=$(cat $tmp_output_file) # 2. trigger governance call diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/cumulus/scripts/bridges_rococo_westend.sh index 9b3bd350276f..8bce141d39a1 100755 --- a/cumulus/scripts/bridges_rococo_westend.sh +++ b/cumulus/scripts/bridges_rococo_westend.sh @@ -129,6 +129,7 @@ ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXa ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5BhiSGP5h9RgQci1txJ2BDbp7KBRE9k8xty3BMUSi" LANE_ID="00000002" +XCM_VERSION=3 function init_ro_wnd() { ensure_relayer @@ -215,6 +216,14 @@ case "$1" in "ws://127.0.0.1:9942" \ "//Alice" \ 1013 1000 4 524288 + # set XCM version of remote AssetHubWestend + force_xcm_version \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9910" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } }')" \ + $XCM_VERSION ;; init-bridge-hub-rococo-local) ensure_polkadot_js_api @@ -236,6 +245,14 @@ case "$1" in "//Alice" \ "$ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain" \ $((1000000000000 + 2000000000000)) + # set XCM version of remote BridgeHubWestend + force_xcm_version \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1013 \ + "ws://127.0.0.1:8943" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1002 } ] } }')" \ + $XCM_VERSION ;; init-asset-hub-westend-local) ensure_polkadot_js_api @@ -264,6 +281,14 @@ case "$1" in "ws://127.0.0.1:9945" \ "//Alice" \ 1002 1000 4 524288 + # set XCM version of remote AssetHubRococo + force_xcm_version \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } }')" \ + $XCM_VERSION ;; init-bridge-hub-westend-local) # SA of sibling asset hub pays for the execution @@ -284,6 +309,14 @@ case "$1" in "//Alice" \ "$ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain" \ $((1000000000000000 + 2000000000000)) + # set XCM version of remote BridgeHubRococo + force_xcm_version \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1002 \ + "ws://127.0.0.1:8945" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1013 } ] } }')" \ + $XCM_VERSION ;; reserve-transfer-assets-from-asset-hub-rococo-local) ensure_polkadot_js_api diff --git a/cumulus/scripts/generate_hex_encoded_call/index.js b/cumulus/scripts/generate_hex_encoded_call/index.js index 09f0e6aaf619..30f89d754ceb 100644 --- a/cumulus/scripts/generate_hex_encoded_call/index.js +++ b/cumulus/scripts/generate_hex_encoded_call/index.js @@ -106,11 +106,11 @@ function forceCreateAsset(endpoint, outputFile, assetId, assetOwnerAccountId, is }); } -function setStorage(endpoint, outputFile, items) { - console.log(`Generating setStorage from RPC endpoint: ${endpoint} to outputFile: ${outputFile}, items: ${items}`); +function forceXcmVersion(endpoint, outputFile, dest, xcm_version) { + console.log(`Generating forceXcmVersion from RPC endpoint: ${endpoint} to outputFile: ${outputFile}, dest: ${dest}, xcm_version: ${xcm_version}`); connect(endpoint) .then((api) => { - const call = api.tx.system.setStorage(JSON.parse(items)); + const call = api.tx.polkadotXcm.forceXcmVersion(JSON.parse(dest), xcm_version); writeHexEncodedBytesToOutput(call.method, outputFile); exit(0); }) @@ -154,8 +154,8 @@ switch (type) { case 'force-create-asset': forceCreateAsset(rpcEnpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); break; - case 'set-storage': - setStorage(rpcEnpoint, output, inputArgs[0]); + case 'force-xcm-version': + forceXcmVersion(rpcEnpoint, output, inputArgs[0], inputArgs[1]); break; case 'check': console.log(`Checking nodejs installation, if you see this everything is ready!`); diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index ab4403f6caa4..2848527f1502 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -2591,7 +2591,7 @@ impl WrapVersion for Pallet { dest: &MultiLocation, xcm: impl Into>, ) -> Result, ()> { - SupportedVersion::::get(XCM_VERSION, LatestVersionedMultiLocation(dest)) + Self::get_version_for(dest) .or_else(|| { Self::note_unknown_version(dest); SafeXcmVersion::::get() @@ -2608,6 +2608,12 @@ impl WrapVersion for Pallet { } } +impl GetVersion for Pallet { + fn get_version_for(dest: &MultiLocation) -> Option { + SupportedVersion::::get(XCM_VERSION, LatestVersionedMultiLocation(dest)) + } +} + impl VersionChangeNotifier for Pallet { /// Start notifying `location` should the XCM version of this chain change. /// diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index e7f5870c9144..2443d3a9cac5 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -655,6 +655,17 @@ pub(crate) fn buy_limited_execution( pub(crate) fn new_test_ext_with_balances( balances: Vec<(AccountId, Balance)>, +) -> sp_io::TestExternalities { + new_test_ext_with_balances_and_xcm_version( + balances, + // By default set actual latest XCM version + Some(XCM_VERSION), + ) +} + +pub(crate) fn new_test_ext_with_balances_and_xcm_version( + balances: Vec<(AccountId, Balance)>, + safe_xcm_version: Option, ) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -662,7 +673,7 @@ pub(crate) fn new_test_ext_with_balances( .assimilate_storage(&mut t) .unwrap(); - pallet_xcm::GenesisConfig:: { safe_xcm_version: Some(2), ..Default::default() } + pallet_xcm::GenesisConfig:: { safe_xcm_version, ..Default::default() } .assimilate_storage(&mut t) .unwrap(); diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 5829eb6edec4..e7a6fdc9dced 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -774,12 +774,13 @@ fn subscription_side_upgrades_work_without_notify() { #[test] fn subscriber_side_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { + new_test_ext_with_balances_and_xcm_version(vec![], Some(XCM_VERSION)).execute_with(|| { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), Box::new(remote.into()), )); + assert_eq!(XcmPallet::get_version_for(&remote), None); take_sent_xcm(); // Assume subscription target is working ok. @@ -798,6 +799,7 @@ fn subscriber_side_subscription_works() { let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); assert_eq!(take_sent_xcm(), vec![]); + assert_eq!(XcmPallet::get_version_for(&remote), Some(1)); // This message cannot be sent to a v2 remote. let v2_msg = xcm::v2::Xcm::<()>(vec![xcm::v2::Instruction::Trap(0)]); @@ -815,6 +817,8 @@ fn subscriber_side_subscription_works() { let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); + assert_eq!(take_sent_xcm(), vec![]); + assert_eq!(XcmPallet::get_version_for(&remote), Some(2)); // This message can now be sent to remote as it's v2. assert_eq!( @@ -827,7 +831,7 @@ fn subscriber_side_subscription_works() { /// We should auto-subscribe when we don't know the remote's version. #[test] fn auto_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { + new_test_ext_with_balances_and_xcm_version(vec![], None).execute_with(|| { let remote_v2: MultiLocation = Parachain(1000).into(); let remote_v3: MultiLocation = Parachain(1001).into(); @@ -995,3 +999,68 @@ fn subscription_side_upgrades_work_with_multistage_notify() { ); }); } + +#[test] +fn get_and_wrap_version_works() { + new_test_ext_with_balances_and_xcm_version(vec![], None).execute_with(|| { + let remote_a: MultiLocation = Parachain(1000).into(); + let remote_b: MultiLocation = Parachain(1001).into(); + let remote_c: MultiLocation = Parachain(1002).into(); + + // no `safe_xcm_version` version at `GenesisConfig` + assert_eq!(XcmPallet::get_version_for(&remote_a), None); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![]); + + // set default XCM version (a.k.a. `safe_xcm_version`) + assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(1))); + assert_eq!(XcmPallet::get_version_for(&remote_a), None); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![]); + + // set XCM version only for `remote_a` + assert_ok!(XcmPallet::force_xcm_version( + RuntimeOrigin::root(), + Box::new(remote_a), + XCM_VERSION + )); + assert_eq!(XcmPallet::get_version_for(&remote_a), Some(XCM_VERSION)); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![]); + + let xcm = Xcm::<()>::default(); + + // wrap version - works because remote_a has `XCM_VERSION` + assert_eq!( + XcmPallet::wrap_version(&remote_a, xcm.clone()), + Ok(VersionedXcm::from(xcm.clone())) + ); + // does not work because remote_b has unknown version and default is set to 1, and + // `XCM_VERSION` cannot be wrapped to the `1` + assert_eq!(XcmPallet::wrap_version(&remote_b, xcm.clone()), Err(())); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![(remote_b.into(), 1)]); + + // set default to the `XCM_VERSION` + assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(XCM_VERSION))); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + + // now works, because default is `XCM_VERSION` + assert_eq!( + XcmPallet::wrap_version(&remote_b, xcm.clone()), + Ok(VersionedXcm::from(xcm.clone())) + ); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![(remote_b.into(), 2)]); + + // change remote_c to `1` + assert_ok!(XcmPallet::force_xcm_version(RuntimeOrigin::root(), Box::new(remote_c), 1)); + + // does not work because remote_c has `1` and default is `XCM_VERSION` which cannot be + // wrapped to the `1` + assert_eq!(XcmPallet::wrap_version(&remote_c, xcm.clone()), Err(())); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![(remote_b.into(), 2)]); + }) +} diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index d804e4bf7351..ddad0b5303be 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -373,6 +373,12 @@ pub trait WrapVersion { ) -> Result, ()>; } +/// Check and return the `Version` that should be used for the `Xcm` datum for the destination +/// `MultiLocation`, which will interpret it. +pub trait GetVersion { + fn get_version_for(dest: &latest::MultiLocation) -> Option; +} + /// `()` implementation does nothing with the XCM, just sending with whatever version it was /// authored as. impl WrapVersion for () { @@ -395,6 +401,11 @@ impl WrapVersion for AlwaysV2 { Ok(VersionedXcm::::V2(xcm.into().try_into()?)) } } +impl GetVersion for AlwaysV2 { + fn get_version_for(_dest: &latest::MultiLocation) -> Option { + Some(v2::VERSION) + } +} /// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before /// wrapping it. @@ -407,6 +418,11 @@ impl WrapVersion for AlwaysV3 { Ok(VersionedXcm::::V3(xcm.into().try_into()?)) } } +impl GetVersion for AlwaysV3 { + fn get_version_for(_dest: &latest::MultiLocation) -> Option { + Some(v3::VERSION) + } +} /// `WrapVersion` implementation which attempts to always convert the XCM to the latest version /// before wrapping it. @@ -418,8 +434,8 @@ pub type AlwaysLts = AlwaysV3; pub mod prelude { pub use super::{ - latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, IntoVersion, Unsupported, - Version as XcmVersion, VersionedAssetId, VersionedInteriorMultiLocation, + latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, GetVersion, IntoVersion, + Unsupported, Version as XcmVersion, VersionedAssetId, VersionedInteriorMultiLocation, VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, VersionedResponse, VersionedXcm, WrapVersion, }; diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs index de08dbee953a..b1361cc85777 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs @@ -23,11 +23,16 @@ use super::*; parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); + pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into(); } type TheBridge = TestBridge>; -type Router = - TestTopic, UniversalLocation>>; +type Router = TestTopic< + UnpaidLocalExporter< + HaulBlobExporter, + UniversalLocation, + >, +>; /// ```nocompile /// local | remote diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs index 8433b6e02129..5371abccf666 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs @@ -23,11 +23,16 @@ use super::*; parameter_types! { pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); + pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into(); } type TheBridge = TestBridge>; -type Router = - TestTopic, UniversalLocation>>; +type Router = TestTopic< + UnpaidLocalExporter< + HaulBlobExporter, + UniversalLocation, + >, +>; /// ```nocompile /// local | remote diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs index 45630dbfc248..0c749b66da61 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs @@ -20,6 +20,7 @@ use super::mock::*; use crate::{universal_exports::*, WithTopicSource}; use frame_support::{parameter_types, traits::Get}; use std::{cell::RefCell, marker::PhantomData}; +use xcm::AlwaysLatest; use xcm_executor::{ traits::{export_xcm, validate_export}, XcmExecutor, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 23d6eb99a909..079eb0175d71 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs @@ -30,6 +30,7 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); + pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -41,7 +42,7 @@ parameter_types! { } type TheBridge = TestBridge>; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = ExecutingRouter; type LocalBridgeRouter = SovereignPaidRemoteExporter< NetworkExportTable, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs index f11143ab9f6f..fb6c5da3eb01 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs @@ -24,6 +24,7 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000)); pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); + pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -36,7 +37,7 @@ parameter_types! { type TheBridge = TestBridge< BridgeBlobDispatcher, >; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = UnpaidExecutingRouter; type LocalBridgingRouter = diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs index 7218e0a04880..0b6dc01e2bf1 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs @@ -24,6 +24,7 @@ parameter_types! { pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); + pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -36,7 +37,7 @@ parameter_types! { type TheBridge = TestBridge< BridgeBlobDispatcher, >; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = UnpaidExecutingRouter; type LocalBridgingRouter = diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs index 45b5efbc44c5..e33c7b15b0af 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs @@ -24,6 +24,7 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); + pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -35,7 +36,7 @@ parameter_types! { } type TheBridge = TestBridge>; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = UnpaidExecutingRouter; type LocalBridgeRouter = diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 8e2cf88b3c32..4aa6a0ef7a50 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -422,11 +422,25 @@ impl< } } -pub struct HaulBlobExporter( - PhantomData<(Bridge, BridgedNetwork, Price)>, +pub struct HaulBlobExporter( + PhantomData<(Bridge, BridgedNetwork, DestinationVersion, Price)>, ); -impl, Price: Get> ExportXcm - for HaulBlobExporter +/// `ExportXcm` implementation for `HaulBlobExporter`. +/// +/// # Type Parameters +/// +/// ```text +/// - Bridge: Implements `HaulBlob`. +/// - BridgedNetwork: The relative location of the bridged consensus system with the expected `GlobalConsensus` junction. +/// - DestinationVersion: Implements `GetVersion` for retrieving XCM version for the destination. +/// - Price: potential fees for exporting. +/// ``` +impl< + Bridge: HaulBlob, + BridgedNetwork: Get, + DestinationVersion: GetVersion, + Price: Get, + > ExportXcm for HaulBlobExporter { type Ticket = (Vec, XcmHash); @@ -437,17 +451,35 @@ impl, Price: Get> destination: &mut Option, message: &mut Option>, ) -> Result<((Vec, XcmHash), MultiAssets), SendError> { - let bridged_network = BridgedNetwork::get(); + let (bridged_network, bridged_network_location_parents) = { + let MultiLocation { parents, interior: mut junctions } = BridgedNetwork::get(); + match junctions.take_first() { + Some(GlobalConsensus(network)) => (network, parents), + _ => return Err(SendError::NotApplicable), + } + }; ensure!(&network == &bridged_network, SendError::NotApplicable); // We don't/can't use the `channel` for this adapter. let dest = destination.take().ok_or(SendError::MissingArgument)?; - let universal_dest = match dest.pushed_front_with(GlobalConsensus(bridged_network)) { - Ok(d) => d.into(), - Err((dest, _)) => { - *destination = Some(dest); - return Err(SendError::NotApplicable) - }, - }; + + // Let's resolve the known/supported XCM version for the destination because we don't know + // if it supports the same/latest version. + let (universal_dest, version) = + match dest.pushed_front_with(GlobalConsensus(bridged_network)) { + Ok(d) => { + let version = DestinationVersion::get_version_for(&MultiLocation::from( + AncestorThen(bridged_network_location_parents, d), + )) + .ok_or(SendError::DestinationUnsupported)?; + (d, version) + }, + Err((dest, _)) => { + *destination = Some(dest); + return Err(SendError::NotApplicable) + }, + }; + + // Let's adjust XCM with `UniversalOrigin`, `DescendOrigin` and`SetTopic`. let (local_net, local_sub) = universal_source .take() .ok_or(SendError::MissingArgument)? @@ -462,7 +494,17 @@ impl, Price: Get> if local_sub != Here { message.0.insert(1, DescendOrigin(local_sub)); } - let message = VersionedXcm::from(message); + + // We cannot use the latest `Versioned` because we don't know if the target chain already + // supports the same version. Therefore, we better control the destination version with best + // efforts. + let message = VersionedXcm::from(message) + .into_version(version) + .map_err(|()| SendError::DestinationUnsupported)?; + let universal_dest = VersionedInteriorMultiLocation::from(universal_dest) + .into_version(version) + .map_err(|()| SendError::DestinationUnsupported)?; + let id = maybe_id.unwrap_or_else(|| message.using_encoded(sp_io::hashing::blake2_256)); let blob = BridgeMessage { universal_dest, message }.encode(); Ok(((blob, id), Price::get())) diff --git a/prdoc/pr_2481.prdoc b/prdoc/pr_2481.prdoc new file mode 100644 index 000000000000..d8736b1afd6e --- /dev/null +++ b/prdoc/pr_2481.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "xcm-builder: `HaulBlobExporter` with improved XCM version check." + +doc: + - audience: Runtime Dev + description: | + Version check in `HaulBlobExporter` uses new trait `CheckVersion` to check known/configured destination versions, + ensuring compatibility. `HaulBlobExporter` will attempt to downgrade the message to destination's known version + instead of using the latest version. + +crates: [ ]