diff --git a/Cargo.lock b/Cargo.lock index 35dc61928178..ad872e5f7c82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3299,7 +3299,7 @@ dependencies = [ [[package]] name = "coretime-rococo-emulated-chain" -version = "0.0.0" +version = "0.1.0" dependencies = [ "coretime-rococo-runtime", "cumulus-primitives-core", @@ -3312,14 +3312,17 @@ dependencies = [ [[package]] name = "coretime-rococo-integration-tests" -version = "0.1.0" +version = "0.0.0" dependencies = [ + "cumulus-pallet-parachain-system", "emulated-integration-tests-common", "frame-support", "pallet-balances", + "pallet-broker", "pallet-identity", "pallet-message-queue", "polkadot-runtime-common", + "polkadot-runtime-parachains", "rococo-runtime-constants", "rococo-system-emulated-network", "sp-runtime", @@ -3395,7 +3398,7 @@ dependencies = [ [[package]] name = "coretime-westend-emulated-chain" -version = "0.0.0" +version = "0.1.0" dependencies = [ "coretime-westend-runtime", "cumulus-primitives-core", @@ -3408,14 +3411,17 @@ dependencies = [ [[package]] name = "coretime-westend-integration-tests" -version = "0.1.0" +version = "0.0.0" dependencies = [ + "cumulus-pallet-parachain-system", "emulated-integration-tests-common", "frame-support", "pallet-balances", + "pallet-broker", "pallet-identity", "pallet-message-queue", "polkadot-runtime-common", + "polkadot-runtime-parachains", "sp-runtime", "staging-xcm", "staging-xcm-executor", diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml index 6af3f270a905..94d43c5eee2f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coretime-rococo-emulated-chain" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml index 895a984eccb2..2640c27d016b 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coretime-westend-emulated-chain" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml index 259be790c3e5..28d9da0993ff 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coretime-rococo-integration-tests" -version = "0.1.0" +version = "0.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" @@ -12,16 +12,19 @@ publish = false # Substrate frame-support = { workspace = true } pallet-balances = { workspace = true } +pallet-broker = { workspace = true, default-features = true } pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } sp-runtime = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } rococo-runtime-constants = { workspace = true, default-features = true } xcm = { workspace = true } xcm-executor = { workspace = true } # Cumulus +cumulus-pallet-parachain-system = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } rococo-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs index ad3c4fd58da9..055bd50d8298 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs @@ -24,7 +24,7 @@ mod imports { // Cumulus pub use emulated_integration_tests_common::xcm_emulator::{ - assert_expected_events, bx, TestExt, + assert_expected_events, bx, Chain, Parachain, TestExt, }; pub use rococo_system_emulated_network::{ coretime_rococo_emulated_chain::{ @@ -32,7 +32,7 @@ mod imports { CoretimeRococoParaPallet as CoretimeRococoPallet, }, CoretimeRococoPara as CoretimeRococo, CoretimeRococoParaReceiver as CoretimeRococoReceiver, - CoretimeRococoParaSender as CoretimeRococoSender, + CoretimeRococoParaSender as CoretimeRococoSender, RococoRelay as Rococo, }; } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs new file mode 100644 index 000000000000..584bce8f1df7 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs @@ -0,0 +1,235 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::imports::*; +use frame_support::traits::OnInitialize; +use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; +use rococo_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; +use sp_runtime::Perbill; + +#[test] +fn transact_hardcoded_weights_are_sane() { + // There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay + // Chain across the CoretimeInterface which are triggered at various points in the sales cycle. + // - Request core count - triggered directly by `start_sales` or `request_core_count` + // extrinsics. + // - Request revenue info - triggered when each timeslice is committed. + // - Assign core - triggered when an entry is encountered in the workplan for the next + // timeslice. + + // RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to + // + type CoretimeEvent = ::RuntimeEvent; + type RelayEvent = ::RuntimeEvent; + + // Reserve a workload, configure broker and start sales. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things + // along and have no concept of time passing otherwise. + ::Broker::on_initialize( + ::System::block_number(), + ); + + let coretime_root_origin = ::RuntimeOrigin::root(); + + // Create and populate schedule with the worst case assignment on this core. + let mut schedule = Vec::new(); + for i in 0..27 { + schedule.push(ScheduleItem { + mask: CoreMask::void().set(i), + assignment: CoreAssignment::Task(2000 + i), + }) + } + + assert_ok!(::Broker::reserve( + coretime_root_origin.clone(), + schedule.try_into().expect("Vector is within bounds."), + )); + + // Configure broker and start sales. + let config = ConfigRecord { + advance_notice: 1, + interlude_length: 1, + leadin_length: 2, + region_length: 1, + ideal_bulk_proportion: Perbill::from_percent(40), + limit_cores_offered: None, + renewal_bump: Perbill::from_percent(2), + contribution_timeout: 1, + }; + assert_ok!(::Broker::configure( + coretime_root_origin.clone(), + config + )); + assert_ok!(::Broker::start_sales( + coretime_root_origin, + 100, + 0 + )); + assert_eq!( + pallet_broker::Status::<::Runtime>::get() + .unwrap() + .core_count, + 1 + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::ReservationMade { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreCountRequested { core_count: 1 } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the request_core_count message was processed successfully. This will fail if the + // weights are misconfigured. + Rococo::execute_with(|| { + Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None); + + assert_expected_events!( + Rococo, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Keep track of the relay chain block number so we can fast forward while still checking the + // right block. + let mut block_number_cursor = Rococo::ext_wrapper(::System::block_number); + + let config = CoretimeRococo::ext_wrapper(|| { + Configuration::<::Runtime>::get() + .expect("Pallet was configured earlier.") + }); + + // Now run up to the block before the sale is rotated. + while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 { + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + }); + + Rococo::ext_wrapper(|| { + block_number_cursor = ::System::block_number(); + }); + } + + // In this block we trigger assign core. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::SaleInitialized { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreAssigned { .. } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the assign_core message was processed successfully. + // This will fail if the weights are misconfigured. + Rococo::execute_with(|| { + Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None); + + assert_expected_events!( + Rococo, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + RelayEvent::Coretime( + polkadot_runtime_parachains::coretime::Event::CoreAssigned { .. } + ) => {}, + ] + ); + }); + + // In this block we trigger request revenue. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the request_revenue_info_at message was processed successfully. + // This will fail if the weights are misconfigured. + Rococo::execute_with(|| { + Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None); + + assert_expected_events!( + Rococo, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Here we receive and process the notify_revenue XCM with zero revenue. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + // Zero revenue in first timeslice so history is immediately dropped. + CoretimeEvent::Broker( + pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 } + ) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs index 0e78351bce03..bb0387a4b350 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs @@ -14,3 +14,4 @@ // limitations under the License. mod claim_assets; +mod coretime_interface; diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml index a8fa905d2e5e..d57e7926b0ec 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coretime-westend-integration-tests" -version = "0.1.0" +version = "0.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" @@ -12,16 +12,19 @@ publish = false # Substrate frame-support = { workspace = true } pallet-balances = { workspace = true } +pallet-broker = { workspace = true, default-features = true } pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } sp-runtime = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } westend-runtime-constants = { workspace = true, default-features = true } xcm = { workspace = true } xcm-executor = { workspace = true } # Cumulus +cumulus-pallet-parachain-system = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs index 838ca6eeafb6..ac844e0f3284 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs @@ -24,7 +24,7 @@ mod imports { // Cumulus pub use emulated_integration_tests_common::xcm_emulator::{ - assert_expected_events, bx, TestExt, + assert_expected_events, bx, Chain, Parachain, TestExt, }; pub use westend_system_emulated_network::{ coretime_westend_emulated_chain::{ @@ -33,7 +33,7 @@ mod imports { }, CoretimeWestendPara as CoretimeWestend, CoretimeWestendParaReceiver as CoretimeWestendReceiver, - CoretimeWestendParaSender as CoretimeWestendSender, + CoretimeWestendParaSender as CoretimeWestendSender, WestendRelay as Westend, }; } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs new file mode 100644 index 000000000000..f61bc4285a0c --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs @@ -0,0 +1,223 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::imports::*; +use frame_support::traits::OnInitialize; +use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; +use sp_runtime::Perbill; +use westend_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; + +#[test] +fn transact_hardcoded_weights_are_sane() { + // There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay + // Chain across the CoretimeInterface which are triggered at various points in the sales cycle. + // - Request core count - triggered directly by `start_sales` or `request_core_count` + // extrinsics. + // - Request revenue info - triggered when each timeslice is committed. + // - Assign core - triggered when an entry is encountered in the workplan for the next + // timeslice. + + // RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to + // + type CoretimeEvent = ::RuntimeEvent; + type RelayEvent = ::RuntimeEvent; + + // Reserve a workload, configure broker and start sales. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things + // along and have no concept of time passing otherwise. + ::Broker::on_initialize( + ::System::block_number(), + ); + + let coretime_root_origin = ::RuntimeOrigin::root(); + + // Create and populate schedule with the worst case assignment on this core. + let mut schedule = Vec::new(); + for i in 0..27 { + schedule.push(ScheduleItem { + mask: CoreMask::void().set(i), + assignment: CoreAssignment::Task(2000 + i), + }) + } + + assert_ok!(::Broker::reserve( + coretime_root_origin.clone(), + schedule.try_into().expect("Vector is within bounds."), + )); + + // Configure broker and start sales. + let config = ConfigRecord { + advance_notice: 1, + interlude_length: 1, + leadin_length: 2, + region_length: 1, + ideal_bulk_proportion: Perbill::from_percent(40), + limit_cores_offered: None, + renewal_bump: Perbill::from_percent(2), + contribution_timeout: 1, + }; + assert_ok!(::Broker::configure( + coretime_root_origin.clone(), + config + )); + assert_ok!(::Broker::start_sales( + coretime_root_origin, + 100, + 0 + )); + assert_eq!( + pallet_broker::Status::<::Runtime>::get() + .unwrap() + .core_count, + 1 + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::ReservationMade { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreCountRequested { core_count: 1 } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the request_core_count message was processed successfully. This will fail if the + // weights are misconfigured. + Westend::execute_with(|| { + Westend::assert_ump_queue_processed(true, Some(CoretimeWestend::para_id()), None); + + assert_expected_events!( + Westend, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Keep track of the relay chain block number so we can fast forward while still checking the + // right block. + let mut block_number_cursor = Westend::ext_wrapper(::System::block_number); + + let config = CoretimeWestend::ext_wrapper(|| { + Configuration::<::Runtime>::get() + .expect("Pallet was configured earlier.") + }); + + // Now run up to the block before the sale is rotated. + while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 { + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + }); + + Westend::ext_wrapper(|| { + block_number_cursor = ::System::block_number(); + }); + } + + // In this block we trigger assign core. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::SaleInitialized { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreAssigned { .. } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // In this block we trigger request revenue. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the assign_core and request_revenue_info_at messages were processed successfully. + // This will fail if the weights are misconfigured. + Westend::execute_with(|| { + Westend::assert_ump_queue_processed(true, Some(CoretimeWestend::para_id()), None); + + assert_expected_events!( + Westend, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + RelayEvent::Coretime( + polkadot_runtime_parachains::coretime::Event::CoreAssigned { .. } + ) => {}, + ] + ); + }); + + // Here we receive and process the notify_revenue XCM with zero revenue. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + // Zero revenue in first timeslice so history is immediately dropped. + CoretimeEvent::Broker( + pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 } + ) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs index 0e78351bce03..bb0387a4b350 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs @@ -14,3 +14,4 @@ // limitations under the License. mod claim_assets; +mod coretime_interface;