chore: relax more consensus functions (#13236)

This commit is contained in:
Matthias Seitz
2024-12-09 19:26:32 +01:00
committed by GitHub
parent a3e90e18b6
commit 3af2afe995
5 changed files with 79 additions and 61 deletions

View File

@ -13,8 +13,8 @@ workspace = true
[dependencies] [dependencies]
# reth # reth
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-primitives.workspace = true
reth-consensus.workspace = true reth-consensus.workspace = true
reth-primitives.workspace = true
# ethereum # ethereum
alloy-primitives.workspace = true alloy-primitives.workspace = true
@ -24,8 +24,8 @@ alloy-consensus.workspace = true
alloy-eips.workspace = true alloy-eips.workspace = true
[dev-dependencies] [dev-dependencies]
alloy-consensus.workspace = true
reth-storage-api.workspace = true reth-storage-api.workspace = true
rand.workspace = true rand.workspace = true
mockall = "0.13" mockall = "0.13"
alloy-consensus.workspace = true

View File

@ -1,14 +1,14 @@
//! Collection of methods for block validation. //! 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::{ use alloy_eips::{
calc_next_block_base_fee, calc_next_block_base_fee,
eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}, 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_consensus::ConsensusError;
use reth_primitives::{BlockBody, EthereumHardfork, GotExpected, SealedBlock, SealedHeader}; use reth_primitives::SealedBlock;
use reth_primitives_traits::BlockBody as _; use reth_primitives_traits::{BlockBody, GotExpected, SealedHeader};
use revm_primitives::calc_excess_blob_gas; 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. /// Gas used needs to be less than gas limit. Gas used is going to be checked after execution.
@ -43,11 +43,11 @@ pub fn validate_header_base_fee<H: BlockHeader, ChainSpec: EthereumHardforks>(
/// ///
/// [EIP-4895]: https://eips.ethereum.org/EIPS/eip-4895 /// [EIP-4895]: https://eips.ethereum.org/EIPS/eip-4895
#[inline] #[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>, block: &SealedBlock<H, B>,
) -> Result<(), ConsensusError> { ) -> Result<(), ConsensusError> {
let withdrawals = block.body.withdrawals().ok_or(ConsensusError::BodyWithdrawalsMissing)?; 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 = let header_withdrawals_root =
block.withdrawals_root().ok_or(ConsensusError::WithdrawalsRootMissing)?; block.withdrawals_root().ok_or(ConsensusError::WithdrawalsRootMissing)?;
if withdrawals_root != *header_withdrawals_root { if withdrawals_root != *header_withdrawals_root {
@ -64,7 +64,7 @@ pub fn validate_shanghai_withdrawals<H: BlockHeader, B: reth_primitives_traits::
/// ///
/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844
#[inline] #[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>, block: &SealedBlock<H, B>,
) -> Result<(), ConsensusError> { ) -> Result<(), ConsensusError> {
// Check that the blob gas used in the header matches the sum of the blob gas used by each // Check that the blob gas used in the header matches the sum of the blob gas used by each
@ -87,28 +87,31 @@ pub fn validate_cancun_gas<H: BlockHeader, B: reth_primitives_traits::BlockBody>
/// - ommer hash /// - ommer hash
/// - transaction root /// - transaction root
/// - withdrawals root /// - withdrawals root
pub fn validate_body_against_header( pub fn validate_body_against_header<B, H>(body: &B, header: &H) -> Result<(), ConsensusError>
body: &BlockBody, where
header: &SealedHeader, B: BlockBody,
) -> Result<(), ConsensusError> { H: BlockHeader,
{
let ommers_hash = body.calculate_ommers_root(); let ommers_hash = body.calculate_ommers_root();
if header.ommers_hash != ommers_hash { if Some(header.ommers_hash()) != ommers_hash {
return Err(ConsensusError::BodyOmmersHashDiff( 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(); let tx_root = body.calculate_tx_root();
if header.transactions_root != tx_root { if header.transactions_root() != tx_root {
return Err(ConsensusError::BodyTransactionRootDiff( 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) { match (header.withdrawals_root(), body.calculate_withdrawals_root()) {
(Some(header_withdrawals_root), Some(withdrawals)) => { (Some(header_withdrawals_root), Some(withdrawals_root)) => {
let withdrawals = withdrawals.as_slice();
let withdrawals_root = reth_primitives::proofs::calculate_withdrawals_root(withdrawals);
if withdrawals_root != header_withdrawals_root { if withdrawals_root != header_withdrawals_root {
return Err(ConsensusError::BodyWithdrawalsRootDiff( return Err(ConsensusError::BodyWithdrawalsRootDiff(
GotExpected { got: withdrawals_root, expected: header_withdrawals_root }.into(), GotExpected { got: withdrawals_root, expected: header_withdrawals_root }.into(),
@ -130,15 +133,24 @@ pub fn validate_body_against_header(
/// - Compares the transactions root in the block header to the block body /// - Compares the transactions root in the block header to the block body
/// - Pre-execution transaction validation /// - Pre-execution transaction validation
/// - (Optionally) Compares the receipts root in the block header to the block body /// - (Optionally) Compares the receipts root in the block header to the block body
pub fn validate_block_pre_execution<ChainSpec: EthereumHardforks>( pub fn validate_block_pre_execution<H, B, ChainSpec>(
block: &SealedBlock, block: &SealedBlock<H, B>,
chain_spec: &ChainSpec, chain_spec: &ChainSpec,
) -> Result<(), ConsensusError> { ) -> Result<(), ConsensusError>
where
H: BlockHeader,
B: BlockBody,
ChainSpec: EthereumHardforks,
{
// Check ommers hash // Check ommers hash
let ommers_hash = block.body.calculate_ommers_root(); 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( 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(),
)) ))
} }
@ -148,11 +160,11 @@ pub fn validate_block_pre_execution<ChainSpec: EthereumHardforks>(
} }
// EIP-4895: Beacon chain push withdrawals as operations // 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)?; 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)?; validate_cancun_gas(block)?;
} }
@ -222,12 +234,12 @@ pub fn validate_header_extradata<H: BlockHeader>(header: &H) -> Result<(), Conse
#[inline] #[inline]
pub fn validate_against_parent_hash_number<H: BlockHeader>( pub fn validate_against_parent_hash_number<H: BlockHeader>(
header: &H, header: &H,
parent: &SealedHeader, parent: &SealedHeader<H>,
) -> Result<(), ConsensusError> { ) -> Result<(), ConsensusError> {
// Parent number is consistent. // Parent number is consistent.
if parent.number + 1 != header.number() { if parent.number() + 1 != header.number() {
return Err(ConsensusError::ParentBlockNumberMismatch { return Err(ConsensusError::ParentBlockNumberMismatch {
parent_block_number: parent.number, parent_block_number: parent.number(),
block_number: header.number(), block_number: header.number(),
}) })
} }

View File

@ -121,7 +121,7 @@ impl<ChainSpec: Send + Sync + EthChainSpec + EthereumHardforks + Debug> Consensu
body: &BlockBody, body: &BlockBody,
header: &SealedHeader, header: &SealedHeader,
) -> Result<(), ConsensusError> { ) -> 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> { fn validate_block_pre_execution(&self, block: &SealedBlock) -> Result<(), ConsensusError> {

View File

@ -65,7 +65,7 @@ impl Consensus for OpBeaconConsensus {
body: &BlockBody, body: &BlockBody,
header: &SealedHeader, header: &SealedHeader,
) -> Result<(), ConsensusError> { ) -> 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> { fn validate_block_pre_execution(&self, block: &SealedBlock) -> Result<(), ConsensusError> {

View File

@ -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> impl<H, B> SealedBlock<H, B>
where where
H: reth_primitives_traits::BlockHeader, H: reth_primitives_traits::BlockHeader,
@ -385,34 +419,6 @@ where
Block::new(self.header.unseal(), self.body) 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. /// Returns a vector of encoded 2718 transactions.
/// ///
/// This is also known as `raw transactions`. /// This is also known as `raw transactions`.