mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-02 14:59:00 -07:00
75 lines
2.4 KiB
Rust
75 lines
2.4 KiB
Rust
use brk_error::{Error, OptionData, Result};
|
|
use brk_types::{BlockTimestamp, Date, Day1, Height, Timestamp};
|
|
use jiff::Timestamp as JiffTimestamp;
|
|
use vecdb::ReadableVec;
|
|
|
|
use crate::Query;
|
|
|
|
impl Query {
|
|
pub fn block_by_timestamp(&self, timestamp: Timestamp) -> Result<BlockTimestamp> {
|
|
let indexer = self.indexer();
|
|
let computer = self.computer();
|
|
|
|
let max_height = self.indexed_height();
|
|
let max_height_usize: usize = max_height.into();
|
|
|
|
if max_height_usize == 0 {
|
|
return Err(Error::NotFound("No blocks indexed".into()));
|
|
}
|
|
|
|
let target = timestamp;
|
|
let date = Date::from(target);
|
|
let day1 = Day1::try_from(date).unwrap_or_default();
|
|
|
|
// Get first height of the target date
|
|
let first_height_of_day = computer
|
|
.indexes
|
|
.day1
|
|
.first_height
|
|
.collect_one(day1)
|
|
.unwrap_or(Height::from(0usize));
|
|
|
|
let start: usize = usize::from(first_height_of_day).min(max_height_usize);
|
|
|
|
let mut ts_cursor = indexer.vecs.blocks.timestamp.cursor();
|
|
|
|
// Search forward from start to find the last block <= target timestamp
|
|
let mut best_height = start;
|
|
let mut best_ts = ts_cursor.get(start).data()?;
|
|
|
|
for h in (start + 1)..=max_height_usize {
|
|
let block_ts = ts_cursor.get(h).data()?;
|
|
if block_ts <= target {
|
|
best_height = h;
|
|
best_ts = block_ts;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check one block before start in case we need to go backward
|
|
if start > 0 && best_ts > target {
|
|
let prev_ts = ts_cursor.get(start - 1).data()?;
|
|
if prev_ts <= target {
|
|
best_height = start - 1;
|
|
best_ts = prev_ts;
|
|
}
|
|
}
|
|
|
|
let height = Height::from(best_height);
|
|
let blockhash = indexer.vecs.blocks.blockhash.collect_one(height).data()?;
|
|
|
|
// Convert timestamp to ISO 8601 format
|
|
let ts_secs: i64 = (*best_ts).into();
|
|
let iso_timestamp = JiffTimestamp::from_second(ts_secs)
|
|
.map(|t| t.strftime("%Y-%m-%dT%H:%M:%S%.3fZ").to_string())
|
|
.unwrap_or_else(|_| best_ts.to_string());
|
|
|
|
Ok(BlockTimestamp {
|
|
height,
|
|
hash: blockhash,
|
|
timestamp: iso_timestamp,
|
|
})
|
|
}
|
|
}
|