1
1
pub use alloy_eips:: eip1559:: BaseFeeParams ;
2
2
3
- use crate :: { constants:: MAINNET_DEPOSIT_CONTRACT , once_cell_set , EthChainSpec } ;
3
+ use crate :: { constants:: MAINNET_DEPOSIT_CONTRACT , EthChainSpec } ;
4
4
use alloc:: { boxed:: Box , collections:: BTreeMap , string:: String , sync:: Arc , vec:: Vec } ;
5
5
use alloy_chains:: { Chain , NamedChain } ;
6
6
use alloy_consensus:: {
@@ -26,25 +26,79 @@ use reth_network_peers::{
26
26
base_nodes, base_testnet_nodes, holesky_nodes, mainnet_nodes, op_nodes, op_testnet_nodes,
27
27
sepolia_nodes, NodeRecord ,
28
28
} ;
29
- use reth_primitives_traits:: {
30
- sync:: { LazyLock , OnceLock } ,
31
- SealedHeader ,
32
- } ;
29
+ use reth_primitives_traits:: { sync:: LazyLock , SealedHeader } ;
30
+
31
+ /// Helper method building a [`Header`] given [`Genesis`] and [`ChainHardforks`].
32
+ pub fn make_genesis_header ( genesis : & Genesis , hardforks : & ChainHardforks ) -> Header {
33
+ // If London is activated at genesis, we set the initial base fee as per EIP-1559.
34
+ let base_fee_per_gas = hardforks
35
+ . fork ( EthereumHardfork :: London )
36
+ . active_at_block ( 0 )
37
+ . then ( || genesis. base_fee_per_gas . map ( |fee| fee as u64 ) . unwrap_or ( INITIAL_BASE_FEE ) ) ;
38
+
39
+ // If shanghai is activated, initialize the header with an empty withdrawals hash, and
40
+ // empty withdrawals list.
41
+ let withdrawals_root = hardforks
42
+ . fork ( EthereumHardfork :: Shanghai )
43
+ . active_at_timestamp ( genesis. timestamp )
44
+ . then_some ( EMPTY_WITHDRAWALS ) ;
45
+
46
+ // If Cancun is activated at genesis, we set:
47
+ // * parent beacon block root to 0x0
48
+ // * blob gas used to provided genesis or 0x0
49
+ // * excess blob gas to provided genesis or 0x0
50
+ let ( parent_beacon_block_root, blob_gas_used, excess_blob_gas) =
51
+ if hardforks. fork ( EthereumHardfork :: Cancun ) . active_at_timestamp ( genesis. timestamp ) {
52
+ let blob_gas_used = genesis. blob_gas_used . unwrap_or ( 0 ) ;
53
+ let excess_blob_gas = genesis. excess_blob_gas . unwrap_or ( 0 ) ;
54
+ ( Some ( B256 :: ZERO ) , Some ( blob_gas_used) , Some ( excess_blob_gas) )
55
+ } else {
56
+ ( None , None , None )
57
+ } ;
58
+
59
+ // If Prague is activated at genesis we set requests root to an empty trie root.
60
+ let requests_hash = hardforks
61
+ . fork ( EthereumHardfork :: Prague )
62
+ . active_at_timestamp ( genesis. timestamp )
63
+ . then_some ( EMPTY_REQUESTS_HASH ) ;
64
+
65
+ Header {
66
+ gas_limit : genesis. gas_limit ,
67
+ difficulty : genesis. difficulty ,
68
+ nonce : genesis. nonce . into ( ) ,
69
+ extra_data : genesis. extra_data . clone ( ) ,
70
+ state_root : state_root_ref_unhashed ( & genesis. alloc ) ,
71
+ timestamp : genesis. timestamp ,
72
+ mix_hash : genesis. mix_hash ,
73
+ beneficiary : genesis. coinbase ,
74
+ base_fee_per_gas,
75
+ withdrawals_root,
76
+ parent_beacon_block_root,
77
+ blob_gas_used,
78
+ excess_blob_gas,
79
+ requests_hash,
80
+ ..Default :: default ( )
81
+ }
82
+ }
33
83
34
84
/// The Ethereum mainnet spec
35
85
pub static MAINNET : LazyLock < Arc < ChainSpec > > = LazyLock :: new ( || {
86
+ let genesis = serde_json:: from_str ( include_str ! ( "../res/genesis/mainnet.json" ) )
87
+ . expect ( "Can't deserialize Mainnet genesis json" ) ;
88
+ let hardforks = EthereumHardfork :: mainnet ( ) . into ( ) ;
36
89
let mut spec = ChainSpec {
37
90
chain : Chain :: mainnet ( ) ,
38
- genesis : serde_json:: from_str ( include_str ! ( "../res/genesis/mainnet.json" ) )
39
- . expect ( "Can't deserialize Mainnet genesis json" ) ,
40
- genesis_hash : once_cell_set ( MAINNET_GENESIS_HASH ) ,
41
- genesis_header : Default :: default ( ) ,
91
+ genesis_header : SealedHeader :: new (
92
+ make_genesis_header ( & genesis, & hardforks) ,
93
+ MAINNET_GENESIS_HASH ,
94
+ ) ,
95
+ genesis,
42
96
// <https://etherscan.io/block/15537394>
43
97
paris_block_and_final_difficulty : Some ( (
44
98
15537394 ,
45
99
U256 :: from ( 58_750_003_716_598_352_816_469u128 ) ,
46
100
) ) ,
47
- hardforks : EthereumHardfork :: mainnet ( ) . into ( ) ,
101
+ hardforks,
48
102
// https://etherscan.io/tx/0xe75fb554e433e03763a1560646ee22dcb74e5274b34c5ad644e7c0f619a7e1d0
49
103
deposit_contract : Some ( DepositContract :: new (
50
104
MAINNET_DEPOSIT_CONTRACT_ADDRESS ,
@@ -61,15 +115,19 @@ pub static MAINNET: LazyLock<Arc<ChainSpec>> = LazyLock::new(|| {
61
115
62
116
/// The Sepolia spec
63
117
pub static SEPOLIA : LazyLock < Arc < ChainSpec > > = LazyLock :: new ( || {
118
+ let genesis = serde_json:: from_str ( include_str ! ( "../res/genesis/sepolia.json" ) )
119
+ . expect ( "Can't deserialize Sepolia genesis json" ) ;
120
+ let hardforks = EthereumHardfork :: sepolia ( ) . into ( ) ;
64
121
let mut spec = ChainSpec {
65
122
chain : Chain :: sepolia ( ) ,
66
- genesis : serde_json:: from_str ( include_str ! ( "../res/genesis/sepolia.json" ) )
67
- . expect ( "Can't deserialize Sepolia genesis json" ) ,
68
- genesis_hash : once_cell_set ( SEPOLIA_GENESIS_HASH ) ,
69
- genesis_header : Default :: default ( ) ,
123
+ genesis_header : SealedHeader :: new (
124
+ make_genesis_header ( & genesis, & hardforks) ,
125
+ SEPOLIA_GENESIS_HASH ,
126
+ ) ,
127
+ genesis,
70
128
// <https://sepolia.etherscan.io/block/1450409>
71
129
paris_block_and_final_difficulty : Some ( ( 1450409 , U256 :: from ( 17_000_018_015_853_232u128 ) ) ) ,
72
- hardforks : EthereumHardfork :: sepolia ( ) . into ( ) ,
130
+ hardforks,
73
131
// https://sepolia.etherscan.io/tx/0x025ecbf81a2f1220da6285d1701dc89fb5a956b62562ee922e1a9efd73eb4b14
74
132
deposit_contract : Some ( DepositContract :: new (
75
133
address ! ( "7f02c3e3c98b133055b8b348b2ac625669ed295d" ) ,
@@ -86,14 +144,18 @@ pub static SEPOLIA: LazyLock<Arc<ChainSpec>> = LazyLock::new(|| {
86
144
87
145
/// The Holesky spec
88
146
pub static HOLESKY : LazyLock < Arc < ChainSpec > > = LazyLock :: new ( || {
147
+ let genesis = serde_json:: from_str ( include_str ! ( "../res/genesis/holesky.json" ) )
148
+ . expect ( "Can't deserialize Holesky genesis json" ) ;
149
+ let hardforks = EthereumHardfork :: holesky ( ) . into ( ) ;
89
150
let mut spec = ChainSpec {
90
151
chain : Chain :: holesky ( ) ,
91
- genesis : serde_json:: from_str ( include_str ! ( "../res/genesis/holesky.json" ) )
92
- . expect ( "Can't deserialize Holesky genesis json" ) ,
93
- genesis_hash : once_cell_set ( HOLESKY_GENESIS_HASH ) ,
94
- genesis_header : Default :: default ( ) ,
152
+ genesis_header : SealedHeader :: new (
153
+ make_genesis_header ( & genesis, & hardforks) ,
154
+ HOLESKY_GENESIS_HASH ,
155
+ ) ,
156
+ genesis,
95
157
paris_block_and_final_difficulty : Some ( ( 0 , U256 :: from ( 1 ) ) ) ,
96
- hardforks : EthereumHardfork :: holesky ( ) . into ( ) ,
158
+ hardforks,
97
159
deposit_contract : Some ( DepositContract :: new (
98
160
address ! ( "4242424242424242424242424242424242424242" ) ,
99
161
0 ,
@@ -112,11 +174,16 @@ pub static HOLESKY: LazyLock<Arc<ChainSpec>> = LazyLock::new(|| {
112
174
/// Includes 20 prefunded accounts with `10_000` ETH each derived from mnemonic "test test test test
113
175
/// test test test test test test test junk".
114
176
pub static DEV : LazyLock < Arc < ChainSpec > > = LazyLock :: new ( || {
177
+ let genesis = serde_json:: from_str ( include_str ! ( "../res/genesis/dev.json" ) )
178
+ . expect ( "Can't deserialize Dev testnet genesis json" ) ;
179
+ let hardforks = DEV_HARDFORKS . clone ( ) ;
115
180
ChainSpec {
116
181
chain : Chain :: dev ( ) ,
117
- genesis : serde_json:: from_str ( include_str ! ( "../res/genesis/dev.json" ) )
118
- . expect ( "Can't deserialize Dev testnet genesis json" ) ,
119
- genesis_hash : once_cell_set ( DEV_GENESIS_HASH ) ,
182
+ genesis_header : SealedHeader :: new (
183
+ make_genesis_header ( & genesis, & hardforks) ,
184
+ DEV_GENESIS_HASH ,
185
+ ) ,
186
+ genesis,
120
187
paris_block_and_final_difficulty : Some ( ( 0 , U256 :: from ( 0 ) ) ) ,
121
188
hardforks : DEV_HARDFORKS . clone ( ) ,
122
189
base_fee_params : BaseFeeParamsKind :: Constant ( BaseFeeParams :: ethereum ( ) ) ,
@@ -220,17 +287,8 @@ pub struct ChainSpec {
220
287
/// The genesis block.
221
288
pub genesis : Genesis ,
222
289
223
- /// The hash of the genesis block.
224
- ///
225
- /// This is either stored at construction time if it is known using [`once_cell_set`], or
226
- /// computed once on the first access.
227
- pub genesis_hash : OnceLock < B256 > ,
228
-
229
290
/// The header corresponding to the genesis block.
230
- ///
231
- /// This is either stored at construction time if it is known using [`once_cell_set`], or
232
- /// computed once on the first access.
233
- pub genesis_header : OnceLock < Header > ,
291
+ pub genesis_header : SealedHeader ,
234
292
235
293
/// The block at which [`EthereumHardfork::Paris`] was activated and the final difficulty at
236
294
/// this block.
@@ -256,7 +314,6 @@ impl Default for ChainSpec {
256
314
fn default ( ) -> Self {
257
315
Self {
258
316
chain : Default :: default ( ) ,
259
- genesis_hash : Default :: default ( ) ,
260
317
genesis : Default :: default ( ) ,
261
318
genesis_header : Default :: default ( ) ,
262
319
paris_block_and_final_difficulty : Default :: default ( ) ,
@@ -307,55 +364,7 @@ impl ChainSpec {
307
364
308
365
/// Get the header for the genesis block.
309
366
pub fn genesis_header ( & self ) -> & Header {
310
- self . genesis_header . get_or_init ( || self . make_genesis_header ( ) )
311
- }
312
-
313
- fn make_genesis_header ( & self ) -> Header {
314
- // If London is activated at genesis, we set the initial base fee as per EIP-1559.
315
- let base_fee_per_gas = self . initial_base_fee ( ) ;
316
-
317
- // If shanghai is activated, initialize the header with an empty withdrawals hash, and
318
- // empty withdrawals list.
319
- let withdrawals_root = self
320
- . fork ( EthereumHardfork :: Shanghai )
321
- . active_at_timestamp ( self . genesis . timestamp )
322
- . then_some ( EMPTY_WITHDRAWALS ) ;
323
-
324
- // If Cancun is activated at genesis, we set:
325
- // * parent beacon block root to 0x0
326
- // * blob gas used to provided genesis or 0x0
327
- // * excess blob gas to provided genesis or 0x0
328
- let ( parent_beacon_block_root, blob_gas_used, excess_blob_gas) =
329
- if self . is_cancun_active_at_timestamp ( self . genesis . timestamp ) {
330
- let blob_gas_used = self . genesis . blob_gas_used . unwrap_or ( 0 ) ;
331
- let excess_blob_gas = self . genesis . excess_blob_gas . unwrap_or ( 0 ) ;
332
- ( Some ( B256 :: ZERO ) , Some ( blob_gas_used) , Some ( excess_blob_gas) )
333
- } else {
334
- ( None , None , None )
335
- } ;
336
-
337
- // If Prague is activated at genesis we set requests root to an empty trie root.
338
- let requests_hash = self
339
- . is_prague_active_at_timestamp ( self . genesis . timestamp )
340
- . then_some ( EMPTY_REQUESTS_HASH ) ;
341
-
342
- Header {
343
- gas_limit : self . genesis . gas_limit ,
344
- difficulty : self . genesis . difficulty ,
345
- nonce : self . genesis . nonce . into ( ) ,
346
- extra_data : self . genesis . extra_data . clone ( ) ,
347
- state_root : state_root_ref_unhashed ( & self . genesis . alloc ) ,
348
- timestamp : self . genesis . timestamp ,
349
- mix_hash : self . genesis . mix_hash ,
350
- beneficiary : self . genesis . coinbase ,
351
- base_fee_per_gas,
352
- withdrawals_root,
353
- parent_beacon_block_root,
354
- blob_gas_used,
355
- excess_blob_gas,
356
- requests_hash,
357
- ..Default :: default ( )
358
- }
367
+ & self . genesis_header
359
368
}
360
369
361
370
/// Get the sealed header for the genesis block.
@@ -413,7 +422,7 @@ impl ChainSpec {
413
422
414
423
/// Get the hash of the genesis block.
415
424
pub fn genesis_hash ( & self ) -> B256 {
416
- * self . genesis_hash . get_or_init ( || self . genesis_header ( ) . hash_slow ( ) )
425
+ self . genesis_header . hash ( )
417
426
}
418
427
419
428
/// Get the timestamp of the genesis block.
@@ -728,11 +737,13 @@ impl From<Genesis> for ChainSpec {
728
737
DepositContract { address, block : 0 , topic : MAINNET_DEPOSIT_CONTRACT . topic }
729
738
} ) ;
730
739
740
+ let hardforks = ChainHardforks :: new ( ordered_hardforks) ;
741
+
731
742
Self {
732
743
chain : genesis. config . chain_id . into ( ) ,
744
+ genesis_header : SealedHeader :: new_unhashed ( make_genesis_header ( & genesis, & hardforks) ) ,
733
745
genesis,
734
- genesis_hash : OnceLock :: new ( ) ,
735
- hardforks : ChainHardforks :: new ( ordered_hardforks) ,
746
+ hardforks,
736
747
paris_block_and_final_difficulty,
737
748
deposit_contract,
738
749
blob_params,
@@ -974,10 +985,14 @@ impl ChainSpecBuilder {
974
985
}
975
986
} )
976
987
} ;
988
+ let genesis = self . genesis . expect ( "The genesis is required" ) ;
977
989
ChainSpec {
978
990
chain : self . chain . expect ( "The chain is required" ) ,
979
- genesis : self . genesis . expect ( "The genesis is required" ) ,
980
- genesis_hash : OnceLock :: new ( ) ,
991
+ genesis_header : SealedHeader :: new_unhashed ( make_genesis_header (
992
+ & genesis,
993
+ & self . hardforks ,
994
+ ) ) ,
995
+ genesis,
981
996
hardforks : self . hardforks ,
982
997
paris_block_and_final_difficulty,
983
998
deposit_contract : None ,
@@ -1930,7 +1945,6 @@ Post-merge hard forks (timestamp based):
1930
1945
assert_eq ! ( & alloy_rlp:: encode( TrieAccount :: from( account. clone( ) ) ) , expected_rlp) ;
1931
1946
}
1932
1947
1933
- assert_eq ! ( chainspec. genesis_hash. get( ) , None ) ;
1934
1948
let expected_state_root: B256 =
1935
1949
hex ! ( "078dc6061b1d8eaa8493384b59c9c65ceb917201221d08b80c4de6770b6ec7e7" ) . into ( ) ;
1936
1950
assert_eq ! ( chainspec. genesis_header( ) . state_root, expected_state_root) ;
@@ -2003,7 +2017,6 @@ Post-merge hard forks (timestamp based):
2003
2017
2004
2018
let genesis = serde_json:: from_str :: < Genesis > ( hive_json) . unwrap ( ) ;
2005
2019
let chainspec: ChainSpec = genesis. into ( ) ;
2006
- assert_eq ! ( chainspec. genesis_hash. get( ) , None ) ;
2007
2020
assert_eq ! ( chainspec. chain, Chain :: from_named( NamedChain :: Optimism ) ) ;
2008
2021
let expected_state_root: B256 =
2009
2022
hex ! ( "9a6049ac535e3dc7436c189eaa81c73f35abd7f282ab67c32944ff0301d63360" ) . into ( ) ;
@@ -2318,7 +2331,6 @@ Post-merge hard forks (timestamp based):
2318
2331
let spec = ChainSpec {
2319
2332
chain : Chain :: mainnet ( ) ,
2320
2333
genesis : Genesis :: default ( ) ,
2321
- genesis_hash : OnceLock :: new ( ) ,
2322
2334
hardforks : ChainHardforks :: new ( vec ! [ (
2323
2335
EthereumHardfork :: Frontier . boxed( ) ,
2324
2336
ForkCondition :: Never ,
@@ -2336,7 +2348,6 @@ Post-merge hard forks (timestamp based):
2336
2348
let spec = ChainSpec {
2337
2349
chain : Chain :: mainnet ( ) ,
2338
2350
genesis : Genesis :: default ( ) ,
2339
- genesis_hash : OnceLock :: new ( ) ,
2340
2351
hardforks : ChainHardforks :: new ( vec ! [ (
2341
2352
EthereumHardfork :: Shanghai . boxed( ) ,
2342
2353
ForkCondition :: Never ,
0 commit comments