referrerpolicy=no-referrer-when-downgrade

sp_timestamp/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Substrate core types and inherents for timestamps.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use codec::{Decode, Encode};
23use core::time::Duration;
24use sp_inherents::{InherentData, InherentIdentifier, IsFatalError};
25
26/// The identifier for the `timestamp` inherent.
27pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0";
28
29/// The type of the inherent.
30pub type InherentType = Timestamp;
31
32/// Unit type wrapper that represents a timestamp.
33///
34/// Such a timestamp is the time since the UNIX_EPOCH in milliseconds at a given point in time.
35#[derive(Debug, Encode, Decode, Eq, Clone, Copy, Default, Ord)]
36pub struct Timestamp(u64);
37
38impl Timestamp {
39	/// Create new `Self`.
40	pub const fn new(inner: u64) -> Self {
41		Self(inner)
42	}
43
44	/// Returns `self` as [`Duration`].
45	pub const fn as_duration(self) -> Duration {
46		Duration::from_millis(self.0)
47	}
48
49	/// Returns `self` as a `u64` representing the elapsed time since the UNIX_EPOCH in
50	/// milliseconds.
51	pub const fn as_millis(&self) -> u64 {
52		self.0
53	}
54
55	/// Checked subtraction that returns `None` on an underflow.
56	pub fn checked_sub(self, other: Self) -> Option<Self> {
57		self.0.checked_sub(other.0).map(Self)
58	}
59
60	/// The current timestamp using the system time.
61	#[cfg(feature = "std")]
62	pub fn current() -> Self {
63		use std::time::SystemTime;
64
65		let now = SystemTime::now();
66		now.duration_since(SystemTime::UNIX_EPOCH)
67			.expect("Current time is always after unix epoch; qed")
68			.into()
69	}
70}
71
72impl core::ops::Deref for Timestamp {
73	type Target = u64;
74
75	fn deref(&self) -> &Self::Target {
76		&self.0
77	}
78}
79
80impl core::ops::Add for Timestamp {
81	type Output = Self;
82
83	fn add(self, other: Self) -> Self {
84		Self(self.0 + other.0)
85	}
86}
87
88impl core::ops::Add<u64> for Timestamp {
89	type Output = Self;
90
91	fn add(self, other: u64) -> Self {
92		Self(self.0 + other)
93	}
94}
95
96impl<T: Into<u64> + Copy> core::cmp::PartialEq<T> for Timestamp {
97	fn eq(&self, eq: &T) -> bool {
98		self.0 == (*eq).into()
99	}
100}
101
102impl<T: Into<u64> + Copy> core::cmp::PartialOrd<T> for Timestamp {
103	fn partial_cmp(&self, other: &T) -> Option<core::cmp::Ordering> {
104		self.0.partial_cmp(&(*other).into())
105	}
106}
107
108#[cfg(feature = "std")]
109impl std::fmt::Display for Timestamp {
110	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111		write!(f, "{}", self.0)
112	}
113}
114
115impl From<u64> for Timestamp {
116	fn from(timestamp: u64) -> Self {
117		Timestamp(timestamp)
118	}
119}
120
121impl From<Timestamp> for u64 {
122	fn from(timestamp: Timestamp) -> u64 {
123		timestamp.0
124	}
125}
126
127impl From<Duration> for Timestamp {
128	fn from(duration: Duration) -> Self {
129		Timestamp(duration.as_millis() as u64)
130	}
131}
132
133/// Errors that can occur while checking the timestamp inherent.
134#[derive(Encode, sp_runtime::RuntimeDebug)]
135#[cfg_attr(feature = "std", derive(Decode, thiserror::Error))]
136pub enum InherentError {
137	/// The time between the blocks is too short.
138	#[cfg_attr(
139		feature = "std",
140		error("The time since the last timestamp is lower than the minimum period.")
141	)]
142	TooEarly,
143	/// The block timestamp is too far in the future.
144	#[cfg_attr(feature = "std", error("The timestamp of the block is too far in the future."))]
145	TooFarInFuture,
146}
147
148impl IsFatalError for InherentError {
149	fn is_fatal_error(&self) -> bool {
150		match self {
151			InherentError::TooEarly => true,
152			InherentError::TooFarInFuture => true,
153		}
154	}
155}
156
157impl InherentError {
158	/// Try to create an instance ouf of the given identifier and data.
159	#[cfg(feature = "std")]
160	pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option<Self> {
161		if id == &INHERENT_IDENTIFIER {
162			<InherentError as codec::Decode>::decode(&mut data).ok()
163		} else {
164			None
165		}
166	}
167}
168
169/// Auxiliary trait to extract timestamp inherent data.
170pub trait TimestampInherentData {
171	/// Get timestamp inherent data.
172	fn timestamp_inherent_data(&self) -> Result<Option<InherentType>, sp_inherents::Error>;
173}
174
175impl TimestampInherentData for InherentData {
176	fn timestamp_inherent_data(&self) -> Result<Option<InherentType>, sp_inherents::Error> {
177		self.get_data(&INHERENT_IDENTIFIER)
178	}
179}
180
181/// Provide duration since unix epoch in millisecond for timestamp inherent.
182#[cfg(feature = "std")]
183pub struct InherentDataProvider {
184	max_drift: InherentType,
185	timestamp: InherentType,
186}
187
188#[cfg(feature = "std")]
189impl InherentDataProvider {
190	/// Create `Self` while using the system time to get the timestamp.
191	pub fn from_system_time() -> Self {
192		Self {
193			max_drift: std::time::Duration::from_secs(60).into(),
194			timestamp: Timestamp::current(),
195		}
196	}
197
198	/// Create `Self` using the given `timestamp`.
199	pub fn new(timestamp: InherentType) -> Self {
200		Self { max_drift: std::time::Duration::from_secs(60).into(), timestamp }
201	}
202
203	/// With the given maximum drift.
204	///
205	/// By default the maximum drift is 60 seconds.
206	///
207	/// The maximum drift is used when checking the inherents of a runtime. If the current timestamp
208	/// plus the maximum drift is smaller than the timestamp in the block, the block will be
209	/// rejected as being too far in the future.
210	pub fn with_max_drift(mut self, max_drift: std::time::Duration) -> Self {
211		self.max_drift = max_drift.into();
212		self
213	}
214
215	/// Returns the timestamp of this inherent data provider.
216	pub fn timestamp(&self) -> InherentType {
217		self.timestamp
218	}
219}
220
221#[cfg(feature = "std")]
222impl core::ops::Deref for InherentDataProvider {
223	type Target = InherentType;
224
225	fn deref(&self) -> &Self::Target {
226		&self.timestamp
227	}
228}
229
230#[cfg(feature = "std")]
231#[async_trait::async_trait]
232impl sp_inherents::InherentDataProvider for InherentDataProvider {
233	async fn provide_inherent_data(
234		&self,
235		inherent_data: &mut InherentData,
236	) -> Result<(), sp_inherents::Error> {
237		inherent_data.put_data(INHERENT_IDENTIFIER, &self.timestamp)
238	}
239
240	async fn try_handle_error(
241		&self,
242		identifier: &InherentIdentifier,
243		error: &[u8],
244	) -> Option<Result<(), sp_inherents::Error>> {
245		Some(Err(sp_inherents::Error::Application(Box::from(InherentError::try_from(
246			identifier, error,
247		)?))))
248	}
249}