tx_indexer/
progress_tracker.rs

1use std::sync::{atomic::AtomicUsize, Arc};
2
3use anyhow::anyhow;
4use chrono::{DateTime, Duration, Utc};
5use oura::utils::ChainWellKnownInfo;
6use tx_bakery::chain_query::{EraParameters, EraSummary, EraTime};
7
8use crate::from_oura::OuraParseError;
9
10/// A progress tracker holds information about the chain info required to calculate
11/// POSIX time from slots
12#[derive(Clone, Debug)]
13pub struct ProgressTracker {
14    pub system_start: DateTime<Utc>,
15    pub era_summaries: Vec<EraSummary>,
16    pub since_slot: u64,
17    pub sync_progress: Arc<AtomicUsize>,
18}
19
20impl ProgressTracker {
21    pub fn new(since_slot: u64, chain_info: &ChainWellKnownInfo) -> Result<Self, anyhow::Error> {
22        let system_start = DateTime::from_timestamp(chain_info.byron_known_time as i64, 0).ok_or(
23            anyhow!("Unable to convert shelley_known_time to to DateTime"),
24        )?;
25
26        Ok(ProgressTracker {
27            system_start,
28            era_summaries: chain_info_to_era_summaries(&system_start, chain_info)?,
29            since_slot,
30            sync_progress: Arc::new(AtomicUsize::new(0)),
31        })
32    }
33
34    pub fn get_percentage(&self, slot: u64) -> Result<f32, OuraParseError> {
35        let current_time = Utc::now();
36        let current_slot =
37            tx_bakery::time::time_into_slot(&self.era_summaries, &self.system_start, current_time)
38                .map_err(OuraParseError::TimeConversionError)?;
39
40        let synced = slot - self.since_slot;
41        let to_be_synced = current_slot - self.since_slot;
42
43        Ok(synced as f32 * 100.0 / to_be_synced as f32)
44    }
45}
46
47/// Convert Oura chain info into Ogmios EraSummaries.
48/// Oura does not include all eras, only Byron and Shelley, all other eras are part of
49/// Shelley. This is good enough for time calculations.
50fn chain_info_to_era_summaries(
51    system_start_time: &DateTime<Utc>,
52    chain_info: &ChainWellKnownInfo,
53) -> Result<Vec<EraSummary>, anyhow::Error> {
54    let byron_start = EraTime {
55        time: Duration::zero(),
56        slot: 0,
57        epoch: 0,
58    };
59
60    let shelley_start = EraTime {
61        time: DateTime::from_timestamp(chain_info.shelley_known_time as i64, 0).ok_or(anyhow!(
62            "Unable to convert shelley_known_time to to DateTime"
63        ))? - system_start_time,
64        slot: chain_info.shelley_known_slot,
65        epoch: chain_info.shelley_known_slot / chain_info.byron_epoch_length as u64,
66    };
67
68    Ok(vec![
69        EraSummary {
70            start: byron_start,
71            end: Some(shelley_start.clone()),
72            parameters: EraParameters {
73                epoch_length: chain_info.byron_epoch_length as u64,
74                slot_length: chain_info.byron_slot_length as u64 * 1000,
75                safe_zone: Some(4320),
76            },
77        },
78        EraSummary {
79            start: shelley_start,
80            end: None,
81            parameters: EraParameters {
82                epoch_length: chain_info.shelley_epoch_length as u64,
83                slot_length: chain_info.shelley_slot_length as u64 * 1000,
84                safe_zone: Some(4320),
85            },
86        },
87    ])
88}