time.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. use std::{
  2. mem,
  3. net::UdpSocket,
  4. time::{Duration, UNIX_EPOCH},
  5. };
  6. use chrono::{NaiveDateTime, Utc};
  7. use log::debug;
  8. use rand::seq::SliceRandom;
  9. use serde::{Deserialize, Serialize};
  10. use serde_json::json;
  11. use url::Url;
  12. use crate::{
  13. rpc::{client::RpcClient, jsonrpc::JsonRequest},
  14. util::serial::{SerialDecodable, SerialEncodable},
  15. Error, Result,
  16. };
  17. /// Wrapper struct to represent [`chrono`] UTC timestamps.
  18. #[derive(
  19. Clone,
  20. Copy,
  21. Debug,
  22. Serialize,
  23. Deserialize,
  24. SerialEncodable,
  25. SerialDecodable,
  26. PartialEq,
  27. PartialOrd,
  28. Eq,
  29. )]
  30. pub struct Timestamp(pub i64);
  31. impl Timestamp {
  32. /// Generate a `Timestamp` of the current time.
  33. pub fn current_time() -> Self {
  34. Self(Utc::now().timestamp())
  35. }
  36. /// Calculates elapsed time of a `Timestamp`.
  37. pub fn elapsed(&self) -> u64 {
  38. let start_time = NaiveDateTime::from_timestamp(self.0, 0);
  39. let end_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
  40. let diff = end_time - start_time;
  41. diff.num_seconds() as u64
  42. }
  43. /// Increment a 'Timestamp'.
  44. pub fn add(&mut self, inc: i64) {
  45. self.0 += inc;
  46. }
  47. }
  48. impl std::fmt::Display for Timestamp {
  49. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  50. let date = timestamp_to_date(self.0, DateFormat::DateTime);
  51. write!(f, "{}", date)
  52. }
  53. }
  54. #[derive(
  55. Clone,
  56. Copy,
  57. Debug,
  58. Serialize,
  59. Deserialize,
  60. SerialEncodable,
  61. SerialDecodable,
  62. PartialEq,
  63. PartialOrd,
  64. Eq,
  65. )]
  66. pub struct NanoTimestamp(pub i64);
  67. impl NanoTimestamp {
  68. pub fn current_time() -> Self {
  69. Self(Utc::now().timestamp_nanos())
  70. }
  71. }
  72. impl std::fmt::Display for NanoTimestamp {
  73. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  74. let date = timestamp_to_date(self.0, DateFormat::Nanos);
  75. write!(f, "{}", date)
  76. }
  77. }
  78. // Clock sync parameters
  79. const RETRIES: u8 = 10;
  80. const NTP_ADDRESS: &str = "pool.ntp.org:123";
  81. const EPOCH: i64 = 2208988800; //1900
  82. // JsonRPC request to a network peer(randomly selected),
  83. // to retrieve their current system clock.
  84. async fn peer_request(peers: &Vec<Url>) -> Result<Option<Timestamp>> {
  85. // Select peer, None if vector is empty
  86. let peer = peers.choose(&mut rand::thread_rng());
  87. match peer {
  88. None => Ok(None),
  89. Some(p) => {
  90. // Create rpc client
  91. let rpc_client = RpcClient::new(p.clone()).await?;
  92. // Execute request
  93. let req = JsonRequest::new("clock", json!([]));
  94. let rep = rpc_client.oneshot_request(req).await?;
  95. // Parse response
  96. let timestamp: Timestamp = serde_json::from_value(rep)?;
  97. Ok(Some(timestamp))
  98. }
  99. }
  100. }
  101. // Raw ntp request execution
  102. async fn ntp_request() -> Result<Timestamp> {
  103. // Create socket
  104. let sock = UdpSocket::bind("0.0.0.0:0")?;
  105. sock.set_read_timeout(Some(Duration::from_secs(5)))?;
  106. sock.set_write_timeout(Some(Duration::from_secs(5)))?;
  107. // Execute request
  108. let mut packet = [0u8; 48];
  109. packet[0] = (3 << 6) | (4 << 3) | 3;
  110. sock.send_to(&packet, NTP_ADDRESS)?;
  111. // Parse response
  112. sock.recv(&mut packet[..])?;
  113. let (bytes, _) = packet[40..44].split_at(mem::size_of::<u32>());
  114. let num = u32::from_be_bytes(bytes.try_into().unwrap());
  115. let timestamp = Timestamp(num as i64 - EPOCH);
  116. Ok(timestamp)
  117. }
  118. // This is a very simple check to verify that system time is correct.
  119. // Retry loop is used to in case discrepancies are found.
  120. // If all retries fail, system clock is considered invalid.
  121. // TODO: 1. Add proxy functionality in order not to leak connections
  122. pub async fn check_clock(peers: Vec<Url>) -> Result<()> {
  123. debug!("System clock check started...");
  124. let mut r = 0;
  125. while r < RETRIES {
  126. if let Err(e) = clock_check(&peers).await {
  127. debug!("Error during clock check: {:#?}", e);
  128. r += 1;
  129. continue
  130. };
  131. break
  132. }
  133. debug!("System clock check finished. Retries: {:#?}", r);
  134. match r {
  135. RETRIES => Err(Error::InvalidClock),
  136. _ => Ok(()),
  137. }
  138. }
  139. async fn clock_check(peers: &Vec<Url>) -> Result<()> {
  140. // Start elapsed time counter to cover for all requests and processing time
  141. let requests_start = Timestamp::current_time();
  142. // Poll one of peers for their current UTC timestamp
  143. let peer_time = peer_request(peers).await?;
  144. // Start elapsed time counter to cover for ntp request and processing time
  145. let ntp_request_start = Timestamp::current_time();
  146. // Poll ntp.org for current timestamp
  147. let mut ntp_time = ntp_request().await?;
  148. // Stop elapsed time counters
  149. let ntp_elapsed_time = ntp_request_start.elapsed() as i64;
  150. let requests_elapsed_time = requests_start.elapsed() as i64;
  151. // Current system time
  152. let system_time = Timestamp::current_time();
  153. // Add elapsed time to respone times
  154. ntp_time.add(ntp_elapsed_time);
  155. let peer_time = match peer_time {
  156. None => None,
  157. Some(p) => {
  158. let mut t = p;
  159. t.add(requests_elapsed_time);
  160. Some(t)
  161. }
  162. };
  163. debug!("peer_time: {:#?}", peer_time);
  164. debug!("ntp_time: {:#?}", ntp_time);
  165. debug!("system_time: {:#?}", system_time);
  166. // We verify that system time is equal to peer(if exists) and ntp times
  167. let check = match peer_time {
  168. Some(p) => (system_time == p) && (system_time == ntp_time),
  169. None => system_time == ntp_time,
  170. };
  171. match check {
  172. true => Ok(()),
  173. false => Err(Error::InvalidClock),
  174. }
  175. }
  176. pub enum DateFormat {
  177. Default,
  178. Date,
  179. DateTime,
  180. Nanos,
  181. }
  182. pub fn timestamp_to_date(timestamp: i64, format: DateFormat) -> String {
  183. if timestamp <= 0 {
  184. return "".to_string()
  185. }
  186. match format {
  187. DateFormat::Date => {
  188. NaiveDateTime::from_timestamp(timestamp, 0).date().format("%-d %b").to_string()
  189. }
  190. DateFormat::DateTime => {
  191. NaiveDateTime::from_timestamp(timestamp, 0).format("%H:%M:%S %A %-d %B").to_string()
  192. }
  193. DateFormat::Nanos => {
  194. const A_BILLION: i64 = 1_000_000_000;
  195. NaiveDateTime::from_timestamp(timestamp / A_BILLION, (timestamp % A_BILLION) as u32)
  196. .format("%H:%M:%S.%f")
  197. .to_string()
  198. }
  199. DateFormat::Default => "".to_string(),
  200. }
  201. }
  202. pub fn unix_timestamp() -> Result<u64> {
  203. Ok(UNIX_EPOCH.elapsed()?.as_secs())
  204. }