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