diff --git a/prdoc/pr_9756.prdoc b/prdoc/pr_9756.prdoc new file mode 100644 index 0000000000000..b378a0fcf0775 --- /dev/null +++ b/prdoc/pr_9756.prdoc @@ -0,0 +1,19 @@ +title: 'FRAME: Register `on_initialize` after each pallet' +doc: +- audience: Runtime Dev + description: |- + Before this pull request, FRAME was executing all pallets `on_initialize` and then register the weight, including the weight of `on_runtime_upgrade`. Thus, other pallets were not aware on how much weight was already used when they were executing their `on_initialize` code. As some pallets are doing some work in `on_initialize`, they need to be aware of how much weight is still left. + To register the weight after each `on_initialize` call, a new trait is added. This new trait is implemented for tuples of types that implement `OnInitialize` and then it registers the weight after each call to `on_initialize`. + + `pallet-scheduler` is changed to take the remaining weight into account and to not just assume that its configured weight is always available. +crates: +- name: frame-support + bump: patch +- name: frame-executive + bump: patch +- name: pallet-scheduler + bump: patch +- name: frame-system + bump: patch +- name: sp-weights + bump: patch diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index ac25bd573c3eb..d1f0667d98ff0 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -161,8 +161,9 @@ use frame_support::{ migrations::MultiStepMigrator, pallet_prelude::InvalidTransaction, traits::{ - BeforeAllRuntimeMigrations, ExecuteBlock, IsInherent, OffchainWorker, OnFinalize, OnIdle, - OnInitialize, OnPoll, OnRuntimeUpgrade, PostInherents, PostTransactions, PreInherents, + BeforeAllRuntimeMigrations, ExecuteBlock, Get, IsInherent, OffchainWorker, OnFinalize, + OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, PostInherents, PostTransactions, + PreInherents, }, weights::{Weight, WeightMeter}, MAX_EXTRINSIC_DEPTH, @@ -260,7 +261,7 @@ impl< UnsignedValidator, AllPalletsWithSystem: OnRuntimeUpgrade + BeforeAllRuntimeMigrations - + OnInitialize> + + OnInitializeWithWeightRegistration + OnIdle> + OnFinalize> + OffchainWorker> @@ -299,7 +300,7 @@ impl< UnsignedValidator, AllPalletsWithSystem: OnRuntimeUpgrade + BeforeAllRuntimeMigrations - + OnInitialize> + + OnInitializeWithWeightRegistration + OnIdle> + OnFinalize> + OffchainWorker> @@ -493,6 +494,38 @@ where } } +/// Extension trait for [`OnInitialize`]. +/// +/// It takes care to register the weight of each pallet directly after executing its +/// `on_initialize`. +/// +/// The trait is sealed. +pub trait OnInitializeWithWeightRegistration { + /// The actual logic that calls `on_initialize` and registers the weight. + fn on_initialize_with_weight_registration(_n: BlockNumberFor) -> Weight; +} + +frame_support::impl_for_tuples_attr! { + #[tuple_types_custom_trait_bound(OnInitialize>)] + impl OnInitializeWithWeightRegistration for Tuple { + fn on_initialize_with_weight_registration(n: BlockNumberFor) -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( + let individual_weight = Tuple::on_initialize(n); + + >::register_extra_weight_unchecked( + individual_weight, + DispatchClass::Mandatory, + ); + + weight = weight.saturating_add(individual_weight); + )* ); + + weight + } + } +} + impl< System: frame_system::Config + IsInherent, Block: traits::Block< @@ -503,7 +536,7 @@ impl< UnsignedValidator, AllPalletsWithSystem: OnRuntimeUpgrade + BeforeAllRuntimeMigrations - + OnInitialize> + + OnInitializeWithWeightRegistration + OnIdle> + OnFinalize> + OffchainWorker> @@ -571,7 +604,7 @@ where ) { // Reset events before apply runtime upgrade hook. // This is required to preserve events from runtime upgrade hook. - // This means the format of all the event related storages must always be compatible. + // This means the format of all the event related storage must always be compatible. >::reset_events(); let mut weight = Weight::zero(); @@ -585,17 +618,24 @@ where ); } >::initialize(block_number, parent_hash, digest); - weight = weight.saturating_add(, - >>::on_initialize(*block_number)); - weight = weight.saturating_add( - >::get().base_block, - ); + + weight = System::BlockWeights::get().base_block.saturating_add(weight); + // Register the base block weight and optional `on_runtime_upgrade` weight. >::register_extra_weight_unchecked( weight, DispatchClass::Mandatory, ); + weight = weight + .saturating_add(>::on_initialize_with_weight_registration(*block_number)); + + log::debug!( + target: LOG_TARGET, + "[{block_number:?}]: Block initialization weight consumption: {weight:?}", + ); + frame_system::Pallet::::note_finished_initialize(); ::PreInherents::pre_inherents(); } diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 94d675581d636..83b1b0d96c743 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -432,7 +432,8 @@ pub mod pallet { /// Execute the scheduled calls fn on_initialize(_now: SystemBlockNumberFor) -> Weight { let now = T::BlockNumberProvider::current_block_number(); - let mut weight_counter = WeightMeter::with_limit(T::MaximumWeight::get()); + let mut weight_counter = frame_system::Pallet::::remaining_block_weight() + .limit_to(T::MaximumWeight::get()); Self::service_agendas(&mut weight_counter, now, u32::MAX); weight_counter.consumed() } diff --git a/substrate/frame/scheduler/src/mock.rs b/substrate/frame/scheduler/src/mock.rs index 42c6529025cb7..cf51b3182ec05 100644 --- a/substrate/frame/scheduler/src/mock.rs +++ b/substrate/frame/scheduler/src/mock.rs @@ -26,6 +26,7 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_runtime::{BuildStorage, Perbill}; +use sp_weights::constants::WEIGHT_REF_TIME_PER_SECOND; // Logger module to track execution. #[frame_support::pallet] @@ -134,7 +135,7 @@ impl Contains for BaseFilter { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - Weight::from_parts(2_000_000_000_000, u64::MAX), + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND * 2, u64::MAX), ); } @@ -142,6 +143,7 @@ parameter_types! { impl system::Config for Test { type BaseCallFilter = BaseFilter; type Block = Block; + type BlockWeights = BlockWeights; } impl logger::Config for Test { type RuntimeEvent = RuntimeEvent; diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index f8061a6ce61f2..4a22b952f81be 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -1639,7 +1639,7 @@ fn on_initialize_weight_is_correct() { let now = 1; ::BlockNumberProvider::set_block_number(now); assert_eq!( - Scheduler::on_initialize(42), // BN unused + Scheduler::on_initialize(42), // block number unused TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(1) + ::service_task(None, true, true) + @@ -1653,7 +1653,7 @@ fn on_initialize_weight_is_correct() { let now = 2; ::BlockNumberProvider::set_block_number(now); assert_eq!( - Scheduler::on_initialize(123), // BN unused + Scheduler::on_initialize(123), // block number unused TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(2) + ::service_task(None, false, true) + @@ -1670,7 +1670,7 @@ fn on_initialize_weight_is_correct() { let now = 3; ::BlockNumberProvider::set_block_number(now); assert_eq!( - Scheduler::on_initialize(555), // BN unused + Scheduler::on_initialize(555), // block number unused TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(1) + ::service_task(None, true, false) + @@ -1686,12 +1686,20 @@ fn on_initialize_weight_is_correct() { // Will contain none let now = 4; ::BlockNumberProvider::set_block_number(now); - let actual_weight = Scheduler::on_initialize(444); // BN unused + let actual_weight = Scheduler::on_initialize(444); // block number unused assert_eq!( actual_weight, TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0) ); assert_eq!(IncompleteSince::::get(), Some(now + 1)); + + frame_system::Pallet::::register_extra_weight_unchecked( + BlockWeights::get().max_block, + frame_support::dispatch::DispatchClass::Mandatory, + ); + + let actual_weight = Scheduler::on_initialize(444); // block number unused + assert!(actual_weight.is_zero()); }); } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 7e79f7a2dfa2e..1921383ad290c 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -54,6 +54,7 @@ pub mod __private { }; pub use codec; pub use frame_metadata as metadata; + pub use impl_trait_for_tuples; pub use log; pub use paste; pub use scale_info; @@ -878,6 +879,108 @@ macro_rules! hypothetically_ok { }; } +/// Puts the [`impl_for_tuples`](impl_trait_for_tuples::impl_for_tuples) attribute above the given +/// code. +/// +/// The main purpose of this macro is to handle the `tuples-*` feature which informs the attribute +/// about the maximum size of the tuple to generate. Besides that, there is no difference to use the +/// attribute directly. +/// +/// # Example +/// +/// ```rust +/// trait ILoveTuples { +/// fn really_hard(); +/// } +/// +/// frame_support::impl_for_tuples_attr! { +/// impl ILoveTuples for Tuple { +/// fn really_hard() { +/// for_tuples! { #( +/// // Print it for each tuple +/// println!("I LOVE TUPLES"); +/// )* } +/// } +/// } +/// } +/// ``` +#[cfg(all(not(feature = "tuples-96"), not(feature = "tuples-128")))] +#[macro_export] +macro_rules! impl_for_tuples_attr { + ( $( $input:tt )* ) => { + #[$crate::__private::impl_trait_for_tuples::impl_for_tuples(64)] + $( $input )* + } +} + +/// Puts the [`impl_for_tuples`](impl_trait_for_tuples::impl_for_tuples) attribute above the given +/// code. +/// +/// The main purpose of this macro is to handle the `tuples-*` feature which informs the attribute +/// about the maximum size of the tuple to generate. Besides that, there is no difference to use the +/// attribute directly. +/// +/// # Example +/// +/// ```rust +/// trait ILoveTuples { +/// fn really_hard(); +/// } +/// +/// frame_support::impl_for_tuples_attr! { +/// impl ILoveTuples for Tuple { +/// fn really_hard() { +/// for_tuples! { #( +/// // Print it for each tuple +/// println!("I LOVE TUPLES"); +/// )* } +/// } +/// } +/// } +/// ``` +#[cfg(all(feature = "tuples-96", not(feature = "tuples-128")))] +#[macro_export] +macro_rules! impl_for_tuples_attr { + ( $( $input:tt )* ) => { + #[$crate::__private::impl_trait_for_tuples::impl_for_tuples(96)] + $( $input )* + } +} + +/// Puts the [`impl_for_tuples`](impl_trait_for_tuples::impl_for_tuples) attribute above the given +/// code. +/// +/// The main purpose of this macro is to handle the `tuples-*` feature which informs the attribute +/// about the maximum size of the tuple to generate. Besides that, there is no difference to use the +/// attribute directly. +/// +/// # Example +/// +/// ```rust +/// trait ILoveTuples { +/// fn really_hard(); +/// } +/// +/// frame_support::impl_for_tuples_attr! { +/// impl ILoveTuples for Tuple { +/// fn really_hard() { +/// for_tuples! { #( +/// // Print it for each tuple +/// println!("I LOVE TUPLES"); +/// )* } +/// } +/// } +/// } +/// ``` +#[cfg(feature = "tuples-128")] +#[macro_export] +macro_rules! impl_for_tuples_attr { + ( $( $input:tt )* ) => { + #[$crate::__private::impl_trait_for_tuples::impl_for_tuples(128)] + $( $input )* + } +} + #[doc(hidden)] pub use serde::{Deserialize, Serialize}; diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index bf54f237eb707..f7404ca7dbe85 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -21,8 +21,7 @@ #![deny(missing_docs)] -use crate::weights::Weight; -use impl_trait_for_tuples::impl_for_tuples; +use crate::{impl_for_tuples_attr, weights::Weight}; use sp_runtime::traits::AtLeast32BitUnsigned; use sp_weights::WeightMeter; @@ -37,12 +36,11 @@ pub trait PreInherents { fn pre_inherents() {} } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl PreInherents for Tuple { - fn pre_inherents() { - for_tuples!( #( Tuple::pre_inherents(); )* ); +impl_for_tuples_attr! { + impl PreInherents for Tuple { + fn pre_inherents() { + for_tuples!( #( Tuple::pre_inherents(); )* ); + } } } @@ -52,12 +50,11 @@ pub trait PostInherents { fn post_inherents() {} } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl PostInherents for Tuple { - fn post_inherents() { - for_tuples!( #( Tuple::post_inherents(); )* ); +impl_for_tuples_attr! { + impl PostInherents for Tuple { + fn post_inherents() { + for_tuples!( #( Tuple::post_inherents(); )* ); + } } } @@ -67,12 +64,11 @@ pub trait PostTransactions { fn post_transactions() {} } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl PostTransactions for Tuple { - fn post_transactions() { - for_tuples!( #( Tuple::post_transactions(); )* ); +impl_for_tuples_attr! { + impl PostTransactions for Tuple { + fn post_transactions() { + for_tuples!( #( Tuple::post_transactions(); )* ); + } } } @@ -85,12 +81,11 @@ pub trait OnPoll { fn on_poll(_n: BlockNumber, _weight: &mut WeightMeter) {} } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl OnPoll for Tuple { - fn on_poll(n: BlockNumber, weight: &mut WeightMeter) { - for_tuples!( #( Tuple::on_poll(n.clone(), weight); )* ); +impl_for_tuples_attr! { + impl OnPoll for Tuple { + fn on_poll(n: BlockNumber, weight: &mut WeightMeter) { + for_tuples!( #( Tuple::on_poll(n.clone(), weight); )* ); + } } } @@ -102,24 +97,22 @@ pub trait OnInitialize { } } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl OnInitialize for Tuple { - fn on_initialize(n: BlockNumber) -> Weight { - let mut weight = Weight::zero(); - for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(n.clone())); )* ); - weight +impl_for_tuples_attr! { + impl OnInitialize for Tuple { + fn on_initialize(n: BlockNumber) -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(n.clone())); )* ); + weight + } } } -/// See [`Hooks::on_finalize`]. -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -pub trait OnFinalize { +impl_for_tuples_attr! { /// See [`Hooks::on_finalize`]. - fn on_finalize(_n: BlockNumber) {} + pub trait OnFinalize { + /// See [`Hooks::on_finalize`]. + fn on_finalize(_n: BlockNumber) {} + } } /// See [`Hooks::on_idle`]. @@ -130,38 +123,36 @@ pub trait OnIdle { } } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl OnIdle for Tuple { - fn on_idle(n: BlockNumber, remaining_weight: Weight) -> Weight { - let on_idle_functions: &[fn(BlockNumber, Weight) -> Weight] = - &[for_tuples!( #( Tuple::on_idle ),* )]; - let mut weight = Weight::zero(); - let len = on_idle_functions.len(); - let start_index = n % (len as u32).into(); - let start_index = start_index.try_into().ok().expect( - "`start_index % len` always fits into `usize`, because `len` can be in maximum `usize::MAX`; qed" - ); - for on_idle_fn in on_idle_functions.iter().cycle().skip(start_index).take(len) { - let adjusted_remaining_weight = remaining_weight.saturating_sub(weight); - weight = weight.saturating_add(on_idle_fn(n, adjusted_remaining_weight)); +impl_for_tuples_attr! { + impl OnIdle for Tuple { + fn on_idle(n: BlockNumber, remaining_weight: Weight) -> Weight { + let on_idle_functions: &[fn(BlockNumber, Weight) -> Weight] = + &[for_tuples!( #( Tuple::on_idle ),* )]; + let mut weight = Weight::zero(); + let len = on_idle_functions.len(); + let start_index = n % (len as u32).into(); + let start_index = start_index.try_into().ok().expect( + "`start_index % len` always fits into `usize`, because `len` can be in maximum `usize::MAX`; qed" + ); + for on_idle_fn in on_idle_functions.iter().cycle().skip(start_index).take(len) { + let adjusted_remaining_weight = remaining_weight.saturating_sub(weight); + weight = weight.saturating_add(on_idle_fn(n, adjusted_remaining_weight)); + } + weight } - weight } } -/// A trait that will be called at genesis. -/// -/// Implementing this trait for a pallet let's you express operations that should -/// happen at genesis. It will be called in an externalities provided environment and -/// will set the genesis state after all pallets have written their genesis state. -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -pub trait OnGenesis { - /// Something that should happen at genesis. - fn on_genesis() {} +impl_for_tuples_attr! { + /// A trait that will be called at genesis. + /// + /// Implementing this trait for a pallet let's you express operations that should + /// happen at genesis. It will be called in an externalities provided environment and + /// will set the genesis state after all pallets have written their genesis state. + pub trait OnGenesis { + /// Something that should happen at genesis. + fn on_genesis() {} + } } /// Implemented by pallets, allows defining logic to run prior to any [`OnRuntimeUpgrade`] logic. @@ -252,95 +243,92 @@ pub trait UncheckedOnRuntimeUpgrade { } } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl BeforeAllRuntimeMigrations for Tuple { - /// Implements the default behavior of - /// [`BeforeAllRuntimeMigrations::before_all_runtime_migrations`] for tuples. - fn before_all_runtime_migrations() -> Weight { - let mut weight = Weight::zero(); - for_tuples!( #( weight = weight.saturating_add(Tuple::before_all_runtime_migrations()); )* ); - weight +impl_for_tuples_attr! { + impl BeforeAllRuntimeMigrations for Tuple { + /// Implements the default behavior of + /// [`BeforeAllRuntimeMigrations::before_all_runtime_migrations`] for tuples. + fn before_all_runtime_migrations() -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( weight = weight.saturating_add(Tuple::before_all_runtime_migrations()); )* ); + weight + } } } -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -impl OnRuntimeUpgrade for Tuple { - /// Implements the default behavior of [`OnRuntimeUpgrade::on_runtime_upgrade`] for tuples. - fn on_runtime_upgrade() -> Weight { - let mut weight = Weight::zero(); - for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); - weight - } +impl_for_tuples_attr! { + impl OnRuntimeUpgrade for Tuple { + /// Implements the default behavior of [`OnRuntimeUpgrade::on_runtime_upgrade`] for tuples. + fn on_runtime_upgrade() -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); + weight + } - /// Implements the default behavior of `try_on_runtime_upgrade` for tuples, logging any errors - /// that occur. - #[cfg(feature = "try-runtime")] - fn try_on_runtime_upgrade(checks: bool) -> Result { - let mut cumulative_weight = Weight::zero(); + /// Implements the default behavior of `try_on_runtime_upgrade` for tuples, logging any errors + /// that occur. + #[cfg(feature = "try-runtime")] + fn try_on_runtime_upgrade(checks: bool) -> Result { + let mut cumulative_weight = Weight::zero(); - let mut errors = Vec::new(); + let mut errors = Vec::new(); - for_tuples!(#( - match Tuple::try_on_runtime_upgrade(checks) { - Ok(weight) => { cumulative_weight.saturating_accrue(weight); }, - Err(err) => { errors.push(err); }, - } - )*); - - if errors.len() == 1 { - return Err(errors[0]) - } else if !errors.is_empty() { - log::error!( - target: "try-runtime", - "Detected multiple errors while executing `try_on_runtime_upgrade`:", - ); + for_tuples!(#( + match Tuple::try_on_runtime_upgrade(checks) { + Ok(weight) => { cumulative_weight.saturating_accrue(weight); }, + Err(err) => { errors.push(err); }, + } + )*); - errors.iter().for_each(|err| { + if errors.len() == 1 { + return Err(errors[0]) + } else if !errors.is_empty() { log::error!( target: "try-runtime", - "{:?}", - err + "Detected multiple errors while executing `try_on_runtime_upgrade`:", ); - }); - return Err("Detected multiple errors while executing `try_on_runtime_upgrade`, check the logs!".into()) - } + errors.iter().for_each(|err| { + log::error!( + target: "try-runtime", + "{:?}", + err + ); + }); - Ok(cumulative_weight) - } + return Err("Detected multiple errors while executing `try_on_runtime_upgrade`, check the logs!".into()) + } - /// [`OnRuntimeUpgrade::pre_upgrade`] should not be used on a tuple. - /// - /// Instead, implementors should use [`OnRuntimeUpgrade::try_on_runtime_upgrade`] which - /// internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple - /// member in sequence, enabling testing of order-dependent migrations. - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - Err("Usage of `pre_upgrade` with Tuples is not expected. Please use `try_on_runtime_upgrade` instead, which internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple member.".into()) - } + Ok(cumulative_weight) + } - /// [`OnRuntimeUpgrade::post_upgrade`] should not be used on a tuple. - /// - /// Instead, implementors should use [`OnRuntimeUpgrade::try_on_runtime_upgrade`] which - /// internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple - /// member in sequence, enabling testing of order-dependent migrations. - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { - Err("Usage of `post_upgrade` with Tuples is not expected. Please use `try_on_runtime_upgrade` instead, which internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple member.".into()) + /// [`OnRuntimeUpgrade::pre_upgrade`] should not be used on a tuple. + /// + /// Instead, implementors should use [`OnRuntimeUpgrade::try_on_runtime_upgrade`] which + /// internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple + /// member in sequence, enabling testing of order-dependent migrations. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Err("Usage of `pre_upgrade` with Tuples is not expected. Please use `try_on_runtime_upgrade` instead, which internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple member.".into()) + } + + /// [`OnRuntimeUpgrade::post_upgrade`] should not be used on a tuple. + /// + /// Instead, implementors should use [`OnRuntimeUpgrade::try_on_runtime_upgrade`] which + /// internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple + /// member in sequence, enabling testing of order-dependent migrations. + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + Err("Usage of `post_upgrade` with Tuples is not expected. Please use `try_on_runtime_upgrade` instead, which internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple member.".into()) + } } } -/// See [`Hooks::integrity_test`]. -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -pub trait IntegrityTest { +impl_for_tuples_attr! { /// See [`Hooks::integrity_test`]. - fn integrity_test() {} + pub trait IntegrityTest { + /// See [`Hooks::integrity_test`]. + fn integrity_test() {} + } } #[cfg_attr(doc, aquamarine::aquamarine)] @@ -616,13 +604,12 @@ pub trait GenesisBuild: sp_runtime::traits::MaybeSerializeDeserialize } } -/// A trait which is called when the timestamp is set in the runtime. -#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] -#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] -#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] -pub trait OnTimestampSet { - /// Called when the timestamp is set. - fn on_timestamp_set(moment: Moment); +impl_for_tuples_attr! { + /// A trait which is called when the timestamp is set in the runtime. + pub trait OnTimestampSet { + /// Called when the timestamp is set. + fn on_timestamp_set(moment: Moment); + } } #[cfg(test)] diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 39596fcdac520..00beed3ffb87e 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -307,7 +307,7 @@ impl core::fmt::Debug for CheckWeight { mod tests { use super::*; use crate::{ - mock::{new_test_ext, System, Test, CALL}, + mock::{new_test_ext, RuntimeBlockWeights, System, Test, CALL}, AllExtrinsicsLen, BlockWeight, DispatchClass, }; use core::marker::PhantomData; @@ -808,9 +808,11 @@ mod tests { .unwrap() .0; + let expected = info.total_weight() + prior_block_weight + base_extrinsic; + assert_eq!(expected, BlockWeight::::get().total()); assert_eq!( - BlockWeight::::get().total(), - info.total_weight() + prior_block_weight + base_extrinsic + RuntimeBlockWeights::get().max_block - expected, + System::remaining_block_weight().remaining() ); // Refund less accurately than the benchmark @@ -833,9 +835,11 @@ mod tests { crate::ExtrinsicWeightReclaimed::::get(), post_info.calc_unspent(&info) ); + let expected = post_info.actual_weight.unwrap() + prior_block_weight + base_extrinsic; + assert_eq!(expected, BlockWeight::::get().total()); assert_eq!( - BlockWeight::::get().total(), - post_info.actual_weight.unwrap() + prior_block_weight + base_extrinsic + RuntimeBlockWeights::get().max_block - expected, + System::remaining_block_weight().remaining() ); }) } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 21e2d77367906..6202a4543a88e 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -148,7 +148,7 @@ use sp_runtime::{ traits::{DispatchInfoOf, PostDispatchInfoOf}, transaction_validity::TransactionValidityError, }; -use sp_weights::{RuntimeDbWeight, Weight}; +use sp_weights::{RuntimeDbWeight, Weight, WeightMeter}; #[cfg(any(feature = "std", test))] use sp_io::TestExternalities; @@ -2386,6 +2386,14 @@ impl Pallet { Ok(()) } + + /// Returns the remaining weight of the block. + pub fn remaining_block_weight() -> WeightMeter { + let limit = T::BlockWeights::get().max_block; + let consumed = BlockWeight::::get().total(); + + WeightMeter::with_consumed_and_limit(consumed, limit) + } } /// Returns a 32 byte datum which is guaranteed to be universally unique. `entropy` is provided diff --git a/substrate/primitives/weights/src/weight_meter.rs b/substrate/primitives/weights/src/weight_meter.rs index cfe8396ae6d67..5e6d65ea545f3 100644 --- a/substrate/primitives/weights/src/weight_meter.rs +++ b/substrate/primitives/weights/src/weight_meter.rs @@ -50,6 +50,11 @@ pub struct WeightMeter { } impl WeightMeter { + /// Creates [`Self`] from `consumed` and `limit`. + pub fn with_consumed_and_limit(consumed: Weight, limit: Weight) -> Self { + Self { consumed, limit } + } + /// Creates [`Self`] from a limit for the maximal consumable weight. pub fn with_limit(limit: Weight) -> Self { Self { consumed: Weight::zero(), limit } @@ -60,6 +65,13 @@ impl WeightMeter { Self::with_limit(Weight::MAX) } + /// Change the limit to the given `weight`. + /// + /// The actual weight will be determined by `min(weight, self.remaining())`. + pub fn limit_to(self, weight: Weight) -> Self { + Self::with_limit(self.remaining().min(weight)) + } + /// The already consumed weight. pub fn consumed(&self) -> Weight { self.consumed