ethers_core/utils/
genesis.rs

1use std::{collections::HashMap, str::FromStr};
2
3use crate::{
4    types::{
5        serde_helpers::{
6            deserialize_stringified_eth_u64, deserialize_stringified_eth_u64_opt,
7            deserialize_stringified_numeric, deserialize_stringified_numeric_opt,
8            deserialize_stringified_u64_opt, Numeric,
9        },
10        Address, Bytes, H256, U256, U64,
11    },
12    utils::from_unformatted_hex_map,
13};
14use serde::{Deserialize, Serialize};
15
16/// This represents the chain configuration, specifying the genesis block, header fields, and hard
17/// fork switch blocks.
18#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
19#[serde(rename_all = "camelCase")]
20pub struct Genesis {
21    /// The fork configuration for this network.
22    #[serde(default)]
23    pub config: ChainConfig,
24
25    /// The genesis header nonce.
26    #[serde(default, deserialize_with = "deserialize_stringified_eth_u64")]
27    pub nonce: U64,
28
29    /// The genesis header timestamp.
30    #[serde(default, deserialize_with = "deserialize_stringified_eth_u64")]
31    pub timestamp: U64,
32
33    /// The genesis header extra data.
34    #[serde(default)]
35    pub extra_data: Bytes,
36
37    /// The genesis header gas limit.
38    #[serde(default, deserialize_with = "deserialize_stringified_eth_u64")]
39    pub gas_limit: U64,
40
41    /// The genesis header difficulty.
42    #[serde(deserialize_with = "deserialize_stringified_numeric")]
43    pub difficulty: U256,
44
45    /// The genesis header mix hash.
46    #[serde(default)]
47    pub mix_hash: H256,
48
49    /// The genesis header coinbase address.
50    #[serde(default)]
51    pub coinbase: Address,
52
53    /// The initial state of the genesis block.
54    pub alloc: HashMap<Address, GenesisAccount>,
55
56    // The following fields are only included for tests, and should not be used in real genesis
57    // blocks.
58    /// The block number
59    #[serde(
60        skip_serializing_if = "Option::is_none",
61        deserialize_with = "deserialize_stringified_eth_u64_opt",
62        default
63    )]
64    pub number: Option<U64>,
65
66    /// The block gas gasUsed
67    #[serde(
68        skip_serializing_if = "Option::is_none",
69        deserialize_with = "deserialize_stringified_eth_u64_opt",
70        default
71    )]
72    pub gas_used: Option<U64>,
73
74    /// The block parent hash
75    #[serde(skip_serializing_if = "Option::is_none", default)]
76    pub parent_hash: Option<H256>,
77
78    /// The base fee
79    #[serde(
80        skip_serializing_if = "Option::is_none",
81        deserialize_with = "deserialize_stringified_numeric_opt",
82        default
83    )]
84    pub base_fee_per_gas: Option<U256>,
85}
86
87impl Genesis {
88    /// Creates a chain config using the given chain id.
89    /// and funds the given address with max coins.
90    ///
91    /// Enables all hard forks up to London at genesis.
92    pub fn new(chain_id: u64, signer_addr: Address) -> Genesis {
93        // set up a clique config with an instant sealing period and short (8 block) epoch
94        let clique_config = CliqueConfig { period: Some(0), epoch: Some(8) };
95
96        let config = ChainConfig {
97            chain_id,
98            eip155_block: Some(0),
99            eip150_block: Some(0),
100            eip158_block: Some(0),
101
102            homestead_block: Some(0),
103            byzantium_block: Some(0),
104            constantinople_block: Some(0),
105            petersburg_block: Some(0),
106            istanbul_block: Some(0),
107            muir_glacier_block: Some(0),
108            berlin_block: Some(0),
109            london_block: Some(0),
110            clique: Some(clique_config),
111            ..Default::default()
112        };
113
114        // fund account
115        let mut alloc = HashMap::new();
116        alloc.insert(
117            signer_addr,
118            GenesisAccount { balance: U256::MAX, nonce: None, code: None, storage: None },
119        );
120
121        // put signer address in the extra data, padded by the required amount of zeros
122        // Clique issue: https://github.com/ethereum/EIPs/issues/225
123        // Clique EIP: https://eips.ethereum.org/EIPS/eip-225
124        //
125        // The first 32 bytes are vanity data, so we will populate it with zeros
126        // This is followed by the signer address, which is 20 bytes
127        // There are 65 bytes of zeros after the signer address, which is usually populated with the
128        // proposer signature. Because the genesis does not have a proposer signature, it will be
129        // populated with zeros.
130        let extra_data_bytes = [&[0u8; 32][..], signer_addr.as_bytes(), &[0u8; 65][..]].concat();
131        let extra_data = Bytes::from(extra_data_bytes);
132
133        Genesis {
134            config,
135            alloc,
136            difficulty: U256::one(),
137            gas_limit: U64::from(5000000),
138            extra_data,
139            ..Default::default()
140        }
141    }
142}
143
144/// An account in the state of the genesis block.
145#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
146pub struct GenesisAccount {
147    #[serde(
148        skip_serializing_if = "Option::is_none",
149        deserialize_with = "deserialize_stringified_u64_opt",
150        default
151    )]
152    pub nonce: Option<u64>,
153    #[serde(deserialize_with = "deserialize_stringified_numeric")]
154    pub balance: U256,
155    #[serde(skip_serializing_if = "Option::is_none", default)]
156    pub code: Option<Bytes>,
157    #[serde(
158        skip_serializing_if = "Option::is_none",
159        deserialize_with = "from_unformatted_hex_map",
160        default
161    )]
162    pub storage: Option<HashMap<H256, H256>>,
163}
164
165/// Represents a node's chain configuration.
166///
167/// See [geth's `ChainConfig`
168/// struct](https://github.com/ethereum/go-ethereum/blob/64dccf7aa411c5c7cd36090c3d9b9892945ae813/params/config.go#L349)
169/// for the source of each field.
170#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
171#[serde(default, rename_all = "camelCase")]
172pub struct ChainConfig {
173    /// The network's chain ID.
174    #[serde(default = "one")]
175    pub chain_id: u64,
176
177    /// The homestead switch block (None = no fork, 0 = already homestead).
178    #[serde(
179        skip_serializing_if = "Option::is_none",
180        deserialize_with = "deserialize_stringified_u64_opt"
181    )]
182    pub homestead_block: Option<u64>,
183
184    /// The DAO fork switch block (None = no fork).
185    #[serde(
186        skip_serializing_if = "Option::is_none",
187        deserialize_with = "deserialize_stringified_u64_opt"
188    )]
189    pub dao_fork_block: Option<u64>,
190
191    /// Whether or not the node supports the DAO hard-fork.
192    pub dao_fork_support: bool,
193
194    /// The EIP-150 hard fork block (None = no fork).
195    #[serde(
196        skip_serializing_if = "Option::is_none",
197        deserialize_with = "deserialize_stringified_u64_opt"
198    )]
199    pub eip150_block: Option<u64>,
200
201    /// The EIP-150 hard fork hash.
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub eip150_hash: Option<H256>,
204
205    /// The EIP-155 hard fork block.
206    #[serde(
207        skip_serializing_if = "Option::is_none",
208        deserialize_with = "deserialize_stringified_u64_opt"
209    )]
210    pub eip155_block: Option<u64>,
211
212    /// The EIP-158 hard fork block.
213    #[serde(
214        skip_serializing_if = "Option::is_none",
215        deserialize_with = "deserialize_stringified_u64_opt"
216    )]
217    pub eip158_block: Option<u64>,
218
219    /// The Byzantium hard fork block.
220    #[serde(
221        skip_serializing_if = "Option::is_none",
222        deserialize_with = "deserialize_stringified_u64_opt"
223    )]
224    pub byzantium_block: Option<u64>,
225
226    /// The Constantinople hard fork block.
227    #[serde(
228        skip_serializing_if = "Option::is_none",
229        deserialize_with = "deserialize_stringified_u64_opt"
230    )]
231    pub constantinople_block: Option<u64>,
232
233    /// The Petersburg hard fork block.
234    #[serde(
235        skip_serializing_if = "Option::is_none",
236        deserialize_with = "deserialize_stringified_u64_opt"
237    )]
238    pub petersburg_block: Option<u64>,
239
240    /// The Istanbul hard fork block.
241    #[serde(
242        skip_serializing_if = "Option::is_none",
243        deserialize_with = "deserialize_stringified_u64_opt"
244    )]
245    pub istanbul_block: Option<u64>,
246
247    /// The Muir Glacier hard fork block.
248    #[serde(
249        skip_serializing_if = "Option::is_none",
250        deserialize_with = "deserialize_stringified_u64_opt"
251    )]
252    pub muir_glacier_block: Option<u64>,
253
254    /// The Berlin hard fork block.
255    #[serde(
256        skip_serializing_if = "Option::is_none",
257        deserialize_with = "deserialize_stringified_u64_opt"
258    )]
259    pub berlin_block: Option<u64>,
260
261    /// The London hard fork block.
262    #[serde(
263        skip_serializing_if = "Option::is_none",
264        deserialize_with = "deserialize_stringified_u64_opt"
265    )]
266    pub london_block: Option<u64>,
267
268    /// The Arrow Glacier hard fork block.
269    #[serde(
270        skip_serializing_if = "Option::is_none",
271        deserialize_with = "deserialize_stringified_u64_opt"
272    )]
273    pub arrow_glacier_block: Option<u64>,
274
275    /// The Gray Glacier hard fork block.
276    #[serde(
277        skip_serializing_if = "Option::is_none",
278        deserialize_with = "deserialize_stringified_u64_opt"
279    )]
280    pub gray_glacier_block: Option<u64>,
281
282    /// Virtual fork after the merge to use as a network splitter.
283    #[serde(
284        skip_serializing_if = "Option::is_none",
285        deserialize_with = "deserialize_stringified_u64_opt"
286    )]
287    pub merge_netsplit_block: Option<u64>,
288
289    /// Shanghai switch time.
290    #[serde(
291        skip_serializing_if = "Option::is_none",
292        deserialize_with = "deserialize_stringified_u64_opt"
293    )]
294    pub shanghai_time: Option<u64>,
295
296    /// Cancun switch time.
297    #[serde(
298        skip_serializing_if = "Option::is_none",
299        deserialize_with = "deserialize_stringified_u64_opt"
300    )]
301    pub cancun_time: Option<u64>,
302
303    /// Total difficulty reached that triggers the merge consensus upgrade.
304    #[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_ttd")]
305    pub terminal_total_difficulty: Option<U256>,
306
307    /// A flag specifying that the network already passed the terminal total difficulty. Its
308    /// purpose is to disable legacy sync without having seen the TTD locally.
309    pub terminal_total_difficulty_passed: bool,
310
311    /// Ethash parameters.
312    #[serde(skip_serializing_if = "Option::is_none")]
313    pub ethash: Option<EthashConfig>,
314
315    /// Clique parameters.
316    #[serde(skip_serializing_if = "Option::is_none")]
317    pub clique: Option<CliqueConfig>,
318}
319
320// used only for serde
321#[inline]
322const fn one() -> u64 {
323    1
324}
325
326/// Empty consensus configuration for proof-of-work networks.
327#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
328pub struct EthashConfig {}
329
330/// Consensus configuration for Clique.
331#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
332pub struct CliqueConfig {
333    /// Number of seconds between blocks to enforce.
334    #[serde(
335        default,
336        skip_serializing_if = "Option::is_none",
337        deserialize_with = "deserialize_stringified_u64_opt"
338    )]
339    pub period: Option<u64>,
340
341    /// Epoch length to reset votes and checkpoints.
342    #[serde(
343        default,
344        skip_serializing_if = "Option::is_none",
345        deserialize_with = "deserialize_stringified_u64_opt"
346    )]
347    pub epoch: Option<u64>,
348}
349
350fn deserialize_ttd<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
351where
352    D: serde::Deserializer<'de>,
353{
354    match Option::<serde_json::Value>::deserialize(deserializer)? {
355        None => Ok(None),
356        Some(val) => {
357            if let Some(num) = val.as_str() {
358                return Numeric::from_str(num)
359                    .map(U256::from)
360                    .map(Some)
361                    .map_err(serde::de::Error::custom)
362            }
363
364            if let serde_json::Value::Number(num) = val {
365                // geth serializes ttd as number, for mainnet this exceeds u64 which serde is unable
366                // to deserialize as integer
367                if num.as_f64() == Some(5.875e22) {
368                    Ok(Some(U256::from(58750000000000000000000u128)))
369                } else {
370                    num.as_u64()
371                        .map(U256::from)
372                        .ok_or_else(|| {
373                            serde::de::Error::custom(format!("expected a number got {num}"))
374                        })
375                        .map(Some)
376                }
377            } else {
378                Err(serde::de::Error::custom(format!("expected a number, got {:?}", val)))
379            }
380        }
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use super::{ChainConfig, Genesis, GenesisAccount, H256};
387    use crate::{
388        types::{Address, Bytes, H160, U256},
389        utils::EthashConfig,
390    };
391    use std::{collections::HashMap, str::FromStr};
392
393    #[test]
394    fn parse_hive_genesis() {
395        let geth_genesis = r#"
396        {
397            "difficulty": "0x20000",
398            "gasLimit": "0x1",
399            "alloc": {},
400            "config": {
401              "ethash": {},
402              "chainId": 1
403            }
404        }
405        "#;
406
407        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
408    }
409
410    #[test]
411    fn parse_hive_clique_smoke_genesis() {
412        let geth_genesis = r#"
413        {
414          "difficulty": "0x1",
415          "gasLimit": "0x400000",
416          "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
417          "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
418          "nonce": "0x0",
419          "timestamp": "0x5c51a607",
420          "alloc": {}
421        }
422        "#;
423
424        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
425    }
426
427    #[test]
428    fn parse_non_hex_prefixed_balance() {
429        // tests that we can parse balance / difficulty fields that are either hex or decimal
430        let example_balance_json = r#"
431        {
432            "nonce": "0x0000000000000042",
433            "difficulty": "34747478",
434            "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
435            "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
436            "timestamp": "0x123456",
437            "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
438            "extraData": "0xfafbfcfd",
439            "gasLimit": "0x2fefd8",
440            "alloc": {
441                "0x3E951C9f69a06Bc3AD71fF7358DbC56bEd94b9F2": {
442                  "balance": "1000000000000000000000000000"
443                },
444                "0xe228C30d4e5245f967ac21726d5412dA27aD071C": {
445                  "balance": "1000000000000000000000000000"
446                },
447                "0xD59Ce7Ccc6454a2D2C2e06bbcf71D0Beb33480eD": {
448                  "balance": "1000000000000000000000000000"
449                },
450                "0x1CF4D54414eF51b41f9B2238c57102ab2e61D1F2": {
451                  "balance": "1000000000000000000000000000"
452                },
453                "0x249bE3fDEd872338C733cF3975af9736bdCb9D4D": {
454                  "balance": "1000000000000000000000000000"
455                },
456                "0x3fCd1bff94513712f8cD63d1eD66776A67D5F78e": {
457                  "balance": "1000000000000000000000000000"
458                }
459            },
460            "config": {
461                "ethash": {},
462                "chainId": 10,
463                "homesteadBlock": 0,
464                "eip150Block": 0,
465                "eip155Block": 0,
466                "eip158Block": 0,
467                "byzantiumBlock": 0,
468                "constantinopleBlock": 0,
469                "petersburgBlock": 0,
470                "istanbulBlock": 0
471            }
472        }
473        "#;
474
475        let genesis: Genesis = serde_json::from_str(example_balance_json).unwrap();
476
477        // check difficulty against hex ground truth
478        let expected_difficulty = U256::from_str("0x2123456").unwrap();
479        assert_eq!(expected_difficulty, genesis.difficulty);
480
481        // check all alloc balances
482        let dec_balance = U256::from_dec_str("1000000000000000000000000000").unwrap();
483        for alloc in &genesis.alloc {
484            assert_eq!(alloc.1.balance, dec_balance);
485        }
486    }
487
488    #[test]
489    fn parse_hive_rpc_genesis() {
490        let geth_genesis = r#"
491        {
492          "config": {
493            "chainId": 7,
494            "homesteadBlock": 0,
495            "eip150Block": 0,
496            "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689",
497            "eip155Block": 0,
498            "eip158Block": 0
499          },
500          "coinbase": "0x0000000000000000000000000000000000000000",
501          "difficulty": "0x20000",
502          "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
503          "gasLimit": "0x2fefd8",
504          "nonce": "0x0000000000000000",
505          "timestamp": "0x1234",
506          "alloc": {
507            "cf49fda3be353c69b41ed96333cd24302da4556f": {
508              "balance": "0x123450000000000000000"
509            },
510            "0161e041aad467a890839d5b08b138c1e6373072": {
511              "balance": "0x123450000000000000000"
512            },
513            "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
514              "balance": "0x123450000000000000000"
515            },
516            "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
517              "balance": "0x123450000000000000000"
518            },
519            "c5065c9eeebe6df2c2284d046bfc906501846c51": {
520              "balance": "0x123450000000000000000"
521            },
522            "0000000000000000000000000000000000000314": {
523              "balance": "0x0",
524              "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029",
525              "storage": {
526                "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
527                "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
528              }
529            },
530            "0000000000000000000000000000000000000315": {
531              "balance": "0x9999999999999999999999999999999",
532              "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
533            }
534          }
535        }
536        "#;
537
538        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
539    }
540
541    #[test]
542    fn parse_hive_graphql_genesis() {
543        let geth_genesis = r#"
544        {
545            "config"     : {},
546            "coinbase"   : "0x8888f1f195afa192cfee860698584c030f4c9db1",
547            "difficulty" : "0x020000",
548            "extraData"  : "0x42",
549            "gasLimit"   : "0x2fefd8",
550            "mixHash"    : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46",
551            "nonce"      : "0x78cc16f7b4f65485",
552            "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
553            "timestamp"  : "0x54c98c81",
554            "alloc"      : {
555                "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
556                    "balance" : "0x09184e72a000"
557                }
558            }
559        }
560        "#;
561
562        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
563    }
564
565    #[test]
566    fn parse_hive_engine_genesis() {
567        let geth_genesis = r#"
568        {
569          "config": {
570            "chainId": 7,
571            "homesteadBlock": 0,
572            "eip150Block": 0,
573            "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689",
574            "eip155Block": 0,
575            "eip158Block": 0,
576            "byzantiumBlock": 0,
577            "constantinopleBlock": 0,
578            "petersburgBlock": 0,
579            "istanbulBlock": 0,
580            "muirGlacierBlock": 0,
581            "berlinBlock": 0,
582            "yolov2Block": 0,
583            "yolov3Block": 0,
584            "londonBlock": 0
585          },
586          "coinbase": "0x0000000000000000000000000000000000000000",
587          "difficulty": "0x30000",
588          "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
589          "gasLimit": "0x2fefd8",
590          "nonce": "0x0000000000000000",
591          "timestamp": "0x1234",
592          "alloc": {
593            "cf49fda3be353c69b41ed96333cd24302da4556f": {
594              "balance": "0x123450000000000000000"
595            },
596            "0161e041aad467a890839d5b08b138c1e6373072": {
597              "balance": "0x123450000000000000000"
598            },
599            "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
600              "balance": "0x123450000000000000000"
601            },
602            "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
603              "balance": "0x123450000000000000000"
604            },
605            "c5065c9eeebe6df2c2284d046bfc906501846c51": {
606              "balance": "0x123450000000000000000"
607            },
608            "0000000000000000000000000000000000000314": {
609              "balance": "0x0",
610              "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029",
611              "storage": {
612                "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
613                "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
614              }
615            },
616            "0000000000000000000000000000000000000315": {
617              "balance": "0x9999999999999999999999999999999",
618              "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
619            },
620            "0000000000000000000000000000000000000316": {
621              "balance": "0x0",
622              "code": "0x444355"
623            },
624            "0000000000000000000000000000000000000317": {
625              "balance": "0x0",
626              "code": "0x600160003555"
627            }
628          }
629        }
630        "#;
631
632        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
633    }
634
635    #[test]
636    fn parse_hive_devp2p_genesis() {
637        let geth_genesis = r#"
638        {
639            "config": {
640                "chainId": 19763,
641                "homesteadBlock": 0,
642                "eip150Block": 0,
643                "eip155Block": 0,
644                "eip158Block": 0,
645                "byzantiumBlock": 0,
646                "ethash": {}
647            },
648            "nonce": "0xdeadbeefdeadbeef",
649            "timestamp": "0x0",
650            "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
651            "gasLimit": "0x80000000",
652            "difficulty": "0x20000",
653            "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
654            "coinbase": "0x0000000000000000000000000000000000000000",
655            "alloc": {
656                "71562b71999873db5b286df957af199ec94617f7": {
657                    "balance": "0xffffffffffffffffffffffffff"
658                }
659            },
660            "number": "0x0",
661            "gasUsed": "0x0",
662            "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
663        }
664        "#;
665
666        let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
667    }
668
669    #[test]
670    fn parse_execution_apis_genesis() {
671        let geth_genesis = r#"
672        {
673          "config": {
674            "chainId": 1337,
675            "homesteadBlock": 0,
676            "eip150Block": 0,
677            "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
678            "eip155Block": 0,
679            "eip158Block": 0,
680            "byzantiumBlock": 0,
681            "constantinopleBlock": 0,
682            "petersburgBlock": 0,
683            "istanbulBlock": 0,
684            "muirGlacierBlock": 0,
685            "berlinBlock": 0,
686            "londonBlock": 0,
687            "arrowGlacierBlock": 0,
688            "grayGlacierBlock": 0,
689            "shanghaiTime": 0,
690            "terminalTotalDifficulty": 0,
691            "terminalTotalDifficultyPassed": true,
692            "ethash": {}
693          },
694          "nonce": "0x0",
695          "timestamp": "0x0",
696          "extraData": "0x",
697          "gasLimit": "0x4c4b40",
698          "difficulty": "0x1",
699          "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
700          "coinbase": "0x0000000000000000000000000000000000000000",
701          "alloc": {
702            "658bdf435d810c91414ec09147daa6db62406379": {
703              "balance": "0x487a9a304539440000"
704            },
705            "aa00000000000000000000000000000000000000": {
706              "code": "0x6042",
707              "storage": {
708                "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000",
709                "0x0100000000000000000000000000000000000000000000000000000000000000": "0x0100000000000000000000000000000000000000000000000000000000000000",
710                "0x0200000000000000000000000000000000000000000000000000000000000000": "0x0200000000000000000000000000000000000000000000000000000000000000",
711                "0x0300000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000303"
712              },
713              "balance": "0x1",
714              "nonce": "0x1"
715            },
716            "bb00000000000000000000000000000000000000": {
717              "code": "0x600154600354",
718              "storage": {
719                "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000",
720                "0x0100000000000000000000000000000000000000000000000000000000000000": "0x0100000000000000000000000000000000000000000000000000000000000000",
721                "0x0200000000000000000000000000000000000000000000000000000000000000": "0x0200000000000000000000000000000000000000000000000000000000000000",
722                "0x0300000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000303"
723              },
724              "balance": "0x2",
725              "nonce": "0x1"
726            }
727          },
728          "number": "0x0",
729          "gasUsed": "0x0",
730          "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
731          "baseFeePerGas": "0x3b9aca00"
732        }
733        "#;
734
735        let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
736
737        // ensure the test fields are parsed correctly
738        assert_eq!(genesis.base_fee_per_gas, Some(1000000000.into()));
739        assert_eq!(genesis.number, Some(0.into()));
740        assert_eq!(genesis.gas_used, Some(0.into()));
741        assert_eq!(genesis.parent_hash, Some(H256::zero()));
742    }
743
744    #[test]
745    fn parse_hive_rpc_genesis_full() {
746        let geth_genesis = r#"
747        {
748          "config": {
749            "clique": {
750              "period": 1
751            },
752            "chainId": 7,
753            "homesteadBlock": 0,
754            "eip150Block": 0,
755            "eip155Block": 0,
756            "eip158Block": 0
757          },
758          "coinbase": "0x0000000000000000000000000000000000000000",
759          "difficulty": "0x020000",
760          "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
761          "gasLimit": "0x2fefd8",
762          "nonce": "0x0000000000000000",
763          "timestamp": "0x1234",
764          "alloc": {
765            "cf49fda3be353c69b41ed96333cd24302da4556f": {
766              "balance": "0x123450000000000000000"
767            },
768            "0161e041aad467a890839d5b08b138c1e6373072": {
769              "balance": "0x123450000000000000000"
770            },
771            "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
772              "balance": "0x123450000000000000000"
773            },
774            "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
775              "balance": "0x123450000000000000000"
776            },
777            "c5065c9eeebe6df2c2284d046bfc906501846c51": {
778              "balance": "0x123450000000000000000"
779            },
780            "0000000000000000000000000000000000000314": {
781              "balance": "0x0",
782              "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029",
783              "storage": {
784                "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
785                "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
786              }
787            },
788            "0000000000000000000000000000000000000315": {
789              "balance": "0x9999999999999999999999999999999",
790              "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
791            }
792          },
793          "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
794          "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
795        }
796        "#;
797
798        let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
799        let alloc_entry = genesis
800            .alloc
801            .get(&H160::from_str("0000000000000000000000000000000000000314").unwrap())
802            .expect("missing account for parsed genesis");
803        let storage = alloc_entry.storage.as_ref().expect("missing storage for parsed genesis");
804        let expected_storage = HashMap::from_iter(vec![
805            (
806                H256::from_str(
807                    "0x0000000000000000000000000000000000000000000000000000000000000000",
808                )
809                .unwrap(),
810                H256::from_str(
811                    "0x0000000000000000000000000000000000000000000000000000000000001234",
812                )
813                .unwrap(),
814            ),
815            (
816                H256::from_str(
817                    "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9",
818                )
819                .unwrap(),
820                H256::from_str(
821                    "0x0000000000000000000000000000000000000000000000000000000000000001",
822                )
823                .unwrap(),
824            ),
825        ]);
826        assert_eq!(storage, &expected_storage);
827
828        let expected_code = Bytes::from_str("0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029").unwrap();
829        let code = alloc_entry.code.as_ref().expect("missing code for parsed genesis");
830        assert_eq!(code, &expected_code);
831    }
832
833    #[test]
834    fn test_hive_smoke_alloc_deserialize() {
835        let hive_genesis = r#"
836        {
837            "nonce": "0x0000000000000042",
838            "difficulty": "0x2123456",
839            "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
840            "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
841            "timestamp": "0x123456",
842            "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
843            "extraData": "0xfafbfcfd",
844            "gasLimit": "0x2fefd8",
845            "alloc": {
846                "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {
847                    "balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
848                },
849                "e6716f9544a56c530d868e4bfbacb172315bdead": {
850                    "balance": "0x11",
851                    "code": "0x12"
852                },
853                "b9c015918bdaba24b4ff057a92a3873d6eb201be": {
854                    "balance": "0x21",
855                    "storage": {
856                        "0x0000000000000000000000000000000000000000000000000000000000000001": "0x22"
857                    }
858                },
859                "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {
860                    "balance": "0x31",
861                    "nonce": "0x32"
862                },
863                "0000000000000000000000000000000000000001": {
864                    "balance": "0x41"
865                },
866                "0000000000000000000000000000000000000002": {
867                    "balance": "0x51"
868                },
869                "0000000000000000000000000000000000000003": {
870                    "balance": "0x61"
871                },
872                "0000000000000000000000000000000000000004": {
873                    "balance": "0x71"
874                }
875            },
876            "config": {
877                "ethash": {},
878                "chainId": 10,
879                "homesteadBlock": 0,
880                "eip150Block": 0,
881                "eip155Block": 0,
882                "eip158Block": 0,
883                "byzantiumBlock": 0,
884                "constantinopleBlock": 0,
885                "petersburgBlock": 0,
886                "istanbulBlock": 0
887            }
888        }
889        "#;
890
891        let expected_genesis = Genesis {
892            nonce: 0x0000000000000042.into(),
893            difficulty: 0x2123456.into(),
894            mix_hash: H256::from_str("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234").unwrap(),
895            coinbase: Address::from_str("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(),
896            timestamp: 0x123456.into(),
897            parent_hash: Some(H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap()),
898            extra_data: Bytes::from_str("0xfafbfcfd").unwrap(),
899            gas_limit: 0x2fefd8.into(),
900            alloc: HashMap::from_iter(vec![
901                (
902                    Address::from_str("0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6").unwrap(),
903                    GenesisAccount {
904                        balance: U256::from_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(),
905                        nonce: None,
906                        code: None,
907                        storage: None,
908                    },
909                ),
910                (
911                    Address::from_str("0xe6716f9544a56c530d868e4bfbacb172315bdead").unwrap(),
912                    GenesisAccount {
913                        balance: U256::from_str("0x11").unwrap(),
914                        nonce: None,
915                        code: Some(Bytes::from_str("0x12").unwrap()),
916                        storage: None,
917                    },
918                ),
919                (
920                    Address::from_str("0xb9c015918bdaba24b4ff057a92a3873d6eb201be").unwrap(),
921                    GenesisAccount {
922                        balance: U256::from_str("0x21").unwrap(),
923                        nonce: None,
924                        code: None,
925                        storage: Some(HashMap::from_iter(vec![
926                            (
927                                H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(),
928                                H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000022").unwrap(),
929                            ),
930                        ])),
931                    },
932                ),
933                (
934                    Address::from_str("0x1a26338f0d905e295fccb71fa9ea849ffa12aaf4").unwrap(),
935                    GenesisAccount {
936                        balance: U256::from_str("0x31").unwrap(),
937                        nonce: Some(0x32u64),
938                        code: None,
939                        storage: None,
940                    },
941                ),
942                (
943                    Address::from_str("0x0000000000000000000000000000000000000001").unwrap(),
944                    GenesisAccount {
945                        balance: U256::from_str("0x41").unwrap(),
946                        nonce: None,
947                        code: None,
948                        storage: None,
949                    },
950                ),
951                (
952                    Address::from_str("0x0000000000000000000000000000000000000002").unwrap(),
953                    GenesisAccount {
954                        balance: U256::from_str("0x51").unwrap(),
955                        nonce: None,
956                        code: None,
957                        storage: None,
958                    },
959                ),
960                (
961                    Address::from_str("0x0000000000000000000000000000000000000003").unwrap(),
962                    GenesisAccount {
963                        balance: U256::from_str("0x61").unwrap(),
964                        nonce: None,
965                        code: None,
966                        storage: None,
967                    },
968                ),
969                (
970                    Address::from_str("0x0000000000000000000000000000000000000004").unwrap(),
971                    GenesisAccount {
972                        balance: U256::from_str("0x71").unwrap(),
973                        nonce: None,
974                        code: None,
975                        storage: None,
976                    },
977                ),
978            ]),
979            config: ChainConfig {
980                ethash: Some(EthashConfig{}),
981                chain_id: 10,
982                homestead_block: Some(0),
983                eip150_block: Some(0),
984                eip155_block: Some(0),
985                eip158_block: Some(0),
986                byzantium_block: Some(0),
987                constantinople_block: Some(0),
988                petersburg_block: Some(0),
989                istanbul_block: Some(0),
990                ..Default::default()
991            },
992            ..Default::default()
993        };
994
995        let deserialized_genesis: Genesis = serde_json::from_str(hive_genesis).unwrap();
996        assert_eq!(deserialized_genesis, expected_genesis, "deserialized genesis {deserialized_genesis:#?} does not match expected {expected_genesis:#?}");
997    }
998}