//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm


//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus {
        &self.consensus
    }

    fn network(&self) -> &Self::Network {
        &self.network
    }

    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
        &self.payload_builder_handle
    }
}

impl<Node, N, Pool, EVM, Cons> Clone for Components<Node, N, Pool, EVM, Cons>
where
    N: Clone,
    Node: FullNodeTypes,
    Pool: TransactionPool,
    EVM: ConfigureEvm,
    Cons: Clone,
{
    fn clone(&self) -> Self {
        Self {
            transaction_pool: self.transaction_pool.clone(),
            evm_config: self.evm_config.clone(),
            consensus: self.consensus.clone(),
            network: self.network.clone(),
            payload_builder_handle: self.payload_builder_handle.clone(),
        }
    }
}


//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus


//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus {
        &self.consensus
    }

    fn network(&self) -> &Self::Network


//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus {
        &self.consensus
    }

    fn network(&self) -> &Self::Network {
        &self.network
    }

    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
        &self.payload_builder_handle
    }

}

impl<Node, N, Pool, EVM, Cons> Clone for Components<Node, N, Pool, EVM, Cons>
where
    N: Clone,
    Node: FullNodeTypes,
    Pool: TransactionPool,
    EVM: ConfigureEvm,
    Cons: Clone,
{
    fn clone(&self) -> Self {
        Self {
            transaction_pool: self.transaction_pool.clone(),
            evm_config: self.evm_config.clone(),
            consensus: self.consensus.clone(),
            network: self.network.clone(),
            payload_builder_handle: self.payload_builder_handle.clone(),
        }
    }
}


onfiguring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus {
        &self.consensus
    }

    fn network(&self) -> &Self::Network {
        &self.network
    }

    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>

{
        &self.payload_builder_handle
    }


//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus {
        &self.consensus
    }

    fn network(&self) -> &Self::Network {
        &self.network
    }

    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
        &self.payload_builder_handle
    }
}

impl<Node, N, Pool, EVM, Cons> Clone for Components<Node, N, Pool, EVM, Cons>
where
    N: Clone,
    Node: FullNodeTypes,
    Pool: TransactionPool,
    EVM: ConfigureEvm,
    Cons: Clone,
{

    fn clone(&self) -> Self {
        Self {
            transaction_pool: self.transaction_pool.clone(),
            evm_config: self.evm_config.clone(),
            consensus: self.consensus.clone(),
            network: self.network.clone(),
            payload_builder_handle: self.payload_builder_handle.clone(),
        }
    }


//! Support for configuring the components of a node.
//!
//! Customizable components of the node include:
//!  - The transaction pool.
//!  - The network implementation.
//!  - The payload builder service.
//!
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).

mod builder;
mod consensus;
mod execute;
mod network;
mod payload;
mod pool;

pub use builder::*;
pub use consensus::*;
pub use execute::*;
pub use network::*;
pub use payload::*;
pub use pool::*;

use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::FullConsensus;
use reth_network::types::NetPrimitivesFor;
use reth_network_api::FullNetwork;
use reth_node_api::{NodeTypes, PrimitivesTy, TxTy};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use std::fmt::Debug;

/// An abstraction over the components of a node, consisting of:
///  - evm and executor
///  - transaction pool
///  - network
///  - payload builder.
pub trait NodeComponents<T: FullNodeTypes>: Clone + Debug + Unpin + Send + Sync + 'static {
    /// The transaction pool of the node.
    type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;

    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    type Evm: ConfigureEvm<Primitives = <T::Types as NodeTypes>::Primitives>;

    /// The consensus type of the node.
    type Consensus: FullConsensus<<T::Types as NodeTypes>::Primitives> + Clone + Unpin + 'static;

    /// Network API.
    type Network: FullNetwork<Primitives: NetPrimitivesFor<<T::Types as NodeTypes>::Primitives>>;

    /// Returns the transaction pool of the node.
    fn pool(&self) -> &Self::Pool;

    /// Returns the node's evm config.
    fn evm_config(&self) -> &Self::Evm;

    /// Returns the node's consensus type.
    fn consensus(&self) -> &Self::Consensus;

    /// Returns the handle to the network
    fn network(&self) -> &Self::Network;

    /// Returns the handle to the payload builder service handling payload building requests from
    /// the engine.
    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<T::Types as NodeTypes>::Payload>;
}

