summaryrefslogtreecommitdiffstats
path: root/src/clock.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-25 23:00:56 +0100
committertv <tv@krebsco.de>2026-10-25 23:00:56 +0100
commitc52d4b5ae43c202569c8801c312c2b56954ff8a0 (patch)
treedac7221b966d9f4fdb8e1b91b1e20bce607de6fc /src/clock.rs
parent2f7265795b7f6ddf460bf93c5f880fb24bde9d3a (diff)
add clock module
The Clock module is the system clock that every unix timestamp new goes through. It comes with an offset that only tests can set.
Diffstat (limited to 'src/clock.rs')
-rw-r--r--src/clock.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/clock.rs b/src/clock.rs
new file mode 100644
index 0000000..dafd44b
--- /dev/null
+++ b/src/clock.rs
@@ -0,0 +1,53 @@
+//! Wall-clock time as this node sees it, in Unix milliseconds: commit stamps, alive
+//! stamps, remake deadlines and votes, archive and quarantine times.
+//!
+//! Every such reading goes through the node's [`Clock`], so tests can put one node's
+//! clock ahead of or behind the others (`docs/trust.md`, "What depends on clocks").
+//! Elapsed time within a node (timeouts, keepalives) uses tokio's monotonic clock and
+//! isn't affected.
+
+use std::sync::atomic::{AtomicI64, Ordering};
+
+/// The node's wall clock: the system clock plus an offset (zero outside tests).
+#[derive(Debug, Default)]
+pub(crate) struct Clock {
+ offset_ms: AtomicI64,
+}
+
+impl Clock {
+ /// Now, in Unix milliseconds.
+ pub(crate) fn now_millis(&self) -> u64 {
+ let offset = self.offset_ms.load(Ordering::Relaxed);
+ system_millis().saturating_add_signed(offset)
+ }
+
+ /// Puts this clock `offset_ms` ahead of the system clock (behind if negative).
+ #[cfg(test)]
+ pub(crate) fn set_offset_ms(&self, offset_ms: i64) {
+ self.offset_ms.store(offset_ms, Ordering::Relaxed);
+ }
+}
+
+/// The system clock, in Unix milliseconds; 0 if it is before 1970.
+fn system_millis() -> u64 {
+ std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .map(|d| d.as_millis() as u64)
+ .unwrap_or(0)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn offset_moves_the_clock() {
+ let clock = Clock::default();
+ let before = clock.now_millis();
+ clock.set_offset_ms(3_600_000);
+ let ahead = clock.now_millis();
+ assert!(ahead >= before + 3_600_000);
+ clock.set_offset_ms(-3_600_000);
+ assert!(clock.now_millis() < before);
+ }
+}