reth_optimism_consensus/validation/
canyon.rs

1//! Canyon consensus rule checks.
2
3use alloy_consensus::BlockHeader;
4use alloy_trie::EMPTY_ROOT_HASH;
5use reth_consensus::ConsensusError;
6use reth_primitives_traits::{BlockBody, GotExpected};
7
8use crate::OpConsensusError;
9
10/// Verifies that withdrawals root in block header (Shanghai) is always [`EMPTY_ROOT_HASH`] in
11/// Canyon.
12#[inline]
13pub fn ensure_empty_withdrawals_root<H: BlockHeader>(header: &H) -> Result<(), ConsensusError> {
14    // Shanghai rule
15    let header_withdrawals_root =
16        &header.withdrawals_root().ok_or(ConsensusError::WithdrawalsRootMissing)?;
17
18    //  Canyon rules
19    if *header_withdrawals_root != EMPTY_ROOT_HASH {
20        return Err(ConsensusError::BodyWithdrawalsRootDiff(
21            GotExpected { got: *header_withdrawals_root, expected: EMPTY_ROOT_HASH }.into(),
22        ));
23    }
24
25    Ok(())
26}
27
28/// Verifies that withdrawals in block body (Shanghai) is always empty in Canyon.
29/// <https://specs.optimism.io/protocol/rollup-node-p2p.html#block-validation>
30#[inline]
31pub fn ensure_empty_shanghai_withdrawals<T: BlockBody>(body: &T) -> Result<(), OpConsensusError> {
32    // Shanghai rule
33    let withdrawals = body.withdrawals().ok_or(ConsensusError::BodyWithdrawalsMissing)?;
34
35    //  Canyon rule
36    if !withdrawals.as_ref().is_empty() {
37        return Err(OpConsensusError::WithdrawalsNonEmpty)
38    }
39
40    Ok(())
41}