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