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}