diff --git a/Cargo.lock b/Cargo.lock index 2ee029368c9..85c7b66afad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1334,6 +1334,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "casey" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabe85130dda9cf267715582ce6cf1ab581c8dfe3cb33f7065fee0f14e3fea14" +dependencies = [ + "syn 1.0.109", +] + [[package]] name = "cast" version = "0.3.0" @@ -4754,6 +4763,47 @@ dependencies = [ "num-traits", ] +[[package]] +name = "integration-tests-common" +version = "1.0.0" +dependencies = [ + "bridge-hub-kusama-runtime", + "bridge-hub-polkadot-runtime", + "collectives-polkadot-runtime", + "cumulus-primitives-core", + "frame-support", + "frame-system", + "kusama-runtime", + "kusama-runtime-constants", + "pallet-assets", + "pallet-balances", + "pallet-im-online", + "pallet-staking", + "pallet-xcm", + "parachain-info", + "parachains-common", + "parity-scale-codec", + "penpal-runtime", + "polkadot-core-primitives", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime", + "polkadot-runtime-constants", + "polkadot-runtime-parachains", + "polkadot-service", + "sc-consensus-grandpa", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-core", + "sp-runtime", + "sp-weights", + "statemine-runtime", + "statemint-runtime", + "xcm", + "xcm-emulator", + "xcm-executor", +] + [[package]] name = "interceptor" version = "0.8.2" @@ -13301,6 +13351,32 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "statemint-it" +version = "1.0.0" +dependencies = [ + "frame-support", + "frame-system", + "integration-tests-common", + "pallet-assets", + "pallet-balances", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "penpal-runtime", + "polkadot-core-primitives", + "polkadot-parachain", + "polkadot-runtime", + "polkadot-runtime-parachains", + "sp-core", + "sp-runtime", + "sp-weights", + "statemint-runtime", + "xcm", + "xcm-emulator", + "xcm-executor", +] + [[package]] name = "statemint-runtime" version = "1.0.0" @@ -13732,34 +13808,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" -[[package]] -name = "test-runtime" -version = "0.1.0" -dependencies = [ - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-utility", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-xcm", - "parachain-info", - "parity-scale-codec", - "polkadot-parachain", - "polkadot-runtime-parachains", - "scale-info", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", -] - [[package]] name = "test-runtime-constants" version = "0.9.41" @@ -15856,52 +15904,34 @@ dependencies = [ name = "xcm-emulator" version = "0.1.0" dependencies = [ + "casey", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-test-relay-sproof-builder", + "cumulus-test-service", "frame-support", "frame-system", + "log", + "pallet-balances", "parachain-info", + "parachains-common", "parity-scale-codec", "paste", "polkadot-primitives", "polkadot-runtime-parachains", "quote", "sp-arithmetic", + "sp-core", "sp-io", "sp-std", + "sp-trie", "xcm", "xcm-executor", ] -[[package]] -name = "xcm-emulator-example" -version = "0.1.0" -dependencies = [ - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "frame-support", - "frame-system", - "kusama-runtime", - "pallet-balances", - "pallet-xcm", - "parachain-info", - "parity-scale-codec", - "polkadot-parachain", - "polkadot-primitives", - "polkadot-runtime-parachains", - "proc-macro2", - "serde", - "sp-io", - "sp-runtime", - "test-runtime", - "xcm", - "xcm-emulator", -] - [[package]] name = "xcm-executor" version = "0.9.41" diff --git a/Cargo.toml b/Cargo.toml index e8476d04273..6ef1df49d48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,14 +50,14 @@ members = [ "parachains/runtimes/collectives/collectives-polkadot", "parachains/runtimes/contracts/contracts-rococo", "parachains/runtimes/testing/penpal", + "parachains/integration-tests/emulated/common", + "parachains/integration-tests/emulated/assets/statemint", "test/client", "test/relay-sproof-builder", "test/relay-validation-worker-provider", "test/runtime", "test/service", "xcm/xcm-emulator", - "xcm/xcm-emulator/example", - "xcm/xcm-emulator/example/test-runtime", ] [profile.release] @@ -68,4 +68,3 @@ opt-level = 3 inherits = "release" lto = true codegen-units = 1 - diff --git a/parachains/integration-tests/statemine/xcm/0_init.yml b/parachains/integration-tests/e2e/assets/statemine/0_xcm/0_init.yml similarity index 100% rename from parachains/integration-tests/statemine/xcm/0_init.yml rename to parachains/integration-tests/e2e/assets/statemine/0_xcm/0_init.yml diff --git a/parachains/integration-tests/statemine/xcm/1_dmp.yml b/parachains/integration-tests/e2e/assets/statemine/0_xcm/1_dmp.yml similarity index 100% rename from parachains/integration-tests/statemine/xcm/1_dmp.yml rename to parachains/integration-tests/e2e/assets/statemine/0_xcm/1_dmp.yml diff --git a/parachains/integration-tests/statemine/xcm/2_ump.yml b/parachains/integration-tests/e2e/assets/statemine/0_xcm/2_ump.yml similarity index 100% rename from parachains/integration-tests/statemine/xcm/2_ump.yml rename to parachains/integration-tests/e2e/assets/statemine/0_xcm/2_ump.yml diff --git a/parachains/integration-tests/statemine/xcm/3_hrmp-open-channels.yml b/parachains/integration-tests/e2e/assets/statemine/0_xcm/3_hrmp-open-channels.yml similarity index 100% rename from parachains/integration-tests/statemine/xcm/3_hrmp-open-channels.yml rename to parachains/integration-tests/e2e/assets/statemine/0_xcm/3_hrmp-open-channels.yml diff --git a/parachains/integration-tests/statemine/xcm/4_hrmp.yml b/parachains/integration-tests/e2e/assets/statemine/0_xcm/4_hrmp.yml similarity index 100% rename from parachains/integration-tests/statemine/xcm/4_hrmp.yml rename to parachains/integration-tests/e2e/assets/statemine/0_xcm/4_hrmp.yml diff --git a/parachains/integration-tests/statemine/config.toml b/parachains/integration-tests/e2e/assets/statemine/config.toml similarity index 100% rename from parachains/integration-tests/statemine/config.toml rename to parachains/integration-tests/e2e/assets/statemine/config.toml diff --git a/parachains/integration-tests/statemint/xcm/0_init.yml b/parachains/integration-tests/e2e/assets/statemint/0_xcm/0_init.yml similarity index 100% rename from parachains/integration-tests/statemint/xcm/0_init.yml rename to parachains/integration-tests/e2e/assets/statemint/0_xcm/0_init.yml diff --git a/parachains/integration-tests/statemint/xcm/1_dmp.yml b/parachains/integration-tests/e2e/assets/statemint/0_xcm/1_dmp.yml similarity index 100% rename from parachains/integration-tests/statemint/xcm/1_dmp.yml rename to parachains/integration-tests/e2e/assets/statemint/0_xcm/1_dmp.yml diff --git a/parachains/integration-tests/statemint/xcm/2_ump.yml b/parachains/integration-tests/e2e/assets/statemint/0_xcm/2_ump.yml similarity index 100% rename from parachains/integration-tests/statemint/xcm/2_ump.yml rename to parachains/integration-tests/e2e/assets/statemint/0_xcm/2_ump.yml diff --git a/parachains/integration-tests/statemint/xcm/3_hrmp-open-channels.yml b/parachains/integration-tests/e2e/assets/statemint/0_xcm/3_hrmp-open-channels.yml similarity index 100% rename from parachains/integration-tests/statemint/xcm/3_hrmp-open-channels.yml rename to parachains/integration-tests/e2e/assets/statemint/0_xcm/3_hrmp-open-channels.yml diff --git a/parachains/integration-tests/statemint/xcm/4_hrmp.yml b/parachains/integration-tests/e2e/assets/statemint/0_xcm/4_hrmp.yml similarity index 100% rename from parachains/integration-tests/statemint/xcm/4_hrmp.yml rename to parachains/integration-tests/e2e/assets/statemint/0_xcm/4_hrmp.yml diff --git a/parachains/integration-tests/statemint/config.toml b/parachains/integration-tests/e2e/assets/statemint/config.toml similarity index 100% rename from parachains/integration-tests/statemint/config.toml rename to parachains/integration-tests/e2e/assets/statemint/config.toml diff --git a/parachains/integration-tests/collectives/0_xcm/0_init.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/0_xcm/0_init.yml similarity index 100% rename from parachains/integration-tests/collectives/0_xcm/0_init.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/0_xcm/0_init.yml diff --git a/parachains/integration-tests/collectives/0_xcm/1_teleport.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/0_xcm/1_teleport.yml similarity index 100% rename from parachains/integration-tests/collectives/0_xcm/1_teleport.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/0_xcm/1_teleport.yml diff --git a/parachains/integration-tests/collectives/0_xcm/2_reserve.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/0_xcm/2_reserve.yml similarity index 100% rename from parachains/integration-tests/collectives/0_xcm/2_reserve.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/0_xcm/2_reserve.yml diff --git a/parachains/integration-tests/collectives/1_alliance/0_join_alliance_fails.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/0_join_alliance_fails.yml similarity index 100% rename from parachains/integration-tests/collectives/1_alliance/0_join_alliance_fails.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/0_join_alliance_fails.yml diff --git a/parachains/integration-tests/collectives/1_alliance/1_init_alliance.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/1_init_alliance.yml similarity index 100% rename from parachains/integration-tests/collectives/1_alliance/1_init_alliance.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/1_init_alliance.yml diff --git a/parachains/integration-tests/collectives/1_alliance/2_join_alliance_fails.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/2_join_alliance_fails.yml similarity index 100% rename from parachains/integration-tests/collectives/1_alliance/2_join_alliance_fails.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/2_join_alliance_fails.yml diff --git a/parachains/integration-tests/collectives/1_alliance/3_kick_member.yml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/3_kick_member.yml similarity index 100% rename from parachains/integration-tests/collectives/1_alliance/3_kick_member.yml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/1_alliance/3_kick_member.yml diff --git a/parachains/integration-tests/collectives/config.toml b/parachains/integration-tests/e2e/collectives/collectives_polkadot/config.toml similarity index 100% rename from parachains/integration-tests/collectives/config.toml rename to parachains/integration-tests/e2e/collectives/collectives_polkadot/config.toml diff --git a/parachains/integration-tests/emulated/assets/statemint/Cargo.toml b/parachains/integration-tests/emulated/assets/statemint/Cargo.toml new file mode 100644 index 00000000000..8c6077b67e4 --- /dev/null +++ b/parachains/integration-tests/emulated/assets/statemint/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "statemint-it" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +description = "Statemint parachain runtime integration tests with xcm-emulator" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } + +# Substrate +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-weights = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +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" } + +# Polkadot +polkadot-core-primitives = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } +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" } +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" } +statemint-runtime = { path = "../../../../runtimes/assets/statemint" } + +# Local +xcm-emulator = { default-features = false, path = "../../../../../xcm/xcm-emulator" } +integration-tests-common = { default-features = false, path = "../../common" } diff --git a/parachains/integration-tests/emulated/assets/statemint/src/lib.rs b/parachains/integration-tests/emulated/assets/statemint/src/lib.rs new file mode 100644 index 00000000000..f7ca680a800 --- /dev/null +++ b/parachains/integration-tests/emulated/assets/statemint/src/lib.rs @@ -0,0 +1,33 @@ +pub use codec::Encode; +pub use frame_support::{ + assert_ok, instances::Instance1, pallet_prelude::Weight, traits::fungibles::Inspect, +}; +pub use integration_tests_common::{ + constants::{ + accounts::{ALICE, BOB}, + polkadot::ED as POLKADOT_ED, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, + }, + AccountId, BHKusama, BHKusamaPallet, BHKusamaReceiver, BHKusamaSender, BHPolkadot, + BHPolkadotPallet, BHPolkadotReceiver, BHPolkadotSender, Collectives, CollectivesPallet, + CollectivesReceiver, CollectivesSender, Kusama, KusamaMockNet, KusamaPallet, KusamaReceiver, + KusamaSender, PenpalKusama, PenpalKusamaReceiver, PenpalKusamaSender, PenpalPolkadot, + PenpalPolkadotReceiver, PenpalPolkadotSender, Polkadot, PolkadotMockNet, PolkadotPallet, + PolkadotReceiver, PolkadotSender, Statemine, StateminePallet, StatemineReceiver, + StatemineSender, Statemint, StatemintPallet, StatemintReceiver, StatemintSender, +}; +pub use polkadot_core_primitives::InboundDownwardMessage; +pub use xcm::{ + prelude::*, + v3::{ + Error, + NetworkId::{Kusama as KusamaId, Polkadot as PolkadotId}, + }, +}; +pub use xcm_emulator::{ + assert_expected_events, bx, cumulus_pallet_dmp_queue, helpers::weight_within_threshold, + Parachain as Para, RelayChain as Relay, TestExt, +}; + +#[cfg(test)] +mod tests; diff --git a/parachains/integration-tests/emulated/assets/statemint/src/tests/mod.rs b/parachains/integration-tests/emulated/assets/statemint/src/tests/mod.rs new file mode 100644 index 00000000000..996f9fd0aae --- /dev/null +++ b/parachains/integration-tests/emulated/assets/statemint/src/tests/mod.rs @@ -0,0 +1,3 @@ +mod reserve_transfer; +mod teleport; +mod transact; diff --git a/parachains/integration-tests/emulated/assets/statemint/src/tests/reserve_transfer.rs b/parachains/integration-tests/emulated/assets/statemint/src/tests/reserve_transfer.rs new file mode 100644 index 00000000000..55d201c5608 --- /dev/null +++ b/parachains/integration-tests/emulated/assets/statemint/src/tests/reserve_transfer.rs @@ -0,0 +1,63 @@ +use crate::*; + +#[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 = Statemint::account_data_of(StatemintReceiver::get()).free; + + let origin = ::RuntimeOrigin::signed(PolkadotSender::get()); + let assets_para_destination: VersionedMultiLocation = + Polkadot::child_location_of(Statemint::para_id()).into(); + let beneficiary: VersionedMultiLocation = + AccountId32 { network: None, id: StatemintReceiver::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!(::XcmPallet::limited_reserve_transfer_assets( + origin, + bx!(assets_para_destination), + bx!(beneficiary), + bx!(native_assets), + fee_asset_item, + weight_limit, + )); + + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted(Outcome::Complete(weight))) => { + weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(2_000_000_000, 0), *weight), + }, + ] + ); + }); + + // Receive XCM message in Assets Parachain + Statemint::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Statemint, + 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 = Statemint::account_data_of(StatemintReceiver::get()).free; + + assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); + assert_eq!(para_sender_balance_after, para_receiver_balance_before); +} diff --git a/parachains/integration-tests/emulated/assets/statemint/src/tests/teleport.rs b/parachains/integration-tests/emulated/assets/statemint/src/tests/teleport.rs new file mode 100644 index 00000000000..163db77ddfd --- /dev/null +++ b/parachains/integration-tests/emulated/assets/statemint/src/tests/teleport.rs @@ -0,0 +1,60 @@ +use crate::*; + +#[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 = Statemint::account_data_of(StatemintReceiver::get()).free; + + let origin = ::RuntimeOrigin::signed(PolkadotSender::get()); + let assets_para_destination: VersionedMultiLocation = + Polkadot::child_location_of(Statemint::para_id()).into(); + let beneficiary: VersionedMultiLocation = + AccountId32 { network: None, id: StatemintReceiver::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!(::XcmPallet::limited_teleport_assets( + origin, + bx!(assets_para_destination), + bx!(beneficiary), + bx!(native_assets), + fee_asset_item, + weight_limit, + )); + + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted(Outcome::Complete { .. })) => {}, + ] + ); + }); + + // Receive XCM message in Assets Parachain + Statemint::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Statemint, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == StatemineReceiver::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 = Statemint::account_data_of(StatemintReceiver::get()).free; + + assert_eq!(relay_sender_balance_before - amount, relay_sender_balance_after); + assert!(para_sender_balance_after > para_receiver_balance_before); +} diff --git a/parachains/integration-tests/emulated/assets/statemint/src/tests/transact.rs b/parachains/integration-tests/emulated/assets/statemint/src/tests/transact.rs new file mode 100644 index 00000000000..9220d914e47 --- /dev/null +++ b/parachains/integration-tests/emulated/assets/statemint/src/tests/transact.rs @@ -0,0 +1,58 @@ +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 = ::RuntimeCall::Assets(pallet_assets::Call::< + ::Runtime, + Instance1, + >::force_create { + id: ASSET_ID.into(), + is_sufficient: true, + min_balance: 1000, + owner: StatemintSender::get().into(), + }) + .encode() + .into(); + + // XcmPallet send arguments + let sudo_origin = ::RuntimeOrigin::root(); + let assets_para_destination: VersionedMultiLocation = + Polkadot::child_location_of(Statemint::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!(::XcmPallet::send( + sudo_origin, + bx!(assets_para_destination), + bx!(xcm), + )); + + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Polkadot, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Receive XCM message in Assets Parachain + Statemint::execute_with(|| { + assert!(::Assets::asset_exists(ASSET_ID)); + }); +} diff --git a/parachains/integration-tests/emulated/common/Cargo.toml b/parachains/integration-tests/emulated/common/Cargo.toml new file mode 100644 index 00000000000..8ea8c1d0f8a --- /dev/null +++ b/parachains/integration-tests/emulated/common/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "integration-tests-common" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +description = "Common resources for integration testing with xcm-emulator" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } + +# Substrate +grandpa = { package = "sc-consensus-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" } +sp-authority-discovery = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-weights = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-babe = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } +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-im-online = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } + +# Polkadot +polkadot-core-primitives = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-parachain = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { 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" } +polkadot-runtime-constants = { git = "https://github.com/paritytech/polkadot", branch = "master" } +kusama-runtime = { git = "https://github.com/paritytech/polkadot", branch = "master" } +kusama-runtime-constants = { 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" } +parachain-info = { path = "../../../pallets/parachain-info" } +cumulus-primitives-core = { path = "../../../../primitives/core" } +penpal-runtime = { path = "../../../runtimes/testing/penpal" } +statemint-runtime = { path = "../../../runtimes/assets/statemint" } +statemine-runtime = { path = "../../../runtimes/assets/statemine" } +collectives-polkadot-runtime = { path = "../../../runtimes/collectives/collectives-polkadot" } +bridge-hub-kusama-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-kusama" } +bridge-hub-polkadot-runtime = { path = "../../../runtimes/bridge-hubs/bridge-hub-polkadot" } +xcm-emulator = { default-features = false, path = "../../../../xcm/xcm-emulator" } diff --git a/parachains/integration-tests/emulated/common/src/constants.rs b/parachains/integration-tests/emulated/common/src/constants.rs new file mode 100644 index 00000000000..b9720db4cf0 --- /dev/null +++ b/parachains/integration-tests/emulated/common/src/constants.rs @@ -0,0 +1,672 @@ +use grandpa::AuthorityId as GrandpaId; +use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +pub use parachains_common::{AccountId, AuraId, Balance, BlockNumber, StatemintAuraId}; +use polkadot_primitives::{AssignmentId, ValidatorId}; +pub use polkadot_runtime_parachains::configuration::HostConfiguration; +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; +use sp_core::{sr25519, storage::Storage, Pair, Public}; +use sp_runtime::{ + traits::{IdentifyAccount, Verify}, + BuildStorage, MultiSignature, Perbill, +}; +pub use xcm; + +pub const XCM_V2: u32 = 3; +pub const XCM_V3: u32 = 2; +pub const REF_TIME_THRESHOLD: u64 = 33; +pub const PROOF_SIZE_THRESHOLD: u64 = 33; + +type AccountPublic = ::Signer; + +/// Helper function to generate a crypto pair from seed +fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +/// Helper function to generate an account ID from seed. +fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +pub mod accounts { + use super::*; + pub const ALICE: &str = "Alice"; + pub const BOB: &str = "Bob"; + pub const CHARLIE: &str = "Charlie"; + pub const DAVE: &str = "Dave"; + pub const EVE: &str = "Eve"; + pub const FERDIE: &str = "Ferdei"; + pub const ALICE_STASH: &str = "Alice//stash"; + pub const BOB_STASH: &str = "Bob//stash"; + pub const CHARLIE_STASH: &str = "Charlie//stash"; + pub const DAVE_STASH: &str = "Dave//stash"; + pub const EVE_STASH: &str = "Eve//stash"; + pub const FERDIE_STASH: &str = "Ferdie//stash"; + + pub fn init_balances() -> Vec { + vec![ + get_account_id_from_seed::(ALICE), + get_account_id_from_seed::(BOB), + get_account_id_from_seed::(CHARLIE), + get_account_id_from_seed::(DAVE), + get_account_id_from_seed::(EVE), + get_account_id_from_seed::(FERDIE), + get_account_id_from_seed::(ALICE_STASH), + get_account_id_from_seed::(BOB_STASH), + get_account_id_from_seed::(CHARLIE_STASH), + get_account_id_from_seed::(DAVE_STASH), + get_account_id_from_seed::(EVE_STASH), + get_account_id_from_seed::(FERDIE_STASH), + ] + } +} + +pub mod collators { + use super::*; + + pub fn invulnerables_statemint() -> Vec<(AccountId, StatemintAuraId)> { + vec![ + ( + get_account_id_from_seed::("Alice"), + get_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_from_seed::("Bob"), + ), + ] + } + + pub fn invulnerables() -> Vec<(AccountId, AuraId)> { + vec![ + ( + get_account_id_from_seed::("Alice"), + get_from_seed::("Alice"), + ), + (get_account_id_from_seed::("Bob"), get_from_seed::("Bob")), + ] + } +} + +pub mod validators { + use super::*; + + pub fn initial_authorities() -> Vec<( + AccountId, + AccountId, + BabeId, + GrandpaId, + ImOnlineId, + ValidatorId, + AssignmentId, + AuthorityDiscoveryId, + )> { + vec![get_authority_keys_from_seed_no_beefy("Alice")] + } +} + +/// The default XCM version to set in genesis config. +const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; +// Polkadot +pub mod polkadot { + use super::*; + pub const ED: Balance = polkadot_runtime_constants::currency::EXISTENTIAL_DEPOSIT; + const STASH: u128 = 100 * polkadot_runtime_constants::currency::UNITS; + + pub fn get_host_config() -> HostConfiguration { + 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, + ..Default::default() + } + } + + fn session_keys( + babe: BabeId, + grandpa: GrandpaId, + im_online: ImOnlineId, + para_validator: ValidatorId, + para_assignment: AssignmentId, + authority_discovery: AuthorityDiscoveryId, + ) -> polkadot_runtime::SessionKeys { + polkadot_runtime::SessionKeys { + babe, + grandpa, + im_online, + para_validator, + para_assignment, + authority_discovery, + } + } + + pub fn genesis() -> Storage { + let genesis_config = polkadot_runtime::GenesisConfig { + system: polkadot_runtime::SystemConfig { + code: polkadot_runtime::WASM_BINARY.unwrap().to_vec(), + }, + balances: polkadot_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + indices: polkadot_runtime::IndicesConfig { indices: vec![] }, + session: polkadot_runtime::SessionConfig { + keys: validators::initial_authorities() + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + polkadot::session_keys( + x.2.clone(), + x.3.clone(), + x.4.clone(), + x.5.clone(), + x.6.clone(), + x.7.clone(), + ), + ) + }) + .collect::>(), + }, + staking: polkadot_runtime::StakingConfig { + validator_count: validators::initial_authorities().len() as u32, + minimum_validator_count: 1, + stakers: validators::initial_authorities() + .iter() + .map(|x| { + (x.0.clone(), x.1.clone(), STASH, polkadot_runtime::StakerStatus::Validator) + }) + .collect(), + invulnerables: validators::initial_authorities() + .iter() + .map(|x| x.0.clone()) + .collect(), + force_era: pallet_staking::Forcing::ForceNone, + slash_reward_fraction: Perbill::from_percent(10), + ..Default::default() + }, + phragmen_election: Default::default(), + democracy: Default::default(), + council: polkadot_runtime::CouncilConfig { + members: vec![], + phantom: Default::default(), + }, + technical_committee: polkadot_runtime::TechnicalCommitteeConfig { + members: vec![], + phantom: Default::default(), + }, + technical_membership: Default::default(), + babe: polkadot_runtime::BabeConfig { + authorities: Default::default(), + epoch_config: Some(polkadot_runtime::BABE_GENESIS_EPOCH_CONFIG), + }, + grandpa: Default::default(), + im_online: Default::default(), + authority_discovery: polkadot_runtime::AuthorityDiscoveryConfig { keys: vec![] }, + claims: polkadot_runtime::ClaimsConfig { claims: vec![], vesting: vec![] }, + vesting: polkadot_runtime::VestingConfig { vesting: vec![] }, + treasury: Default::default(), + hrmp: Default::default(), + configuration: polkadot_runtime::ConfigurationConfig { config: get_host_config() }, + paras: Default::default(), + xcm_pallet: Default::default(), + nomination_pools: Default::default(), + }; + + genesis_config.build_storage().unwrap() + } +} + +// Kusama +pub mod kusama { + use super::*; + pub const ED: Balance = kusama_runtime_constants::currency::EXISTENTIAL_DEPOSIT; + const STASH: u128 = 100 * kusama_runtime_constants::currency::UNITS; + + pub fn get_host_config() -> HostConfiguration { + 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, + ..Default::default() + } + } + + fn session_keys( + babe: BabeId, + grandpa: GrandpaId, + im_online: ImOnlineId, + para_validator: ValidatorId, + para_assignment: AssignmentId, + authority_discovery: AuthorityDiscoveryId, + ) -> kusama_runtime::SessionKeys { + kusama_runtime::SessionKeys { + babe, + grandpa, + im_online, + para_validator, + para_assignment, + authority_discovery, + } + } + + pub fn genesis() -> Storage { + let genesis_config = kusama_runtime::GenesisConfig { + system: kusama_runtime::SystemConfig { + code: kusama_runtime::WASM_BINARY.unwrap().to_vec(), + }, + balances: kusama_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + indices: kusama_runtime::IndicesConfig { indices: vec![] }, + session: kusama_runtime::SessionConfig { + keys: validators::initial_authorities() + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + kusama::session_keys( + x.2.clone(), + x.3.clone(), + x.4.clone(), + x.5.clone(), + x.6.clone(), + x.7.clone(), + ), + ) + }) + .collect::>(), + }, + staking: kusama_runtime::StakingConfig { + minimum_validator_count: 1, + validator_count: validators::initial_authorities().len() as u32, + stakers: validators::initial_authorities() + .iter() + .map(|x| { + (x.0.clone(), x.1.clone(), STASH, kusama_runtime::StakerStatus::Validator) + }) + .collect(), + invulnerables: validators::initial_authorities() + .iter() + .map(|x| x.0.clone()) + .collect(), + force_era: pallet_staking::Forcing::NotForcing, + slash_reward_fraction: Perbill::from_percent(10), + ..Default::default() + }, + babe: kusama_runtime::BabeConfig { + authorities: Default::default(), + epoch_config: Some(kusama_runtime::BABE_GENESIS_EPOCH_CONFIG), + }, + grandpa: Default::default(), + im_online: Default::default(), + authority_discovery: kusama_runtime::AuthorityDiscoveryConfig { keys: vec![] }, + claims: kusama_runtime::ClaimsConfig { claims: vec![], vesting: vec![] }, + vesting: kusama_runtime::VestingConfig { vesting: vec![] }, + treasury: Default::default(), + hrmp: Default::default(), + configuration: kusama_runtime::ConfigurationConfig { config: get_host_config() }, + paras: Default::default(), + xcm_pallet: Default::default(), + nomination_pools: Default::default(), + nis_counterpart_balances: Default::default(), + }; + + genesis_config.build_storage().unwrap() + } +} + +// Statemint +pub mod statemint { + use super::*; + pub const PARA_ID: u32 = 1000; + pub const ED: Balance = statemint_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + let genesis_config = statemint_runtime::GenesisConfig { + system: statemint_runtime::SystemConfig { + code: statemint_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: statemint_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: statemint_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into() }, + collator_selection: statemint_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables_statemint() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: statemint_runtime::SessionConfig { + keys: collators::invulnerables_statemint() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + statemint_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: statemint_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + }; + + genesis_config.build_storage().unwrap() + } +} + +// Statemint +pub mod statemine { + use super::*; + pub const PARA_ID: u32 = 1000; + pub const ED: Balance = statemine_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + let genesis_config = statemine_runtime::GenesisConfig { + system: statemine_runtime::SystemConfig { + code: statemine_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: statemine_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: statemine_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into() }, + collator_selection: statemine_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: statemine_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + statemine_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: statemine_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + }; + + genesis_config.build_storage().unwrap() + } +} + +// Penpal +pub mod penpal { + use super::*; + pub const PARA_ID: u32 = 2000; + pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; + + pub fn genesis(para_id: u32) -> Storage { + let genesis_config = penpal_runtime::GenesisConfig { + system: penpal_runtime::SystemConfig { + code: penpal_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: penpal_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: penpal_runtime::ParachainInfoConfig { parachain_id: para_id.into() }, + collator_selection: penpal_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: penpal_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + penpal_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: penpal_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + sudo: penpal_runtime::SudoConfig { + key: Some(get_account_id_from_seed::("Alice")), + }, + }; + + genesis_config.build_storage().unwrap() + } +} + +// Collectives +pub mod collectives { + use super::*; + pub const PARA_ID: u32 = 1001; + pub const ED: Balance = collectives_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + let genesis_config = collectives_polkadot_runtime::GenesisConfig { + system: collectives_polkadot_runtime::SystemConfig { + code: collectives_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: collectives_polkadot_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: collectives_polkadot_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + }, + collator_selection: collectives_polkadot_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: collectives_polkadot_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + collectives_polkadot_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + // no need to pass anything to aura, in fact it will panic if we do. Session will take care + // of this. + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: collectives_polkadot_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + alliance: Default::default(), + alliance_motion: Default::default(), + }; + + genesis_config.build_storage().unwrap() + } +} + +pub mod bridge_hub_kusama { + use super::*; + pub const PARA_ID: u32 = 1002; + pub const ED: Balance = bridge_hub_kusama_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + let genesis_config = bridge_hub_kusama_runtime::GenesisConfig { + system: bridge_hub_kusama_runtime::SystemConfig { + code: bridge_hub_kusama_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: bridge_hub_kusama_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: bridge_hub_kusama_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + }, + collator_selection: bridge_hub_kusama_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: bridge_hub_kusama_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_kusama_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: bridge_hub_kusama_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + }; + + genesis_config.build_storage().unwrap() + } +} + +pub mod bridge_hub_polkadot { + use super::*; + pub const PARA_ID: u32 = 1002; + pub const ED: Balance = bridge_hub_polkadot_runtime::constants::currency::EXISTENTIAL_DEPOSIT; + + pub fn genesis() -> Storage { + let genesis_config = bridge_hub_polkadot_runtime::GenesisConfig { + system: bridge_hub_polkadot_runtime::SystemConfig { + code: bridge_hub_polkadot_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: bridge_hub_polkadot_runtime::BalancesConfig { + balances: accounts::init_balances() + .iter() + .cloned() + .map(|k| (k, ED * 4096)) + .collect(), + }, + parachain_info: bridge_hub_polkadot_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + }, + collator_selection: bridge_hub_polkadot_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables() + .iter() + .cloned() + .map(|(acc, _)| acc) + .collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: bridge_hub_polkadot_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + bridge_hub_polkadot_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: bridge_hub_polkadot_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + }; + + genesis_config.build_storage().unwrap() + } +} diff --git a/parachains/integration-tests/emulated/common/src/lib.rs b/parachains/integration-tests/emulated/common/src/lib.rs new file mode 100644 index 00000000000..0d0928998a0 --- /dev/null +++ b/parachains/integration-tests/emulated/common/src/lib.rs @@ -0,0 +1,253 @@ +pub mod constants; + +pub use constants::{ + accounts::{ALICE, BOB}, + bridge_hub_kusama, bridge_hub_polkadot, collectives, kusama, penpal, polkadot, statemine, + statemint, +}; +use frame_support::{parameter_types, sp_io, sp_tracing}; +pub use parachains_common::{AccountId, AuraId, Balance, BlockNumber, StatemintAuraId}; +pub use sp_core::{sr25519, storage::Storage, Get}; +use xcm::prelude::*; +use xcm_emulator::{ + decl_test_networks, decl_test_parachains, decl_test_relay_chains, Parachain, RelayChain, + TestExt, +}; +use xcm_executor::traits::Convert; + +decl_test_relay_chains! { + 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, + XcmConfig: polkadot_runtime::xcm_config::XcmConfig, + SovereignAccountOf: polkadot_runtime::xcm_config::SovereignAccountOf, + System: polkadot_runtime::System, + Balances: polkadot_runtime::Balances, + }, + pallets_extra = { + XcmPallet: polkadot_runtime::XcmPallet, + } + }, + pub struct Kusama { + genesis = kusama::genesis(), + on_init = (), + runtime = { + Runtime: kusama_runtime::Runtime, + RuntimeOrigin: kusama_runtime::RuntimeOrigin, + RuntimeCall: polkadot_runtime::RuntimeCall, + RuntimeEvent: kusama_runtime::RuntimeEvent, + XcmConfig: kusama_runtime::xcm_config::XcmConfig, + SovereignAccountOf: kusama_runtime::xcm_config::SovereignAccountOf, + System: kusama_runtime::System, + Balances: kusama_runtime::Balances, + }, + pallets_extra = { + XcmPallet: kusama_runtime::XcmPallet, + } + } +} + +decl_test_parachains! { + // Polkadot + pub struct Statemint { + genesis = statemint::genesis(), + on_init = (), + runtime = { + Runtime: statemint_runtime::Runtime, + RuntimeOrigin: statemint_runtime::RuntimeOrigin, + RuntimeCall: statemint_runtime::RuntimeCall, + RuntimeEvent: statemint_runtime::RuntimeEvent, + XcmpMessageHandler: statemint_runtime::XcmpQueue, + DmpMessageHandler: statemint_runtime::DmpQueue, + LocationToAccountId: statemint_runtime::xcm_config::LocationToAccountId, + System: statemint_runtime::System, + Balances: statemint_runtime::Balances, + ParachainSystem: statemint_runtime::ParachainSystem, + ParachainInfo: statemint_runtime::ParachainInfo, + }, + pallets_extra = { + PolkadotXcm: statemint_runtime::PolkadotXcm, + Assets: statemint_runtime::Assets, + } + }, + pub struct PenpalPolkadot { + genesis = penpal::genesis(penpal::PARA_ID), + on_init = (), + runtime = { + Runtime: penpal_runtime::Runtime, + RuntimeOrigin: penpal_runtime::RuntimeOrigin, + RuntimeCall: penpal_runtime::RuntimeEvent, + RuntimeEvent: penpal_runtime::RuntimeEvent, + 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 = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } + }, + // Kusama + pub struct Statemine { + genesis = statemine::genesis(), + on_init = (), + runtime = { + Runtime: statemine_runtime::Runtime, + RuntimeOrigin: statemine_runtime::RuntimeOrigin, + RuntimeCall: statemine_runtime::RuntimeEvent, + RuntimeEvent: statemine_runtime::RuntimeEvent, + XcmpMessageHandler: statemine_runtime::XcmpQueue, + DmpMessageHandler: statemine_runtime::DmpQueue, + LocationToAccountId: statemine_runtime::xcm_config::LocationToAccountId, + System: statemine_runtime::System, + Balances: statemine_runtime::Balances, + ParachainSystem: statemine_runtime::ParachainSystem, + ParachainInfo: statemine_runtime::ParachainInfo, + }, + pallets_extra = { + PolkadotXcm: statemine_runtime::PolkadotXcm, + Assets: statemine_runtime::Assets, + ForeignAssets: statemine_runtime::Assets, + } + }, + pub struct PenpalKusama { + genesis = penpal::genesis(penpal::PARA_ID), + on_init = (), + runtime = { + Runtime: penpal_runtime::Runtime, + RuntimeOrigin: penpal_runtime::RuntimeOrigin, + RuntimeCall: penpal_runtime::RuntimeEvent, + RuntimeEvent: penpal_runtime::RuntimeEvent, + 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 = { + PolkadotXcm: penpal_runtime::PolkadotXcm, + Assets: penpal_runtime::Assets, + } + }, + pub struct Collectives { + genesis = collectives::genesis(), + on_init = (), + runtime = { + Runtime: collectives_polkadot_runtime::Runtime, + RuntimeOrigin: collectives_polkadot_runtime::RuntimeOrigin, + RuntimeCall: collectives_polkadot_runtime::RuntimeEvent, + RuntimeEvent: collectives_polkadot_runtime::RuntimeEvent, + 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 = { + PolkadotXcm: collectives_polkadot_runtime::PolkadotXcm, + } + }, + pub struct BHKusama { + 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::RuntimeEvent, + RuntimeEvent: bridge_hub_kusama_runtime::RuntimeEvent, + 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 = { + PolkadotXcm: bridge_hub_kusama_runtime::PolkadotXcm, + } + }, + pub struct BHPolkadot { + 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::RuntimeEvent, + RuntimeEvent: bridge_hub_polkadot_runtime::RuntimeEvent, + 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 = { + PolkadotXcm: bridge_hub_polkadot_runtime::PolkadotXcm, + } + } +} + +decl_test_networks! { + pub struct PolkadotMockNet { + relay_chain = Polkadot, + parachains = vec![ + Statemint, + PenpalPolkadot, + Collectives, + BHPolkadot, + ], + }, + pub struct KusamaMockNet { + relay_chain = Kusama, + parachains = vec![ + Statemine, + PenpalKusama, + BHKusama, + ], + } +} + +parameter_types! { + // Polkadot + pub PolkadotSender: AccountId = Polkadot::account_id_of(ALICE); + pub PolkadotReceiver: AccountId = Polkadot::account_id_of(BOB); + // Kusama + pub KusamaSender: AccountId = Kusama::account_id_of(ALICE); + pub KusamaReceiver: AccountId = Kusama::account_id_of(BOB); + // Statemint + pub StatemintSender: AccountId = Statemint::account_id_of(ALICE); + pub StatemintReceiver: AccountId = Statemint::account_id_of(BOB); + // Statemine + pub StatemineSender: AccountId = Statemine::account_id_of(ALICE); + pub StatemineReceiver: AccountId = Statemine::account_id_of(BOB); + // Penpal Polkadot + pub PenpalPolkadotSender: AccountId = PenpalPolkadot::account_id_of(ALICE); + pub PenpalPolkadotReceiver: AccountId = PenpalPolkadot::account_id_of(BOB); + // Penpal Kusama + pub PenpalKusamaSender: AccountId = PenpalKusama::account_id_of(ALICE); + pub PenpalKusamaReceiver: AccountId = PenpalKusama::account_id_of(BOB); + // Collectives + pub CollectivesSender: AccountId = Collectives::account_id_of(ALICE); + pub CollectivesReceiver: AccountId = Collectives::account_id_of(BOB); + // Bridge Hub Polkadot + pub BHPolkadotSender: AccountId = BHPolkadot::account_id_of(ALICE); + pub BHPolkadotReceiver: AccountId = BHPolkadot::account_id_of(BOB); + // Bridge Hub Kusama + pub BHKusamaSender: AccountId = BHKusama::account_id_of(ALICE); + pub BHKusamaReceiver: AccountId = BHKusama::account_id_of(BOB); +} diff --git a/xcm/xcm-emulator/Cargo.toml b/xcm/xcm-emulator/Cargo.toml index 819de0199c8..8da28d0283f 100644 --- a/xcm/xcm-emulator/Cargo.toml +++ b/xcm/xcm-emulator/Cargo.toml @@ -9,20 +9,27 @@ edition = "2021" codec = { package = "parity-scale-codec", version = "3.0.0" } paste = "1.0.5" quote = "1.0.23" +casey = "0.3.3" +log = { version = "0.4.17", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } 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-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } cumulus-primitives-core = { path = "../../primitives/core"} cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue" } cumulus-pallet-dmp-queue = { path = "../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system" } +cumulus-test-service = { path = "../../test/service" } parachain-info = { path = "../../parachains/pallets/parachain-info" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" } +parachains-common = { path = "../../parachains/common" } xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master" } diff --git a/xcm/xcm-emulator/README.md b/xcm/xcm-emulator/README.md index 384a781fab4..267258d758b 100644 --- a/xcm/xcm-emulator/README.md +++ b/xcm/xcm-emulator/README.md @@ -9,8 +9,9 @@ a zombienet and as all the chains are in one process debugging using Clion is ea ## Limitations -As the channels are mocked, using xcm-emulator tests to test -channel setup would not be appropriate. +As the messages do not physically go through the same messaging infrastructure +there is some code that is not being tested compared to using slower E2E tests. +In future it may be possible to run these XCM emulated tests as E2E tests (without changes). ## Alternatives @@ -20,7 +21,7 @@ repo) is the perfect tool for this. ## How to use -1. Set up a relay chain: + diff --git a/xcm/xcm-emulator/example/Cargo.toml b/xcm/xcm-emulator/example/Cargo.toml deleted file mode 100644 index e5bacd89909..00000000000 --- a/xcm/xcm-emulator/example/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "xcm-emulator-example" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" - -[dependencies] -serde = { version = "1.0.137", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -proc-macro2 = "1.0.40" - -frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } -frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } - -cumulus-primitives-core = { path = "../../../primitives/core" } -cumulus-pallet-xcmp-queue = { path = "../../../pallets/xcmp-queue" } -parachain-info = { path = "../../../parachains/pallets/parachain-info" } - -xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } -kusama-runtime = { git = "https://github.com/paritytech/polkadot", branch = "master" } -pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } - - -xcm-emulator = { path = ".." } -test-runtime = { path = "test-runtime" } - -[features] -runtime-benchmarks = [ - "kusama-runtime/runtime-benchmarks", - "test-runtime/runtime-benchmarks", -] diff --git a/xcm/xcm-emulator/example/src/lib.rs b/xcm/xcm-emulator/example/src/lib.rs deleted file mode 100644 index e8626db930c..00000000000 --- a/xcm/xcm-emulator/example/src/lib.rs +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use frame_support::{pallet_prelude::Weight, traits::GenesisBuild}; -use sp_runtime::AccountId32; - -use xcm_emulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; - -// Set up relay chain. -decl_test_relay_chain! { - pub struct KusamaRelay { - Runtime = kusama_runtime::Runtime, - XcmConfig = kusama_runtime::xcm_config::XcmConfig, - new_ext = kusama_ext(), - } -} - -// Set up ParachainA. -decl_test_parachain! { - pub struct ParachainA { - Runtime = test_runtime::Runtime, - RuntimeOrigin = test_runtime::RuntimeOrigin, - XcmpMessageHandler = test_runtime::XcmpQueue, - DmpMessageHandler = test_runtime::DmpQueue, - new_ext = parachain_ext(1), - } -} - -// Set up ParachainB. -decl_test_parachain! { - pub struct ParachainB { - Runtime = test_runtime::Runtime, - RuntimeOrigin = test_runtime::RuntimeOrigin, - XcmpMessageHandler = test_runtime::XcmpQueue, - DmpMessageHandler = test_runtime::DmpQueue, - new_ext = parachain_ext(2), - } -} - -// Set up ParachainC. -decl_test_parachain! { - pub struct ParachainC { - Runtime = test_runtime::Runtime, - RuntimeOrigin = test_runtime::RuntimeOrigin, - XcmpMessageHandler = test_runtime::XcmpQueue, - DmpMessageHandler = test_runtime::DmpQueue, - new_ext = parachain_ext(3), - } -} - -// Set up a network with all the declared parachains and a relay chain. -decl_test_network! { - pub struct Network { - relay_chain = KusamaRelay, - parachains = vec![ - (1, ParachainA), - (2, ParachainB), - (3, ParachainC), - ], - } -} - -pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); -pub const INITIAL_BALANCE: u128 = 1_000_000_000_000; - -// Parachain TextExternalities setup. -pub fn parachain_ext(para_id: u32) -> sp_io::TestExternalities { - use test_runtime::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - - let parachain_info_config = parachain_info::GenesisConfig { parachain_id: para_id.into() }; - - >::assimilate_storage( - ¶chain_info_config, - &mut t, - ) - .unwrap(); - - pallet_balances::GenesisConfig:: { balances: vec![(ALICE, INITIAL_BALANCE)] } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -fn default_parachains_host_configuration( -) -> polkadot_runtime_parachains::configuration::HostConfiguration< - polkadot_primitives::v4::BlockNumber, -> { - use polkadot_primitives::v4::{MAX_CODE_SIZE, MAX_POV_SIZE}; - - polkadot_runtime_parachains::configuration::HostConfiguration { - minimum_validation_upgrade_delay: 5, - validation_upgrade_cooldown: 10u32, - validation_upgrade_delay: 10, - code_retention_period: 1200, - max_code_size: MAX_CODE_SIZE, - max_pov_size: MAX_POV_SIZE, - max_head_data_size: 32 * 1024, - group_rotation_frequency: 20, - chain_availability_period: 4, - thread_availability_period: 4, - max_upward_queue_count: 8, - max_upward_queue_size: 1024 * 1024, - max_downward_message_size: 1024, - ump_service_total_weight: Weight::from_parts(4 * 1_000_000_000, 0), - max_upward_message_size: 50 * 1024, - max_upward_message_num_per_candidate: 5, - hrmp_sender_deposit: 0, - hrmp_recipient_deposit: 0, - hrmp_channel_max_capacity: 8, - hrmp_channel_max_total_size: 8 * 1024, - hrmp_max_parachain_inbound_channels: 4, - hrmp_max_parathread_inbound_channels: 4, - hrmp_channel_max_message_size: 1024 * 1024, - hrmp_max_parachain_outbound_channels: 4, - hrmp_max_parathread_outbound_channels: 4, - hrmp_max_message_num_per_candidate: 5, - dispute_period: 6, - no_show_slots: 2, - n_delay_tranches: 25, - needed_approvals: 2, - relay_vrf_modulo_samples: 2, - zeroth_delay_tranche_width: 0, - ..Default::default() - } -} - -// Relay chain TestExternalities setup. -pub fn kusama_ext() -> sp_io::TestExternalities { - use kusama_runtime::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - - pallet_balances::GenesisConfig:: { balances: vec![(ALICE, INITIAL_BALANCE)] } - .assimilate_storage(&mut t) - .unwrap(); - - polkadot_runtime_parachains::configuration::GenesisConfig:: { - config: default_parachains_host_configuration(), - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -#[cfg(test)] -mod tests { - use super::*; - use codec::Encode; - - use cumulus_primitives_core::ParaId; - use frame_support::{assert_ok, dispatch::GetDispatchInfo, traits::Currency}; - use sp_runtime::traits::AccountIdConversion; - use xcm::{latest::Error::BadOrigin, v3::prelude::*, VersionedMultiLocation, VersionedXcm}; - use xcm_emulator::TestExt; - - #[test] - fn dmp() { - Network::reset(); - - let remark = test_runtime::RuntimeCall::System( - frame_system::Call::::remark_with_event { - remark: "Hello from Kusama!".as_bytes().to_vec(), - }, - ); - KusamaRelay::execute_with(|| { - assert_ok!(kusama_runtime::XcmPallet::force_default_xcm_version( - kusama_runtime::RuntimeOrigin::root(), - Some(3) - )); - assert_ok!(kusama_runtime::XcmPallet::send_xcm( - Here, - Parachain(1), - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), - call: remark.encode().into(), - }]), - )); - }); - - ParachainA::execute_with(|| { - use test_runtime::{RuntimeEvent, System}; - System::events().iter().for_each(|r| println!(">>> {:?}", r.event)); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { sender: _, hash: _ }) - ))); - }); - } - - #[test] - fn ump() { - Network::reset(); - - KusamaRelay::execute_with(|| { - assert_ok!(kusama_runtime::XcmPallet::force_default_xcm_version( - kusama_runtime::RuntimeOrigin::root(), - Some(3) - )); - let _ = kusama_runtime::Balances::deposit_creating( - &ParaId::from(1).into_account_truncating(), - 1_000_000_000_000, - ); - }); - - let remark = kusama_runtime::RuntimeCall::System(frame_system::Call::< - kusama_runtime::Runtime, - >::remark_with_event { - remark: "Hello from ParachainA!".as_bytes().to_vec(), - }); - ParachainA::execute_with(|| { - assert_ok!(test_runtime::PolkadotXcm::force_default_xcm_version( - test_runtime::RuntimeOrigin::root(), - Some(3) - )); - assert_ok!(test_runtime::PolkadotXcm::send_xcm( - Here, - Parent, - Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts( - INITIAL_BALANCE as u64, - 1024 * 1024 - ), - call: remark.encode().into(), - } - ]), - )); - }); - - KusamaRelay::execute_with(|| { - use kusama_runtime::{RuntimeEvent, System}; - // TODO: https://github.com/paritytech/polkadot/pull/6824 or change this call to - // force_create_assets like we do in cumulus integration tests. - // assert!(System::events().iter().any(|r| matches!( - // r.event, - // RuntimeEvent::System(frame_system::Event::Remarked { sender: _, hash: _ }) - // ))); - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Ump(polkadot_runtime_parachains::ump::Event::ExecutedUpward( - _, - Outcome::Incomplete(_, XcmError::NoPermission) - )) - ))); - }); - } - - #[test] - fn para_to_para() { - Network::reset(); - - let remark = test_runtime::RuntimeCall::System( - frame_system::Call::::remark_with_event { - remark: "Hello from ParachainA!".as_bytes().to_vec(), - }, - ); - ParachainA::execute_with(|| { - assert_ok!(test_runtime::PolkadotXcm::send_xcm( - Here, - MultiLocation::new(1, X1(Parachain(2))), - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(9_000_000, 0), - call: remark.encode().into(), - }]), - )); - }); - - ParachainB::execute_with(|| { - use test_runtime::{RuntimeEvent, System}; - System::events().iter().for_each(|r| println!(">>> {:?}", r.event)); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { sender: _, hash: _ }) - ))); - }); - } - - #[test] - fn xcmp_through_a_parachain() { - use test_runtime::{PolkadotXcm, Runtime, RuntimeCall}; - - Network::reset(); - - // The message goes through: ParachainA --> ParachainB --> ParachainC - let remark = RuntimeCall::System(frame_system::Call::::remark_with_event { - remark: "Hello from ParachainA!".as_bytes().to_vec(), - }); - let send_xcm_to_parachain_c = RuntimeCall::PolkadotXcm(pallet_xcm::Call::::send { - dest: Box::new(VersionedMultiLocation::V3(MultiLocation::new(1, X1(Parachain(3))))), - message: Box::new(VersionedXcm::V3(Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - // The weight here does not matter, as this is going to fail with BadOrigin once it - // reaches ParachainC, as it's not going to satisfy AccountId32Aliases conversion - // rules. - require_weight_at_most: Weight::from_parts(0, 0), - call: remark.encode().into(), - }]))), - }); - assert_eq!( - send_xcm_to_parachain_c.get_dispatch_info().weight, - Weight::from_parts(100000010, 10) - ); - ParachainA::execute_with(|| { - assert_ok!(PolkadotXcm::send_xcm( - Here, - MultiLocation::new(1, X1(Parachain(2))), - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(110_000_010, 20_000), - call: send_xcm_to_parachain_c.encode().into(), - }]), - )); - }); - - ParachainB::execute_with(|| { - use test_runtime::{RuntimeEvent, System}; - System::events().iter().for_each(|r| println!(">>> {:?}", r.event)); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent(_, _, _)) - ))); - }); - - // ParachainC: The origin should not satisfy AccountId32Aliases conversion rules and thus fail. - ParachainC::execute_with(|| { - use test_runtime::{RuntimeEvent, System}; - System::events().iter().for_each(|r| println!(">>> {:?}", r.event)); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { error, .. }) if error == BadOrigin - ))); - }); - } - - #[test] - fn deduplicate_dmp() { - Network::reset(); - KusamaRelay::execute_with(|| { - assert_ok!(kusama_runtime::XcmPallet::force_default_xcm_version( - kusama_runtime::RuntimeOrigin::root(), - Some(3) - )); - }); - - send_remark_with_event_to_child_parachain_a("Kusama", 2); - parachain_a_verify_remark_event_and_reset_all_events(true); - - // a different dmp message in same relay-parent-block allow execution. - send_remark_with_event_to_child_parachain_a("Polkadot", 1); - parachain_a_verify_remark_event_and_reset_all_events(true); - - // same dmp message with same relay-parent-block wouldn't execution - send_remark_with_event_to_child_parachain_a("Kusama", 1); - parachain_a_verify_remark_event_and_reset_all_events(false); - - // different relay-parent-block allow dmp message execution - KusamaRelay::execute_with(|| kusama_runtime::System::set_block_number(2)); - - send_remark_with_event_to_child_parachain_a("Kusama", 1); - parachain_a_verify_remark_event_and_reset_all_events(true); - - // reset can send same dmp message again - Network::reset(); - KusamaRelay::execute_with(|| { - assert_ok!(kusama_runtime::XcmPallet::force_default_xcm_version( - kusama_runtime::RuntimeOrigin::root(), - Some(3) - )); - }); - - send_remark_with_event_to_child_parachain_a("Kusama", 1); - parachain_a_verify_remark_event_and_reset_all_events(true); - } - - fn send_remark_with_event_to_child_parachain_a(msg: &str, count: u32) { - let remark = test_runtime::RuntimeCall::System( - frame_system::Call::::remark_with_event { - remark: msg.as_bytes().to_vec(), - }, - ); - KusamaRelay::execute_with(|| { - for _ in 0..count { - assert_ok!(kusama_runtime::XcmPallet::send_xcm( - Here, - Parachain(1), - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts( - INITIAL_BALANCE as u64, - 1024 * 1024 - ), - call: remark.encode().into(), - }]), - )); - } - }); - } - - fn parachain_a_verify_remark_event_and_reset_all_events(received: bool) { - ParachainA::execute_with(|| { - use test_runtime::{RuntimeEvent, System}; - System::events().iter().for_each(|r| println!(">>> {:?}", r.event)); - - if received { - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { sender: _, hash: _ }) - ))); - - System::reset_events(); - } else { - assert!(System::events().iter().all(|r| !matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { sender: _, hash: _ }) - ))); - } - }); - } -} diff --git a/xcm/xcm-emulator/example/test-runtime/Cargo.toml b/xcm/xcm-emulator/example/test-runtime/Cargo.toml deleted file mode 100644 index 945d9e54751..00000000000 --- a/xcm/xcm-emulator/example/test-runtime/Cargo.toml +++ /dev/null @@ -1,71 +0,0 @@ -[package] -name = "test-runtime" -description = "A simple runtime for cross-chain message tests." -license = "Apache-2.0" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" - -[dependencies] -serde = { version = "1.0.137", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.1", default-features = false, features = ["derive"] } - -sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } -frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } - -cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } -parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false } -cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } -cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } - -xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } -xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master" } -pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } - - -[features] -default = ["std"] -no_std = [] -std = [ - "serde/std", - "codec/std", - "scale-info/std", - - "sp-runtime/std", - "sp-io/std", - "sp-std/std", - "sp-core/std", - "pallet-balances/std", - "frame-support/std", - "frame-system/std", - - "cumulus-pallet-dmp-queue/std", - "cumulus-pallet-xcmp-queue/std", - "cumulus-pallet-xcm/std", - "cumulus-pallet-parachain-system/std", - "parachain-info/std", - "cumulus-primitives-utility/std", - - "xcm/std", - "xcm-executor/std", - "polkadot-parachain/std", - "xcm-builder/std", - "pallet-xcm/std", - "polkadot-runtime-parachains/std", -] - -runtime-benchmarks = [ - "pallet-xcm/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", -] diff --git a/xcm/xcm-emulator/example/test-runtime/src/lib.rs b/xcm/xcm-emulator/example/test-runtime/src/lib.rs deleted file mode 100644 index 9010936892c..00000000000 --- a/xcm/xcm-emulator/example/test-runtime/src/lib.rs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2023 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use frame_support::{ - construct_runtime, parameter_types, - traits::{ConstU32, Everything, Nothing}, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use polkadot_parachain::primitives::Sibling; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{Convert, IdentityLookup}, - AccountId32, -}; -use xcm::v3::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin, - FixedWeightBounds, IsConcrete, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, -}; - -use xcm_executor::{Config, XcmExecutor}; - -pub type AccountId = AccountId32; -pub type Balance = u128; -pub type Amount = i128; - -parameter_types! { - pub const BlockHashCount: u64 = 250; -} - -impl frame_system::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = ConstU32<16>; -} - -parameter_types! { - pub ExistentialDeposit: Balance = 1; - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; -} - -impl pallet_balances::Config for Runtime { - type MaxLocks = MaxLocks; - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; - type HoldIdentifier = (); - type FreezeIdentifier = (); - type MaxHolds = (); - type MaxFreezes = (); -} - -impl parachain_info::Config for Runtime {} - -parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Kusama; - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); -} - -pub type LocationToAccountId = ( - ParentIsPreset, - SiblingParachainConvertsVia, - AccountId32Aliases, -); - -pub type XcmOriginToCallOrigin = ( - SovereignSignedViaLocation, - RelayChainAsNative, - SiblingParachainAsNative, - SignedAccountId32AsNative, - XcmPassthrough, -); - -parameter_types! { - pub const UnitWeightCost: u64 = 10; - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; - pub const RelayChain: MultiLocation = MultiLocation::parent(); -} - -/// Means for transacting assets on this chain. -pub type LocalAssetTransactor = CurrencyAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; - -/// The means for routing XCM messages which are not for local execution into -/// the right message queues. -pub type XcmRouter = ( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -); - -pub type Barrier = AllowUnpaidExecutionFrom; - -pub struct XcmConfig; -impl Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = XcmOriginToCallOrigin; - type IsReserve = (); - type IsTeleporter = (); - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = (); - type ResponseHandler = (); - type AssetTrap = (); - type AssetClaims = (); - type SubscriptionService = (); - type AssetLocker = PolkadotXcm; - type AssetExchanger = (); - type PalletInstancesInfo = (); - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; -} - -parameter_types! { - pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); - pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); -} - -impl cumulus_pallet_parachain_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = ParachainInfo; - type DmpMessageHandler = DmpQueue; - type ReservedDmpWeight = ReservedDmpWeight; - type OutboundXcmpMessageSource = XcmpQueue; - type XcmpMessageHandler = XcmpQueue; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - type ExecuteOverweightOrigin = EnsureRoot; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToCallOrigin; - type WeightInfo = (); - type PriceForSiblingDelivery = (); -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} - -#[cfg(feature = "runtime-benchmarks")] -parameter_types! { - pub ReachableDest: Option = Some(Parent.into()); -} - -pub type LocalOriginToLocation = SignedToAccountId32; - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Nothing; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = (); - type MaxLockers = ConstU32<8>; - type WeightInfo = pallet_xcm::TestWeightInfo; - type AdminOrigin = EnsureRoot; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; -} - -pub struct AccountIdToMultiLocation; -impl Convert for AccountIdToMultiLocation { - fn convert(account: AccountId) -> MultiLocation { - X1(Junction::AccountId32 { network: None, id: account.into() }).into() - } -} - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Runtime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Config, Event}, - ParachainInfo: parachain_info::{Pallet, Storage, Config}, - XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event}, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event}, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin}, - } -); diff --git a/xcm/xcm-emulator/src/lib.rs b/xcm/xcm-emulator/src/lib.rs index a8bebd6fb02..ad9cb2873f4 100644 --- a/xcm/xcm-emulator/src/lib.rs +++ b/xcm/xcm-emulator/src/lib.rs @@ -14,17 +14,22 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +pub use casey::pascal; pub use codec::Encode; -pub use paste; - pub use frame_support::{ + sp_runtime::BuildStorage, traits::{Get, Hooks}, weights::Weight, }; -pub use frame_system; +pub use frame_system::AccountInfo; +pub use log; +pub use pallet_balances::AccountData; +pub use paste; pub use sp_arithmetic::traits::Bounded; +pub use sp_core::storage::Storage; pub use sp_io::TestExternalities; pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData}; +pub use sp_trie::StorageProof; pub use cumulus_pallet_dmp_queue; pub use cumulus_pallet_parachain_system; @@ -35,91 +40,230 @@ pub use cumulus_primitives_core::{ }; pub use cumulus_primitives_parachain_inherent::ParachainInherentData; pub use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; +pub use cumulus_test_service::get_account_id_from_seed; pub use parachain_info; +pub use parachains_common::{AccountId, BlockNumber}; pub use polkadot_primitives; pub use polkadot_runtime_parachains::{ dmp, ump::{MessageId, UmpSink, XcmSink}, }; +pub use std::{collections::HashMap, thread::LocalKey}; pub use xcm::{v3::prelude::*, VersionedXcm}; pub use xcm_executor::XcmExecutor; +thread_local! { + /// Downward messages, each message is: `(to_para_id, [(relay_block_number, msg)])` + #[allow(clippy::type_complexity)] + pub static DOWNWARD_MESSAGES: RefCell)>)>>> + = RefCell::new(HashMap::new()); + /// Downward messages that already processed by parachains, each message is: `(to_para_id, relay_block_number, Vec)` + #[allow(clippy::type_complexity)] + pub static DMP_DONE: RefCell)>>> + = RefCell::new(HashMap::new()); + /// Horizontal messages, each message is: `(to_para_id, [(from_para_id, relay_block_number, msg)])` + #[allow(clippy::type_complexity)] + pub static HORIZONTAL_MESSAGES: RefCell)>)>>> + = RefCell::new(HashMap::new()); + /// Upward messages, each message is: `(from_para_id, msg) + pub static UPWARD_MESSAGES: RefCell)>>> = RefCell::new(HashMap::new()); + /// Global incremental relay chain block number + pub static RELAY_BLOCK_NUMBER: RefCell> = RefCell::new(HashMap::new()); + /// Parachains Ids a the Network + pub static PARA_IDS: RefCell>> = RefCell::new(HashMap::new()); + /// Flag indicating if global variables have been initialized for a certain Network + pub static INITIALIZED: RefCell> = RefCell::new(HashMap::new()); +} + pub trait TestExt { + fn build_new_ext(storage: Storage) -> sp_io::TestExternalities; fn new_ext() -> sp_io::TestExternalities; fn reset_ext(); fn execute_with(execute: impl FnOnce() -> R) -> R; + fn ext_wrapper(func: impl FnOnce() -> R) -> R; } -#[macro_export] -macro_rules! decl_test_relay_chain { - ( - pub struct $name:ident { - Runtime = $runtime:path, - XcmConfig = $xcm_config:path, - new_ext = $new_ext:expr, - } - ) => { - pub struct $name; +pub trait Network { + fn _init(); + fn _para_ids() -> Vec; + fn _relay_block_number() -> u32; + fn _set_relay_block_number(block_number: u32); + fn _process_messages(); + fn _has_unprocessed_messages() -> bool; + fn _process_downward_messages(); + fn _process_horizontal_messages(); + fn _process_upward_messages(); + fn _hrmp_channel_parachain_inherent_data( + para_id: u32, + relay_parent_number: u32, + ) -> ParachainInherentData; +} - $crate::__impl_ext_for_relay_chain!($name, $runtime, $new_ext); +pub trait NetworkComponent { + fn network_name() -> &'static str; + + fn init() { + N::_init(); + } + + fn relay_block_number() -> u32 { + N::_relay_block_number() + } + + fn set_relay_block_number(block_number: u32) { + N::_set_relay_block_number(block_number); + } + + fn para_ids() -> Vec { + N::_para_ids() + } + + fn send_horizontal_messages)>>( + to_para_id: u32, + iter: I, + ) { + HORIZONTAL_MESSAGES.with(|b| { + b.borrow_mut() + .get_mut(Self::network_name()) + .unwrap() + .push_back((to_para_id, iter.collect())) + }); + } + + fn send_upward_message(from_para_id: u32, msg: Vec) { + UPWARD_MESSAGES.with(|b| { + b.borrow_mut() + .get_mut(Self::network_name()) + .unwrap() + .push_back((from_para_id, msg)) + }); + } + + fn send_downward_messages( + to_para_id: u32, + iter: impl Iterator)>, + ) { + DOWNWARD_MESSAGES.with(|b| { + b.borrow_mut() + .get_mut(Self::network_name()) + .unwrap() + .push_back((to_para_id, iter.collect())) + }); + } + + fn hrmp_channel_parachain_inherent_data( + para_id: u32, + relay_parent_number: u32, + ) -> ParachainInherentData { + N::_hrmp_channel_parachain_inherent_data(para_id, relay_parent_number) + } + + fn process_messages() { + N::_process_messages(); + } +} - impl $crate::UmpSink for $name { - fn process_upward_message( - origin: $crate::ParaId, - msg: &[u8], - max_weight: $crate::Weight, - ) -> Result<$crate::Weight, ($crate::MessageId, $crate::Weight)> { - use $crate::{TestExt, UmpSink}; +pub trait RelayChain: UmpSink { + type Runtime; + type RuntimeOrigin; + type RuntimeCall; + type RuntimeEvent; + type XcmConfig; + type SovereignAccountOf; + type System; + type Balances; +} - Self::execute_with(|| { - $crate::XcmSink::<$crate::XcmExecutor<$xcm_config>, $runtime>::process_upward_message(origin, msg, max_weight) - }) - } - } - }; +pub trait Parachain: XcmpMessageHandler + DmpMessageHandler { + type Runtime; + type RuntimeOrigin; + type RuntimeCall; + type RuntimeEvent; + type XcmpMessageHandler; + type DmpMessageHandler; + type LocationToAccountId; + type System; + type Balances; + type ParachainSystem; + type ParachainInfo; } +// Relay Chain Implementation #[macro_export] -macro_rules! decl_test_parachain { +macro_rules! decl_test_relay_chains { ( - pub struct $name:ident { - Runtime = $runtime:path, - RuntimeOrigin = $origin:path, - XcmpMessageHandler = $xcmp_message_handler:path, - DmpMessageHandler = $dmp_message_handler:path, - new_ext = $new_ext:expr, - } + $( + pub struct $name:ident { + genesis = $genesis:expr, + on_init = $on_init:expr, + runtime = { + Runtime: $($runtime:tt)::*, + RuntimeOrigin: $($runtime_origin:tt)::*, + RuntimeCall: $($runtime_call:tt)::*, + RuntimeEvent: $($runtime_event:tt)::*, + XcmConfig: $($xcm_config:tt)::*, + SovereignAccountOf: $($sovereign_acc_of:tt)::*, + System: $($system:tt)::*, + Balances: $($balances:tt)::*, + }, + pallets_extra = { + $($pallet_name:ident: $pallet_path:path,)* + } + } + ), + + ) => { - pub struct $name; - - $crate::__impl_ext_for_parachain!($name, $runtime, $origin, $new_ext); + $( + pub struct $name; + + 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)::*; + } - impl $crate::XcmpMessageHandler for $name { - fn handle_xcmp_messages< - 'a, - I: Iterator, - >( - iter: I, - max_weight: $crate::Weight, - ) -> $crate::Weight { - use $crate::{TestExt, XcmpMessageHandler}; + $crate::paste::paste! { + pub trait [<$name Pallet>] { + $( + type $pallet_name; + )? + } - $name::execute_with(|| { - <$xcmp_message_handler>::handle_xcmp_messages(iter, max_weight) - }) + impl [<$name Pallet>] for $name { + $( + type $pallet_name = $pallet_path; + )? + } } - } - impl $crate::DmpMessageHandler for $name { - fn handle_dmp_messages( - iter: impl Iterator)>, + $crate::__impl_xcm_handlers_for_relay_chain!($name); + $crate::__impl_test_ext_for_relay_chain!($name, $genesis, $on_init); + )+ + }; +} + +#[macro_export] +macro_rules! __impl_xcm_handlers_for_relay_chain { + ($name:ident) => { + impl $crate::UmpSink for $name { + fn process_upward_message( + origin: $crate::ParaId, + msg: &[u8], max_weight: $crate::Weight, - ) -> $crate::Weight { - use $crate::{DmpMessageHandler, TestExt}; + ) -> Result<$crate::Weight, ($crate::MessageId, $crate::Weight)> { + use $crate::{TestExt, UmpSink}; - $name::execute_with(|| { - <$dmp_message_handler>::handle_dmp_messages(iter, max_weight) + Self::execute_with(|| { + $crate::XcmSink::< + $crate::XcmExecutor<::XcmConfig>, + ::Runtime, + >::process_upward_message(origin, msg, max_weight) }) } } @@ -127,30 +271,44 @@ macro_rules! decl_test_parachain { } #[macro_export] -macro_rules! __impl_ext_for_relay_chain { +macro_rules! __impl_test_ext_for_relay_chain { // entry point: generate ext name - ($name:ident, $runtime:path, $new_ext:expr) => { + ($name:ident, $genesis:expr, $on_init:expr) => { $crate::paste::paste! { - $crate::__impl_ext_for_relay_chain!(@impl $name, $runtime, $new_ext, []); + $crate::__impl_test_ext_for_relay_chain!(@impl $name, $genesis, $on_init, []); } }; // impl - (@impl $name:ident, $runtime:path, $new_ext:expr, $ext_name:ident) => { + (@impl $name:ident, $genesis:expr, $on_init:expr, $ext_name:ident) => { thread_local! { pub static $ext_name: $crate::RefCell<$crate::TestExternalities> - = $crate::RefCell::new($new_ext); + = $crate::RefCell::new(<$name>::build_new_ext($genesis)); } - impl $crate::TestExt for $name { + impl TestExt for $name { + fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { + let mut ext = sp_io::TestExternalities::new(storage); + ext.execute_with(|| { + $on_init; + sp_tracing::try_init_simple(); + ::System::set_block_number(1); + }); + ext + } + fn new_ext() -> $crate::TestExternalities { - $new_ext + <$name>::build_new_ext($genesis) } fn reset_ext() { - $ext_name.with(|v| *v.borrow_mut() = $new_ext); + $ext_name.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); } fn execute_with(execute: impl FnOnce() -> R) -> R { + use $crate::{NetworkComponent}; + // Make sure the Network is initialized + <$name>::init(); + let r = $ext_name.with(|v| v.borrow_mut().execute_with(execute)); // send messages if needed @@ -159,15 +317,15 @@ macro_rules! __impl_ext_for_relay_chain { use $crate::polkadot_primitives::runtime_api::runtime_decl_for_parachain_host::ParachainHostV4; //TODO: mark sent count & filter out sent msg - for para_id in _para_ids() { + for para_id in <$name>::para_ids() { // downward messages - let downward_messages = <$runtime>::dmq_contents(para_id.into()) + let downward_messages = ::Runtime::dmq_contents(para_id.into()) .into_iter() .map(|inbound| (inbound.sent_at, inbound.msg)); if downward_messages.len() == 0 { continue; } - _Messenger::send_downward_messages(para_id, downward_messages.into_iter()); + <$name>::send_downward_messages(para_id, downward_messages.into_iter()); // Note: no need to handle horizontal messages, as the // simulator directly sends them to dest (not relayed). @@ -175,80 +333,227 @@ macro_rules! __impl_ext_for_relay_chain { }) }); - _process_messages(); + <$name>::process_messages(); r } + + fn ext_wrapper(func: impl FnOnce() -> R) -> R { + $ext_name.with(|v| { + v.borrow_mut().execute_with(|| { + func() + }) + }) + } + } + }; +} + +#[macro_export] +macro_rules! __impl_relay { + ($network_name:ident, $relay_chain:ty) => { + impl $crate::NetworkComponent<$network_name> for $relay_chain { + fn network_name() -> &'static str { + stringify!($network_name) + } + } + + 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::(seed) + } + + pub fn account_data_of(account: AccountId) -> $crate::AccountData { + Self::ext_wrapper(|| ::System::account(account).data) + } + + pub fn sovereign_account_id_of(location: $crate::MultiLocation) -> $crate::AccountId { + ::SovereignAccountOf::convert(location.into()).unwrap() + } + + pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { + Self::ext_wrapper(|| { + for account in accounts { + let _ = ::Balances::force_set_balance( + ::RuntimeOrigin::root(), + account.0.into(), + account.1.into(), + ); + } + }); + } + + pub fn events() -> Vec<::RuntimeEvent> { + ::System::events() + .iter() + .map(|record| record.event.clone()) + .collect() + } + } + }; +} + +// Parachain Implementation +#[macro_export] +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, + 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 = { + $($pallet_name:ident: $pallet_path:path,)* + } + } + ), + + + ) => { + $( + pub struct $name; + + 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 ParachainInfo = $parachain_info; + } + + $crate::paste::paste! { + pub trait [<$name Pallet>] { + $( + type $pallet_name; + )* + } + + impl [<$name Pallet>] for $name { + $( + type $pallet_name = $pallet_path; + )* + } + } + + $crate::__impl_xcm_handlers_for_parachain!($name); + $crate::__impl_test_ext_for_parachain!($name, $genesis, $on_init); + )+ + }; +} + +#[macro_export] +macro_rules! __impl_xcm_handlers_for_parachain { + ($name:ident) => { + impl $crate::XcmpMessageHandler for $name { + fn handle_xcmp_messages< + 'a, + I: Iterator, + >( + iter: I, + max_weight: $crate::Weight, + ) -> $crate::Weight { + use $crate::{TestExt, XcmpMessageHandler}; + + $name::execute_with(|| { + ::XcmpMessageHandler::handle_xcmp_messages(iter, max_weight) + }) + } + } + + impl $crate::DmpMessageHandler for $name { + fn handle_dmp_messages( + iter: impl Iterator)>, + max_weight: $crate::Weight, + ) -> $crate::Weight { + use $crate::{DmpMessageHandler, TestExt}; + + $name::execute_with(|| { + ::DmpMessageHandler::handle_dmp_messages(iter, max_weight) + }) + } } }; } #[macro_export] -macro_rules! __impl_ext_for_parachain { +macro_rules! __impl_test_ext_for_parachain { // entry point: generate ext name - ($name:ident, $runtime:path, $origin:path, $new_ext:expr) => { + ($name:ident, $genesis:expr, $on_init:expr) => { $crate::paste::paste! { - $crate::__impl_ext_for_parachain!(@impl $name, $runtime, $origin, $new_ext, []); + $crate::__impl_test_ext_for_parachain!(@impl $name, $genesis, $on_init, []); } }; // impl - (@impl $name:ident, $runtime:path, $origin:path, $new_ext:expr, $ext_name:ident) => { + (@impl $name:ident, $genesis:expr, $on_init:expr, $ext_name:ident) => { thread_local! { pub static $ext_name: $crate::RefCell<$crate::TestExternalities> - = $crate::RefCell::new($new_ext); + = $crate::RefCell::new(<$name>::build_new_ext($genesis)); } - impl $name { - fn prepare_for_xcmp() { - $ext_name.with(|v| { - v.borrow_mut().execute_with(|| { - use $crate::{Get, Hooks}; - type ParachainSystem = $crate::cumulus_pallet_parachain_system::Pallet<$runtime>; - - let block_number = $crate::frame_system::Pallet::<$runtime>::block_number(); - let para_id = $crate::parachain_info::Pallet::<$runtime>::get(); - - let _ = ParachainSystem::set_validation_data( - <$origin>::none(), - _hrmp_channel_parachain_inherent_data(para_id.into(), 1), - ); - // set `AnnouncedHrmpMessagesPerCandidate` - ParachainSystem::on_initialize(block_number); - }) + impl TestExt for $name { + fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { + let mut ext = sp_io::TestExternalities::new(storage); + ext.execute_with(|| { + $on_init; + sp_tracing::try_init_simple(); + ::System::set_block_number(1); }); + ext } - } - impl $crate::TestExt for $name { fn new_ext() -> $crate::TestExternalities { - $new_ext + <$name>::build_new_ext($genesis) } fn reset_ext() { - $ext_name.with(|v| *v.borrow_mut() = $new_ext); + $ext_name.with(|v| *v.borrow_mut() = <$name>::build_new_ext($genesis)); } fn execute_with(execute: impl FnOnce() -> R) -> R { - use $crate::{Get, Hooks}; - type ParachainSystem = $crate::cumulus_pallet_parachain_system::Pallet<$runtime>; + use $crate::{Get, Hooks, NetworkComponent}; - $crate::GLOBAL_RELAY.with(|v| { - *v.borrow_mut() += 1; - }); + // Make sure the Network is initialized + <$name>::init(); + + let mut relay_block_number = <$name>::relay_block_number(); + relay_block_number += 1; + <$name>::set_relay_block_number(relay_block_number); + + let para_id = <$name>::para_id().into(); $ext_name.with(|v| { v.borrow_mut().execute_with(|| { - let para_id = $crate::parachain_info::Pallet::<$runtime>::get(); - $crate::GLOBAL_RELAY.with(|v| { - let relay_block = *v.borrow(); - let _ = ParachainSystem::set_validation_data( - <$origin>::none(), - _hrmp_channel_parachain_inherent_data(para_id.into(), relay_block), - ); - }); + // Make sure it has been recorded properly + let relay_block_number = <$name>::relay_block_number(); + let _ = ::ParachainSystem::set_validation_data( + ::RuntimeOrigin::none(), + <$name>::hrmp_channel_parachain_inherent_data(para_id, relay_block_number), + ); }) }); + let r = $ext_name.with(|v| v.borrow_mut().execute_with(execute)); // send messages if needed @@ -256,7 +561,7 @@ macro_rules! __impl_ext_for_parachain { v.borrow_mut().execute_with(|| { use sp_runtime::traits::Header as HeaderT; - let block_number = $crate::frame_system::Pallet::<$runtime>::block_number(); + let block_number = ::System::block_number(); let mock_header = HeaderT::new( 0, Default::default(), @@ -266,222 +571,367 @@ macro_rules! __impl_ext_for_parachain { ); // get messages - ParachainSystem::on_finalize(block_number); - let collation_info = ParachainSystem::collect_collation_info(&mock_header); + ::ParachainSystem::on_finalize(block_number); + let collation_info = ::ParachainSystem::collect_collation_info(&mock_header); // send upward messages - let para_id = $crate::parachain_info::Pallet::<$runtime>::get(); + let relay_block_number = <$name>::relay_block_number(); for msg in collation_info.upward_messages.clone() { - _Messenger::send_upward_message(para_id.into(), msg); + <$name>::send_upward_message(para_id, msg); } // send horizontal messages for msg in collation_info.horizontal_messages { - $crate::GLOBAL_RELAY.with(|v| { - let relay_block = *v.borrow(); - _Messenger::send_horizontal_messages( - msg.recipient.into(), - vec![(para_id.into(), relay_block, msg.data)].into_iter(), - ); - }); + <$name>::send_horizontal_messages( + msg.recipient.into(), + vec![(para_id.into(), relay_block_number, msg.data)].into_iter(), + ); } // clean messages - ParachainSystem::on_initialize(block_number); + ::ParachainSystem::on_initialize(block_number); }) }); - _process_messages(); + <$name>::process_messages(); r } + + fn ext_wrapper(func: impl FnOnce() -> R) -> R { + $ext_name.with(|v| { + v.borrow_mut().execute_with(|| { + func() + }) + }) + } } }; } -thread_local! { - /// Downward messages, each message is: `(to_para_id, [(relay_block_number, msg)])` - #[allow(clippy::type_complexity)] - pub static DOWNWARD_MESSAGES: RefCell)>)>> - = RefCell::new(VecDeque::new()); - #[allow(clippy::type_complexity)] - /// Downward messages that already processed by parachains, each message is: `(to_para_id, relay_block_number, Vec)` - pub static DMP_DONE: RefCell)>> - = RefCell::new(VecDeque::new()); - /// Horizontal messages, each message is: `(to_para_id, [(from_para_id, relay_block_number, msg)])` - #[allow(clippy::type_complexity)] - pub static HORIZONTAL_MESSAGES: RefCell)>)>> - = RefCell::new(VecDeque::new()); - /// Upward messages, each message is: `(from_para_id, msg) - pub static UPWARD_MESSAGES: RefCell)>> = RefCell::new(VecDeque::new()); - /// Global incremental relay chain block number - pub static GLOBAL_RELAY: RefCell = RefCell::new(1); -} - #[macro_export] -macro_rules! decl_test_network { - ( - pub struct $name:ident { - relay_chain = $relay_chain:ty, - parachains = vec![ $( ($para_id:expr, $parachain:ty), )* ], +macro_rules! __impl_parachain { + ($network_name:ident, $parachain:ty) => { + impl $crate::NetworkComponent<$network_name> for $parachain { + fn network_name() -> &'static str { + stringify!($network_name) + } } - ) => { - pub struct $name; - impl $name { - pub fn reset() { - use $crate::{TestExt, VecDeque}; + impl $parachain { + pub fn para_id() -> $crate::ParaId { + Self::ext_wrapper(|| ::ParachainInfo::get()) + } - <$relay_chain>::reset_ext(); - $( <$parachain>::reset_ext(); )* + pub fn parent_location() -> $crate::MultiLocation { + (Parent).into() + } - $( <$parachain>::prepare_for_xcmp(); )* + pub fn account_id_of(seed: &str) -> $crate::AccountId { + $crate::get_account_id_from_seed::(seed) + } - $crate::DOWNWARD_MESSAGES.with(|b| b.replace(VecDeque::new())); - $crate::DMP_DONE.with(|b| b.replace(VecDeque::new())); + pub fn account_data_of(account: AccountId) -> $crate::AccountData { + Self::ext_wrapper(|| ::System::account(account).data) } - } - fn _para_ids() -> Vec { - vec![$( $para_id, )*] - } + pub fn sovereign_account_id_of(location: $crate::MultiLocation) -> $crate::AccountId { + ::LocationToAccountId::convert(location.into()).unwrap() + } - fn _process_messages() { - while _has_unprocessed_messages() { - _process_upward_messages(); - _process_horizontal_messages(); - _process_downward_messages(); + pub fn fund_accounts(accounts: Vec<(AccountId, Balance)>) { + Self::ext_wrapper(|| { + for account in accounts { + let _ = ::Balances::force_set_balance( + ::RuntimeOrigin::root(), + account.0.into(), + account.1.into(), + ); + } + }); } - } - fn _has_unprocessed_messages() -> bool { - $crate::DOWNWARD_MESSAGES.with(|b| !b.borrow_mut().is_empty()) - || $crate::HORIZONTAL_MESSAGES.with(|b| !b.borrow_mut().is_empty()) - || $crate::UPWARD_MESSAGES.with(|b| !b.borrow_mut().is_empty()) + pub fn events() -> Vec<::RuntimeEvent> { + ::System::events() + .iter() + .map(|record| record.event.clone()) + .collect() + } + + fn prepare_for_xcmp() { + use $crate::NetworkComponent; + let para_id = Self::para_id(); + + ::ext_wrapper(|| { + use $crate::{Get, Hooks}; + + let block_number = ::System::block_number(); + + let _ = ::ParachainSystem::set_validation_data( + ::RuntimeOrigin::none(), + Self::hrmp_channel_parachain_inherent_data(para_id.into(), 1), + ); + // set `AnnouncedHrmpMessagesPerCandidate` + ::ParachainSystem::on_initialize(block_number); + }); + } } + }; +} - fn _process_downward_messages() { - use $crate::{DmpMessageHandler, Bounded}; - use polkadot_parachain::primitives::RelayChainBlockNumber; +// Network Implementation +#[macro_export] +macro_rules! decl_test_networks { + ( + $( + pub struct $name:ident { + relay_chain = $relay_chain:ty, + parachains = vec![ $( $parachain:ty, )* ], + } + ), + + + ) => { + $( + pub struct $name; + + impl $name { + pub 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::RELAY_BLOCK_NUMBER.with(|b| b.borrow_mut().remove(stringify!($name))); + + <$relay_chain>::reset_ext(); + $( <$parachain>::reset_ext(); )* + $( <$parachain>::prepare_for_xcmp(); )* + } + } - while let Some((to_para_id, messages)) - = $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().pop_front()) { - match to_para_id { - $( - $para_id => { - let mut msg_dedup: Vec<(RelayChainBlockNumber, Vec)> = Vec::new(); - for m in messages { - msg_dedup.push((m.0, m.1.clone())); - } - msg_dedup.dedup(); - - let msgs = msg_dedup.clone().into_iter().filter(|m| { - !$crate::DMP_DONE.with(|b| b.borrow_mut().contains(&(to_para_id, m.0, m.1.clone()))) - }).collect::)>>(); - if msgs.len() != 0 { - <$parachain>::handle_dmp_messages(msgs.clone().into_iter(), $crate::Weight::max_value()); - for m in msgs { - $crate::DMP_DONE.with(|b| b.borrow_mut().push_back((to_para_id, m.0, m.1))); + impl $crate::Network for $name { + 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::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())); + } + } + + fn _para_ids() -> Vec { + vec![$( + <$parachain>::para_id().into(), + )*] + } + + fn _relay_block_number() -> u32 { + $crate::RELAY_BLOCK_NUMBER.with(|v| *v.clone().borrow().get(stringify!($name)).unwrap()) + } + + 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 _process_messages() { + while Self::_has_unprocessed_messages() { + Self::_process_upward_messages(); + Self::_process_horizontal_messages(); + Self::_process_downward_messages(); + } + } + + 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()) + } + + fn _process_downward_messages() { + use $crate::{DmpMessageHandler, Bounded}; + 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()) { + $( + if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().contains(&to_para_id)) { + let mut msg_dedup: Vec<(RelayChainBlockNumber, Vec)> = Vec::new(); + for m in &messages { + msg_dedup.push((m.0, m.1.clone())); } + 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()))) + }).collect::)>>(); + if msgs.len() != 0 { + <$parachain>::handle_dmp_messages(msgs.clone().into_iter(), $crate::Weight::max_value()); + 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))); + } + } + } else { + unreachable!(); } - }, - )* - _ => unreachable!(), + )* + } } - } - } - fn _process_horizontal_messages() { - use $crate::{XcmpMessageHandler, Bounded}; + fn _process_horizontal_messages() { + use $crate::{XcmpMessageHandler, Bounded}; - while let Some((to_para_id, messages)) - = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().pop_front()) { - let iter = messages.iter().map(|(p, b, m)| (*p, *b, &m[..])).collect::>().into_iter(); - match to_para_id { - $( - $para_id => { - <$parachain>::handle_xcmp_messages(iter, $crate::Weight::max_value()); - }, - )* - _ => unreachable!(), + while let Some((to_para_id, messages)) + = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().pop_front()) { + let iter = messages.iter().map(|(p, b, m)| (*p, *b, &m[..])).collect::>().into_iter(); + $( + if $crate::PARA_IDS.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().contains(&to_para_id)) { + <$parachain>::handle_xcmp_messages(iter.clone(), $crate::Weight::max_value()); + } + )* + } } - } - } - fn _process_upward_messages() { - use $crate::{UmpSink, Bounded}; - while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().pop_front()) { - let _ = <$relay_chain>::process_upward_message( - from_para_id.into(), - &msg[..], - $crate::Weight::max_value(), - ); - } - } + fn _process_upward_messages() { + use $crate::{UmpSink, Bounded}; + while let Some((from_para_id, msg)) = $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().get_mut(stringify!($name)).unwrap().pop_front()) { + let _ = <$relay_chain>::process_upward_message( + from_para_id.into(), + &msg[..], + $crate::Weight::max_value(), + ); + } + } - pub struct _Messenger; - impl _Messenger { - fn send_downward_messages(to_para_id: u32, iter: impl Iterator)>) { - $crate::DOWNWARD_MESSAGES.with(|b| b.borrow_mut().push_back((to_para_id, iter.collect()))); - } + fn _hrmp_channel_parachain_inherent_data( + para_id: u32, + relay_parent_number: u32, + ) -> $crate::ParachainInherentData { + use $crate::cumulus_primitives_core::{relay_chain::HrmpChannelId, AbridgedHrmpChannel}; + + let mut sproof = $crate::RelayStateSproofBuilder::default(); + sproof.para_id = para_id.into(); + + // 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()) { + 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); + } - fn send_horizontal_messages< - I: Iterator)>, - >(to_para_id: u32, iter: I) { - $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().push_back((to_para_id, iter.collect()))); - } + sproof + .hrmp_channels + .entry(HrmpChannelId { + sender: sproof.para_id, + recipient: recipient_para_id, + }) + .or_insert_with(|| AbridgedHrmpChannel { + max_capacity: 1024, + max_total_size: 1024 * 1024, + max_message_size: 1024 * 1024, + msg_count: 0, + total_size: 0, + mqc_head: Option::None, + }); + } - fn send_upward_message(from_para_id: u32, msg: Vec) { - $crate::UPWARD_MESSAGES.with(|b| b.borrow_mut().push_back((from_para_id, msg))); + let (relay_storage_root, proof) = sproof.into_state_root_and_proof(); + + $crate::ParachainInherentData { + validation_data: $crate::PersistedValidationData { + parent_head: Default::default(), + relay_parent_number, + relay_parent_storage_root: relay_storage_root, + max_pov_size: Default::default(), + }, + relay_chain_state: proof, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + } + } } - } - fn _hrmp_channel_parachain_inherent_data( - para_id: u32, - relay_parent_number: u32, - ) -> $crate::ParachainInherentData { - use $crate::cumulus_primitives_core::{relay_chain::HrmpChannelId, AbridgedHrmpChannel}; - - let mut sproof = $crate::RelayStateSproofBuilder::default(); - sproof.para_id = para_id.into(); - - // egress channel - let e_index = sproof.hrmp_egress_channel_index.get_or_insert_with(Vec::new); - for recipient_para_id in &[ $( $para_id, )* ] { - 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); + $crate::__impl_relay!($name, $relay_chain); + + $( + $crate::__impl_parachain!($name, $parachain); + )* + )+ + }; +} + +#[macro_export] +macro_rules! assert_expected_events { + ( $chain:ident, vec![$( $event_pat:pat => { $($attr:ident : $condition:expr, )* }, )*] ) => { + let mut message: Vec = Vec::new(); + $( + let mut meet_conditions = true; + let mut event_message: Vec = Vec::new(); + + let event_received = <$chain>::events().iter().any(|event| { + $crate::log::debug!(target: format!("events::{}", stringify!($chain)).to_lowercase().as_str(), "{:?}", event); + + match event { + $event_pat => { + $( + if !$condition { + event_message.push(format!(" - The attribute {:?} = {:?} did not met the condition {:?}\n", stringify!($attr), $attr, stringify!($condition))); + meet_conditions &= $condition + } + )* + true + }, + _ => false } + }); - sproof - .hrmp_channels - .entry(HrmpChannelId { - sender: sproof.para_id, - recipient: recipient_para_id, - }) - .or_insert_with(|| AbridgedHrmpChannel { - max_capacity: 1024, - max_total_size: 1024 * 1024, - max_message_size: 1024 * 1024, - msg_count: 0, - total_size: 0, - mqc_head: Option::None, - }); - } - - let (relay_storage_root, proof) = sproof.into_state_root_and_proof(); - - $crate::ParachainInherentData { - validation_data: $crate::PersistedValidationData { - parent_head: Default::default(), - relay_parent_number, - relay_parent_storage_root: relay_storage_root, - max_pov_size: Default::default(), - }, - relay_chain_state: proof, - downward_messages: Default::default(), - horizontal_messages: Default::default(), + 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())); + } else if !event_received { + message.push(format!("\n\nEvent \x1b[31m{}\x1b[0m was never received", stringify!($event_pat))); } + )* + if !message.is_empty() { + panic!("{}", message.concat()) } + } + +} + +#[macro_export] +macro_rules! bx { + ($e:expr) => { + Box::new($e) }; } + +pub mod helpers { + use super::Weight; + + pub fn within_threshold(threshold: u64, expected_value: u64, current_value: u64) -> bool { + let margin = (current_value * threshold) / 100; + let lower_limit = expected_value - margin; + let upper_limit = expected_value + margin; + + current_value >= lower_limit && current_value <= upper_limit + } + + pub fn weight_within_threshold( + (threshold_time, threshold_size): (u64, u64), + expected_weight: Weight, + weight: Weight, + ) -> bool { + let ref_time_within = + within_threshold(threshold_time, expected_weight.ref_time(), weight.ref_time()); + let proof_size_within = + within_threshold(threshold_size, expected_weight.proof_size(), weight.proof_size()); + + ref_time_within && proof_size_within + } +}