1use std::{
8 fmt::{Display, Formatter, Result as FmtResult},
9 time::{SystemTime, UNIX_EPOCH},
10};
11
12use crate::EigenError;
13
14#[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 pub fn to_be_bytes(self) -> [u8; 8] {
28 self.0.to_be_bytes()
29 }
30
31 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 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 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 pub fn previous(&self) -> Self {
67 Epoch(self.0 - 1)
68 }
69
70 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}