use crate::model::stores::{block_window_cache::BlockWindowHeap, headers::HeaderStoreReader};
use kaspa_consensus_core::errors::block::RuleError;
use std::sync::Arc;
#[derive(Clone)]
pub struct FullPastMedianTimeManager<T: HeaderStoreReader> {
headers_store: Arc<T>,
genesis_timestamp: u64,
}
impl<T: HeaderStoreReader> FullPastMedianTimeManager<T> {
pub fn new(headers_store: Arc<T>, genesis_timestamp: u64) -> Self {
Self { headers_store, genesis_timestamp }
}
pub fn calc_past_median_time(&self, window: &BlockWindowHeap) -> Result<u64, RuleError> {
if window.is_empty() {
return Ok(self.genesis_timestamp);
}
let mut window_timestamps: Vec<u64> =
window.iter().map(|item| self.headers_store.get_timestamp(item.0.hash).unwrap()).collect();
window_timestamps.sort_unstable(); Ok(window_timestamps[window_timestamps.len() / 2])
}
}
#[derive(Clone)]
pub struct SampledPastMedianTimeManager<T: HeaderStoreReader> {
headers_store: Arc<T>,
genesis_timestamp: u64,
}
impl<T: HeaderStoreReader> SampledPastMedianTimeManager<T> {
pub fn new(headers_store: Arc<T>, genesis_timestamp: u64) -> Self {
Self { headers_store, genesis_timestamp }
}
pub fn calc_past_median_time(&self, window: &BlockWindowHeap) -> Result<u64, RuleError> {
const AVERAGE_FRAME_SIZE: usize = 11;
if window.is_empty() {
return Ok(self.genesis_timestamp);
}
let mut window_timestamps: Vec<u64> =
window.iter().map(|item| self.headers_store.get_timestamp(item.0.hash).unwrap()).collect();
window_timestamps.sort_unstable(); let avg_frame_size = window_timestamps.len().min(AVERAGE_FRAME_SIZE);
let ending_index = (window_timestamps.len() + avg_frame_size + 1) / 2;
let timestamp = (window_timestamps[ending_index - avg_frame_size..ending_index].iter().sum::<u64>()
+ avg_frame_size as u64 / 2)
/ avg_frame_size as u64;
Ok(timestamp)
}
}