alloy_genesis/
lib.rs

1//! Alloy genesis types
2
3#![doc = include_str!(".././README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg",
6    html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14use alloc::{collections::BTreeMap, string::String, vec::Vec};
15use alloy_eips::{eip7840::BlobParams, BlobScheduleBlobParams};
16use alloy_primitives::{keccak256, Address, Bytes, B256, U256};
17use alloy_serde::{storage::deserialize_storage_map, OtherFields};
18use alloy_trie::{TrieAccount, EMPTY_ROOT_HASH, KECCAK_EMPTY};
19use core::str::FromStr;
20use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
21
22/// The genesis block specification.
23#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase", default)]
25pub struct Genesis {
26    /// The fork configuration for this network.
27    #[serde(default)]
28    pub config: ChainConfig,
29    /// The genesis header nonce.
30    #[serde(with = "alloy_serde::quantity")]
31    pub nonce: u64,
32    /// The genesis header timestamp.
33    #[serde(with = "alloy_serde::quantity")]
34    pub timestamp: u64,
35    /// The genesis header extra data.
36    pub extra_data: Bytes,
37    /// The genesis header gas limit.
38    #[serde(with = "alloy_serde::quantity")]
39    pub gas_limit: u64,
40    /// The genesis header difficulty.
41    pub difficulty: U256,
42    /// The genesis header mix hash.
43    pub mix_hash: B256,
44    /// The genesis header coinbase address.
45    pub coinbase: Address,
46    /// The initial state of accounts in the genesis block.
47    pub alloc: BTreeMap<Address, GenesisAccount>,
48    // NOTE: the following fields:
49    // * base_fee_per_gas
50    // * excess_blob_gas
51    // * blob_gas_used
52    // * number
53    // should NOT be set in a real genesis file, but are included here for compatibility with
54    // consensus tests, which have genesis files with these fields populated.
55    /// The genesis header base fee
56    #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
57    pub base_fee_per_gas: Option<u128>,
58    /// The genesis header excess blob gas
59    #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
60    pub excess_blob_gas: Option<u64>,
61    /// The genesis header blob gas used
62    #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
63    pub blob_gas_used: Option<u64>,
64    /// The genesis block number
65    #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
66    pub number: Option<u64>,
67}
68
69impl Genesis {
70    /// Creates a chain config for Clique using the given chain id and funds the given address with
71    /// max coins.
72    ///
73    /// Enables all hard forks up to London at genesis.
74    pub fn clique_genesis(chain_id: u64, signer_addr: Address) -> Self {
75        // set up a clique config with an instant sealing period and short (8 block) epoch
76        let clique_config = CliqueConfig { period: Some(0), epoch: Some(8) };
77
78        let config = ChainConfig {
79            chain_id,
80            eip155_block: Some(0),
81            eip150_block: Some(0),
82            eip158_block: Some(0),
83
84            homestead_block: Some(0),
85            byzantium_block: Some(0),
86            constantinople_block: Some(0),
87            petersburg_block: Some(0),
88            istanbul_block: Some(0),
89            muir_glacier_block: Some(0),
90            berlin_block: Some(0),
91            london_block: Some(0),
92            clique: Some(clique_config),
93            ..Default::default()
94        };
95
96        // fund account
97        let alloc = BTreeMap::from([(
98            signer_addr,
99            GenesisAccount { balance: U256::MAX, ..Default::default() },
100        )]);
101
102        // put signer address in the extra data, padded by the required amount of zeros
103        // Clique issue: https://github.com/ethereum/EIPs/issues/225
104        // Clique EIP: https://eips.ethereum.org/EIPS/eip-225
105        //
106        // The first 32 bytes are vanity data, so we will populate it with zeros
107        // This is followed by the signer address, which is 20 bytes
108        // There are 65 bytes of zeros after the signer address, which is usually populated with the
109        // proposer signature. Because the genesis does not have a proposer signature, it will be
110        // populated with zeros.
111        let extra_data_bytes = [&[0u8; 32][..], signer_addr.as_slice(), &[0u8; 65][..]].concat();
112        let extra_data = extra_data_bytes.into();
113
114        Self {
115            config,
116            alloc,
117            difficulty: U256::from(1),
118            gas_limit: 5_000_000,
119            extra_data,
120            ..Default::default()
121        }
122    }
123
124    /// Set the nonce.
125    pub const fn with_nonce(mut self, nonce: u64) -> Self {
126        self.nonce = nonce;
127        self
128    }
129
130    /// Set the timestamp.
131    pub const fn with_timestamp(mut self, timestamp: u64) -> Self {
132        self.timestamp = timestamp;
133        self
134    }
135
136    /// Set the extra data.
137    pub fn with_extra_data(mut self, extra_data: Bytes) -> Self {
138        self.extra_data = extra_data;
139        self
140    }
141
142    /// Set the gas limit.
143    pub const fn with_gas_limit(mut self, gas_limit: u64) -> Self {
144        self.gas_limit = gas_limit;
145        self
146    }
147
148    /// Set the difficulty.
149    pub const fn with_difficulty(mut self, difficulty: U256) -> Self {
150        self.difficulty = difficulty;
151        self
152    }
153
154    /// Set the mix hash of the header.
155    pub const fn with_mix_hash(mut self, mix_hash: B256) -> Self {
156        self.mix_hash = mix_hash;
157        self
158    }
159
160    /// Set the coinbase address.
161    pub const fn with_coinbase(mut self, address: Address) -> Self {
162        self.coinbase = address;
163        self
164    }
165
166    /// Set the base fee.
167    pub const fn with_base_fee(mut self, base_fee: Option<u128>) -> Self {
168        self.base_fee_per_gas = base_fee;
169        self
170    }
171
172    /// Set the excess blob gas.
173    pub const fn with_excess_blob_gas(mut self, excess_blob_gas: Option<u64>) -> Self {
174        self.excess_blob_gas = excess_blob_gas;
175        self
176    }
177
178    /// Set the blob gas used.
179    pub const fn with_blob_gas_used(mut self, blob_gas_used: Option<u64>) -> Self {
180        self.blob_gas_used = blob_gas_used;
181        self
182    }
183
184    /// Add accounts to the genesis block. If the address is already present,
185    /// the account is updated.
186    pub fn extend_accounts(
187        mut self,
188        accounts: impl IntoIterator<Item = (Address, GenesisAccount)>,
189    ) -> Self {
190        self.alloc.extend(accounts);
191        self
192    }
193}
194
195/// An account in the state of the genesis block.
196#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
197#[serde(deny_unknown_fields)]
198pub struct GenesisAccount {
199    /// The nonce of the account at genesis.
200    #[serde(skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt", default)]
201    pub nonce: Option<u64>,
202    /// The balance of the account at genesis.
203    pub balance: U256,
204    /// The account's bytecode at genesis.
205    #[serde(default, skip_serializing_if = "Option::is_none")]
206    pub code: Option<Bytes>,
207    /// The account's storage at genesis.
208    #[serde(
209        default,
210        skip_serializing_if = "Option::is_none",
211        deserialize_with = "deserialize_storage_map"
212    )]
213    pub storage: Option<BTreeMap<B256, B256>>,
214    /// The account's private key. Should only be used for testing.
215    #[serde(
216        rename = "secretKey",
217        default,
218        skip_serializing_if = "Option::is_none",
219        deserialize_with = "deserialize_private_key"
220    )]
221    pub private_key: Option<B256>,
222}
223
224impl GenesisAccount {
225    /// Set the nonce.
226    pub const fn with_nonce(mut self, nonce: Option<u64>) -> Self {
227        self.nonce = nonce;
228        self
229    }
230
231    /// Set the balance.
232    pub const fn with_balance(mut self, balance: U256) -> Self {
233        self.balance = balance;
234        self
235    }
236
237    /// Set the code.
238    pub fn with_code(mut self, code: Option<Bytes>) -> Self {
239        self.code = code;
240        self
241    }
242
243    /// Set the storage.
244    pub fn with_storage(mut self, storage: Option<BTreeMap<B256, B256>>) -> Self {
245        self.storage = storage;
246        self
247    }
248
249    /// Returns an iterator over the storage slots in (`B256`, `U256`) format.
250    pub fn storage_slots(&self) -> impl Iterator<Item = (B256, U256)> + '_ {
251        self.storage.as_ref().into_iter().flat_map(|storage| storage.iter()).map(|(key, value)| {
252            let value = U256::from_be_bytes(value.0);
253            (*key, value)
254        })
255    }
256
257    /// Convert the genesis account into the [`TrieAccount`] format.
258    pub fn into_trie_account(self) -> TrieAccount {
259        self.into()
260    }
261}
262
263impl From<GenesisAccount> for TrieAccount {
264    fn from(account: GenesisAccount) -> Self {
265        let storage_root = account
266            .storage
267            .map(|storage| {
268                alloy_trie::root::storage_root_unhashed(
269                    storage
270                        .into_iter()
271                        .filter(|(_, value)| !value.is_zero())
272                        .map(|(slot, value)| (slot, U256::from_be_bytes(*value))),
273                )
274            })
275            .unwrap_or(EMPTY_ROOT_HASH);
276
277        Self {
278            nonce: account.nonce.unwrap_or_default(),
279            balance: account.balance,
280            storage_root,
281            code_hash: account.code.map_or(KECCAK_EMPTY, keccak256),
282        }
283    }
284}
285
286/// Defines core blockchain settings per block.
287///
288/// Tailors unique settings for each network based on its genesis block.
289///
290/// Governs crucial blockchain behavior and adaptability.
291///
292/// Encapsulates parameters shaping network evolution and behavior.
293///
294/// See [geth's `ChainConfig`
295/// struct](https://github.com/ethereum/go-ethereum/blob/v1.14.0/params/config.go#L326)
296/// for the source of each field.
297#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
298#[serde(default, rename_all = "camelCase")]
299pub struct ChainConfig {
300    /// The network's chain ID.
301    pub chain_id: u64,
302
303    /// The homestead switch block (None = no fork, 0 = already homestead).
304    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
305    pub homestead_block: Option<u64>,
306
307    /// The DAO fork switch block (None = no fork).
308    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
309    pub dao_fork_block: Option<u64>,
310
311    /// Whether or not the node supports the DAO hard-fork.
312    pub dao_fork_support: bool,
313
314    /// The [EIP-150](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md) hard fork block (None = no fork).
315    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
316    pub eip150_block: Option<u64>,
317
318    /// The [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) hard fork block.
319    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
320    pub eip155_block: Option<u64>,
321
322    /// The [EIP-158](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-158.md) hard fork block.
323    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
324    pub eip158_block: Option<u64>,
325
326    /// The Byzantium hard fork block (None = no fork, 0 = already on byzantium).
327    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
328    pub byzantium_block: Option<u64>,
329
330    /// The Constantinople hard fork block (None = no fork, 0 = already on constantinople).
331    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
332    pub constantinople_block: Option<u64>,
333
334    /// The Petersburg hard fork block (None = no fork, 0 = already on petersburg).
335    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
336    pub petersburg_block: Option<u64>,
337
338    /// The Istanbul hard fork block (None = no fork, 0 = already on istanbul).
339    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
340    pub istanbul_block: Option<u64>,
341
342    /// The Muir Glacier hard fork block (None = no fork, 0 = already on muir glacier).
343    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
344    pub muir_glacier_block: Option<u64>,
345
346    /// The Berlin hard fork block (None = no fork, 0 = already on berlin).
347    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
348    pub berlin_block: Option<u64>,
349
350    /// The London hard fork block (None = no fork, 0 = already on london).
351    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
352    pub london_block: Option<u64>,
353
354    /// The Arrow Glacier hard fork block (None = no fork, 0 = already on arrow glacier).
355    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
356    pub arrow_glacier_block: Option<u64>,
357
358    /// The Gray Glacier hard fork block (None = no fork, 0 = already on gray glacier).
359    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
360    pub gray_glacier_block: Option<u64>,
361
362    /// Virtual fork after the merge to use as a network splitter.
363    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
364    pub merge_netsplit_block: Option<u64>,
365
366    /// Shanghai switch time (None = no fork, 0 = already on shanghai).
367    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
368    pub shanghai_time: Option<u64>,
369
370    /// Cancun switch time (None = no fork, 0 = already on cancun).
371    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
372    pub cancun_time: Option<u64>,
373
374    /// Prague switch time (None = no fork, 0 = already on prague).
375    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
376    pub prague_time: Option<u64>,
377
378    /// Osaka switch time (None = no fork, 0 = already on osaka).
379    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
380    pub osaka_time: Option<u64>,
381
382    /// BPO1 switch time (None = no fork, 0 = already on BPO1).
383    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
384    pub bpo1_time: Option<u64>,
385
386    /// BPO2 switch time (None = no fork, 0 = already on BPO2).
387    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
388    pub bpo2_time: Option<u64>,
389
390    /// BPO3 switch time (None = no fork, 0 = already on BPO3).
391    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
392    pub bpo3_time: Option<u64>,
393
394    /// BPO4 switch time (None = no fork, 0 = already on BPO4).
395    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
396    pub bpo4_time: Option<u64>,
397
398    /// BPO5 switch time (None = no fork, 0 = already on BPO5).
399    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_u64_opt")]
400    pub bpo5_time: Option<u64>,
401
402    /// Total difficulty reached that triggers the merge consensus upgrade.
403    #[serde(skip_serializing_if = "Option::is_none", with = "alloy_serde::ttd")]
404    pub terminal_total_difficulty: Option<U256>,
405
406    /// A flag specifying that the network already passed the terminal total difficulty. Its
407    /// purpose is to disable legacy sync without having seen the TTD locally.
408    pub terminal_total_difficulty_passed: bool,
409
410    /// Ethash parameters.
411    #[serde(skip_serializing_if = "Option::is_none")]
412    pub ethash: Option<EthashConfig>,
413
414    /// Clique parameters.
415    #[serde(skip_serializing_if = "Option::is_none")]
416    pub clique: Option<CliqueConfig>,
417
418    /// Parlia parameters.
419    #[serde(skip_serializing_if = "Option::is_none")]
420    pub parlia: Option<ParliaConfig>,
421
422    /// Additional fields specific to each chain.
423    #[serde(flatten, default)]
424    pub extra_fields: OtherFields,
425
426    /// The deposit contract address
427    #[serde(default, skip_serializing_if = "Option::is_none")]
428    pub deposit_contract_address: Option<Address>,
429
430    /// The blob schedule for the chain, indexed by hardfork name.
431    ///
432    /// See [EIP-7840](https://github.com/ethereum/EIPs/tree/master/EIPS/eip-7840.md).
433    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
434    pub blob_schedule: BTreeMap<String, BlobParams>,
435}
436
437/// Bincode-compatible [`ChainConfig`] serde implementation.
438#[cfg(feature = "serde-bincode-compat")]
439pub mod serde_bincode_compat {
440    use alloc::{
441        borrow::Cow,
442        collections::BTreeMap,
443        string::{String, ToString},
444    };
445    use alloy_primitives::{Address, U256};
446    use alloy_serde::OtherFields;
447    use serde::{Deserialize, Deserializer, Serialize, Serializer};
448    use serde_with::{DeserializeAs, SerializeAs};
449
450    /// Bincode-compatible [`super::ChainConfig`] serde implementation.
451    ///
452    /// Intended to use with the [`serde_with::serde_as`] macro in the following way:
453    /// ```rust
454    /// use alloy_genesis::{serde_bincode_compat, ChainConfig};
455    /// use serde::{Deserialize, Serialize};
456    /// use serde_with::serde_as;
457    ///
458    /// #[serde_as]
459    /// #[derive(Serialize, Deserialize)]
460    /// struct Data {
461    ///     #[serde_as(as = "serde_bincode_compat::ChainConfig")]
462    ///     config: ChainConfig,
463    /// }
464    /// ```
465    #[derive(Debug, Serialize, Deserialize)]
466    pub struct ChainConfig<'a> {
467        chain_id: u64,
468        #[serde(default)]
469        homestead_block: Option<u64>,
470        #[serde(default)]
471        dao_fork_block: Option<u64>,
472        #[serde(default)]
473        dao_fork_support: bool,
474        #[serde(default)]
475        eip150_block: Option<u64>,
476        #[serde(default)]
477        eip155_block: Option<u64>,
478        #[serde(default)]
479        eip158_block: Option<u64>,
480        #[serde(default)]
481        byzantium_block: Option<u64>,
482        #[serde(default)]
483        constantinople_block: Option<u64>,
484        #[serde(default)]
485        petersburg_block: Option<u64>,
486        #[serde(default)]
487        istanbul_block: Option<u64>,
488        #[serde(default)]
489        muir_glacier_block: Option<u64>,
490        #[serde(default)]
491        berlin_block: Option<u64>,
492        #[serde(default)]
493        london_block: Option<u64>,
494        #[serde(default)]
495        arrow_glacier_block: Option<u64>,
496        #[serde(default)]
497        gray_glacier_block: Option<u64>,
498        #[serde(default)]
499        merge_netsplit_block: Option<u64>,
500        #[serde(default)]
501        shanghai_time: Option<u64>,
502        #[serde(default)]
503        cancun_time: Option<u64>,
504        #[serde(default)]
505        prague_time: Option<u64>,
506        #[serde(default)]
507        osaka_time: Option<u64>,
508        #[serde(default)]
509        bpo1_time: Option<u64>,
510        #[serde(default)]
511        bpo2_time: Option<u64>,
512        #[serde(default)]
513        bpo3_time: Option<u64>,
514        #[serde(default)]
515        bpo4_time: Option<u64>,
516        #[serde(default)]
517        bpo5_time: Option<u64>,
518        #[serde(default)]
519        terminal_total_difficulty: Option<U256>,
520        #[serde(default)]
521        terminal_total_difficulty_passed: bool,
522        #[serde(default)]
523        ethash: Option<super::EthashConfig>,
524        #[serde(default)]
525        clique: Option<super::CliqueConfig>,
526        #[serde(default)]
527        parlia: Option<super::ParliaConfig>,
528        #[serde(default)]
529        deposit_contract_address: Option<Address>,
530        #[serde(default)]
531        blob_schedule: Cow<'a, BTreeMap<String, super::BlobParams>>,
532        /// Extra fields as string key-value pairs (bincode-compatible alternative to OtherFields)
533        #[serde(default)]
534        extra_fields: BTreeMap<String, String>,
535    }
536
537    impl<'a> From<&'a super::ChainConfig> for ChainConfig<'a> {
538        fn from(value: &'a super::ChainConfig) -> Self {
539            Self {
540                chain_id: value.chain_id,
541                homestead_block: value.homestead_block,
542                dao_fork_block: value.dao_fork_block,
543                dao_fork_support: value.dao_fork_support,
544                eip150_block: value.eip150_block,
545                eip155_block: value.eip155_block,
546                eip158_block: value.eip158_block,
547                byzantium_block: value.byzantium_block,
548                constantinople_block: value.constantinople_block,
549                petersburg_block: value.petersburg_block,
550                istanbul_block: value.istanbul_block,
551                muir_glacier_block: value.muir_glacier_block,
552                berlin_block: value.berlin_block,
553                london_block: value.london_block,
554                arrow_glacier_block: value.arrow_glacier_block,
555                gray_glacier_block: value.gray_glacier_block,
556                merge_netsplit_block: value.merge_netsplit_block,
557                shanghai_time: value.shanghai_time,
558                cancun_time: value.cancun_time,
559                prague_time: value.prague_time,
560                osaka_time: value.osaka_time,
561                bpo1_time: value.bpo1_time,
562                bpo2_time: value.bpo2_time,
563                bpo3_time: value.bpo3_time,
564                bpo4_time: value.bpo4_time,
565                bpo5_time: value.bpo5_time,
566                terminal_total_difficulty: value.terminal_total_difficulty,
567                terminal_total_difficulty_passed: value.terminal_total_difficulty_passed,
568                ethash: value.ethash,
569                clique: value.clique,
570                parlia: value.parlia,
571                deposit_contract_address: value.deposit_contract_address,
572                blob_schedule: Cow::Borrowed(&value.blob_schedule),
573                extra_fields: {
574                    let mut extra_fields = BTreeMap::new();
575                    for (k, v) in value.extra_fields.clone().into_iter() {
576                        // Convert all serde_json::Value types to string for bincode compatibility
577                        extra_fields.insert(k, v.to_string());
578                    }
579                    extra_fields
580                },
581            }
582        }
583    }
584
585    impl From<ChainConfig<'_>> for super::ChainConfig {
586        fn from(value: ChainConfig<'_>) -> Self {
587            Self {
588                chain_id: value.chain_id,
589                homestead_block: value.homestead_block,
590                dao_fork_block: value.dao_fork_block,
591                dao_fork_support: value.dao_fork_support,
592                eip150_block: value.eip150_block,
593                eip155_block: value.eip155_block,
594                eip158_block: value.eip158_block,
595                byzantium_block: value.byzantium_block,
596                constantinople_block: value.constantinople_block,
597                petersburg_block: value.petersburg_block,
598                istanbul_block: value.istanbul_block,
599                muir_glacier_block: value.muir_glacier_block,
600                berlin_block: value.berlin_block,
601                london_block: value.london_block,
602                arrow_glacier_block: value.arrow_glacier_block,
603                gray_glacier_block: value.gray_glacier_block,
604                merge_netsplit_block: value.merge_netsplit_block,
605                shanghai_time: value.shanghai_time,
606                cancun_time: value.cancun_time,
607                prague_time: value.prague_time,
608                osaka_time: value.osaka_time,
609                bpo1_time: value.bpo1_time,
610                bpo2_time: value.bpo2_time,
611                bpo3_time: value.bpo3_time,
612                bpo4_time: value.bpo4_time,
613                bpo5_time: value.bpo5_time,
614                terminal_total_difficulty: value.terminal_total_difficulty,
615                terminal_total_difficulty_passed: value.terminal_total_difficulty_passed,
616                ethash: value.ethash,
617                clique: value.clique,
618                parlia: value.parlia,
619                extra_fields: {
620                    let mut extra_fields = OtherFields::default();
621                    for (k, v) in value.extra_fields {
622                        // Parse strings back to serde_json::Value
623                        extra_fields.insert(
624                            k,
625                            v.parse().expect("Failed to parse extra field value back to JSON"),
626                        );
627                    }
628                    extra_fields
629                },
630                deposit_contract_address: value.deposit_contract_address,
631                blob_schedule: value.blob_schedule.into_owned(),
632            }
633        }
634    }
635
636    impl<'a> SerializeAs<super::ChainConfig> for ChainConfig<'a> {
637        fn serialize_as<S>(source: &super::ChainConfig, serializer: S) -> Result<S::Ok, S::Error>
638        where
639            S: Serializer,
640        {
641            ChainConfig::from(source).serialize(serializer)
642        }
643    }
644
645    impl<'de> DeserializeAs<'de, super::ChainConfig> for ChainConfig<'de> {
646        fn deserialize_as<D>(deserializer: D) -> Result<super::ChainConfig, D::Error>
647        where
648            D: Deserializer<'de>,
649        {
650            ChainConfig::deserialize(deserializer).map(Into::into)
651        }
652    }
653
654    #[cfg(test)]
655    mod tests {
656        use super::super::ChainConfig;
657        use bincode::config;
658        use serde::{Deserialize, Serialize};
659        use serde_with::serde_as;
660
661        #[test]
662        fn test_chain_config_bincode_roundtrip() {
663            #[serde_as]
664            #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
665            struct Data {
666                #[serde_as(as = "super::ChainConfig")]
667                config: ChainConfig,
668            }
669
670            // Create a test config with mixed Some/None values to test serialization
671            let config = ChainConfig {
672                chain_id: 1,
673                homestead_block: None,
674                dao_fork_block: Some(100),
675                dao_fork_support: false,
676                eip150_block: None,
677                eip155_block: Some(200),
678                eip158_block: None,
679                byzantium_block: Some(300),
680                constantinople_block: None,
681                petersburg_block: None,
682                istanbul_block: None,
683                muir_glacier_block: None,
684                berlin_block: None,
685                london_block: None,
686                arrow_glacier_block: None,
687                gray_glacier_block: None,
688                merge_netsplit_block: None,
689                shanghai_time: None,
690                cancun_time: None,
691                prague_time: None,
692                osaka_time: None,
693                bpo1_time: None,
694                bpo2_time: None,
695                bpo3_time: None,
696                bpo4_time: None,
697                bpo5_time: None,
698                terminal_total_difficulty: None,
699                terminal_total_difficulty_passed: false,
700                ethash: None,
701                clique: None,
702                parlia: None,
703                extra_fields: Default::default(),
704                deposit_contract_address: None,
705                blob_schedule: Default::default(),
706            };
707
708            let data = Data { config };
709
710            let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
711            let (decoded, _) =
712                bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
713            assert_eq!(decoded, data);
714        }
715
716        #[test]
717        fn test_chain_config_serde_bincode_compat() {
718            use serde_with::serde_as;
719
720            #[serde_as]
721            #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
722            struct Data {
723                #[serde_as(as = "super::ChainConfig")]
724                config: crate::ChainConfig,
725            }
726
727            let mut config = crate::ChainConfig {
728                chain_id: 1,
729                homestead_block: None,
730                dao_fork_block: Some(100),
731                dao_fork_support: false,
732                eip150_block: None,
733                eip155_block: Some(200),
734                eip158_block: None,
735                byzantium_block: Some(300),
736                constantinople_block: None,
737                petersburg_block: None,
738                istanbul_block: None,
739                muir_glacier_block: None,
740                berlin_block: None,
741                london_block: None,
742                arrow_glacier_block: None,
743                gray_glacier_block: None,
744                merge_netsplit_block: None,
745                shanghai_time: None,
746                cancun_time: None,
747                prague_time: None,
748                osaka_time: None,
749                bpo1_time: None,
750                bpo2_time: None,
751                bpo3_time: None,
752                bpo4_time: None,
753                bpo5_time: None,
754                terminal_total_difficulty: None,
755                terminal_total_difficulty_passed: false,
756                ethash: None,
757                clique: None,
758                parlia: None,
759                extra_fields: Default::default(),
760                deposit_contract_address: None,
761                blob_schedule: Default::default(),
762            };
763
764            // Add some extra fields with different serde_json::Value types
765            config.extra_fields.insert(
766                "string_field".to_string(),
767                serde_json::Value::String("test_value".to_string()),
768            );
769            config.extra_fields.insert(
770                "number_field".to_string(),
771                serde_json::Value::Number(serde_json::Number::from(42)),
772            );
773            config.extra_fields.insert("bool_field".to_string(), serde_json::Value::Bool(true));
774
775            let data = Data { config };
776
777            // Test bincode serialization with serde_bincode_compat
778            let encoded = bincode::serde::encode_to_vec(&data, bincode::config::legacy()).unwrap();
779            let (decoded, _) =
780                bincode::serde::decode_from_slice::<Data, _>(&encoded, bincode::config::legacy())
781                    .unwrap();
782
783            assert_eq!(decoded, data);
784        }
785
786        #[test]
787        fn test_default_genesis_chain_config_bincode() {
788            use serde_with::serde_as;
789
790            #[serde_as]
791            #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
792            struct Data {
793                #[serde_as(as = "super::ChainConfig")]
794                config: crate::ChainConfig,
795            }
796
797            // Create a default genesis and extract its chain config
798            let genesis = crate::Genesis::default();
799            let config = genesis.config;
800
801            let data = Data { config };
802
803            // Test bincode serialization with serde_bincode_compat
804            let encoded = bincode::serde::encode_to_vec(&data, bincode::config::legacy()).unwrap();
805            let (decoded, _) =
806                bincode::serde::decode_from_slice::<Data, _>(&encoded, bincode::config::legacy())
807                    .unwrap();
808
809            assert_eq!(decoded, data);
810        }
811
812        #[test]
813        fn test_mainnet_genesis_chain_config_bincode() {
814            use serde_with::serde_as;
815
816            #[serde_as]
817            #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
818            struct Data {
819                #[serde_as(as = "super::ChainConfig")]
820                config: crate::ChainConfig,
821            }
822
823            // Parse the mainnet genesis JSON
824            let mainnet_genesis_json = include_str!("../dumpgenesis/mainnet.json");
825
826            // Parse the genesis JSON
827            let genesis: crate::Genesis = serde_json::from_str(mainnet_genesis_json).unwrap();
828            let config = genesis.config;
829
830            let data = Data { config };
831
832            // Test bincode serialization with serde_bincode_compat
833            let encoded = bincode::serde::encode_to_vec(&data, bincode::config::legacy()).unwrap();
834            let (decoded, _) =
835                bincode::serde::decode_from_slice::<Data, _>(&encoded, bincode::config::legacy())
836                    .unwrap();
837
838            assert_eq!(decoded, data);
839        }
840    }
841}
842
843impl ChainConfig {
844    /// Returns the [`BlobScheduleBlobParams`] from the configured blob schedule values.
845    pub fn blob_schedule_blob_params(&self) -> BlobScheduleBlobParams {
846        let mut cancun = None;
847        let mut prague = None;
848        let mut osaka = None;
849        let mut scheduled = Vec::new();
850
851        for (key, params) in &self.blob_schedule {
852            match key.as_str() {
853                "cancun" => cancun = Some(*params),
854                "prague" => prague = Some(*params),
855                "osaka" => osaka = Some(*params),
856                "bpo1" => {
857                    if let Some(timestamp) = self.bpo1_time {
858                        scheduled.push((timestamp, *params));
859                    }
860                }
861                "bpo2" => {
862                    if let Some(timestamp) = self.bpo2_time {
863                        scheduled.push((timestamp, *params));
864                    }
865                }
866                "bpo3" => {
867                    if let Some(timestamp) = self.bpo3_time {
868                        scheduled.push((timestamp, *params));
869                    }
870                }
871                "bpo4" => {
872                    if let Some(timestamp) = self.bpo4_time {
873                        scheduled.push((timestamp, *params));
874                    }
875                }
876                "bpo5" => {
877                    if let Some(timestamp) = self.bpo5_time {
878                        scheduled.push((timestamp, *params));
879                    }
880                }
881                _ => (),
882            }
883        }
884
885        scheduled.sort_by_key(|(timestamp, _)| *timestamp);
886
887        BlobScheduleBlobParams {
888            cancun: cancun.unwrap_or_else(BlobParams::cancun),
889            prague: prague.unwrap_or_else(BlobParams::prague),
890            osaka: osaka.unwrap_or_else(BlobParams::osaka),
891            scheduled,
892        }
893    }
894
895    /// Checks if the blockchain is active at or after the Homestead fork block.
896    pub fn is_homestead_active_at_block(&self, block: u64) -> bool {
897        self.is_active_at_block(self.homestead_block, block)
898    }
899
900    /// Checks if the blockchain is active at or after the EIP150 fork block.
901    pub fn is_eip150_active_at_block(&self, block: u64) -> bool {
902        self.is_active_at_block(self.eip150_block, block)
903    }
904
905    /// Checks if the blockchain is active at or after the EIP155 fork block.
906    pub fn is_eip155_active_at_block(&self, block: u64) -> bool {
907        self.is_active_at_block(self.eip155_block, block)
908    }
909
910    /// Checks if the blockchain is active at or after the EIP158 fork block.
911    pub fn is_eip158_active_at_block(&self, block: u64) -> bool {
912        self.is_active_at_block(self.eip158_block, block)
913    }
914
915    /// Checks if the blockchain is active at or after the Byzantium fork block.
916    pub fn is_byzantium_active_at_block(&self, block: u64) -> bool {
917        self.is_active_at_block(self.byzantium_block, block)
918    }
919
920    /// Checks if the blockchain is active at or after the Constantinople fork block.
921    pub fn is_constantinople_active_at_block(&self, block: u64) -> bool {
922        self.is_active_at_block(self.constantinople_block, block)
923    }
924
925    /// Checks if the blockchain is active at or after the Muir Glacier (EIP-2384) fork block.
926    pub fn is_muir_glacier_active_at_block(&self, block: u64) -> bool {
927        self.is_active_at_block(self.muir_glacier_block, block)
928    }
929
930    /// Checks if the blockchain is active at or after the Petersburg fork block.
931    pub fn is_petersburg_active_at_block(&self, block: u64) -> bool {
932        self.is_active_at_block(self.petersburg_block, block)
933    }
934
935    /// Checks if the blockchain is active at or after the Istanbul fork block.
936    pub fn is_istanbul_active_at_block(&self, block: u64) -> bool {
937        self.is_active_at_block(self.istanbul_block, block)
938    }
939
940    /// Checks if the blockchain is active at or after the Berlin fork block.
941    pub fn is_berlin_active_at_block(&self, block: u64) -> bool {
942        self.is_active_at_block(self.berlin_block, block)
943    }
944
945    /// Checks if the blockchain is active at or after the London fork block.
946    pub fn is_london_active_at_block(&self, block: u64) -> bool {
947        self.is_active_at_block(self.london_block, block)
948    }
949
950    /// Checks if the blockchain is active at or after the Arrow Glacier (EIP-4345) fork block.
951    pub fn is_arrow_glacier_active_at_block(&self, block: u64) -> bool {
952        self.is_active_at_block(self.arrow_glacier_block, block)
953    }
954
955    /// Checks if the blockchain is active at or after the Gray Glacier (EIP-5133) fork block.
956    pub fn is_gray_glacier_active_at_block(&self, block: u64) -> bool {
957        self.is_active_at_block(self.gray_glacier_block, block)
958    }
959
960    /// Checks if the blockchain is active at or after the Shanghai fork block and the specified
961    /// timestamp.
962    pub fn is_shanghai_active_at_block_and_timestamp(&self, block: u64, timestamp: u64) -> bool {
963        self.is_london_active_at_block(block)
964            && self.is_active_at_timestamp(self.shanghai_time, timestamp)
965    }
966
967    /// Checks if the blockchain is active at or after the Cancun fork block and the specified
968    /// timestamp.
969    pub fn is_cancun_active_at_block_and_timestamp(&self, block: u64, timestamp: u64) -> bool {
970        self.is_london_active_at_block(block)
971            && self.is_active_at_timestamp(self.cancun_time, timestamp)
972    }
973
974    // Private function handling the comparison logic for block numbers
975    fn is_active_at_block(&self, config_block: Option<u64>, block: u64) -> bool {
976        config_block.is_some_and(|cb| cb <= block)
977    }
978
979    // Private function handling the comparison logic for timestamps
980    fn is_active_at_timestamp(&self, config_timestamp: Option<u64>, timestamp: u64) -> bool {
981        config_timestamp.is_some_and(|cb| cb <= timestamp)
982    }
983}
984
985impl Default for ChainConfig {
986    fn default() -> Self {
987        Self {
988            // mainnet
989            chain_id: 1,
990            homestead_block: None,
991            dao_fork_block: None,
992            dao_fork_support: false,
993            eip150_block: None,
994            eip155_block: None,
995            eip158_block: None,
996            byzantium_block: None,
997            constantinople_block: None,
998            petersburg_block: None,
999            istanbul_block: None,
1000            muir_glacier_block: None,
1001            berlin_block: None,
1002            london_block: None,
1003            arrow_glacier_block: None,
1004            gray_glacier_block: None,
1005            merge_netsplit_block: None,
1006            shanghai_time: None,
1007            cancun_time: None,
1008            prague_time: None,
1009            osaka_time: None,
1010            bpo1_time: None,
1011            bpo2_time: None,
1012            bpo3_time: None,
1013            bpo4_time: None,
1014            bpo5_time: None,
1015            terminal_total_difficulty: None,
1016            terminal_total_difficulty_passed: false,
1017            ethash: None,
1018            clique: None,
1019            parlia: None,
1020            extra_fields: Default::default(),
1021            deposit_contract_address: None,
1022            blob_schedule: Default::default(),
1023        }
1024    }
1025}
1026
1027/// Empty consensus configuration for proof-of-work networks.
1028#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1029pub struct EthashConfig {}
1030
1031/// Consensus configuration for Clique.
1032#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1033pub struct CliqueConfig {
1034    /// Number of seconds between blocks to enforce.
1035    #[serde(default, skip_serializing_if = "Option::is_none")]
1036    pub period: Option<u64>,
1037
1038    /// Epoch length to reset votes and checkpoints.
1039    #[serde(default, skip_serializing_if = "Option::is_none")]
1040    pub epoch: Option<u64>,
1041}
1042
1043/// Consensus configuration for Parlia.
1044///
1045/// Parlia is the consensus engine for BNB Smart Chain.
1046/// For the general introduction: <https://docs.bnbchain.org/docs/learn/consensus/>
1047/// For the specification: <https://github.com/bnb-chain/bsc/blob/master/params/config.go#L558>
1048#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1049pub struct ParliaConfig {
1050    /// Number of seconds between blocks to enforce.
1051    #[serde(default, skip_serializing_if = "Option::is_none")]
1052    pub period: Option<u64>,
1053
1054    /// Epoch length to update validator set.
1055    #[serde(default, skip_serializing_if = "Option::is_none")]
1056    pub epoch: Option<u64>,
1057}
1058
1059/// Custom deserialization function for the private key.
1060///
1061/// This function allows the private key to be deserialized from a string or a `null` value.
1062///
1063/// We need a custom function here especially to handle the case where the private key is `0x` and
1064/// should be deserialized as `None`.
1065fn deserialize_private_key<'de, D>(deserializer: D) -> Result<Option<B256>, D::Error>
1066where
1067    D: Deserializer<'de>,
1068{
1069    if deserializer.is_human_readable() {
1070        match Option::<String>::deserialize(deserializer)? {
1071            Some(ref s) => {
1072                if s == "0x" {
1073                    return Ok(None);
1074                }
1075                B256::from_str(s).map(Some).map_err(D::Error::custom)
1076            }
1077            None => Ok(None),
1078        }
1079    } else {
1080        Option::<B256>::deserialize(deserializer)
1081    }
1082}
1083
1084/// Custom deserialization function for `Option<u64>`.
1085///
1086/// This function allows it to be deserialized from a number or a "quantity" hex string.
1087/// We need a custom function as this should only be used for non-human-readable formats.
1088fn deserialize_u64_opt<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
1089where
1090    D: Deserializer<'de>,
1091{
1092    if deserializer.is_human_readable() {
1093        alloy_serde::quantity::opt::deserialize(deserializer)
1094    } else {
1095        Option::<u64>::deserialize(deserializer)
1096    }
1097}
1098
1099#[cfg(test)]
1100mod tests {
1101    use super::*;
1102    use alloc::{collections::BTreeMap, vec};
1103    use alloy_primitives::{hex, Bytes};
1104    use alloy_trie::{root::storage_root_unhashed, TrieAccount};
1105    use core::str::FromStr;
1106    use serde_json::json;
1107
1108    #[test]
1109    fn genesis_defaults_config() {
1110        let s = r#"{}"#;
1111        let genesis: Genesis = serde_json::from_str(s).unwrap();
1112        assert_eq!(genesis.config.chain_id, 1);
1113    }
1114
1115    #[test]
1116    fn test_genesis() {
1117        let default_genesis = Genesis::default();
1118
1119        let nonce = 999;
1120        let timestamp = 12345;
1121        let extra_data = Bytes::from(b"extra-data");
1122        let gas_limit = 333333;
1123        let difficulty = U256::from(9000);
1124        let mix_hash =
1125            hex!("74385b512f1e0e47100907efe2b00ac78df26acba6dd16b0772923068a5801a8").into();
1126        let coinbase = hex!("265873b6faf3258b3ab0827805386a2a20ed040e").into();
1127        // create dummy account
1128        let first_address: Address = hex!("7618a8c597b89e01c66a1f662078992c52a30c9a").into();
1129        let mut account = BTreeMap::default();
1130        account.insert(first_address, GenesisAccount::default());
1131
1132        // check values updated
1133        let custom_genesis = Genesis::default()
1134            .with_nonce(nonce)
1135            .with_timestamp(timestamp)
1136            .with_extra_data(extra_data.clone())
1137            .with_gas_limit(gas_limit)
1138            .with_difficulty(difficulty)
1139            .with_mix_hash(mix_hash)
1140            .with_coinbase(coinbase)
1141            .extend_accounts(account.clone());
1142
1143        assert_ne!(custom_genesis, default_genesis);
1144        // check every field
1145        assert_eq!(custom_genesis.nonce, nonce);
1146        assert_eq!(custom_genesis.timestamp, timestamp);
1147        assert_eq!(custom_genesis.extra_data, extra_data);
1148        assert_eq!(custom_genesis.gas_limit, gas_limit);
1149        assert_eq!(custom_genesis.difficulty, difficulty);
1150        assert_eq!(custom_genesis.mix_hash, mix_hash);
1151        assert_eq!(custom_genesis.coinbase, coinbase);
1152        assert_eq!(custom_genesis.alloc, account.clone());
1153
1154        // update existing account
1155        assert_eq!(custom_genesis.alloc.len(), 1);
1156        let same_address = first_address;
1157        let new_alloc_account = GenesisAccount {
1158            nonce: Some(1),
1159            balance: U256::from(1),
1160            code: Some(b"code".into()),
1161            storage: Some(BTreeMap::default()),
1162            private_key: None,
1163        };
1164        let mut updated_account = BTreeMap::default();
1165        updated_account.insert(same_address, new_alloc_account);
1166        let custom_genesis = custom_genesis.extend_accounts(updated_account.clone());
1167        assert_ne!(account, updated_account);
1168        assert_eq!(custom_genesis.alloc.len(), 1);
1169
1170        // add second account
1171        let different_address = hex!("94e0681e3073dd71cec54b53afe988f39078fd1a").into();
1172        let more_accounts = BTreeMap::from([(different_address, GenesisAccount::default())]);
1173        let custom_genesis = custom_genesis.extend_accounts(more_accounts);
1174        assert_eq!(custom_genesis.alloc.len(), 2);
1175
1176        // ensure accounts are different
1177        let first_account = custom_genesis.alloc.get(&first_address);
1178        let second_account = custom_genesis.alloc.get(&different_address);
1179        assert!(first_account.is_some());
1180        assert!(second_account.is_some());
1181        assert_ne!(first_account, second_account);
1182    }
1183
1184    #[test]
1185    fn test_genesis_account() {
1186        let default_account = GenesisAccount::default();
1187
1188        let nonce = Some(1);
1189        let balance = U256::from(33);
1190        let code = Some(b"code".into());
1191        let root = hex!("9474ddfcea39c5a690d2744103e39d1ff1b03d18db10fc147d970ad24699395a").into();
1192        let value = hex!("58eb8294d9bb16832a9dabfcb270fff99ab8ee1d8764e4f3d9fdf59ec1dee469").into();
1193        let mut map = BTreeMap::default();
1194        map.insert(root, value);
1195        let storage = Some(map);
1196
1197        let genesis_account = GenesisAccount::default()
1198            .with_nonce(nonce)
1199            .with_balance(balance)
1200            .with_code(code.clone())
1201            .with_storage(storage.clone());
1202
1203        assert_ne!(default_account, genesis_account);
1204        // check every field
1205        assert_eq!(genesis_account.nonce, nonce);
1206        assert_eq!(genesis_account.balance, balance);
1207        assert_eq!(genesis_account.code, code);
1208        assert_eq!(genesis_account.storage, storage);
1209    }
1210
1211    #[test]
1212    fn parse_hive_genesis() {
1213        let geth_genesis = r#"
1214    {
1215        "difficulty": "0x20000",
1216        "gasLimit": "0x1",
1217        "alloc": {},
1218        "config": {
1219          "ethash": {},
1220          "chainId": 1
1221        }
1222    }
1223    "#;
1224
1225        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1226    }
1227
1228    #[test]
1229    fn parse_hive_clique_smoke_genesis() {
1230        let geth_genesis = r#"
1231    {
1232      "difficulty": "0x1",
1233      "gasLimit": "0x400000",
1234      "extraData":
1235    "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1236    ,   "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1237      "nonce": "0x0",
1238      "timestamp": "0x5c51a607",
1239      "alloc": {}
1240    }
1241    "#;
1242
1243        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1244    }
1245
1246    #[test]
1247    fn parse_non_hex_prefixed_balance() {
1248        // tests that we can parse balance / difficulty fields that are either hex or decimal
1249        let example_balance_json = r#"
1250    {
1251        "nonce": "0x0000000000000042",
1252        "difficulty": "34747478",
1253        "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
1254        "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1255        "timestamp": "0x123456",
1256        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1257        "extraData": "0xfafbfcfd",
1258        "gasLimit": "0x2fefd8",
1259        "alloc": {
1260            "0x3E951C9f69a06Bc3AD71fF7358DbC56bEd94b9F2": {
1261              "balance": "1000000000000000000000000000"
1262            },
1263            "0xe228C30d4e5245f967ac21726d5412dA27aD071C": {
1264              "balance": "1000000000000000000000000000"
1265            },
1266            "0xD59Ce7Ccc6454a2D2C2e06bbcf71D0Beb33480eD": {
1267              "balance": "1000000000000000000000000000"
1268            },
1269            "0x1CF4D54414eF51b41f9B2238c57102ab2e61D1F2": {
1270              "balance": "1000000000000000000000000000"
1271            },
1272            "0x249bE3fDEd872338C733cF3975af9736bdCb9D4D": {
1273              "balance": "1000000000000000000000000000"
1274            },
1275            "0x3fCd1bff94513712f8cD63d1eD66776A67D5F78e": {
1276              "balance": "1000000000000000000000000000"
1277            }
1278        },
1279        "config": {
1280            "ethash": {},
1281            "chainId": 10,
1282            "homesteadBlock": 0,
1283            "eip150Block": 0,
1284            "eip155Block": 0,
1285            "eip158Block": 0,
1286            "byzantiumBlock": 0,
1287            "constantinopleBlock": 0,
1288            "petersburgBlock": 0,
1289            "istanbulBlock": 0
1290        }
1291    }
1292    "#;
1293
1294        let genesis: Genesis = serde_json::from_str(example_balance_json).unwrap();
1295
1296        // check difficulty against hex ground truth
1297        let expected_difficulty = U256::from_str("0x2123456").unwrap();
1298        assert_eq!(expected_difficulty, genesis.difficulty);
1299
1300        // check all alloc balances
1301        let dec_balance = U256::from_str("1000000000000000000000000000").unwrap();
1302        for alloc in &genesis.alloc {
1303            assert_eq!(alloc.1.balance, dec_balance);
1304        }
1305    }
1306
1307    #[test]
1308    fn parse_hive_rpc_genesis() {
1309        let geth_genesis = r#"
1310    {
1311      "config": {
1312        "chainId": 7,
1313        "homesteadBlock": 0,
1314        "eip150Block": 0,
1315        "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689",
1316        "eip155Block": 0,
1317        "eip158Block": 0
1318      },
1319      "coinbase": "0x0000000000000000000000000000000000000000",
1320      "difficulty": "0x20000",
1321      "extraData":
1322    "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1323    ,   "gasLimit": "0x2fefd8",
1324      "nonce": "0x0000000000000000",
1325      "timestamp": "0x1234",
1326      "alloc": {
1327        "cf49fda3be353c69b41ed96333cd24302da4556f": {
1328          "balance": "0x123450000000000000000"
1329        },
1330        "0161e041aad467a890839d5b08b138c1e6373072": {
1331          "balance": "0x123450000000000000000"
1332        },
1333        "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
1334          "balance": "0x123450000000000000000"
1335        },
1336        "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
1337          "balance": "0x123450000000000000000"
1338        },
1339        "c5065c9eeebe6df2c2284d046bfc906501846c51": {
1340          "balance": "0x123450000000000000000"
1341        },
1342        "0000000000000000000000000000000000000314": {
1343          "balance": "0x0",
1344          "code":
1345    "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1346    ,       "storage": {
1347            "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
1348            "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
1349          }
1350        },
1351        "0000000000000000000000000000000000000315": {
1352          "balance": "0x9999999999999999999999999999999",
1353          "code":
1354    "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
1355        }
1356      }
1357    }
1358    "#;
1359
1360        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1361    }
1362
1363    #[test]
1364    fn parse_hive_graphql_genesis() {
1365        let geth_genesis = r#"
1366    {
1367        "config"     : {},
1368        "coinbase"   : "0x8888f1f195afa192cfee860698584c030f4c9db1",
1369        "difficulty" : "0x020000",
1370        "extraData"  : "0x42",
1371        "gasLimit"   : "0x2fefd8",
1372        "mixHash"    : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46",
1373        "nonce"      : "0x78cc16f7b4f65485",
1374        "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
1375        "timestamp"  : "0x54c98c81",
1376        "alloc"      : {
1377            "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
1378                "balance" : "0x09184e72a000"
1379            }
1380        }
1381    }
1382    "#;
1383
1384        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1385    }
1386
1387    #[test]
1388    fn parse_hive_engine_genesis() {
1389        let geth_genesis = r#"
1390    {
1391      "config": {
1392        "chainId": 7,
1393        "homesteadBlock": 0,
1394        "eip150Block": 0,
1395        "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689",
1396        "eip155Block": 0,
1397        "eip158Block": 0,
1398        "byzantiumBlock": 0,
1399        "constantinopleBlock": 0,
1400        "petersburgBlock": 0,
1401        "istanbulBlock": 0,
1402        "muirGlacierBlock": 0,
1403        "berlinBlock": 0,
1404        "yolov2Block": 0,
1405        "yolov3Block": 0,
1406        "londonBlock": 0
1407      },
1408      "coinbase": "0x0000000000000000000000000000000000000000",
1409      "difficulty": "0x30000",
1410      "extraData":
1411    "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1412    ,   "gasLimit": "0x2fefd8",
1413      "nonce": "0x0000000000000000",
1414      "timestamp": "0x1234",
1415      "alloc": {
1416        "cf49fda3be353c69b41ed96333cd24302da4556f": {
1417          "balance": "0x123450000000000000000"
1418        },
1419        "0161e041aad467a890839d5b08b138c1e6373072": {
1420          "balance": "0x123450000000000000000"
1421        },
1422        "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
1423          "balance": "0x123450000000000000000"
1424        },
1425        "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
1426          "balance": "0x123450000000000000000"
1427        },
1428        "c5065c9eeebe6df2c2284d046bfc906501846c51": {
1429          "balance": "0x123450000000000000000"
1430        },
1431        "0000000000000000000000000000000000000314": {
1432          "balance": "0x0",
1433          "code":
1434    "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1435    ,       "storage": {
1436            "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
1437            "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
1438          }
1439        },
1440        "0000000000000000000000000000000000000315": {
1441          "balance": "0x9999999999999999999999999999999",
1442          "code":
1443    "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
1444        },
1445        "0000000000000000000000000000000000000316": {
1446          "balance": "0x0",
1447          "code": "0x444355"
1448        },
1449        "0000000000000000000000000000000000000317": {
1450          "balance": "0x0",
1451          "code": "0x600160003555"
1452        }
1453      }
1454    }
1455    "#;
1456
1457        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1458    }
1459
1460    #[test]
1461    fn parse_hive_devp2p_genesis() {
1462        let geth_genesis = r#"
1463    {
1464        "config": {
1465            "chainId": 19763,
1466            "homesteadBlock": 0,
1467            "eip150Block": 0,
1468            "eip155Block": 0,
1469            "eip158Block": 0,
1470            "byzantiumBlock": 0,
1471            "ethash": {}
1472        },
1473        "nonce": "0xdeadbeefdeadbeef",
1474        "timestamp": "0x0",
1475        "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
1476        "gasLimit": "0x80000000",
1477        "difficulty": "0x20000",
1478        "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1479        "coinbase": "0x0000000000000000000000000000000000000000",
1480        "alloc": {
1481            "71562b71999873db5b286df957af199ec94617f7": {
1482                "balance": "0xffffffffffffffffffffffffff"
1483            }
1484        },
1485        "number": "0x0",
1486        "gasUsed": "0x0",
1487        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
1488    }
1489    "#;
1490
1491        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1492    }
1493
1494    #[test]
1495    fn parse_deposit_contract_address() {
1496        let genesis = r#"
1497    {
1498      "config": {
1499        "chainId": 1337,
1500        "homesteadBlock": 0,
1501        "eip150Block": 0,
1502        "eip155Block": 0,
1503        "eip158Block": 0,
1504        "byzantiumBlock": 0,
1505        "constantinopleBlock": 0,
1506        "petersburgBlock": 0,
1507        "istanbulBlock": 0,
1508        "muirGlacierBlock": 0,
1509        "berlinBlock": 0,
1510        "londonBlock": 0,
1511        "arrowGlacierBlock": 0,
1512        "grayGlacierBlock": 0,
1513        "shanghaiTime": 0,
1514        "cancunTime": 0,
1515        "pragueTime": 1,
1516        "osakaTime": 2,
1517        "terminalTotalDifficulty": 0,
1518        "depositContractAddress": "0x0000000000000000000000000000000000000000",
1519        "terminalTotalDifficultyPassed": true
1520      },
1521      "nonce": "0x0",
1522      "timestamp": "0x0",
1523      "extraData": "0x",
1524      "gasLimit": "0x4c4b40",
1525      "difficulty": "0x1",
1526      "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1527      "coinbase": "0x0000000000000000000000000000000000000000"
1528    }
1529    "#;
1530
1531        let got_genesis: Genesis = serde_json::from_str(genesis).unwrap();
1532        let expected_genesis = Genesis {
1533            config: ChainConfig {
1534                chain_id: 1337,
1535                homestead_block: Some(0),
1536                eip150_block: Some(0),
1537                eip155_block: Some(0),
1538                eip158_block: Some(0),
1539                byzantium_block: Some(0),
1540                constantinople_block: Some(0),
1541                petersburg_block: Some(0),
1542                istanbul_block: Some(0),
1543                muir_glacier_block: Some(0),
1544                berlin_block: Some(0),
1545                london_block: Some(0),
1546                arrow_glacier_block: Some(0),
1547                gray_glacier_block: Some(0),
1548                dao_fork_block: None,
1549                dao_fork_support: false,
1550                shanghai_time: Some(0),
1551                cancun_time: Some(0),
1552                prague_time: Some(1),
1553                osaka_time: Some(2),
1554                terminal_total_difficulty: Some(U256::ZERO),
1555                terminal_total_difficulty_passed: true,
1556                deposit_contract_address: Some(Address::ZERO),
1557                ..Default::default()
1558            },
1559            nonce: 0,
1560            timestamp: 0,
1561            extra_data: Bytes::new(),
1562            gas_limit: 0x4c4b40,
1563            difficulty: U256::from(1),
1564            ..Default::default()
1565        };
1566
1567        assert_eq!(expected_genesis, got_genesis);
1568    }
1569
1570    #[test]
1571    fn parse_prague_time() {
1572        let genesis = r#"
1573    {
1574      "config": {
1575        "chainId": 1337,
1576        "homesteadBlock": 0,
1577        "eip150Block": 0,
1578        "eip155Block": 0,
1579        "eip158Block": 0,
1580        "byzantiumBlock": 0,
1581        "constantinopleBlock": 0,
1582        "petersburgBlock": 0,
1583        "istanbulBlock": 0,
1584        "muirGlacierBlock": 0,
1585        "berlinBlock": 0,
1586        "londonBlock": 0,
1587        "arrowGlacierBlock": 0,
1588        "grayGlacierBlock": 0,
1589        "shanghaiTime": 0,
1590        "cancunTime": 0,
1591        "pragueTime": 1,
1592        "terminalTotalDifficulty": 0,
1593        "terminalTotalDifficultyPassed": true
1594      },
1595      "nonce": "0x0",
1596      "timestamp": "0x0",
1597      "extraData": "0x",
1598      "gasLimit": "0x4c4b40",
1599      "difficulty": "0x1",
1600      "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1601      "coinbase": "0x0000000000000000000000000000000000000000"
1602    }
1603    "#;
1604
1605        let got_genesis: Genesis = serde_json::from_str(genesis).unwrap();
1606        let expected_genesis = Genesis {
1607            config: ChainConfig {
1608                chain_id: 1337,
1609                homestead_block: Some(0),
1610                eip150_block: Some(0),
1611                eip155_block: Some(0),
1612                eip158_block: Some(0),
1613                byzantium_block: Some(0),
1614                constantinople_block: Some(0),
1615                petersburg_block: Some(0),
1616                istanbul_block: Some(0),
1617                muir_glacier_block: Some(0),
1618                berlin_block: Some(0),
1619                london_block: Some(0),
1620                arrow_glacier_block: Some(0),
1621                gray_glacier_block: Some(0),
1622                dao_fork_block: None,
1623                dao_fork_support: false,
1624                shanghai_time: Some(0),
1625                cancun_time: Some(0),
1626                prague_time: Some(1),
1627                terminal_total_difficulty: Some(U256::ZERO),
1628                terminal_total_difficulty_passed: true,
1629                ..Default::default()
1630            },
1631            nonce: 0,
1632            timestamp: 0,
1633            extra_data: Bytes::new(),
1634            gas_limit: 0x4c4b40,
1635            difficulty: U256::from(1),
1636            ..Default::default()
1637        };
1638
1639        assert_eq!(expected_genesis, got_genesis);
1640    }
1641
1642    #[test]
1643    fn parse_execution_apis_genesis() {
1644        let geth_genesis = r#"
1645    {
1646      "config": {
1647        "chainId": 1337,
1648        "homesteadBlock": 0,
1649        "eip150Block": 0,
1650        "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1651        "eip155Block": 0,
1652        "eip158Block": 0,
1653        "byzantiumBlock": 0,
1654        "constantinopleBlock": 0,
1655        "petersburgBlock": 0,
1656        "istanbulBlock": 0,
1657        "muirGlacierBlock": 0,
1658        "berlinBlock": 0,
1659        "londonBlock": 0,
1660        "arrowGlacierBlock": 0,
1661        "grayGlacierBlock": 0,
1662        "shanghaiTime": 0,
1663        "terminalTotalDifficulty": 0,
1664        "terminalTotalDifficultyPassed": true,
1665        "ethash": {}
1666      },
1667      "nonce": "0x0",
1668      "timestamp": "0x0",
1669      "extraData": "0x",
1670      "gasLimit": "0x4c4b40",
1671      "difficulty": "0x1",
1672      "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1673      "coinbase": "0x0000000000000000000000000000000000000000",
1674      "alloc": {
1675        "658bdf435d810c91414ec09147daa6db62406379": {
1676          "balance": "0x487a9a304539440000"
1677        },
1678        "aa00000000000000000000000000000000000000": {
1679          "code": "0x6042",
1680          "storage": {
1681            "0x0000000000000000000000000000000000000000000000000000000000000000":
1682    "0x0000000000000000000000000000000000000000000000000000000000000000",
1683            "0x0100000000000000000000000000000000000000000000000000000000000000":
1684    "0x0100000000000000000000000000000000000000000000000000000000000000",
1685            "0x0200000000000000000000000000000000000000000000000000000000000000":
1686    "0x0200000000000000000000000000000000000000000000000000000000000000",
1687            "0x0300000000000000000000000000000000000000000000000000000000000000":
1688    "0x0000000000000000000000000000000000000000000000000000000000000303"       },
1689          "balance": "0x1",
1690          "nonce": "0x1"
1691        },
1692        "bb00000000000000000000000000000000000000": {
1693          "code": "0x600154600354",
1694          "storage": {
1695            "0x0000000000000000000000000000000000000000000000000000000000000000":
1696    "0x0000000000000000000000000000000000000000000000000000000000000000",
1697            "0x0100000000000000000000000000000000000000000000000000000000000000":
1698    "0x0100000000000000000000000000000000000000000000000000000000000000",
1699            "0x0200000000000000000000000000000000000000000000000000000000000000":
1700    "0x0200000000000000000000000000000000000000000000000000000000000000",
1701            "0x0300000000000000000000000000000000000000000000000000000000000000":
1702    "0x0000000000000000000000000000000000000000000000000000000000000303"       },
1703          "balance": "0x2",
1704          "nonce": "0x1"
1705        }
1706      }
1707    }
1708    "#;
1709
1710        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1711    }
1712
1713    #[test]
1714    fn parse_hive_rpc_genesis_full() {
1715        let geth_genesis = r#"
1716    {
1717      "config": {
1718        "clique": {
1719          "period": 1
1720        },
1721        "chainId": 7,
1722        "homesteadBlock": 0,
1723        "eip150Block": 0,
1724        "eip155Block": 0,
1725        "eip158Block": 0
1726      },
1727      "coinbase": "0x0000000000000000000000000000000000000000",
1728      "difficulty": "0x020000",
1729      "extraData":
1730    "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1731    ,   "gasLimit": "0x2fefd8",
1732      "nonce": "0x0000000000000000",
1733      "timestamp": "0x1234",
1734      "alloc": {
1735        "cf49fda3be353c69b41ed96333cd24302da4556f": {
1736          "balance": "0x123450000000000000000"
1737        },
1738        "0161e041aad467a890839d5b08b138c1e6373072": {
1739          "balance": "0x123450000000000000000"
1740        },
1741        "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
1742          "balance": "0x123450000000000000000"
1743        },
1744        "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
1745          "balance": "0x123450000000000000000"
1746        },
1747        "c5065c9eeebe6df2c2284d046bfc906501846c51": {
1748          "balance": "0x123450000000000000000"
1749        },
1750        "0000000000000000000000000000000000000314": {
1751          "balance": "0x0",
1752          "code":
1753    "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1754    ,       "storage": {
1755            "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
1756            "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
1757          }
1758        },
1759        "0000000000000000000000000000000000000315": {
1760          "balance": "0x9999999999999999999999999999999",
1761          "code":
1762    "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
1763        }
1764      },
1765      "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1766      "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
1767    }
1768    "#;
1769
1770        let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1771        let alloc_entry = genesis
1772            .alloc
1773            .get(&Address::from_str("0000000000000000000000000000000000000314").unwrap())
1774            .expect("missing account for parsed genesis");
1775        let storage = alloc_entry.storage.as_ref().expect("missing storage for parsed genesis");
1776        let expected_storage = BTreeMap::from_iter(vec![
1777            (
1778                B256::from_str(
1779                    "0x0000000000000000000000000000000000000000000000000000000000000000",
1780                )
1781                .unwrap(),
1782                B256::from_str(
1783                    "0x0000000000000000000000000000000000000000000000000000000000001234",
1784                )
1785                .unwrap(),
1786            ),
1787            (
1788                B256::from_str(
1789                    "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9",
1790                )
1791                .unwrap(),
1792                B256::from_str(
1793                    "0x0000000000000000000000000000000000000000000000000000000000000001",
1794                )
1795                .unwrap(),
1796            ),
1797        ]);
1798        assert_eq!(storage, &expected_storage);
1799
1800        let expected_code =
1801    Bytes::from_str("0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1802    ).unwrap();
1803        let code = alloc_entry.code.as_ref().expect(
1804            "missing code for parsed
1805    genesis",
1806        );
1807        assert_eq!(code, &expected_code);
1808    }
1809
1810    #[test]
1811    fn test_hive_smoke_alloc_deserialize() {
1812        let hive_genesis = r#"
1813    {
1814        "nonce": "0x0000000000000042",
1815        "difficulty": "0x2123456",
1816        "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
1817        "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1818        "timestamp": "0x123456",
1819        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1820        "extraData": "0xfafbfcfd",
1821        "gasLimit": "0x2fefd8",
1822        "alloc": {
1823            "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {
1824                "balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1825            },
1826            "e6716f9544a56c530d868e4bfbacb172315bdead": {
1827                "balance": "0x11",
1828                "code": "0x12"
1829            },
1830            "b9c015918bdaba24b4ff057a92a3873d6eb201be": {
1831                "balance": "0x21",
1832                "storage": {
1833                    "0x0000000000000000000000000000000000000000000000000000000000000001": "0x22"
1834                }
1835            },
1836            "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {
1837                "balance": "0x31",
1838                "nonce": "0x32"
1839            },
1840            "0000000000000000000000000000000000000001": {
1841                "balance": "0x41"
1842            },
1843            "0000000000000000000000000000000000000002": {
1844                "balance": "0x51"
1845            },
1846            "0000000000000000000000000000000000000003": {
1847                "balance": "0x61"
1848            },
1849            "0000000000000000000000000000000000000004": {
1850                "balance": "0x71"
1851            }
1852        },
1853        "config": {
1854            "ethash": {},
1855            "chainId": 10,
1856            "homesteadBlock": 0,
1857            "eip150Block": 0,
1858            "eip155Block": 0,
1859            "eip158Block": 0,
1860            "byzantiumBlock": 0,
1861            "constantinopleBlock": 0,
1862            "petersburgBlock": 0,
1863            "istanbulBlock": 0
1864        }
1865    }
1866    "#;
1867
1868        let expected_genesis =
1869            Genesis {
1870                nonce: 0x0000000000000042,
1871                difficulty: U256::from(0x2123456),
1872                mix_hash: B256::from_str(
1873                    "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
1874                )
1875                .unwrap(),
1876                coinbase: Address::from_str("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(),
1877                timestamp: 0x123456,
1878                extra_data: Bytes::from_str("0xfafbfcfd").unwrap(),
1879                gas_limit: 0x2fefd8,
1880                base_fee_per_gas: None,
1881                excess_blob_gas: None,
1882                blob_gas_used: None,
1883                number: None,
1884                alloc: BTreeMap::from_iter(vec![
1885                (
1886                    Address::from_str("0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6").unwrap(),
1887                    GenesisAccount {
1888                        balance:
1889    U256::from_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
1890    unwrap(),                     nonce: None,
1891                        code: None,
1892                        storage: None,
1893                        private_key: None,
1894                    },
1895                ),
1896                (
1897                    Address::from_str("0xe6716f9544a56c530d868e4bfbacb172315bdead").unwrap(),
1898                    GenesisAccount {
1899                        balance: U256::from_str("0x11").unwrap(),
1900                        nonce: None,
1901                        code: Some(Bytes::from_str("0x12").unwrap()),
1902                        storage: None,
1903                        private_key: None,
1904                    },
1905                ),
1906                (
1907                    Address::from_str("0xb9c015918bdaba24b4ff057a92a3873d6eb201be").unwrap(),
1908                    GenesisAccount {
1909                        balance: U256::from_str("0x21").unwrap(),
1910                        nonce: None,
1911                        code: None,
1912                        storage: Some(BTreeMap::from_iter(vec![
1913                            (
1914
1915    B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001").
1916    unwrap(),
1917    B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000022").
1918    unwrap(),                         ),
1919                        ])),
1920                        private_key: None,
1921                    },
1922                ),
1923                (
1924                    Address::from_str("0x1a26338f0d905e295fccb71fa9ea849ffa12aaf4").unwrap(),
1925                    GenesisAccount {
1926                        balance: U256::from_str("0x31").unwrap(),
1927                        nonce: Some(0x32u64),
1928                        code: None,
1929                        storage: None,
1930                        private_key: None,
1931                    },
1932                ),
1933                (
1934                    Address::from_str("0x0000000000000000000000000000000000000001").unwrap(),
1935                    GenesisAccount {
1936                        balance: U256::from_str("0x41").unwrap(),
1937                        nonce: None,
1938                        code: None,
1939                        storage: None,
1940                        private_key: None,
1941                    },
1942                ),
1943                (
1944                    Address::from_str("0x0000000000000000000000000000000000000002").unwrap(),
1945                    GenesisAccount {
1946                        balance: U256::from_str("0x51").unwrap(),
1947                        nonce: None,
1948                        code: None,
1949                        storage: None,
1950                        private_key: None,
1951                    },
1952                ),
1953                (
1954                    Address::from_str("0x0000000000000000000000000000000000000003").unwrap(),
1955                    GenesisAccount {
1956                        balance: U256::from_str("0x61").unwrap(),
1957                        nonce: None,
1958                        code: None,
1959                        storage: None,
1960                        private_key: None,
1961                    },
1962                ),
1963                (
1964                    Address::from_str("0x0000000000000000000000000000000000000004").unwrap(),
1965                    GenesisAccount {
1966                        balance: U256::from_str("0x71").unwrap(),
1967                        nonce: None,
1968                        code: None,
1969                        storage: None,
1970                        private_key: None,
1971                    },
1972                ),
1973            ]),
1974                config: ChainConfig {
1975                    ethash: Some(EthashConfig {}),
1976                    chain_id: 10,
1977                    homestead_block: Some(0),
1978                    eip150_block: Some(0),
1979                    eip155_block: Some(0),
1980                    eip158_block: Some(0),
1981                    byzantium_block: Some(0),
1982                    constantinople_block: Some(0),
1983                    petersburg_block: Some(0),
1984                    istanbul_block: Some(0),
1985                    deposit_contract_address: None,
1986                    ..Default::default()
1987                },
1988            };
1989
1990        let deserialized_genesis: Genesis = serde_json::from_str(hive_genesis).unwrap();
1991        assert_eq!(
1992            deserialized_genesis, expected_genesis,
1993            "deserialized genesis
1994    {deserialized_genesis:#?} does not match expected {expected_genesis:#?}"
1995        );
1996    }
1997
1998    #[test]
1999    fn parse_dump_genesis_mainnet() {
2000        let mainnet = include_str!("../dumpgenesis/mainnet.json");
2001        let gen1 = serde_json::from_str::<Genesis>(mainnet).unwrap();
2002        let s = serde_json::to_string_pretty(&gen1).unwrap();
2003        let gen2 = serde_json::from_str::<Genesis>(&s).unwrap();
2004        assert_eq!(gen1, gen2);
2005    }
2006
2007    #[test]
2008    fn parse_dump_genesis_sepolia() {
2009        let sepolia = include_str!("../dumpgenesis/sepolia.json");
2010        let gen1 = serde_json::from_str::<Genesis>(sepolia).unwrap();
2011        let s = serde_json::to_string_pretty(&gen1).unwrap();
2012        let gen2 = serde_json::from_str::<Genesis>(&s).unwrap();
2013        assert_eq!(gen1, gen2);
2014    }
2015
2016    #[test]
2017    fn parse_dump_genesis_holesky() {
2018        let holesky = include_str!("../dumpgenesis/holesky.json");
2019        let gen1 = serde_json::from_str::<Genesis>(holesky).unwrap();
2020        let s = serde_json::to_string_pretty(&gen1).unwrap();
2021        let gen2 = serde_json::from_str::<Genesis>(&s).unwrap();
2022        assert_eq!(gen1, gen2);
2023    }
2024
2025    #[test]
2026    fn parse_extra_fields() {
2027        let geth_genesis = r#"
2028    {
2029        "difficulty": "0x20000",
2030        "gasLimit": "0x1",
2031        "alloc": {},
2032        "config": {
2033          "ethash": {},
2034          "chainId": 1,
2035          "string_field": "string_value",
2036          "numeric_field": 7,
2037          "object_field": {
2038            "sub_field": "sub_value"
2039          }
2040        }
2041    }
2042    "#;
2043        let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
2044        let actual_string_value = genesis.config.extra_fields.get("string_field").unwrap();
2045        assert_eq!(actual_string_value, "string_value");
2046        let actual_numeric_value = genesis.config.extra_fields.get("numeric_field").unwrap();
2047        assert_eq!(actual_numeric_value, 7);
2048        let actual_object_value = genesis.config.extra_fields.get("object_field").unwrap();
2049        assert_eq!(actual_object_value, &serde_json::json!({"sub_field": "sub_value"}));
2050    }
2051
2052    #[test]
2053    fn deserialize_private_key_as_none_when_0x() {
2054        // Test case where "secretKey" is "0x", expecting None
2055        let json_data = json!({
2056            "balance": "0x0",
2057            "secretKey": "0x"
2058        });
2059
2060        let account: GenesisAccount = serde_json::from_value(json_data).unwrap();
2061        assert_eq!(account.private_key, None);
2062    }
2063
2064    #[test]
2065    fn deserialize_private_key_with_valid_hex() {
2066        // Test case where "secretKey" is a valid hex string
2067        let json_data = json!({
2068            "balance": "0x0",
2069            "secretKey": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234"
2070        });
2071
2072        let account: GenesisAccount = serde_json::from_value(json_data).unwrap();
2073        let expected_key =
2074            B256::from_str("123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234")
2075                .unwrap();
2076        assert_eq!(account.private_key, Some(expected_key));
2077    }
2078
2079    #[test]
2080    fn deserialize_private_key_as_none_when_null() {
2081        // Test case where "secretKey" is null, expecting None
2082        let json_data = json!({
2083            "balance": "0x0",
2084            "secretKey": null
2085        });
2086
2087        let account: GenesisAccount = serde_json::from_value(json_data).unwrap();
2088        assert_eq!(account.private_key, None);
2089    }
2090
2091    #[test]
2092    fn deserialize_private_key_with_invalid_hex_fails() {
2093        // Test case where "secretKey" is an invalid hex string, expecting an error
2094        let json_data = json!({
2095            "balance": "0x0",
2096            "secretKey": "0xINVALIDHEX"
2097        });
2098
2099        let result: Result<GenesisAccount, _> = serde_json::from_value(json_data);
2100        assert!(result.is_err()); // The deserialization should fail due to invalid hex
2101    }
2102
2103    #[test]
2104    fn deserialize_private_key_with_empty_string_fails() {
2105        // Test case where "secretKey" is an empty string, expecting an error
2106        let json_data = json!({
2107            "secretKey": ""
2108        });
2109
2110        let result: Result<GenesisAccount, _> = serde_json::from_value(json_data);
2111        assert!(result.is_err()); // The deserialization should fail due to an empty string
2112    }
2113
2114    #[test]
2115    fn test_from_genesis_account_with_default_values() {
2116        let genesis_account = GenesisAccount::default();
2117
2118        // Convert the GenesisAccount to a TrieAccount
2119        let trie_account: TrieAccount = genesis_account.into();
2120
2121        // Check the fields are properly set.
2122        assert_eq!(trie_account.nonce, 0);
2123        assert_eq!(trie_account.balance, U256::default());
2124        assert_eq!(trie_account.storage_root, EMPTY_ROOT_HASH);
2125        assert_eq!(trie_account.code_hash, KECCAK_EMPTY);
2126
2127        // Check that the default Account converts to the same TrieAccount
2128        assert_eq!(TrieAccount::default(), trie_account);
2129    }
2130
2131    #[test]
2132    fn test_from_genesis_account_with_values() {
2133        // Create a GenesisAccount with specific values
2134        let mut storage = BTreeMap::new();
2135        storage.insert(B256::from([0x01; 32]), B256::from([0x02; 32]));
2136
2137        let genesis_account = GenesisAccount {
2138            nonce: Some(10),
2139            balance: U256::from(1000),
2140            code: Some(Bytes::from(vec![0x60, 0x61])),
2141            storage: Some(storage),
2142            private_key: None,
2143        };
2144
2145        // Convert the GenesisAccount to a TrieAccount
2146        let trie_account: TrieAccount = genesis_account.into();
2147
2148        let expected_storage_root = storage_root_unhashed(BTreeMap::from([(
2149            B256::from([0x01; 32]),
2150            U256::from_be_bytes(*B256::from([0x02; 32])),
2151        )]));
2152
2153        // Check that the fields are properly set.
2154        assert_eq!(trie_account.nonce, 10);
2155        assert_eq!(trie_account.balance, U256::from(1000));
2156        assert_eq!(trie_account.storage_root, expected_storage_root);
2157        assert_eq!(trie_account.code_hash, keccak256([0x60, 0x61]));
2158    }
2159
2160    #[test]
2161    fn test_from_genesis_account_with_zeroed_storage_values() {
2162        // Create a GenesisAccount with storage containing zero values
2163        let storage = BTreeMap::from([(B256::from([0x01; 32]), B256::from([0x00; 32]))]);
2164
2165        let genesis_account = GenesisAccount {
2166            nonce: Some(3),
2167            balance: U256::from(300),
2168            code: None,
2169            storage: Some(storage),
2170            private_key: None,
2171        };
2172
2173        // Convert the GenesisAccount to a TrieAccount
2174        let trie_account: TrieAccount = genesis_account.into();
2175
2176        // Check the fields are properly set.
2177        assert_eq!(trie_account.nonce, 3);
2178        assert_eq!(trie_account.balance, U256::from(300));
2179        // Zero values in storage should result in EMPTY_ROOT_HASH
2180        assert_eq!(trie_account.storage_root, EMPTY_ROOT_HASH);
2181        // No code provided, so code hash should be KECCAK_EMPTY
2182        assert_eq!(trie_account.code_hash, KECCAK_EMPTY);
2183    }
2184}