/// All the components of the node.
///
/// This provides access to all the components of the node.
#[derive(Debug)]
pub struct Components<Node: FullNodeTypes, Network, Pool, EVM, Consensus> {
    /// The transaction pool of the node.
    pub transaction_pool: Pool,
    /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
    pub evm_config: EVM,
    /// The consensus implementation of the node.
    pub consensus: Consensus,
    /// The network implementation of the node.
    pub network: Network,
    /// The handle to the payload builder service.
    pub payload_builder_handle: PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload>,
}

impl<Node, Pool, EVM, Cons, Network> NodeComponents<Node>
    for Components<Node, Network, Pool, EVM, Cons>
where
    Node: FullNodeTypes,
    Network: FullNetwork<
        Primitives: NetPrimitivesFor<
            PrimitivesTy<Node::Types>,
            PooledTransaction = PoolPooledTx<Pool>,
        >,
    >,
    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
        + Unpin
        + 'static,
    EVM: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>> + 'static,
    Cons: FullConsensus<PrimitivesTy<Node::Types>> + Clone + Unpin + 'static,
{
    type Pool = Pool;
    type Evm = EVM;
    type Consensus = Cons;
    type Network = Network;

    fn pool(&self) -> &Self::Pool {
        &self.transaction_pool
    }

    fn evm_config(&self) -> &Self::Evm {
        &self.evm_config
    }

    fn consensus(&self) -> &Self::Consensus {
        &self.consensus
    }

    fn network(&self) -> &Self::Network {
        &self.network
    }

    fn payload_builder_handle(&self) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
        &self.payload_builder_handle
    }
}

impl<Node, N, Pool, EVM, Cons> Clone for Components<Node, N, Pool, EVM, Cons>
where
    N: Clone,
    Node: FullNodeTypes,
    Pool: TransactionPool,
    EVM: ConfigureEvm,
    Cons: Clone,
{
    fn clone(&self) -> Self

{
        Self {
            transaction_pool: self.transaction_pool.clone(),
            evm_config: self.evm_config.clone(),
            consensus: self.consensus.clone(),
            network: self.network.clone(),
            payload_builder_handle: self.payload_builder_handle.clone(),
        }
    }


use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};

use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};

use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: heade


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};

use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;

use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;

use reth_primitives_traits::{BlockHeader, Header, SealedHeader};

use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error|


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]

    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }

}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }
}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber

{
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]

    pub fn is_closed(&self) -> bool {
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }

}

/// Validate whether the header is valid in relation to its parent.
pub fn validate_header_download<H: BlockHeader>(
    consensus: &dyn HeaderValidator<H>,
    header: &SealedHeader<H>,
    parent: &SealedHeader<H>,
) -> DownloadResult<()> {
    // validate header against parent
    consensus.validate_header_against_parent(header, parent).map_err(|error| {
        DownloadError::HeaderValidation {
            hash: header.hash(),
            number: header.number(),
            error: Box::new(error),
        }
    })?;
    // validate header standalone
    consensus.validate_header(header).map_err(|error| DownloadError::HeaderValidation {
        hash: header.hash(),
        number: header.number(),
        error: Box::new(error),
    })?;
    Ok(())
}


use super::error::HeadersDownloaderResult;
use crate::error::{DownloadError, DownloadResult};
use alloy_eips::{eip1898::BlockWithParent, BlockHashOrNumber};
use alloy_primitives::{Sealable, B256};
use futures::Stream;
use reth_consensus::HeaderValidator;
use reth_primitives_traits::{BlockHeader, Header, SealedHeader};
use std::fmt::Debug;

