use alloy::{
consensus::{ReceiptEnvelope, TxReceipt},
primitives::{Address, Bloom, Bytes, Log},
};
use std::sync::OnceLock;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlockOutput<T: TxReceipt = ReceiptEnvelope> {
receipts: Vec<T>,
senders: Vec<Address>,
bloom: OnceLock<Bloom>,
}
impl Default for BlockOutput {
fn default() -> Self {
Self::with_capacity(0)
}
}
impl<T: TxReceipt<Log = alloy::primitives::Log>> BlockOutput<T> {
pub fn with_capacity(capacity: usize) -> Self {
Self {
receipts: Vec::with_capacity(capacity),
senders: Vec::with_capacity(capacity),
bloom: Default::default(),
}
}
fn seal(&self) {
self.bloom.get_or_init(|| {
let mut bloom = Bloom::default();
for log in self.logs() {
bloom.accrue_log(log);
}
bloom
});
}
fn unseal(&mut self) {
self.bloom.take();
}
pub fn reserve(&mut self, capacity: usize) {
self.receipts.reserve(capacity);
self.senders.reserve(capacity);
}
#[allow(clippy::missing_const_for_fn)] pub fn receipts(&self) -> &[T] {
&self.receipts
}
pub fn logs(&self) -> impl Iterator<Item = &Log> {
self.receipts.iter().flat_map(|r| r.logs())
}
pub fn logs_bloom(&self) -> Bloom {
self.seal();
self.bloom.get().cloned().unwrap()
}
#[allow(clippy::missing_const_for_fn)] pub fn senders(&self) -> &[Address] {
&self.senders
}
pub fn cumulative_gas_used(&self) -> u64 {
self.receipts().last().map(TxReceipt::cumulative_gas_used).unwrap_or_default()
}
pub fn push_result(&mut self, receipt: T, sender: Address) {
self.unseal();
self.push_receipt(receipt);
self.push_sender(sender);
}
fn push_receipt(&mut self, receipt: T) {
self.receipts.push(receipt);
}
fn push_sender(&mut self, sender: Address) {
self.senders.push(sender);
}
pub fn find_deposit_requests(&self) -> impl Iterator<Item = Bytes> + use<'_, T> {
crate::system::eip6110::check_logs_for_deposits(
self.receipts().iter().flat_map(TxReceipt::logs),
)
}
pub fn into_parts(self) -> (Vec<T>, Vec<Address>, Bloom) {
let bloom = self.logs_bloom();
(self.receipts, self.senders, bloom)
}
}