1use crate::{ChainSpec, DepositContract};
2use alloc::{boxed::Box, vec::Vec};
3use alloy_chains::Chain;
4use alloy_consensus::Header;
5use alloy_eips::{calc_next_block_base_fee, eip1559::BaseFeeParams, eip7840::BlobParams};
6use alloy_genesis::Genesis;
7use alloy_primitives::{B256, U256};
8use core::fmt::{Debug, Display};
9use reth_ethereum_forks::EthereumHardforks;
10use reth_network_peers::NodeRecord;
11use reth_primitives_traits::{AlloyBlockHeader, BlockHeader};
12
13#[auto_impl::auto_impl(&, Arc)]
15pub trait EthChainSpec: Send + Sync + Unpin + Debug {
16 type Header: BlockHeader;
18
19 fn chain(&self) -> Chain;
21
22 fn chain_id(&self) -> u64 {
24 self.chain().id()
25 }
26
27 fn base_fee_params_at_timestamp(&self, timestamp: u64) -> BaseFeeParams;
29
30 fn blob_params_at_timestamp(&self, timestamp: u64) -> Option<BlobParams>;
32
33 fn deposit_contract(&self) -> Option<&DepositContract>;
35
36 fn genesis_hash(&self) -> B256;
38
39 fn prune_delete_limit(&self) -> usize;
41
42 fn display_hardforks(&self) -> Box<dyn Display>;
44
45 fn genesis_header(&self) -> &Self::Header;
47
48 fn genesis(&self) -> &Genesis;
50
51 fn bootnodes(&self) -> Option<Vec<NodeRecord>>;
53
54 fn is_optimism(&self) -> bool {
56 self.chain().is_optimism()
57 }
58
59 fn is_ethereum(&self) -> bool {
61 self.chain().is_ethereum()
62 }
63
64 fn final_paris_total_difficulty(&self) -> Option<U256>;
66
67 fn next_block_base_fee(&self, parent: &Self::Header, target_timestamp: u64) -> Option<u64> {
69 Some(calc_next_block_base_fee(
70 parent.gas_used(),
71 parent.gas_limit(),
72 parent.base_fee_per_gas()?,
73 self.base_fee_params_at_timestamp(target_timestamp),
74 ))
75 }
76}
77
78impl EthChainSpec for ChainSpec {
79 type Header = Header;
80
81 fn chain(&self) -> Chain {
82 self.chain
83 }
84
85 fn base_fee_params_at_timestamp(&self, timestamp: u64) -> BaseFeeParams {
86 self.base_fee_params_at_timestamp(timestamp)
87 }
88
89 fn blob_params_at_timestamp(&self, timestamp: u64) -> Option<BlobParams> {
90 if let Some(blob_param) = self.blob_params.active_scheduled_params_at_timestamp(timestamp) {
91 Some(*blob_param)
92 } else if self.is_osaka_active_at_timestamp(timestamp) {
93 Some(self.blob_params.osaka)
94 } else if self.is_prague_active_at_timestamp(timestamp) {
95 Some(self.blob_params.prague)
96 } else if self.is_cancun_active_at_timestamp(timestamp) {
97 Some(self.blob_params.cancun)
98 } else {
99 None
100 }
101 }
102
103 fn deposit_contract(&self) -> Option<&DepositContract> {
104 self.deposit_contract.as_ref()
105 }
106
107 fn genesis_hash(&self) -> B256 {
108 self.genesis_hash()
109 }
110
111 fn prune_delete_limit(&self) -> usize {
112 self.prune_delete_limit
113 }
114
115 fn display_hardforks(&self) -> Box<dyn Display> {
116 Box::new(Self::display_hardforks(self))
117 }
118
119 fn genesis_header(&self) -> &Self::Header {
120 self.genesis_header()
121 }
122
123 fn genesis(&self) -> &Genesis {
124 self.genesis()
125 }
126
127 fn bootnodes(&self) -> Option<Vec<NodeRecord>> {
128 self.bootnodes()
129 }
130
131 fn is_optimism(&self) -> bool {
132 false
133 }
134
135 fn final_paris_total_difficulty(&self) -> Option<U256> {
136 self.paris_block_and_final_difficulty.map(|(_, final_difficulty)| final_difficulty)
137 }
138}