Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions crates/consensus/common/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use alloy_eips::{eip4844::DATA_GAS_PER_BLOB, eip7840::BlobParams};
use reth_chainspec::{EthChainSpec, EthereumHardfork, EthereumHardforks};
use reth_consensus::ConsensusError;
use reth_primitives_traits::{
constants::MAXIMUM_GAS_LIMIT_BLOCK, Block, BlockBody, BlockHeader, GotExpected, SealedBlock,
SealedHeader,
constants::{GAS_LIMIT_BOUND_DIVISOR, MAXIMUM_GAS_LIMIT_BLOCK, MINIMUM_GAS_LIMIT},
Block, BlockBody, BlockHeader, GotExpected, SealedBlock, SealedHeader,
};

/// The maximum RLP length of a block, defined in [EIP-7934](https://eips.ethereum.org/EIPS/eip-7934).
Expand Down Expand Up @@ -329,6 +329,54 @@ pub fn validate_against_parent_timestamp<H: BlockHeader>(
Ok(())
}

/// Validates gas limit against parent gas limit.
///
/// The maximum allowable difference between self and parent gas limits is determined by the
/// parent's gas limit divided by the [`GAS_LIMIT_BOUND_DIVISOR`].
#[inline]
pub fn validate_against_parent_gas_limit<
H: BlockHeader,
ChainSpec: EthChainSpec + EthereumHardforks,
>(
header: &SealedHeader<H>,
parent: &SealedHeader<H>,
chain_spec: &ChainSpec,
) -> Result<(), ConsensusError> {
// Determine the parent gas limit, considering elasticity multiplier on the London fork.
let parent_gas_limit = if !chain_spec.is_london_active_at_block(parent.number()) &&
chain_spec.is_london_active_at_block(header.number())
{
parent.gas_limit() *
chain_spec.base_fee_params_at_timestamp(header.timestamp()).elasticity_multiplier
as u64
} else {
parent.gas_limit()
};

// Check for an increase in gas limit beyond the allowed threshold.
if header.gas_limit() > parent_gas_limit {
if header.gas_limit() - parent_gas_limit >= parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR {
return Err(ConsensusError::GasLimitInvalidIncrease {
parent_gas_limit,
child_gas_limit: header.gas_limit(),
})
}
}
// Check for a decrease in gas limit beyond the allowed threshold.
else if parent_gas_limit - header.gas_limit() >= parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR {
return Err(ConsensusError::GasLimitInvalidDecrease {
parent_gas_limit,
child_gas_limit: header.gas_limit(),
})
}
// Check if the self gas limit is below the minimum required limit.
else if header.gas_limit() < MINIMUM_GAS_LIMIT {
return Err(ConsensusError::GasLimitInvalidMinimum { child_gas_limit: header.gas_limit() })
}

Ok(())
}

/// Validates that the EIP-4844 header fields are correct with respect to the parent block. This
/// ensures that the `blob_gas_used` and `excess_blob_gas` fields exist in the child header, and
/// that the `excess_blob_gas` field matches the expected `excess_blob_gas` calculated from the
Expand Down
81 changes: 18 additions & 63 deletions crates/ethereum/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_consensus::{Consensus, ConsensusError, FullConsensus, HeaderValidator};
use reth_consensus_common::validation::{
validate_4844_header_standalone, validate_against_parent_4844,
validate_against_parent_eip1559_base_fee, validate_against_parent_hash_number,
validate_against_parent_timestamp, validate_block_pre_execution, validate_body_against_header,
validate_header_base_fee, validate_header_extra_data, validate_header_gas,
validate_against_parent_eip1559_base_fee, validate_against_parent_gas_limit,
validate_against_parent_hash_number, validate_against_parent_timestamp,
validate_block_pre_execution, validate_body_against_header, validate_header_base_fee,
validate_header_extra_data, validate_header_gas,
};
use reth_execution_types::BlockExecutionResult;
use reth_primitives_traits::{
constants::{GAS_LIMIT_BOUND_DIVISOR, MINIMUM_GAS_LIMIT},
Block, BlockHeader, NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader,
};

Expand All @@ -46,53 +46,9 @@ impl<ChainSpec: EthChainSpec + EthereumHardforks> EthBeaconConsensus<ChainSpec>
Self { chain_spec }
}

