use kona_engine::{EngineTask, FinalizeTask};
use kona_protocol::{BlockInfo, OpAttributesWithParent};
use std::collections::BTreeMap;
use tokio::sync::watch;
use crate::actors::engine::actor::EngineActorState;
type L1BlockNumber = u64;
type L2BlockNumber = u64;
#[derive(Debug)]
pub struct L2Finalizer {
finalized_l1_block_rx: watch::Receiver<Option<BlockInfo>>,
awaiting_finalization: BTreeMap<L1BlockNumber, L2BlockNumber>,
}
impl L2Finalizer {
pub const fn new(finalized_l1_block_rx: watch::Receiver<Option<BlockInfo>>) -> Self {
Self { finalized_l1_block_rx, awaiting_finalization: BTreeMap::new() }
}
pub fn enqueue_for_finalization(&mut self, attributes: &OpAttributesWithParent) {
self.awaiting_finalization
.entry(
attributes.derived_from.map(|b| b.number).expect(
"Fatal: Cannot enqueue attributes for finalization that weren't derived",
),
)
.and_modify(|n| *n = (*n).max(attributes.block_number()))
.or_insert(attributes.block_number());
}
pub fn clear(&mut self) {
self.awaiting_finalization.clear();
}
pub async fn new_finalized_block(&mut self) -> Result<(), watch::error::RecvError> {
self.finalized_l1_block_rx.changed().await
}
pub(super) async fn try_finalize_next(&mut self, engine_state: &mut EngineActorState) {
let Some(new_finalized_l1) = *self.finalized_l1_block_rx.borrow() else {
return;
};
let highest_safe = self.awaiting_finalization.range(..=new_finalized_l1.number).next_back();
if let Some((_, highest_safe_number)) = highest_safe {
let task = EngineTask::Finalize(FinalizeTask::new(
engine_state.client.clone(),
engine_state.rollup.clone(),
*highest_safe_number,
));
engine_state.engine.enqueue(task);
self.awaiting_finalization.retain(|&number, _| number > new_finalized_l1.number);
}
}
}