diff --git a/pallets/async-backing/src/lib.rs b/pallets/async-backing/src/lib.rs index a5d77c1..fe236e6 100644 --- a/pallets/async-backing/src/lib.rs +++ b/pallets/async-backing/src/lib.rs @@ -25,8 +25,9 @@ mod tests; pub use pallet::*; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, traits::OnTimestampSet}; use sp_consensus_slots::{Slot, SlotDuration}; +use sp_runtime::SaturatedConversion; /// The InherentIdentifier for nimbus's extension inherent pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"nimb-ext"; @@ -98,7 +99,7 @@ pub mod pallet { /// Purely informative, but used by mocking tools like chospticks to allow knowing how to mock /// blocks #[pallet::constant] - type ExpectedBlockTime: Get; + type SlotDuration: Get; } /// First tuple element is the highest slot that has been seen in the history of this chain. @@ -107,4 +108,33 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn slot_info)] pub type SlotInfo = StorageValue<_, (Slot, u32), OptionQuery>; + + impl Pallet { + /// Determine the slot-duration based on the Timestamp module configuration. + pub fn slot_duration() -> T::Moment { + T::SlotDuration::get() + } + } +} + +impl OnTimestampSet for Pallet { + fn on_timestamp_set(moment: T::Moment) { + let slot_duration = Self::slot_duration(); + assert!(!slot_duration.is_zero(), "Slot duration cannot be zero."); + + let timestamp_slot = moment / slot_duration; + let timestamp_slot = Slot::from(timestamp_slot.saturated_into::()); + + let Some((current_slot, _)) = SlotInfo::::get() else { + unreachable!("`SlotInfo` should exist at this point; qed"); + }; + + assert_eq!( + current_slot, + timestamp_slot, + "`timestamp_slot` must match `current_slot`. This likely means that the configured block \ + time in the node and/or rest of the runtime is not compatible with Nimbus's Async backing \ + `SlotDuration`", + ); + } } diff --git a/pallets/async-backing/src/mock.rs b/pallets/async-backing/src/mock.rs index 1b3d4eb..c4b44ac 100644 --- a/pallets/async-backing/src/mock.rs +++ b/pallets/async-backing/src/mock.rs @@ -91,7 +91,7 @@ parameter_types! { impl async_backing::Config for Test { type AllowMultipleBlocksPerSlot = AllowMultipleBlocksPerSlot; type GetAndVerifySlot = RelaySlot; - type ExpectedBlockTime = ConstU64<1>; + type SlotDuration = ConstU64<1>; } /// Build genesis storage according to the mock runtime. diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 1e76093..cb155bc 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -357,7 +357,7 @@ parameter_types! { impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; - type OnTimestampSet = (); + type OnTimestampSet = NimbusAsyncBacking; type MinimumPeriod = MinimumPeriod; type WeightInfo = (); } @@ -667,13 +667,13 @@ impl pallet_author_slot_filter::Config for Runtime { } parameter_types! { - pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK; + pub const SlotDuration: u64 = MILLISECS_PER_BLOCK; } impl pallet_async_backing::Config for Runtime { type AllowMultipleBlocksPerSlot = ConstBool; type GetAndVerifySlot = pallet_async_backing::RelaySlot; - type ExpectedBlockTime = ExpectedBlockTime; + type SlotDuration = SlotDuration; } parameter_types! {