/// A downloader capable of fetching and yielding block headers.
///
/// A downloader represents a distinct strategy for submitting requests to download block headers,
/// while a [`HeadersClient`][crate::headers::client::HeadersClient] represents a client capable
/// of fulfilling these requests.
///
/// A [`HeaderDownloader`] is a [Stream] that returns batches of headers.
pub trait HeaderDownloader:
    Send
    + Sync
    + Stream<Item = HeadersDownloaderResult<Vec<SealedHeader<Self::Header>>, Self::Header>>
    + Unpin
{
    /// The header type being downloaded.
    type Header: Sealable + Debug + Send + Sync + Unpin + 'static;

    /// Updates the gap to sync which ranges from local head to the sync target.
    ///
    /// See also [`HeaderDownloader::update_sync_target`] and
    /// [`HeaderDownloader::update_local_head`]
    fn update_sync_gap(&mut self, head: SealedHeader<Self::Header>, target: SyncTarget) {
        self.update_local_head(head);
        self.update_sync_target(target);
    }

    /// Updates the block number of the local database
    fn update_local_head(&mut self, head: SealedHeader<Self::Header>);

    /// Updates the target we want to sync to.
    fn update_sync_target(&mut self, target: SyncTarget);

    /// Sets the headers batch size that the Stream should return.
    fn set_batch_size(&mut self, limit: usize);
}

/// Specifies the target to sync for [`HeaderDownloader::update_sync_target`]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SyncTarget {
    /// This represents a range missing headers in the form of `(head,..`
    ///
    /// Sync _inclusively_ to the given block hash.
    ///
    /// This target specifies the upper end of the sync gap `(head...tip]`
    Tip(B256),
    /// This represents a gap missing headers bounded by the given header `h` in the form of
    /// `(head,..h),h+1,h+2...`
    ///
    /// Sync _exclusively_ to the given header's parent which is: `(head..h-1]`
    ///
    /// The benefit of this variant is, that this already provides the block number of the highest
    /// missing block.
    Gap(BlockWithParent),
    /// This represents a tip by block number
    TipNum(u64),
}

// === impl SyncTarget ===

impl SyncTarget {
    /// Returns the tip to sync to _inclusively_
    ///
    /// This returns the hash if the target is [`SyncTarget::Tip`] or the `parent_hash` of the given
    /// header in [`SyncTarget::Gap`]
    pub fn tip(&self) -> BlockHashOrNumber {
        match self {
            Self::Tip(tip) => (*tip).into(),
            Self::Gap(gap) => gap.parent.into(),
            Self::TipNum(num) => (*num).into(),
        }
    }
}

/// Represents a gap to sync: from `local_head` to `target`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HeaderSyncGap<H: Sealable = Header> {
    /// The local head block. Represents lower bound of sync range.
    pub local_head: SealedHeader<H>,

    /// The sync target. Represents upper bound of sync range.
    pub target: SyncTarget,
}

impl<H: BlockHeader + Sealable> HeaderSyncGap<H> {
    /// Returns `true` if the gap from the head to the target was closed
    #[inline]
    pub fn is_closed(&self) -> bool

{
        match self.target.tip() {
            BlockHashOrNumber::Hash(hash) => self.local_head.hash() == hash,
            BlockHashOrNumber::Number(num) => self.local_head.number() == num,
        }
    }


use reth_chainspec::{ChainSpec, DEV, HOLESKY, HOODI, MAINNET, SEPOLIA};

use reth_cli::chainspec::{parse_genesis, ChainSpecParser};
use std::sync::Arc;

/// Chains supported by reth. First value should be used as the default.
pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "holesky", "hoodi", "dev"];

/// Clap value parser for [`ChainSpec`]s.
///
/// The value parser matches either a known chain, the path
/// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct.
pub fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
    Ok(match s {
        "mainnet" => MAINNET.clone(),
        "sepolia" => SEPOLIA.clone(),
        "holesky" => HOLESKY.clone(),
        "hoodi" => HOODI.clone(),
        "dev" => DEV.clone(),
        _ => Arc::new(parse_genesis(s)?.into()),
    })
}

