use alloy_primitives::B256;
use std::{sync::Arc, time::Instant};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TransportReceipt {
identity: B256,
received: Instant,
decoded: Instant,
}
impl TransportReceipt {
pub fn new(identity: B256, received: Instant, decoded: Instant) -> Option<Self> {
(received <= decoded).then_some(Self {
identity,
received,
decoded,
})
}
pub const fn identity(self) -> B256 {
self.identity
}
pub const fn received(self) -> Instant {
self.received
}
pub const fn decoded(self) -> Instant {
self.decoded
}
}
pub type TransportReceiptLookup = Arc<dyn Fn(&str) -> Option<TransportReceipt> + Send + Sync>;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CanonicalIngressTiming {
receipt: TransportReceipt,
dequeued: Instant,
decoded: Instant,
}
impl CanonicalIngressTiming {
pub fn new(receipt: TransportReceipt, dequeued: Instant, decoded: Instant) -> Option<Self> {
(receipt.decoded <= dequeued && dequeued <= decoded).then_some(Self {
receipt,
dequeued,
decoded,
})
}
pub const fn receipt(self) -> TransportReceipt {
self.receipt
}
pub const fn dequeued(self) -> Instant {
self.dequeued
}
pub const fn decoded(self) -> Instant {
self.decoded
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn queue_age_is_retained_and_invalid_clocks_remain_missing() {
let received = Instant::now();
let envelope = received + Duration::from_micros(5);
let dequeue = envelope + Duration::from_millis(30);
let decode = dequeue + Duration::from_micros(10);
let receipt = TransportReceipt::new(B256::repeat_byte(1), received, envelope).unwrap();
let timing = CanonicalIngressTiming::new(receipt, dequeue, decode).unwrap();
assert_eq!(timing.receipt().received(), received);
assert_eq!(
timing.dequeued().duration_since(receipt.decoded()),
Duration::from_millis(30)
);
assert!(TransportReceipt::new(B256::ZERO, envelope, received).is_none());
assert!(CanonicalIngressTiming::new(receipt, received, decode).is_none());
}
}