anvil/eth/backend/
time.rs1use 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, Copy, Debug, PartialEq, Eq)]
14pub enum TimePrecision {
15 Seconds,
17 Milliseconds,
19}
20
21#[derive(Clone, Debug)]
23pub struct TimeManager {
24 offset: Arc<RwLock<i128>>,
26 last_timestamp: Arc<RwLock<u64>>,
28 next_exact_timestamp: Arc<RwLock<Option<u64>>>,
32 interval: Arc<RwLock<Option<u64>>>,
34 precision: TimePrecision,
35}
36
37impl TimeManager {
38 pub fn new(start_timestamp: u64) -> Self {
39 let time_manager = Self {
40 last_timestamp: Default::default(),
41 offset: Default::default(),
42 next_exact_timestamp: Default::default(),
43 interval: Default::default(),
44 precision: TimePrecision::Seconds,
45 };
46 time_manager.reset(start_timestamp);
47 time_manager
48 }
49
50 pub fn new_with_milliseconds(start_timestamp: u64) -> Self {
51 let time_manager = Self {
52 last_timestamp: Default::default(),
53 offset: Default::default(),
54 next_exact_timestamp: Default::default(),
55 interval: Default::default(),
56 precision: TimePrecision::Milliseconds,
57 };
58 let start_timestamp = start_timestamp.saturating_div(1000);
59 time_manager.reset(start_timestamp);
60 time_manager
61 }
62
63 fn convert_from_milliseconds(&self, value: u64) -> u64 {
65 match self.precision {
66 TimePrecision::Seconds => value.saturating_div(1000),
67 TimePrecision::Milliseconds => value,
68 }
69 }
70
71 pub fn reset(&self, start_timestamp: u64) {
74 let current = duration_since_unix_epoch().as_millis() as i128;
75 let start_timestamp = to_milliseconds(start_timestamp);
76 *self.last_timestamp.write() = start_timestamp;
77 *self.offset.write() = (start_timestamp as i128) - current;
78 self.next_exact_timestamp.write().take();
79 }
80
81 pub fn offset(&self) -> i128 {
82 *self.offset.read()
83 }
84
85 fn add_offset(&self, offset: i128) -> i128 {
87 let mut current = self.offset.write();
88 let next = current.saturating_add(offset);
89 trace!(target: "time", "adding timestamp offset={}, total={}", offset, next);
90 *current = next;
91 next
92 }
93
94 pub fn increase_time(&self, seconds: u64) -> i128 {
98 self.add_offset(to_milliseconds(seconds) as i128)
99 }
100
101 pub fn set_next_block_timestamp(&self, timestamp: u64) -> Result<(), BlockchainError> {
104 trace!(target: "time", "override next timestamp {}", timestamp);
105 let timestamp = to_milliseconds(timestamp);
106 if timestamp < *self.last_timestamp.read() {
107 return Err(BlockchainError::TimestampError(format!(
108 "{} is lower than previous block's timestamp",
109 self.convert_from_milliseconds(timestamp)
110 )));
111 }
112 self.next_exact_timestamp.write().replace(timestamp);
113 Ok(())
114 }
115
116 pub fn set_block_timestamp_interval(&self, interval: u64) {
121 trace!(target: "time", "set interval {}", interval);
122 let interval = to_milliseconds(interval);
123 self.interval.write().replace(interval);
124 }
125
126 pub fn remove_block_timestamp_interval(&self) -> bool {
128 if self.interval.write().take().is_some() {
129 trace!(target: "time", "removed interval");
130 true
131 } else {
132 false
133 }
134 }
135
136 fn compute_next_timestamp(&self) -> (u64, Option<i128>) {
138 let current = duration_since_unix_epoch().as_millis() as i128;
139 let last_timestamp = *self.last_timestamp.read();
140
141 let (mut next_timestamp, update_offset) =
142 if let Some(next) = *self.next_exact_timestamp.read() {
143 (next, true)
144 } else if let Some(interval) = *self.interval.read() {
145 (last_timestamp.saturating_add(interval), false)
146 } else {
147 (current.saturating_add(self.offset()) as u64, false)
148 };
149 if next_timestamp < last_timestamp {
151 next_timestamp = last_timestamp + to_milliseconds(1);
152 }
153 let next_offset = update_offset.then_some((next_timestamp as i128) - current);
154 (next_timestamp, next_offset)
155 }
156
157 pub fn next_timestamp(&self) -> u64 {
159 let (next_timestamp, next_offset) = self.compute_next_timestamp();
160 self.next_exact_timestamp.write().take();
162 if let Some(next_offset) = next_offset {
163 *self.offset.write() = next_offset;
164 }
165 *self.last_timestamp.write() = next_timestamp;
166 self.convert_from_milliseconds(next_timestamp)
167 }
168
169 pub fn current_call_timestamp(&self) -> u64 {
171 let (next_timestamp, _) = self.compute_next_timestamp();
172 self.convert_from_milliseconds(next_timestamp)
173 }
174}
175
176pub fn duration_since_unix_epoch() -> Duration {
178 use std::time::SystemTime;
179 let now = SystemTime::now();
180 now.duration_since(SystemTime::UNIX_EPOCH)
181 .unwrap_or_else(|err| panic!("Current time {now:?} is invalid: {err:?}"))
182}
183
184fn to_milliseconds(value: u64) -> u64 {
186 value.saturating_mul(1000)
187}