Skip to content
Merged
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ polkadot-runtime-parachains.workspace = true
polkadot-runtime-parachains.default-features = true
xcm.workspace = true
xcm.default-features = true
pallet-xcm.workspace = true
pallet-xcm.default-features = true
pallet-xcm = { features = ["test-utils"], workspace = true, default-features = true }
parachains-common.workspace = true
parachains-common.default-features = true
cumulus-primitives-core.workspace = true
cumulus-primitives-core.default-features = true
xcm-emulator.workspace = true
xcm-emulator.default-features = true
xcm-simulator = { workspace = true, default-features = true }
cumulus-pallet-xcmp-queue.workspace = true
cumulus-pallet-xcmp-queue.default-features = true
cumulus-pallet-parachain-system.workspace = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod macros;
pub mod xcm_helpers;

pub use xcm_emulator;
pub use xcm_simulator;

// Substrate
use frame_support::parameter_types;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
use parachains_common::AccountId;

// Polkadot
use sp_core::H256;
use xcm::{prelude::*, DoubleEncoded};
use xcm_emulator::Chain;

/// Helper method to build a XCM with a `Transact` instruction and paying for its execution
pub fn xcm_transact_paid_execution(
Expand Down Expand Up @@ -74,3 +76,29 @@ pub fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 {
};
amount
}

/// Helper method to find the ID of the first `Event::Processed` event in the chain's events.
pub fn find_mq_processed_id<C: Chain>() -> Option<H256>
where
<C as Chain>::Runtime: pallet_message_queue::Config,
C::RuntimeEvent: TryInto<pallet_message_queue::Event<<C as Chain>::Runtime>>,
{
C::events().into_iter().find_map(|event| {
if let Ok(pallet_message_queue::Event::Processed { id, .. }) = event.try_into() {
Some(id)
} else {
None
}
})
}

/// Helper method to find the message ID of the first `Event::Sent` event in the chain's events.
pub fn find_xcm_sent_message_id<
C: Chain<RuntimeEvent = <<C as Chain>::Runtime as pallet_xcm::Config>::RuntimeEvent>,
>() -> Option<XcmHash>
where
C::Runtime: pallet_xcm::Config,
C::RuntimeEvent: TryInto<pallet_xcm::Event<C::Runtime>>,
{
pallet_xcm::xcm_helpers::find_xcm_sent_message_id::<<C as Chain>::Runtime>(C::events())
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ use crate::{
imports::*,
tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt,
};
use emulated_integration_tests_common::xcm_helpers::find_mq_processed_id;

fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) {
fn para_to_para_assethub_hop_assertions(mut t: ParaToParaThroughAHTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
let sov_penpal_a_on_ah = AssetHubWestend::sovereign_account_id_of(
AssetHubWestend::sibling_location_of(PenpalA::para_id()),
Expand Down Expand Up @@ -49,6 +50,9 @@ fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) {
) => {},
]
);

let mq_prc_id = find_mq_processed_id::<AssetHubWestend>().expect("Missing Processed Event");
t.insert_unique_topic_id("AssetHubWestend", mq_prc_id);
}

fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
Expand Down Expand Up @@ -586,6 +590,9 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() {
test.set_dispatchable::<PenpalA>(para_to_para_transfer_assets_through_ah);
test.assert();

// assert unique topic across all chains
test.assert_unique_topic_id();

// Query final balances
let sender_wnds_after = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.

use crate::{create_pool_with_wnd_on, foreign_balance_on, imports::*};
use emulated_integration_tests_common::xcm_helpers::find_mq_processed_id;
use sp_core::{crypto::get_public_from_string_or_panic, sr25519};

fn relay_to_para_sender_assertions(t: RelayToParaTest) {
Expand Down Expand Up @@ -468,10 +469,16 @@ fn para_to_para_asset_hub_hop_assertions(t: ParaToParaThroughAHTest) {
);
}

pub fn para_to_para_through_hop_receiver_assertions<Hop: Clone>(t: Test<PenpalA, PenpalB, Hop>) {
pub fn para_to_para_through_hop_receiver_assertions<Hop: Clone>(
mut t: Test<PenpalA, PenpalB, Hop>,
) {
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;

PenpalB::assert_xcmp_queue_success(None);

let mq_prc_id = find_mq_processed_id::<PenpalB>().expect("Missing Processed Event");
t.insert_unique_topic_id("PenpalB", mq_prc_id);

for asset in t.args.assets.into_inner().into_iter() {
let expected_id = asset.id.0.try_into().unwrap();
assert_expected_events!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
// limitations under the License.

use crate::{create_pool_with_native_on, tests::*};
use emulated_integration_tests_common::{
xcm_helpers::find_mq_processed_id, xcm_simulator::helpers::TopicIdTracker,
};
use xcm::latest::AssetTransferFilter;

fn send_assets_over_bridge<F: FnOnce()>(send_fn: F) {
Expand Down Expand Up @@ -553,6 +556,7 @@ fn dry_run_transfer_to_rococo_sends_xcm_to_bridge_hub() {
}

fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
topic_id_tracker: &mut TopicIdTracker,
wnds: (Location, u128),
pens: (Location, u128),
) {
Expand Down Expand Up @@ -652,6 +656,9 @@ fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
}));
AssetHubWestend::execute_with(|| {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
let mq_prc_id =
find_mq_processed_id::<AssetHubWestend>().expect("Missing Processed Event");
topic_id_tracker.insert_and_assert_unique("AssetHubWestend", mq_prc_id);
assert_expected_events!(
AssetHubWestend,
vec![
Expand All @@ -672,6 +679,12 @@ fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
]
);
});

BridgeHubWestend::ext_wrapper(|| {
let mq_prc_id =
find_mq_processed_id::<BridgeHubWestend>().expect("Missing Processed Event");
topic_id_tracker.insert_and_assert_unique("BridgeHubWestend", mq_prc_id);
});
});
}

