eigen_trust/
epoch.rs

1//! The module for epoch related calculatioins, like:
2//! - Creating an epoch struct
3//! - Seconds until next epoch
4//! - Current epoch
5//! - Current timestamp
6
7use std::{
8	fmt::{Display, Formatter, Result as FmtResult},
9	time::{SystemTime, UNIX_EPOCH},
10};
11
12use crate::EigenError;
13
14/// Epoch struct, which is a wrapper around epoch number and timestamp.
15// TODO: add epoch_number and timestamp as private fields
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
17pub struct Epoch(pub u64);
18
19impl Display for Epoch {
20	fn fmt(&self, f: &mut Formatter) -> FmtResult {
21		write!(f, "Epoch({})", self.0)
22	}
23}
24
25impl Epoch {
26	/// Returns epoch number as bytes.
27	pub fn to_be_bytes(self) -> [u8; 8] {
28		self.0.to_be_bytes()
29	}
30
31	/// Calculates the current epoch number based on the interval duration.
32	pub fn current_epoch(interval: u64) -> Result<Self, EigenError> {
33		let unix_timestamp = SystemTime::now()
34			.duration_since(UNIX_EPOCH)
35			.map_err(|_| EigenError::EpochError)?;
36
37		let current_epoch = unix_timestamp.as_secs() / interval;
38
39		Ok(Epoch(current_epoch))
40	}
41
42	/// Calculates the seconds until the next epoch based on the interval
43	/// duration.
44	pub fn secs_until_next_epoch(interval: u64) -> Result<u64, EigenError> {
45		let unix_timestamp = SystemTime::now()
46			.duration_since(UNIX_EPOCH)
47			.map_err(|_| EigenError::EpochError)?;
48
49		let current_epoch = unix_timestamp.as_secs() / interval;
50		let secs_until_next_epoch = (current_epoch + 1) * interval - unix_timestamp.as_secs();
51
52		Ok(secs_until_next_epoch)
53	}
54
55	/// Calculates the current timestamp. The difference between UNIX timestamp
56	/// start and now.
57	pub fn current_timestamp() -> Result<u64, EigenError> {
58		let unix_timestamp = SystemTime::now()
59			.duration_since(UNIX_EPOCH)
60			.map_err(|_| EigenError::EpochError)?;
61
62		Ok(unix_timestamp.as_secs())
63	}
64
65	/// Returns previous epoch.
66	pub fn previous(&self) -> Self {
67		Epoch(self.0 - 1)
68	}
69
70	/// Returns next epoch.
71	pub fn next(&self) -> Self {
72		Epoch(self.0 + 1)
73	}
74}
75
76#[cfg(test)]
77mod tests {
78	use super::*;
79
80	#[test]
81	fn test_display() {
82		let epoch = format!("{}", Epoch(123));
83		assert_eq!(epoch, "Epoch(123)");
84	}
85
86	#[test]
87	fn test_current_epoch() {
88		let epoch = Epoch(1);
89		assert_eq!(epoch.next(), Epoch(2));
90		assert_eq!(epoch.previous(), Epoch(0));
91	}
92
93	#[test]
94	fn test_epoch_to_be_bytes() {
95		let epoch = Epoch(0);
96		let expected = [0, 0, 0, 0, 0, 0, 0, 0];
97		let actual = epoch.to_be_bytes();
98		assert_eq!(expected, actual);
99	}
100
101	#[test]
102	fn test_epoch_current_epoch() {
103		let interval = 10;
104		let epoch = Epoch::current_epoch(interval).unwrap();
105
106		let unix_timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
107
108		let expected = Epoch(unix_timestamp.as_secs() / interval);
109
110		assert_eq!(expected, epoch);
111	}
112
113	#[test]
114	fn test_epoch_secs_until_next_epoch() {
115		let interval = 10;
116		let secs_until_next_epoch = Epoch::secs_until_next_epoch(interval).unwrap();
117
118		let unix_timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
119
120		let current_epoch = unix_timestamp.as_secs() / interval;
121		let expected = (current_epoch + 1) * interval - unix_timestamp.as_secs();
122
123		assert_eq!(expected, secs_until_next_epoch);
124	}
125
126	#[test]
127	fn test_epoch_current_timestamp() {
128		let timestamp = Epoch::current_timestamp().unwrap();
129
130		let unix_timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
131
132		assert_eq!(unix_timestamp.as_secs(), timestamp);
133	}
134}