feat: consensus trait generic over NodePrimitives (#13026)

This commit is contained in:
Arsenii Kulikov
2024-11-30 02:26:36 +04:00
committed by GitHub
parent 55ddaab1e4
commit 5d71150355
26 changed files with 166 additions and 113 deletions

View File

@ -13,7 +13,7 @@ use reth_blockchain_tree::{
};
use reth_chainspec::ChainSpec;
use reth_config::config::StageConfig;
use reth_consensus::{test_utils::TestConsensus, Consensus};
use reth_consensus::{test_utils::TestConsensus, FullConsensus};
use reth_db::{test_utils::TempDatabase, DatabaseEnv as DE};
use reth_downloaders::{
bodies::bodies::BodiesDownloaderBuilder,
@ -332,7 +332,7 @@ where
let provider_factory =
create_test_provider_factory_with_chain_spec(self.base_config.chain_spec.clone());
let consensus: Arc<dyn Consensus> = match self.base_config.consensus {
let consensus: Arc<dyn FullConsensus> = match self.base_config.consensus {
TestConsensusConfig::Real => {
Arc::new(EthBeaconConsensus::new(Arc::clone(&self.base_config.chain_spec)))
}
@ -374,13 +374,17 @@ where
.into_task();
let body_downloader = BodiesDownloaderBuilder::default()
.build(client.clone(), consensus.clone(), provider_factory.clone())
.build(
client.clone(),
consensus.clone().as_consensus(),
provider_factory.clone(),
)
.into_task();
Pipeline::<MockNodeTypesWithDB>::builder().add_stages(DefaultStages::new(
provider_factory.clone(),
tip_rx.clone(),
Arc::clone(&consensus),
consensus.clone().as_consensus(),
header_downloader,
body_downloader,
executor_factory.clone(),

View File

@ -16,8 +16,8 @@ use alloy_consensus::Header;
use alloy_eips::eip7685::Requests;
use alloy_primitives::{BlockHash, BlockNumber, Bloom, B256, U256};
use reth_primitives::{
BlockBody, BlockWithSenders, GotExpected, GotExpectedBoxed, InvalidTransactionError, Receipt,
SealedBlock, SealedHeader,
BlockBody, BlockWithSenders, EthPrimitives, GotExpected, GotExpectedBoxed,
InvalidTransactionError, NodePrimitives, Receipt, SealedBlock, SealedHeader,
};
use reth_primitives_traits::constants::MINIMUM_GAS_LIMIT;
@ -28,7 +28,7 @@ pub mod noop;
/// test helpers for mocking consensus
pub mod test_utils;
/// Post execution input passed to [`Consensus::validate_block_post_execution`].
/// Post execution input passed to [`FullConsensus::validate_block_post_execution`].
#[derive(Debug)]
pub struct PostExecutionInput<'a, R = Receipt> {
/// Receipts of the block.
@ -44,11 +44,28 @@ impl<'a, R> PostExecutionInput<'a, R> {
}
}
/// [`Consensus`] implementation which knows full node primitives and is able to validation block's
/// execution outcome.
#[auto_impl::auto_impl(&, Arc)]
pub trait FullConsensus<N: NodePrimitives = EthPrimitives>:
AsConsensus<N::BlockHeader, N::BlockBody>
{
/// Validate a block considering world state, i.e. things that can not be checked before
/// execution.
///
/// See the Yellow Paper sections 4.3.2 "Holistic Validity".
///
/// Note: validating blocks does not include other validations of the Consensus
fn validate_block_post_execution(
&self,
block: &BlockWithSenders<N::Block>,
input: PostExecutionInput<'_, N::Receipt>,
) -> Result<(), ConsensusError>;
}
/// Consensus is a protocol that chooses canonical chain.
#[auto_impl::auto_impl(&, Arc)]
pub trait Consensus<H = Header, B = BlockBody>:
AsHeaderValidator<H> + HeaderValidator<H> + Debug + Send + Sync
{
pub trait Consensus<H = Header, B = BlockBody>: AsHeaderValidator<H> {
/// Ensures that body field values match the header.
fn validate_body_against_header(
&self,
@ -67,18 +84,6 @@ pub trait Consensus<H = Header, B = BlockBody>:
/// Note: validating blocks does not include other validations of the Consensus
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.
///
/// See the Yellow Paper sections 4.3.2 "Holistic Validity".
///
/// Note: validating blocks does not include other validations of the Consensus
fn validate_block_post_execution(
&self,
block: &BlockWithSenders,
input: PostExecutionInput<'_>,
) -> Result<(), ConsensusError>;
}
/// HeaderValidator is a protocol that validates headers and their relationships.
@ -162,6 +167,23 @@ impl<T: HeaderValidator<H>, H> AsHeaderValidator<H> for T {
}
}
/// Helper trait to cast `Arc<dyn FullConsensus>` to `Arc<dyn Consensus>`
pub trait AsConsensus<H, B>: Consensus<H, B> {
/// Converts the [`Arc`] of self to [`Arc`] of [`HeaderValidator`]
fn as_consensus<'a>(self: Arc<Self>) -> Arc<dyn Consensus<H, B> + 'a>
where
Self: 'a;
}
impl<T: Consensus<H, B>, H, B> AsConsensus<H, B> for T {
fn as_consensus<'a>(self: Arc<Self>) -> Arc<dyn Consensus<H, B> + 'a>
where
Self: 'a,
{
self
}
}
/// Consensus Errors
#[derive(Debug, PartialEq, Eq, Clone, derive_more::Display, derive_more::Error)]
pub enum ConsensusError {

View File

@ -1,6 +1,6 @@
use crate::{Consensus, ConsensusError, HeaderValidator, PostExecutionInput};
use crate::{Consensus, ConsensusError, FullConsensus, HeaderValidator, PostExecutionInput};
use alloy_primitives::U256;
use reth_primitives::{BlockWithSenders, SealedBlock, SealedHeader};
use reth_primitives::{BlockWithSenders, NodePrimitives, SealedBlock, SealedHeader};
/// A Consensus implementation that does nothing.
#[derive(Debug, Copy, Clone, Default)]
@ -44,11 +44,13 @@ impl<H, B> Consensus<H, B> for NoopConsensus {
) -> Result<(), ConsensusError> {
Ok(())
}
}
impl<N: NodePrimitives> FullConsensus<N> for NoopConsensus {
fn validate_block_post_execution(
&self,
_block: &BlockWithSenders,
_input: PostExecutionInput<'_>,
_block: &BlockWithSenders<N::Block>,
_input: PostExecutionInput<'_, N::Receipt>,
) -> Result<(), ConsensusError> {
Ok(())
}

View File

@ -1,7 +1,7 @@
use crate::{Consensus, ConsensusError, HeaderValidator, PostExecutionInput};
use crate::{Consensus, ConsensusError, FullConsensus, HeaderValidator, PostExecutionInput};
use alloy_primitives::U256;
use core::sync::atomic::{AtomicBool, Ordering};
use reth_primitives::{BlockWithSenders, SealedBlock, SealedHeader};
use reth_primitives::{BlockWithSenders, NodePrimitives, SealedBlock, SealedHeader};
/// Consensus engine implementation for testing
#[derive(Debug)]
@ -46,6 +46,20 @@ impl TestConsensus {
}
}
impl<N: NodePrimitives> FullConsensus<N> for TestConsensus {
fn validate_block_post_execution(
&self,
_block: &BlockWithSenders<N::Block>,
_input: PostExecutionInput<'_, N::Receipt>,
) -> Result<(), ConsensusError> {
if self.fail_validation() {
Err(ConsensusError::BaseFeeMissing)
} else {
Ok(())
}
}
}
impl<H, B> Consensus<H, B> for TestConsensus {
fn validate_body_against_header(
&self,
@ -69,18 +83,6 @@ impl<H, B> Consensus<H, B> for TestConsensus {
Ok(())
}
}
fn validate_block_post_execution(
&self,
_block: &BlockWithSenders,
_input: PostExecutionInput<'_>,
) -> Result<(), ConsensusError> {
if self.fail_validation() {
Err(ConsensusError::BaseFeeMissing)
} else {
Ok(())
}
}
}
impl<H> HeaderValidator<H> for TestConsensus {