Skip to content

Commit

Permalink
chore: relax more consensus functions (#13236)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse authored Dec 9, 2024
1 parent a3e90e1 commit 3af2afe
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 61 deletions.
4 changes: 2 additions & 2 deletions crates/consensus/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ workspace = true
[dependencies]
# reth
reth-chainspec.workspace = true
reth-primitives.workspace = true
reth-consensus.workspace = true
reth-primitives.workspace = true

# ethereum
alloy-primitives.workspace = true
Expand All @@ -24,8 +24,8 @@ alloy-consensus.workspace = true
alloy-eips.workspace = true

[dev-dependencies]
alloy-consensus.workspace = true
reth-storage-api.workspace = true
rand.workspace = true
mockall = "0.13"

alloy-consensus.workspace = true
70 changes: 41 additions & 29 deletions crates/consensus/common/src/validation.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Collection of methods for block validation.
use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, BlockHeader};
use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, BlockHeader, EMPTY_OMMER_ROOT_HASH};
use alloy_eips::{
calc_next_block_base_fee,
eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK},
};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_chainspec::{EthChainSpec, EthereumHardfork, EthereumHardforks};
use reth_consensus::ConsensusError;
use reth_primitives::{BlockBody, EthereumHardfork, GotExpected, SealedBlock, SealedHeader};
use reth_primitives_traits::BlockBody as _;
use reth_primitives::SealedBlock;
use reth_primitives_traits::{BlockBody, GotExpected, SealedHeader};
use revm_primitives::calc_excess_blob_gas;

