use core::time::Duration;
use std::time::{Instant, SystemTime};
use crate::{SignatureScheme, ValidRound};
use super::{Borshy, BorshyBlockchain};
serai_db::schema!(TributaryState {
BlockNumber: (genesis: &[u8]) -> crate::BlockNumber,
RoundNumber: (genesis: &[u8]) -> crate::RoundNumber,
PendingStepTimeout: (genesis: &[u8]) -> u64,
PendingPrecommitTimeout: (genesis: &[u8]) -> u64,
Step: (genesis: &[u8]) -> super::Step,
Valid: <B: BorshyBlockchain>(genesis: &[u8]) -> (
ValidRound<<B::SignatureScheme as SignatureScheme>::AggregateSignature>,
B::Block
),
Locked: <Hash: Borshy>(genesis: &[u8]) -> (crate::RoundNumber, Hash),
OurLatestPrevotes: <B: BorshyBlockchain>(genesis: &[u8]) -> [Option<crate::MessageFor<B>>; 2],
OurLatestPrecommit: <B: BorshyBlockchain>(genesis: &[u8]) -> crate::MessageFor<B>,
});
pub(super) fn timeout_in_ms_since_epoch(timeout: Duration) -> u64 {
let expiry = SystemTime::now().checked_add(timeout);
let expiry_from_epoch =
expiry.map(|expiry| expiry.duration_since(SystemTime::UNIX_EPOCH).unwrap_or(Duration::ZERO));
let expiry_in_ms_since_epoch = expiry_from_epoch.unwrap_or(Duration::MAX);
u64::try_from(expiry_in_ms_since_epoch.as_millis()).unwrap_or(u64::MAX)
}
pub(super) fn timeout_from_ms_since_epoch(ms: u64) -> (Instant, Duration) {
let start = Instant::now();
let duration = match SystemTime::UNIX_EPOCH.checked_add(Duration::from_millis(ms)) {
Some(expiry) => expiry.duration_since(SystemTime::now()).unwrap_or(Duration::ZERO),
None => Duration::MAX,
};
(start, duration)
}
#[test]
fn unix_time() {
for _ in 0 .. 128 {
let timeout = Duration::from_millis(1000);
let unix_time_in_ms = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_millis();
let fetched_unix_time = timeout_in_ms_since_epoch(timeout);
let actual_timeout_start = Instant::now();
let unix_time_in_ms_now = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_millis();
assert!((unix_time_in_ms_now - unix_time_in_ms) < 100);
assert!((unix_time_in_ms + 1000) <= u128::from(fetched_unix_time));
assert!(u128::from(fetched_unix_time) <= (unix_time_in_ms_now + 1000));
let (now, time_remaining) = timeout_from_ms_since_epoch(fetched_unix_time);
let actual_time_remaining =
timeout.checked_sub(now.duration_since(actual_timeout_start)).unwrap();
assert!(time_remaining < actual_time_remaining);
assert!(actual_time_remaining <= (time_remaining + Duration::from_millis(100)));
}
}