mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: make Consensus trait generic over block parts (#12451)
This commit is contained in:
@ -4,7 +4,9 @@ use alloy_consensus::constants::MAXIMUM_EXTRA_DATA_SIZE;
|
||||
use alloy_eips::eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK};
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||
use reth_consensus::ConsensusError;
|
||||
use reth_primitives::{EthereumHardfork, GotExpected, Header, SealedBlock, SealedHeader};
|
||||
use reth_primitives::{
|
||||
BlockBody, EthereumHardfork, GotExpected, Header, SealedBlock, 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.
|
||||
@ -73,6 +75,49 @@ pub fn validate_cancun_gas(block: &SealedBlock) -> Result<(), ConsensusError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensures the block response data matches the header.
|
||||
///
|
||||
/// This ensures the body response items match the header's hashes:
|
||||
/// - ommer hash
|
||||
/// - transaction root
|
||||
/// - withdrawals root
|
||||
pub fn validate_body_against_header(
|
||||
body: &BlockBody,
|
||||
header: &SealedHeader,
|
||||
) -> Result<(), ConsensusError> {
|
||||
let ommers_hash = body.calculate_ommers_root();
|
||||
if header.ommers_hash != ommers_hash {
|
||||
return Err(ConsensusError::BodyOmmersHashDiff(
|
||||
GotExpected { got: ommers_hash, expected: header.ommers_hash }.into(),
|
||||
))
|
||||
}
|
||||
|
||||
let tx_root = body.calculate_tx_root();
|
||||
if header.transactions_root != tx_root {
|
||||
return Err(ConsensusError::BodyTransactionRootDiff(
|
||||
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);
|
||||
if withdrawals_root != header_withdrawals_root {
|
||||
return Err(ConsensusError::BodyWithdrawalsRootDiff(
|
||||
GotExpected { got: withdrawals_root, expected: header_withdrawals_root }.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
(None, None) => {
|
||||
// this is ok because we assume the fork is not active in this case
|
||||
}
|
||||
_ => return Err(ConsensusError::WithdrawalsRootUnexpected),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate a block without regard for state:
|
||||
///
|
||||
/// - Compares the ommer hash in the block header to the block body
|
||||
|
||||
@ -15,8 +15,8 @@ use alloc::{fmt::Debug, vec::Vec};
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::{BlockHash, BlockNumber, Bloom, B256, U256};
|
||||
use reth_primitives::{
|
||||
constants::MINIMUM_GAS_LIMIT, BlockWithSenders, GotExpected, GotExpectedBoxed, Header,
|
||||
InvalidTransactionError, Receipt, SealedBlock, SealedHeader,
|
||||
constants::MINIMUM_GAS_LIMIT, BlockBody, BlockWithSenders, GotExpected, GotExpectedBoxed,
|
||||
Header, InvalidTransactionError, Receipt, SealedBlock, SealedHeader,
|
||||
};
|
||||
|
||||
/// A consensus implementation that does nothing.
|
||||
@ -44,11 +44,11 @@ impl<'a> PostExecutionInput<'a> {
|
||||
|
||||
/// Consensus is a protocol that chooses canonical chain.
|
||||
#[auto_impl::auto_impl(&, Arc)]
|
||||
pub trait Consensus: Debug + Send + Sync {
|
||||
pub trait Consensus<H = Header, B = BlockBody>: Debug + Send + Sync {
|
||||
/// Validate if header is correct and follows consensus specification.
|
||||
///
|
||||
/// This is called on standalone header to check if all hashes are correct.
|
||||
fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError>;
|
||||
fn validate_header(&self, header: &SealedHeader<H>) -> Result<(), ConsensusError>;
|
||||
|
||||
/// Validate that the header information regarding parent are correct.
|
||||
/// This checks the block number, timestamp, basefee and gas limit increment.
|
||||
@ -61,8 +61,8 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// Note: Validating header against its parent does not include other Consensus validations.
|
||||
fn validate_header_against_parent(
|
||||
&self,
|
||||
header: &SealedHeader,
|
||||
parent: &SealedHeader,
|
||||
header: &SealedHeader<H>,
|
||||
parent: &SealedHeader<H>,
|
||||
) -> Result<(), ConsensusError>;
|
||||
|
||||
/// Validates the given headers
|
||||
@ -71,7 +71,13 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// on its own and valid against its parent.
|
||||
///
|
||||
/// Note: this expects that the headers are in natural order (ascending block number)
|
||||
fn validate_header_range(&self, headers: &[SealedHeader]) -> Result<(), HeaderConsensusError> {
|
||||
fn validate_header_range(
|
||||
&self,
|
||||
headers: &[SealedHeader<H>],
|
||||
) -> Result<(), HeaderConsensusError<H>>
|
||||
where
|
||||
H: Clone,
|
||||
{
|
||||
if let Some((initial_header, remaining_headers)) = headers.split_first() {
|
||||
self.validate_header(initial_header)
|
||||
.map_err(|e| HeaderConsensusError(e, initial_header.clone()))?;
|
||||
@ -94,10 +100,17 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// Note: validating headers with TD does not include other Consensus validation.
|
||||
fn validate_header_with_total_difficulty(
|
||||
&self,
|
||||
header: &Header,
|
||||
header: &H,
|
||||
total_difficulty: U256,
|
||||
) -> Result<(), ConsensusError>;
|
||||
|
||||
/// Ensures that body field values match the header.
|
||||
fn validate_body_against_header(
|
||||
&self,
|
||||
body: &B,
|
||||
header: &SealedHeader<H>,
|
||||
) -> Result<(), ConsensusError>;
|
||||
|
||||
/// Validate a block disregarding world state, i.e. things that can be checked before sender
|
||||
/// recovery and execution.
|
||||
///
|
||||
@ -107,7 +120,8 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// **This should not be called for the genesis block**.
|
||||
///
|
||||
/// Note: validating blocks does not include other validations of the Consensus
|
||||
fn validate_block_pre_execution(&self, block: &SealedBlock) -> Result<(), ConsensusError>;
|
||||
fn validate_block_pre_execution(&self, block: &SealedBlock<H, B>)
|
||||
-> Result<(), ConsensusError>;
|
||||
|
||||
/// Validate a block considering world state, i.e. things that can not be checked before
|
||||
/// execution.
|
||||
@ -407,4 +421,4 @@ impl From<InvalidTransactionError> for ConsensusError {
|
||||
/// `HeaderConsensusError` combines a `ConsensusError` with the `SealedHeader` it relates to.
|
||||
#[derive(derive_more::Display, derive_more::Error, Debug)]
|
||||
#[display("Consensus error: {_0}, Invalid header: {_1:?}")]
|
||||
pub struct HeaderConsensusError(ConsensusError, SealedHeader);
|
||||
pub struct HeaderConsensusError<H>(ConsensusError, SealedHeader<H>);
|
||||
|
||||
@ -1,34 +1,45 @@
|
||||
use crate::{Consensus, ConsensusError, PostExecutionInput};
|
||||
use alloy_primitives::U256;
|
||||
use reth_primitives::{BlockWithSenders, Header, SealedBlock, SealedHeader};
|
||||
use reth_primitives::{BlockWithSenders, SealedBlock, SealedHeader};
|
||||
|
||||
/// A Consensus implementation that does nothing.
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct NoopConsensus;
|
||||
|
||||
impl Consensus for NoopConsensus {
|
||||
fn validate_header(&self, _header: &SealedHeader) -> Result<(), ConsensusError> {
|
||||
impl<H, B> Consensus<H, B> for NoopConsensus {
|
||||
fn validate_header(&self, _header: &SealedHeader<H>) -> Result<(), ConsensusError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_header_against_parent(
|
||||
&self,
|
||||
_header: &SealedHeader,
|
||||
_parent: &SealedHeader,
|
||||
_header: &SealedHeader<H>,
|
||||
_parent: &SealedHeader<H>,
|
||||
) -> Result<(), ConsensusError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_header_with_total_difficulty(
|
||||
&self,
|
||||
_header: &Header,
|
||||
_header: &H,
|
||||
_total_difficulty: U256,
|
||||
) -> Result<(), ConsensusError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_block_pre_execution(&self, _block: &SealedBlock) -> Result<(), ConsensusError> {
|
||||
fn validate_body_against_header(
|
||||
&self,
|
||||
_body: &B,
|
||||
_header: &SealedHeader<H>,
|
||||
) -> Result<(), ConsensusError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_block_pre_execution(
|
||||
&self,
|
||||
_block: &SealedBlock<H, B>,
|
||||
) -> Result<(), ConsensusError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
use crate::{Consensus, ConsensusError, PostExecutionInput};
|
||||
use alloy_primitives::U256;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use reth_primitives::{BlockWithSenders, Header, SealedBlock, SealedHeader};
|
||||
use reth_primitives::{BlockWithSenders, SealedBlock, SealedHeader};
|
||||
|
||||
/// Consensus engine implementation for testing
|
||||
#[derive(Debug)]
|
||||
pub struct TestConsensus {
|
||||
/// Flag whether the header validation should purposefully fail
|
||||
fail_validation: AtomicBool,
|
||||
/// Separate flag for setting whether `validate_body_against_header` should fail. It is needed
|
||||
/// for testing networking logic for which the body failing this check is getting completely
|
||||
/// rejected while more high-level failures are handled by the sync logic.
|
||||
fail_body_against_header: AtomicBool,
|
||||
}
|
||||
|
||||
impl Default for TestConsensus {
|
||||
fn default() -> Self {
|
||||
Self { fail_validation: AtomicBool::new(false) }
|
||||
Self {
|
||||
fail_validation: AtomicBool::new(false),
|
||||
fail_body_against_header: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,12 +31,23 @@ impl TestConsensus {
|
||||
|
||||
/// Update the validation flag.
|
||||
pub fn set_fail_validation(&self, val: bool) {
|
||||
self.fail_validation.store(val, Ordering::SeqCst)
|
||||
self.fail_validation.store(val, Ordering::SeqCst);
|
||||
self.fail_body_against_header.store(val, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// Returns the body validation flag.
|
||||
pub fn fail_body_against_header(&self) -> bool {
|
||||
self.fail_body_against_header.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Update the body validation flag.
|
||||
pub fn set_fail_body_against_header(&self, val: bool) {
|
||||
self.fail_body_against_header.store(val, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
impl Consensus for TestConsensus {
|
||||
fn validate_header(&self, _header: &SealedHeader) -> Result<(), ConsensusError> {
|
||||
impl<H, B> Consensus<H, B> for TestConsensus {
|
||||
fn validate_header(&self, _header: &SealedHeader<H>) -> Result<(), ConsensusError> {
|
||||
if self.fail_validation() {
|
||||
Err(ConsensusError::BaseFeeMissing)
|
||||
} else {
|
||||
@ -39,8 +57,8 @@ impl Consensus for TestConsensus {
|
||||
|
||||
fn validate_header_against_parent(
|
||||
&self,
|
||||
_header: &SealedHeader,
|
||||
_parent: &SealedHeader,
|
||||
_header: &SealedHeader<H>,
|
||||
_parent: &SealedHeader<H>,
|
||||
) -> Result<(), ConsensusError> {
|
||||
if self.fail_validation() {
|
||||
Err(ConsensusError::BaseFeeMissing)
|
||||
@ -51,7 +69,7 @@ impl Consensus for TestConsensus {
|
||||
|
||||
fn validate_header_with_total_difficulty(
|
||||
&self,
|
||||
_header: &Header,
|
||||
_header: &H,
|
||||
_total_difficulty: U256,
|
||||
) -> Result<(), ConsensusError> {
|
||||
if self.fail_validation() {
|
||||
@ -61,7 +79,22 @@ impl Consensus for TestConsensus {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_block_pre_execution(&self, _block: &SealedBlock) -> Result<(), ConsensusError> {
|
||||
fn validate_body_against_header(
|
||||
&self,
|
||||
_body: &B,
|
||||
_header: &SealedHeader<H>,
|
||||
) -> Result<(), ConsensusError> {
|
||||
if self.fail_body_against_header() {
|
||||
Err(ConsensusError::BaseFeeMissing)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_block_pre_execution(
|
||||
&self,
|
||||
_block: &SealedBlock<H, B>,
|
||||
) -> Result<(), ConsensusError> {
|
||||
if self.fail_validation() {
|
||||
Err(ConsensusError::BaseFeeMissing)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user