use brk_computer::Computer;
use brk_error::{Error, Result};
use brk_types::{DifficultyAdjustmentEntry, Height};
use vecdb::{ReadableVec, Ro, VecIndex};
pub(super) fn iter_difficulty_epochs(
computer: &Computer<Ro>,
start_height: usize,
end_height: usize,
) -> Result<Vec<DifficultyAdjustmentEntry>> {
let start_epoch = computer
.indexes
.height
.epoch
.collect_one(Height::from(start_height))
.ok_or(Error::Internal(
"iter_difficulty_epochs: start_height not in epoch index",
))?;
let end_epoch = computer
.indexes
.height
.epoch
.collect_one(Height::from(end_height))
.ok_or(Error::Internal(
"iter_difficulty_epochs: end_height not in epoch index",
))?;
let mut height_cursor = computer.indexes.epoch.first_height.cursor();
let mut timestamp_cursor = computer.indexes.timestamp.epoch.cursor();
let mut difficulty_cursor = computer.blocks.difficulty.value.epoch.cursor();
let mut results = Vec::with_capacity(end_epoch.to_usize() - start_epoch.to_usize() + 1);
let mut prev_difficulty: Option<f64> = None;
for epoch_usize in start_epoch.to_usize()..=end_epoch.to_usize() {
let epoch_height = height_cursor.get(epoch_usize).ok_or(Error::Internal(
"iter_difficulty_epochs: missing epoch first_height",
))?;
if epoch_height.to_usize() < start_height {
prev_difficulty = Some(*difficulty_cursor.get(epoch_usize).ok_or(Error::Internal(
"iter_difficulty_epochs: missing pre-window epoch difficulty",
))?);
continue;
}
let epoch_timestamp = timestamp_cursor.get(epoch_usize).ok_or(Error::Internal(
"iter_difficulty_epochs: missing epoch timestamp",
))?;
let epoch_difficulty = *difficulty_cursor.get(epoch_usize).ok_or(Error::Internal(
"iter_difficulty_epochs: missing epoch difficulty",
))?;
let change_percent = match prev_difficulty {
Some(prev) if prev > 0.0 => epoch_difficulty / prev,
_ => 0.0,
};
results.push(DifficultyAdjustmentEntry {
timestamp: epoch_timestamp,
height: epoch_height,
difficulty: epoch_difficulty,
change_percent,
});
prev_difficulty = Some(epoch_difficulty);
}
Ok(results)
}