tx_bakery/
time.rs

1//! POSIX time to/from slot conversions
2
3use crate::chain_query::EraSummary;
4use crate::error::{Error, Result};
5use anyhow::anyhow;
6use chrono::{DateTime, Duration, Utc};
7use plutus_ledger_api::{
8    csl::lib as csl,
9    v3::{
10        interval::{Extended, LowerBound, PlutusInterval, UpperBound},
11        transaction::{POSIXTime, POSIXTimeConversionError, POSIXTimeRange},
12    },
13};
14
15/// Convert a POSIX time into number of slots in the current system
16pub fn posix_time_into_slot(
17    era_summaries: &[EraSummary],
18    sys_start: &DateTime<Utc>,
19    posix_time: POSIXTime,
20) -> Result<u64> {
21    let abs_time: DateTime<Utc> = posix_time
22        .try_into()
23        .map_err(|source: POSIXTimeConversionError| Error::ConversionError(anyhow!(source)))?;
24    time_into_slot(era_summaries, sys_start, abs_time)
25}
26
27pub fn time_into_slot(
28    era_summaries: &[EraSummary],
29    sys_start: &DateTime<Utc>,
30    time: DateTime<Utc>,
31) -> Result<u64> {
32    // Time since system start
33    let rel_time = time - sys_start;
34
35    if era_summaries.is_empty() {
36        return Err(Error::InvalidConfiguration("era_summaries".to_string()));
37    }
38
39    let era_summary = era_summaries
40        .iter()
41        .filter(|era_summary| era_summary.start.time <= rel_time)
42        .last()
43        .ok_or(Error::InvalidPOSIXTime(format!(
44            "{} is before system start at {}, or era_summaries are invalid.",
45            time, sys_start
46        )))?;
47
48    let time_in_era = rel_time - era_summary.start.time;
49    let slots_in_era = time_in_era.num_milliseconds() as u64 / era_summary.parameters.slot_length;
50
51    Ok(era_summary.start.slot + slots_in_era)
52}
53
54pub fn slot_into_posix_time(
55    era_summaries: &[EraSummary],
56    sys_start: &DateTime<Utc>,
57    slot: u64,
58) -> Result<POSIXTime> {
59    Ok(slot_into_time(era_summaries, sys_start, slot)?.into())
60}
61
62pub fn slot_into_time(
63    era_summaries: &[EraSummary],
64    sys_start: &DateTime<Utc>,
65    slot: u64,
66) -> Result<DateTime<Utc>> {
67    let era_summary = era_summaries
68        .iter()
69        .filter(|era_summary| era_summary.start.slot <= slot)
70        .last()
71        .ok_or(Error::InvalidConfiguration("era_summaries".to_string()))?;
72
73    let time_in_era = Duration::try_milliseconds(
74        ((slot - era_summary.start.slot) * era_summary.parameters.slot_length) as i64,
75    )
76    .ok_or(Error::Internal(anyhow!(
77        "Couldn't convert era in time to milliseconds"
78    )))?;
79
80    Ok(*sys_start + era_summary.start.time + time_in_era)
81}
82
83pub fn time_range_into_slots(
84    era_summaries: &[EraSummary],
85    sys_start: &DateTime<Utc>,
86    interval: POSIXTimeRange,
87) -> Result<(Option<csl::BigNum>, Option<csl::BigNum>)> {
88    let PlutusInterval {
89        from:
90            LowerBound {
91                bound: lower_bound,
92                closed: lower_closed,
93            },
94        to: UpperBound {
95            bound: upper_bound,
96            closed: upper_closed,
97        },
98    } = interval;
99
100    let lb_slots = match lower_bound {
101        Extended::NegInf => None,
102        Extended::PosInf => Some(u64::MAX),
103        Extended::Finite(posix_time) => {
104            let slots = posix_time_into_slot(era_summaries, sys_start, posix_time)?;
105            if lower_closed {
106                Some(slots)
107            } else {
108                Some(slots + 1)
109            }
110        }
111    };
112
113    let ub_slots = match upper_bound {
114        Extended::NegInf => Some(0),
115        Extended::PosInf => None,
116        Extended::Finite(posix_time) => {
117            let slots = posix_time_into_slot(era_summaries, sys_start, posix_time)?;
118            if upper_closed {
119                Some(slots)
120            } else {
121                Some(slots - 1)
122            }
123        }
124    };
125
126    Ok((
127        lb_slots.map(csl::BigNum::from),
128        ub_slots.map(csl::BigNum::from),
129    ))
130}