Skip to content

Commit

Permalink
feat: consensus trait generic over NodePrimitives (paradigmxyz#13026)
Browse files Browse the repository at this point in the history
  • Loading branch information
klkvr authored Nov 29, 2024
1 parent 55ddaab commit 5d71150
Show file tree
Hide file tree
Showing 26 changed files with 165 additions and 112 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions bin/reth/src/commands/debug_cmd/build_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use reth_chainspec::ChainSpec;
use reth_cli::chainspec::ChainSpecParser;
use reth_cli_commands::common::{AccessRights, CliNodeTypes, Environment, EnvironmentArgs};
use reth_cli_runner::CliContext;
use reth_consensus::Consensus;
use reth_consensus::{Consensus, FullConsensus};
use reth_errors::RethResult;
use reth_evm::execute::{BlockExecutorProvider, Executor};
use reth_execution_types::ExecutionOutcome;
Expand Down Expand Up @@ -128,7 +128,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
) -> eyre::Result<()> {
let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;

let consensus: Arc<dyn Consensus> =
let consensus: Arc<dyn FullConsensus> =
Arc::new(EthBeaconConsensus::new(provider_factory.chain_spec()));

let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec());
Expand Down
4 changes: 2 additions & 2 deletions bin/reth/src/commands/debug_cmd/replay_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use reth_cli_commands::common::{AccessRights, CliNodeTypes, Environment, Environ
use reth_cli_runner::CliContext;
use reth_cli_util::get_secret_key;
use reth_config::Config;
use reth_consensus::Consensus;
use reth_consensus::FullConsensus;
use reth_db::DatabaseEnv;
use reth_engine_util::engine_store::{EngineMessageStore, StoredEngineApiMessage};
use reth_fs_util as fs;
Expand Down Expand Up @@ -92,7 +92,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
let Environment { provider_factory, config, data_dir } =
self.env.init::<N>(AccessRights::RW)?;

let consensus: Arc<dyn Consensus> =
let consensus: Arc<dyn FullConsensus> =
Arc::new(EthBeaconConsensus::new(provider_factory.chain_spec()));

let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec());
Expand Down
2 changes: 1 addition & 1 deletion crates/blockchain-tree/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use reth_blockchain_tree_api::{
error::{BlockchainTreeError, InsertBlockErrorKind},
BlockAttachment, BlockValidationKind,
};
use reth_consensus::{Consensus, ConsensusError, PostExecutionInput};
use reth_consensus::{ConsensusError, PostExecutionInput};
use reth_evm::execute::{BlockExecutorProvider, Executor};
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::{Chain, ExecutionOutcome};
Expand Down
6 changes: 3 additions & 3 deletions crates/blockchain-tree/src/externals.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Blockchain tree externals.
use alloy_primitives::{BlockHash, BlockNumber};
use reth_consensus::Consensus;
use reth_consensus::FullConsensus;
use reth_db::{static_file::BlockHashMask, tables};
use reth_db_api::{cursor::DbCursorRO, transaction::DbTx};
use reth_node_types::NodeTypesWithDB;
Expand All @@ -28,7 +28,7 @@ pub struct TreeExternals<N: NodeTypesWithDB, E> {
/// The provider factory, used to commit the canonical chain, or unwind it.
pub(crate) provider_factory: ProviderFactory<N>,
/// The consensus engine.
pub(crate) consensus: Arc<dyn Consensus>,
pub(crate) consensus: Arc<dyn FullConsensus>,
/// The executor factory to execute blocks with.
pub(crate) executor_factory: E,
}
Expand All @@ -37,7 +37,7 @@ impl<N: ProviderNodeTypes, E> TreeExternals<N, E> {
/// Create new tree externals.
pub fn new(
provider_factory: ProviderFactory<N>,
consensus: Arc<dyn Consensus>,
consensus: Arc<dyn FullConsensus>,
executor_factory: E,
) -> Self {
Self { provider_factory, consensus, executor_factory }
Expand Down
12 changes: 8 additions & 4 deletions crates/consensus/beacon/src/engine/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)))
}
Expand Down Expand Up @@ -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(),
Expand Down
58 changes: 40 additions & 18 deletions crates/consensus/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand All @@ -44,11 +44,28 @@ impl<'a, R> PostExecutionInput<'a, R> {
}
}

/// Consensus is a protocol that chooses canonical chain.
/// [`Consensus`] implementation which knows full node primitives and is able to validation block's
/// execution outcome.
#[auto_impl::auto_impl(&, Arc)]
pub trait Consensus<H = Header, B = BlockBody>:
AsHeaderValidator<H> + HeaderValidator<H> + Debug + Send + Sync
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> {
/// Ensures that body field values match the header.
fn validate_body_against_header(
&self,
Expand All @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down
10 changes: 6 additions & 4 deletions crates/consensus/consensus/src/noop.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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(())
}
Expand Down
28 changes: 15 additions & 13 deletions crates/consensus/consensus/src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -46,34 +46,36 @@ impl TestConsensus {
}
}

