Crate pallet_timestamp

source ·
Expand description

Made with Substrate, for Polkadot.

github polkadot

§Timestamp Pallet

A pallet that provides a way for consensus systems to set and check the onchain time.

§Pallet API

See the pallet module for more information about the interfaces this pallet exposes, including its configuration trait, dispatchables, storage items, events and errors.

§Overview

The Timestamp pallet is designed to create a consensus-based time source. This helps ensure that nodes maintain a synchronized view of time that all network participants can agree on.

It defines an acceptable range using a configurable constant to specify how much time must pass before setting the new timestamp. Validator nodes in the network must verify that the timestamp falls within this acceptable range and reject blocks that do not.

Note: The timestamp set by this pallet is the recommended way to query the onchain time instead of using block numbers alone. Measuring time with block numbers can cause cumulative calculation errors if depended upon in time critical operations and hence should generally be avoided.

§Example

To get the current time for the current block in another pallet:

use pallet_timestamp::{self as timestamp};

#[frame_support::pallet]
pub mod pallet {
	use super::*;
	use frame_support::pallet_prelude::*;
	use frame_system::pallet_prelude::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config + timestamp::Config {}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		#[pallet::weight(0)]
		pub fn get_time(origin: OriginFor<T>) -> DispatchResult {
			let _sender = ensure_signed(origin)?;
			let _now = timestamp::Pallet::<T>::get();
			Ok(())
		}
	}
}

If Pallet::get is called prior to setting the timestamp, it will return the timestamp of the previous block.

§Low Level / Implementation Details

A timestamp is added to the chain using an inherent extrinsic that only a block author can submit. Inherents are a special type of extrinsic in Substrate chains that will always be included in a block.

To provide inherent data to the runtime, this pallet implements ProvideInherent. It will only create an inherent if the Call::set dispatchable is called, using the inherent macro which enables validator nodes to call into the runtime to check that the timestamp provided is valid. The implementation of ProvideInherent specifies a constant called MAX_TIMESTAMP_DRIFT_MILLIS which is used to determine the acceptable range for a valid timestamp. If a block author sets a timestamp to anything that is more than this constant, a validator node will reject the block.

The pallet also ensures that a timestamp is set at the start of each block by running an assertion in the on_finalize runtime hook. See frame_support::traits::Hooks for more information about how hooks work.

Because inherents are applied to a block in the order they appear in the runtime construction, the index of this pallet in construct_runtime must always be less than any other pallet that depends on it.

The Config::OnTimestampSet configuration trait can be set to another pallet we want to notify that the timestamp has been updated, as long as it implements OnTimestampSet. Examples are the Babe and Aura pallets. This pallet also implements Time and UnixTime so it can be used to configure other pallets that require these types (e.g. in Staking pallet).

§Panics

There are 3 cases where this pallet could cause the runtime to panic.

  1. If no timestamp is set at the end of a block.

  2. If a timestamp is set more than once per block:

#[test]
#[should_panic(expected = "Timestamp must be updated only once in the block")]
fn double_timestamp_should_fail() {
	new_test_ext().execute_with(|| {
		Timestamp::set_timestamp(42);
		assert_ok!(Timestamp::set(RuntimeOrigin::none(), 69));
	});
}
  1. If a timestamp is set before the Config::MinimumPeriod is elapsed:
#[test]
#[should_panic(
	expected = "Timestamp must increment by at least <MinimumPeriod> between sequential blocks"
)]
fn block_period_minimum_enforced() {
	new_test_ext().execute_with(|| {
		crate::Now::<Test>::put(44);
		let _ = Timestamp::set(RuntimeOrigin::none(), 46);
	});
}

Re-exports§

Modules§

  • The pallet module in each FRAME pallet hosts the most important items needed to construct this pallet.
  • Autogenerated weights for pallet_timestamp