anvil/eth/backend/
time.rs
1use crate::eth::error::BlockchainError;
4use chrono::{DateTime, Utc};
5use parking_lot::RwLock;
6use std::{sync::Arc, time::Duration};
7
8pub fn utc_from_secs(secs: u64) -> DateTime<Utc> {
10 DateTime::from_timestamp(secs as i64, 0).unwrap()
11}
12
13#[derive(Clone, Debug)]
15pub struct TimeManager {
16 offset: Arc<RwLock<i128>>,
18 last_timestamp: Arc<RwLock<u64>>,
20 next_exact_timestamp: Arc<RwLock<Option<u64>>>,
24 interval: Arc<RwLock<Option<u64>>>,
26}
27
28impl TimeManager {
29 pub fn new(start_timestamp: u64) -> Self {
30 let time_manager = Self {
31 last_timestamp: Default::default(),
32 offset: Default::default(),
33 next_exact_timestamp: Default::default(),
34 interval: Default::default(),
35 };
36 time_manager.reset(start_timestamp);
37 time_manager
38 }
39
40 pub fn reset(&self, start_timestamp: u64) {
43 let current = duration_since_unix_epoch().as_secs() as i128;
44 *self.last_timestamp.write() = start_timestamp;
45 *self.offset.write() = (start_timestamp as i128) - current;
46 self.next_exact_timestamp.write().take();
47 }
48
49 pub fn offset(&self) -> i128 {
50 *self.offset.read()
51 }
52
53 fn add_offset(&self, offset: i128) -> i128 {
55 let mut current = self.offset.write();
56 let next = current.saturating_add(offset);
57 trace!(target: "time", "adding timestamp offset={}, total={}", offset, next);
58 *current = next;
59 next
60 }
61
62 pub fn increase_time(&self, seconds: u64) -> i128 {
66 self.add_offset(seconds as i128)
67 }
68
69 pub fn set_next_block_timestamp(&self, timestamp: u64) -> Result<(), BlockchainError> {
72 trace!(target: "time", "override next timestamp {}", timestamp);
73 if timestamp < *self.last_timestamp.read() {
74 return Err(BlockchainError::TimestampError(format!(
75 "{timestamp} is lower than previous block's timestamp"
76 )))
77 }
78 self.next_exact_timestamp.write().replace(timestamp);
79 Ok(())
80 }
81
82 pub fn set_block_timestamp_interval(&self, interval: u64) {
87 trace!(target: "time", "set interval {}", interval);
88 self.interval.write().replace(interval);
89 }
90
91 pub fn remove_block_timestamp_interval(&self) -> bool {
93 if self.interval.write().take().is_some() {
94 trace!(target: "time", "removed interval");
95 true
96 } else {
97 false
98 }
99 }
100
101 fn compute_next_timestamp(&self) -> (u64, Option<i128>) {
103 let current = duration_since_unix_epoch().as_secs() as i128;
104 let last_timestamp = *self.last_timestamp.read();
105
106 let (mut next_timestamp, update_offset) =
107 if let Some(next) = *self.next_exact_timestamp.read() {
108 (next, true)
109 } else if let Some(interval) = *self.interval.read() {
110 (last_timestamp.saturating_add(interval), false)
111 } else {
112 (current.saturating_add(self.offset()) as u64, false)
113 };
114 if next_timestamp < last_timestamp {
116 next_timestamp = last_timestamp + 1;
117 }
118 let next_offset = update_offset.then_some((next_timestamp as i128) - current);
119 (next_timestamp, next_offset)
120 }
121
122 pub fn next_timestamp(&self) -> u64 {
124 let (next_timestamp, next_offset) = self.compute_next_timestamp();
125 self.next_exact_timestamp.write().take();
127 if let Some(next_offset) = next_offset {
128 *self.offset.write() = next_offset;
129 }
130 *self.last_timestamp.write() = next_timestamp;
131 next_timestamp
132 }
133
134 pub fn current_call_timestamp(&self) -> u64 {
136 let (next_timestamp, _) = self.compute_next_timestamp();
137 next_timestamp
138 }
139}
140
141pub fn duration_since_unix_epoch() -> Duration {
143 use std::time::SystemTime;
144 let now = SystemTime::now();
145 now.duration_since(SystemTime::UNIX_EPOCH)
146 .unwrap_or_else(|err| panic!("Current time {now:?} is invalid: {err:?}"))
147}