Expand Down Expand Up @@ -776,14 +789,20 @@ fn send_pens_and_wnds_from_penpal_westend_via_ahw_to_ahr() {
)
});

// init topic ID tracker
let mut topic_id_tracker = TopicIdTracker::new();

// transfer assets
do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
&mut topic_id_tracker,
(wnd_at_westend_parachains.clone(), wnds_to_send),
(pens_location_on_penpal.try_into().unwrap(), pens_to_send),
);

AssetHubRococo::execute_with(|| {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
let mq_prc_id = find_mq_processed_id::<AssetHubRococo>().expect("Missing Processed Event");
topic_id_tracker.insert_and_assert_unique("AssetHubRococo", mq_prc_id);
assert_expected_events!(
AssetHubRococo,
vec![
Expand All @@ -800,6 +819,9 @@ fn send_pens_and_wnds_from_penpal_westend_via_ahw_to_ahr() {
);
});

// assert unique topic across all chains
topic_id_tracker.assert_unique();

// account balances after
let sender_wnds_after = PenpalB::execute_with(|| {
type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ pub(crate) fn assert_bridge_hub_westend_message_accepted(expected_processed: boo
]
);
}
});
})
}

pub(crate) fn assert_bridge_hub_rococo_message_received() {
Expand Down
1 change: 1 addition & 0 deletions cumulus/xcm/xcm-emulator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ xcm.workspace = true
xcm.default-features = true
xcm-executor.workspace = true
xcm-executor.default-features = true
xcm-simulator = { workspace = true, default-features = true }
polkadot-primitives.workspace = true
polkadot-primitives.default-features = true
polkadot-parachain-primitives.workspace = true
Expand Down
24 changes: 23 additions & 1 deletion cumulus/xcm/xcm-emulator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub use array_bytes;
pub use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
pub use log;
pub use paste;
use std::sync::Arc;
pub use std::{
any::type_name,
collections::HashMap,
Expand Down Expand Up @@ -75,12 +76,13 @@ pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueu

// Polkadot
pub use polkadot_parachain_primitives::primitives::RelayChainBlockNumber;
use sp_core::crypto::AccountId32;
use sp_core::{crypto::AccountId32, H256};
pub use xcm::latest::prelude::{
AccountId32 as AccountId32Junction, Ancestor, Assets, Here, Location,
Parachain as ParachainJunction, Parent, WeightLimit, XcmHash,
};
pub use xcm_executor::traits::ConvertLocation;
use xcm_simulator::helpers::TopicIdTracker;

pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;

Expand Down Expand Up @@ -1545,11 +1547,30 @@ where
pub hops_dispatchable: HashMap<String, fn(Self) -> DispatchResult>,
pub hops_calls: HashMap<String, Origin::RuntimeCall>,
pub args: Args,
topic_id_tracker: Arc<Mutex<TopicIdTracker>>,
_marker: PhantomData<(Destination, Hops)>,
}

/// `Test` implementation.
impl<Origin, Destination, Hops, Args> Test<Origin, Destination, Hops, Args>
where
Args: Clone,
Origin: Chain + Clone,
Destination: Chain + Clone,
Origin::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Origin::Runtime>> + Clone,
Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
Hops: Clone,
{
/// Asserts that a single unique topic ID exists across all chains.
pub fn assert_unique_topic_id(&self) {
self.topic_id_tracker.lock().unwrap().assert_unique();
}
/// Inserts a topic ID for a specific chain and asserts it remains globally unique.
pub fn insert_unique_topic_id(&mut self, chain: &str, id: H256) {
self.topic_id_tracker.lock().unwrap().insert_and_assert_unique(chain, id);
}
}
impl<Origin, Destination, Hops, Args> Test<Origin, Destination, Hops, Args>
where
Args: Clone,
Origin: Chain + Clone + CheckAssertion<Origin, Destination, Hops, Args>,
Expand All @@ -1575,6 +1596,7 @@ where
hops_dispatchable: Default::default(),
hops_calls: Default::default(),
args: test_args.args,
topic_id_tracker: Arc::new(Mutex::new(TopicIdTracker::new())),
_marker: Default::default(),
}
}
Expand Down
2 changes: 2 additions & 0 deletions polkadot/xcm/pallet-xcm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pallet-balances = { optional = true, workspace = true }
pallet-assets = { default-features = true, path = "../../../substrate/frame/assets" }
polkadot-runtime-parachains = { default-features = true, path = "../../runtime/parachains" }
polkadot-parachain-primitives = { default-features = true, path = "../../parachain" }
xcm-simulator = { workspace = true, default-features = true }

[features]
default = ["std"]
Expand Down Expand Up @@ -62,6 +63,7 @@ runtime-benchmarks = [
"xcm-executor/runtime-benchmarks",
"xcm-runtime-apis/runtime-benchmarks",
]
test-utils = ["std"]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
Expand Down
2 changes: 2 additions & 0 deletions polkadot/xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ mod mock;
mod tests;

pub mod migration;
#[cfg(any(test, feature = "test-utils"))]
pub mod xcm_helpers;

extern crate alloc;

Expand Down
Loading
Loading