Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
102 changes: 85 additions & 17 deletions srml/timestamp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,74 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

//! Timestamp manager: provides means to find out the current time.
//! # Timestamp Module
//!
//! The timestamp module provides functionality to get and set the on-chain time.
//!
//! ## Overview
//!
//! The timestamp module allows the validators to set and validate a timestamp with each block. It uses timestamp data as an inherent which is provided by the block author and validated/verified by other validators.
//!
//! It is expected that the timestamp is set by the validator in the beginning of each block, typically one of the first extrinsics. The timestamp can be set only once per block and must be set each block.
//!
//! Note, that there could be a constraint on how much time must pass before setting the new timestamp, specified by the `tim:block_period` storage entry.
//!
//! The timestamp module is the recommended way to query the on-chain time instead of using an approach based on block numbers. The block numbers based time measurement can cause issues because of cummulative calculation errors and hence it should be avoided.
//!
//! ## Interface
//!
//! ### Types
//!
//! * `Moment` - Represents the current timestamp.
//!
//! ### Dispatchable functions
//!
//! * `set` - Sets the current time.
//!
//! Please refer to the [`Call`] enum and its associated functions for a detailed list of dispatchable functions.
//!
//! ### Public functions
//!
//! * `get` - Gets the current time for the current block. If this function is called prior the setting to timestamp, it will return the timestamp of the previous block.
//!
//! * `block_period` - Gets the block period for the chain.
//!
//! ## Usage
//!
//! The following example shows how to use the timestamp module in your custom module to query the current timestamp.
//!
//! ### Prerequisites
//!
//! Import the `timestamp` module in your custom module.
//!
//! ```ignore
//! use timestamp;
//! ```
//!
//! Derive the module configuration trait from the `timestamp` trait.
//!
//! ```ignore
//! pub trait Trait: timestamp::Trait {}
//! ```
//!
//! ### Simple getter
//!
//! In your custom module, after importing the `timestamp` module and deriving your module's configuration trait with the timestamp trait,
//! call the timestamp module's `get` function to get the current timestamp.
//!
//! ```ignore
//! let now = <timestamp::Module<T>>::get();
//! ```
//!
//! ### Example from SRML
//!
//! The [`Session` module](https://github.com/paritytech/substrate/blob/master/srml/session/src/lib.rs) uses the `timestamp` module for session management.
//!
//! ## Related Modules
//!
//! * [`System`](https://crates.parity.io/srml_system/index.html)
//! * [`Session`](https://crates.parity.io/srml_session/index.html)
//!
//! It is expected that the timestamp is set by the validator in the
//! beginning of each block, typically one of the first extrinsics. The timestamp
//! can be set only once per block and must be set each block.
//!
//! Note, that there might be a constraint on how much time must pass
//! before setting the new timestamp, specified by the `tim:block_period`
//! storage entry.
//!
//! # Interaction with the system
//!
//! ## Finalization
//!
//! This module should be hooked up to the finalization routine.

#![cfg_attr(not(feature = "std"), no_std)]

Expand Down Expand Up @@ -99,10 +152,12 @@ pub struct InherentDataProvider;

#[cfg(feature = "std")]
impl ProvideInherentData for InherentDataProvider {
/// Returns the identifier for timestamp in inherent data
fn inherent_identifier(&self) -> &'static InherentIdentifier {
&INHERENT_IDENTIFIER
}

/// Provides the current system timestamp (in seconds from epoch) as timestamp inherent data
fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), RuntimeString> {
use std::time::SystemTime;

Expand All @@ -116,6 +171,7 @@ impl ProvideInherentData for InherentDataProvider {
})
}

/// Tries to convert the `InherentError` into a string
fn error_to_string(&self, error: &[u8]) -> Option<String> {
InherentError::try_from(&INHERENT_IDENTIFIER, error).map(|e| format!("{:?}", e))
}
Expand Down Expand Up @@ -144,11 +200,13 @@ macro_rules! impl_timestamp_set {

for_each_tuple!(impl_timestamp_set);

/// The module configuration trait
pub trait Trait: system::Trait {
/// Type used for expressing timestamp.
type Moment: Parameter + Default + SimpleArithmetic
+ Mul<Self::BlockNumber, Output = Self::Moment>
+ Div<Self::BlockNumber, Output = Self::Moment>;

/// Something which can be notified when the timestamp is set. Set this to `()` if not needed.
type OnTimestampSet: OnTimestampSet<Self::Moment>;
}
Expand All @@ -157,12 +215,11 @@ decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// Set the current time.
///
/// Extrinsic with this call should be placed at the specific position in the each block
/// (specified by the Trait::TIMESTAMP_SET_POSITION) typically at the start of the each block.
/// This call should be invoked exactly once per block. It will panic at the finalization phase,
/// if this call hasn't been invoked by that time.
///
/// The timestamp should be greater than the previous one by the amount specified by `block_period`.
/// The dispatch origin for this call must be `Inherent`.
fn set(origin, #[compact] now: T::Moment) {
ensure_inherent(origin)?;
assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block");
Expand All @@ -186,6 +243,7 @@ decl_storage! {
trait Store for Module<T: Trait> as Timestamp {
/// Current time for the current block.
pub Now get(now) build(|_| T::Moment::sa(0)): T::Moment;

/// The minimum (and advised) period between blocks.
pub BlockPeriod get(block_period) config(period): T::Moment = T::Moment::sa(5);

Expand All @@ -198,7 +256,7 @@ impl<T: Trait> Module<T> {

/// Get the current time for the current block.
///
/// NOTE: if this function is called prior the setting the timestamp,
/// NOTE: if this function is called prior to setting the timestamp,
/// it will return the timestamp of the previous block.
pub fn get() -> T::Moment {
Self::now()
Expand All @@ -211,6 +269,7 @@ impl<T: Trait> Module<T> {
}
}

/// Extracts the timestamp inherent from inherent data.
fn extract_inherent_data(data: &InherentData) -> Result<InherentType, RuntimeString> {
data.get_data::<InherentType>(&INHERENT_IDENTIFIER)
.map_err(|_| RuntimeString::from("Invalid timestamp inherent data encoding."))?
Expand All @@ -222,13 +281,22 @@ impl<T: Trait> ProvideInherent for Module<T> {
type Error = InherentError;
const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;

/// Creates inherent data in storage for timestamp inherent
///
/// Extracts timestamp inherent from the inherent data
/// Finds out the max between current timestamp and `now + block period`
/// Sets the new timestamp by calling the `set` dispatchable function
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
let data = extract_inherent_data(data).expect("Gets and decodes timestamp inherent data");

let next_time = cmp::max(As::sa(data), Self::now() + Self::block_period());
Some(Call::set(next_time.into()))
}

/// Allows other validators to validate the inherent data for timestamp
///
/// Checks if the timestamp is not too far in the future
/// or too behind in the past
fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> {
const MAX_TIMESTAMP_DRIFT: u64 = 60;

Expand Down