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