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