impl<H, B> Consensus<H, B> for TestConsensus {
fn validate_body_against_header(
impl<N: NodePrimitives> FullConsensus<N> for TestConsensus {
fn validate_block_post_execution(
&self,
_body: &B,
_header: &SealedHeader<H>,
_block: &BlockWithSenders<N::Block>,
_input: PostExecutionInput<'_, N::Receipt>,
) -> Result<(), ConsensusError> {
if self.fail_body_against_header() {
if self.fail_validation() {
Err(ConsensusError::BaseFeeMissing)
} else {
Ok(())
}
}
}

fn validate_block_pre_execution(
impl<H, B> Consensus<H, B> for TestConsensus {
fn validate_body_against_header(
&self,
_block: &SealedBlock<H, B>,
_body: &B,
_header: &SealedHeader<H>,
) -> Result<(), ConsensusError> {
if self.fail_validation() {
if self.fail_body_against_header() {
Err(ConsensusError::BaseFeeMissing)
} else {
Ok(())
}
}

fn validate_block_post_execution(
fn validate_block_pre_execution(
&self,
_block: &BlockWithSenders,
_input: PostExecutionInput<'_>,
_block: &SealedBlock<H, B>,
) -> Result<(), ConsensusError> {
if self.fail_validation() {
Err(ConsensusError::BaseFeeMissing)
Expand Down
4 changes: 2 additions & 2 deletions crates/engine/local/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::miner::{LocalMiner, MiningMode};
use futures_util::{Stream, StreamExt};
use reth_beacon_consensus::{BeaconConsensusEngineEvent, EngineNodeTypes};
use reth_chainspec::EthChainSpec;
use reth_consensus::Consensus;
use reth_consensus::FullConsensus;
use reth_engine_primitives::{BeaconEngineMessage, EngineValidator};
use reth_engine_service::service::EngineMessageStream;
use reth_engine_tree::{
Expand Down Expand Up @@ -64,7 +64,7 @@ where
/// Constructor for [`LocalEngineService`].
#[allow(clippy::too_many_arguments)]
pub fn new<B, V>(
consensus: Arc<dyn Consensus>,
consensus: Arc<dyn FullConsensus>,
executor_factory: impl BlockExecutorProvider<Primitives = N::Primitives>,
provider: ProviderFactory<N>,
blockchain_db: BlockchainProvider2<N>,
Expand Down
6 changes: 3 additions & 3 deletions crates/engine/service/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use futures::{Stream, StreamExt};
use pin_project::pin_project;
use reth_beacon_consensus::{BeaconConsensusEngineEvent, EngineNodeTypes};
use reth_chainspec::EthChainSpec;
use reth_consensus::Consensus;
use reth_consensus::FullConsensus;
use reth_engine_primitives::{BeaconEngineMessage, EngineValidator};
use reth_engine_tree::{
backfill::PipelineSync,
Expand Down Expand Up @@ -65,7 +65,7 @@ where
/// Constructor for `EngineService`.
#[allow(clippy::too_many_arguments)]
pub fn new<V>(
consensus: Arc<dyn Consensus>,
consensus: Arc<dyn FullConsensus>,
executor_factory: E,
chain_spec: Arc<N::ChainSpec>,
client: Client,
Expand All @@ -87,7 +87,7 @@ where
let engine_kind =
if chain_spec.is_optimism() { EngineApiKind::OpStack } else { EngineApiKind::Ethereum };

let downloader = BasicBlockDownloader::new(client, consensus.clone());
let downloader = BasicBlockDownloader::new(client, consensus.clone().as_consensus());

let persistence_handle =
PersistenceHandle::spawn_service(provider, pruner, sync_metrics_tx);
Expand Down
8 changes: 4 additions & 4 deletions crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use reth_blockchain_tree::{
use reth_chain_state::{
CanonicalInMemoryState, ExecutedBlock, MemoryOverlayStateProvider, NewCanonicalChain,
};
use reth_consensus::{Consensus, PostExecutionInput};
use reth_consensus::{Consensus, FullConsensus, PostExecutionInput};
use reth_engine_primitives::{
BeaconEngineMessage, BeaconOnNewPayloadError, EngineApiMessageVersion, EngineTypes,
EngineValidator, ForkchoiceStateTracker, OnForkChoiceUpdated,
Expand Down Expand Up @@ -473,7 +473,7 @@ where
{
provider: P,
executor_provider: E,
consensus: Arc<dyn Consensus>,
consensus: Arc<dyn FullConsensus>,
payload_validator: V,
/// Keeps track of internals such as executed and buffered blocks.
state: EngineApiTreeState,
Expand Down Expand Up @@ -557,7 +557,7 @@ where
pub fn new(
provider: P,
executor_provider: E,
consensus: Arc<dyn Consensus>,
consensus: Arc<dyn FullConsensus>,
payload_validator: V,
outgoing: UnboundedSender<EngineApiEvent>,
state: EngineApiTreeState,
Expand Down Expand Up @@ -606,7 +606,7 @@ where
pub fn spawn_new(
provider: P,
executor_provider: E,
consensus: Arc<dyn Consensus>,
consensus: Arc<dyn FullConsensus>,
payload_validator: V,
persistence: PersistenceHandle,
payload_builder: PayloadBuilderHandle<T>,
Expand Down
Loading

0 comments on commit 5d71150

Please sign in to comment.