referrerpolicy=no-referrer-when-downgrade

polkadot_node_clock/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Clock abstraction shared by Polkadot node subsystems.
18//!
19//! Production code uses [`SystemClock`]. Tests inject a deterministic mock so subsystems'
20//! time-dependent behavior can be driven and observed without wall-clock dependence.
21//!
22//! Subsystems that need time should accept `Arc<dyn Clock>` rather than reading
23//! `Instant::now()`, `SystemTime::now()`, `futures_timer::Delay::new(..)`, or
24//! `tokio::time::sleep(..)` directly. Consider enforcing this via a crate-level
25//! `clippy.toml` (see `polkadot-collator-protocol` for an example).
26//!
27//! Note: not every subsystem currently routes all of its time reads through this
28//! trait. In particular, `polkadot-node-core-chain-selection`,
29//! `polkadot-node-core-av-store`, and `polkadot-node-core-dispute-coordinator`
30//! presently use this trait only for their wall-clock reads and continue to call
31//! `futures_timer::Delay::new` directly for their internal timers. Those call sites
32//! need to be migrated before those subsystems can run under a deterministic test
33//! harness.
34
35#![deny(missing_docs)]
36#![deny(unused_crate_dependencies)]
37
38use std::{
39	future::Future,
40	pin::Pin,
41	sync::Arc,
42	time::{Duration, Instant, SystemTime, UNIX_EPOCH},
43};
44
45/// Boxed future returned by [`Clock::delay`].
46pub type BoxedDelay = Pin<Box<dyn Future<Output = ()> + Send>>;
47
48/// Abstraction over wall-clock time. See module-level docs.
49pub trait Clock: Send + Sync {
50	/// Monotonic timestamp suitable for measuring durations between two reads.
51	fn now(&self) -> Instant;
52
53	/// Future that resolves after `dur` has elapsed in this clock's frame.
54	fn delay(&self, dur: Duration) -> BoxedDelay;
55
56	/// Wall-clock duration since the UNIX epoch. Used for slot math and persistence
57	/// timestamps; not monotonic. Callers pick a granularity (`as_secs`, `as_millis`)
58	/// at the call site.
59	fn duration_since_epoch(&self) -> Duration;
60}
61
62/// Production clock backed by `std::time` and `futures_timer`.
63pub struct SystemClock;
64
65impl Clock for SystemClock {
66	fn now(&self) -> Instant {
67		Instant::now()
68	}
69
70	fn delay(&self, dur: Duration) -> BoxedDelay {
71		Box::pin(futures_timer::Delay::new(dur))
72	}
73
74	fn duration_since_epoch(&self) -> Duration {
75		SystemTime::now()
76			.duration_since(UNIX_EPOCH)
77			.expect("system time is before the UNIX epoch; check the system clock;")
78	}
79}
80
81/// Convenience constructor returning a thread-safe handle to a [`SystemClock`].
82pub fn system_clock() -> Arc<dyn Clock> {
83	Arc::new(SystemClock)
84}
85
86#[cfg(feature = "test")]
87pub mod mock;
88#[cfg(feature = "test")]
89pub use mock::MockClock;