/// Gas used needs to be less than gas limit. Gas used is going to be checked after execution.
Expand Down Expand Up @@ -43,11 +43,11 @@ pub fn validate_header_base_fee<H: BlockHeader, ChainSpec: EthereumHardforks>(
///
/// [EIP-4895]: https://eips.ethereum.org/EIPS/eip-4895
#[inline]
pub fn validate_shanghai_withdrawals<H: BlockHeader, B: reth_primitives_traits::BlockBody>(
pub fn validate_shanghai_withdrawals<H: BlockHeader, B: BlockBody>(
block: &SealedBlock<H, B>,
) -> Result<(), ConsensusError> {
let withdrawals = block.body.withdrawals().ok_or(ConsensusError::BodyWithdrawalsMissing)?;
let withdrawals_root = reth_primitives::proofs::calculate_withdrawals_root(withdrawals);
let withdrawals_root = alloy_consensus::proofs::calculate_withdrawals_root(withdrawals);
let header_withdrawals_root =
block.withdrawals_root().ok_or(ConsensusError::WithdrawalsRootMissing)?;
if withdrawals_root != *header_withdrawals_root {
Expand All @@ -64,7 +64,7 @@ pub fn validate_shanghai_withdrawals<H: BlockHeader, B: reth_primitives_traits::
///
/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
#[inline]
pub fn validate_cancun_gas<H: BlockHeader, B: reth_primitives_traits::BlockBody>(
pub fn validate_cancun_gas<H: BlockHeader, B: BlockBody>(
block: &SealedBlock<H, B>,
) -> Result<(), ConsensusError> {
// Check that the blob gas used in the header matches the sum of the blob gas used by each
Expand All @@ -87,28 +87,31 @@ pub fn validate_cancun_gas<H: BlockHeader, B: reth_primitives_traits::BlockBody>
/// - ommer hash
/// - transaction root
/// - withdrawals root
pub fn validate_body_against_header(
body: &BlockBody,
header: &SealedHeader,
) -> Result<(), ConsensusError> {
pub fn validate_body_against_header<B, H>(body: &B, header: &H) -> Result<(), ConsensusError>
where
B: BlockBody,
H: BlockHeader,
{
let ommers_hash = body.calculate_ommers_root();
if header.ommers_hash != ommers_hash {
if Some(header.ommers_hash()) != ommers_hash {
return Err(ConsensusError::BodyOmmersHashDiff(
GotExpected { got: ommers_hash, expected: header.ommers_hash }.into(),
GotExpected {
got: ommers_hash.unwrap_or(EMPTY_OMMER_ROOT_HASH),
expected: header.ommers_hash(),
}
.into(),
))
}

let tx_root = body.calculate_tx_root();
if header.transactions_root != tx_root {
if header.transactions_root() != tx_root {
return Err(ConsensusError::BodyTransactionRootDiff(
GotExpected { got: tx_root, expected: header.transactions_root }.into(),
GotExpected { got: tx_root, expected: header.transactions_root() }.into(),
))
}

match (header.withdrawals_root, &body.withdrawals) {
(Some(header_withdrawals_root), Some(withdrawals)) => {
let withdrawals = withdrawals.as_slice();
let withdrawals_root = reth_primitives::proofs::calculate_withdrawals_root(withdrawals);
match (header.withdrawals_root(), body.calculate_withdrawals_root()) {
(Some(header_withdrawals_root), Some(withdrawals_root)) => {
if withdrawals_root != header_withdrawals_root {
return Err(ConsensusError::BodyWithdrawalsRootDiff(
GotExpected { got: withdrawals_root, expected: header_withdrawals_root }.into(),
Expand All @@ -130,15 +133,24 @@ pub fn validate_body_against_header(
/// - Compares the transactions root in the block header to the block body
/// - Pre-execution transaction validation
/// - (Optionally) Compares the receipts root in the block header to the block body
pub fn validate_block_pre_execution<ChainSpec: EthereumHardforks>(
block: &SealedBlock,
pub fn validate_block_pre_execution<H, B, ChainSpec>(
block: &SealedBlock<H, B>,
chain_spec: &ChainSpec,
) -> Result<(), ConsensusError> {
) -> Result<(), ConsensusError>
where
H: BlockHeader,
B: BlockBody,
ChainSpec: EthereumHardforks,
{
// Check ommers hash
let ommers_hash = block.body.calculate_ommers_root();
if block.header.ommers_hash != ommers_hash {
if Some(block.header.ommers_hash()) != ommers_hash {
return Err(ConsensusError::BodyOmmersHashDiff(
GotExpected { got: ommers_hash, expected: block.header.ommers_hash }.into(),
GotExpected {
got: ommers_hash.unwrap_or(EMPTY_OMMER_ROOT_HASH),
expected: block.header.ommers_hash(),
}
.into(),
))
}

Expand All @@ -148,11 +160,11 @@ pub fn validate_block_pre_execution<ChainSpec: EthereumHardforks>(
}

// EIP-4895: Beacon chain push withdrawals as operations
if chain_spec.is_shanghai_active_at_timestamp(block.timestamp) {
if chain_spec.is_shanghai_active_at_timestamp(block.timestamp()) {
validate_shanghai_withdrawals(block)?;
}

if chain_spec.is_cancun_active_at_timestamp(block.timestamp) {
if chain_spec.is_cancun_active_at_timestamp(block.timestamp()) {
validate_cancun_gas(block)?;
}

Expand Down Expand Up @@ -222,12 +234,12 @@ pub fn validate_header_extradata<H: BlockHeader>(header: &H) -> Result<(), Conse
#[inline]
pub fn validate_against_parent_hash_number<H: BlockHeader>(
header: &H,
parent: &SealedHeader,
parent: &SealedHeader<H>,
) -> Result<(), ConsensusError> {
// Parent number is consistent.
if parent.number + 1 != header.number() {
if parent.number() + 1 != header.number() {
return Err(ConsensusError::ParentBlockNumberMismatch {
parent_block_number: parent.number,
parent_block_number: parent.number(),
block_number: header.number(),
})
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ethereum/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl<ChainSpec: Send + Sync + EthChainSpec + EthereumHardforks + Debug> Consensu
body: &BlockBody,
header: &SealedHeader,
) -> Result<(), ConsensusError> {
validate_body_against_header(body, header)
validate_body_against_header(body, header.header())
}

fn validate_block_pre_execution(&self, block: &SealedBlock) -> Result<(), ConsensusError> {
Expand Down
2 changes: 1 addition & 1 deletion crates/optimism/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl Consensus for OpBeaconConsensus {
body: &BlockBody,
header: &SealedHeader,
) -> Result<(), ConsensusError> {
validate_body_against_header(body, header)
validate_body_against_header(body, header.header())
}

fn validate_block_pre_execution(&self, block: &SealedBlock) -> Result<(), ConsensusError> {
Expand Down
62 changes: 34 additions & 28 deletions crates/primitives/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,40 @@ impl SealedBlock {
}
}

impl<H, B> SealedBlock<H, B>
where
H: alloy_consensus::BlockHeader,
B: reth_primitives_traits::BlockBody,
{
/// Ensures that the transaction root in the block header is valid.
///
/// The transaction root is the Keccak 256-bit hash of the root node of the trie structure
/// populated with each transaction in the transactions list portion of the block.
///
/// # Returns
///
/// Returns `Ok(())` if the calculated transaction root matches the one stored in the header,
/// indicating that the transactions in the block are correctly represented in the trie.
///
/// Returns `Err(error)` if the transaction root validation fails, providing a `GotExpected`
/// error containing the calculated and expected roots.
pub fn ensure_transaction_root_valid(&self) -> Result<(), GotExpected<B256>>
where
B::Transaction: Encodable2718,
{
let calculated_root = self.body.calculate_tx_root();

if self.header.transactions_root() != calculated_root {
return Err(GotExpected {
got: calculated_root,
expected: self.header.transactions_root(),
})
}

Ok(())
}
}

impl<H, B> SealedBlock<H, B>
where
H: reth_primitives_traits::BlockHeader,
Expand Down Expand Up @@ -385,34 +419,6 @@ where
Block::new(self.header.unseal(), self.body)
}

/// Ensures that the transaction root in the block header is valid.
///
/// The transaction root is the Keccak 256-bit hash of the root node of the trie structure
/// populated with each transaction in the transactions list portion of the block.
///
/// # Returns
///
/// Returns `Ok(())` if the calculated transaction root matches the one stored in the header,
/// indicating that the transactions in the block are correctly represented in the trie.
///
/// Returns `Err(error)` if the transaction root validation fails, providing a `GotExpected`
/// error containing the calculated and expected roots.
pub fn ensure_transaction_root_valid(&self) -> Result<(), GotExpected<B256>>
where
B::Transaction: Encodable2718,
{
let calculated_root = self.body.calculate_tx_root();

if self.header.transactions_root() != calculated_root {
return Err(GotExpected {
got: calculated_root,
expected: self.header.transactions_root(),
})
}

Ok(())
}

/// Returns a vector of encoded 2718 transactions.
///
/// This is also known as `raw transactions`.
Expand Down

0 comments on commit 3af2afe

Please sign in to comment.