diff --git a/Cargo.lock b/Cargo.lock index 2b82655a82652..eba58a53aae18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1175,6 +1175,9 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-test-utils", + "bp-asset-hub-rococo", + "bp-asset-hub-westend", + "bp-xcm-bridge", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", diff --git a/bridges/modules/xcm-bridge/src/lib.rs b/bridges/modules/xcm-bridge/src/lib.rs index c5a22557364dd..bc4506d119c20 100644 --- a/bridges/modules/xcm-bridge/src/lib.rs +++ b/bridges/modules/xcm-bridge/src/lib.rs @@ -670,6 +670,11 @@ pub mod pallet { .into()), } } + + /// Get the bridge deposit amount required to open a new bridge. + pub fn bridge_deposit() -> BalanceOf> { + T::BridgeDeposit::get() + } } #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 33d2506907a51..3985a6a975bc1 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -191,6 +191,11 @@ where // collect messages from `OutboundMessages` for each active outbound lane in the source for lane in active_outbound_lanes { + if OutboundLanes::::get(lane).is_none() { + // TODO: FAIL - investigate how was this created + continue; + } + let latest_generated_nonce = OutboundLanes::::get(lane).unwrap().latest_generated_nonce; let latest_received_nonce = diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs index 81fca403e704e..df62a64eb260e 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/src/lib.rs @@ -73,23 +73,9 @@ decl_test_bridges! { } } -type AssetHubRococoRuntime = ::Runtime; -type AssetHubWestendRuntime = ::Runtime; type BridgeHubRococoRuntime = ::Runtime; type BridgeHubWestendRuntime = ::Runtime; -pub type AssetHubRococoWestendMessageHandler = BridgeMessagesHandler< - AssetHubRococoRuntime, - BridgeMessagesInstance1, - AssetHubWestendRuntime, - BridgeMessagesInstance1, ->; -pub type AssetHubWestendRococoMessageHandler = BridgeMessagesHandler< - AssetHubWestendRuntime, - BridgeMessagesInstance1, - AssetHubRococoRuntime, - BridgeMessagesInstance1, ->; pub type RococoWestendMessageHandler = BridgeMessagesHandler< BridgeHubRococoRuntime, BridgeMessagesInstance3, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index a205ac50f8fd7..047961de0359a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -41,8 +41,12 @@ emulated-integration-tests-common = { workspace = true } parachains-common = { workspace = true, default-features = true } rococo-system-emulated-network = { workspace = true } westend-system-emulated-network = { workspace = true } +rococo-westend-system-emulated-network = { workspace = true } # Bridge +bp-asset-hub-westend = { workspace = true } +bp-asset-hub-rococo = { workspace = true } +bp-xcm-bridge = { workspace = true } pallet-xcm-bridge = { workspace = true } [dev-dependencies] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 0f02c6aa36ecb..7384e691b2cad 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -49,13 +49,6 @@ mod imports { PenpalATeleportableAssetLocation, ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, USDT_ID, XCM_V3, }; pub use parachains_common::{AccountId, Balance}; - pub use rococo_system_emulated_network::{ - asset_hub_rococo_emulated_chain::{ - genesis::AssetHubRococoUniversalLocation, - AssetHubRococoParaPallet as AssetHubRococoPallet, AssetHubRococoRuntimeOrigin, - }, - AssetHubRococoPara as AssetHubRococo, - }; pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ asset_hub_westend_runtime::{ @@ -67,11 +60,8 @@ mod imports { AssetConversionOrigin as AssetHubWestendAssetConversionOrigin, ExistentialDeposit as AssetHubWestendExistentialDeposit, }, - genesis::{ - AssetHubWestendAssetOwner, AssetHubWestendUniversalLocation, - ED as ASSET_HUB_WESTEND_ED, - }, - AssetHubWestendParaPallet as AssetHubWestendPallet, AssetHubWestendRuntimeOrigin, + genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, + AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_westend_emulated_chain::{ bridge_hub_westend_runtime::xcm_config::{self as bhw_xcm_config}, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/bridging.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/bridging.rs index bdbd4e1a71a48..4ea9aa80a6788 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/bridging.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/bridging.rs @@ -13,7 +13,35 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::imports::*; +use crate::imports::assert_ok; +pub use codec::Encode; +use emulated_integration_tests_common::{ + xcm_emulator::{bx, Chain, Parachain as Para, TestExt}, + xcm_helpers::xcm_transact_paid_execution, +}; +use xcm::{ + latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, + prelude::*, +}; + +// For a bridging we need rococo_westend system and not separated ones (because different Penpal setups). +use rococo_westend_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + asset_hub_rococo_runtime::ExistentialDeposit as AssetHubRococoExistentialDeposit, + genesis::AssetHubRococoUniversalLocation, AssetHubRococoParaPallet as AssetHubRococoPallet, + AssetHubRococoRuntimeOrigin, + }, + asset_hub_westend_emulated_chain::{ + asset_hub_westend_runtime::ExistentialDeposit as AssetHubWestendExistentialDeposit, + genesis::AssetHubWestendUniversalLocation, + AssetHubWestendParaPallet as AssetHubWestendPallet, AssetHubWestendRuntimeOrigin, + }, + penpal_emulated_chain::{ + PenpalAParaPallet as PenpalAPallet, PenpalBParaPallet as PenpalBPallet, + }, + AssetHubRococoPara as AssetHubRococo, AssetHubWestendPara as AssetHubWestend, + PenpalAPara as PenpalA, PenpalBPara as PenpalB, +}; #[test] fn ah_to_ah_open_close_bridge_works() { @@ -108,3 +136,136 @@ fn ah_to_ah_open_close_bridge_works() { }); assert!(rococo_bridge_pruned_lane_id.is_some(), "Rococo BridgePruned event not found"); } + +#[test] +fn para_to_para_open_close_bridge_works() { + // Ensure Penpal A/B locations (set `on_init` with `set_storage`). + let penpal_a_on_rococo_universal_location = PenpalA::execute_with(|| { + let loc = <::Runtime as pallet_xcm::Config>::UniversalLocation::get(); + assert_eq!(loc.global_consensus(), Ok(ByGenesis(ROCOCO_GENESIS_HASH))); + loc + }); + let penpal_b_on_westend_universal_location = PenpalB::execute_with(|| { + let loc = <::Runtime as pallet_xcm::Config>::UniversalLocation::get(); + assert_eq!(loc.global_consensus(), Ok(ByGenesis(WESTEND_GENESIS_HASH))); + loc + }); + + // 1. Open bridge from PenpalA(Rococo) to PenpalB(Westend) + let penpal_a_para_sovereign_account = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let fee_amount = AssetHubRococoExistentialDeposit::get() * 1000; + let bridge_deposit = AssetHubRococo::ext_wrapper(|| { + ::XcmOverAssetHubWestend::bridge_deposit() + }); + AssetHubRococo::fund_accounts(vec![( + penpal_a_para_sovereign_account.clone().into(), + AssetHubRococoExistentialDeposit::get() + fee_amount + bridge_deposit, + )]); + + // send paid XCM with `open_bridge` from PenpalA to the AssetHubRococo + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + ::RuntimeOrigin::root(), + bx!(PenpalA::sibling_location_of(AssetHubRococo::para_id()).into()), + bx!(xcm_transact_paid_execution( + bp_asset_hub_rococo::Call::XcmOverAssetHubWestend( + bp_xcm_bridge::XcmBridgeCall::open_bridge { + bridge_destination_universal_location: Box::new( + penpal_b_on_westend_universal_location.into() + ), + maybe_notify: None, + }, + ) + .encode() + .into(), + OriginKind::Xcm, + (Parent, fee_amount).into(), + penpal_a_para_sovereign_account, + )), + )); + + PenpalA::assert_xcm_pallet_sent(); + }); + + // check BridgeOpened event on AssetHubRococo + let penpal_a_bridge_opened_lane_id = AssetHubRococo::execute_with(|| { + let events = AssetHubRococo::events(); + type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcmp_queue_success(None); + let e = events.iter().find_map(|event| { + if let RuntimeEvent::XcmOverAssetHubWestend(pallet_xcm_bridge::Event::BridgeOpened { + lane_id, + .. + }) = event + { + Some(*lane_id) + } else { + None + } + }); + e + }); + assert!(penpal_a_bridge_opened_lane_id.is_some(), "PenpalA BridgeOpened event not found"); + + // 2. Open bridge from PenpalB(Westend) to PenpalA(Rococo) + let penpal_b_para_sovereign_account = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + let fee_amount = AssetHubWestendExistentialDeposit::get() * 1000; + let bridge_deposit = AssetHubWestend::ext_wrapper(|| { + ::XcmOverAssetHubRococo::bridge_deposit() + }); + AssetHubWestend::fund_accounts(vec![( + penpal_b_para_sovereign_account.clone().into(), + AssetHubWestendExistentialDeposit::get() + fee_amount + bridge_deposit, + )]); + + // send paid XCM with `open_bridge` from PenpalB to the AssetHubWestend + PenpalB::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + ::RuntimeOrigin::root(), + bx!(PenpalB::sibling_location_of(AssetHubWestend::para_id()).into()), + bx!(xcm_transact_paid_execution( + bp_asset_hub_westend::Call::XcmOverAssetHubRococo( + bp_xcm_bridge::XcmBridgeCall::open_bridge { + bridge_destination_universal_location: Box::new( + penpal_a_on_rococo_universal_location.into() + ), + maybe_notify: None, + }, + ) + .encode() + .into(), + OriginKind::Xcm, + (Parent, fee_amount).into(), + penpal_b_para_sovereign_account, + )), + )); + + PenpalB::assert_xcm_pallet_sent(); + }); + + // check BridgeOpened event on AssetHubWestend + let penpal_b_bridge_opened_lane_id = AssetHubWestend::execute_with(|| { + let events = AssetHubWestend::events(); + type RuntimeEvent = ::RuntimeEvent; + AssetHubWestend::assert_xcmp_queue_success(None); + events.iter().find_map(|event| { + if let RuntimeEvent::XcmOverAssetHubRococo(pallet_xcm_bridge::Event::BridgeOpened { + lane_id, + .. + }) = event + { + Some(*lane_id) + } else { + None + } + }) + }); + assert!(penpal_b_bridge_opened_lane_id.is_some(), "PenpalB BridgeOpened event not found"); + + // check the same lane ID is generated + assert_eq!(penpal_a_bridge_opened_lane_id, penpal_b_bridge_opened_lane_id); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/bridge-primitives/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/bridge-primitives/src/lib.rs index 527217c059ba5..aa2d6827b88a1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/bridge-primitives/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/bridge-primitives/src/lib.rs @@ -50,6 +50,9 @@ pub enum Call { /// `ToWestendXcmRouter` bridge pallet. #[codec(index = 45)] ToWestendXcmRouter(XcmBridgeHubCall), + /// Points to the `pallet_xcm_bridge` pallet instance for `AssetHubWestend`. + #[codec(index = 61)] + XcmOverAssetHubWestend(bp_xcm_bridge::XcmBridgeCall), } frame_support::parameter_types! { @@ -165,11 +168,3 @@ frame_support::parameter_types! { /// (initially was calculated by test `AssetHubRococo::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) pub const AssetHubRococoBaseConfirmationFeeInRocs: u128 = 56_782_099; } - -/// Wrapper over `AssetHubRococo`'s `RuntimeCall` that can be used without a runtime. -#[derive(Decode, Encode)] -pub enum RuntimeCall { - /// Points to the `pallet_xcm_bridge` pallet instance for `AssetHubWestend`. - #[codec(index = 61)] - XcmOverAssetHubWestend(bp_xcm_bridge::XcmBridgeCall), -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/bridge-primitives/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/bridge-primitives/src/lib.rs index 3ec168cc58b51..8cf3c6f363916 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/bridge-primitives/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/bridge-primitives/src/lib.rs @@ -50,6 +50,9 @@ pub enum Call { /// `ToRococoXcmRouter` bridge pallet. #[codec(index = 34)] ToRococoXcmRouter(XcmBridgeHubCall), + /// Points to the `pallet_xcm_bridge_hub` pallet instance for `AssetHubRococo`. + #[codec(index = 62)] + XcmOverAssetHubRococo(bp_xcm_bridge::XcmBridgeCall), } frame_support::parameter_types! { @@ -166,11 +169,3 @@ frame_support::parameter_types! { /// (initially was calculated by test `AssetHubWestend::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) pub const AssetHubWestendBaseConfirmationFeeInWnds: u128 = 56_782_099; } - -/// Wrapper over `AssetHubWestend`'s `RuntimeCall` that can be used without a runtime. -#[derive(Decode, Encode)] -pub enum RuntimeCall { - /// Points to the `pallet_xcm_bridge_hub` pallet instance for `AssetHubRococo`. - #[codec(index = 62)] // TODO: FAIL-CI - corect index when AssetHubWestend - XcmOverAssetHubRococo(bp_xcm_bridge::XcmBridgeCall), -}