Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make DatabaseProvider generic over chainspec #10978

Merged
merged 10 commits into from
Sep 19, 2024
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
2 changes: 1 addition & 1 deletion crates/blockchain-tree/src/blockchain_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use reth_execution_errors::{BlockExecutionError, BlockValidationError};
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_node_types::NodeTypesWithDB;
use reth_primitives::{
BlockNumHash, EthereumHardfork, ForkBlock, GotExpected, Receipt, SealedBlock,
BlockNumHash, EthereumHardfork, ForkBlock, GotExpected, Hardforks, Receipt, SealedBlock,
SealedBlockWithSenders, SealedHeader, StaticFileSegment,
};
use reth_provider::{
Expand Down
9 changes: 9 additions & 0 deletions crates/chainspec/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
use crate::ChainSpec;
use alloy_chains::Chain;
use alloy_eips::eip1559::BaseFeeParams;
use core::fmt::Debug;

/// Trait representing type configuring a chain spec.
#[auto_impl::auto_impl(&, Arc)]
pub trait EthChainSpec: Send + Sync + Unpin + Debug + 'static {
// todo: make chain spec type generic over hardfork
//type Hardfork: Clone + Copy + 'static;

/// Chain id.
fn chain(&self) -> Chain;

/// Get the [`BaseFeeParams`] for the chain at the given timestamp.
fn base_fee_params_at_timestamp(&self, timestamp: u64) -> BaseFeeParams;
}

impl EthChainSpec for ChainSpec {
fn chain(&self) -> Chain {
self.chain
}

fn base_fee_params_at_timestamp(&self, timestamp: u64) -> BaseFeeParams {
self.base_fee_params_at_timestamp(timestamp)
}
}
21 changes: 20 additions & 1 deletion crates/chainspec/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use derive_more::From;
use once_cell::sync::{Lazy, OnceCell};
use reth_ethereum_forks::{
ChainHardforks, DisplayHardforks, EthereumHardfork, EthereumHardforks, ForkCondition,
ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head, DEV_HARDFORKS,
ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Hardforks, Head, OptimismHardforks,
DEV_HARDFORKS,
};
use reth_network_peers::{
base_nodes, base_testnet_nodes, holesky_nodes, mainnet_nodes, op_nodes, op_testnet_nodes,
Expand Down Expand Up @@ -616,6 +617,24 @@ impl From<Genesis> for ChainSpec {
}
}

impl Hardforks for ChainSpec {
fn fork<H: Hardfork>(&self, fork: H) -> ForkCondition {
self.hardforks.fork(fork)
}

fn forks_iter(&self) -> impl Iterator<Item = (&dyn Hardfork, ForkCondition)> {
self.hardforks.forks_iter()
}
}

impl EthereumHardforks for ChainSpec {
fn final_paris_total_difficulty(&self, block_number: u64) -> Option<U256> {
self.final_paris_total_difficulty(block_number)
}
}

impl OptimismHardforks for ChainSpec {}