/// Ethereum chain specification parser.
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct EthereumChainSpecParser;

impl ChainSpecParser for EthereumChainSpecParser {
    type ChainSpec = ChainSpec;

    const SUPPORTED_CHAINS: &'static [&'static str] = SUPPORTED_CHAINS;

    fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
        chain_value_parser(s)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use reth_chainspec::EthereumHardforks;

    #[test]
    fn parse_known_chain_spec() {
        for &chain in EthereumChainSpecParser::SUPPORTED_CHAINS {
            assert!(<EthereumChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
        }
    }

    #[test]
    fn parse_raw_chainspec_hardforks() {
        let s = r#"{
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "stateRoot": "0x76f118cb05a8bc558388df9e3b4ad66ae1f17ef656e5308cb8f600717251b509",
  "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "bloom": "0x000...000",
  "difficulty": "0x00",
  "number": "0x00",
  "gasLimit": "0x016345785d8a0000",
  "gasUsed": "0x00",
  "timestamp": "0x01",
  "extraData": "0x00",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0000000000000000",
  "baseFeePerGas": "0x07",
  "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "blobGasUsed": "0x00",
  "excessBlobGas": "0x00",
  "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "requestsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "hash": "0xc20e1a771553139cdc77e6c3d5f64a7165d972d327eee9632c9c7d0fe839ded4",
  "alloc": {},
  "config": {
    "ethash": {},
    "chainId": 1,
    "homesteadBlock": 0,
    "daoForkSupport": true,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "londonBlock": 0,
    "terminalTotalDifficulty": 0,
    "shanghaiTime": 0,
    "cancunTime": 0,
    "pragueTime": 0,
    "osakaTime": 0
  }
}"#;

        let spec = <EthereumChainSpecParser as ChainSpecParser>::parse(s).unwrap();
        assert!(spec.is_shanghai_active_at_timestamp(0));
        assert!(spec.is_cancun_active_at_timestamp(0));
        assert!(spec.is_prague_active_at_timestamp(0));
        assert!(spec.is_osaka_active_at_timestamp(0));
    }
}


use reth_chainspec::{ChainSpec, DEV, HOLESKY, HOODI, MAINNET, SEPOLIA};

use std::sync::Arc;

/// Chains supported by reth. First value should be used as the default.
pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "holesky", "hoodi", "dev"];

/// Clap value parser for [`ChainSpec`]s.
///
/// The value parser matches either a known chain, the path
/// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct.
pub fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
    Ok(match s {
        "mainnet" => MAINNET.clone(),
        "sepolia" => SEPOLIA.clone(),
        "holesky" => HOLESKY.clone(),
        "hoodi" => HOODI.clone(),
        "dev" => DEV.clone(),
        _ => Arc::new(parse_genesis(s)?.into()),
    })
}

/// Ethereum chain specification parser.
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct EthereumChainSpecParser;

impl ChainSpecParser for EthereumChainSpecParser {
    type ChainSpec = ChainSpec;

