1#![doc = include_str!(".././README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg",
6 html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14use alloc::{collections::BTreeMap, string::String};
15use alloy_eips::{eip7840::BlobParams, BlobScheduleBlobParams};
16use alloy_primitives::{keccak256, Address, Bytes, B256, U256};
17use alloy_serde::{storage::deserialize_storage_map, ttd::deserialize_json_ttd_opt, OtherFields};
18use alloy_trie::{TrieAccount, EMPTY_ROOT_HASH, KECCAK_EMPTY};
19use core::str::FromStr;
20use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
21
22#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase", default)]
25pub struct Genesis {
26 #[serde(default)]
28 pub config: ChainConfig,
29 #[serde(with = "alloy_serde::quantity")]
31 pub nonce: u64,
32 #[serde(with = "alloy_serde::quantity")]
34 pub timestamp: u64,
35 pub extra_data: Bytes,
37 #[serde(with = "alloy_serde::quantity")]
39 pub gas_limit: u64,
40 pub difficulty: U256,
42 pub mix_hash: B256,
44 pub coinbase: Address,
46 pub alloc: BTreeMap<Address, GenesisAccount>,
48 #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
57 pub base_fee_per_gas: Option<u128>,
58 #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
60 pub excess_blob_gas: Option<u64>,
61 #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
63 pub blob_gas_used: Option<u64>,
64 #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")]
66 pub number: Option<u64>,
67}
68
69impl Genesis {
70 pub fn clique_genesis(chain_id: u64, signer_addr: Address) -> Self {
75 let clique_config = CliqueConfig { period: Some(0), epoch: Some(8) };
77
78 let config = ChainConfig {
79 chain_id,
80 eip155_block: Some(0),
81 eip150_block: Some(0),
82 eip158_block: Some(0),
83
84 homestead_block: Some(0),
85 byzantium_block: Some(0),
86 constantinople_block: Some(0),
87 petersburg_block: Some(0),
88 istanbul_block: Some(0),
89 muir_glacier_block: Some(0),
90 berlin_block: Some(0),
91 london_block: Some(0),
92 clique: Some(clique_config),
93 ..Default::default()
94 };
95
96 let alloc = BTreeMap::from([(
98 signer_addr,
99 GenesisAccount { balance: U256::MAX, ..Default::default() },
100 )]);
101
102 let extra_data_bytes = [&[0u8; 32][..], signer_addr.as_slice(), &[0u8; 65][..]].concat();
112 let extra_data = extra_data_bytes.into();
113
114 Self {
115 config,
116 alloc,
117 difficulty: U256::from(1),
118 gas_limit: 5_000_000,
119 extra_data,
120 ..Default::default()
121 }
122 }
123
124 pub const fn with_nonce(mut self, nonce: u64) -> Self {
126 self.nonce = nonce;
127 self
128 }
129
130 pub const fn with_timestamp(mut self, timestamp: u64) -> Self {
132 self.timestamp = timestamp;
133 self
134 }
135
136 pub fn with_extra_data(mut self, extra_data: Bytes) -> Self {
138 self.extra_data = extra_data;
139 self
140 }
141
142 pub const fn with_gas_limit(mut self, gas_limit: u64) -> Self {
144 self.gas_limit = gas_limit;
145 self
146 }
147
148 pub const fn with_difficulty(mut self, difficulty: U256) -> Self {
150 self.difficulty = difficulty;
151 self
152 }
153
154 pub const fn with_mix_hash(mut self, mix_hash: B256) -> Self {
156 self.mix_hash = mix_hash;
157 self
158 }
159
160 pub const fn with_coinbase(mut self, address: Address) -> Self {
162 self.coinbase = address;
163 self
164 }
165
166 pub const fn with_base_fee(mut self, base_fee: Option<u128>) -> Self {
168 self.base_fee_per_gas = base_fee;
169 self
170 }
171
172 pub const fn with_excess_blob_gas(mut self, excess_blob_gas: Option<u64>) -> Self {
174 self.excess_blob_gas = excess_blob_gas;
175 self
176 }
177
178 pub const fn with_blob_gas_used(mut self, blob_gas_used: Option<u64>) -> Self {
180 self.blob_gas_used = blob_gas_used;
181 self
182 }
183
184 pub fn extend_accounts(
187 mut self,
188 accounts: impl IntoIterator<Item = (Address, GenesisAccount)>,
189 ) -> Self {
190 self.alloc.extend(accounts);
191 self
192 }
193}
194
195#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
197#[serde(deny_unknown_fields)]
198pub struct GenesisAccount {
199 #[serde(skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt", default)]
201 pub nonce: Option<u64>,
202 pub balance: U256,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub code: Option<Bytes>,
207 #[serde(
209 default,
210 skip_serializing_if = "Option::is_none",
211 deserialize_with = "deserialize_storage_map"
212 )]
213 pub storage: Option<BTreeMap<B256, B256>>,
214 #[serde(
216 rename = "secretKey",
217 default,
218 skip_serializing_if = "Option::is_none",
219 deserialize_with = "deserialize_private_key"
220 )]
221 pub private_key: Option<B256>,
222}
223
224impl GenesisAccount {
225 pub const fn with_nonce(mut self, nonce: Option<u64>) -> Self {
227 self.nonce = nonce;
228 self
229 }
230
231 pub const fn with_balance(mut self, balance: U256) -> Self {
233 self.balance = balance;
234 self
235 }
236
237 pub fn with_code(mut self, code: Option<Bytes>) -> Self {
239 self.code = code;
240 self
241 }
242
243 pub fn with_storage(mut self, storage: Option<BTreeMap<B256, B256>>) -> Self {
245 self.storage = storage;
246 self
247 }
248
249 pub fn storage_slots(&self) -> impl Iterator<Item = (B256, U256)> + '_ {
251 self.storage.as_ref().into_iter().flat_map(|storage| storage.iter()).map(|(key, value)| {
252 let value = U256::from_be_bytes(value.0);
253 (*key, value)
254 })
255 }
256
257 pub fn into_trie_account(self) -> TrieAccount {
259 self.into()
260 }
261}
262
263impl From<GenesisAccount> for TrieAccount {
264 fn from(account: GenesisAccount) -> Self {
265 let storage_root = account
266 .storage
267 .map(|storage| {
268 alloy_trie::root::storage_root_unhashed(
269 storage
270 .into_iter()
271 .filter(|(_, value)| !value.is_zero())
272 .map(|(slot, value)| (slot, U256::from_be_bytes(*value))),
273 )
274 })
275 .unwrap_or(EMPTY_ROOT_HASH);
276
277 Self {
278 nonce: account.nonce.unwrap_or_default(),
279 balance: account.balance,
280 storage_root,
281 code_hash: account.code.map_or(KECCAK_EMPTY, keccak256),
282 }
283 }
284}
285
286fn deserialize_private_key<'de, D>(deserializer: D) -> Result<Option<B256>, D::Error>
293where
294 D: Deserializer<'de>,
295{
296 let opt_str: Option<String> = Option::deserialize(deserializer)?;
297
298 if let Some(ref s) = opt_str {
299 if s == "0x" {
300 return Ok(None);
301 }
302 B256::from_str(s).map(Some).map_err(D::Error::custom)
303 } else {
304 Ok(None)
305 }
306}
307
308#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
320#[serde(default, rename_all = "camelCase")]
321pub struct ChainConfig {
322 pub chain_id: u64,
324
325 #[serde(
327 skip_serializing_if = "Option::is_none",
328 deserialize_with = "alloy_serde::quantity::opt::deserialize"
329 )]
330 pub homestead_block: Option<u64>,
331
332 #[serde(
334 skip_serializing_if = "Option::is_none",
335 deserialize_with = "alloy_serde::quantity::opt::deserialize"
336 )]
337 pub dao_fork_block: Option<u64>,
338
339 pub dao_fork_support: bool,
341
342 #[serde(
344 skip_serializing_if = "Option::is_none",
345 deserialize_with = "alloy_serde::quantity::opt::deserialize"
346 )]
347 pub eip150_block: Option<u64>,
348
349 #[serde(
351 skip_serializing_if = "Option::is_none",
352 deserialize_with = "alloy_serde::quantity::opt::deserialize"
353 )]
354 pub eip155_block: Option<u64>,
355
356 #[serde(
358 skip_serializing_if = "Option::is_none",
359 deserialize_with = "alloy_serde::quantity::opt::deserialize"
360 )]
361 pub eip158_block: Option<u64>,
362
363 #[serde(
365 skip_serializing_if = "Option::is_none",
366 deserialize_with = "alloy_serde::quantity::opt::deserialize"
367 )]
368 pub byzantium_block: Option<u64>,
369
370 #[serde(
372 skip_serializing_if = "Option::is_none",
373 deserialize_with = "alloy_serde::quantity::opt::deserialize"
374 )]
375 pub constantinople_block: Option<u64>,
376
377 #[serde(
379 skip_serializing_if = "Option::is_none",
380 deserialize_with = "alloy_serde::quantity::opt::deserialize"
381 )]
382 pub petersburg_block: Option<u64>,
383
384 #[serde(
386 skip_serializing_if = "Option::is_none",
387 deserialize_with = "alloy_serde::quantity::opt::deserialize"
388 )]
389 pub istanbul_block: Option<u64>,
390
391 #[serde(
393 skip_serializing_if = "Option::is_none",
394 deserialize_with = "alloy_serde::quantity::opt::deserialize"
395 )]
396 pub muir_glacier_block: Option<u64>,
397
398 #[serde(
400 skip_serializing_if = "Option::is_none",
401 deserialize_with = "alloy_serde::quantity::opt::deserialize"
402 )]
403 pub berlin_block: Option<u64>,
404
405 #[serde(
407 skip_serializing_if = "Option::is_none",
408 deserialize_with = "alloy_serde::quantity::opt::deserialize"
409 )]
410 pub london_block: Option<u64>,
411
412 #[serde(
414 skip_serializing_if = "Option::is_none",
415 deserialize_with = "alloy_serde::quantity::opt::deserialize"
416 )]
417 pub arrow_glacier_block: Option<u64>,
418
419 #[serde(
421 skip_serializing_if = "Option::is_none",
422 deserialize_with = "alloy_serde::quantity::opt::deserialize"
423 )]
424 pub gray_glacier_block: Option<u64>,
425
426 #[serde(
428 skip_serializing_if = "Option::is_none",
429 deserialize_with = "alloy_serde::quantity::opt::deserialize"
430 )]
431 pub merge_netsplit_block: Option<u64>,
432
433 #[serde(
435 skip_serializing_if = "Option::is_none",
436 deserialize_with = "alloy_serde::quantity::opt::deserialize"
437 )]
438 pub shanghai_time: Option<u64>,
439
440 #[serde(
442 skip_serializing_if = "Option::is_none",
443 deserialize_with = "alloy_serde::quantity::opt::deserialize"
444 )]
445 pub cancun_time: Option<u64>,
446
447 #[serde(
449 skip_serializing_if = "Option::is_none",
450 deserialize_with = "alloy_serde::quantity::opt::deserialize"
451 )]
452 pub prague_time: Option<u64>,
453
454 #[serde(
456 skip_serializing_if = "Option::is_none",
457 deserialize_with = "alloy_serde::quantity::opt::deserialize"
458 )]
459 pub osaka_time: Option<u64>,
460
461 #[serde(
463 skip_serializing_if = "Option::is_none",
464 deserialize_with = "deserialize_json_ttd_opt"
465 )]
466 pub terminal_total_difficulty: Option<U256>,
467
468 pub terminal_total_difficulty_passed: bool,
471
472 #[serde(skip_serializing_if = "Option::is_none")]
474 pub ethash: Option<EthashConfig>,
475
476 #[serde(skip_serializing_if = "Option::is_none")]
478 pub clique: Option<CliqueConfig>,
479
480 #[serde(skip_serializing_if = "Option::is_none")]
482 pub parlia: Option<ParliaConfig>,
483
484 #[serde(flatten, default)]
486 pub extra_fields: OtherFields,
487
488 #[serde(default, skip_serializing_if = "Option::is_none")]
490 pub deposit_contract_address: Option<Address>,
491
492 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
496 pub blob_schedule: BTreeMap<String, BlobParams>,
497}
498
499impl ChainConfig {
500 pub fn blob_schedule_blob_params(&self) -> BlobScheduleBlobParams {
502 BlobScheduleBlobParams::from_schedule(&self.blob_schedule)
503 }
504
505 pub fn is_homestead_active_at_block(&self, block: u64) -> bool {
507 self.is_active_at_block(self.homestead_block, block)
508 }
509
510 pub fn is_eip150_active_at_block(&self, block: u64) -> bool {
512 self.is_active_at_block(self.eip150_block, block)
513 }
514
515 pub fn is_eip155_active_at_block(&self, block: u64) -> bool {
517 self.is_active_at_block(self.eip155_block, block)
518 }
519
520 pub fn is_eip158_active_at_block(&self, block: u64) -> bool {
522 self.is_active_at_block(self.eip158_block, block)
523 }
524
525 pub fn is_byzantium_active_at_block(&self, block: u64) -> bool {
527 self.is_active_at_block(self.byzantium_block, block)
528 }
529
530 pub fn is_constantinople_active_at_block(&self, block: u64) -> bool {
532 self.is_active_at_block(self.constantinople_block, block)
533 }
534
535 pub fn is_muir_glacier_active_at_block(&self, block: u64) -> bool {
537 self.is_active_at_block(self.muir_glacier_block, block)
538 }
539
540 pub fn is_petersburg_active_at_block(&self, block: u64) -> bool {
542 self.is_active_at_block(self.petersburg_block, block)
543 }
544
545 pub fn is_istanbul_active_at_block(&self, block: u64) -> bool {
547 self.is_active_at_block(self.istanbul_block, block)
548 }
549
550 pub fn is_berlin_active_at_block(&self, block: u64) -> bool {
552 self.is_active_at_block(self.berlin_block, block)
553 }
554
555 pub fn is_london_active_at_block(&self, block: u64) -> bool {
557 self.is_active_at_block(self.london_block, block)
558 }
559
560 pub fn is_arrow_glacier_active_at_block(&self, block: u64) -> bool {
562 self.is_active_at_block(self.arrow_glacier_block, block)
563 }
564
565 pub fn is_gray_glacier_active_at_block(&self, block: u64) -> bool {
567 self.is_active_at_block(self.gray_glacier_block, block)
568 }
569
570 pub fn is_shanghai_active_at_block_and_timestamp(&self, block: u64, timestamp: u64) -> bool {
573 self.is_london_active_at_block(block)
574 && self.is_active_at_timestamp(self.shanghai_time, timestamp)
575 }
576
577 pub fn is_cancun_active_at_block_and_timestamp(&self, block: u64, timestamp: u64) -> bool {
580 self.is_london_active_at_block(block)
581 && self.is_active_at_timestamp(self.cancun_time, timestamp)
582 }
583
584 fn is_active_at_block(&self, config_block: Option<u64>, block: u64) -> bool {
586 config_block.is_some_and(|cb| cb <= block)
587 }
588
589 fn is_active_at_timestamp(&self, config_timestamp: Option<u64>, timestamp: u64) -> bool {
591 config_timestamp.is_some_and(|cb| cb <= timestamp)
592 }
593}
594
595impl Default for ChainConfig {
596 fn default() -> Self {
597 Self {
598 chain_id: 1,
600 homestead_block: None,
601 dao_fork_block: None,
602 dao_fork_support: false,
603 eip150_block: None,
604 eip155_block: None,
605 eip158_block: None,
606 byzantium_block: None,
607 constantinople_block: None,
608 petersburg_block: None,
609 istanbul_block: None,
610 muir_glacier_block: None,
611 berlin_block: None,
612 london_block: None,
613 arrow_glacier_block: None,
614 gray_glacier_block: None,
615 merge_netsplit_block: None,
616 shanghai_time: None,
617 cancun_time: None,
618 prague_time: None,
619 osaka_time: None,
620 terminal_total_difficulty: None,
621 terminal_total_difficulty_passed: false,
622 ethash: None,
623 clique: None,
624 parlia: None,
625 extra_fields: Default::default(),
626 deposit_contract_address: None,
627 blob_schedule: Default::default(),
628 }
629 }
630}
631
632#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
634pub struct EthashConfig {}
635
636#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
638pub struct CliqueConfig {
639 #[serde(default, skip_serializing_if = "Option::is_none")]
641 pub period: Option<u64>,
642
643 #[serde(default, skip_serializing_if = "Option::is_none")]
645 pub epoch: Option<u64>,
646}
647
648#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
654pub struct ParliaConfig {
655 #[serde(default, skip_serializing_if = "Option::is_none")]
657 pub period: Option<u64>,
658
659 #[serde(default, skip_serializing_if = "Option::is_none")]
661 pub epoch: Option<u64>,
662}
663
664#[cfg(test)]
665mod tests {
666 use super::*;
667 use alloc::{collections::BTreeMap, vec};
668 use alloy_primitives::{hex, Bytes};
669 use alloy_trie::{root::storage_root_unhashed, TrieAccount};
670 use core::str::FromStr;
671 use serde_json::json;
672
673 #[test]
674 fn genesis_defaults_config() {
675 let s = r#"{}"#;
676 let genesis: Genesis = serde_json::from_str(s).unwrap();
677 assert_eq!(genesis.config.chain_id, 1);
678 }
679
680 #[test]
681 fn test_genesis() {
682 let default_genesis = Genesis::default();
683
684 let nonce = 999;
685 let timestamp = 12345;
686 let extra_data = Bytes::from(b"extra-data");
687 let gas_limit = 333333;
688 let difficulty = U256::from(9000);
689 let mix_hash =
690 hex!("74385b512f1e0e47100907efe2b00ac78df26acba6dd16b0772923068a5801a8").into();
691 let coinbase = hex!("265873b6faf3258b3ab0827805386a2a20ed040e").into();
692 let first_address: Address = hex!("7618a8c597b89e01c66a1f662078992c52a30c9a").into();
694 let mut account = BTreeMap::default();
695 account.insert(first_address, GenesisAccount::default());
696
697 let custom_genesis = Genesis::default()
699 .with_nonce(nonce)
700 .with_timestamp(timestamp)
701 .with_extra_data(extra_data.clone())
702 .with_gas_limit(gas_limit)
703 .with_difficulty(difficulty)
704 .with_mix_hash(mix_hash)
705 .with_coinbase(coinbase)
706 .extend_accounts(account.clone());
707
708 assert_ne!(custom_genesis, default_genesis);
709 assert_eq!(custom_genesis.nonce, nonce);
711 assert_eq!(custom_genesis.timestamp, timestamp);
712 assert_eq!(custom_genesis.extra_data, extra_data);
713 assert_eq!(custom_genesis.gas_limit, gas_limit);
714 assert_eq!(custom_genesis.difficulty, difficulty);
715 assert_eq!(custom_genesis.mix_hash, mix_hash);
716 assert_eq!(custom_genesis.coinbase, coinbase);
717 assert_eq!(custom_genesis.alloc, account.clone());
718
719 assert_eq!(custom_genesis.alloc.len(), 1);
721 let same_address = first_address;
722 let new_alloc_account = GenesisAccount {
723 nonce: Some(1),
724 balance: U256::from(1),
725 code: Some(b"code".into()),
726 storage: Some(BTreeMap::default()),
727 private_key: None,
728 };
729 let mut updated_account = BTreeMap::default();
730 updated_account.insert(same_address, new_alloc_account);
731 let custom_genesis = custom_genesis.extend_accounts(updated_account.clone());
732 assert_ne!(account, updated_account);
733 assert_eq!(custom_genesis.alloc.len(), 1);
734
735 let different_address = hex!("94e0681e3073dd71cec54b53afe988f39078fd1a").into();
737 let more_accounts = BTreeMap::from([(different_address, GenesisAccount::default())]);
738 let custom_genesis = custom_genesis.extend_accounts(more_accounts);
739 assert_eq!(custom_genesis.alloc.len(), 2);
740
741 let first_account = custom_genesis.alloc.get(&first_address);
743 let second_account = custom_genesis.alloc.get(&different_address);
744 assert!(first_account.is_some());
745 assert!(second_account.is_some());
746 assert_ne!(first_account, second_account);
747 }
748
749 #[test]
750 fn test_genesis_account() {
751 let default_account = GenesisAccount::default();
752
753 let nonce = Some(1);
754 let balance = U256::from(33);
755 let code = Some(b"code".into());
756 let root = hex!("9474ddfcea39c5a690d2744103e39d1ff1b03d18db10fc147d970ad24699395a").into();
757 let value = hex!("58eb8294d9bb16832a9dabfcb270fff99ab8ee1d8764e4f3d9fdf59ec1dee469").into();
758 let mut map = BTreeMap::default();
759 map.insert(root, value);
760 let storage = Some(map);
761
762 let genesis_account = GenesisAccount::default()
763 .with_nonce(nonce)
764 .with_balance(balance)
765 .with_code(code.clone())
766 .with_storage(storage.clone());
767
768 assert_ne!(default_account, genesis_account);
769 assert_eq!(genesis_account.nonce, nonce);
771 assert_eq!(genesis_account.balance, balance);
772 assert_eq!(genesis_account.code, code);
773 assert_eq!(genesis_account.storage, storage);
774 }
775
776 #[test]
777 fn parse_hive_genesis() {
778 let geth_genesis = r#"
779 {
780 "difficulty": "0x20000",
781 "gasLimit": "0x1",
782 "alloc": {},
783 "config": {
784 "ethash": {},
785 "chainId": 1
786 }
787 }
788 "#;
789
790 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
791 }
792
793 #[test]
794 fn parse_hive_clique_smoke_genesis() {
795 let geth_genesis = r#"
796 {
797 "difficulty": "0x1",
798 "gasLimit": "0x400000",
799 "extraData":
800 "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
801 , "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
802 "nonce": "0x0",
803 "timestamp": "0x5c51a607",
804 "alloc": {}
805 }
806 "#;
807
808 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
809 }
810
811 #[test]
812 fn parse_non_hex_prefixed_balance() {
813 let example_balance_json = r#"
815 {
816 "nonce": "0x0000000000000042",
817 "difficulty": "34747478",
818 "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
819 "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
820 "timestamp": "0x123456",
821 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
822 "extraData": "0xfafbfcfd",
823 "gasLimit": "0x2fefd8",
824 "alloc": {
825 "0x3E951C9f69a06Bc3AD71fF7358DbC56bEd94b9F2": {
826 "balance": "1000000000000000000000000000"
827 },
828 "0xe228C30d4e5245f967ac21726d5412dA27aD071C": {
829 "balance": "1000000000000000000000000000"
830 },
831 "0xD59Ce7Ccc6454a2D2C2e06bbcf71D0Beb33480eD": {
832 "balance": "1000000000000000000000000000"
833 },
834 "0x1CF4D54414eF51b41f9B2238c57102ab2e61D1F2": {
835 "balance": "1000000000000000000000000000"
836 },
837 "0x249bE3fDEd872338C733cF3975af9736bdCb9D4D": {
838 "balance": "1000000000000000000000000000"
839 },
840 "0x3fCd1bff94513712f8cD63d1eD66776A67D5F78e": {
841 "balance": "1000000000000000000000000000"
842 }
843 },
844 "config": {
845 "ethash": {},
846 "chainId": 10,
847 "homesteadBlock": 0,
848 "eip150Block": 0,
849 "eip155Block": 0,
850 "eip158Block": 0,
851 "byzantiumBlock": 0,
852 "constantinopleBlock": 0,
853 "petersburgBlock": 0,
854 "istanbulBlock": 0
855 }
856 }
857 "#;
858
859 let genesis: Genesis = serde_json::from_str(example_balance_json).unwrap();
860
861 let expected_difficulty = U256::from_str("0x2123456").unwrap();
863 assert_eq!(expected_difficulty, genesis.difficulty);
864
865 let dec_balance = U256::from_str("1000000000000000000000000000").unwrap();
867 for alloc in &genesis.alloc {
868 assert_eq!(alloc.1.balance, dec_balance);
869 }
870 }
871
872 #[test]
873 fn parse_hive_rpc_genesis() {
874 let geth_genesis = r#"
875 {
876 "config": {
877 "chainId": 7,
878 "homesteadBlock": 0,
879 "eip150Block": 0,
880 "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689",
881 "eip155Block": 0,
882 "eip158Block": 0
883 },
884 "coinbase": "0x0000000000000000000000000000000000000000",
885 "difficulty": "0x20000",
886 "extraData":
887 "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
888 , "gasLimit": "0x2fefd8",
889 "nonce": "0x0000000000000000",
890 "timestamp": "0x1234",
891 "alloc": {
892 "cf49fda3be353c69b41ed96333cd24302da4556f": {
893 "balance": "0x123450000000000000000"
894 },
895 "0161e041aad467a890839d5b08b138c1e6373072": {
896 "balance": "0x123450000000000000000"
897 },
898 "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
899 "balance": "0x123450000000000000000"
900 },
901 "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
902 "balance": "0x123450000000000000000"
903 },
904 "c5065c9eeebe6df2c2284d046bfc906501846c51": {
905 "balance": "0x123450000000000000000"
906 },
907 "0000000000000000000000000000000000000314": {
908 "balance": "0x0",
909 "code":
910 "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
911 , "storage": {
912 "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
913 "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
914 }
915 },
916 "0000000000000000000000000000000000000315": {
917 "balance": "0x9999999999999999999999999999999",
918 "code":
919 "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
920 }
921 }
922 }
923 "#;
924
925 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
926 }
927
928 #[test]
929 fn parse_hive_graphql_genesis() {
930 let geth_genesis = r#"
931 {
932 "config" : {},
933 "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
934 "difficulty" : "0x020000",
935 "extraData" : "0x42",
936 "gasLimit" : "0x2fefd8",
937 "mixHash" : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46",
938 "nonce" : "0x78cc16f7b4f65485",
939 "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
940 "timestamp" : "0x54c98c81",
941 "alloc" : {
942 "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
943 "balance" : "0x09184e72a000"
944 }
945 }
946 }
947 "#;
948
949 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
950 }
951
952 #[test]
953 fn parse_hive_engine_genesis() {
954 let geth_genesis = r#"
955 {
956 "config": {
957 "chainId": 7,
958 "homesteadBlock": 0,
959 "eip150Block": 0,
960 "eip150Hash": "0x5de1ee4135274003348e80b788e5afa4b18b18d320a5622218d5c493fedf5689",
961 "eip155Block": 0,
962 "eip158Block": 0,
963 "byzantiumBlock": 0,
964 "constantinopleBlock": 0,
965 "petersburgBlock": 0,
966 "istanbulBlock": 0,
967 "muirGlacierBlock": 0,
968 "berlinBlock": 0,
969 "yolov2Block": 0,
970 "yolov3Block": 0,
971 "londonBlock": 0
972 },
973 "coinbase": "0x0000000000000000000000000000000000000000",
974 "difficulty": "0x30000",
975 "extraData":
976 "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
977 , "gasLimit": "0x2fefd8",
978 "nonce": "0x0000000000000000",
979 "timestamp": "0x1234",
980 "alloc": {
981 "cf49fda3be353c69b41ed96333cd24302da4556f": {
982 "balance": "0x123450000000000000000"
983 },
984 "0161e041aad467a890839d5b08b138c1e6373072": {
985 "balance": "0x123450000000000000000"
986 },
987 "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
988 "balance": "0x123450000000000000000"
989 },
990 "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
991 "balance": "0x123450000000000000000"
992 },
993 "c5065c9eeebe6df2c2284d046bfc906501846c51": {
994 "balance": "0x123450000000000000000"
995 },
996 "0000000000000000000000000000000000000314": {
997 "balance": "0x0",
998 "code":
999 "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1000 , "storage": {
1001 "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
1002 "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
1003 }
1004 },
1005 "0000000000000000000000000000000000000315": {
1006 "balance": "0x9999999999999999999999999999999",
1007 "code":
1008 "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
1009 },
1010 "0000000000000000000000000000000000000316": {
1011 "balance": "0x0",
1012 "code": "0x444355"
1013 },
1014 "0000000000000000000000000000000000000317": {
1015 "balance": "0x0",
1016 "code": "0x600160003555"
1017 }
1018 }
1019 }
1020 "#;
1021
1022 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1023 }
1024
1025 #[test]
1026 fn parse_hive_devp2p_genesis() {
1027 let geth_genesis = r#"
1028 {
1029 "config": {
1030 "chainId": 19763,
1031 "homesteadBlock": 0,
1032 "eip150Block": 0,
1033 "eip155Block": 0,
1034 "eip158Block": 0,
1035 "byzantiumBlock": 0,
1036 "ethash": {}
1037 },
1038 "nonce": "0xdeadbeefdeadbeef",
1039 "timestamp": "0x0",
1040 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
1041 "gasLimit": "0x80000000",
1042 "difficulty": "0x20000",
1043 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1044 "coinbase": "0x0000000000000000000000000000000000000000",
1045 "alloc": {
1046 "71562b71999873db5b286df957af199ec94617f7": {
1047 "balance": "0xffffffffffffffffffffffffff"
1048 }
1049 },
1050 "number": "0x0",
1051 "gasUsed": "0x0",
1052 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
1053 }
1054 "#;
1055
1056 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1057 }
1058
1059 #[test]
1060 fn parse_deposit_contract_address() {
1061 let genesis = r#"
1062 {
1063 "config": {
1064 "chainId": 1337,
1065 "homesteadBlock": 0,
1066 "eip150Block": 0,
1067 "eip155Block": 0,
1068 "eip158Block": 0,
1069 "byzantiumBlock": 0,
1070 "constantinopleBlock": 0,
1071 "petersburgBlock": 0,
1072 "istanbulBlock": 0,
1073 "muirGlacierBlock": 0,
1074 "berlinBlock": 0,
1075 "londonBlock": 0,
1076 "arrowGlacierBlock": 0,
1077 "grayGlacierBlock": 0,
1078 "shanghaiTime": 0,
1079 "cancunTime": 0,
1080 "pragueTime": 1,
1081 "osakaTime": 2,
1082 "terminalTotalDifficulty": 0,
1083 "depositContractAddress": "0x0000000000000000000000000000000000000000",
1084 "terminalTotalDifficultyPassed": true
1085 },
1086 "nonce": "0x0",
1087 "timestamp": "0x0",
1088 "extraData": "0x",
1089 "gasLimit": "0x4c4b40",
1090 "difficulty": "0x1",
1091 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1092 "coinbase": "0x0000000000000000000000000000000000000000"
1093 }
1094 "#;
1095
1096 let got_genesis: Genesis = serde_json::from_str(genesis).unwrap();
1097 let expected_genesis = Genesis {
1098 config: ChainConfig {
1099 chain_id: 1337,
1100 homestead_block: Some(0),
1101 eip150_block: Some(0),
1102 eip155_block: Some(0),
1103 eip158_block: Some(0),
1104 byzantium_block: Some(0),
1105 constantinople_block: Some(0),
1106 petersburg_block: Some(0),
1107 istanbul_block: Some(0),
1108 muir_glacier_block: Some(0),
1109 berlin_block: Some(0),
1110 london_block: Some(0),
1111 arrow_glacier_block: Some(0),
1112 gray_glacier_block: Some(0),
1113 dao_fork_block: None,
1114 dao_fork_support: false,
1115 shanghai_time: Some(0),
1116 cancun_time: Some(0),
1117 prague_time: Some(1),
1118 osaka_time: Some(2),
1119 terminal_total_difficulty: Some(U256::ZERO),
1120 terminal_total_difficulty_passed: true,
1121 deposit_contract_address: Some(Address::ZERO),
1122 ..Default::default()
1123 },
1124 nonce: 0,
1125 timestamp: 0,
1126 extra_data: Bytes::new(),
1127 gas_limit: 0x4c4b40,
1128 difficulty: U256::from(1),
1129 ..Default::default()
1130 };
1131
1132 assert_eq!(expected_genesis, got_genesis);
1133 }
1134
1135 #[test]
1136 fn parse_prague_time() {
1137 let genesis = r#"
1138 {
1139 "config": {
1140 "chainId": 1337,
1141 "homesteadBlock": 0,
1142 "eip150Block": 0,
1143 "eip155Block": 0,
1144 "eip158Block": 0,
1145 "byzantiumBlock": 0,
1146 "constantinopleBlock": 0,
1147 "petersburgBlock": 0,
1148 "istanbulBlock": 0,
1149 "muirGlacierBlock": 0,
1150 "berlinBlock": 0,
1151 "londonBlock": 0,
1152 "arrowGlacierBlock": 0,
1153 "grayGlacierBlock": 0,
1154 "shanghaiTime": 0,
1155 "cancunTime": 0,
1156 "pragueTime": 1,
1157 "terminalTotalDifficulty": 0,
1158 "terminalTotalDifficultyPassed": true
1159 },
1160 "nonce": "0x0",
1161 "timestamp": "0x0",
1162 "extraData": "0x",
1163 "gasLimit": "0x4c4b40",
1164 "difficulty": "0x1",
1165 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1166 "coinbase": "0x0000000000000000000000000000000000000000"
1167 }
1168 "#;
1169
1170 let got_genesis: Genesis = serde_json::from_str(genesis).unwrap();
1171 let expected_genesis = Genesis {
1172 config: ChainConfig {
1173 chain_id: 1337,
1174 homestead_block: Some(0),
1175 eip150_block: Some(0),
1176 eip155_block: Some(0),
1177 eip158_block: Some(0),
1178 byzantium_block: Some(0),
1179 constantinople_block: Some(0),
1180 petersburg_block: Some(0),
1181 istanbul_block: Some(0),
1182 muir_glacier_block: Some(0),
1183 berlin_block: Some(0),
1184 london_block: Some(0),
1185 arrow_glacier_block: Some(0),
1186 gray_glacier_block: Some(0),
1187 dao_fork_block: None,
1188 dao_fork_support: false,
1189 shanghai_time: Some(0),
1190 cancun_time: Some(0),
1191 prague_time: Some(1),
1192 terminal_total_difficulty: Some(U256::ZERO),
1193 terminal_total_difficulty_passed: true,
1194 ..Default::default()
1195 },
1196 nonce: 0,
1197 timestamp: 0,
1198 extra_data: Bytes::new(),
1199 gas_limit: 0x4c4b40,
1200 difficulty: U256::from(1),
1201 ..Default::default()
1202 };
1203
1204 assert_eq!(expected_genesis, got_genesis);
1205 }
1206
1207 #[test]
1208 fn parse_execution_apis_genesis() {
1209 let geth_genesis = r#"
1210 {
1211 "config": {
1212 "chainId": 1337,
1213 "homesteadBlock": 0,
1214 "eip150Block": 0,
1215 "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1216 "eip155Block": 0,
1217 "eip158Block": 0,
1218 "byzantiumBlock": 0,
1219 "constantinopleBlock": 0,
1220 "petersburgBlock": 0,
1221 "istanbulBlock": 0,
1222 "muirGlacierBlock": 0,
1223 "berlinBlock": 0,
1224 "londonBlock": 0,
1225 "arrowGlacierBlock": 0,
1226 "grayGlacierBlock": 0,
1227 "shanghaiTime": 0,
1228 "terminalTotalDifficulty": 0,
1229 "terminalTotalDifficultyPassed": true,
1230 "ethash": {}
1231 },
1232 "nonce": "0x0",
1233 "timestamp": "0x0",
1234 "extraData": "0x",
1235 "gasLimit": "0x4c4b40",
1236 "difficulty": "0x1",
1237 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1238 "coinbase": "0x0000000000000000000000000000000000000000",
1239 "alloc": {
1240 "658bdf435d810c91414ec09147daa6db62406379": {
1241 "balance": "0x487a9a304539440000"
1242 },
1243 "aa00000000000000000000000000000000000000": {
1244 "code": "0x6042",
1245 "storage": {
1246 "0x0000000000000000000000000000000000000000000000000000000000000000":
1247 "0x0000000000000000000000000000000000000000000000000000000000000000",
1248 "0x0100000000000000000000000000000000000000000000000000000000000000":
1249 "0x0100000000000000000000000000000000000000000000000000000000000000",
1250 "0x0200000000000000000000000000000000000000000000000000000000000000":
1251 "0x0200000000000000000000000000000000000000000000000000000000000000",
1252 "0x0300000000000000000000000000000000000000000000000000000000000000":
1253 "0x0000000000000000000000000000000000000000000000000000000000000303" },
1254 "balance": "0x1",
1255 "nonce": "0x1"
1256 },
1257 "bb00000000000000000000000000000000000000": {
1258 "code": "0x600154600354",
1259 "storage": {
1260 "0x0000000000000000000000000000000000000000000000000000000000000000":
1261 "0x0000000000000000000000000000000000000000000000000000000000000000",
1262 "0x0100000000000000000000000000000000000000000000000000000000000000":
1263 "0x0100000000000000000000000000000000000000000000000000000000000000",
1264 "0x0200000000000000000000000000000000000000000000000000000000000000":
1265 "0x0200000000000000000000000000000000000000000000000000000000000000",
1266 "0x0300000000000000000000000000000000000000000000000000000000000000":
1267 "0x0000000000000000000000000000000000000000000000000000000000000303" },
1268 "balance": "0x2",
1269 "nonce": "0x1"
1270 }
1271 }
1272 }
1273 "#;
1274
1275 let _genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1276 }
1277
1278 #[test]
1279 fn parse_hive_rpc_genesis_full() {
1280 let geth_genesis = r#"
1281 {
1282 "config": {
1283 "clique": {
1284 "period": 1
1285 },
1286 "chainId": 7,
1287 "homesteadBlock": 0,
1288 "eip150Block": 0,
1289 "eip155Block": 0,
1290 "eip158Block": 0
1291 },
1292 "coinbase": "0x0000000000000000000000000000000000000000",
1293 "difficulty": "0x020000",
1294 "extraData":
1295 "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1296 , "gasLimit": "0x2fefd8",
1297 "nonce": "0x0000000000000000",
1298 "timestamp": "0x1234",
1299 "alloc": {
1300 "cf49fda3be353c69b41ed96333cd24302da4556f": {
1301 "balance": "0x123450000000000000000"
1302 },
1303 "0161e041aad467a890839d5b08b138c1e6373072": {
1304 "balance": "0x123450000000000000000"
1305 },
1306 "87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
1307 "balance": "0x123450000000000000000"
1308 },
1309 "b97de4b8c857e4f6bc354f226dc3249aaee49209": {
1310 "balance": "0x123450000000000000000"
1311 },
1312 "c5065c9eeebe6df2c2284d046bfc906501846c51": {
1313 "balance": "0x123450000000000000000"
1314 },
1315 "0000000000000000000000000000000000000314": {
1316 "balance": "0x0",
1317 "code":
1318 "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1319 , "storage": {
1320 "0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
1321 "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
1322 }
1323 },
1324 "0000000000000000000000000000000000000315": {
1325 "balance": "0x9999999999999999999999999999999",
1326 "code":
1327 "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
1328 }
1329 },
1330 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1331 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
1332 }
1333 "#;
1334
1335 let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1336 let alloc_entry = genesis
1337 .alloc
1338 .get(&Address::from_str("0000000000000000000000000000000000000314").unwrap())
1339 .expect("missing account for parsed genesis");
1340 let storage = alloc_entry.storage.as_ref().expect("missing storage for parsed genesis");
1341 let expected_storage = BTreeMap::from_iter(vec![
1342 (
1343 B256::from_str(
1344 "0x0000000000000000000000000000000000000000000000000000000000000000",
1345 )
1346 .unwrap(),
1347 B256::from_str(
1348 "0x0000000000000000000000000000000000000000000000000000000000001234",
1349 )
1350 .unwrap(),
1351 ),
1352 (
1353 B256::from_str(
1354 "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9",
1355 )
1356 .unwrap(),
1357 B256::from_str(
1358 "0x0000000000000000000000000000000000000000000000000000000000000001",
1359 )
1360 .unwrap(),
1361 ),
1362 ]);
1363 assert_eq!(storage, &expected_storage);
1364
1365 let expected_code =
1366 Bytes::from_str("0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029"
1367 ).unwrap();
1368 let code = alloc_entry.code.as_ref().expect(
1369 "missing code for parsed
1370 genesis",
1371 );
1372 assert_eq!(code, &expected_code);
1373 }
1374
1375 #[test]
1376 fn test_hive_smoke_alloc_deserialize() {
1377 let hive_genesis = r#"
1378 {
1379 "nonce": "0x0000000000000042",
1380 "difficulty": "0x2123456",
1381 "mixHash": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
1382 "coinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1383 "timestamp": "0x123456",
1384 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1385 "extraData": "0xfafbfcfd",
1386 "gasLimit": "0x2fefd8",
1387 "alloc": {
1388 "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {
1389 "balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1390 },
1391 "e6716f9544a56c530d868e4bfbacb172315bdead": {
1392 "balance": "0x11",
1393 "code": "0x12"
1394 },
1395 "b9c015918bdaba24b4ff057a92a3873d6eb201be": {
1396 "balance": "0x21",
1397 "storage": {
1398 "0x0000000000000000000000000000000000000000000000000000000000000001": "0x22"
1399 }
1400 },
1401 "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {
1402 "balance": "0x31",
1403 "nonce": "0x32"
1404 },
1405 "0000000000000000000000000000000000000001": {
1406 "balance": "0x41"
1407 },
1408 "0000000000000000000000000000000000000002": {
1409 "balance": "0x51"
1410 },
1411 "0000000000000000000000000000000000000003": {
1412 "balance": "0x61"
1413 },
1414 "0000000000000000000000000000000000000004": {
1415 "balance": "0x71"
1416 }
1417 },
1418 "config": {
1419 "ethash": {},
1420 "chainId": 10,
1421 "homesteadBlock": 0,
1422 "eip150Block": 0,
1423 "eip155Block": 0,
1424 "eip158Block": 0,
1425 "byzantiumBlock": 0,
1426 "constantinopleBlock": 0,
1427 "petersburgBlock": 0,
1428 "istanbulBlock": 0
1429 }
1430 }
1431 "#;
1432
1433 let expected_genesis =
1434 Genesis {
1435 nonce: 0x0000000000000042,
1436 difficulty: U256::from(0x2123456),
1437 mix_hash: B256::from_str(
1438 "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234",
1439 )
1440 .unwrap(),
1441 coinbase: Address::from_str("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(),
1442 timestamp: 0x123456,
1443 extra_data: Bytes::from_str("0xfafbfcfd").unwrap(),
1444 gas_limit: 0x2fefd8,
1445 base_fee_per_gas: None,
1446 excess_blob_gas: None,
1447 blob_gas_used: None,
1448 number: None,
1449 alloc: BTreeMap::from_iter(vec![
1450 (
1451 Address::from_str("0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6").unwrap(),
1452 GenesisAccount {
1453 balance:
1454 U256::from_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
1455 unwrap(), nonce: None,
1456 code: None,
1457 storage: None,
1458 private_key: None,
1459 },
1460 ),
1461 (
1462 Address::from_str("0xe6716f9544a56c530d868e4bfbacb172315bdead").unwrap(),
1463 GenesisAccount {
1464 balance: U256::from_str("0x11").unwrap(),
1465 nonce: None,
1466 code: Some(Bytes::from_str("0x12").unwrap()),
1467 storage: None,
1468 private_key: None,
1469 },
1470 ),
1471 (
1472 Address::from_str("0xb9c015918bdaba24b4ff057a92a3873d6eb201be").unwrap(),
1473 GenesisAccount {
1474 balance: U256::from_str("0x21").unwrap(),
1475 nonce: None,
1476 code: None,
1477 storage: Some(BTreeMap::from_iter(vec![
1478 (
1479
1480 B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001").
1481 unwrap(),
1482 B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000022").
1483 unwrap(), ),
1484 ])),
1485 private_key: None,
1486 },
1487 ),
1488 (
1489 Address::from_str("0x1a26338f0d905e295fccb71fa9ea849ffa12aaf4").unwrap(),
1490 GenesisAccount {
1491 balance: U256::from_str("0x31").unwrap(),
1492 nonce: Some(0x32u64),
1493 code: None,
1494 storage: None,
1495 private_key: None,
1496 },
1497 ),
1498 (
1499 Address::from_str("0x0000000000000000000000000000000000000001").unwrap(),
1500 GenesisAccount {
1501 balance: U256::from_str("0x41").unwrap(),
1502 nonce: None,
1503 code: None,
1504 storage: None,
1505 private_key: None,
1506 },
1507 ),
1508 (
1509 Address::from_str("0x0000000000000000000000000000000000000002").unwrap(),
1510 GenesisAccount {
1511 balance: U256::from_str("0x51").unwrap(),
1512 nonce: None,
1513 code: None,
1514 storage: None,
1515 private_key: None,
1516 },
1517 ),
1518 (
1519 Address::from_str("0x0000000000000000000000000000000000000003").unwrap(),
1520 GenesisAccount {
1521 balance: U256::from_str("0x61").unwrap(),
1522 nonce: None,
1523 code: None,
1524 storage: None,
1525 private_key: None,
1526 },
1527 ),
1528 (
1529 Address::from_str("0x0000000000000000000000000000000000000004").unwrap(),
1530 GenesisAccount {
1531 balance: U256::from_str("0x71").unwrap(),
1532 nonce: None,
1533 code: None,
1534 storage: None,
1535 private_key: None,
1536 },
1537 ),
1538 ]),
1539 config: ChainConfig {
1540 ethash: Some(EthashConfig {}),
1541 chain_id: 10,
1542 homestead_block: Some(0),
1543 eip150_block: Some(0),
1544 eip155_block: Some(0),
1545 eip158_block: Some(0),
1546 byzantium_block: Some(0),
1547 constantinople_block: Some(0),
1548 petersburg_block: Some(0),
1549 istanbul_block: Some(0),
1550 deposit_contract_address: None,
1551 ..Default::default()
1552 },
1553 };
1554
1555 let deserialized_genesis: Genesis = serde_json::from_str(hive_genesis).unwrap();
1556 assert_eq!(
1557 deserialized_genesis, expected_genesis,
1558 "deserialized genesis
1559 {deserialized_genesis:#?} does not match expected {expected_genesis:#?}"
1560 );
1561 }
1562
1563 #[test]
1564 fn parse_dump_genesis_mainnet() {
1565 let mainnet = include_str!("../dumpgenesis/mainnet.json");
1566 let gen = serde_json::from_str::<Genesis>(mainnet).unwrap();
1567 let s = serde_json::to_string_pretty(&gen).unwrap();
1568 let gen2 = serde_json::from_str::<Genesis>(&s).unwrap();
1569 assert_eq!(gen, gen2);
1570 }
1571
1572 #[test]
1573 fn parse_dump_genesis_sepolia() {
1574 let sepolia = include_str!("../dumpgenesis/sepolia.json");
1575 let gen = serde_json::from_str::<Genesis>(sepolia).unwrap();
1576 let s = serde_json::to_string_pretty(&gen).unwrap();
1577 let gen2 = serde_json::from_str::<Genesis>(&s).unwrap();
1578 assert_eq!(gen, gen2);
1579 }
1580
1581 #[test]
1582 fn parse_dump_genesis_holesky() {
1583 let holesky = include_str!("../dumpgenesis/holesky.json");
1584 let gen = serde_json::from_str::<Genesis>(holesky).unwrap();
1585 let s = serde_json::to_string_pretty(&gen).unwrap();
1586 let gen2 = serde_json::from_str::<Genesis>(&s).unwrap();
1587 assert_eq!(gen, gen2);
1588 }
1589
1590 #[test]
1591 fn parse_extra_fields() {
1592 let geth_genesis = r#"
1593 {
1594 "difficulty": "0x20000",
1595 "gasLimit": "0x1",
1596 "alloc": {},
1597 "config": {
1598 "ethash": {},
1599 "chainId": 1,
1600 "string_field": "string_value",
1601 "numeric_field": 7,
1602 "object_field": {
1603 "sub_field": "sub_value"
1604 }
1605 }
1606 }
1607 "#;
1608 let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
1609 let actual_string_value = genesis.config.extra_fields.get("string_field").unwrap();
1610 assert_eq!(actual_string_value, "string_value");
1611 let actual_numeric_value = genesis.config.extra_fields.get("numeric_field").unwrap();
1612 assert_eq!(actual_numeric_value, 7);
1613 let actual_object_value = genesis.config.extra_fields.get("object_field").unwrap();
1614 assert_eq!(actual_object_value, &serde_json::json!({"sub_field": "sub_value"}));
1615 }
1616
1617 #[test]
1618 fn deserialize_private_key_as_none_when_0x() {
1619 let json_data = json!({
1621 "balance": "0x0",
1622 "secretKey": "0x"
1623 });
1624
1625 let account: GenesisAccount = serde_json::from_value(json_data).unwrap();
1626 assert_eq!(account.private_key, None);
1627 }
1628
1629 #[test]
1630 fn deserialize_private_key_with_valid_hex() {
1631 let json_data = json!({
1633 "balance": "0x0",
1634 "secretKey": "0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234"
1635 });
1636
1637 let account: GenesisAccount = serde_json::from_value(json_data).unwrap();
1638 let expected_key =
1639 B256::from_str("123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234")
1640 .unwrap();
1641 assert_eq!(account.private_key, Some(expected_key));
1642 }
1643
1644 #[test]
1645 fn deserialize_private_key_as_none_when_null() {
1646 let json_data = json!({
1648 "balance": "0x0",
1649 "secretKey": null
1650 });
1651
1652 let account: GenesisAccount = serde_json::from_value(json_data).unwrap();
1653 assert_eq!(account.private_key, None);
1654 }
1655
1656 #[test]
1657 fn deserialize_private_key_with_invalid_hex_fails() {
1658 let json_data = json!({
1660 "balance": "0x0",
1661 "secretKey": "0xINVALIDHEX"
1662 });
1663
1664 let result: Result<GenesisAccount, _> = serde_json::from_value(json_data);
1665 assert!(result.is_err()); }
1667
1668 #[test]
1669 fn deserialize_private_key_with_empty_string_fails() {
1670 let json_data = json!({
1672 "secretKey": ""
1673 });
1674
1675 let result: Result<GenesisAccount, _> = serde_json::from_value(json_data);
1676 assert!(result.is_err()); }
1678
1679 #[test]
1680 fn test_from_genesis_account_with_default_values() {
1681 let genesis_account = GenesisAccount::default();
1682
1683 let trie_account: TrieAccount = genesis_account.into();
1685
1686 assert_eq!(trie_account.nonce, 0);
1688 assert_eq!(trie_account.balance, U256::default());
1689 assert_eq!(trie_account.storage_root, EMPTY_ROOT_HASH);
1690 assert_eq!(trie_account.code_hash, KECCAK_EMPTY);
1691
1692 assert_eq!(TrieAccount::default(), trie_account);
1694 }
1695
1696 #[test]
1697 fn test_from_genesis_account_with_values() {
1698 let mut storage = BTreeMap::new();
1700 storage.insert(B256::from([0x01; 32]), B256::from([0x02; 32]));
1701
1702 let genesis_account = GenesisAccount {
1703 nonce: Some(10),
1704 balance: U256::from(1000),
1705 code: Some(Bytes::from(vec![0x60, 0x61])),
1706 storage: Some(storage),
1707 private_key: None,
1708 };
1709
1710 let trie_account: TrieAccount = genesis_account.into();
1712
1713 let expected_storage_root = storage_root_unhashed(BTreeMap::from([(
1714 B256::from([0x01; 32]),
1715 U256::from_be_bytes(*B256::from([0x02; 32])),
1716 )]));
1717
1718 assert_eq!(trie_account.nonce, 10);
1720 assert_eq!(trie_account.balance, U256::from(1000));
1721 assert_eq!(trie_account.storage_root, expected_storage_root);
1722 assert_eq!(trie_account.code_hash, keccak256([0x60, 0x61]));
1723 }
1724
1725 #[test]
1726 fn test_from_genesis_account_with_zeroed_storage_values() {
1727 let storage = BTreeMap::from([(B256::from([0x01; 32]), B256::from([0x00; 32]))]);
1729
1730 let genesis_account = GenesisAccount {
1731 nonce: Some(3),
1732 balance: U256::from(300),
1733 code: None,
1734 storage: Some(storage),
1735 private_key: None,
1736 };
1737
1738 let trie_account: TrieAccount = genesis_account.into();
1740
1741 assert_eq!(trie_account.nonce, 3);
1743 assert_eq!(trie_account.balance, U256::from(300));
1744 assert_eq!(trie_account.storage_root, EMPTY_ROOT_HASH);
1746 assert_eq!(trie_account.code_hash, KECCAK_EMPTY);
1748 }
1749}