pub mod block_builder;
pub mod projected_blocks;
use std::{
sync::{
Arc,
atomic::{AtomicBool, AtomicU64, Ordering},
},
time::{SystemTime, UNIX_EPOCH},
};
use brk_rpc::Client;
use parking_lot::RwLock;
#[cfg(debug_assertions)]
use self::projected_blocks::verify::Verifier;
use self::{
block_builder::build_projected_blocks,
projected_blocks::{BlockStats, RecommendedFees, Snapshot},
};
use crate::stores::EntryPool;
const MIN_REBUILD_INTERVAL_MS: u64 = 1000;
#[derive(Default)]
pub struct Rebuilder {
snapshot: RwLock<Arc<Snapshot>>,
dirty: AtomicBool,
last_rebuild_ms: AtomicU64,
}
impl Rebuilder {
pub fn mark_dirty(&self) {
self.dirty.store(true, Ordering::Release);
}
pub fn tick(&self, client: &Client, entries: &RwLock<EntryPool>) {
if !self.dirty.load(Ordering::Acquire) {
return;
}
let now_ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0);
let last = self.last_rebuild_ms.load(Ordering::Acquire);
if now_ms.saturating_sub(last) < MIN_REBUILD_INTERVAL_MS {
return;
}
if self
.last_rebuild_ms
.compare_exchange(last, now_ms, Ordering::AcqRel, Ordering::Relaxed)
.is_err()
{
return;
}
self.dirty.store(false, Ordering::Release);
let built = {
let entries = entries.read();
let entries_slice = entries.entries();
let blocks = build_projected_blocks(entries_slice);
#[cfg(debug_assertions)]
Verifier::check(client, &blocks, entries_slice);
#[cfg(not(debug_assertions))]
let _ = client;
Snapshot::build(blocks, entries_slice)
};
*self.snapshot.write() = Arc::new(built);
}
fn current(&self) -> Arc<Snapshot> {
self.snapshot.read().clone()
}
pub fn snapshot(&self) -> Arc<Snapshot> {
self.current()
}
pub fn fees(&self) -> RecommendedFees {
self.current().fees.clone()
}
pub fn block_stats(&self) -> Vec<BlockStats> {
self.current().block_stats.clone()
}
pub fn next_block_hash(&self) -> u64 {
self.current().next_block_hash
}
}