From eadfbca388176f46e63d20edbaf546d06afad1bc Mon Sep 17 00:00:00 2001 From: Ignacio Palacios <ignacio.palacios.santos@gmail.com> Date: Thu, 10 Aug 2023 19:38:18 +0200 Subject: [PATCH] Replicate `e2e` integration test as `emulated` (#2958) * Allow functions to work over both parachains and relay chains * additional references * import * backup * refactoring para and relay traits * use runtime crates to build types * decouple ProcessMessage * decouple ProcessMessage 2 * dmp and xcmp handlers decouple * backup * refactor done * common int values working * added global ext with mutex * works for two mutex * single mutex and remove condvar * global test ext done * failing moving test_ext because relay block num * relay_block_number issue fixed * backup * Test working with assertions * assertions get Test as arg * DispatchArgs as generic * clean up * backup * teleports for asset-hub-kusama done * improve assert_expected_events macro * rename Test generics * check assertions for tuples * test assertions redone * reserve_transfer_assets done * send transact done * hrmp test for paras * hrmp channels test done * hrmp channels test done 2 * before modifying test dispatch * reserve tests done & Test dispatch fixed * reserve transfer local asset * force_create_and_mint_asset * force create and mint done * tests done * fix imports in common * common events refactored * add option to events attributes * asset-hub-polkadot tests done * asset-hub-westend half done * relay chain events move to common * remove failing send tests for asset-hub-westend * added events to bridge-hub-rococo * added events to collectives-polkadot * cargo clean up * fix asset-hub-westend tests * ".git/.scripts/commands/fmt/fmt.sh" * fix clippy * ".git/.scripts/commands/fmt/fmt.sh" * Removed unnecessary deps * Extracted some commonality for Kusama/Polkadot (which will be reused also for BridgeHubs) (#2971) * Extracted some commonality for Kusama/Polkadot (which will be reused also for BridgeHubs) * AssetHubRococo should better use AssetHubKusama runtime * add fund_account --------- Co-authored-by: NachoPal <ignacio.palacios.santos@gmail.com> * address comments * rename event assertion helpers * clean comments * address comments 2 * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: Giles Cope <gilescope@gmail.com> Co-authored-by: command-bot <> Co-authored-by: Branislav Kontur <bkontur@gmail.com> --- cumulus/Cargo.lock | 38 +- .../assets/asset-hub-kusama/Cargo.toml | 5 +- .../assets/asset-hub-kusama/src/lib.rs | 74 +- .../src/tests/hrmp_channels.rs | 201 ++++ .../assets/asset-hub-kusama/src/tests/mod.rs | 4 +- .../src/tests/reserve_transfer.rs | 451 ++++++- .../assets/asset-hub-kusama/src/tests/send.rs | 196 +++ .../src/tests/set_xcm_versions.rs | 94 ++ .../asset-hub-kusama/src/tests/teleport.rs | 402 ++++++- .../asset-hub-kusama/src/tests/transact.rs | 74 -- .../assets/asset-hub-polkadot/Cargo.toml | 5 +- .../assets/asset-hub-polkadot/src/lib.rs | 78 +- .../src/tests/hrmp_channels.rs | 201 ++++ .../asset-hub-polkadot/src/tests/mod.rs | 4 +- .../src/tests/reserve_transfer.rs | 451 ++++++- .../asset-hub-polkadot/src/tests/send.rs | 202 ++++ .../src/tests/set_xcm_versions.rs | 97 ++ .../asset-hub-polkadot/src/tests/teleport.rs | 400 ++++++- .../asset-hub-polkadot/src/tests/transact.rs | 74 -- .../assets/asset-hub-westend/Cargo.toml | 5 +- .../assets/asset-hub-westend/src/lib.rs | 75 +- .../assets/asset-hub-westend/src/tests/mod.rs | 3 +- .../src/tests/reserve_transfer.rs | 451 ++++++- .../asset-hub-westend/src/tests/send.rs | 141 +++ .../src/tests/set_xcm_versions.rs | 97 ++ .../asset-hub-westend/src/tests/swap.rs | 78 +- .../asset-hub-westend/src/tests/teleport.rs | 400 ++++++- .../asset-hub-westend/src/tests/transact.rs | 74 -- .../bridges/bridge-hub-rococo/Cargo.toml | 2 +- .../bridges/bridge-hub-rococo/src/lib.rs | 62 +- .../bridge-hub-rococo/src/tests/example.rs | 10 +- .../collectives-polkadot/Cargo.toml | 3 +- .../collectives-polkadot/src/lib.rs | 91 +- .../src/tests/fellowship.rs | 12 +- .../emulated/common/Cargo.toml | 6 + .../emulated/common/src/constants.rs | 108 +- .../emulated/common/src/impls.rs | 481 +++++++- .../emulated/common/src/lib.rs | 446 ++++--- cumulus/xcm/xcm-emulator/Cargo.toml | 7 +- cumulus/xcm/xcm-emulator/src/lib.rs | 1051 +++++++++++------ 40 files changed, 5349 insertions(+), 1305 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/transact.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/transact.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs create mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs delete mode 100644 cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/transact.rs diff --git a/cumulus/Cargo.lock b/cumulus/Cargo.lock index 7164f6b25b3..fdaecced8fc 100644 --- a/cumulus/Cargo.lock +++ b/cumulus/Cargo.lock @@ -447,7 +447,9 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" name = "asset-hub-kusama-integration-tests" version = "1.0.0" dependencies = [ - "asset-hub-kusama-runtime", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -456,7 +458,6 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime", @@ -544,7 +545,9 @@ dependencies = [ name = "asset-hub-polkadot-integration-tests" version = "1.0.0" dependencies = [ - "asset-hub-polkadot-runtime", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -553,7 +556,6 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime", @@ -641,6 +643,9 @@ version = "1.0.0" dependencies = [ "assert_matches", "asset-hub-westend-runtime", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "integration-tests-common", @@ -650,7 +655,6 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "polkadot-core-primitives", "polkadot-parachain", "polkadot-runtime", @@ -658,7 +662,6 @@ dependencies = [ "sp-core", "sp-runtime", "sp-weights", - "westend-runtime", "xcm", "xcm-emulator", "xcm-executor", @@ -1445,7 +1448,7 @@ name = "bridge-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ "bp-messages", - "bridge-hub-rococo-runtime", + "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", @@ -1759,15 +1762,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "casey" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614586263949597dcc18675da12ef9b429135e13628d92eb8b8c6fa50ca5656b" -dependencies = [ - "syn 1.0.109", -] - [[package]] name = "cast" version = "0.3.0" @@ -1999,6 +1993,7 @@ version = "0.1.0" dependencies = [ "asset-hub-polkadot-runtime", "collectives-polkadot-runtime", + "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", @@ -5263,20 +5258,26 @@ dependencies = [ "bridge-hub-rococo-runtime", "bridge-runtime-common", "collectives-polkadot-runtime", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "frame-support", "frame-system", "kusama-runtime", "kusama-runtime-constants", + "lazy_static", "pallet-assets", "pallet-balances", "pallet-bridge-messages", "pallet-im-online", + "pallet-message-queue", "pallet-staking", "pallet-xcm", "parachain-info", "parachains-common", "parity-scale-codec", + "paste", "penpal-runtime", "polkadot-core-primitives", "polkadot-parachain", @@ -15908,7 +15909,6 @@ dependencies = [ name = "xcm-emulator" version = "0.1.0" dependencies = [ - "casey", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", @@ -15917,6 +15917,8 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "frame-support", "frame-system", + "impl-trait-for-tuples", + "lazy_static", "log", "pallet-balances", "pallet-message-queue", @@ -15926,7 +15928,6 @@ dependencies = [ "paste", "polkadot-primitives", "polkadot-runtime-parachains", - "quote", "sp-arithmetic", "sp-core", "sp-io", @@ -15934,6 +15935,7 @@ dependencies = [ "sp-std", "sp-trie", "xcm", + "xcm-executor", ] [[package]] diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml index a25e2116873..d3ecbde4291 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/Cargo.toml @@ -28,8 +28,9 @@ pallet-xcm = { default-features = false, git = "https://github.com/paritytech/po # Cumulus parachains-common = { path = "../../../../common" } -penpal-runtime = { path = "../../../../runtimes/testing/penpal" } -asset-hub-kusama-runtime = { path = "../../../../runtimes/assets/asset-hub-kusama" } +cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../pallets/xcmp-queue" } +cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } # Local xcm-emulator = { default-features = false, path = "../../../../../xcm/xcm-emulator" } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs index b090432fa7c..4282e91c499 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/lib.rs @@ -16,31 +16,89 @@ pub use codec::Encode; pub use frame_support::{ - assert_ok, instances::Instance1, pallet_prelude::Weight, traits::fungibles::Inspect, + assert_err, assert_ok, + instances::Instance1, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, + traits::{fungibles::Inspect, OriginTrait}, }; pub use integration_tests_common::{ constants::{ accounts::{ALICE, BOB}, + asset_hub_kusama::ED as ASSET_HUB_KUSAMA_ED, kusama::ED as KUSAMA_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - AccountId, AssetHubKusama, AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, - BridgeHubKusama, BridgeHubKusamaPallet, BridgeHubKusamaReceiver, BridgeHubKusamaSender, - BridgeHubPolkadot, BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, - Collectives, CollectivesPallet, CollectivesReceiver, CollectivesSender, Kusama, KusamaMockNet, - KusamaPallet, KusamaReceiver, KusamaSender, PenpalKusama, PenpalKusamaReceiver, - PenpalKusamaSender, PenpalPolkadot, PenpalPolkadotReceiver, PenpalPolkadotSender, Polkadot, + lazy_static::lazy_static, + xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubKusama, + AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, BridgeHubKusama, + BridgeHubKusamaPallet, BridgeHubKusamaReceiver, BridgeHubKusamaSender, BridgeHubPolkadot, + BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, Collectives, + CollectivesPallet, CollectivesReceiver, CollectivesSender, Kusama, KusamaMockNet, KusamaPallet, + KusamaReceiver, KusamaSender, PenpalKusamaA, PenpalKusamaAPallet, PenpalKusamaAReceiver, + PenpalKusamaASender, PenpalKusamaB, PenpalKusamaBPallet, PenpalKusamaBReceiver, + PenpalKusamaBSender, PenpalPolkadotA, PenpalPolkadotAReceiver, PenpalPolkadotASender, Polkadot, PolkadotMockNet, PolkadotPallet, PolkadotReceiver, PolkadotSender, }; +pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; +pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, v3::{Error, NetworkId::Kusama as KusamaId}, + DoubleEncoded, }; pub use xcm_emulator::{ assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - Parachain as Para, RelayChain as Relay, TestExt, + AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, TestExternalities, }; +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +// `Assets` pallet index +pub const ASSETS_PALLET_ID: u8 = 50; + +pub type RelayToSystemParaTest = Test<Kusama, AssetHubKusama>; +pub type SystemParaToRelayTest = Test<AssetHubKusama, Kusama>; +pub type SystemParaToParaTest = Test<AssetHubKusama, PenpalKusamaA>; + +/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +pub fn relay_test_args(amount: Balance) -> TestArgs { + TestArgs { + dest: Kusama::child_location_of(AssetHubKusama::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubKusamaReceiver::get().into(), + } + .into(), + amount, + assets: (Here, amount).into(), + asset_id: None, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + +/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +pub fn system_para_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, + assets: MultiAssets, + asset_id: Option<u32>, +) -> TestArgs { + TestArgs { + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), + amount, + assets, + asset_id, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs new file mode 100644 index 00000000000..9d0bd50502e --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/hrmp_channels.rs @@ -0,0 +1,201 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +const MAX_CAPACITY: u32 = 8; +const MAX_MESSAGE_SIZE: u32 = 8192; + +/// Opening HRMP channels between Parachains should work +#[test] +fn open_hrmp_channel_between_paras_works() { + // Parchain A init values + let para_a_id = PenpalKusamaA::para_id(); + let para_a_root_origin = <PenpalKusamaA as Chain>::RuntimeOrigin::root(); + + // Parachain B init values + let para_b_id = PenpalKusamaB::para_id(); + let para_b_root_origin = <PenpalKusamaB as Chain>::RuntimeOrigin::root(); + + let fee_amount = KUSAMA_ED * 1000; + let fund_amount = KUSAMA_ED * 1000_000_000; + + // Fund Parachain's Sovereign accounts to be able to reserve the deposit + let para_a_sovereign_account = Kusama::fund_para_sovereign(fund_amount, para_a_id); + let para_b_sovereign_account = Kusama::fund_para_sovereign(fund_amount, para_b_id); + + let relay_destination: VersionedMultiLocation = PenpalKusamaA::parent_location().into(); + + // ---- Init Open channel from Parachain to System Parachain + let mut call = Kusama::init_open_channel_call(para_b_id, MAX_CAPACITY, MAX_MESSAGE_SIZE); + let origin_kind = OriginKind::Native; + let native_asset: MultiAsset = (Here, fee_amount).into(); + let beneficiary = Kusama::sovereign_account_id_of_child_para(para_a_id); + + let mut xcm = xcm_transact_paid_execution(call, origin_kind, native_asset.clone(), beneficiary); + + PenpalKusamaA::execute_with(|| { + assert_ok!(<PenpalKusamaA as PenpalKusamaAPallet>::PolkadotXcm::send( + para_a_root_origin, + bx!(relay_destination.clone()), + bx!(xcm), + )); + }); + + Kusama::execute_with(|| { + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + Kusama::assert_ump_queue_processed( + true, + Some(para_a_id), + Some(Weight::from_parts(1_312_558_000, 200000)), + ); + + assert_expected_events!( + Kusama, + vec![ + // Parachain's Sovereign account balance is withdrawn to pay XCM fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == para_a_sovereign_account.clone(), + amount: *amount == fee_amount, + }, + // Sender deposit is reserved for Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == para_a_sovereign_account, + }, + // Open channel requested from Para A to Para B + RuntimeEvent::Hrmp( + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested( + sender, recipient, max_capacity, max_message_size + ) + ) => { + sender: *sender == para_a_id.into(), + recipient: *recipient == para_b_id.into(), + max_capacity: *max_capacity == MAX_CAPACITY, + max_message_size: *max_message_size == MAX_MESSAGE_SIZE, + }, + ] + ); + }); + + // ---- Accept Open channel from Parachain to System Parachain + call = Kusama::accept_open_channel_call(para_a_id); + let beneficiary = Kusama::sovereign_account_id_of_child_para(para_b_id); + + xcm = xcm_transact_paid_execution(call, origin_kind, native_asset, beneficiary); + + PenpalKusamaB::execute_with(|| { + assert_ok!(<PenpalKusamaB as PenpalKusamaBPallet>::PolkadotXcm::send( + para_b_root_origin, + bx!(relay_destination), + bx!(xcm), + )); + }); + + Kusama::execute_with(|| { + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + Kusama::assert_ump_queue_processed( + true, + Some(para_b_id), + Some(Weight::from_parts(1_312_558_000, 200_000)), + ); + + assert_expected_events!( + Kusama, + vec![ + // Parachain's Sovereign account balance is withdrawn to pay XCM fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == para_b_sovereign_account.clone(), + amount: *amount == fee_amount, + }, + // Sender deposit is reserved for Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == para_b_sovereign_account, + }, + // Open channel accepted for Para A to Para B + RuntimeEvent::Hrmp( + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted( + sender, recipient + ) + ) => { + sender: *sender == para_a_id.into(), + recipient: *recipient == para_b_id.into(), + }, + ] + ); + }); + + Kusama::force_process_hrmp_open(para_a_id, para_b_id); +} + +/// Opening HRMP channels between System Parachains and Parachains should work +#[test] +fn force_open_hrmp_channel_for_system_para_works() { + // Relay Chain init values + let relay_root_origin = <Kusama as Chain>::RuntimeOrigin::root(); + + // System Para init values + let system_para_id = AssetHubKusama::para_id(); + + // Parachain A init values + let para_a_id = PenpalKusamaA::para_id(); + + let fund_amount = KUSAMA_ED * 1000_000_000; + + // Fund Parachain's Sovereign accounts to be able to reserve the deposit + let para_a_sovereign_account = Kusama::fund_para_sovereign(fund_amount, para_a_id); + let system_para_sovereign_account = Kusama::fund_para_sovereign(fund_amount, system_para_id); + + Kusama::execute_with(|| { + assert_ok!(<Kusama as KusamaPallet>::Hrmp::force_open_hrmp_channel( + relay_root_origin, + system_para_id, + para_a_id, + MAX_CAPACITY, + MAX_MESSAGE_SIZE + )); + + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + assert_expected_events!( + Kusama, + vec![ + // Sender deposit is reserved for System Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == system_para_sovereign_account, + }, + // Recipient deposit is reserved for Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == para_a_sovereign_account, + }, + // HRMP channel forced opened + RuntimeEvent::Hrmp( + polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened( + sender, recipient, max_capacity, max_message_size + ) + ) => { + sender: *sender == system_para_id.into(), + recipient: *recipient == para_a_id.into(), + max_capacity: *max_capacity == MAX_CAPACITY, + max_message_size: *max_message_size == MAX_MESSAGE_SIZE, + }, + ] + ); + }); + + Kusama::force_process_hrmp_open(system_para_id, para_a_id); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs index 44861d2a872..00e0a663e47 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. +mod hrmp_channels; mod reserve_transfer; +mod send; +mod set_xcm_versions; mod teleport; -mod transact; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs index b1c5cbbd3bf..d26f48215c1 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/reserve_transfer.rs @@ -16,66 +16,395 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); + + assert_expected_events!( + Kusama, + vec![ + // Amount to reserve transfer is transferred to System Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { + from: *from == t.sender.account_id, + to: *to == Kusama::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { + AssetHubKusama::assert_dmp_queue_incomplete( + Some(Weight::from_parts(1_000_000_000, 0)), + Some(Error::UntrustedReserveLocation), + ); +} + +fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { + AssetHubKusama::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) +} + +fn system_para_to_para_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 630_092_000, + 6_196, + ))); + + assert_expected_events!( + AssetHubKusama, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereing account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == AssetHubKusama::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 676_119_000, + 6196, + ))); + + assert_expected_events!( + AssetHubKusama, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereing account + RuntimeEvent::Assets( + pallet_assets::Event::Transferred { asset_id, from, to, amount } + ) => { + asset_id: *asset_id == ASSET_ID, + from: *from == t.sender.account_id, + to: *to == AssetHubKusama::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Kusama as KusamaPallet>::XcmPallet::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Kusama as KusamaPallet>::XcmPallet::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_assets() { - // Init tests variables - let amount = KUSAMA_ED * 1000; - let relay_sender_balance_before = Kusama::account_data_of(KusamaSender::get()).free; - let para_receiver_balance_before = - AssetHubKusama::account_data_of(AssetHubKusamaReceiver::get()).free; - - let origin = <Kusama as Relay>::RuntimeOrigin::signed(KusamaSender::get()); - let assets_para_destination: VersionedMultiLocation = - Kusama::child_location_of(AssetHubKusama::para_id()).into(); - let beneficiary: VersionedMultiLocation = - AccountId32 { network: None, id: AssetHubKusamaReceiver::get().into() }.into(); - let native_assets: VersionedMultiAssets = (Here, amount).into(); - let fee_asset_item = 0; - let weight_limit = WeightLimit::Unlimited; - - // Send XCM message from Relay Chain - Kusama::execute_with(|| { - assert_ok!(<Kusama as KusamaPallet>::XcmPallet::limited_reserve_transfer_assets( - origin, - bx!(assets_para_destination), - bx!(beneficiary), - bx!(native_assets), - fee_asset_item, - weight_limit, - )); - - type RuntimeEvent = <Kusama as Relay>::RuntimeEvent; - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => { - weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(630_092_000, 6196), *weight), - }, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubKusama::execute_with(|| { - type RuntimeEvent = <AssetHubKusama as Para>::RuntimeEvent; - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Incomplete(_, Error::UntrustedReserveLocation), - .. - }) => {}, - ] - ); - }); - - // Check if balances are updated accordingly in Relay Chain and Assets Parachain - let relay_sender_balance_after = Kusama::account_data_of(KusamaSender::get()).free; - let para_sender_balance_after = - AssetHubKusama::account_data_of(AssetHubKusamaReceiver::get()).free; - - assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); - assert_eq!(para_sender_balance_after, para_receiver_balance_before); +fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = KUSAMA_ED * 1000; + let test_args = TestContext { + sender: KusamaSender::get(), + receiver: AssetHubKusamaReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Kusama>(relay_origin_assertions); + test.set_assertion::<AssetHubKusama>(system_para_dest_assertions_incomplete); + test.set_dispatchable::<Kusama>(relay_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work +#[test] +fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { + // Init values for System Parachain + let destination = AssetHubKusama::parent_location(); + let beneficiary_id = KusamaReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: KusamaReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubKusama>(system_para_to_relay_assertions); + test.set_dispatchable::<AssetHubKusama>(system_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +#[test] +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = KUSAMA_ED * 1000; + let test_args = TestContext { + sender: KusamaSender::get(), + receiver: AssetHubKusamaReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Kusama>(relay_origin_assertions); + test.set_assertion::<AssetHubKusama>(system_para_dest_assertions_incomplete); + test.set_dispatchable::<Kusama>(relay_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +#[test] +fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { + // Init values for System Parachain + let destination = AssetHubKusama::parent_location(); + let beneficiary_id = KusamaReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: KusamaReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubKusama>(system_para_to_relay_assertions); + test.set_dispatchable::<AssetHubKusama>(system_para_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work +#[test] +fn limited_reserve_transfer_native_asset_from_system_para_to_para() { + // Init values for System Parachain + let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); + let beneficiary_id = PenpalKusamaAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: PenpalKusamaAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + + test.set_assertion::<AssetHubKusama>(system_para_to_para_assertions); + // TODO: Add assertion for Penpal runtime. Right now message is failing with `UntrustedReserveLocation` + test.set_dispatchable::<AssetHubKusama>(system_para_to_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve transfers +} + +/// Reserve Transfers of native asset from System Parachain to Parachain should work +#[test] +fn reserve_transfer_native_asset_from_system_para_to_para() { + // Init values for System Parachain + let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); + let beneficiary_id = PenpalKusamaAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: PenpalKusamaAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + + test.set_assertion::<AssetHubKusama>(system_para_to_para_assertions); + // TODO: Add assertion for Penpal runtime. Right now message is failing with `UntrustedReserveLocation` + test.set_dispatchable::<AssetHubKusama>(system_para_to_para_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve transfers +} + +/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work +#[test] +fn limited_reserve_transfer_asset_from_system_para_to_para() { + // Force create asset from Relay Chain and mint assets for System Parachain's sender account + AssetHubKusama::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubKusamaSender::get(), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); + let beneficiary_id = PenpalKusamaAReceiver::get(); + let amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) + .into(); + + let system_para_test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: PenpalKusamaAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + + system_para_test.set_assertion::<AssetHubKusama>(system_para_to_para_assets_assertions); + // TODO: Add assertions when Penpal is able to manage assets + system_para_test + .set_dispatchable::<AssetHubKusama>(system_para_to_para_limited_reserve_transfer_assets); + system_para_test.assert(); +} + +/// Reserve Transfers of a local asset from System Parachain to Parachain should work +#[test] +fn reserve_transfer_asset_from_system_para_to_para() { + // Force create asset from Relay Chain and mint assets for System Parachain's sender account + AssetHubKusama::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubKusamaSender::get(), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + let destination = AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()); + let beneficiary_id = PenpalKusamaAReceiver::get(); + let amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) + .into(); + + let system_para_test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: PenpalKusamaAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + + system_para_test.set_assertion::<AssetHubKusama>(system_para_to_para_assets_assertions); + // TODO: Add assertions when Penpal is able to manage assets + system_para_test + .set_dispatchable::<AssetHubKusama>(system_para_to_para_reserve_transfer_assets); + system_para_test.assert(); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs new file mode 100644 index 00000000000..8b92447f11f --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/send.rs @@ -0,0 +1,196 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +/// Relay Chain should be able to execute `Transact` instructions in System Parachain +/// when `OriginKind::Superuser` and signer is `sudo` +#[test] +fn send_transact_sudo_from_relay_to_system_para_works() { + // Init tests variables + let root_origin = <Kusama as Chain>::RuntimeOrigin::root(); + let system_para_destination = Kusama::child_location_of(AssetHubKusama::para_id()).into(); + let asset_owner: AccountId = AssetHubKusamaSender::get().into(); + let xcm = AssetHubKusama::force_create_asset_xcm( + OriginKind::Superuser, + ASSET_ID, + asset_owner.clone(), + true, + 1000, + ); + // Send XCM message from Relay Chain + Kusama::execute_with(|| { + assert_ok!(<Kusama as KusamaPallet>::XcmPallet::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + Kusama::assert_xcm_pallet_sent(); + }); + + // Receive XCM message in Assets Parachain + AssetHubKusama::execute_with(|| { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_445_000, 200_000))); + + assert_expected_events!( + AssetHubKusama, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == asset_owner, + }, + ] + ); + + assert!(<AssetHubKusama as AssetHubKusamaPallet>::Assets::asset_exists(ASSET_ID)); + }); +} + +/// Relay Chain shouldn't be able to execute `Transact` instructions in System Parachain +/// when `OriginKind::Native` +#[test] +fn send_transact_native_from_relay_to_system_para_fails() { + // Init tests variables + let signed_origin = <Kusama as Chain>::RuntimeOrigin::signed(KusamaSender::get().into()); + let system_para_destination = Kusama::child_location_of(AssetHubKusama::para_id()).into(); + let asset_owner = AssetHubKusamaSender::get().into(); + let xcm = AssetHubKusama::force_create_asset_xcm( + OriginKind::Native, + ASSET_ID, + asset_owner, + true, + 1000, + ); + + // Send XCM message from Relay Chain + Kusama::execute_with(|| { + assert_err!( + <Kusama as KusamaPallet>::XcmPallet::send( + signed_origin, + bx!(system_para_destination), + bx!(xcm) + ), + DispatchError::BadOrigin + ); + }); +} + +/// System Parachain shouldn't be able to execute `Transact` instructions in Relay Chain +/// when `OriginKind::Native` +#[test] +fn send_transact_native_from_system_para_to_relay_fails() { + // Init tests variables + let signed_origin = + <AssetHubKusama as Chain>::RuntimeOrigin::signed(AssetHubKusamaSender::get().into()); + let relay_destination = AssetHubKusama::parent_location().into(); + let call = <Kusama as Chain>::RuntimeCall::System(frame_system::Call::< + <Kusama as Chain>::Runtime, + >::remark_with_event { + remark: vec![0, 1, 2, 3], + }) + .encode() + .into(); + let origin_kind = OriginKind::Native; + + let xcm = xcm_transact_unpaid_execution(call, origin_kind); + + // Send XCM message from Relay Chain + AssetHubKusama::execute_with(|| { + assert_err!( + <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::send( + signed_origin, + bx!(relay_destination), + bx!(xcm) + ), + DispatchError::BadOrigin + ); + }); +} + +/// Parachain should be able to send XCM paying its fee with sufficient asset +/// in the System Parachain +#[test] +fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { + let para_sovereign_account = AssetHubKusama::sovereign_account_id_of( + AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()), + ); + + // Force create and mint assets for Parachain's sovereign account + AssetHubKusama::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + para_sovereign_account.clone(), + ASSET_MIN_BALANCE * 1000000000, + ); + + // We just need a call that can pass the `SafeCallFilter` + // Call values are not relevant + let call = AssetHubKusama::force_create_asset_call( + ASSET_ID, + para_sovereign_account.clone(), + true, + ASSET_MIN_BALANCE, + ); + + let origin_kind = OriginKind::SovereignAccount; + let fee_amount = ASSET_MIN_BALANCE * 1000000; + let native_asset = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); + + let root_origin = <PenpalKusamaA as Chain>::RuntimeOrigin::root(); + let system_para_destination = + PenpalKusamaA::sibling_location_of(AssetHubKusama::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + native_asset, + para_sovereign_account.clone(), + ); + + PenpalKusamaA::execute_with(|| { + assert_ok!(<PenpalKusamaA as PenpalKusamaAPallet>::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + AssetHubKusama::assert_xcm_pallet_sent(); + }); + + AssetHubKusama::execute_with(|| { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_xcmp_queue_success(Some(Weight::from_parts(2_176_414_000, 203_593))); + + assert_expected_events!( + AssetHubKusama, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == para_sovereign_account, + balance: *balance == fee_amount, + }, + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { + asset_id: *asset_id == ASSET_ID, + }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs new file mode 100644 index 00000000000..0ab53b45122 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs @@ -0,0 +1,94 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +#[test] +fn relay_sets_system_para_xcm_supported_version() { + // Init tests variables + let sudo_origin = <Kusama as Chain>::RuntimeOrigin::root(); + let system_para_destination: MultiLocation = + Kusama::child_location_of(AssetHubKusama::para_id()); + + // Relay Chain sets supported version for Asset Parachain + Kusama::execute_with(|| { + assert_ok!(<Kusama as KusamaPallet>::XcmPallet::force_xcm_version( + sudo_origin, + bx!(system_para_destination), + XCM_V3 + )); + + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + assert_expected_events!( + Kusama, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { + location, + version: XCM_V3 + }) => { location: *location == system_para_destination, }, + ] + ); + }); +} + +#[test] +fn system_para_sets_relay_xcm_supported_version() { + // Init test variables + let sudo_origin = <Kusama as Chain>::RuntimeOrigin::root(); + let parent_location = AssetHubKusama::parent_location(); + let system_para_destination: VersionedMultiLocation = + Kusama::child_location_of(AssetHubKusama::para_id()).into(); + let call = <AssetHubKusama as Chain>::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< + <AssetHubKusama as Chain>::Runtime, + >::force_xcm_version { + location: bx!(parent_location), + version: XCM_V3, + }) + .encode() + .into(); + let origin_kind = OriginKind::Superuser; + + let xcm = xcm_transact_unpaid_execution(call, origin_kind); + + // System Parachain sets supported version for Relay Chain throught it + Kusama::execute_with(|| { + assert_ok!(<Kusama as KusamaPallet>::XcmPallet::send( + sudo_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + Kusama::assert_xcm_pallet_sent(); + }); + + // System Parachain receive the XCM message + AssetHubKusama::execute_with(|| { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); + + assert_expected_events!( + AssetHubKusama, + vec![ + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { + location, + version: XCM_V3 + }) => { location: *location == parent_location, }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs index 16c0db907c3..baaca92e051 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/teleport.rs @@ -16,65 +16,347 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); + + assert_expected_events!( + Kusama, + vec![ + // Amount to teleport is withdrawn from Sender + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + // Amount to teleport is deposited in Relay's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + who: *who == <Kusama as KusamaPallet>::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_dest_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = <Kusama as Chain>::RuntimeEvent; + + Kusama::assert_ump_queue_processed( + true, + Some(AssetHubKusama::para_id()), + Some(Weight::from_parts(307_225_000, 7_186)), + ); + + assert_expected_events!( + Kusama, + vec![ + // Amount is witdrawn from Relay Chain's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == <Kusama as KusamaPallet>::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + // Amount minus fees are deposited in Receiver's account + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { + Kusama::assert_ump_queue_processed( + false, + Some(AssetHubKusama::para_id()), + Some(Weight::from_parts(148_433_000, 3_593)), + ); +} + +fn para_origin_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 534_872_000, + 7_133, + ))); + + AssetHubKusama::assert_parachain_system_ump_sent(); + + assert_expected_events!( + AssetHubKusama, + vec![ + // Amount is withdrawn from Sender's account + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_dest_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent; + + AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(165_592_000, 0))); + + assert_expected_events!( + AssetHubKusama, + vec![ + // Amount minus fees are deposited in Receiver's account + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Kusama as KusamaPallet>::XcmPallet::limited_teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Kusama as KusamaPallet>::XcmPallet::teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::limited_teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged +// fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { +// <AssetHubKusama as AssetHubKusamaPallet>::PolkadotXcm::teleport_assets( +// t.signed_origin, +// bx!(t.args.dest), +// bx!(t.args.beneficiary), +// bx!(t.args.assets), +// t.args.fee_asset_item, +// ) +// } + +/// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] -fn teleport_native_assets_from_relay_to_assets_para() { - // Init tests variables - let amount = KUSAMA_ED * 1000; - let relay_sender_balance_before = Kusama::account_data_of(KusamaSender::get()).free; - let para_receiver_balance_before = - AssetHubKusama::account_data_of(AssetHubKusamaReceiver::get()).free; - - let origin = <Kusama as Relay>::RuntimeOrigin::signed(KusamaSender::get()); - let assets_para_destination: VersionedMultiLocation = - Kusama::child_location_of(AssetHubKusama::para_id()).into(); - let beneficiary: VersionedMultiLocation = - AccountId32 { network: None, id: AssetHubKusamaReceiver::get().into() }.into(); - let native_assets: VersionedMultiAssets = (Here, amount).into(); - let fee_asset_item = 0; - let weight_limit = WeightLimit::Unlimited; - - // Send XCM message from Relay Chain - Kusama::execute_with(|| { - assert_ok!(<Kusama as KusamaPallet>::XcmPallet::limited_teleport_assets( - origin, - bx!(assets_para_destination), - bx!(beneficiary), - bx!(native_assets), - fee_asset_item, - weight_limit, - )); - - type RuntimeEvent = <Kusama as Relay>::RuntimeEvent; - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet( - pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } - ) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubKusama::execute_with(|| { - type RuntimeEvent = <AssetHubKusama as Para>::RuntimeEvent; - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { - who: *who == AssetHubKusamaReceiver::get().into(), - }, - ] - ); - }); - - // Check if balances are updated accordingly in Relay Chain and Assets Parachain - let relay_sender_balance_after = Kusama::account_data_of(KusamaSender::get()).free; - let para_sender_balance_after = - AssetHubKusama::account_data_of(AssetHubKusamaReceiver::get()).free; - - assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); - assert!(para_sender_balance_after > para_receiver_balance_before); +fn limited_teleport_native_assets_from_relay_to_system_para_works() { + // Init values for Relay Chain + let amount_to_send: Balance = KUSAMA_ED * 1000; + let test_args = TestContext { + sender: KusamaSender::get(), + receiver: AssetHubKusamaReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Kusama>(relay_origin_assertions); + test.set_assertion::<AssetHubKusama>(para_dest_assertions); + test.set_dispatchable::<Kusama>(relay_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } + +/// Limited Teleport of native asset from System Parachain to Relay Chain +/// should work when there is enough balance in Relay Chain's `CheckAccount` +#[test] +fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { + // Dependency - Relay Chain's `CheckAccount` should have enough balance + limited_teleport_native_assets_from_relay_to_system_para_works(); + + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let destination = AssetHubKusama::parent_location(); + let beneficiary_id = KusamaReceiver::get(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: KusamaReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubKusama>(para_origin_assertions); + test.set_assertion::<Kusama>(relay_dest_assertions); + test.set_dispatchable::<AssetHubKusama>(system_para_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +/// Limited Teleport of native asset from System Parachain to Relay Chain +/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +#[test] +fn limited_teleport_native_assets_from_system_para_to_relay_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; + let destination = AssetHubKusama::parent_location().into(); + let beneficiary_id = KusamaReceiver::get().into(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubKusamaSender::get(), + receiver: KusamaReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubKusama>(para_origin_assertions); + test.set_assertion::<Kusama>(relay_dest_assertions_fail); + test.set_dispatchable::<AssetHubKusama>(system_para_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance does not change + assert_eq!(receiver_balance_after, receiver_balance_before); +} + +/// Teleport of native asset from Relay Chain to the System Parachain should work +#[test] +fn teleport_native_assets_from_relay_to_system_para_works() { + // Init values for Relay Chain + let amount_to_send: Balance = KUSAMA_ED * 1000; + let test_args = TestContext { + sender: KusamaSender::get(), + receiver: AssetHubKusamaReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Kusama>(relay_origin_assertions); + test.set_assertion::<AssetHubKusama>(para_dest_assertions); + test.set_dispatchable::<Kusama>(relay_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged + +// Right now it is failing in the Relay Chain with a +// `messageQueue.ProcessingFailed` event `error: Unsupported`. +// The reason is the `Weigher` in `pallet_xcm` is not properly calculating the `remote_weight` +// and it cause an `Overweight` error in `AllowTopLevelPaidExecutionFrom` barrier + +// /// Teleport of native asset from System Parachains to the Relay Chain +// /// should work when there is enough balance in Relay Chain's `CheckAccount` +// #[test] +// fn teleport_native_assets_back_from_system_para_to_relay_works() { +// // Dependency - Relay Chain's `CheckAccount` should have enough balance +// teleport_native_assets_from_relay_to_system_para_works(); + +// // Init values for Relay Chain +// let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; +// let test_args = TestContext { +// sender: AssetHubKusamaSender::get(), +// receiver: KusamaReceiver::get(), +// args: get_para_dispatch_args(amount_to_send), +// }; + +// let mut test = SystemParaToRelayTest::new(test_args); + +// let sender_balance_before = test.sender.balance; +// let receiver_balance_before = test.receiver.balance; + +// test.set_assertion::<AssetHubKusama>(para_origin_assertions); +// test.set_assertion::<Kusama>(relay_dest_assertions); +// test.set_dispatchable::<AssetHubKusama>(system_para_teleport_assets); +// test.assert(); + +// let sender_balance_after = test.sender.balance; +// let receiver_balance_after = test.receiver.balance; + +// // Sender's balance is reduced +// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); +// // Receiver's balance is increased +// assert!(receiver_balance_after > receiver_balance_before); +// } + +// /// Teleport of native asset from System Parachain to Relay Chain +// /// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` +// #[test] +// fn teleport_native_assets_from_system_para_to_relay_fails() { +// // Init values for Relay Chain +// let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; +// let assets = (Parent, amount_to_send).into(); +// +// let test_args = TestContext { +// sender: AssetHubKusamaSender::get(), +// receiver: KusamaReceiver::get(), +// args: system_para_test_args(amount_to_send), +// assets, +// None +// }; + +// let mut test = SystemParaToRelayTest::new(test_args); + +// let sender_balance_before = test.sender.balance; +// let receiver_balance_before = test.receiver.balance; + +// test.set_assertion::<AssetHubKusama>(para_origin_assertions); +// test.set_assertion::<Kusama>(relay_dest_assertions); +// test.set_dispatchable::<AssetHubKusama>(system_para_teleport_assets); +// test.assert(); + +// let sender_balance_after = test.sender.balance; +// let receiver_balance_after = test.receiver.balance; + +// // Sender's balance is reduced +// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); +// // Receiver's balance does not change +// assert_eq!(receiver_balance_after, receiver_balance_before); +// } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/transact.rs deleted file mode 100644 index 65264c25203..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-kusama/src/tests/transact.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. - -use crate::*; - -#[test] -fn transact_sudo_from_relay_to_assets_para() { - // Init tests variables - // Call to be executed in Assets Parachain - const ASSET_ID: u32 = 1; - - let call = <AssetHubKusama as Para>::RuntimeCall::Assets(pallet_assets::Call::< - <AssetHubKusama as Para>::Runtime, - Instance1, - >::force_create { - id: ASSET_ID.into(), - is_sufficient: true, - min_balance: 1000, - owner: AssetHubKusamaSender::get().into(), - }) - .encode() - .into(); - - // XcmPallet send arguments - let sudo_origin = <Kusama as Relay>::RuntimeOrigin::root(); - let assets_para_destination: VersionedMultiLocation = - Kusama::child_location_of(AssetHubKusama::para_id()).into(); - - let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let origin_kind = OriginKind::Superuser; - let check_origin = None; - - let xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit, check_origin }, - Transact { require_weight_at_most, origin_kind, call }, - ])); - - // Send XCM message from Relay Chain - Kusama::execute_with(|| { - assert_ok!(<Kusama as KusamaPallet>::XcmPallet::send( - sudo_origin, - bx!(assets_para_destination), - bx!(xcm), - )); - - type RuntimeEvent = <Kusama as Relay>::RuntimeEvent; - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubKusama::execute_with(|| { - assert!(<AssetHubKusama as AssetHubKusamaPallet>::Assets::asset_exists(ASSET_ID)); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml index b518257b1a5..ceba1820d35 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/Cargo.toml @@ -28,8 +28,9 @@ pallet-xcm = { default-features = false, git = "https://github.com/paritytech/po # Cumulus parachains-common = { path = "../../../../common" } -penpal-runtime = { path = "../../../../runtimes/testing/penpal" } -asset-hub-polkadot-runtime = { path = "../../../../runtimes/assets/asset-hub-polkadot" } +cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../pallets/xcmp-queue" } +cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } # Local xcm-emulator = { default-features = false, path = "../../../../../xcm/xcm-emulator" } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs index 70506d98cbc..9d87458f876 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/lib.rs @@ -16,35 +16,87 @@ pub use codec::Encode; pub use frame_support::{ - assert_ok, instances::Instance1, pallet_prelude::Weight, traits::fungibles::Inspect, + assert_err, assert_ok, + instances::Instance1, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, + traits::{fungibles::Inspect, OriginTrait}, }; pub use integration_tests_common::{ constants::{ accounts::{ALICE, BOB}, + asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, polkadot::ED as POLKADOT_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - AccountId, AssetHubKusama, AssetHubKusamaPallet, AssetHubKusamaReceiver, AssetHubKusamaSender, - AssetHubPolkadot, AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, - BridgeHubKusama, BridgeHubKusamaPallet, BridgeHubKusamaReceiver, BridgeHubKusamaSender, - BridgeHubPolkadot, BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, - Collectives, CollectivesPallet, CollectivesReceiver, CollectivesSender, Kusama, KusamaMockNet, - KusamaPallet, KusamaReceiver, KusamaSender, PenpalKusama, PenpalKusamaReceiver, - PenpalKusamaSender, PenpalPolkadot, PenpalPolkadotReceiver, PenpalPolkadotSender, Polkadot, + lazy_static::lazy_static, + xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubPolkadot, + AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, BridgeHubPolkadot, + BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, Collectives, + CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalPolkadotA, + PenpalPolkadotAPallet, PenpalPolkadotAReceiver, PenpalPolkadotASender, PenpalPolkadotB, + PenpalPolkadotBPallet, PenpalPolkadotBReceiver, PenpalPolkadotBSender, Polkadot, PolkadotMockNet, PolkadotPallet, PolkadotReceiver, PolkadotSender, }; +pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; +pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, - v3::{ - Error, - NetworkId::{Kusama as KusamaId, Polkadot as PolkadotId}, - }, + v3::{Error, NetworkId::Polkadot as PolkadotId}, + DoubleEncoded, }; pub use xcm_emulator::{ assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - Parachain as Para, RelayChain as Relay, TestExt, + AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, TestExternalities, }; +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +// `Assets` pallet index +pub const ASSETS_PALLET_ID: u8 = 50; + +pub type RelayToSystemParaTest = Test<Polkadot, AssetHubPolkadot>; +pub type SystemParaToRelayTest = Test<AssetHubPolkadot, Polkadot>; +pub type SystemParaToParaTest = Test<AssetHubPolkadot, PenpalPolkadotA>; + +/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +pub fn relay_test_args(amount: Balance) -> TestArgs { + TestArgs { + dest: Polkadot::child_location_of(AssetHubPolkadot::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubPolkadotReceiver::get().into(), + } + .into(), + amount, + assets: (Here, amount).into(), + asset_id: None, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + +/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +pub fn system_para_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, + assets: MultiAssets, + asset_id: Option<u32>, +) -> TestArgs { + TestArgs { + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), + amount, + assets, + asset_id, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs new file mode 100644 index 00000000000..e0cb340ddaa --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/hrmp_channels.rs @@ -0,0 +1,201 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +const MAX_CAPACITY: u32 = 8; +const MAX_MESSAGE_SIZE: u32 = 8192; + +/// Opening HRMP channels between Parachains should work +#[test] +fn open_hrmp_channel_between_paras_works() { + // Parchain A init values + let para_a_id = PenpalPolkadotA::para_id(); + let para_a_root_origin = <PenpalPolkadotA as Chain>::RuntimeOrigin::root(); + + // Parachain B init values + let para_b_id = PenpalPolkadotB::para_id(); + let para_b_root_origin = <PenpalPolkadotB as Chain>::RuntimeOrigin::root(); + + let fee_amount = POLKADOT_ED * 1000; + let fund_amount = POLKADOT_ED * 1000_000_000; + + // Fund Parachain's Sovereign accounts to be able to reserve the deposit + let para_a_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, para_a_id); + let para_b_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, para_b_id); + + let relay_destination: VersionedMultiLocation = PenpalPolkadotA::parent_location().into(); + + // ---- Init Open channel from Parachain to System Parachain + let mut call = Polkadot::init_open_channel_call(para_b_id, MAX_CAPACITY, MAX_MESSAGE_SIZE); + let origin_kind = OriginKind::Native; + let native_asset: MultiAsset = (Here, fee_amount).into(); + let beneficiary = Polkadot::sovereign_account_id_of_child_para(para_a_id); + + let mut xcm = xcm_transact_paid_execution(call, origin_kind, native_asset.clone(), beneficiary); + + PenpalPolkadotA::execute_with(|| { + assert_ok!(<PenpalPolkadotA as PenpalPolkadotAPallet>::PolkadotXcm::send( + para_a_root_origin, + bx!(relay_destination.clone()), + bx!(xcm), + )); + }); + + Polkadot::execute_with(|| { + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + Polkadot::assert_ump_queue_processed( + true, + Some(para_a_id), + Some(Weight::from_parts(1_282_426_000, 207_186)), + ); + + assert_expected_events!( + Polkadot, + vec![ + // Parachain's Sovereign account balance is withdrawn to pay XCM fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == para_a_sovereign_account.clone(), + amount: *amount == fee_amount, + }, + // Sender deposit is reserved for Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == para_a_sovereign_account, + }, + // Open channel requested from Para A to Para B + RuntimeEvent::Hrmp( + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested( + sender, recipient, max_capacity, max_message_size + ) + ) => { + sender: *sender == para_a_id.into(), + recipient: *recipient == para_b_id.into(), + max_capacity: *max_capacity == MAX_CAPACITY, + max_message_size: *max_message_size == MAX_MESSAGE_SIZE, + }, + ] + ); + }); + + // ---- Accept Open channel from Parachain to System Parachain + call = Polkadot::accept_open_channel_call(para_a_id); + let beneficiary = Polkadot::sovereign_account_id_of_child_para(para_b_id); + + xcm = xcm_transact_paid_execution(call, origin_kind, native_asset, beneficiary); + + PenpalPolkadotB::execute_with(|| { + assert_ok!(<PenpalPolkadotB as PenpalPolkadotBPallet>::PolkadotXcm::send( + para_b_root_origin, + bx!(relay_destination), + bx!(xcm), + )); + }); + + Polkadot::execute_with(|| { + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + Polkadot::assert_ump_queue_processed( + true, + Some(para_b_id), + Some(Weight::from_parts(1_282_426_000, 207_186)), + ); + + assert_expected_events!( + Polkadot, + vec![ + // Parachain's Sovereign account balance is withdrawn to pay XCM fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == para_b_sovereign_account.clone(), + amount: *amount == fee_amount, + }, + // Sender deposit is reserved for Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == para_b_sovereign_account, + }, + // Open channel accepted for Para A to Para B + RuntimeEvent::Hrmp( + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted( + sender, recipient + ) + ) => { + sender: *sender == para_a_id.into(), + recipient: *recipient == para_b_id.into(), + }, + ] + ); + }); + + Polkadot::force_process_hrmp_open(para_a_id, para_b_id); +} + +/// Opening HRMP channels between System Parachains and Parachains should work +#[test] +fn force_open_hrmp_channel_for_system_para_works() { + // Relay Chain init values + let relay_root_origin = <Polkadot as Chain>::RuntimeOrigin::root(); + + // System Para init values + let system_para_id = AssetHubPolkadot::para_id(); + + // Parachain A init values + let para_a_id = PenpalPolkadotA::para_id(); + + let fund_amount = POLKADOT_ED * 1000_000_000; + + // Fund Parachain's Sovereign accounts to be able to reserve the deposit + let system_para_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, system_para_id); + let para_a_sovereign_account = Polkadot::fund_para_sovereign(fund_amount, para_a_id); + + Polkadot::execute_with(|| { + assert_ok!(<Polkadot as PolkadotPallet>::Hrmp::force_open_hrmp_channel( + relay_root_origin, + system_para_id, + para_a_id, + MAX_CAPACITY, + MAX_MESSAGE_SIZE + )); + + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + assert_expected_events!( + Polkadot, + vec![ + // Sender deposit is reserved for System Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == system_para_sovereign_account, + }, + // Recipient deposit is reserved for Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Reserved { who, .. }) =>{ + who: *who == para_a_sovereign_account, + }, + // HRMP channel forced opened + RuntimeEvent::Hrmp( + polkadot_runtime_parachains::hrmp::Event::HrmpChannelForceOpened( + sender, recipient, max_capacity, max_message_size + ) + ) => { + sender: *sender == system_para_id.into(), + recipient: *recipient == para_a_id.into(), + max_capacity: *max_capacity == MAX_CAPACITY, + max_message_size: *max_message_size == MAX_MESSAGE_SIZE, + }, + ] + ); + }); + + Polkadot::force_process_hrmp_open(system_para_id, para_a_id); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs index 44861d2a872..00e0a663e47 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. +mod hrmp_channels; mod reserve_transfer; +mod send; +mod set_xcm_versions; mod teleport; -mod transact; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs index ffe9bac86d5..6b1ecde6a14 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs @@ -16,66 +16,395 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + Polkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(629_384_000, 6_196))); + + assert_expected_events!( + Polkadot, + vec![ + // Amount to reserve transfer is transferred to System Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { + from: *from == t.sender.account_id, + to: *to == Polkadot::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { + AssetHubPolkadot::assert_dmp_queue_incomplete( + Some(Weight::from_parts(1_000_000_000, 0)), + Some(Error::UntrustedReserveLocation), + ); +} + +fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { + AssetHubPolkadot::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) +} + +fn system_para_to_para_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 676_119_000, + 6196, + ))); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereing account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == AssetHubPolkadot::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 676_119_000, + 6196, + ))); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereing account + RuntimeEvent::Assets( + pallet_assets::Event::Transferred { asset_id, from, to, amount } + ) => { + asset_id: *asset_id == ASSET_ID, + from: *from == t.sender.account_id, + to: *to == AssetHubPolkadot::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Polkadot as PolkadotPallet>::XcmPallet::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Polkadot as PolkadotPallet>::XcmPallet::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_assets() { - // Init tests variables - let amount = POLKADOT_ED * 1000; - let relay_sender_balance_before = Polkadot::account_data_of(PolkadotSender::get()).free; - let para_receiver_balance_before = - AssetHubPolkadot::account_data_of(AssetHubPolkadotReceiver::get()).free; - - let origin = <Polkadot as Relay>::RuntimeOrigin::signed(PolkadotSender::get()); - let assets_para_destination: VersionedMultiLocation = - Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); - let beneficiary: VersionedMultiLocation = - AccountId32 { network: None, id: AssetHubPolkadotReceiver::get().into() }.into(); - let native_assets: VersionedMultiAssets = (Here, amount).into(); - let fee_asset_item = 0; - let weight_limit = WeightLimit::Unlimited; - - // Send XCM message from Relay Chain - Polkadot::execute_with(|| { - assert_ok!(<Polkadot as PolkadotPallet>::XcmPallet::limited_reserve_transfer_assets( - origin, - bx!(assets_para_destination), - bx!(beneficiary), - bx!(native_assets), - fee_asset_item, - weight_limit, - )); - - type RuntimeEvent = <Polkadot as Relay>::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => { - weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(686_043_000, 6196), *weight), - }, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = <AssetHubPolkadot as Para>::RuntimeEvent; - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Incomplete(_, Error::UntrustedReserveLocation), - .. - }) => {}, - ] - ); - }); - - // Check if balances are updated accordingly in Relay Chain and Assets Parachain - let relay_sender_balance_after = Polkadot::account_data_of(PolkadotSender::get()).free; - let para_sender_balance_after = - AssetHubPolkadot::account_data_of(AssetHubPolkadotReceiver::get()).free; - - assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); - assert_eq!(para_sender_balance_after, para_receiver_balance_before); +fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = POLKADOT_ED * 1000; + let test_args = TestContext { + sender: PolkadotSender::get(), + receiver: AssetHubPolkadotReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Polkadot>(relay_origin_assertions); + test.set_assertion::<AssetHubPolkadot>(system_para_dest_assertions_incomplete); + test.set_dispatchable::<Polkadot>(relay_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work +#[test] +fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { + // Init values for System Parachain + let destination = AssetHubPolkadot::parent_location(); + let beneficiary_id = PolkadotReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PolkadotReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubPolkadot>(system_para_to_relay_assertions); + test.set_dispatchable::<AssetHubPolkadot>(system_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +#[test] +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = POLKADOT_ED * 1000; + let test_args = TestContext { + sender: PolkadotSender::get(), + receiver: AssetHubPolkadotReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Polkadot>(relay_origin_assertions); + test.set_assertion::<AssetHubPolkadot>(system_para_dest_assertions_incomplete); + test.set_dispatchable::<Polkadot>(relay_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +#[test] +fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { + // Init values for System Parachain + let destination = AssetHubPolkadot::parent_location(); + let beneficiary_id = PolkadotReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PolkadotReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubPolkadot>(system_para_to_relay_assertions); + test.set_dispatchable::<AssetHubPolkadot>(system_para_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work +#[test] +fn limited_reserve_transfer_native_asset_from_system_para_to_para() { + // Init values for System Parachain + let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); + let beneficiary_id = PenpalPolkadotAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PenpalPolkadotAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + + test.set_assertion::<AssetHubPolkadot>(system_para_to_para_assertions); + // TODO: Add assertion for Penpal runtime. Right now message is failing with `UntrustedReserveLocation` + test.set_dispatchable::<AssetHubPolkadot>(system_para_to_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve transfers +} + +/// Reserve Transfers of native asset from System Parachain to Parachain should work +#[test] +fn reserve_transfer_native_asset_from_system_para_to_para() { + // Init values for System Parachain + let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); + let beneficiary_id = PenpalPolkadotAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PenpalPolkadotAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + + test.set_assertion::<AssetHubPolkadot>(system_para_to_para_assertions); + // TODO: Add assertion for Penpal runtime. Right now message is failing with `UntrustedReserveLocation` + test.set_dispatchable::<AssetHubPolkadot>(system_para_to_para_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve transfers +} + +/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work +#[test] +fn limited_reserve_transfer_asset_from_system_para_to_para() { + // Force create asset from Relay Chain and mint assets for System Parachain's sender account + AssetHubPolkadot::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubPolkadotSender::get(), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); + let beneficiary_id = PenpalPolkadotAReceiver::get(); + let amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) + .into(); + + let system_para_test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PenpalPolkadotAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + + system_para_test.set_assertion::<AssetHubPolkadot>(system_para_to_para_assets_assertions); + // TODO: Add assertions when Penpal is able to manage assets + system_para_test + .set_dispatchable::<AssetHubPolkadot>(system_para_to_para_limited_reserve_transfer_assets); + system_para_test.assert(); +} + +/// Reserve Transfers of a local asset from System Parachain to Parachain should work +#[test] +fn reserve_transfer_asset_from_system_para_to_para() { + // Force create asset from Relay Chain and mint assets for System Parachain's sender account + AssetHubPolkadot::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubPolkadotSender::get(), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + let destination = AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()); + let beneficiary_id = PenpalPolkadotAReceiver::get(); + let amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) + .into(); + + let system_para_test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PenpalPolkadotAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + + system_para_test.set_assertion::<AssetHubPolkadot>(system_para_to_para_assets_assertions); + // TODO: Add assertions when Penpal is able to manage assets + system_para_test + .set_dispatchable::<AssetHubPolkadot>(system_para_to_para_reserve_transfer_assets); + system_para_test.assert(); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs new file mode 100644 index 00000000000..ef34d1b4337 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/send.rs @@ -0,0 +1,202 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +/// Relay Chain should be able to execute `Transact` instructions in System Parachain +/// when `OriginKind::Superuser` and signer is `sudo` +#[test] +fn send_transact_sudo_from_relay_to_system_para_works() { + // Init tests variables + let root_origin = <Polkadot as Chain>::RuntimeOrigin::root(); + let system_para_destination = Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); + let asset_owner: AccountId = AssetHubPolkadotSender::get().into(); + let xcm = AssetHubPolkadot::force_create_asset_xcm( + OriginKind::Superuser, + ASSET_ID, + asset_owner.clone(), + true, + 1000, + ); + // Send XCM message from Relay Chain + Polkadot::execute_with(|| { + assert_ok!(<Polkadot as PolkadotPallet>::XcmPallet::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + Polkadot::assert_xcm_pallet_sent(); + }); + + // Receive XCM message in Assets Parachain + AssetHubPolkadot::execute_with(|| { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts( + 1_019_445_000, + 200_000, + ))); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == asset_owner, + }, + ] + ); + + assert!(<AssetHubPolkadot as AssetHubPolkadotPallet>::Assets::asset_exists(ASSET_ID)); + }); +} + +/// Relay Chain shouldn't be able to execute `Transact` instructions in System Parachain +/// when `OriginKind::Native` +#[test] +fn send_transact_native_from_relay_to_system_para_fails() { + // Init tests variables + let signed_origin = <Polkadot as Chain>::RuntimeOrigin::signed(PolkadotSender::get().into()); + let system_para_destination = Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); + let asset_owner = AssetHubPolkadotSender::get().into(); + let xcm = AssetHubPolkadot::force_create_asset_xcm( + OriginKind::Native, + ASSET_ID, + asset_owner, + true, + 1000, + ); + + // Send XCM message from Relay Chain + Polkadot::execute_with(|| { + assert_err!( + <Polkadot as PolkadotPallet>::XcmPallet::send( + signed_origin, + bx!(system_para_destination), + bx!(xcm) + ), + DispatchError::BadOrigin + ); + }); +} + +/// System Parachain shouldn't be able to execute `Transact` instructions in Relay Chain +/// when `OriginKind::Native` +#[test] +fn send_transact_native_from_system_para_to_relay_fails() { + // Init tests variables + let signed_origin = + <AssetHubPolkadot as Chain>::RuntimeOrigin::signed(AssetHubPolkadotSender::get().into()); + let relay_destination = AssetHubPolkadot::parent_location().into(); + let call = <Polkadot as Chain>::RuntimeCall::System(frame_system::Call::< + <Polkadot as Chain>::Runtime, + >::remark_with_event { + remark: vec![0, 1, 2, 3], + }) + .encode() + .into(); + let origin_kind = OriginKind::Native; + + let xcm = xcm_transact_unpaid_execution(call, origin_kind); + + // Send XCM message from Relay Chain + AssetHubPolkadot::execute_with(|| { + assert_err!( + <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::send( + signed_origin, + bx!(relay_destination), + bx!(xcm) + ), + DispatchError::BadOrigin + ); + }); +} + +/// Parachain should be able to send XCM paying its fee with sufficient asset +/// in the System Parachain +#[test] +fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { + let para_sovereign_account = AssetHubPolkadot::sovereign_account_id_of( + AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()), + ); + + // Force create and mint assets for Parachain's sovereign account + AssetHubPolkadot::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + para_sovereign_account.clone(), + ASSET_MIN_BALANCE * 1000000000, + ); + + // We just need a call that can pass the `SafeCallFilter` + // Call values are not relevant + let call = AssetHubPolkadot::force_create_asset_call( + ASSET_ID, + para_sovereign_account.clone(), + true, + ASSET_MIN_BALANCE, + ); + + let origin_kind = OriginKind::SovereignAccount; + let fee_amount = ASSET_MIN_BALANCE * 1000000; + let native_asset = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); + + let root_origin = <PenpalPolkadotA as Chain>::RuntimeOrigin::root(); + let system_para_destination = + PenpalPolkadotA::sibling_location_of(AssetHubPolkadot::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + native_asset, + para_sovereign_account.clone(), + ); + + PenpalPolkadotA::execute_with(|| { + assert_ok!(<PenpalPolkadotA as PenpalPolkadotAPallet>::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + AssetHubPolkadot::assert_xcm_pallet_sent(); + }); + + AssetHubPolkadot::execute_with(|| { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_xcmp_queue_success(Some(Weight::from_parts( + 2_176_414_000, + 203_593, + ))); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == para_sovereign_account, + balance: *balance == fee_amount, + }, + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { + asset_id: *asset_id == ASSET_ID, + }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs new file mode 100644 index 00000000000..84abf630e50 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs @@ -0,0 +1,97 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +#[test] +fn relay_sets_system_para_xcm_supported_version() { + // Init tests variables + let sudo_origin = <Polkadot as Chain>::RuntimeOrigin::root(); + let system_para_destination: MultiLocation = + Polkadot::child_location_of(AssetHubPolkadot::para_id()); + + // Relay Chain sets supported version for Asset Parachain + Polkadot::execute_with(|| { + assert_ok!(<Polkadot as PolkadotPallet>::XcmPallet::force_xcm_version( + sudo_origin, + bx!(system_para_destination), + XCM_V3 + )); + + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { + location, + version: XCM_V3 + }) => { location: *location == system_para_destination, }, + ] + ); + }); +} + +#[test] +fn system_para_sets_relay_xcm_supported_version() { + // Init test variables + let sudo_origin = <Polkadot as Chain>::RuntimeOrigin::root(); + let parent_location = AssetHubPolkadot::parent_location(); + let system_para_destination: VersionedMultiLocation = + Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); + let call = <AssetHubPolkadot as Chain>::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< + <AssetHubPolkadot as Chain>::Runtime, + >::force_xcm_version { + location: bx!(parent_location), + version: XCM_V3, + }) + .encode() + .into(); + let origin_kind = OriginKind::Superuser; + + let xcm = xcm_transact_unpaid_execution(call, origin_kind); + + // System Parachain sets supported version for Relay Chain throught it + Polkadot::execute_with(|| { + assert_ok!(<Polkadot as PolkadotPallet>::XcmPallet::send( + sudo_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + Polkadot::assert_xcm_pallet_sent(); + }); + + // System Parachain receive the XCM message + AssetHubPolkadot::execute_with(|| { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts( + 1_019_210_000, + 200_000, + ))); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { + location, + version: XCM_V3 + }) => { location: *location == parent_location, }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs index 6b799096054..5d40e5d3538 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/teleport.rs @@ -16,63 +16,347 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + Polkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(632_207_000, 7_186))); + + assert_expected_events!( + Polkadot, + vec![ + // Amount to teleport is withdrawn from Sender + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + // Amount to teleport is deposited in Relay's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + who: *who == <Polkadot as PolkadotPallet>::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_dest_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = <Polkadot as Chain>::RuntimeEvent; + + Polkadot::assert_ump_queue_processed( + true, + Some(AssetHubPolkadot::para_id()), + Some(Weight::from_parts(368_931_000, 7_186)), + ); + + assert_expected_events!( + Polkadot, + vec![ + // Amount is witdrawn from Relay Chain's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == <Polkadot as PolkadotPallet>::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + // Amount minus fees are deposited in Receiver's account + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { + Polkadot::assert_ump_queue_processed( + false, + Some(AssetHubPolkadot::para_id()), + Some(Weight::from_parts(232_982_000, 3_593)), + ); +} + +fn para_origin_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 632_207_000, + 7_186, + ))); + + AssetHubPolkadot::assert_parachain_system_ump_sent(); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + // Amount is withdrawn from Sender's account + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_dest_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; + + AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts(161_196_000, 0))); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + // Amount minus fees are deposited in Receiver's account + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Polkadot as PolkadotPallet>::XcmPallet::limited_teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Polkadot as PolkadotPallet>::XcmPallet::teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::limited_teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged +// fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { +// <AssetHubPolkadot as AssetHubPolkadotPallet>::PolkadotXcm::teleport_assets( +// t.signed_origin, +// bx!(t.args.dest), +// bx!(t.args.beneficiary), +// bx!(t.args.assets), +// t.args.fee_asset_item, +// ) +// } + +/// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] -fn teleport_native_assets_from_relay_to_assets_para() { - // Init tests variables - let amount = POLKADOT_ED * 1000; - let relay_sender_balance_before = Polkadot::account_data_of(PolkadotSender::get()).free; - let para_receiver_balance_before = - AssetHubPolkadot::account_data_of(AssetHubPolkadotReceiver::get()).free; - - let origin = <Polkadot as Relay>::RuntimeOrigin::signed(PolkadotSender::get()); - let assets_para_destination: VersionedMultiLocation = - Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); - let beneficiary: VersionedMultiLocation = - AccountId32 { network: None, id: AssetHubPolkadotReceiver::get().into() }.into(); - let native_assets: VersionedMultiAssets = (Here, amount).into(); - let fee_asset_item = 0; - let weight_limit = WeightLimit::Unlimited; - - // Send XCM message from Relay Chain - Polkadot::execute_with(|| { - assert_ok!(<Polkadot as PolkadotPallet>::XcmPallet::limited_teleport_assets( - origin, - bx!(assets_para_destination), - bx!(beneficiary), - bx!(native_assets), - fee_asset_item, - weight_limit, - )); - - type RuntimeEvent = <Polkadot as Relay>::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = <AssetHubPolkadot as Para>::RuntimeEvent; - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { - who: *who == AssetHubPolkadotReceiver::get().into(), - }, - ] - ); - }); - - // Check if balances are updated accordingly in Relay Chain and Assets Parachain - let relay_sender_balance_after = Polkadot::account_data_of(PolkadotSender::get()).free; - let para_sender_balance_after = - AssetHubPolkadot::account_data_of(AssetHubPolkadotReceiver::get()).free; - - assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); - assert!(para_sender_balance_after > para_receiver_balance_before); +fn limited_teleport_native_assets_from_relay_to_system_para_works() { + // Init values for Relay Chain + let amount_to_send: Balance = POLKADOT_ED * 1000; + let test_args = TestContext { + sender: PolkadotSender::get(), + receiver: AssetHubPolkadotReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Polkadot>(relay_origin_assertions); + test.set_assertion::<AssetHubPolkadot>(para_dest_assertions); + test.set_dispatchable::<Polkadot>(relay_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } + +/// Limited Teleport of native asset from System Parachain to Relay Chain +/// should work when there is enough balance in Relay Chain's `CheckAccount` +#[test] +fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { + // Dependency - Relay Chain's `CheckAccount` should have enough balance + limited_teleport_native_assets_from_relay_to_system_para_works(); + + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; + let destination = AssetHubPolkadot::parent_location(); + let beneficiary_id = PolkadotReceiver::get(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PolkadotReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubPolkadot>(para_origin_assertions); + test.set_assertion::<Polkadot>(relay_dest_assertions); + test.set_dispatchable::<AssetHubPolkadot>(system_para_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +/// Limited Teleport of native asset from System Parachain to Relay Chain +/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +#[test] +fn limited_teleport_native_assets_from_system_para_to_relay_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; + let destination = AssetHubPolkadot::parent_location().into(); + let beneficiary_id = PolkadotReceiver::get().into(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubPolkadotSender::get(), + receiver: PolkadotReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubPolkadot>(para_origin_assertions); + test.set_assertion::<Polkadot>(relay_dest_assertions_fail); + test.set_dispatchable::<AssetHubPolkadot>(system_para_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance does not change + assert_eq!(receiver_balance_after, receiver_balance_before); +} + +/// Teleport of native asset from Relay Chain to the System Parachain should work +#[test] +fn teleport_native_assets_from_relay_to_system_para_works() { + // Init values for Relay Chain + let amount_to_send: Balance = POLKADOT_ED * 1000; + let test_args = TestContext { + sender: PolkadotSender::get(), + receiver: AssetHubPolkadotReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Polkadot>(relay_origin_assertions); + test.set_assertion::<AssetHubPolkadot>(para_dest_assertions); + test.set_dispatchable::<Polkadot>(relay_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged + +// Right now it is failing in the Relay Chain with a +// `messageQueue.ProcessingFailed` event `error: Unsupported`. +// The reason is the `Weigher` in `pallet_xcm` is not properly calculating the `remote_weight` +// and it cause an `Overweight` error in `AllowTopLevelPaidExecutionFrom` barrier + +// /// Teleport of native asset from System Parachains to the Relay Chain +// /// should work when there is enough balance in Relay Chain's `CheckAccount` +// #[test] +// fn teleport_native_assets_back_from_system_para_to_relay_works() { +// // Dependency - Relay Chain's `CheckAccount` should have enough balance +// teleport_native_assets_from_relay_to_system_para_works(); + +// // Init values for Relay Chain +// let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; +// let test_args = TestContext { +// sender: AssetHubPolkadotSender::get(), +// receiver: PolkadotReceiver::get(), +// args: get_para_dispatch_args(amount_to_send), +// }; + +// let mut test = SystemParaToRelayTest::new(test_args); + +// let sender_balance_before = test.sender.balance; +// let receiver_balance_before = test.receiver.balance; + +// test.set_assertion::<AssetHubPolkadot>(para_origin_assertions); +// test.set_assertion::<Polkadot>(relay_dest_assertions); +// test.set_dispatchable::<AssetHubPolkadot>(system_para_teleport_assets); +// test.assert(); + +// let sender_balance_after = test.sender.balance; +// let receiver_balance_after = test.receiver.balance; + +// // Sender's balance is reduced +// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); +// // Receiver's balance is increased +// assert!(receiver_balance_after > receiver_balance_before); +// } + +// /// Teleport of native asset from System Parachain to Relay Chain +// /// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` +// #[test] +// fn teleport_native_assets_from_system_para_to_relay_fails() { +// // Init values for Relay Chain +// let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; +// let assets = (Parent, amount_to_send).into(); +// +// let test_args = TestContext { +// sender: AssetHubPolkadotSender::get(), +// receiver: PolkadotReceiver::get(), +// args: system_para_test_args(amount_to_send), +// assets, +// None +// }; + +// let mut test = SystemParaToRelayTest::new(test_args); + +// let sender_balance_before = test.sender.balance; +// let receiver_balance_before = test.receiver.balance; + +// test.set_assertion::<AssetHubPolkadot>(para_origin_assertions); +// test.set_assertion::<Polkadot>(relay_dest_assertions); +// test.set_dispatchable::<AssetHubPolkadot>(system_para_teleport_assets); +// test.assert(); + +// let sender_balance_after = test.sender.balance; +// let receiver_balance_after = test.receiver.balance; + +// // Sender's balance is reduced +// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); +// // Receiver's balance does not change +// assert_eq!(receiver_balance_after, receiver_balance_before); +// } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/transact.rs deleted file mode 100644 index dc2f1e87d4b..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-polkadot/src/tests/transact.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. - -use crate::*; - -#[test] -fn transact_sudo_from_relay_to_assets_para() { - // Init tests variables - // Call to be executed in Assets Parachain - const ASSET_ID: u32 = 1; - - let call = <AssetHubPolkadot as Para>::RuntimeCall::Assets(pallet_assets::Call::< - <AssetHubPolkadot as Para>::Runtime, - Instance1, - >::force_create { - id: ASSET_ID.into(), - is_sufficient: true, - min_balance: 1000, - owner: AssetHubPolkadotSender::get().into(), - }) - .encode() - .into(); - - // XcmPallet send arguments - let sudo_origin = <Polkadot as Relay>::RuntimeOrigin::root(); - let assets_para_destination: VersionedMultiLocation = - Polkadot::child_location_of(AssetHubPolkadot::para_id()).into(); - - let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let origin_kind = OriginKind::Superuser; - let check_origin = None; - - let xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit, check_origin }, - Transact { require_weight_at_most, origin_kind, call }, - ])); - - // Send XCM message from Relay Chain - Polkadot::execute_with(|| { - assert_ok!(<Polkadot as PolkadotPallet>::XcmPallet::send( - sudo_origin, - bx!(assets_para_destination), - bx!(xcm), - )); - - type RuntimeEvent = <Polkadot as Relay>::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubPolkadot::execute_with(|| { - assert!(<AssetHubPolkadot as AssetHubPolkadotPallet>::Assets::asset_exists(ASSET_ID)); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml index 8e9b1dd6603..6b2bb18ae8b 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/Cargo.toml @@ -24,15 +24,16 @@ polkadot-core-primitives = { default-features = false, git = "https://github.com polkadot-parachain = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "master" } -westend-runtime = { git = "https://github.com/paritytech/polkadot", branch = "master" } xcm = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } xcm-executor = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } pallet-xcm = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } # Cumulus parachains-common = { path = "../../../../common" } -penpal-runtime = { path = "../../../../runtimes/testing/penpal" } asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" } +cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../pallets/xcmp-queue" } +cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } # Local xcm-emulator = { default-features = false, path = "../../../../../xcm/xcm-emulator" } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs index e3d33dabaa2..b7f064e7d6e 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/lib.rs @@ -16,31 +16,86 @@ pub use codec::Encode; pub use frame_support::{ - assert_ok, instances::Instance1, pallet_prelude::Weight, traits::fungibles::Inspect, + assert_err, assert_ok, + instances::{Instance1, Instance2}, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchError, DispatchResult, ModuleError, MultiAddress}, + traits::{fungibles::Inspect, OriginTrait}, + BoundedVec, }; pub use integration_tests_common::{ constants::{ accounts::{ALICE, BOB}, - polkadot::ED as POLKADOT_ED, + asset_hub_westend::ED as ASSET_HUB_WESTEND_ED, + westend::ED as WESTEND_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - AccountId, AssetHubWestend, AssetHubWestendPallet, AssetHubWestendReceiver, - AssetHubWestendSender, Collectives, CollectivesPallet, CollectivesReceiver, CollectivesSender, - PenpalWestend, PenpalWestendPallet, PenpalWestendReceiver, PenpalWestendSender, Westend, + lazy_static::lazy_static, + xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubWestend, + AssetHubWestendPallet, AssetHubWestendReceiver, AssetHubWestendSender, Collectives, + CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalWestendA, + PenpalWestendAPallet, PenpalWestendAReceiver, PenpalWestendASender, Westend, WestendMockNet, WestendPallet, WestendReceiver, WestendSender, }; +pub use parachains_common::{AccountId, Balance}; pub use polkadot_core_primitives::InboundDownwardMessage; +pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, - v3::{ - Error, - NetworkId::{Kusama as KusamaId, Polkadot as PolkadotId}, - }, + v3::{Error, NetworkId::Westend as WestendId}, + DoubleEncoded, }; pub use xcm_emulator::{ assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - Parachain as Para, RelayChain as Relay, TestExt, + AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, TestExternalities, }; +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +// `Assets` pallet index +pub const ASSETS_PALLET_ID: u8 = 50; + +pub type RelayToSystemParaTest = Test<Westend, AssetHubWestend>; +pub type SystemParaToRelayTest = Test<AssetHubWestend, Westend>; +pub type SystemParaToParaTest = Test<AssetHubWestend, PenpalWestendA>; + +/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +pub fn relay_test_args(amount: Balance) -> TestArgs { + TestArgs { + dest: Westend::child_location_of(AssetHubWestend::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubWestendReceiver::get().into(), + } + .into(), + amount, + assets: (Here, amount).into(), + asset_id: None, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + +/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +pub fn system_para_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, + assets: MultiAssets, + asset_id: Option<u32>, +) -> TestArgs { + TestArgs { + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), + amount, + assets, + asset_id, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs index d4e304eb0ff..e45b78da1c2 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/mod.rs @@ -15,6 +15,7 @@ // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. mod reserve_transfer; +mod send; +mod set_xcm_versions; mod swap; mod teleport; -mod transact; diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 7ef76efdfed..430c203edd8 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -16,66 +16,395 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <Westend as Chain>::RuntimeEvent; + + Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(629_384_000, 6_196))); + + assert_expected_events!( + Westend, + vec![ + // Amount to reserve transfer is transferred to System Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { + from: *from == t.sender.account_id, + to: *to == Westend::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { + AssetHubWestend::assert_dmp_queue_incomplete( + Some(Weight::from_parts(1_000_000_000, 0)), + Some(Error::UntrustedReserveLocation), + ); +} + +fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { + AssetHubWestend::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier)) +} + +fn system_para_to_para_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 676_119_000, + 6196, + ))); + + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereing account + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == AssetHubWestend::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 676_119_000, + 6196, + ))); + + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereing account + RuntimeEvent::Assets( + pallet_assets::Event::Transferred { asset_id, from, to, amount } + ) => { + asset_id: *asset_id == ASSET_ID, + from: *from == t.sender.account_id, + to: *to == AssetHubWestend::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Westend as WestendPallet>::XcmPallet::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Westend as WestendPallet>::XcmPallet::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] -fn reserve_transfer_native_asset_from_relay_to_assets() { - // Init tests variables - let amount = POLKADOT_ED * 1000; - let relay_sender_balance_before = Westend::account_data_of(WestendSender::get()).free; - let para_receiver_balance_before = - AssetHubWestend::account_data_of(AssetHubWestendReceiver::get()).free; - - let origin = <Westend as Relay>::RuntimeOrigin::signed(WestendSender::get()); - let assets_para_destination: VersionedMultiLocation = - Westend::child_location_of(AssetHubWestend::para_id()).into(); - let beneficiary: VersionedMultiLocation = - AccountId32 { network: None, id: AssetHubWestendReceiver::get().into() }.into(); - let native_assets: VersionedMultiAssets = (Here, amount).into(); - let fee_asset_item = 0; - let weight_limit = WeightLimit::Unlimited; - - // Send XCM message from Relay Chain - Westend::execute_with(|| { - assert_ok!(<Westend as WestendPallet>::XcmPallet::limited_reserve_transfer_assets( - origin, - bx!(assets_para_destination), - bx!(beneficiary), - bx!(native_assets), - fee_asset_item, - weight_limit, - )); - - type RuntimeEvent = <Westend as Relay>::RuntimeEvent; - - assert_expected_events!( - Westend, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => { - weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(629_384_000, 6196), *weight), - }, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubWestend::execute_with(|| { - type RuntimeEvent = <AssetHubWestend as Para>::RuntimeEvent; - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { - outcome: Outcome::Incomplete(_, Error::UntrustedReserveLocation), - .. - }) => {}, - ] - ); - }); - - // Check if balances are updated accordingly in Relay Chain and Assets Parachain - let relay_sender_balance_after = Westend::account_data_of(WestendSender::get()).free; - let para_sender_balance_after = - AssetHubWestend::account_data_of(AssetHubWestendReceiver::get()).free; - - assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); - assert_eq!(para_sender_balance_after, para_receiver_balance_before); +fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = WESTEND_ED * 1000; + let test_args = TestContext { + sender: WestendSender::get(), + receiver: AssetHubWestendReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Westend>(relay_origin_assertions); + test.set_assertion::<AssetHubWestend>(system_para_dest_assertions_incomplete); + test.set_dispatchable::<Westend>(relay_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work +#[test] +fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() { + // Init values for System Parachain + let destination = AssetHubWestend::parent_location(); + let beneficiary_id = WestendReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: WestendReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubWestend>(system_para_to_relay_assertions); + test.set_dispatchable::<AssetHubWestend>(system_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work +#[test] +fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = WESTEND_ED * 1000; + let test_args = TestContext { + sender: WestendSender::get(), + receiver: AssetHubWestendReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Westend>(relay_origin_assertions); + test.set_assertion::<AssetHubWestend>(system_para_dest_assertions_incomplete); + test.set_dispatchable::<Westend>(relay_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work +#[test] +fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { + // Init values for System Parachain + let destination = AssetHubWestend::parent_location(); + let beneficiary_id = WestendReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: WestendReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubWestend>(system_para_to_relay_assertions); + test.set_dispatchable::<AssetHubWestend>(system_para_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + assert_eq!(sender_balance_before, sender_balance_after); + assert_eq!(receiver_balance_before, receiver_balance_after); +} + +/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work +#[test] +fn limited_reserve_transfer_native_asset_from_system_para_to_para() { + // Init values for System Parachain + let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); + let beneficiary_id = PenpalWestendAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: PenpalWestendAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + + test.set_assertion::<AssetHubWestend>(system_para_to_para_assertions); + // TODO: Add assertion for Penpal runtime. Right now message is failing with `UntrustedReserveLocation` + test.set_dispatchable::<AssetHubWestend>(system_para_to_para_limited_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve transfers +} + +/// Reserve Transfers of native asset from System Parachain to Parachain should work +#[test] +fn reserve_transfer_native_asset_from_system_para_to_para() { + // Init values for System Parachain + let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); + let beneficiary_id = PenpalWestendAReceiver::get(); + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: PenpalWestendAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + + test.set_assertion::<AssetHubWestend>(system_para_to_para_assertions); + // TODO: Add assertion for Penpal runtime. Right now message is failing with `UntrustedReserveLocation` + test.set_dispatchable::<AssetHubWestend>(system_para_to_para_reserve_transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve transfers +} + +/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work +#[test] +fn limited_reserve_transfer_asset_from_system_para_to_para() { + // Force create asset from Relay Chain and mint assets for System Parachain's sender account + AssetHubWestend::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubWestendSender::get(), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); + let beneficiary_id = PenpalWestendAReceiver::get(); + let amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) + .into(); + + let system_para_test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: PenpalWestendAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + + system_para_test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_assertions); + // TODO: Add assertions when Penpal is able to manage assets + system_para_test + .set_dispatchable::<AssetHubWestend>(system_para_to_para_limited_reserve_transfer_assets); + system_para_test.assert(); +} + +/// Reserve Transfers of a local asset from System Parachain to Parachain should work +#[test] +fn reserve_transfer_asset_from_system_para_to_para() { + // Force create asset from Relay Chain and mint assets for System Parachain's sender account + AssetHubWestend::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + AssetHubWestendSender::get(), + ASSET_MIN_BALANCE * 1000000, + ); + + // Init values for System Parachain + let destination = AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()); + let beneficiary_id = PenpalWestendAReceiver::get(); + let amount_to_send = ASSET_MIN_BALANCE * 1000; + let assets = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) + .into(); + + let system_para_test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: PenpalWestendAReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); + + system_para_test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_assertions); + // TODO: Add assertions when Penpal is able to manage assets + system_para_test + .set_dispatchable::<AssetHubWestend>(system_para_to_para_reserve_transfer_assets); + system_para_test.assert(); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs new file mode 100644 index 00000000000..24301fe1c7d --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/send.rs @@ -0,0 +1,141 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +/// Relay Chain should be able to execute `Transact` instructions in System Parachain +/// when `OriginKind::Superuser` and signer is `sudo` +#[test] +fn send_transact_sudo_from_relay_to_system_para_works() { + // Init tests variables + let root_origin = <Westend as Chain>::RuntimeOrigin::root(); + let system_para_destination = Westend::child_location_of(AssetHubWestend::para_id()).into(); + let asset_owner: AccountId = AssetHubWestendSender::get().into(); + let xcm = AssetHubWestend::force_create_asset_xcm( + OriginKind::Superuser, + ASSET_ID, + asset_owner.clone(), + true, + 1000, + ); + // Send XCM message from Relay Chain + Westend::execute_with(|| { + assert_ok!(<Westend as WestendPallet>::XcmPallet::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + Westend::assert_xcm_pallet_sent(); + }); + + // Receive XCM message in Assets Parachain + AssetHubWestend::execute_with(|| { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts( + 1_019_445_000, + 200_000, + ))); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == asset_owner, + }, + ] + ); + + assert!(<AssetHubWestend as AssetHubWestendPallet>::Assets::asset_exists(ASSET_ID)); + }); +} + +/// Parachain should be able to send XCM paying its fee with sufficient asset +/// in the System Parachain +#[test] +fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { + let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()), + ); + + // Force create and mint assets for Parachain's sovereign account + AssetHubWestend::force_create_and_mint_asset( + ASSET_ID, + ASSET_MIN_BALANCE, + true, + para_sovereign_account.clone(), + ASSET_MIN_BALANCE * 1000000000, + ); + + // We just need a call that can pass the `SafeCallFilter` + // Call values are not relevant + let call = AssetHubWestend::force_create_asset_call( + ASSET_ID, + para_sovereign_account.clone(), + true, + ASSET_MIN_BALANCE, + ); + + let origin_kind = OriginKind::SovereignAccount; + let fee_amount = ASSET_MIN_BALANCE * 1000000; + let native_asset = + (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into(); + + let root_origin = <PenpalWestendA as Chain>::RuntimeOrigin::root(); + let system_para_destination = + PenpalWestendA::sibling_location_of(AssetHubWestend::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + native_asset, + para_sovereign_account.clone(), + ); + + PenpalWestendA::execute_with(|| { + assert_ok!(<PenpalWestendA as PenpalWestendAPallet>::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + AssetHubWestend::assert_xcm_pallet_sent(); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( + 2_176_414_000, + 203_593, + ))); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == ASSET_ID, + owner: *owner == para_sovereign_account, + balance: *balance == fee_amount, + }, + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { + asset_id: *asset_id == ASSET_ID, + }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs new file mode 100644 index 00000000000..76e38083659 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/set_xcm_versions.rs @@ -0,0 +1,97 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. + +use crate::*; + +#[test] +fn relay_sets_system_para_xcm_supported_version() { + // Init tests variables + let sudo_origin = <Westend as Chain>::RuntimeOrigin::root(); + let system_para_destination: MultiLocation = + Westend::child_location_of(AssetHubWestend::para_id()); + + // Relay Chain sets supported version for Asset Parachain + Westend::execute_with(|| { + assert_ok!(<Westend as WestendPallet>::XcmPallet::force_xcm_version( + sudo_origin, + bx!(system_para_destination), + XCM_V3 + )); + + type RuntimeEvent = <Westend as Chain>::RuntimeEvent; + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { + location, + version: XCM_V3 + }) => { location: *location == system_para_destination, }, + ] + ); + }); +} + +#[test] +fn system_para_sets_relay_xcm_supported_version() { + // Init test variables + let sudo_origin = <Westend as Chain>::RuntimeOrigin::root(); + let parent_location = AssetHubWestend::parent_location(); + let system_para_destination: VersionedMultiLocation = + Westend::child_location_of(AssetHubWestend::para_id()).into(); + let call = <AssetHubWestend as Chain>::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< + <AssetHubWestend as Chain>::Runtime, + >::force_xcm_version { + location: bx!(parent_location), + version: XCM_V3, + }) + .encode() + .into(); + let origin_kind = OriginKind::Superuser; + + let xcm = xcm_transact_unpaid_execution(call, origin_kind); + + // System Parachain sets supported version for Relay Chain throught it + Westend::execute_with(|| { + assert_ok!(<Westend as WestendPallet>::XcmPallet::send( + sudo_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + Westend::assert_xcm_pallet_sent(); + }); + + // System Parachain receive the XCM message + AssetHubWestend::execute_with(|| { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts( + 1_019_210_000, + 200_000, + ))); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { + location, + version: XCM_V3 + }) => { location: *location == parent_location, }, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index fabdb9349ef..03ac7514608 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -1,23 +1,18 @@ use crate::*; -use frame_support::{instances::Instance2, BoundedVec}; -use sp_runtime::{DispatchError, ModuleError}; -use xcm_emulator::Parachain; #[test] fn swap_locally_on_chain_using_local_assets() { - const ASSET_ID: u32 = 1; - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); let asset_one = Box::new(MultiLocation { parents: 0, - interior: X2(PalletInstance(50), GeneralIndex(ASSET_ID.into())), + interior: X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), }); AssetHubWestend::execute_with(|| { - type RuntimeEvent = <AssetHubWestend as Parachain>::RuntimeEvent; + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::Assets::create( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), ASSET_ID.into(), AssetHubWestendSender::get().into(), 1000, @@ -25,14 +20,14 @@ fn swap_locally_on_chain_using_local_assets() { assert!(<AssetHubWestend as AssetHubWestendPallet>::Assets::asset_exists(ASSET_ID)); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::Assets::mint( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), ASSET_ID.into(), AssetHubWestendSender::get().into(), 3_000_000_000_000, )); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), asset_one.clone(), )); @@ -45,7 +40,7 @@ fn swap_locally_on_chain_using_local_assets() { ); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::add_liquidity( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), asset_one.clone(), 1_000_000_000_000, @@ -65,7 +60,7 @@ fn swap_locally_on_chain_using_local_assets() { let path = BoundedVec::<_, _>::truncate_from(vec![asset_native.clone(), asset_one.clone()]); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::swap_exact_tokens_for_tokens( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), path, 100, 1, @@ -84,7 +79,7 @@ fn swap_locally_on_chain_using_local_assets() { ); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::remove_liquidity( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native, asset_one, 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. @@ -99,14 +94,13 @@ fn swap_locally_on_chain_using_local_assets() { fn swap_locally_on_chain_using_foreign_assets() { use frame_support::weights::WeightToFee; - const ASSET_ID: u32 = 1; let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation { parents: 1, interior: X3( - Parachain(PenpalWestend::para_id().into()), - PalletInstance(50), + Parachain(PenpalWestendA::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), }); @@ -116,18 +110,18 @@ fn swap_locally_on_chain_using_foreign_assets() { .into(); let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalWestend::para_id().into())) }; + MultiLocation { parents: 1, interior: X1(Parachain(PenpalWestendA::para_id().into())) }; // 1. Create asset on penpal: - PenpalWestend::execute_with(|| { - assert_ok!(<PenpalWestend as PenpalWestendPallet>::Assets::create( - <PenpalWestend as Parachain>::RuntimeOrigin::signed(PenpalWestendSender::get()), + PenpalWestendA::execute_with(|| { + assert_ok!(<PenpalWestendA as PenpalWestendAPallet>::Assets::create( + <PenpalWestendA as Chain>::RuntimeOrigin::signed(PenpalWestendASender::get()), ASSET_ID.into(), - PenpalWestendSender::get().into(), + PenpalWestendASender::get().into(), 1000, )); - assert!(<PenpalWestend as PenpalWestendPallet>::Assets::asset_exists(ASSET_ID)); + assert!(<PenpalWestendA as PenpalWestendAPallet>::Assets::asset_exists(ASSET_ID)); }); // 2. Create foreign asset on asset_hub_westend: @@ -137,21 +131,21 @@ fn swap_locally_on_chain_using_foreign_assets() { let sov_penpal_on_asset_hub_westend = AssetHubWestend::sovereign_account_id_of(penpal_location); AssetHubWestend::fund_accounts(vec![ - (AssetHubWestendSender::get(), 5_000_000), // An account to swap dot for something else. - (sov_penpal_on_asset_hub_westend.clone(), 1000_000_000_000_000_000), + (AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED), + (sov_penpal_on_asset_hub_westend.clone().into(), 1000_000_000_000_000_000 * WESTEND_ED), ]); let sov_penpal_on_asset_hub_westend_as_location: MultiLocation = MultiLocation { parents: 0, - interior: X1(AccountId32 { + interior: X1(AccountId32Junction { network: None, id: sov_penpal_on_asset_hub_westend.clone().into(), }), }; let call_foreign_assets_create = - <AssetHubWestend as Para>::RuntimeCall::ForeignAssets(pallet_assets::Call::< - <AssetHubWestend as Para>::Runtime, + <AssetHubWestend as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::< + <AssetHubWestend as Chain>::Runtime, Instance2, >::create { id: *foreign_asset1_at_asset_hub_westend, @@ -183,18 +177,18 @@ fn swap_locally_on_chain_using_foreign_assets() { ])); // Send XCM message from penpal => asset_hub_westend - let sudo_penpal_origin = <PenpalWestend as Parachain>::RuntimeOrigin::root(); - PenpalWestend::execute_with(|| { - assert_ok!(<PenpalWestend as PenpalWestendPallet>::PolkadotXcm::send( + let sudo_penpal_origin = <PenpalWestendA as Chain>::RuntimeOrigin::root(); + PenpalWestendA::execute_with(|| { + assert_ok!(<PenpalWestendA as PenpalWestendAPallet>::PolkadotXcm::send( sudo_penpal_origin.clone(), bx!(assets_para_destination.clone()), bx!(xcm), )); - type RuntimeEvent = <PenpalWestend as Parachain>::RuntimeEvent; + type RuntimeEvent = <PenpalWestendA as Chain>::RuntimeEvent; assert_expected_events!( - PenpalWestend, + PenpalWestendA, vec![ RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, ] @@ -212,10 +206,10 @@ fn swap_locally_on_chain_using_foreign_assets() { // (While it might be nice to use batch, // currently that's disabled due to safe call filters.) - type RuntimeEvent = <AssetHubWestend as Parachain>::RuntimeEvent; + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; // 3. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::ForeignAssets::mint( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed( + <AssetHubWestend as Chain>::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone().into() ), *foreign_asset1_at_asset_hub_westend, @@ -232,7 +226,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 4. Create pool: assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), foreign_asset1_at_asset_hub_westend.clone(), )); @@ -246,7 +240,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 5. Add liquidity: assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::add_liquidity( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed( + <AssetHubWestend as Chain>::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone() ), asset_native.clone(), @@ -274,7 +268,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ]); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::swap_exact_tokens_for_tokens( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), path, 100000, 1000, @@ -294,7 +288,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 7. Remove liquidity assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::remove_liquidity( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed( + <AssetHubWestend as Chain>::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone() ), asset_native, @@ -309,8 +303,6 @@ fn swap_locally_on_chain_using_foreign_assets() { #[test] fn cannot_create_pool_from_pool_assets() { - const ASSET_ID: u32 = 1; - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); let mut asset_one = asset_hub_westend_runtime::xcm_config::PoolAssetsPalletLocation::get(); asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets"); @@ -319,7 +311,7 @@ fn cannot_create_pool_from_pool_assets() { let pool_owner_account_id = asset_hub_westend_runtime::AssetConversionOrigin::get(); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::PoolAssets::create( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(pool_owner_account_id.clone()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(pool_owner_account_id.clone()), ASSET_ID.into(), pool_owner_account_id.clone().into(), 1000, @@ -327,7 +319,7 @@ fn cannot_create_pool_from_pool_assets() { assert!(<AssetHubWestend as AssetHubWestendPallet>::PoolAssets::asset_exists(ASSET_ID)); assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::PoolAssets::mint( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(pool_owner_account_id), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(pool_owner_account_id), ASSET_ID.into(), AssetHubWestendSender::get().into(), 3_000_000_000_000, @@ -335,7 +327,7 @@ fn cannot_create_pool_from_pool_assets() { assert_matches::assert_matches!( <AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool( - <AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), + <AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), Box::new(asset_one), ), diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs index c8a57933b05..577f9ee85bd 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/teleport.rs @@ -16,63 +16,347 @@ use crate::*; +fn relay_origin_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <Westend as Chain>::RuntimeEvent; + + Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(632_207_000, 7_186))); + + assert_expected_events!( + Westend, + vec![ + // Amount to teleport is withdrawn from Sender + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + // Amount to teleport is deposited in Relay's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, amount }) => { + who: *who == <Westend as WestendPallet>::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn relay_dest_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = <Westend as Chain>::RuntimeEvent; + + Westend::assert_ump_queue_processed( + true, + Some(AssetHubWestend::para_id()), + Some(Weight::from_parts(308_222_000, 7_186)), + ); + + assert_expected_events!( + Westend, + vec![ + // Amount is witdrawn from Relay Chain's `CheckAccount` + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == <Westend as WestendPallet>::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + // Amount minus fees are deposited in Receiver's account + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { + Westend::assert_ump_queue_processed( + false, + Some(AssetHubWestend::para_id()), + Some(Weight::from_parts(148_705_000, 3_593)), + ); +} + +fn para_origin_assertions(t: SystemParaToRelayTest) { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( + 533_910_000, + 7167, + ))); + + AssetHubWestend::assert_parachain_system_ump_sent(); + + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount is withdrawn from Sender's account + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_dest_assertions(t: RelayToSystemParaTest) { + type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; + + AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(164_733_000, 0))); + + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount minus fees are deposited in Receiver's account + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Westend as WestendPallet>::XcmPallet::limited_teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { + <Westend as WestendPallet>::XcmPallet::teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + ) +} + +fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { + <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_teleport_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged +// fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { +// <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::teleport_assets( +// t.signed_origin, +// bx!(t.args.dest), +// bx!(t.args.beneficiary), +// bx!(t.args.assets), +// t.args.fee_asset_item, +// ) +// } + +/// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] -fn teleport_native_assets_from_relay_to_assets_para() { - // Init tests variables - let amount = POLKADOT_ED * 1000; - let relay_sender_balance_before = Westend::account_data_of(WestendSender::get()).free; - let para_receiver_balance_before = - AssetHubWestend::account_data_of(AssetHubWestendReceiver::get()).free; - - let origin = <Westend as Relay>::RuntimeOrigin::signed(WestendSender::get()); - let assets_para_destination: VersionedMultiLocation = - Westend::child_location_of(AssetHubWestend::para_id()).into(); - let beneficiary: VersionedMultiLocation = - AccountId32 { network: None, id: AssetHubWestendReceiver::get().into() }.into(); - let native_assets: VersionedMultiAssets = (Here, amount).into(); - let fee_asset_item = 0; - let weight_limit = WeightLimit::Unlimited; - - // Send XCM message from Relay Chain - Westend::execute_with(|| { - assert_ok!(<Westend as WestendPallet>::XcmPallet::limited_teleport_assets( - origin, - bx!(assets_para_destination), - bx!(beneficiary), - bx!(native_assets), - fee_asset_item, - weight_limit, - )); - - type RuntimeEvent = <Westend as Relay>::RuntimeEvent; - - assert_expected_events!( - Westend, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubWestend::execute_with(|| { - type RuntimeEvent = <AssetHubWestend as Para>::RuntimeEvent; - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { - who: *who == AssetHubWestendReceiver::get().into(), - }, - ] - ); - }); - - // Check if balances are updated accordingly in Relay Chain and Assets Parachain - let relay_sender_balance_after = Westend::account_data_of(WestendSender::get()).free; - let para_sender_balance_after = - AssetHubWestend::account_data_of(AssetHubWestendReceiver::get()).free; - - assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); - assert!(para_sender_balance_after > para_receiver_balance_before); +fn limited_teleport_native_assets_from_relay_to_system_para_works() { + // Init values for Relay Chain + let amount_to_send: Balance = WESTEND_ED * 1000; + let test_args = TestContext { + sender: WestendSender::get(), + receiver: AssetHubWestendReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Westend>(relay_origin_assertions); + test.set_assertion::<AssetHubWestend>(para_dest_assertions); + test.set_dispatchable::<Westend>(relay_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); } + +/// Limited Teleport of native asset from System Parachain to Relay Chain +/// should work when there is enough balance in Relay Chain's `CheckAccount` +#[test] +fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { + // Dependency - Relay Chain's `CheckAccount` should have enough balance + limited_teleport_native_assets_from_relay_to_system_para_works(); + + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let destination = AssetHubWestend::parent_location(); + let beneficiary_id = WestendReceiver::get(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: WestendReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubWestend>(para_origin_assertions); + test.set_assertion::<Westend>(relay_dest_assertions); + test.set_dispatchable::<AssetHubWestend>(system_para_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +/// Limited Teleport of native asset from System Parachain to Relay Chain +/// should't work when there is not enough balance in Relay Chain's `CheckAccount` +#[test] +fn limited_teleport_native_assets_from_system_para_to_relay_fails() { + // Init values for Relay Chain + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let destination = AssetHubWestend::parent_location().into(); + let beneficiary_id = WestendReceiver::get().into(); + let assets = (Parent, amount_to_send).into(); + + let test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: WestendReceiver::get(), + args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), + }; + + let mut test = SystemParaToRelayTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<AssetHubWestend>(para_origin_assertions); + test.set_assertion::<Westend>(relay_dest_assertions_fail); + test.set_dispatchable::<AssetHubWestend>(system_para_limited_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance does not change + assert_eq!(receiver_balance_after, receiver_balance_before); +} + +/// Teleport of native asset from Relay Chain to the System Parachain should work +#[test] +fn teleport_native_assets_from_relay_to_system_para_works() { + // Init values for Relay Chain + let amount_to_send: Balance = WESTEND_ED * 1000; + let test_args = TestContext { + sender: WestendSender::get(), + receiver: AssetHubWestendReceiver::get(), + args: relay_test_args(amount_to_send), + }; + + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + + test.set_assertion::<Westend>(relay_origin_assertions); + test.set_assertion::<AssetHubWestend>(para_dest_assertions); + test.set_dispatchable::<Westend>(relay_teleport_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); +} + +// TODO: Uncomment when https://github.com/paritytech/polkadot/pull/7424 is merged + +// Right now it is failing in the Relay Chain with a +// `messageQueue.ProcessingFailed` event `error: Unsupported`. +// The reason is the `Weigher` in `pallet_xcm` is not properly calculating the `remote_weight` +// and it cause an `Overweight` error in `AllowTopLevelPaidExecutionFrom` barrier + +// /// Teleport of native asset from System Parachains to the Relay Chain +// /// should work when there is enough balance in Relay Chain's `CheckAccount` +// #[test] +// fn teleport_native_assets_back_from_system_para_to_relay_works() { +// // Dependency - Relay Chain's `CheckAccount` should have enough balance +// teleport_native_assets_from_relay_to_system_para_works(); + +// // Init values for Relay Chain +// let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; +// let test_args = TestContext { +// sender: AssetHubWestendSender::get(), +// receiver: WestendReceiver::get(), +// args: get_para_dispatch_args(amount_to_send), +// }; + +// let mut test = SystemParaToRelayTest::new(test_args); + +// let sender_balance_before = test.sender.balance; +// let receiver_balance_before = test.receiver.balance; + +// test.set_assertion::<AssetHubWestend>(para_origin_assertions); +// test.set_assertion::<Westend>(relay_dest_assertions); +// test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets); +// test.assert(); + +// let sender_balance_after = test.sender.balance; +// let receiver_balance_after = test.receiver.balance; + +// // Sender's balance is reduced +// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); +// // Receiver's balance is increased +// assert!(receiver_balance_after > receiver_balance_before); +// } + +// /// Teleport of native asset from System Parachain to Relay Chain +// /// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` +// #[test] +// fn teleport_native_assets_from_system_para_to_relay_fails() { +// // Init values for Relay Chain +// let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; +// let assets = (Parent, amount_to_send).into(); +// +// let test_args = TestContext { +// sender: AssetHubWestendSender::get(), +// receiver: WestendReceiver::get(), +// args: system_para_test_args(amount_to_send), +// assets, +// None +// }; + +// let mut test = SystemParaToRelayTest::new(test_args); + +// let sender_balance_before = test.sender.balance; +// let receiver_balance_before = test.receiver.balance; + +// test.set_assertion::<AssetHubWestend>(para_origin_assertions); +// test.set_assertion::<Westend>(relay_dest_assertions); +// test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets); +// test.assert(); + +// let sender_balance_after = test.sender.balance; +// let receiver_balance_after = test.receiver.balance; + +// // Sender's balance is reduced +// assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); +// // Receiver's balance does not change +// assert_eq!(receiver_balance_after, receiver_balance_before); +// } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/transact.rs deleted file mode 100644 index e71a9174848..00000000000 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/transact.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. - -use crate::*; - -#[test] -fn transact_sudo_from_relay_to_assets_para() { - // Init tests variables - // Call to be executed in Assets Parachain - const ASSET_ID: u32 = 1; - - let call = <AssetHubWestend as Para>::RuntimeCall::Assets(pallet_assets::Call::< - <AssetHubWestend as Para>::Runtime, - Instance1, - >::force_create { - id: ASSET_ID.into(), - is_sufficient: true, - min_balance: 1000, - owner: AssetHubWestendSender::get().into(), - }) - .encode() - .into(); - - // XcmPallet send arguments - let sudo_origin = <Westend as Relay>::RuntimeOrigin::root(); - let assets_para_destination: VersionedMultiLocation = - Westend::child_location_of(AssetHubWestend::para_id()).into(); - - let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let origin_kind = OriginKind::Superuser; - let check_origin = None; - - let xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit, check_origin }, - Transact { require_weight_at_most, origin_kind, call }, - ])); - - // Send XCM message from Relay Chain - Westend::execute_with(|| { - assert_ok!(<Westend as WestendPallet>::XcmPallet::send( - sudo_origin, - bx!(assets_para_destination), - bx!(xcm), - )); - - type RuntimeEvent = <Westend as Relay>::RuntimeEvent; - - assert_expected_events!( - Westend, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain - AssetHubWestend::execute_with(|| { - assert!(<AssetHubWestend as AssetHubWestendPallet>::Assets::asset_exists(ASSET_ID)); - }); -} diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml index d61de30915a..901b3a99512 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/Cargo.toml @@ -29,7 +29,7 @@ pallet-xcm = { default-features = false, git = "https://github.com/paritytech/po # Cumulus parachains-common = { path = "../../../../common" } cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../pallets/xcmp-queue" } -bridge-hub-rococo-runtime = { path = "../../../../runtimes/bridge-hubs/bridge-hub-rococo" } +cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } pallet-bridge-messages = { default-features = false, path = "../../../../../bridges/modules/messages" } bp-messages = { default-features = false, path = "../../../../../bridges/primitives/messages" } diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs index 105212b1907..2a4927d857c 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/lib.rs @@ -16,33 +16,73 @@ pub use bp_messages::LaneId; pub use codec::Encode; -pub use frame_support::{assert_ok, pallet_prelude::Weight}; +pub use frame_support::{ + assert_err, assert_ok, + instances::Instance1, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, + traits::{fungibles::Inspect, OriginTrait}, +}; pub use integration_tests_common::{ constants::{ accounts::{ALICE, BOB}, - rococo::{ED as ROCOCO_ED, ED as WOCOCO_ED}, + asset_hub_kusama::ED as ASSET_HUB_ROCOCO_ED, + kusama::ED as ROCOCO_ED, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }, - AccountId, AssetHubWococo, BridgeHubPolkadot, BridgeHubPolkadotPallet, - BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, BridgeHubRococo, BridgeHubRococoPallet, - BridgeHubRococoReceiver, BridgeHubRococoSender, BridgeHubWococo, Collectives, - CollectivesPallet, CollectivesReceiver, CollectivesSender, Kusama, KusamaPallet, - PenpalPolkadot, PenpalPolkadotReceiver, PenpalPolkadotSender, Polkadot, PolkadotMockNet, - PolkadotPallet, PolkadotReceiver, PolkadotSender, Rococo, RococoMockNet, RococoPallet, - RococoReceiver, RococoSender, + lazy_static::lazy_static, + xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubRococo, + AssetHubRococoPallet, AssetHubRococoReceiver, AssetHubRococoSender, AssetHubWococo, + AssetHubWococoPallet, AssetHubWococoReceiver, AssetHubWococoSender, BridgeHubRococo, + BridgeHubRococoPallet, BridgeHubRococoReceiver, BridgeHubRococoSender, BridgeHubWococo, + BridgeHubWococoPallet, BridgeHubWococoReceiver, BridgeHubWococoSender, Collectives, + CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalRococoA, PenpalRococoAPallet, + PenpalRococoAReceiver, PenpalRococoASender, Rococo, RococoMockNet, RococoPallet, + RococoReceiver, RococoSender, Wococo, WococoMockNet, WococoPallet, WococoReceiver, + WococoSender, }; -// pub use polkadot_core_primitives::InboundDownwardMessage; +pub use parachains_common::{AccountId, Balance}; +pub use polkadot_core_primitives::InboundDownwardMessage; +pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use xcm::{ prelude::*, v3::{ Error, NetworkId::{Rococo as RococoId, Wococo as WococoId}, }, + DoubleEncoded, }; pub use xcm_emulator::{ assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, - Parachain as Para, RelayChain as Relay, TestExt, + AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, TestExternalities, }; +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +pub const ASSETS_PALLET_ID: u8 = 50; + +pub type RelayToSystemParaTest = Test<Rococo, AssetHubRococo>; +pub type SystemParaToRelayTest = Test<AssetHubRococo, Rococo>; +pub type SystemParaToParaTest = Test<AssetHubRococo, PenpalRococoA>; + +/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +pub fn relay_test_args(amount: Balance) -> TestArgs { + TestArgs { + dest: Rococo::child_location_of(AssetHubRococo::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubRococoReceiver::get().into(), + } + .into(), + amount, + assets: (Here, amount).into(), + asset_id: None, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs index 1d06d7f9fcd..5b11337a7e6 100644 --- a/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs +++ b/cumulus/parachains/integration-tests/emulated/bridges/bridge-hub-rococo/src/tests/example.rs @@ -20,7 +20,7 @@ use crate::*; fn example() { // Init tests variables // XcmPallet send arguments - let sudo_origin = <Rococo as Relay>::RuntimeOrigin::root(); + let sudo_origin = <Rococo as Chain>::RuntimeOrigin::root(); let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into(); let weight_limit = WeightLimit::Unlimited; let check_origin = None; @@ -45,7 +45,7 @@ fn example() { bx!(xcm), )); - type RuntimeEvent = <Rococo as Relay>::RuntimeEvent; + type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; assert_expected_events!( Rococo, @@ -56,7 +56,7 @@ fn example() { }); // Receive XCM message in Bridge Hub source Parachain BridgeHubRococo::execute_with(|| { - type RuntimeEvent = <BridgeHubRococo as Para>::RuntimeEvent; + type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent; assert_expected_events!( BridgeHubRococo, @@ -76,7 +76,7 @@ fn example() { // Wococo GLobal Consensus // Receive XCM message in Bridge Hub target Parachain BridgeHubWococo::execute_with(|| { - type RuntimeEvent = <BridgeHubWococo as Para>::RuntimeEvent; + type RuntimeEvent = <BridgeHubWococo as Chain>::RuntimeEvent; assert_expected_events!( BridgeHubWococo, @@ -87,7 +87,7 @@ fn example() { }); // Receive embeded XCM message within `ExportMessage` in Parachain destination AssetHubWococo::execute_with(|| { - type RuntimeEvent = <AssetHubWococo as Para>::RuntimeEvent; + type RuntimeEvent = <AssetHubWococo as Chain>::RuntimeEvent; assert_expected_events!( AssetHubWococo, diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml index 2f81d34b51a..8663f4b0b4a 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"] edition = "2021" description = "Polkadot Collectives parachain runtime integration tests based on xcm-emulator" -[dev-dependencies] +[dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } # Substrate @@ -31,6 +31,7 @@ pallet-xcm = { default-features = false, git = "https://github.com/paritytech/po # Cumulus parachains-common = { path = "../../../../common" } cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../pallets/xcmp-queue" } +cumulus-pallet-parachain-system = { path = "../../../../../pallets/parachain-system" } collectives-polkadot-runtime = { path = "../../../../runtimes/collectives/collectives-polkadot" } asset-hub-polkadot-runtime = { path = "../../../../runtimes/assets/asset-hub-polkadot" } diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs index d83ddfffd99..b71ee65a222 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/lib.rs @@ -14,17 +14,88 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. -//! Collectives Parachain integration tests based on xcm-emulator. - -#![cfg(test)] - -pub use frame_support::assert_ok; +pub use codec::Encode; +pub use frame_support::{ + assert_err, assert_ok, + instances::Instance1, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchError, DispatchResult, MultiAddress}, + traits::{fungibles::Inspect, OriginTrait}, +}; pub use integration_tests_common::{ - constants::accounts::ALICE, AccountId, AssetHubPolkadot as AssetHub, - AssetHubPolkadotPallet as AssetHubPallet, Collectives, CollectivesPallet, Polkadot, - PolkadotMockNet, + constants::{ + accounts::{ALICE, BOB}, + asset_hub_polkadot::ED as ASSET_HUB_POLKADOT_ED, + polkadot::ED as POLKADOT_ED, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, + }, + lazy_static::lazy_static, + xcm_transact_paid_execution, xcm_transact_unpaid_execution, AssetHubPolkadot, + AssetHubPolkadotPallet, AssetHubPolkadotReceiver, AssetHubPolkadotSender, BridgeHubPolkadot, + BridgeHubPolkadotPallet, BridgeHubPolkadotReceiver, BridgeHubPolkadotSender, Collectives, + CollectivesPallet, CollectivesReceiver, CollectivesSender, PenpalPolkadotA, + PenpalPolkadotAPallet, PenpalPolkadotAReceiver, PenpalPolkadotASender, PenpalPolkadotB, + PenpalPolkadotBPallet, PenpalPolkadotBReceiver, PenpalPolkadotBSender, Polkadot, + PolkadotMockNet, PolkadotPallet, PolkadotReceiver, PolkadotSender, +}; +pub use parachains_common::{AccountId, Balance}; +pub use polkadot_core_primitives::InboundDownwardMessage; +pub use polkadot_parachain::primitives::{HrmpChannelId, Id}; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; +pub use xcm::{ + prelude::*, + v3::{Error, NetworkId::Polkadot as PolkadotId}, + DoubleEncoded, +}; +pub use xcm_emulator::{ + assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, + AccountId32Junction, Chain, ParaId, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, TestExternalities, }; -pub use xcm::prelude::*; -pub use xcm_emulator::{assert_expected_events, Parachain}; +pub const ASSET_ID: u32 = 1; +pub const ASSET_MIN_BALANCE: u128 = 1000; +pub const ASSETS_PALLET_ID: u8 = 50; + +pub type RelayToSystemParaTest = Test<Polkadot, AssetHubPolkadot>; +pub type SystemParaToRelayTest = Test<AssetHubPolkadot, Polkadot>; +pub type SystemParaToParaTest = Test<AssetHubPolkadot, PenpalPolkadotA>; + +/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests +pub fn relay_test_args(amount: Balance) -> TestArgs { + TestArgs { + dest: Polkadot::child_location_of(AssetHubPolkadot::para_id()), + beneficiary: AccountId32Junction { + network: None, + id: AssetHubPolkadotReceiver::get().into(), + } + .into(), + amount, + assets: (Here, amount).into(), + asset_id: None, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + +/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests +pub fn system_para_test_args( + dest: MultiLocation, + beneficiary_id: AccountId32, + amount: Balance, + assets: MultiAssets, + asset_id: Option<u32>, +) -> TestArgs { + TestArgs { + dest, + beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(), + amount, + assets, + asset_id, + fee_asset_item: 0, + weight_limit: WeightLimit::Unlimited, + } +} + +#[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs index 233fd67083d..e13090c1a51 100644 --- a/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs +++ b/cumulus/parachains/integration-tests/emulated/collectives/collectives-polkadot/src/tests/fellowship.rs @@ -34,8 +34,8 @@ fn pay_salary() { let pay_to = Polkadot::account_id_of(ALICE); let pay_amount = 9000; - AssetHub::execute_with(|| { - type AssetHubAssets = <AssetHub as AssetHubPallet>::Assets; + AssetHubPolkadot::execute_with(|| { + type AssetHubAssets = <AssetHubPolkadot as AssetHubPolkadotPallet>::Assets; assert_ok!(<AssetHubAssets as Create<_>>::create( asset_id, @@ -47,7 +47,7 @@ fn pay_salary() { }); Collectives::execute_with(|| { - type RuntimeEvent = <Collectives as Parachain>::RuntimeEvent; + type RuntimeEvent = <Collectives as Chain>::RuntimeEvent; assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount)); assert_expected_events!( @@ -58,11 +58,11 @@ fn pay_salary() { ); }); - AssetHub::execute_with(|| { - type RuntimeEvent = <AssetHub as Parachain>::RuntimeEvent; + AssetHubPolkadot::execute_with(|| { + type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent; assert_expected_events!( - AssetHub, + AssetHubPolkadot, vec![ RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { asset_id: id == &asset_id, diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index ec7fd21fac7..6a0fa51e6b2 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -7,6 +7,8 @@ description = "Common resources for integration testing with xcm-emulator" [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +lazy_static = "1.4.0" +paste = "1.0.14" # Substrate grandpa = { package = "sc-consensus-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" } @@ -20,6 +22,7 @@ sp-consensus-babe = { default-features = false, git = "https://github.com/parity pallet-balances = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } pallet-assets = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } pallet-staking = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-message-queue = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } pallet-im-online = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } beefy-primitives = { package = "sp-consensus-beefy", git = "https://github.com/paritytech/substrate", branch = "master" } @@ -54,6 +57,9 @@ bridge-hub-kusama-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-k bridge-hub-polkadot-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-polkadot" } bridge-hub-rococo-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-rococo" } xcm-emulator = { default-features = false, path = "../../../../xcm/xcm-emulator" } +cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../pallets/xcmp-queue" } +cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system" } bp-messages = { path = "../../../../bridges/primitives/messages"} bp-runtime = { path = "../../../../bridges/primitives/runtime"} pallet-bridge-messages = { path = "../../../../bridges/modules/messages" } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs index 8c658b0b2bb..ed529b867bc 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/constants.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/constants.rs @@ -2,8 +2,12 @@ use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; use grandpa::AuthorityId as GrandpaId; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; +use polkadot_parachain::primitives::{HeadData, ValidationCode}; use polkadot_primitives::{AssignmentId, ValidatorId}; -use polkadot_runtime_parachains::configuration::HostConfiguration; +use polkadot_runtime_parachains::{ + configuration::HostConfiguration, + paras::{ParaGenesisArgs, ParaKind}, +}; use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; @@ -129,6 +133,13 @@ pub mod polkadot { max_upward_message_size: 51200, max_upward_message_num_per_candidate: 10, max_downward_message_size: 51200, + hrmp_sender_deposit: 100_000_000_000, + hrmp_recipient_deposit: 100_000_000_000, + hrmp_channel_max_capacity: 1000, + hrmp_channel_max_message_size: 102400, + hrmp_channel_max_total_size: 102400, + hrmp_max_parachain_outbound_channels: 30, + hrmp_max_parachain_inbound_channels: 30, ..Default::default() } } @@ -206,6 +217,41 @@ pub mod polkadot { ..Default::default() }, configuration: polkadot_runtime::ConfigurationConfig { config: get_host_config() }, + paras: polkadot_runtime::ParasConfig { + paras: vec![ + ( + asset_hub_polkadot::PARA_ID.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + asset_hub_polkadot_runtime::WASM_BINARY.unwrap().to_vec(), + ), + para_kind: ParaKind::Parachain, + }, + ), + ( + penpal::PARA_ID_A.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + penpal_runtime::WASM_BINARY.unwrap().to_vec(), + ), + para_kind: ParaKind::Parachain, + }, + ), + ( + penpal::PARA_ID_B.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + penpal_runtime::WASM_BINARY.unwrap().to_vec(), + ), + para_kind: ParaKind::Parachain, + }, + ), + ], + ..Default::default() + }, ..Default::default() }; @@ -228,6 +274,13 @@ pub mod westend { max_upward_message_size: 51200, max_upward_message_num_per_candidate: 10, max_downward_message_size: 51200, + hrmp_sender_deposit: 100_000_000_000, + hrmp_recipient_deposit: 100_000_000_000, + hrmp_channel_max_capacity: 1000, + hrmp_channel_max_message_size: 102400, + hrmp_channel_max_total_size: 102400, + hrmp_max_parachain_outbound_channels: 30, + hrmp_max_parachain_inbound_channels: 30, ..Default::default() } } @@ -327,6 +380,13 @@ pub mod kusama { max_upward_message_size: 51200, max_upward_message_num_per_candidate: 10, max_downward_message_size: 51200, + hrmp_sender_deposit: 5_000_000_000_000, + hrmp_recipient_deposit: 5_000_000_000_000, + hrmp_channel_max_capacity: 1000, + hrmp_channel_max_message_size: 102400, + hrmp_channel_max_total_size: 102400, + hrmp_max_parachain_outbound_channels: 30, + hrmp_max_parachain_inbound_channels: 30, ..Default::default() } } @@ -403,6 +463,41 @@ pub mod kusama { ..Default::default() }, configuration: kusama_runtime::ConfigurationConfig { config: get_host_config() }, + paras: kusama_runtime::ParasConfig { + paras: vec![ + ( + asset_hub_kusama::PARA_ID.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + asset_hub_kusama_runtime::WASM_BINARY.unwrap().to_vec(), + ), + para_kind: ParaKind::Parachain, + }, + ), + ( + penpal::PARA_ID_A.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + penpal_runtime::WASM_BINARY.unwrap().to_vec(), + ), + para_kind: ParaKind::Parachain, + }, + ), + ( + penpal::PARA_ID_B.into(), + ParaGenesisArgs { + genesis_head: HeadData::default(), + validation_code: ValidationCode( + penpal_runtime::WASM_BINARY.unwrap().to_vec(), + ), + para_kind: ParaKind::Parachain, + }, + ), + ], + ..Default::default() + }, ..Default::default() }; @@ -419,10 +514,18 @@ pub mod rococo { pub fn get_host_config() -> HostConfiguration<BlockNumber> { HostConfiguration { + max_upward_queue_count: 10, max_upward_queue_size: 51200, max_upward_message_size: 51200, max_upward_message_num_per_candidate: 10, max_downward_message_size: 51200, + hrmp_sender_deposit: 0, + hrmp_recipient_deposit: 0, + hrmp_channel_max_capacity: 1000, + hrmp_channel_max_message_size: 102400, + hrmp_channel_max_total_size: 102400, + hrmp_max_parachain_outbound_channels: 30, + hrmp_max_parachain_inbound_channels: 30, ..Default::default() } } @@ -674,7 +777,8 @@ pub mod asset_hub_kusama { // Penpal pub mod penpal { use super::*; - pub const PARA_ID: u32 = 2000; + pub const PARA_ID_A: u32 = 2000; + pub const PARA_ID_B: u32 = 2001; pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; pub fn genesis(para_id: u32) -> Storage { diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 9c4acf4637e..92c68f4dd61 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -1,4 +1,5 @@ use super::{BridgeHubRococo, BridgeHubWococo}; +// pub use paste; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, LaneId, MessageKey, OutboundLaneData, @@ -8,7 +9,7 @@ use codec::Decode; pub use cumulus_primitives_core::{DmpMessageHandler, XcmpMessageHandler}; use pallet_bridge_messages::{Config, Instance1, Instance2, OutboundLanes, Pallet}; use sp_core::Get; -use xcm_emulator::{BridgeMessage, BridgeMessageDispatchError, BridgeMessageHandler, Parachain}; +use xcm_emulator::{BridgeMessage, BridgeMessageDispatchError, BridgeMessageHandler, Chain}; pub struct BridgeHubMessageHandler<S, T, I> { _marker: std::marker::PhantomData<(S, T, I)>, @@ -28,12 +29,12 @@ impl From<u32> for LaneIdWrapper { } } -type BridgeHubRococoRuntime = <BridgeHubRococo as Parachain>::Runtime; -type BridgeHubWococoRuntime = <BridgeHubWococo as Parachain>::Runtime; +type BridgeHubRococoRuntime = <BridgeHubRococo as Chain>::Runtime; +type BridgeHubWococoRuntime = <BridgeHubWococo as Chain>::Runtime; // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged -// type BridgeHubPolkadotRuntime = <BridgeHubPolkadot as Parachain>::Runtime; -// type BridgeHubKusamaRuntime = <BridgeHubKusama as Parachain>::Runtime; +// type BridgeHubPolkadotRuntime = <BridgeHubPolkadot as Chain>::Runtime; +// type BridgeHubKusamaRuntime = <BridgeHubKusama as Chain>::Runtime; pub type RococoWococoMessageHandler = BridgeHubMessageHandler<BridgeHubRococoRuntime, BridgeHubWococoRuntime, Instance2>; @@ -124,3 +125,473 @@ where OutboundLanes::<S, Instance1>::insert(LaneIdWrapper::from(lane_id).0, new_data); } } + +#[macro_export] +macro_rules! impl_accounts_helpers_for_relay_chain { + ( $chain:ident ) => { + $crate::paste::paste! { + impl $chain { + /// Fund a set of accounts with a balance + pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { + Self::execute_with(|| { + for account in accounts { + assert_ok!(<Self as [<$chain Pallet>]>::Balances::force_set_balance( + <Self as Chain>::RuntimeOrigin::root(), + account.0.into(), + account.1, + )); + } + }); + } + /// Fund a sovereign account based on its Parachain Id + pub fn fund_para_sovereign(amount: Balance, para_id: ParaId) -> sp_runtime::AccountId32 { + let sovereign_account = Self::sovereign_account_id_of_child_para(para_id); + Self::fund_accounts(vec![(sovereign_account.clone(), amount)]); + sovereign_account + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_assert_events_helpers_for_relay_chain { + ( $chain:ident ) => { + $crate::paste::paste! { + type [<$chain RuntimeEvent>] = <$chain as Chain>::RuntimeEvent; + + impl $chain { + /// Asserts a dispatchable is completely executed and XCM sent + pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<Weight>) { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::XcmPallet( + pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) } + ) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + }, + ] + ); + } + + /// Asserts a dispatchable is incompletely executed and XCM sent + pub fn assert_xcm_pallet_attempted_incomplete( + expected_weight: Option<Weight>, + expected_error: Option<Error>, + ) { + assert_expected_events!( + Self, + vec![ + // Dispatchable is properly executed and XCM message sent + [<$chain RuntimeEvent>]::XcmPallet( + pallet_xcm::Event::Attempted { outcome: Outcome::Incomplete(weight, error) } + ) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + error: *error == expected_error.unwrap_or(*error), + }, + ] + ); + } + + /// Asserts a XCM message is sent + pub fn assert_xcm_pallet_sent() { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + } + + /// Asserts a XCM from System Parachain is succesfully received and proccessed + pub fn assert_ump_queue_processed( + expected_success: bool, + expected_id: Option<ParaId>, + expected_weight: Option<Weight>, + ) { + assert_expected_events!( + Self, + vec![ + // XCM is succesfully received and proccessed + [<$chain RuntimeEvent>]::MessageQueue(pallet_message_queue::Event::Processed { + origin: AggregateMessageOrigin::Ump(UmpQueueId::Para(id)), + weight_used, + success, + .. + }) => { + id: *id == expected_id.unwrap_or(*id), + weight_used: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight_used), + *weight_used + ), + success: *success == expected_success, + }, + ] + ); + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_hrmp_channels_helpers_for_relay_chain { + ( $chain:ident ) => { + $crate::paste::paste! { + impl $chain { + /// Init open channel request with another Parachain + pub fn init_open_channel_call( + recipient_para_id: ParaId, + max_capacity: u32, + max_message_size: u32, + ) -> DoubleEncoded<()> { + <Self as Chain>::RuntimeCall::Hrmp(polkadot_runtime_parachains::hrmp::Call::< + <Self as Chain>::Runtime, + >::hrmp_init_open_channel { + recipient: recipient_para_id, + proposed_max_capacity: max_capacity, + proposed_max_message_size: max_message_size, + }) + .encode() + .into() + } + /// Recipient Parachain accept the open request from another Parachain + pub fn accept_open_channel_call(sender_para_id: ParaId) -> DoubleEncoded<()> { + <Self as Chain>::RuntimeCall::Hrmp(polkadot_runtime_parachains::hrmp::Call::< + <Self as Chain>::Runtime, + >::hrmp_accept_open_channel { + sender: sender_para_id, + }) + .encode() + .into() + } + + /// A root origin force to open a channel between two Parachains + pub fn force_process_hrmp_open(sender: ParaId, recipient: ParaId) { + Self::execute_with(|| { + let relay_root_origin = <Self as Chain>::RuntimeOrigin::root(); + + // Force process HRMP open channel requests without waiting for the next session + assert_ok!(<Self as [<$chain Pallet>]>::Hrmp::force_process_hrmp_open( + relay_root_origin, + 0 + )); + + let channel_id = HrmpChannelId { sender, recipient }; + + let hrmp_channel_exist = polkadot_runtime_parachains::hrmp::HrmpChannels::< + <Self as Chain>::Runtime, + >::contains_key(&channel_id); + + // Check the HRMP channel has been successfully registrered + assert!(hrmp_channel_exist) + }); + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_accounts_helpers_for_parachain { + ( $chain:ident ) => { + $crate::paste::paste! { + impl $chain { + /// Fund a set of accounts with a balance + pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { + Self::execute_with(|| { + for account in accounts { + assert_ok!(<Self as [<$chain Pallet>]>::Balances::force_set_balance( + <Self as Chain>::RuntimeOrigin::root(), + account.0.into(), + account.1, + )); + } + }); + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_assert_events_helpers_for_parachain { + ( $chain:ident ) => { + $crate::paste::paste! { + type [<$chain RuntimeEvent>] = <$chain as Chain>::RuntimeEvent; + + impl $chain { + /// Asserts a dispatchable is completely executed and XCM sent + pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<Weight>) { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::PolkadotXcm( + pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) } + ) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + }, + ] + ); + } + + /// Asserts a dispatchable is incompletely executed and XCM sent + pub fn assert_xcm_pallet_attempted_incomplete( + expected_weight: Option<Weight>, + expected_error: Option<Error>, + ) { + assert_expected_events!( + Self, + vec![ + // Dispatchable is properly executed and XCM message sent + [<$chain RuntimeEvent>]::PolkadotXcm( + pallet_xcm::Event::Attempted { outcome: Outcome::Incomplete(weight, error) } + ) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + error: *error == expected_error.unwrap_or(*error), + }, + ] + ); + } + + /// Asserts a dispatchable throws and error when trying to be sent + pub fn assert_xcm_pallet_attempted_error(expected_error: Option<Error>) { + assert_expected_events!( + Self, + vec![ + // Execution fails in the origin with `Barrier` + [<$chain RuntimeEvent>]::PolkadotXcm( + pallet_xcm::Event::Attempted { outcome: Outcome::Error(error) } + ) => { + error: *error == expected_error.unwrap_or(*error), + }, + ] + ); + } + + /// Asserts a XCM message is sent + pub fn assert_xcm_pallet_sent() { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + } + + /// Asserts a XCM message is sent to Relay Chain + pub fn assert_parachain_system_ump_sent() { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + } + + /// Asserts a XCM from Relay Chain is completely executed + pub fn assert_dmp_queue_complete(expected_weight: Option<Weight>) { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: Outcome::Complete(weight), .. + }) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + }, + ] + ); + } + + /// Asserts a XCM from Relay Chain is incompletely executed + pub fn assert_dmp_queue_incomplete( + expected_weight: Option<Weight>, + expected_error: Option<Error>, + ) { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { + outcome: Outcome::Incomplete(weight, error), .. + }) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + error: *error == expected_error.unwrap_or(*error), + }, + ] + ); + } + + /// Asserts a XCM from another Parachain is completely executed + pub fn assert_xcmp_queue_success(expected_weight: Option<Weight>) { + assert_expected_events!( + Self, + vec![ + [<$chain RuntimeEvent>]::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::Success { weight, .. } + ) => { + weight: weight_within_threshold( + (REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), + expected_weight.unwrap_or(*weight), + *weight + ), + }, + ] + ); + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_assets_helpers_for_parachain { + ( $chain:ident, $relay_chain:ident ) => { + $crate::paste::paste! { + impl $chain { + /// Returns the encoded call for `force_create` from the assets pallet + pub fn force_create_asset_call( + asset_id: u32, + owner: AccountId, + is_sufficient: bool, + min_balance: Balance, + ) -> DoubleEncoded<()> { + <Self as Chain>::RuntimeCall::Assets(pallet_assets::Call::< + <Self as Chain>::Runtime, + Instance1, + >::force_create { + id: asset_id.into(), + owner: owner.into(), + is_sufficient, + min_balance, + }) + .encode() + .into() + } + + /// Returns a `VersionedXcm` for `force_create` from the assets pallet + pub fn force_create_asset_xcm( + origin_kind: OriginKind, + asset_id: u32, + owner: AccountId, + is_sufficient: bool, + min_balance: Balance, + ) -> VersionedXcm<()> { + let call = Self::force_create_asset_call(asset_id, owner, is_sufficient, min_balance); + xcm_transact_unpaid_execution(call, origin_kind) + } + + /// Mint assets making use of the assets pallet + pub fn mint_asset( + signed_origin: <Self as Chain>::RuntimeOrigin, + id: u32, + beneficiary: AccountId, + amount_to_mint: u128, + ) { + Self::execute_with(|| { + assert_ok!(<Self as [<$chain Pallet>]>::Assets::mint( + signed_origin, + id.into(), + beneficiary.clone().into(), + amount_to_mint + )); + + type RuntimeEvent = <$chain as Chain>::RuntimeEvent; + + assert_expected_events!( + Self, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == id, + owner: *owner == beneficiary.clone().into(), + amount: *amount == amount_to_mint, + }, + ] + ); + }); + } + + /// Force create and mint assets making use of the assets pallet + pub fn force_create_and_mint_asset( + id: u32, + min_balance: u128, + is_sufficient: bool, + asset_owner: AccountId, + amount_to_mint: u128, + ) { + // Init values for Relay Chain + let root_origin = <$relay_chain as Chain>::RuntimeOrigin::root(); + let destination = <$relay_chain>::child_location_of(<$chain>::para_id()); + let xcm = Self::force_create_asset_xcm( + OriginKind::Superuser, + id, + asset_owner.clone(), + is_sufficient, + min_balance, + ); + + <$relay_chain>::execute_with(|| { + assert_ok!(<$relay_chain as [<$relay_chain Pallet>]>::XcmPallet::send( + root_origin, + bx!(destination.into()), + bx!(xcm), + )); + + <$relay_chain>::assert_xcm_pallet_sent(); + }); + + Self::execute_with(|| { + Self::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_445_000, 200_000))); + + type RuntimeEvent = <$chain as Chain>::RuntimeEvent; + + assert_expected_events!( + Self, + vec![ + // Asset has been created + RuntimeEvent::Assets(pallet_assets::Event::ForceCreated { asset_id, owner }) => { + asset_id: *asset_id == id, + owner: *owner == asset_owner.clone(), + }, + ] + ); + + assert!(<Self as [<$chain Pallet>]>::Assets::asset_exists(id.into())); + }); + + let signed_origin = <Self as Chain>::RuntimeOrigin::signed(asset_owner.clone()); + + // Mint asset for System Parachain's sender + Self::mint_asset(signed_origin, id, asset_owner, amount_to_mint); + } + } + } + }; +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 23b05a54c72..7ef57027c45 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -1,121 +1,114 @@ +pub use lazy_static; pub mod constants; pub mod impls; +pub use codec::Encode; pub use constants::{ accounts::{ALICE, BOB}, asset_hub_kusama, asset_hub_polkadot, asset_hub_westend, bridge_hub_kusama, bridge_hub_polkadot, bridge_hub_rococo, collectives, kusama, penpal, polkadot, rococo, westend, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, +}; +use frame_support::{ + assert_ok, instances::Instance1, parameter_types, sp_tracing, traits::fungibles::Inspect, }; pub use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler}; - -use frame_support::{parameter_types, sp_io, sp_tracing}; -pub use parachains_common::{AccountId, AssetHubPolkadotAuraId, AuraId, Balance, BlockNumber}; +pub use parachains_common::{AccountId, Balance}; +pub use paste; +use polkadot_parachain::primitives::HrmpChannelId; +pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; pub use sp_core::{sr25519, storage::Storage, Get}; -use xcm::prelude::*; use xcm_emulator::{ - decl_test_bridges, decl_test_networks, decl_test_parachains, decl_test_relay_chains, - decl_test_sender_receiver_accounts_parameter_types, BridgeMessageHandler, Parachain, - RelayChain, TestExt, + assert_expected_events, bx, decl_test_bridges, decl_test_networks, decl_test_parachains, + decl_test_relay_chains, decl_test_sender_receiver_accounts_parameter_types, + helpers::weight_within_threshold, BridgeMessageHandler, Chain, DefaultMessageProcessor, ParaId, + Parachain, RelayChain, TestExt, +}; + +pub use xcm::{ + prelude::{ + AccountId32, All, BuyExecution, DepositAsset, MultiAsset, MultiAssets, MultiLocation, + OriginKind, Outcome, RefundSurplus, Transact, UnpaidExecution, VersionedXcm, Weight, + WeightLimit, WithdrawAsset, Xcm, X1, + }, + v3::Error, + DoubleEncoded, }; -use xcm_executor::traits::ConvertLocation; decl_test_relay_chains! { #[api_version(5)] pub struct Polkadot { genesis = polkadot::genesis(), on_init = (), - runtime = { - Runtime: polkadot_runtime::Runtime, - RuntimeOrigin: polkadot_runtime::RuntimeOrigin, - RuntimeCall: polkadot_runtime::RuntimeCall, - RuntimeEvent: polkadot_runtime::RuntimeEvent, - MessageQueue: polkadot_runtime::MessageQueue, - XcmConfig: polkadot_runtime::xcm_config::XcmConfig, + runtime = polkadot_runtime, + core = { + MessageProcessor: DefaultMessageProcessor<Polkadot>, SovereignAccountOf: polkadot_runtime::xcm_config::SovereignAccountOf, - System: polkadot_runtime::System, - Balances: polkadot_runtime::Balances, }, - pallets_extra = { + pallets = { XcmPallet: polkadot_runtime::XcmPallet, + Balances: polkadot_runtime::Balances, + Hrmp: polkadot_runtime::Hrmp, } }, #[api_version(5)] pub struct Kusama { genesis = kusama::genesis(), on_init = (), - runtime = { - Runtime: kusama_runtime::Runtime, - RuntimeOrigin: kusama_runtime::RuntimeOrigin, - RuntimeCall: kusama_runtime::RuntimeCall, - RuntimeEvent: kusama_runtime::RuntimeEvent, - MessageQueue: kusama_runtime::MessageQueue, - XcmConfig: kusama_runtime::xcm_config::XcmConfig, + runtime = kusama_runtime, + core = { + MessageProcessor: DefaultMessageProcessor<Kusama>, SovereignAccountOf: kusama_runtime::xcm_config::SovereignAccountOf, - System: kusama_runtime::System, - Balances: kusama_runtime::Balances, }, - pallets_extra = { + pallets = { XcmPallet: kusama_runtime::XcmPallet, + Balances: kusama_runtime::Balances, + Hrmp: kusama_runtime::Hrmp, } }, #[api_version(5)] pub struct Westend { genesis = westend::genesis(), on_init = (), - runtime = { - Runtime: westend_runtime::Runtime, - RuntimeOrigin: westend_runtime::RuntimeOrigin, - RuntimeCall: westend_runtime::RuntimeCall, - RuntimeEvent: westend_runtime::RuntimeEvent, - MessageQueue: westend_runtime::MessageQueue, - XcmConfig: westend_runtime::xcm_config::XcmConfig, + runtime = westend_runtime, + core = { + MessageProcessor: DefaultMessageProcessor<Westend>, SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, - System: westend_runtime::System, - Balances: westend_runtime::Balances, }, - pallets_extra = { + pallets = { XcmPallet: westend_runtime::XcmPallet, Sudo: westend_runtime::Sudo, + Balances: westend_runtime::Balances, } }, #[api_version(5)] pub struct Rococo { genesis = rococo::genesis(), on_init = (), - runtime = { - Runtime: rococo_runtime::Runtime, - RuntimeOrigin: rococo_runtime::RuntimeOrigin, - RuntimeCall: rococo_runtime::RuntimeCall, - RuntimeEvent: rococo_runtime::RuntimeEvent, - MessageQueue: rococo_runtime::MessageQueue, - XcmConfig: rococo_runtime::xcm_config::XcmConfig, + runtime = rococo_runtime, + core = { + MessageProcessor: DefaultMessageProcessor<Rococo>, SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, - System: rococo_runtime::System, - Balances: rococo_runtime::Balances, }, - pallets_extra = { + pallets = { XcmPallet: rococo_runtime::XcmPallet, Sudo: rococo_runtime::Sudo, + Balances: rococo_runtime::Balances, } }, #[api_version(5)] pub struct Wococo { genesis = rococo::genesis(), on_init = (), - runtime = { - Runtime: rococo_runtime::Runtime, - RuntimeOrigin: rococo_runtime::RuntimeOrigin, - RuntimeCall: rococo_runtime::RuntimeCall, - RuntimeEvent: rococo_runtime::RuntimeEvent, - MessageQueue: rococo_runtime::MessageQueue, - XcmConfig: rococo_runtime::xcm_config::XcmConfig, + runtime = rococo_runtime, + core = { + MessageProcessor: DefaultMessageProcessor<Wococo>, SovereignAccountOf: rococo_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, - System: rococo_runtime::System, - Balances: rococo_runtime::Balances, }, - pallets_extra = { + pallets = { XcmPallet: rococo_runtime::XcmPallet, Sudo: rococo_runtime::Sudo, + Balances: rococo_runtime::Balances, } } } @@ -125,81 +118,74 @@ decl_test_parachains! { pub struct AssetHubPolkadot { genesis = asset_hub_polkadot::genesis(), on_init = (), - runtime = { - Runtime: asset_hub_polkadot_runtime::Runtime, - RuntimeOrigin: asset_hub_polkadot_runtime::RuntimeOrigin, - RuntimeCall: asset_hub_polkadot_runtime::RuntimeCall, - RuntimeEvent: asset_hub_polkadot_runtime::RuntimeEvent, + runtime = asset_hub_polkadot_runtime, + core = { XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue, DmpMessageHandler: asset_hub_polkadot_runtime::DmpQueue, LocationToAccountId: asset_hub_polkadot_runtime::xcm_config::LocationToAccountId, - System: asset_hub_polkadot_runtime::System, - Balances: asset_hub_polkadot_runtime::Balances, - ParachainSystem: asset_hub_polkadot_runtime::ParachainSystem, ParachainInfo: asset_hub_polkadot_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, Assets: asset_hub_polkadot_runtime::Assets, + Balances: asset_hub_polkadot_runtime::Balances, } }, pub struct Collectives { genesis = collectives::genesis(), on_init = (), - runtime = { - Runtime: collectives_polkadot_runtime::Runtime, - RuntimeOrigin: collectives_polkadot_runtime::RuntimeOrigin, - RuntimeCall: collectives_polkadot_runtime::RuntimeCall, - RuntimeEvent: collectives_polkadot_runtime::RuntimeEvent, + runtime = collectives_polkadot_runtime, + core = { XcmpMessageHandler: collectives_polkadot_runtime::XcmpQueue, DmpMessageHandler: collectives_polkadot_runtime::DmpQueue, LocationToAccountId: collectives_polkadot_runtime::xcm_config::LocationToAccountId, - System: collectives_polkadot_runtime::System, - Balances: collectives_polkadot_runtime::Balances, - ParachainSystem: collectives_polkadot_runtime::ParachainSystem, ParachainInfo: collectives_polkadot_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: collectives_polkadot_runtime::PolkadotXcm, + Balances: collectives_polkadot_runtime::Balances, } }, pub struct BridgeHubPolkadot { genesis = bridge_hub_polkadot::genesis(), on_init = (), - runtime = { - Runtime: bridge_hub_polkadot_runtime::Runtime, - RuntimeOrigin: bridge_hub_polkadot_runtime::RuntimeOrigin, - RuntimeCall: bridge_hub_polkadot_runtime::RuntimeCall, - RuntimeEvent: bridge_hub_polkadot_runtime::RuntimeEvent, + runtime = bridge_hub_polkadot_runtime, + core = { XcmpMessageHandler: bridge_hub_polkadot_runtime::XcmpQueue, DmpMessageHandler: bridge_hub_polkadot_runtime::DmpQueue, LocationToAccountId: bridge_hub_polkadot_runtime::xcm_config::LocationToAccountId, - System: bridge_hub_polkadot_runtime::System, - Balances: bridge_hub_polkadot_runtime::Balances, - ParachainSystem: bridge_hub_polkadot_runtime::ParachainSystem, ParachainInfo: bridge_hub_polkadot_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: bridge_hub_polkadot_runtime::PolkadotXcm, } }, - pub struct PenpalPolkadot { - genesis = penpal::genesis(penpal::PARA_ID), + pub struct PenpalPolkadotA { + genesis = penpal::genesis(penpal::PARA_ID_A), on_init = (), - runtime = { - Runtime: penpal_runtime::Runtime, - RuntimeOrigin: penpal_runtime::RuntimeOrigin, - RuntimeCall: penpal_runtime::RuntimeCall, - RuntimeEvent: penpal_runtime::RuntimeEvent, + runtime = penpal_runtime, + core = { XcmpMessageHandler: penpal_runtime::XcmpQueue, DmpMessageHandler: penpal_runtime::DmpQueue, LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - System: penpal_runtime::System, - Balances: penpal_runtime::Balances, - ParachainSystem: penpal_runtime::ParachainSystem, ParachainInfo: penpal_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } + }, + pub struct PenpalPolkadotB { + genesis = penpal::genesis(penpal::PARA_ID_B), + on_init = (), + runtime = penpal_runtime, + core = { + XcmpMessageHandler: penpal_runtime::XcmpQueue, + DmpMessageHandler: penpal_runtime::DmpQueue, + LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, + ParachainInfo: penpal_runtime::ParachainInfo, + }, + pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, } @@ -208,62 +194,60 @@ decl_test_parachains! { pub struct AssetHubKusama { genesis = asset_hub_kusama::genesis(), on_init = (), - runtime = { - Runtime: asset_hub_kusama_runtime::Runtime, - RuntimeOrigin: asset_hub_kusama_runtime::RuntimeOrigin, - RuntimeCall: asset_hub_kusama_runtime::RuntimeCall, - RuntimeEvent: asset_hub_kusama_runtime::RuntimeEvent, + runtime = asset_hub_kusama_runtime, + core = { XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue, DmpMessageHandler: asset_hub_kusama_runtime::DmpQueue, LocationToAccountId: asset_hub_kusama_runtime::xcm_config::LocationToAccountId, - System: asset_hub_kusama_runtime::System, - Balances: asset_hub_kusama_runtime::Balances, - ParachainSystem: asset_hub_kusama_runtime::ParachainSystem, ParachainInfo: asset_hub_kusama_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: asset_hub_kusama_runtime::PolkadotXcm, Assets: asset_hub_kusama_runtime::Assets, ForeignAssets: asset_hub_kusama_runtime::Assets, + Balances: asset_hub_kusama_runtime::Balances, } }, pub struct BridgeHubKusama { genesis = bridge_hub_kusama::genesis(), on_init = (), - runtime = { - Runtime: bridge_hub_kusama_runtime::Runtime, - RuntimeOrigin: bridge_hub_kusama_runtime::RuntimeOrigin, - RuntimeCall: bridge_hub_kusama_runtime::RuntimeCall, - RuntimeEvent: bridge_hub_kusama_runtime::RuntimeEvent, + runtime = bridge_hub_kusama_runtime, + core = { XcmpMessageHandler: bridge_hub_kusama_runtime::XcmpQueue, DmpMessageHandler: bridge_hub_kusama_runtime::DmpQueue, LocationToAccountId: bridge_hub_kusama_runtime::xcm_config::LocationToAccountId, - System: bridge_hub_kusama_runtime::System, - Balances: bridge_hub_kusama_runtime::Balances, - ParachainSystem: bridge_hub_kusama_runtime::ParachainSystem, ParachainInfo: bridge_hub_kusama_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: bridge_hub_kusama_runtime::PolkadotXcm, } }, - pub struct PenpalKusama { - genesis = penpal::genesis(penpal::PARA_ID), + pub struct PenpalKusamaA { + genesis = penpal::genesis(penpal::PARA_ID_A), + on_init = (), + runtime = penpal_runtime, + core = { + XcmpMessageHandler: penpal_runtime::XcmpQueue, + DmpMessageHandler: penpal_runtime::DmpQueue, + LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, + ParachainInfo: penpal_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } + }, + pub struct PenpalKusamaB { + genesis = penpal::genesis(penpal::PARA_ID_B), on_init = (), - runtime = { - Runtime: penpal_runtime::Runtime, - RuntimeOrigin: penpal_runtime::RuntimeOrigin, - RuntimeCall: penpal_runtime::RuntimeCall, - RuntimeEvent: penpal_runtime::RuntimeEvent, + runtime = penpal_runtime, + core = { XcmpMessageHandler: penpal_runtime::XcmpQueue, DmpMessageHandler: penpal_runtime::DmpQueue, LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - System: penpal_runtime::System, - Balances: penpal_runtime::Balances, - ParachainSystem: penpal_runtime::ParachainSystem, ParachainInfo: penpal_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, } @@ -272,44 +256,33 @@ decl_test_parachains! { pub struct AssetHubWestend { genesis = asset_hub_westend::genesis(), on_init = (), - runtime = { - Runtime: asset_hub_westend_runtime::Runtime, - RuntimeOrigin: asset_hub_westend_runtime::RuntimeOrigin, - RuntimeCall: asset_hub_westend_runtime::RuntimeCall, - RuntimeEvent: asset_hub_westend_runtime::RuntimeEvent, + runtime = asset_hub_westend_runtime, + core = { XcmpMessageHandler: asset_hub_westend_runtime::XcmpQueue, DmpMessageHandler: asset_hub_westend_runtime::DmpQueue, LocationToAccountId: asset_hub_westend_runtime::xcm_config::LocationToAccountId, - System: asset_hub_westend_runtime::System, - Balances: asset_hub_westend_runtime::Balances, - ParachainSystem: asset_hub_westend_runtime::ParachainSystem, ParachainInfo: asset_hub_westend_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm, + Balances: asset_hub_westend_runtime::Balances, Assets: asset_hub_westend_runtime::Assets, ForeignAssets: asset_hub_westend_runtime::ForeignAssets, PoolAssets: asset_hub_westend_runtime::PoolAssets, AssetConversion: asset_hub_westend_runtime::AssetConversion, } }, - pub struct PenpalWestend { - genesis = penpal::genesis(penpal::PARA_ID), + pub struct PenpalWestendA { + genesis = penpal::genesis(penpal::PARA_ID_A), on_init = (), - runtime = { - Runtime: penpal_runtime::Runtime, - RuntimeOrigin: penpal_runtime::RuntimeOrigin, - RuntimeCall: penpal_runtime::RuntimeCall, - RuntimeEvent: penpal_runtime::RuntimeEvent, + runtime = penpal_runtime, + core = { XcmpMessageHandler: penpal_runtime::XcmpQueue, DmpMessageHandler: penpal_runtime::DmpQueue, LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - System: penpal_runtime::System, - Balances: penpal_runtime::Balances, - ParachainSystem: penpal_runtime::ParachainSystem, ParachainInfo: penpal_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, } @@ -318,85 +291,78 @@ decl_test_parachains! { pub struct BridgeHubRococo { genesis = bridge_hub_rococo::genesis(), on_init = (), - runtime = { - Runtime: bridge_hub_rococo_runtime::Runtime, - RuntimeOrigin: bridge_hub_rococo_runtime::RuntimeOrigin, - RuntimeCall: bridge_hub_rococo_runtime::RuntimeCall, - RuntimeEvent: bridge_hub_rococo_runtime::RuntimeEvent, + runtime = bridge_hub_rococo_runtime, + core = { XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, DmpMessageHandler: bridge_hub_rococo_runtime::DmpQueue, LocationToAccountId: bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, - System: bridge_hub_rococo_runtime::System, - Balances: bridge_hub_rococo_runtime::Balances, - ParachainSystem: bridge_hub_rococo_runtime::ParachainSystem, ParachainInfo: bridge_hub_rococo_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, + Balances: bridge_hub_rococo_runtime::Balances, } }, + // AssetHubRococo (aka Rockmine/Rockmine2) mirrors AssetHubKusama pub struct AssetHubRococo { - genesis = asset_hub_polkadot::genesis(), + genesis = asset_hub_kusama::genesis(), on_init = (), - runtime = { - Runtime: asset_hub_polkadot_runtime::Runtime, - RuntimeOrigin: asset_hub_polkadot_runtime::RuntimeOrigin, - RuntimeCall: asset_hub_polkadot_runtime::RuntimeCall, - RuntimeEvent: asset_hub_polkadot_runtime::RuntimeEvent, - XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue, - DmpMessageHandler: asset_hub_polkadot_runtime::DmpQueue, - LocationToAccountId: asset_hub_polkadot_runtime::xcm_config::LocationToAccountId, - System: asset_hub_polkadot_runtime::System, - Balances: asset_hub_polkadot_runtime::Balances, - ParachainSystem: asset_hub_polkadot_runtime::ParachainSystem, - ParachainInfo: asset_hub_polkadot_runtime::ParachainInfo, + runtime = asset_hub_kusama_runtime, + core = { + XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue, + DmpMessageHandler: asset_hub_kusama_runtime::DmpQueue, + LocationToAccountId: asset_hub_kusama_runtime::xcm_config::LocationToAccountId, + ParachainInfo: asset_hub_kusama_runtime::ParachainInfo, }, - pallets_extra = { - PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, - Assets: asset_hub_polkadot_runtime::Assets, + pallets = { + PolkadotXcm: asset_hub_kusama_runtime::PolkadotXcm, + Assets: asset_hub_kusama_runtime::Assets, } }, // Wococo Parachains pub struct BridgeHubWococo { genesis = bridge_hub_rococo::genesis(), on_init = (), - runtime = { - Runtime: bridge_hub_rococo_runtime::Runtime, - RuntimeOrigin: bridge_hub_rococo_runtime::RuntimeOrigin, - RuntimeCall: bridge_hub_rococo_runtime::RuntimeCall, - RuntimeEvent: bridge_hub_rococo_runtime::RuntimeEvent, + runtime = bridge_hub_rococo_runtime, + core = { XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue, DmpMessageHandler: bridge_hub_rococo_runtime::DmpQueue, LocationToAccountId: bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, - System: bridge_hub_rococo_runtime::System, - Balances: bridge_hub_rococo_runtime::Balances, - ParachainSystem: bridge_hub_rococo_runtime::ParachainSystem, ParachainInfo: bridge_hub_rococo_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: bridge_hub_rococo_runtime::PolkadotXcm, } }, pub struct AssetHubWococo { genesis = asset_hub_polkadot::genesis(), on_init = (), - runtime = { - Runtime: asset_hub_polkadot_runtime::Runtime, - RuntimeOrigin: asset_hub_polkadot_runtime::RuntimeOrigin, - RuntimeCall: asset_hub_polkadot_runtime::RuntimeCall, - RuntimeEvent: asset_hub_polkadot_runtime::RuntimeEvent, + runtime = asset_hub_polkadot_runtime, + core = { XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue, DmpMessageHandler: asset_hub_polkadot_runtime::DmpQueue, LocationToAccountId: asset_hub_polkadot_runtime::xcm_config::LocationToAccountId, - System: asset_hub_polkadot_runtime::System, - Balances: asset_hub_polkadot_runtime::Balances, - ParachainSystem: asset_hub_polkadot_runtime::ParachainSystem, ParachainInfo: asset_hub_polkadot_runtime::ParachainInfo, }, - pallets_extra = { + pallets = { PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, Assets: asset_hub_polkadot_runtime::Assets, } + }, + pub struct PenpalRococoA { + genesis = penpal::genesis(penpal::PARA_ID_A), + on_init = (), + runtime = penpal_runtime, + core = { + XcmpMessageHandler: penpal_runtime::XcmpQueue, + DmpMessageHandler: penpal_runtime::DmpQueue, + LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, + ParachainInfo: penpal_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } } } @@ -405,9 +371,10 @@ decl_test_networks! { relay_chain = Polkadot, parachains = vec![ AssetHubPolkadot, - PenpalPolkadot, Collectives, BridgeHubPolkadot, + PenpalPolkadotA, + PenpalPolkadotB, ], // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged // bridge = PolkadotKusamaMockBridge @@ -417,8 +384,9 @@ decl_test_networks! { relay_chain = Kusama, parachains = vec![ AssetHubKusama, - PenpalKusama, + PenpalKusamaA, BridgeHubKusama, + PenpalKusamaB, ], // TODO: uncomment when https://github.com/paritytech/cumulus/pull/2528 is merged // bridge = KusamaPolkadotMockBridge @@ -428,7 +396,7 @@ decl_test_networks! { relay_chain = Westend, parachains = vec![ AssetHubWestend, - PenpalWestend, + PenpalWestendA, ], bridge = () }, @@ -437,6 +405,7 @@ decl_test_networks! { parachains = vec![ AssetHubRococo, BridgeHubRococo, + PenpalRococoA, ], bridge = RococoWococoMockBridge }, @@ -474,6 +443,51 @@ decl_test_bridges! { // } } +// Polkadot implementation +impl_accounts_helpers_for_relay_chain!(Polkadot); +impl_assert_events_helpers_for_relay_chain!(Polkadot); +impl_hrmp_channels_helpers_for_relay_chain!(Polkadot); + +// Kusama implementation +impl_accounts_helpers_for_relay_chain!(Kusama); +impl_assert_events_helpers_for_relay_chain!(Kusama); +impl_hrmp_channels_helpers_for_relay_chain!(Kusama); + +// Westend implementation +impl_accounts_helpers_for_relay_chain!(Westend); +impl_assert_events_helpers_for_relay_chain!(Westend); + +// Rococo implementation +impl_accounts_helpers_for_relay_chain!(Rococo); +impl_assert_events_helpers_for_relay_chain!(Rococo); + +// Wococo implementation +impl_accounts_helpers_for_relay_chain!(Wococo); +impl_assert_events_helpers_for_relay_chain!(Wococo); + +// AssetHubPolkadot implementation +impl_accounts_helpers_for_parachain!(AssetHubPolkadot); +impl_assets_helpers_for_parachain!(AssetHubPolkadot, Polkadot); +impl_assert_events_helpers_for_parachain!(AssetHubPolkadot); + +// AssetHubKusama implementation +impl_accounts_helpers_for_parachain!(AssetHubKusama); +impl_assets_helpers_for_parachain!(AssetHubKusama, Kusama); +impl_assert_events_helpers_for_parachain!(AssetHubKusama); + +// AssetHubWestend implementation +impl_accounts_helpers_for_parachain!(AssetHubWestend); +impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); +impl_assert_events_helpers_for_parachain!(AssetHubWestend); + +// Collectives implementation +impl_accounts_helpers_for_parachain!(Collectives); +impl_assert_events_helpers_for_parachain!(Collectives); + +// BridgeHubRococo implementation +impl_accounts_helpers_for_parachain!(BridgeHubRococo); +impl_assert_events_helpers_for_parachain!(BridgeHubRococo); + decl_test_sender_receiver_accounts_parameter_types! { // Relays Polkadot { sender: ALICE, receiver: BOB }, @@ -495,7 +509,51 @@ decl_test_sender_receiver_accounts_parameter_types! { BridgeHubRococo { sender: ALICE, receiver: BOB }, BridgeHubWococo { sender: ALICE, receiver: BOB }, // Penpals - PenpalPolkadot { sender: ALICE, receiver: BOB }, - PenpalKusama { sender: ALICE, receiver: BOB }, - PenpalWestend { sender: ALICE, receiver: BOB } + PenpalPolkadotA { sender: ALICE, receiver: BOB }, + PenpalPolkadotB { sender: ALICE, receiver: BOB }, + PenpalKusamaA { sender: ALICE, receiver: BOB }, + PenpalKusamaB { sender: ALICE, receiver: BOB }, + PenpalWestendA { sender: ALICE, receiver: BOB }, + PenpalRococoA { sender: ALICE, receiver: BOB } +} + +/// Helper method to build a XCM with a `Transact` instruction and paying for its execution +pub fn xcm_transact_paid_execution( + call: DoubleEncoded<()>, + origin_kind: OriginKind, + native_asset: MultiAsset, + beneficiary: AccountId, +) -> VersionedXcm<()> { + let weight_limit = WeightLimit::Unlimited; + let require_weight_at_most = Weight::from_parts(1000000000, 200000); + let native_assets: MultiAssets = native_asset.clone().into(); + + VersionedXcm::from(Xcm(vec![ + WithdrawAsset(native_assets), + BuyExecution { fees: native_asset, weight_limit }, + Transact { require_weight_at_most, origin_kind, call }, + RefundSurplus, + DepositAsset { + assets: All.into(), + beneficiary: MultiLocation { + parents: 0, + interior: X1(AccountId32 { network: None, id: beneficiary.into() }), + }, + }, + ])) +} + +/// Helper method to build a XCM with a `Transact` instruction without paying for its execution +pub fn xcm_transact_unpaid_execution( + call: DoubleEncoded<()>, + origin_kind: OriginKind, +) -> VersionedXcm<()> { + let weight_limit = WeightLimit::Unlimited; + let require_weight_at_most = Weight::from_parts(1000000000, 200000); + let check_origin = None; + + VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit, check_origin }, + Transact { require_weight_at_most, origin_kind, call }, + ])) } diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 3a1402109e2..25d44913bdb 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -8,9 +8,9 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } paste = "1.0.14" -quote = "1.0.32" -casey = "0.4.0" log = { version = "0.4.19", default-features = false } +lazy_static = "1.4.0" +impl-trait-for-tuples = "0.2.2" # Substrate frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -18,9 +18,9 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "mast sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -36,5 +36,6 @@ parachains-common = { path = "../../parachains/common" } # Polkadot xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 115a32ebf24..f881cdd1fca 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -15,37 +15,54 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. pub use codec::{Decode, Encode}; +pub use lazy_static::lazy_static; pub use log; pub use paste; -pub use std::{collections::HashMap, error::Error, fmt, thread::LocalKey}; +pub use std::{ + any::type_name, + collections::HashMap, + error::Error, + fmt, + marker::PhantomData, + ops::Deref, + sync::{Condvar, Mutex}, + thread::LocalKey, +}; // Substrate pub use frame_support::{ assert_ok, - traits::{EnqueueMessage, Get, Hooks, ProcessMessage, ProcessMessageError, ServiceQueues}, + dispatch::EncodeLike, + sp_runtime::{AccountId32, DispatchResult}, + traits::{ + tokens::currency::Currency, EnqueueMessage, Get, Hooks, OriginTrait, ProcessMessage, + ProcessMessageError, ServiceQueues, + }, weights::{Weight, WeightMeter}, }; -pub use frame_system::AccountInfo; +pub use frame_system::{AccountInfo, Config as SystemConfig, Pallet as SystemPallet}; pub use pallet_balances::AccountData; pub use sp_arithmetic::traits::Bounded; -pub use sp_core::{storage::Storage, Pair, H256}; -pub use sp_io; +pub use sp_core::{sr25519, storage::Storage, Pair, H256}; +pub use sp_io::TestExternalities; pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, fmt::Debug}; pub use sp_trie::StorageProof; //Cumulus pub use cumulus_pallet_dmp_queue; -pub use cumulus_pallet_parachain_system; -pub use cumulus_pallet_xcmp_queue; +pub use cumulus_pallet_parachain_system::{self, Pallet as ParachainSystemPallet}; +pub use cumulus_pallet_xcmp_queue::{Config as XcmpQueueConfig, Pallet as XcmpQueuePallet}; pub use cumulus_primitives_core::{ self, relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, PersistedValidationData, XcmpMessageHandler, }; pub use cumulus_primitives_parachain_inherent::ParachainInherentData; pub use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; -pub use pallet_message_queue; +pub use pallet_message_queue::{ + Config as MessageQueueConfig, Event as MessageQueueEvent, Pallet as MessageQueuePallet, +}; pub use parachain_info; -pub use parachains_common::{AccountId, BlockNumber}; +pub use parachains_common::{AccountId, Balance, BlockNumber}; pub use polkadot_primitives; pub use polkadot_runtime_parachains::{ dmp, @@ -53,7 +70,11 @@ pub use polkadot_runtime_parachains::{ }; // Polkadot -pub use xcm::v3::prelude::*; +pub use xcm::{ + v3::prelude::{AccountId32 as AccountId32Junction, Parachain as ParachainJunction, *}, + VersionedMultiAssets, VersionedMultiLocation, +}; +pub use xcm_executor::traits::ConvertLocation; thread_local! { /// Downward messages, each message is: `(to_para_id, [(relay_block_number, msg)])` @@ -72,29 +93,60 @@ thread_local! { pub static UPWARD_MESSAGES: RefCell<HashMap<String, VecDeque<(u32, Vec<u8>)>>> = RefCell::new(HashMap::new()); /// Bridged messages, each message is: `BridgeMessage` pub static BRIDGED_MESSAGES: RefCell<HashMap<String, VecDeque<BridgeMessage>>> = RefCell::new(HashMap::new()); - /// Global incremental relay chain block number - pub static RELAY_BLOCK_NUMBER: RefCell<HashMap<String, u32>> = RefCell::new(HashMap::new()); /// Parachains Ids a the Network pub static PARA_IDS: RefCell<HashMap<String, Vec<u32>>> = RefCell::new(HashMap::new()); /// Flag indicating if global variables have been initialized for a certain Network pub static INITIALIZED: RefCell<HashMap<String, bool>> = RefCell::new(HashMap::new()); } +pub trait CheckAssertion<Origin, Destination, Hops, Args> +where + Origin: Chain + Clone, + Destination: Chain + Clone, + Origin::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Destination::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Hops: Clone, + Args: Clone, +{ + fn check_assertion(test: Test<Origin, Destination, Hops, Args>); +} + +#[impl_trait_for_tuples::impl_for_tuples(5)] +impl<Origin, Destination, Hops, Args> CheckAssertion<Origin, Destination, Hops, Args> for Tuple +where + Origin: Chain + Clone, + Destination: Chain + Clone, + Origin::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Destination::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Hops: Clone, + Args: Clone, +{ + fn check_assertion(test: Test<Origin, Destination, Hops, Args>) { + for_tuples!( #( + Tuple::check_assertion(test.clone()); + )* ); + } +} + pub trait TestExt { - fn build_new_ext(storage: Storage) -> sp_io::TestExternalities; - fn new_ext() -> sp_io::TestExternalities; + fn build_new_ext(storage: Storage) -> TestExternalities; + fn new_ext() -> TestExternalities; + fn move_ext_out(id: &'static str); + fn move_ext_in(id: &'static str); fn reset_ext(); fn execute_with<R>(execute: impl FnOnce() -> R) -> R; fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R; } impl TestExt for () { - fn build_new_ext(_storage: Storage) -> sp_io::TestExternalities { - sp_io::TestExternalities::default() + fn build_new_ext(_storage: Storage) -> TestExternalities { + TestExternalities::default() } - fn new_ext() -> sp_io::TestExternalities { - sp_io::TestExternalities::default() + fn new_ext() -> TestExternalities { + TestExternalities::default() } + fn move_ext_out(_id: &'static str) {} + fn move_ext_in(_id: &'static str) {} fn reset_ext() {} fn execute_with<R>(execute: impl FnOnce() -> R) -> R { execute() @@ -105,12 +157,15 @@ impl TestExt for () { } pub trait Network { + type Relay: RelayChain; type Bridge: Bridge; + fn name() -> &'static str; fn init(); + fn reset(); fn para_ids() -> Vec<u32>; fn relay_block_number() -> u32; - fn set_relay_block_number(block_number: u32); + fn set_relay_block_number(number: u32); fn process_messages(); fn has_unprocessed_messages() -> bool; fn process_downward_messages(); @@ -126,15 +181,13 @@ pub trait Network { pub trait NetworkComponent { type Network: Network; - fn network_name() -> &'static str; - fn send_horizontal_messages<I: Iterator<Item = (ParaId, RelayBlockNumber, Vec<u8>)>>( to_para_id: u32, iter: I, ) { HORIZONTAL_MESSAGES.with(|b| { b.borrow_mut() - .get_mut(Self::network_name()) + .get_mut(Self::Network::name()) .unwrap() .push_back((to_para_id, iter.collect())) }); @@ -143,7 +196,7 @@ pub trait NetworkComponent { fn send_upward_message(from_para_id: u32, msg: Vec<u8>) { UPWARD_MESSAGES.with(|b| { b.borrow_mut() - .get_mut(Self::network_name()) + .get_mut(Self::Network::name()) .unwrap() .push_back((from_para_id, msg)) }); @@ -155,7 +208,7 @@ pub trait NetworkComponent { ) { DOWNWARD_MESSAGES.with(|b| { b.borrow_mut() - .get_mut(Self::network_name()) + .get_mut(Self::Network::name()) .unwrap() .push_back((to_para_id, iter.collect())) }); @@ -163,33 +216,67 @@ pub trait NetworkComponent { fn send_bridged_messages(msg: BridgeMessage) { BRIDGED_MESSAGES - .with(|b| b.borrow_mut().get_mut(Self::network_name()).unwrap().push_back(msg)); + .with(|b| b.borrow_mut().get_mut(Self::Network::name()).unwrap().push_back(msg)); } } -pub trait RelayChain: ProcessMessage { - type Runtime; - type RuntimeOrigin; +pub trait Chain: TestExt + NetworkComponent { + type Runtime: SystemConfig; type RuntimeCall; + type RuntimeOrigin; type RuntimeEvent; - type XcmConfig; - type SovereignAccountOf; type System; - type Balances; + + fn account_id_of(seed: &str) -> AccountId { + helpers::get_account_id_from_seed::<sr25519::Public>(seed) + } + + fn account_data_of(account: AccountId) -> AccountData<Balance>; + + fn events() -> Vec<<Self as Chain>::RuntimeEvent>; } -pub trait Parachain: XcmpMessageHandler + DmpMessageHandler { - type Runtime; - type RuntimeOrigin; - type RuntimeCall; - type RuntimeEvent; - type XcmpMessageHandler; - type DmpMessageHandler; - type LocationToAccountId; - type System; - type Balances; +pub trait RelayChain: Chain { + type MessageProcessor: ProcessMessage; + type SovereignAccountOf: ConvertLocation<AccountId>; + + fn child_location_of(id: ParaId) -> MultiLocation { + (Ancestor(0), ParachainJunction(id.into())).into() + } + + fn sovereign_account_id_of(location: MultiLocation) -> AccountId { + Self::SovereignAccountOf::convert_location(&location).unwrap() + } + + fn sovereign_account_id_of_child_para(id: ParaId) -> AccountId { + Self::sovereign_account_id_of(Self::child_location_of(id)) + } +} + +pub trait Parachain: Chain { + type XcmpMessageHandler: XcmpMessageHandler; + type DmpMessageHandler: DmpMessageHandler; + type LocationToAccountId: ConvertLocation<AccountId>; + type ParachainInfo: Get<ParaId>; type ParachainSystem; - type ParachainInfo; + + fn para_id() -> ParaId { + Self::ext_wrapper(|| Self::ParachainInfo::get()) + } + + fn parent_location() -> MultiLocation { + (Parent).into() + } + + fn sibling_location_of(para_id: ParaId) -> MultiLocation { + (Parent, X1(ParachainJunction(para_id.into()))).into() + } + + fn sovereign_account_id_of(location: MultiLocation) -> AccountId { + Self::LocationToAccountId::convert_location(&location).unwrap() + } + + fn prepare_for_xcmp(); } pub trait Bridge { @@ -250,19 +337,6 @@ impl fmt::Display for BridgeMessageDispatchError { } } -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed<TPublic: sp_core::Public>(seed: &str) -> AccountId -where - sp_runtime::MultiSigner: - From<<<TPublic as sp_runtime::CryptoType>::Pair as sp_core::Pair>::Public>, -{ - use sp_runtime::traits::IdentifyAccount; - let pubkey = TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public(); - sp_runtime::MultiSigner::from(pubkey).into_account() -} - // Relay Chain Implementation #[macro_export] macro_rules! decl_test_relay_chains { @@ -272,18 +346,13 @@ macro_rules! decl_test_relay_chains { pub struct $name:ident { genesis = $genesis:expr, on_init = $on_init:expr, - runtime = { - Runtime: $runtime:path, - RuntimeOrigin: $runtime_origin:path, - RuntimeCall: $runtime_call:path, - RuntimeEvent: $runtime_event:path, - MessageQueue: $mq:path, - XcmConfig: $xcm_config:path, + runtime = $runtime:ident, + core = { + MessageProcessor: $mp:path, SovereignAccountOf: $sovereign_acc_of:path, - System: $system:path, - Balances: $balances:path, + }, - pallets_extra = { + pallets = { $($pallet_name:ident: $pallet_path:path,)* } } @@ -291,17 +360,31 @@ macro_rules! decl_test_relay_chains { + ) => { $( + #[derive(Clone)] pub struct $name; + impl Chain for $name { + type Runtime = $runtime::Runtime; + type RuntimeCall = $runtime::RuntimeCall; + type RuntimeOrigin = $runtime::RuntimeOrigin; + type RuntimeEvent = $runtime::RuntimeEvent; + type System = $crate::SystemPallet::<Self::Runtime>; + + fn account_data_of(account: AccountId) -> $crate::AccountData<Balance> { + Self::ext_wrapper(|| $crate::SystemPallet::<Self::Runtime>::account(account).data.into()) + } + + fn events() -> Vec<<Self as Chain>::RuntimeEvent> { + Self::System::events() + .iter() + .map(|record| record.event.clone()) + .collect() + } + } + impl RelayChain for $name { - type Runtime = $runtime; - type RuntimeOrigin = $runtime_origin; - type RuntimeCall = $runtime_call; - type RuntimeEvent = $runtime_event; - type XcmConfig = $xcm_config; type SovereignAccountOf = $sovereign_acc_of; - type System = $system; - type Balances = $balances; + type MessageProcessor = $mp; } $crate::paste::paste! { @@ -318,43 +401,8 @@ macro_rules! decl_test_relay_chains { } } - impl $crate::ProcessMessage for $name { - type Origin = $crate::ParaId; - - fn process_message( - msg: &[u8], - para: Self::Origin, - meter: &mut $crate::WeightMeter, - _id: &mut XcmHash - ) -> Result<bool, $crate::ProcessMessageError> { - use $crate::{Weight, AggregateMessageOrigin, UmpQueueId, ServiceQueues, EnqueueMessage}; - use $mq as message_queue; - use $runtime_event as runtime_event; - - Self::ext_wrapper(|| { - <$mq as EnqueueMessage<AggregateMessageOrigin>>::enqueue_message( - msg.try_into().expect("Message too long"), - AggregateMessageOrigin::Ump(UmpQueueId::Para(para.clone())) - ); - - <$system>::reset_events(); - <$mq as ServiceQueues>::service_queues(Weight::MAX); - let events = <$system>::events(); - let event = events.last().expect("There must be at least one event"); - - match &event.event { - runtime_event::MessageQueue( - $crate::pallet_message_queue::Event::Processed {origin, ..}) => { - assert_eq!(origin, &AggregateMessageOrigin::Ump(UmpQueueId::Para(para))); - }, - event => panic!("Unexpected event: {:#?}", event), - } - Ok(true) - }) - } - } - $crate::__impl_test_ext_for_relay_chain!($name, $genesis, $on_init, $api_version); + $crate::__impl_check_assertion!($name); )+ }; } @@ -364,34 +412,99 @@ macro_rules! __impl_test_ext_for_relay_chain { // entry point: generate ext name ($name:ident, $genesis:expr, $on_init:expr, $api_version:tt) => { $crate::paste::paste! { - $crate::__impl_test_ext_for_relay_chain!(@impl $name, $genesis, $on_init, [<ParachainHostV $api_version>], [<EXT_ $name:upper>]); + $crate::__impl_test_ext_for_relay_chain!( + @impl $name, + $genesis, + $on_init, + [<ParachainHostV $api_version>], + [<LOCAL_EXT_ $name:upper>], + [<GLOBAL_EXT_ $name:upper>] + ); } }; // impl - (@impl $name:ident, $genesis:expr, $on_init:expr, $api_version:ident, $ext_name:ident) => { + (@impl $name:ident, $genesis:expr, $on_init:expr, $api_version:ident, $local_ext:ident, $global_ext:ident) => { thread_local! { - pub static $ext_name: $crate::RefCell<$crate::sp_io::TestExternalities> + pub static $local_ext: $crate::RefCell<$crate::TestExternalities> = $crate::RefCell::new(<$name>::build_new_ext($genesis)); } + $crate::lazy_static! { + pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>> + = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); + } + impl TestExt for $name { - fn build_new_ext(storage: $crate::Storage) -> $crate::sp_io::TestExternalities { - let mut ext = sp_io::TestExternalities::new(storage); + fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { + use $crate::{NetworkComponent, Network, Chain}; + + let mut ext = $crate::TestExternalities::new(storage); + ext.execute_with(|| { #[allow(clippy::no_effect)] $on_init; sp_tracing::try_init_simple(); - <Self as RelayChain>::System::set_block_number(1); + + let mut block_number = <Self as Chain>::System::block_number(); + block_number = std::cmp::max(1, block_number); + <Self as Chain>::System::set_block_number(block_number); }); ext } - fn new_ext() -> $crate::sp_io::TestExternalities { + fn new_ext() -> $crate::TestExternalities { <$name>::build_new_ext($genesis) } + fn move_ext_out(id: &'static str) { + use $crate::Deref; + + // Take TestExternality from thread_local + let local_ext = $local_ext.with(|v| { + v.take() + }); + + // Get TestExternality from lazy_static + let global_ext_guard = $global_ext.lock().unwrap(); + + // Replace TestExternality in lazy_static by TestExternality from thread_local + global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext); + } + + fn move_ext_in(id: &'static str) { + use $crate::Deref; + + let mut global_ext_unlocked = false; + + // Keep the mutex unlocked until TesExternality from lazy_static + // has been updated + while !global_ext_unlocked { + // Get TesExternality from lazy_static + let global_ext_result = $global_ext.try_lock(); + + if let Ok(global_ext_guard) = global_ext_result { + // Unlock the mutex as long as the condition is not met + if !global_ext_guard.deref().borrow().contains_key(id) { + drop(global_ext_guard); + } else { + global_ext_unlocked = true; + } + } + } + + // Now that we know that lazy_static TestExt has been updated, we lock its mutex + let mut global_ext_guard = $global_ext.lock().unwrap(); + + // and set TesExternality from lazy_static into TesExternality for local_thread + let global_ext = global_ext_guard.deref(); + + $local_ext.with(|v| { + v.replace(global_ext.take().remove(id).unwrap()); + }); + } + fn reset_ext() { - $ext_name.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); + $local_ext.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); } fn execute_with<R>(execute: impl FnOnce() -> R) -> R { @@ -399,17 +512,18 @@ macro_rules! __impl_test_ext_for_relay_chain { // Make sure the Network is initialized <$name as NetworkComponent>::Network::init(); - let r = $ext_name.with(|v| v.borrow_mut().execute_with(execute)); + // Execute + let r = $local_ext.with(|v| v.borrow_mut().execute_with(execute)); - // send messages if needed - $ext_name.with(|v| { + // Send messages if needed + $local_ext.with(|v| { v.borrow_mut().execute_with(|| { use $crate::polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::$api_version; //TODO: mark sent count & filter out sent msg for para_id in<$name as NetworkComponent>::Network::para_ids() { // downward messages - let downward_messages = <Self as RelayChain>::Runtime::dmq_contents(para_id.into()) + let downward_messages = <Self as Chain>::Runtime::dmq_contents(para_id.into()) .into_iter() .map(|inbound| (inbound.sent_at, inbound.msg)); if downward_messages.len() == 0 { @@ -420,6 +534,14 @@ macro_rules! __impl_test_ext_for_relay_chain { // Note: no need to handle horizontal messages, as the // simulator directly sends them to dest (not relayed). } + + // log events + Self::events().iter().for_each(|event| { + $crate::log::debug!(target: concat!("events::", stringify!($name)), "{:?}", event); + }); + + // clean events + <Self as Chain>::System::reset_events(); }) }); @@ -429,7 +551,7 @@ macro_rules! __impl_test_ext_for_relay_chain { } fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R { - $ext_name.with(|v| { + $local_ext.with(|v| { v.borrow_mut().execute_with(|| { func() }) @@ -439,56 +561,6 @@ macro_rules! __impl_test_ext_for_relay_chain { }; } -#[macro_export] -macro_rules! __impl_relay { - ($network:ident, $relay_chain:ty) => { - impl $crate::NetworkComponent for $relay_chain { - type Network = $network; - - fn network_name() -> &'static str { - stringify!($network) - } - } - - impl $relay_chain { - pub fn child_location_of(id: $crate::ParaId) -> MultiLocation { - (Ancestor(0), Parachain(id.into())).into() - } - - pub fn account_id_of(seed: &str) -> $crate::AccountId { - $crate::get_account_id_from_seed::<sr25519::Public>(seed) - } - - pub fn account_data_of(account: AccountId) -> $crate::AccountData<Balance> { - Self::ext_wrapper(|| <Self as RelayChain>::System::account(account).data) - } - - pub fn sovereign_account_id_of(location: $crate::MultiLocation) -> $crate::AccountId { - <Self as RelayChain>::SovereignAccountOf::convert_location(&location).unwrap() - } - - pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { - Self::ext_wrapper(|| { - for account in accounts { - let _ = <Self as RelayChain>::Balances::force_set_balance( - <Self as RelayChain>::RuntimeOrigin::root(), - account.0.into(), - account.1.into(), - ); - } - }); - } - - pub fn events() -> Vec<<Self as RelayChain>::RuntimeEvent> { - <Self as RelayChain>::System::events() - .iter() - .map(|record| record.event.clone()) - .collect() - } - } - }; -} - // Parachain Implementation #[macro_export] macro_rules! decl_test_parachains { @@ -497,20 +569,14 @@ macro_rules! decl_test_parachains { pub struct $name:ident { genesis = $genesis:expr, on_init = $on_init:expr, - runtime = { - Runtime: $runtime:path, - RuntimeOrigin: $runtime_origin:path, - RuntimeCall: $runtime_call:path, - RuntimeEvent: $runtime_event:path, + runtime = $runtime:ident, + core = { XcmpMessageHandler: $xcmp_message_handler:path, DmpMessageHandler: $dmp_message_handler:path, LocationToAccountId: $location_to_account:path, - System: $system:path, - Balances: $balances_pallet:path, - ParachainSystem: $parachain_system:path, ParachainInfo: $parachain_info:path, }, - pallets_extra = { + pallets = { $($pallet_name:ident: $pallet_path:path,)* } } @@ -518,20 +584,55 @@ macro_rules! decl_test_parachains { + ) => { $( + #[derive(Clone)] pub struct $name; + impl Chain for $name { + type Runtime = $runtime::Runtime; + type RuntimeCall = $runtime::RuntimeCall; + type RuntimeOrigin = $runtime::RuntimeOrigin; + type RuntimeEvent = $runtime::RuntimeEvent; + type System = $crate::SystemPallet::<Self::Runtime>; + + fn account_data_of(account: AccountId) -> $crate::AccountData<Balance> { + Self::ext_wrapper(|| $crate::SystemPallet::<Self::Runtime>::account(account).data.into()) + } + + fn events() -> Vec<<Self as Chain>::RuntimeEvent> { + Self::System::events() + .iter() + .map(|record| record.event.clone()) + .collect() + } + } + impl Parachain for $name { - type Runtime = $runtime; - type RuntimeOrigin = $runtime_origin; - type RuntimeCall = $runtime_call; - type RuntimeEvent = $runtime_event; type XcmpMessageHandler = $xcmp_message_handler; type DmpMessageHandler = $dmp_message_handler; type LocationToAccountId = $location_to_account; - type System = $system; - type Balances = $balances_pallet; - type ParachainSystem = $parachain_system; + type ParachainSystem = $crate::ParachainSystemPallet<<Self as Chain>::Runtime>; type ParachainInfo = $parachain_info; + + fn prepare_for_xcmp() { + use $crate::{Network, NetworkComponent, Hooks}; + + let para_id = Self::para_id(); + + <Self as TestExt>::ext_wrapper(|| { + let block_number = <Self as Chain>::System::block_number(); + let mut relay_block_number = <Self as NetworkComponent>::Network::relay_block_number(); + + let _ = <Self as Parachain>::ParachainSystem::set_validation_data( + <Self as Chain>::RuntimeOrigin::none(), + <Self as NetworkComponent>::Network::hrmp_channel_parachain_inherent_data( + para_id.into(), + relay_block_number, + ), + ); + // set `AnnouncedHrmpMessagesPerCandidate` + <Self as Parachain>::ParachainSystem::on_initialize(block_number); + }); + } } $crate::paste::paste! { @@ -548,79 +649,103 @@ macro_rules! decl_test_parachains { } } - $crate::__impl_xcm_handlers_for_parachain!($name); $crate::__impl_test_ext_for_parachain!($name, $genesis, $on_init); + $crate::__impl_check_assertion!($name); )+ }; } -#[macro_export] -macro_rules! __impl_xcm_handlers_for_parachain { - ($name:ident) => { - impl $crate::XcmpMessageHandler for $name { - fn handle_xcmp_messages< - 'a, - I: Iterator<Item = ($crate::ParaId, $crate::RelayBlockNumber, &'a [u8])>, - >( - iter: I, - max_weight: $crate::Weight, - ) -> $crate::Weight { - use $crate::{TestExt, XcmpMessageHandler}; - - $name::ext_wrapper(|| { - <Self as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter, max_weight) - }) - } - } - - impl $crate::DmpMessageHandler for $name { - fn handle_dmp_messages( - iter: impl Iterator<Item = ($crate::RelayBlockNumber, Vec<u8>)>, - max_weight: $crate::Weight, - ) -> $crate::Weight { - use $crate::{DmpMessageHandler, TestExt}; - - $name::ext_wrapper(|| { - <Self as Parachain>::DmpMessageHandler::handle_dmp_messages(iter, max_weight) - }) - } - } - }; -} - #[macro_export] macro_rules! __impl_test_ext_for_parachain { // entry point: generate ext name ($name:ident, $genesis:expr, $on_init:expr) => { $crate::paste::paste! { - $crate::__impl_test_ext_for_parachain!(@impl $name, $genesis, $on_init, [<EXT_ $name:upper>]); + $crate::__impl_test_ext_for_parachain!(@impl $name, $genesis, $on_init, [<LOCAL_EXT_ $name:upper>], [<GLOBAL_EXT_ $name:upper>]); } }; // impl - (@impl $name:ident, $genesis:expr, $on_init:expr, $ext_name:ident) => { + (@impl $name:ident, $genesis:expr, $on_init:expr, $local_ext:ident, $global_ext:ident) => { thread_local! { - pub static $ext_name: $crate::RefCell<$crate::sp_io::TestExternalities> + pub static $local_ext: $crate::RefCell<$crate::TestExternalities> = $crate::RefCell::new(<$name>::build_new_ext($genesis)); } + $crate::lazy_static! { + pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap<String, $crate::TestExternalities>>> + = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); + } + impl TestExt for $name { - fn build_new_ext(storage: $crate::Storage) -> $crate::sp_io::TestExternalities { - let mut ext = sp_io::TestExternalities::new(storage); + fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { + use $crate::{NetworkComponent, Network, Chain}; + + let mut ext = $crate::TestExternalities::new(storage); + ext.execute_with(|| { #[allow(clippy::no_effect)] $on_init; sp_tracing::try_init_simple(); - <Self as Parachain>::System::set_block_number(1); + + let mut block_number = <Self as Chain>::System::block_number(); + block_number = std::cmp::max(1, block_number); + <Self as Chain>::System::set_block_number(block_number); }); ext } - fn new_ext() -> $crate::sp_io::TestExternalities { + fn new_ext() -> $crate::TestExternalities { <$name>::build_new_ext($genesis) } + fn move_ext_out(id: &'static str) { + use $crate::Deref; + + // Take TestExternality from thread_local + let local_ext = $local_ext.with(|v| { + v.take() + }); + + // Get TestExternality from lazy_static + let global_ext_guard = $global_ext.lock().unwrap(); + + // Replace TestExternality in lazy_static by TestExternality from thread_local + global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext); + } + + fn move_ext_in(id: &'static str) { + use $crate::Deref; + + let mut global_ext_unlocked = false; + + // Keep the mutex unlocked until TesExternality from lazy_static + // has been updated + while !global_ext_unlocked { + // Get TesExternality from lazy_static + let global_ext_result = $global_ext.try_lock(); + + if let Ok(global_ext_guard) = global_ext_result { + // Unlock the mutex as long as the condition is not met + if !global_ext_guard.deref().borrow().contains_key(id) { + drop(global_ext_guard); + } else { + global_ext_unlocked = true; + } + } + } + + // Now that we know that lazy_static TestExt has been updated, we lock its mutex + let mut global_ext_guard = $global_ext.lock().unwrap(); + + // and set TesExternality from lazy_static into TesExternality for local_thread + let global_ext = global_ext_guard.deref(); + + $local_ext.with(|v| { + v.replace(global_ext.take().remove(id).unwrap()); + }); + } + fn reset_ext() { - $ext_name.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); + $local_ext.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); } fn execute_with<R>(execute: impl FnOnce() -> R) -> R { @@ -629,32 +754,32 @@ macro_rules! __impl_test_ext_for_parachain { // Make sure the Network is initialized <$name as NetworkComponent>::Network::init(); - let mut relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); - relay_block_number += 1; - <$name as NetworkComponent>::Network::set_relay_block_number(relay_block_number); - let para_id = <$name>::para_id().into(); - $ext_name.with(|v| { + // Initialize block + $local_ext.with(|v| { v.borrow_mut().execute_with(|| { - // Make sure it has been recorded properly - let relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); + // Increase block number + let mut relay_block_number = <$name as NetworkComponent>::Network::relay_block_number(); + relay_block_number += 1; + <$name as NetworkComponent>::Network::set_relay_block_number(relay_block_number); + let _ = <Self as Parachain>::ParachainSystem::set_validation_data( - <Self as Parachain>::RuntimeOrigin::none(), + <Self as Chain>::RuntimeOrigin::none(), <$name as NetworkComponent>::Network::hrmp_channel_parachain_inherent_data(para_id, relay_block_number), ); }) }); + // Execute + let r = $local_ext.with(|v| v.borrow_mut().execute_with(execute)); - let r = $ext_name.with(|v| v.borrow_mut().execute_with(execute)); - - // send messages if needed - $ext_name.with(|v| { + // Finalize block and send messages if needed + $local_ext.with(|v| { v.borrow_mut().execute_with(|| { use sp_runtime::traits::Header as HeaderT; - let block_number = <Self as Parachain>::System::block_number(); + let block_number = <Self as Chain>::System::block_number(); let mock_header = HeaderT::new( 0, Default::default(), @@ -693,6 +818,14 @@ macro_rules! __impl_test_ext_for_parachain { // clean messages <Self as Parachain>::ParachainSystem::on_initialize(block_number); + + // log events + Self::events().iter().for_each(|event| { + $crate::log::debug!(target: concat!("events::", stringify!($name)), "{:?}", event); + }); + + // clean events + <Self as Chain>::System::reset_events(); }) }); @@ -702,7 +835,7 @@ macro_rules! __impl_test_ext_for_parachain { } fn ext_wrapper<R>(func: impl FnOnce() -> R) -> R { - $ext_name.with(|v| { + $local_ext.with(|v| { v.borrow_mut().execute_with(|| { func() }) @@ -712,85 +845,6 @@ macro_rules! __impl_test_ext_for_parachain { }; } -#[macro_export] -macro_rules! __impl_parachain { - ($network:ident, $parachain:ty) => { - impl $crate::NetworkComponent for $parachain { - type Network = $network; - - fn network_name() -> &'static str { - stringify!($network) - } - } - - impl $parachain { - pub fn para_id() -> $crate::ParaId { - Self::ext_wrapper(|| <Self as Parachain>::ParachainInfo::get()) - } - - pub fn parent_location() -> $crate::MultiLocation { - (Parent).into() - } - - pub fn sibling_location_of(para_id: $crate::ParaId) -> $crate::MultiLocation { - (Parent, X1(Parachain(para_id.into()))).into() - } - - pub fn account_id_of(seed: &str) -> $crate::AccountId { - $crate::get_account_id_from_seed::<sr25519::Public>(seed) - } - - pub fn account_data_of(account: AccountId) -> $crate::AccountData<Balance> { - Self::ext_wrapper(|| <Self as Parachain>::System::account(account).data) - } - - pub fn sovereign_account_id_of(location: $crate::MultiLocation) -> $crate::AccountId { - <Self as Parachain>::LocationToAccountId::convert_location(&location).unwrap() - } - - pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { - Self::ext_wrapper(|| { - for account in accounts { - let _ = <Self as Parachain>::Balances::force_set_balance( - <Self as Parachain>::RuntimeOrigin::root(), - account.0.into(), - account.1.into(), - ); - } - }); - } - - pub fn events() -> Vec<<Self as Parachain>::RuntimeEvent> { - <Self as Parachain>::System::events() - .iter() - .map(|record| record.event.clone()) - .collect() - } - - fn prepare_for_xcmp() { - use $crate::{Network, NetworkComponent}; - let para_id = Self::para_id(); - - <Self as TestExt>::ext_wrapper(|| { - use $crate::{Get, Hooks}; - - let block_number = <Self as Parachain>::System::block_number(); - - let _ = <Self as Parachain>::ParachainSystem::set_validation_data( - <Self as Parachain>::RuntimeOrigin::none(), - <Self as NetworkComponent>::Network::hrmp_channel_parachain_inherent_data( - para_id.into(), - 1, - ), - ); - // set `AnnouncedHrmpMessagesPerCandidate` - <Self as Parachain>::ParachainSystem::on_initialize(block_number); - }); - } - } - }; -} - // Network Implementation #[macro_export] macro_rules! decl_test_networks { @@ -807,37 +861,38 @@ macro_rules! decl_test_networks { $( pub struct $name; - impl $name { - pub fn reset() { + impl $crate::Network for $name { + type Relay = $relay_chain; + type Bridge = $bridge; + + fn name() -> &'static str { + $crate::type_name::<Self>() + } + + fn reset() { use $crate::{TestExt, VecDeque}; - $crate::INITIALIZED.with(|b| b.borrow_mut().remove(stringify!($name))); - $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().remove(stringify!($name))); - $crate::DMP_DONE.with(|b| b.borrow_mut().remove(stringify!($name))); - $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().remove(stringify!($name))); - $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().remove(stringify!($name))); - $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().remove(stringify!($name))); - $crate::RELAY_BLOCK_NUMBER.with(|b| b.borrow_mut().remove(stringify!($name))); + $crate::INITIALIZED.with(|b| b.borrow_mut().remove(Self::name())); + $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().remove(Self::name())); + $crate::DMP_DONE.with(|b| b.borrow_mut().remove(Self::name())); + $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().remove(Self::name())); + $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().remove(Self::name())); + $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().remove(Self::name())); <$relay_chain>::reset_ext(); $( <$parachain>::reset_ext(); )* } - } - - impl $crate::Network for $name { - type Bridge = $bridge; fn init() { // If Network has not been itialized yet, it gets initialized - if $crate::INITIALIZED.with(|b| b.borrow_mut().get(stringify!($name)).is_none()) { - $crate::INITIALIZED.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), true)); - $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), $crate::VecDeque::new())); - $crate::DMP_DONE.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), $crate::VecDeque::new())); - $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), $crate::VecDeque::new())); - $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), $crate::VecDeque::new())); - $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), $crate::VecDeque::new())); - $crate::RELAY_BLOCK_NUMBER.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), 1)); - $crate::PARA_IDS.with(|b| b.borrow_mut().insert(stringify!($name).to_string(), Self::para_ids())); + if $crate::INITIALIZED.with(|b| b.borrow_mut().get(Self::name()).is_none()) { + $crate::INITIALIZED.with(|b| b.borrow_mut().insert(Self::name().to_string(), true)); + $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new())); + $crate::DMP_DONE.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new())); + $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new())); + $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new())); + $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().insert(Self::name().to_string(), $crate::VecDeque::new())); + $crate::PARA_IDS.with(|b| b.borrow_mut().insert(Self::name().to_string(), Self::para_ids())); $( <$parachain>::prepare_for_xcmp(); )* } @@ -850,11 +905,15 @@ macro_rules! decl_test_networks { } fn relay_block_number() -> u32 { - $crate::RELAY_BLOCK_NUMBER.with(|v| *v.clone().borrow().get(stringify!($name)).unwrap()) + Self::Relay::ext_wrapper(|| { + <Self::Relay as Chain>::System::block_number() + }) } - fn set_relay_block_number(block_number: u32) { - $crate::RELAY_BLOCK_NUMBER.with(|v| v.borrow_mut().insert(stringify!($name).to_string(), block_number)); + fn set_relay_block_number(number: u32) { + Self::Relay::ext_wrapper(|| { + <Self::Relay as Chain>::System::set_block_number(number); + }) } fn process_messages() { @@ -867,10 +926,10 @@ macro_rules! decl_test_networks { } fn has_unprocessed_messages() -> bool { - $crate::DOWNWARD_MESSAGES.with(|b| !b.borrow_mut().get_mut(stringify!($name)).unwrap().is_empty()) - || $crate::HORIZONTAL_MESSAGES.with(|b| !b.borrow_mut().get_mut(stringify!($name)).unwrap().is_empty()) - || $crate::UPWARD_MESSAGES.with(|b| !b.borrow_mut().get_mut(stringify!($name)).unwrap().is_empty()) - || $crate::BRIDGED_MESSAGES.with(|b| !b.borrow_mut().get_mut(stringify!($name)).unwrap().is_empty()) + $crate::DOWNWARD_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty()) + || $crate::HORIZONTAL_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty()) + || $crate::UPWARD_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty()) + || $crate::BRIDGED_MESSAGES.with(|b| !b.borrow_mut().get_mut(Self::name()).unwrap().is_empty()) } fn process_downward_messages() { @@ -878,11 +937,11 @@ macro_rules! decl_test_networks { use polkadot_parachain::primitives::RelayChainBlockNumber; while let Some((to_para_id, messages)) - = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().pop_front()) { + = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { $( let para_id: u32 = <$parachain>::para_id().into(); - if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().contains(&to_para_id)) && para_id == to_para_id { + if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id { let mut msg_dedup: Vec<(RelayChainBlockNumber, Vec<u8>)> = Vec::new(); for m in &messages { msg_dedup.push((m.0, m.1.clone())); @@ -890,13 +949,15 @@ macro_rules! decl_test_networks { msg_dedup.dedup(); let msgs = msg_dedup.clone().into_iter().filter(|m| { - !$crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap_or(&mut $crate::VecDeque::new()).contains(&(to_para_id, m.0, m.1.clone()))) + !$crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap_or(&mut $crate::VecDeque::new()).contains(&(to_para_id, m.0, m.1.clone()))) }).collect::<Vec<(RelayChainBlockNumber, Vec<u8>)>>(); if msgs.len() != 0 { - <$parachain>::handle_dmp_messages(msgs.clone().into_iter(), $crate::Weight::max_value()); + <$parachain>::ext_wrapper(|| { + <$parachain as Parachain>::DmpMessageHandler::handle_dmp_messages(msgs.clone().into_iter(), $crate::Weight::max_value()); + }); $crate::log::debug!(target: concat!("dmp::", stringify!($name)) , "DMP messages processed {:?} to para_id {:?}", msgs.clone(), &to_para_id); for m in msgs { - $crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().push_back((to_para_id, m.0, m.1))); + $crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((to_para_id, m.0, m.1))); } } } @@ -908,13 +969,15 @@ macro_rules! decl_test_networks { use $crate::{XcmpMessageHandler, Bounded}; while let Some((to_para_id, messages)) - = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().pop_front()) { + = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { let iter = messages.iter().map(|(p, b, m)| (*p, *b, &m[..])).collect::<Vec<_>>().into_iter(); $( let para_id: u32 = <$parachain>::para_id().into(); - if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().contains(&to_para_id)) && para_id == to_para_id { - <$parachain>::handle_xcmp_messages(iter.clone(), $crate::Weight::max_value()); + if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().contains(&to_para_id)) && para_id == to_para_id { + <$parachain>::ext_wrapper(|| { + <$parachain as Parachain>::XcmpMessageHandler::handle_xcmp_messages(iter.clone(), $crate::Weight::max_value()); + }); $crate::log::debug!(target: concat!("hrmp::", stringify!($name)) , "HRMP messages processed {:?} to para_id {:?}", &messages, &to_para_id); } )* @@ -924,14 +987,16 @@ macro_rules! decl_test_networks { fn process_upward_messages() { use $crate::{Bounded, ProcessMessage, WeightMeter}; use sp_core::Encode; - while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().pop_front()) { + while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { let mut weight_meter = WeightMeter::max_limit(); - let _ = <$relay_chain>::process_message( - &msg[..], - from_para_id.into(), - &mut weight_meter, - &mut msg.using_encoded(sp_core::blake2_256), - ); + <$relay_chain>::ext_wrapper(|| { + let _ = <$relay_chain as RelayChain>::MessageProcessor::process_message( + &msg[..], + from_para_id.into(), + &mut weight_meter, + &mut msg.using_encoded(sp_core::blake2_256), + ); + }); $crate::log::debug!(target: concat!("ump::", stringify!($name)) , "Upward message processed {:?} from para_id {:?}", &msg, &from_para_id); } } @@ -941,7 +1006,7 @@ macro_rules! decl_test_networks { // Make sure both, including the target `Network` are initialized <Self::Bridge as Bridge>::init(); - while let Some(msg) = $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().pop_front()) { + while let Some(msg) = $crate::BRIDGED_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { let dispatch_result = <<Self::Bridge as $crate::Bridge>::Target as TestExt>::ext_wrapper(|| { <<Self::Bridge as Bridge>::Handler as BridgeMessageHandler>::dispatch_target_inbound_message(msg.clone()) }); @@ -969,7 +1034,7 @@ macro_rules! decl_test_networks { // egress channel let e_index = sproof.hrmp_egress_channel_index.get_or_insert_with(Vec::new); - for recipient_para_id in $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().clone()) { + for recipient_para_id in $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().clone()) { let recipient_para_id = $crate::ParaId::from(recipient_para_id); if let Err(idx) = e_index.binary_search(&recipient_para_id) { e_index.insert(idx, recipient_para_id); @@ -1007,10 +1072,14 @@ macro_rules! decl_test_networks { } } - $crate::__impl_relay!($name, $relay_chain); + impl $crate::NetworkComponent for $relay_chain { + type Network = $name; + } $( - $crate::__impl_parachain!($name, $parachain); + impl $crate::NetworkComponent for $parachain { + type Network = $name; + } )* )+ }; @@ -1039,7 +1108,7 @@ macro_rules! decl_test_bridges { fn init() { use $crate::{NetworkComponent, Network}; - // Make sure source and target `Network` has been initialized + // Make sure source and target `Network` have been initialized <$source as NetworkComponent>::Network::init(); <$target as NetworkComponent>::Network::init(); } @@ -1048,42 +1117,109 @@ macro_rules! decl_test_bridges { }; } +#[macro_export] +macro_rules! __impl_check_assertion { + ($chain:ident) => { + impl<Origin, Destination, Hops, Args> + $crate::CheckAssertion<Origin, Destination, Hops, Args> for $chain + where + Origin: Chain + Clone, + Destination: Chain + Clone, + Origin::RuntimeOrigin: $crate::OriginTrait<AccountId = $crate::AccountId32> + Clone, + Destination::RuntimeOrigin: + $crate::OriginTrait<AccountId = $crate::AccountId32> + Clone, + Hops: Clone, + Args: Clone, + { + fn check_assertion(test: $crate::Test<Origin, Destination, Hops, Args>) { + let chain_name = std::any::type_name::<$chain>(); + + <$chain>::execute_with(|| { + if let Some(dispatchable) = test.hops_dispatchable.get(chain_name) { + $crate::assert_ok!(dispatchable(test.clone())); + } + if let Some(assertion) = test.hops_assertion.get(chain_name) { + assertion(test); + } + }); + } + } + }; +} + #[macro_export] macro_rules! assert_expected_events { ( $chain:ident, vec![$( $event_pat:pat => { $($attr:ident : $condition:expr, )* }, )*] ) => { let mut message: Vec<String> = Vec::new(); + let mut events = <$chain>::events(); + $( + let mut event_received = false; let mut meet_conditions = true; + let mut index_match = 0; let mut event_message: Vec<String> = Vec::new(); - let event_received = <$chain>::events().iter().any(|event| { - $crate::log::debug!(target: concat!("events::", stringify!($chain)), "{:?}", event); - + for (index, event) in events.iter().enumerate() { + // Have to reset the variable to override a previous partial match + meet_conditions = true; match event { $event_pat => { + event_received = true; + let mut conditions_message: Vec<String> = Vec::new(); + $( - if !$condition { - event_message.push(format!(" - The attribute {:?} = {:?} did not met the condition {:?}\n", stringify!($attr), $attr, stringify!($condition))); - meet_conditions &= $condition + // We only want to record condition error messages in case it did not happened before + // Only the first partial match is recorded + if !$condition && event_message.is_empty() { + conditions_message.push( + format!( + " - The attribute {:?} = {:?} did not met the condition {:?}\n", + stringify!($attr), + $attr, + stringify!($condition) + ) + ); } + meet_conditions &= $condition; )* - true + + // Set the index where we found a perfect match + if event_received && meet_conditions { + index_match = index; + break; + } else { + event_message.extend(conditions_message); + } }, - _ => false + _ => {} } - }); + } if event_received && !meet_conditions { - message.push(format!("\n\nEvent \x1b[31m{}\x1b[0m was received but some of its attributes did not meet the conditions:\n{}", stringify!($event_pat), event_message.concat())); + message.push( + format!( + "\n\n{}::\x1b[31m{}\x1b[0m was received but some of its attributes did not meet the conditions:\n{}", + stringify!($chain), + stringify!($event_pat), + event_message.concat() + ) + ); } else if !event_received { - message.push(format!("\n\nEvent \x1b[31m{}\x1b[0m was never received", stringify!($event_pat))); + message.push(format!("\n\n{}::\x1b[31m{}\x1b[0m was never received", stringify!($chain), stringify!($event_pat))); + } else { + // If we find a perfect match we remove the event to avoid being potentially assessed multiple times + events.remove(index_match); } )* + if !message.is_empty() { + // Log events as they will not be logged after the panic + <$chain>::events().iter().for_each(|event| { + $crate::log::debug!(target: concat!("events::", stringify!($chain)), "{:?}", event); + }); panic!("{}", message.concat()) } } - } #[macro_export] @@ -1107,8 +1243,140 @@ macro_rules! decl_test_sender_receiver_accounts_parameter_types { }; } +pub struct DefaultMessageProcessor<T>(PhantomData<T>); +impl<T> ProcessMessage for DefaultMessageProcessor<T> +where + T: Chain + RelayChain, + T::Runtime: MessageQueueConfig, + <<T::Runtime as MessageQueueConfig>::MessageProcessor as ProcessMessage>::Origin: + PartialEq<AggregateMessageOrigin>, + MessageQueuePallet<T::Runtime>: EnqueueMessage<AggregateMessageOrigin> + ServiceQueues, +{ + type Origin = ParaId; + + fn process_message( + msg: &[u8], + para: Self::Origin, + _meter: &mut WeightMeter, + _id: &mut XcmHash, + ) -> Result<bool, ProcessMessageError> { + MessageQueuePallet::<T::Runtime>::enqueue_message( + msg.try_into().expect("Message too long"), + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)), + ); + MessageQueuePallet::<T::Runtime>::service_queues(Weight::MAX); + + Ok(true) + } +} + +/// Struct that keeps account's id and balance +#[derive(Clone)] +pub struct TestAccount { + pub account_id: AccountId, + pub balance: Balance, +} + +/// Default `Args` provided by xcm-emulator to be stored in a `Test` instance +#[derive(Clone)] +pub struct TestArgs { + pub dest: MultiLocation, + pub beneficiary: MultiLocation, + pub amount: Balance, + pub assets: MultiAssets, + pub asset_id: Option<u32>, + pub fee_asset_item: u32, + pub weight_limit: WeightLimit, +} + +/// Auxiliar struct to help creating a new `Test` instance +pub struct TestContext<T> { + pub sender: AccountId, + pub receiver: AccountId, + pub args: T, +} + +/// Struct that help with tests where either dispatchables or assertions need +/// to be reused. The struct keeps the test's arguments of your choice in the generic `Args`. +/// These arguments can be easily reused and shared between the assertions functions +/// and dispatchables functions, which are also stored in `Test`. +/// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution. +/// `Destination` corresponds to the last chain where an effect of the intial execution is expected happen. +/// `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke some effect. +#[derive(Clone)] +pub struct Test<Origin, Destination, Hops = (), Args = TestArgs> +where + Origin: Chain + Clone, + Destination: Chain + Clone, + Origin::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Destination::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Hops: Clone, +{ + pub sender: TestAccount, + pub receiver: TestAccount, + pub signed_origin: Origin::RuntimeOrigin, + pub root_origin: Origin::RuntimeOrigin, + pub hops_assertion: HashMap<String, fn(Self)>, + pub hops_dispatchable: HashMap<String, fn(Self) -> DispatchResult>, + pub args: Args, + _marker: PhantomData<(Destination, Hops)>, +} + +/// `Test` implementation +impl<Origin, Destination, Hops, Args> Test<Origin, Destination, Hops, Args> +where + Args: Clone, + Origin: Chain + Clone + CheckAssertion<Origin, Destination, Hops, Args>, + Destination: Chain + Clone + CheckAssertion<Origin, Destination, Hops, Args>, + Origin::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Destination::RuntimeOrigin: OriginTrait<AccountId = AccountId32> + Clone, + Hops: Clone + CheckAssertion<Origin, Destination, Hops, Args>, +{ + /// Creates a new `Test` instance + pub fn new(test_args: TestContext<Args>) -> Self { + Test { + sender: TestAccount { + account_id: test_args.sender.clone(), + balance: Origin::account_data_of(test_args.sender.clone()).free, + }, + receiver: TestAccount { + account_id: test_args.receiver.clone(), + balance: Destination::account_data_of(test_args.receiver.clone()).free, + }, + signed_origin: <Origin as Chain>::RuntimeOrigin::signed(test_args.sender), + root_origin: <Origin as Chain>::RuntimeOrigin::root(), + hops_assertion: Default::default(), + hops_dispatchable: Default::default(), + args: test_args.args, + _marker: Default::default(), + } + } + /// Stores an assertion in a particular Chain + pub fn set_assertion<Hop>(&mut self, assertion: fn(Self)) { + let chain_name = std::any::type_name::<Hop>(); + self.hops_assertion.insert(chain_name.to_string(), assertion); + } + /// Stores an assertion in a particular Chain + pub fn set_dispatchable<Hop>(&mut self, dispatchable: fn(Self) -> DispatchResult) { + let chain_name = std::any::type_name::<Hop>(); + self.hops_dispatchable.insert(chain_name.to_string(), dispatchable); + } + /// Executes all dispatchables and assertions in order from `Origin` to `Destination` + pub fn assert(&mut self) { + Origin::check_assertion(self.clone()); + Hops::check_assertion(self.clone()); + Destination::check_assertion(self.clone()); + Self::update_balances(self); + } + /// Updates sender and receiver balances + fn update_balances(&mut self) { + self.sender.balance = Origin::account_data_of(self.sender.account_id.clone()).free; + self.receiver.balance = Destination::account_data_of(self.receiver.account_id.clone()).free; + } +} + pub mod helpers { - use super::Weight; + use super::*; pub fn within_threshold(threshold: u64, expected_value: u64, current_value: u64) -> bool { let margin = (current_value * threshold) / 100; @@ -1130,4 +1398,17 @@ pub mod helpers { ref_time_within && proof_size_within } + + /// Helper function to generate an account ID from seed. + pub fn get_account_id_from_seed<TPublic: sp_core::Public>(seed: &str) -> AccountId + where + sp_runtime::MultiSigner: + From<<<TPublic as sp_runtime::CryptoType>::Pair as sp_core::Pair>::Public>, + { + use sp_runtime::traits::IdentifyAccount; + let pubkey = TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public(); + sp_runtime::MultiSigner::from(pubkey).into_account() + } } -- GitLab