diff --git a/Cargo.lock b/Cargo.lock index 41204eb3813ab..9c384c5bc155b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27639,6 +27639,7 @@ dependencies = [ "log", "pallet-balances", "pallet-message-queue", + "pallet-timestamp", "parachains-common", "parity-scale-codec", "paste", diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 0474a5f709de7..52e551d6a4699 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -32,6 +32,8 @@ pallet-balances.default-features = true pallet-balances.workspace = true pallet-message-queue.default-features = true pallet-message-queue.workspace = true +pallet-timestamp.default-features = true +pallet-timestamp.workspace = true parachains-common.default-features = true parachains-common.workspace = true paste = { workspace = true, default-features = true } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 28719c8654ece..2387a935c9919 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -37,20 +37,22 @@ pub use cumulus_primitives_core::AggregateMessageOrigin as CumulusAggregateMessa pub use frame_support::{ assert_ok, sp_runtime::{ - traits::{Convert, Dispatchable, Header as HeaderT}, + traits::{Convert, Dispatchable, Header as HeaderT, Zero}, Digest, DispatchResult, }, traits::{ - EnqueueMessage, ExecuteOverweightError, Get, Hooks, OnInitialize, OriginTrait, - ProcessMessage, ProcessMessageError, ServiceQueues, + EnqueueMessage, ExecuteOverweightError, Get, Hooks, OnFinalize, OnIdle, OnInitialize, + OriginTrait, ProcessMessage, ProcessMessageError, ServiceQueues, }, weights::{Weight, WeightMeter}, }; pub use frame_system::{ - pallet_prelude::BlockNumberFor, Config as SystemConfig, Pallet as SystemPallet, + limits::BlockWeights as BlockWeightsLimits, pallet_prelude::BlockNumberFor, + Config as SystemConfig, Pallet as SystemPallet, }; pub use pallet_balances::AccountData; pub use pallet_message_queue; +pub use pallet_timestamp::Call as TimestampCall; pub use sp_arithmetic::traits::Bounded; pub use sp_core::{ crypto::get_public_from_string_or_panic, parameter_types, sr25519, storage::Storage, Pair, @@ -61,7 +63,9 @@ pub use sp_runtime::BoundedSlice; pub use sp_tracing; // Cumulus -pub use cumulus_pallet_parachain_system::Pallet as ParachainSystemPallet; +pub use cumulus_pallet_parachain_system::{ + Call as ParachainSystemCall, Pallet as ParachainSystemPallet, +}; pub use cumulus_primitives_core::{ relay_chain::{BlockNumber as RelayBlockNumber, HeadData, HrmpChannelId}, AbridgedHrmpChannel, DmpMessageHandler, ParaId, PersistedValidationData, XcmpMessageHandler, @@ -263,7 +267,7 @@ pub trait Parachain: Chain { type ParachainInfo: Get; type ParachainSystem; type MessageProcessor: ProcessMessage + ServiceQueues; - type DigestProvider: sp_runtime::traits::Convert, Digest>; + type DigestProvider: Convert, Digest>; fn init(); @@ -645,7 +649,8 @@ macro_rules! decl_test_parachains { // We run an empty block during initialisation to open HRMP channels // and have them ready for the next block fn init() { - use $crate::{Chain, HeadData, Network, Hooks, Encode, Parachain, TestExt}; + use $crate::{Chain, TestExt}; + // Initialize the thread local variable $crate::paste::paste! { [].with(|v| *v.borrow_mut() = Self::build_new_ext($genesis)); @@ -659,7 +664,9 @@ macro_rules! decl_test_parachains { } fn new_block() { - use $crate::{Chain, Convert, HeadData, Network, Hooks, Encode, Parachain, TestExt}; + use $crate::{ + Dispatchable, Chain, Convert, TestExt, Zero, + }; let para_id = Self::para_id().into(); @@ -680,24 +687,50 @@ macro_rules! decl_test_parachains { .clone() ); + // Initialze `System`. let digest = ::DigestProvider::convert(block_number); - ::System::initialize(&block_number, &parent_head_data.hash(), &digest); - <::ParachainSystem as Hooks<$crate::BlockNumberFor>>::on_initialize(block_number); - let _ = ::ParachainSystem::set_validation_data( - ::RuntimeOrigin::none(), - N::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data), + // Process `on_initialize` for all pallets except `System`. + let _ = $runtime::AllPalletsWithoutSystem::on_initialize(block_number); + + // Process parachain inherents: + + // 1. inherent: cumulus_pallet_parachain_system::Call::set_validation_data + let set_validation_data: ::RuntimeCall = $crate::ParachainSystemCall::set_validation_data { + data: N::hrmp_channel_parachain_inherent_data(para_id, relay_block_number, parent_head_data), + }.into(); + $crate::assert_ok!( + set_validation_data.dispatch(::RuntimeOrigin::none()) + ); + + // 2. inherent: pallet_timestamp::Call::set (we expect the parachain has `pallet_timestamp`) + let timestamp_set: ::RuntimeCall = $crate::TimestampCall::set { + // We need to satisfy `pallet_timestamp::on_finalize`. + now: Zero::zero(), + }.into(); + $crate::assert_ok!( + timestamp_set.dispatch(::RuntimeOrigin::none()) ); }); } fn finalize_block() { - use $crate::{Chain, Encode, Hooks, Network, Parachain, TestExt}; + use $crate::{BlockWeightsLimits, Chain, OnFinalize, OnIdle, SystemConfig, TestExt, Weight}; Self::ext_wrapper(|| { let block_number = ::System::block_number(); - ::ParachainSystem::on_finalize(block_number); + + // Process `on_idle` for all pallets. + let weight = ::System::block_weight(); + let max_weight: Weight = <<::Runtime as SystemConfig>::BlockWeights as frame_support::traits::Get>::get().max_block; + let remaining_weight = max_weight.saturating_sub(weight.total()); + if remaining_weight.all_gt(Weight::zero()) { + let _ = $runtime::AllPalletsWithSystem::on_idle(block_number, remaining_weight); + } + + // Process `on_finalize` for all pallets except `System`. + $runtime::AllPalletsWithoutSystem::on_finalize(block_number); }); Self::set_last_head(); @@ -705,7 +738,7 @@ macro_rules! decl_test_parachains { fn set_last_head() { - use $crate::{Chain, Encode, HeadData, Network, Parachain, TestExt}; + use $crate::{Chain, Encode, HeadData, TestExt}; let para_id = Self::para_id().into(); @@ -1157,7 +1190,7 @@ macro_rules! decl_test_networks { $crate::ParachainInherentData { validation_data: $crate::PersistedValidationData { - parent_head: Default::default(), + parent_head: parent_head_data.clone(), relay_parent_number, relay_parent_storage_root: relay_storage_root, max_pov_size: Default::default(), diff --git a/prdoc/pr_8170.prdoc b/prdoc/pr_8170.prdoc new file mode 100644 index 0000000000000..7cd34b8afd4a7 --- /dev/null +++ b/prdoc/pr_8170.prdoc @@ -0,0 +1,13 @@ +title: '`xcm-emulator` improved callback triggering (`on_initialize`, `on_finalize`, + `on_idle`, `OnSystemEvent`).' +doc: +- audience: Runtime Dev + description: |- + This PR fixes several issues related to `xcm-emulator`: + - Corrects parent head propagation to the `PersistedValidationData` and `OnSystemEvent` callback. + - Triggers `on_initialize` for all pallets, not just `ParachainSystem`. + - Triggers `on_finalize` for all pallets, not just `ParachainSystem`. + - Triggers `on_idle` for all parachain pallets. +crates: +- name: xcm-emulator + bump: minor