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