/// Checks the gas limit for consistency between parent and self headers.
///
/// The maximum allowable difference between self and parent gas limits is determined by the
/// parent's gas limit divided by the [`GAS_LIMIT_BOUND_DIVISOR`].
fn validate_against_parent_gas_limit<H: BlockHeader>(
&self,
header: &SealedHeader<H>,
parent: &SealedHeader<H>,
) -> Result<(), ConsensusError> {
// Determine the parent gas limit, considering elasticity multiplier on the London fork.
let parent_gas_limit = if !self.chain_spec.is_london_active_at_block(parent.number()) &&
self.chain_spec.is_london_active_at_block(header.number())
{
parent.gas_limit() *
self.chain_spec
.base_fee_params_at_timestamp(header.timestamp())
.elasticity_multiplier as u64
} else {
parent.gas_limit()
};

// Check for an increase in gas limit beyond the allowed threshold.
if header.gas_limit() > parent_gas_limit {
if header.gas_limit() - parent_gas_limit >= parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR {
return Err(ConsensusError::GasLimitInvalidIncrease {
parent_gas_limit,
child_gas_limit: header.gas_limit(),
})
}
}
// Check for a decrease in gas limit beyond the allowed threshold.
else if parent_gas_limit - header.gas_limit() >=
parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR
{
return Err(ConsensusError::GasLimitInvalidDecrease {
parent_gas_limit,
child_gas_limit: header.gas_limit(),
})
}
// Check if the self gas limit is below the minimum required limit.
else if header.gas_limit() < MINIMUM_GAS_LIMIT {
return Err(ConsensusError::GasLimitInvalidMinimum {
child_gas_limit: header.gas_limit(),
})
}

Ok(())
/// Returns the chain spec associated with this consensus engine.
pub const fn chain_spec(&self) -> &Arc<ChainSpec> {
&self.chain_spec
}
}

Expand Down Expand Up @@ -220,7 +176,7 @@ where

validate_against_parent_timestamp(header.header(), parent.header())?;

self.validate_against_parent_gas_limit(header, parent)?;
validate_against_parent_gas_limit(header, parent, &self.chain_spec)?;

validate_against_parent_eip1559_base_fee(
header.header(),
Expand All @@ -242,7 +198,11 @@ mod tests {
use super::*;
use alloy_primitives::B256;
use reth_chainspec::{ChainSpec, ChainSpecBuilder};
use reth_primitives_traits::proofs;
use reth_consensus_common::validation::validate_against_parent_gas_limit;
use reth_primitives_traits::{
constants::{GAS_LIMIT_BOUND_DIVISOR, MINIMUM_GAS_LIMIT},
proofs,
};

fn header_with_gas_limit(gas_limit: u64) -> SealedHeader {
let header = reth_primitives_traits::Header { gas_limit, ..Default::default() };
Expand All @@ -255,8 +215,7 @@ mod tests {
let child = header_with_gas_limit((parent.gas_limit + 5) as u64);

assert_eq!(
EthBeaconConsensus::new(Arc::new(ChainSpec::default()))
.validate_against_parent_gas_limit(&child, &parent),
validate_against_parent_gas_limit(&child, &parent, &ChainSpec::default()),
Ok(())
);
}
Expand All @@ -267,8 +226,7 @@ mod tests {
let child = header_with_gas_limit(MINIMUM_GAS_LIMIT - 1);

assert_eq!(
EthBeaconConsensus::new(Arc::new(ChainSpec::default()))
.validate_against_parent_gas_limit(&child, &parent),
validate_against_parent_gas_limit(&child, &parent, &ChainSpec::default()),
Err(ConsensusError::GasLimitInvalidMinimum { child_gas_limit: child.gas_limit as u64 })
);
}
Expand All @@ -281,8 +239,7 @@ mod tests {
);

assert_eq!(
EthBeaconConsensus::new(Arc::new(ChainSpec::default()))
.validate_against_parent_gas_limit(&child, &parent),
validate_against_parent_gas_limit(&child, &parent, &ChainSpec::default()),
Err(ConsensusError::GasLimitInvalidIncrease {
parent_gas_limit: parent.gas_limit,
child_gas_limit: child.gas_limit,
Expand All @@ -296,8 +253,7 @@ mod tests {
let child = header_with_gas_limit(parent.gas_limit - 5);

assert_eq!(
EthBeaconConsensus::new(Arc::new(ChainSpec::default()))
.validate_against_parent_gas_limit(&child, &parent),
validate_against_parent_gas_limit(&child, &parent, &ChainSpec::default()),
Ok(())
);
}
Expand All @@ -310,8 +266,7 @@ mod tests {
);

assert_eq!(
EthBeaconConsensus::new(Arc::new(ChainSpec::default()))
.validate_against_parent_gas_limit(&child, &parent),
validate_against_parent_gas_limit(&child, &parent, &ChainSpec::default()),
Err(ConsensusError::GasLimitInvalidDecrease {
parent_gas_limit: parent.gas_limit,
child_gas_limit: child.gas_limit,
Expand Down