reth_optimism_consensus/
validation.rsuse crate::proof::calculate_receipt_root_optimism;
use alloy_consensus::TxReceipt;
use alloy_primitives::{Bloom, B256};
use reth_chainspec::{ChainSpec, EthereumHardforks};
use reth_consensus::ConsensusError;
use reth_primitives::{gas_spent_by_transactions, BlockWithSenders, GotExpected, Receipt};
pub fn validate_block_post_execution(
block: &BlockWithSenders,
chain_spec: &ChainSpec,
receipts: &[Receipt],
) -> Result<(), ConsensusError> {
if chain_spec.is_byzantium_active_at_block(block.header.number) {
if let Err(error) = verify_receipts(
block.header.receipts_root,
block.header.logs_bloom,
receipts,
chain_spec,
block.timestamp,
) {
tracing::debug!(%error, ?receipts, "receipts verification failed");
return Err(error)
}
}
let cumulative_gas_used =
receipts.last().map(|receipt| receipt.cumulative_gas_used).unwrap_or(0);
if block.gas_used != cumulative_gas_used {
return Err(ConsensusError::BlockGasUsed {
gas: GotExpected { got: cumulative_gas_used, expected: block.gas_used },
gas_spent_by_tx: gas_spent_by_transactions(receipts),
})
}
Ok(())
}
fn verify_receipts(
expected_receipts_root: B256,
expected_logs_bloom: Bloom,
receipts: &[Receipt],
chain_spec: &ChainSpec,
timestamp: u64,
) -> Result<(), ConsensusError> {
let receipts_with_bloom = receipts.iter().cloned().map(Receipt::with_bloom).collect::<Vec<_>>();
let receipts_root =
calculate_receipt_root_optimism(&receipts_with_bloom, chain_spec, timestamp);
let logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | r.bloom());
compare_receipts_root_and_logs_bloom(
receipts_root,
logs_bloom,
expected_receipts_root,
expected_logs_bloom,
)?;
Ok(())
}
fn compare_receipts_root_and_logs_bloom(
calculated_receipts_root: B256,
calculated_logs_bloom: Bloom,
expected_receipts_root: B256,
expected_logs_bloom: Bloom,
) -> Result<(), ConsensusError> {
if calculated_receipts_root != expected_receipts_root {
return Err(ConsensusError::BodyReceiptRootDiff(
GotExpected { got: calculated_receipts_root, expected: expected_receipts_root }.into(),
))
}
if calculated_logs_bloom != expected_logs_bloom {
return Err(ConsensusError::BodyBloomLogDiff(
GotExpected { got: calculated_logs_bloom, expected: expected_logs_bloom }.into(),
))
}
Ok(())
}