    const SUPPORTED_CHAINS: &'static [&'static str] = SUPPORTED_CHAINS;

    fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
        chain_value_parser(s)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use reth_chainspec::EthereumHardforks;

    #[test]
    fn parse_known_chain_spec() {
        for &chain in EthereumChainSpecParser::SUPPORTED_CHAINS {
            assert!(<EthereumChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
        }
    }

    #[test]
    fn parse_raw_chainspec_hardforks() {
        let s = r#"{
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "stateRoot": "0x76f118cb05a8bc558388df9e3b4ad66ae1f17ef656e5308cb8f600717251b509",
  "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "bloom": "0x000...000",
  "difficulty": "0x00",
  "number": "0x00",
  "gasLimit": "0x016345785d8a0000",
  "gasUsed": "0x00",
  "timestamp": "0x01",
  "extraData": "0x00",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0000000000000000",
  "baseFeePerGas": "0x07",
  "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "blobGasUsed": "0x00",
  "excessBlobGas": "0x00",
  "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "requestsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "hash": "0xc20e1a771553139cdc77e6c3d5f64a7165d972d327eee9632c9c7d0fe839ded4",
  "alloc": {},
  "config": {
    "ethash": {},
    "chainId": 1,
    "homesteadBlock": 0,
    "daoForkSupport": true,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "londonBlock": 0,
    "terminalTotalDifficulty": 0,
    "shanghaiTime": 0,
    "cancunTime": 0,
    "pragueTime": 0,
    "osakaTime": 0
  }
}"#;

        let spec = <EthereumChainSpecParser as ChainSpecParser>::parse(s).unwrap();
        assert!(spec.is_shanghai_active_at_timestamp(0));
        assert!(spec.is_cancun_active_at_timestamp(0));
        assert!(spec.is_prague_active_at_timestamp(0));
        assert!(spec.is_osaka_active_at_timestamp(0));
    }
}


use reth_chainspec::{ChainSpec, DEV, HOLESKY, HOODI, MAINNET, SEPOLIA};
use reth_cli::chainspec::{parse_genesis, ChainSpecParser};

/// Chains supported by reth. First value should be used as the default.
pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "holesky", "hoodi", "dev"];

/// Clap value parser for [`ChainSpec`]s.
///
/// The value parser matches either a known chain, the path
/// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct.
pub fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
    Ok(match s {
        "mainnet" => MAINNET.clone(),
        "sepolia" => SEPOLIA.clone(),
        "holesky" => HOLESKY.clone(),
        "hoodi" => HOODI.clone(),
        "dev" => DEV.clone(),
        _ => Arc::new(parse_genesis(s)?.into()),
    })
}

/// Ethereum chain specification parser.
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct EthereumChainSpecParser;

impl ChainSpecParser for EthereumChainSpecParser {
    type ChainSpec = ChainSpec;

    const SUPPORTED_CHAINS: &'static [&'static str] = SUPPORTED_CHAINS;

    fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
        chain_value_parser(s)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use reth_chainspec::EthereumHardforks;

    #[test]
    fn parse_known_chain_spec() {
        for &chain in EthereumChainSpecParser::SUPPORTED_CHAINS {
            assert!(<EthereumChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
        }
    }

    #[test]
    fn parse_raw_chainspec_hardforks() {
        let s = r#"{
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "stateRoot": "0x76f118cb05a8bc558388df9e3b4ad66ae1f17ef656e5308cb8f600717251b509",
  "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "bloom": "0x000...000",
  "difficulty": "0x00",
  "number": "0x00",
  "gasLimit": "0x016345785d8a0000",
  "gasUsed": "0x00",
  "timestamp": "0x01",
  "extraData": "0x00",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0000000000000000",
  "baseFeePerGas": "0x07",
  "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "blobGasUsed": "0x00",
  "excessBlobGas": "0x00",
  "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "requestsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "hash": "0xc20e1a771553139cdc77e6c3d5f64a7165d972d327eee9632c9c7d0fe839ded4",
  "alloc": {},
  "config": {
    "ethash": {},
    "chainId": 1,
    "homesteadBlock": 0,
    "daoForkSupport": true,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "londonBlock": 0,
    "terminalTotalDifficulty": 0,
    "shanghaiTime": 0,
    "cancunTime": 0,
    "pragueTime": 0,
    "osakaTime": 0
  }
}"#;

        let spec = <EthereumChainSpecParser as ChainSpecParser>::parse(s).unwrap();
        assert!(spec.is_shanghai_active_at_timestamp(0));
        assert!(spec.is_cancun_active_at_timestamp(0));
        assert!(spec.is_prague_active_at_timestamp(0));
        assert!(spec.is_osaka_active_at_timestamp(0));
    }
}