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