/// Convert the given [`Genesis`] into an Ethereum [`ChainSpec`].
#[cfg(not(feature = "optimism"))]
fn into_ethereum_chain_spec(genesis: Genesis) -> ChainSpec {
Expand Down
3 changes: 3 additions & 0 deletions crates/consensus/beacon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ thiserror.workspace = true
schnellru.workspace = true
itertools.workspace = true

reth-chainspec = { workspace = true, optional = true }

[dev-dependencies]
# reth
reth-payload-builder = { workspace = true, features = ["test-utils"] }
Expand Down Expand Up @@ -79,4 +81,5 @@ optimism = [
"reth-primitives/optimism",
"reth-provider/optimism",
"reth-blockchain-tree/optimism",
"reth-chainspec"
]
5 changes: 3 additions & 2 deletions crates/consensus/beacon/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ where
/// The payload store.
payload_builder: PayloadBuilderHandle<N::Engine>,
/// Validator for execution payloads
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<N::ChainSpec>,
/// Current blockchain tree action.
blockchain_tree_action: Option<BlockchainTreeAction<N::Engine>>,
/// Pending forkchoice update.
Expand Down Expand Up @@ -462,7 +462,8 @@ where
) -> bool {
// On Optimism, the proposers are allowed to reorg their own chain at will.
#[cfg(feature = "optimism")]
if self.blockchain.chain_spec().is_optimism() {
if reth_chainspec::EthChainSpec::chain(self.blockchain.chain_spec().as_ref()).is_optimism()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsure what's the best way to do this. for now just changed to checks on chain id, but I guess there are cases that we don't cover by this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prob should get rid of the feature flag altogether and capture this logic in the OP engine consensus impl?

{
debug!(
target: "consensus::engine",
fcu_head_num=?header.number,
Expand Down
2 changes: 1 addition & 1 deletion crates/consensus/beacon/src/engine/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ mod tests {
fn build<N>(
self,
pipeline: Pipeline<N>,
chain_spec: Arc<ChainSpec>,
chain_spec: Arc<N::ChainSpec>,
) -> EngineSyncController<N, Either<Client, TestFullBlockClient>>
where
N: ProviderNodeTypes,
Expand Down
8 changes: 4 additions & 4 deletions crates/consensus/common/src/validation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Collection of methods for block validation.

use reth_chainspec::{ChainSpec, EthereumHardforks};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_consensus::ConsensusError;
use reth_primitives::{
constants::{
Expand All @@ -25,7 +25,7 @@ pub const fn validate_header_gas(header: &Header) -> Result<(), ConsensusError>

/// Ensure the EIP-1559 base fee is set if the London hardfork is active.
#[inline]
pub fn validate_header_base_fee(
pub fn validate_header_base_fee<ChainSpec: EthereumHardforks>(
header: &Header,
chain_spec: &ChainSpec,
) -> Result<(), ConsensusError> {
Expand Down Expand Up @@ -101,7 +101,7 @@ pub fn validate_prague_request(block: &SealedBlock) -> Result<(), ConsensusError
/// - Compares the transactions root in the block header to the block body
/// - Pre-execution transaction validation
/// - (Optionally) Compares the receipts root in the block header to the block body
pub fn validate_block_pre_execution(
pub fn validate_block_pre_execution<ChainSpec: EthereumHardforks>(
block: &SealedBlock,
chain_spec: &ChainSpec,
) -> Result<(), ConsensusError> {
Expand Down Expand Up @@ -218,7 +218,7 @@ pub fn validate_against_parent_hash_number(

/// Validates the base fee against the parent and EIP-1559 rules.
#[inline]
pub fn validate_against_parent_eip1559_base_fee(
pub fn validate_against_parent_eip1559_base_fee<ChainSpec: EthChainSpec + EthereumHardforks>(
header: &Header,
parent: &Header,
chain_spec: &ChainSpec,
Expand Down
2 changes: 1 addition & 1 deletion crates/engine/invalid-block-hooks/src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ where
// Apply pre-block system contract calls.
apply_beacon_root_contract_call(
&self.evm_config,
&self.provider.chain_spec(),
self.provider.chain_spec().as_ref(),
block.timestamp,
block.number,
block.parent_beacon_block_root,
Expand Down
5 changes: 2 additions & 3 deletions crates/engine/tree/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ reth-blockchain-tree.workspace = true
reth-blockchain-tree-api.workspace = true
reth-chain-state.workspace = true
reth-consensus.workspace = true
reth-chainspec.workspace = true
reth-engine-primitives.workspace = true
reth-errors.workspace = true
reth-evm.workspace = true
Expand Down Expand Up @@ -51,7 +52,6 @@ reth-prune-types = { workspace = true, optional = true }
reth-stages = { workspace = true, optional = true }
reth-static-file = { workspace = true, optional = true }
reth-tracing = { workspace = true, optional = true }
reth-chainspec = { workspace = true, optional = true }

[dev-dependencies]
# reth
Expand Down Expand Up @@ -82,6 +82,5 @@ test-utils = [
"reth-prune-types",
"reth-stages/test-utils",
"reth-static-file",
"reth-tracing",
"reth-chainspec"
"reth-tracing"
]
19 changes: 12 additions & 7 deletions crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use reth_blockchain_tree::{
use reth_chain_state::{
CanonicalInMemoryState, ExecutedBlock, MemoryOverlayStateProvider, NewCanonicalChain,
};
use reth_chainspec::EthereumHardforks;
use reth_consensus::{Consensus, PostExecutionInput};
use reth_engine_primitives::EngineTypes;
use reth_errors::{ConsensusError, ProviderResult};
Expand Down Expand Up @@ -457,11 +458,11 @@ pub enum TreeAction {
///
/// This type is responsible for processing engine API requests, maintaining the canonical state and
/// emitting events.
pub struct EngineApiTreeHandler<P, E, T: EngineTypes> {
pub struct EngineApiTreeHandler<P, E, T: EngineTypes, Spec> {
provider: P,
executor_provider: E,
consensus: Arc<dyn Consensus>,
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
/// Keeps track of internals such as executed and buffered blocks.
state: EngineApiTreeState,
/// The half for sending messages to the engine.
Expand Down Expand Up @@ -499,7 +500,9 @@ pub struct EngineApiTreeHandler<P, E, T: EngineTypes> {
metrics: EngineApiMetrics,
}

impl<P: Debug, E: Debug, T: EngineTypes + Debug> std::fmt::Debug for EngineApiTreeHandler<P, E, T> {
impl<P: Debug, E: Debug, T: EngineTypes + Debug, Spec: Debug> std::fmt::Debug
for EngineApiTreeHandler<P, E, T, Spec>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EngineApiTreeHandler")
.field("provider", &self.provider)
Expand All @@ -521,20 +524,21 @@ impl<P: Debug, E: Debug, T: EngineTypes + Debug> std::fmt::Debug for EngineApiTr
}
}

impl<P, E, T> EngineApiTreeHandler<P, E, T>
impl<P, E, T, Spec> EngineApiTreeHandler<P, E, T, Spec>
where
P: DatabaseProviderFactory + BlockReader + StateProviderFactory + StateReader + Clone + 'static,
<P as DatabaseProviderFactory>::Provider: BlockReader,
E: BlockExecutorProvider,
T: EngineTypes,
Spec: Send + Sync + EthereumHardforks + 'static,
{
/// Creates a new [`EngineApiTreeHandler`].
#[allow(clippy::too_many_arguments)]
pub fn new(
provider: P,
executor_provider: E,
consensus: Arc<dyn Consensus>,
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
outgoing: UnboundedSender<EngineApiEvent>,
state: EngineApiTreeState,
canonical_in_memory_state: CanonicalInMemoryState,
Expand Down Expand Up @@ -580,7 +584,7 @@ where
provider: P,
executor_provider: E,
consensus: Arc<dyn Consensus>,
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
persistence: PersistenceHandle,
payload_builder: PayloadBuilderHandle<T>,
canonical_in_memory_state: CanonicalInMemoryState,
Expand Down Expand Up @@ -2651,7 +2655,8 @@ mod tests {
}

struct TestHarness {
tree: EngineApiTreeHandler<MockEthProvider, MockExecutorProvider, EthEngineTypes>,
tree:
EngineApiTreeHandler<MockEthProvider, MockExecutorProvider, EthEngineTypes, ChainSpec>,
to_tree_tx: Sender<FromEngine<EngineApiRequest<EthEngineTypes>>>,
from_tree_rx: UnboundedReceiver<EngineApiEvent>,
blocks: Vec<ExecutedBlock>,
Expand Down
12 changes: 6 additions & 6 deletions crates/engine/util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@ pub trait EngineMessageStreamExt<Engine: EngineTypes>:
}

/// Creates reorgs with specified frequency.
fn reorg<Provider, Evm>(
fn reorg<Provider, Evm, Spec>(
self,
provider: Provider,
evm_config: Evm,
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
frequency: usize,
depth: Option<usize>,
) -> EngineReorg<Self, Engine, Provider, Evm>
) -> EngineReorg<Self, Engine, Provider, Evm, Spec>
where
Self: Sized,
{
Expand All @@ -118,14 +118,14 @@ pub trait EngineMessageStreamExt<Engine: EngineTypes>:

/// If frequency is [Some], returns the stream that creates reorgs with
/// specified frequency. Otherwise, returns `Self`.
fn maybe_reorg<Provider, Evm>(
fn maybe_reorg<Provider, Evm, Spec>(
self,
provider: Provider,
evm_config: Evm,
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
frequency: Option<usize>,
depth: Option<usize>,
) -> Either<EngineReorg<Self, Engine, Provider, Evm>, Self>
) -> Either<EngineReorg<Self, Engine, Provider, Evm, Spec>, Self>
where
Self: Sized,
{
Expand Down
16 changes: 9 additions & 7 deletions crates/engine/util/src/reorg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type ReorgResponseFut = Pin<Box<dyn Future<Output = EngineReorgResponse> + Send
/// Engine API stream wrapper that simulates reorgs with specified frequency.
#[derive(Debug)]
#[pin_project::pin_project]
pub struct EngineReorg<S, Engine: EngineTypes, Provider, Evm> {
pub struct EngineReorg<S, Engine: EngineTypes, Provider, Evm, Spec> {
/// Underlying stream
#[pin]
stream: S,
Expand All @@ -59,7 +59,7 @@ pub struct EngineReorg<S, Engine: EngineTypes, Provider, Evm> {
/// Evm configuration.
evm_config: Evm,
/// Payload validator.
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
/// The frequency of reorgs.
frequency: usize,
/// The depth of reorgs.
Expand All @@ -75,13 +75,13 @@ pub struct EngineReorg<S, Engine: EngineTypes, Provider, Evm> {
reorg_responses: FuturesUnordered<ReorgResponseFut>,
}

impl<S, Engine: EngineTypes, Provider, Evm> EngineReorg<S, Engine, Provider, Evm> {
impl<S, Engine: EngineTypes, Provider, Evm, Spec> EngineReorg<S, Engine, Provider, Evm, Spec> {
/// Creates new [`EngineReorg`] stream wrapper.
pub fn new(
stream: S,
provider: Provider,
evm_config: Evm,
payload_validator: ExecutionPayloadValidator,
payload_validator: ExecutionPayloadValidator<Spec>,
frequency: usize,
depth: usize,
) -> Self {
Expand All @@ -100,12 +100,13 @@ impl<S, Engine: EngineTypes, Provider, Evm> EngineReorg<S, Engine, Provider, Evm
}
}

impl<S, Engine, Provider, Evm> Stream for EngineReorg<S, Engine, Provider, Evm>
impl<S, Engine, Provider, Evm, Spec> Stream for EngineReorg<S, Engine, Provider, Evm, Spec>
where
S: Stream<Item = BeaconEngineMessage<Engine>>,
Engine: EngineTypes,
Provider: BlockReader + StateProviderFactory,
Evm: ConfigureEvm<Header = Header>,
Spec: EthereumHardforks,
{
type Item = S::Item;

Expand Down Expand Up @@ -227,17 +228,18 @@ where
}
}

fn create_reorg_head<Provider, Evm>(
fn create_reorg_head<Provider, Evm, Spec>(
provider: &Provider,
evm_config: &Evm,
payload_validator: &ExecutionPayloadValidator,
payload_validator: &ExecutionPayloadValidator<Spec>,
mut depth: usize,
next_payload: ExecutionPayload,
next_cancun_fields: Option<CancunPayloadFields>,
) -> RethResult<(ExecutionPayload, Option<CancunPayloadFields>)>
where
Provider: BlockReader + StateProviderFactory,
Evm: ConfigureEvm<Header = Header>,
Spec: EthereumHardforks,
{
let chain_spec = payload_validator.chain_spec();

Expand Down
16 changes: 10 additions & 6 deletions crates/ethereum-forks/src/hardforks/ethereum.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
hardforks::{ChainHardforks, Hardforks},
EthereumHardfork, ForkCondition,
};
use alloy_primitives::U256;

use crate::{hardforks::Hardforks, EthereumHardfork, ForkCondition};

/// Helper methods for Ethereum forks.
#[auto_impl::auto_impl(&, Arc)]
pub trait EthereumHardforks: Hardforks {
/// Convenience method to check if [`EthereumHardfork::Shanghai`] is active at a given
/// timestamp.
Expand Down Expand Up @@ -51,6 +51,10 @@ pub trait EthereumHardforks: Hardforks {
_ => None,
}
}
}

impl EthereumHardforks for ChainHardforks {}
/// Returns the final total difficulty if the given block number is after the Paris hardfork.
///
/// Note: technically this would also be valid for the block before the paris upgrade, but this
/// edge case is omitted here.
fn final_paris_total_difficulty(&self, block_number: u64) -> Option<U256>;
}
1 change: 1 addition & 0 deletions crates/ethereum-forks/src/hardforks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use alloc::collections::btree_map::Entry;
use alloc::{boxed::Box, vec::Vec};

/// Generic trait over a set of ordered hardforks
#[auto_impl::auto_impl(&, Arc)]
pub trait Hardforks: Default + Clone {
/// Retrieves [`ForkCondition`] from `fork`. If `fork` is not present, returns
/// [`ForkCondition::Never`].
Expand Down
Loading
Loading