mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
Parse Genesis Value from Memory (#5238)
This commit is contained in:
@ -34,8 +34,11 @@ pub fn chain_spec_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Er
|
||||
})
|
||||
}
|
||||
|
||||
/// Clap value parser for [ChainSpec]s that takes either a built-in genesis format or the path
|
||||
/// to a custom one.
|
||||
/// Clap value parser for [ChainSpec]s.
|
||||
///
|
||||
/// The value parser matches either a known chain, the path
|
||||
/// to a json file, or a json formatted string in-memory. The json can be either
|
||||
/// a serialized [ChainSpec] or Genesis struct.
|
||||
pub fn genesis_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
Ok(match s {
|
||||
"mainnet" => MAINNET.clone(),
|
||||
@ -44,8 +47,21 @@ pub fn genesis_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error
|
||||
"holesky" => HOLESKY.clone(),
|
||||
"dev" => DEV.clone(),
|
||||
_ => {
|
||||
let raw = fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned()))?;
|
||||
let genesis: AllGenesisFormats = serde_json::from_str(&raw)?;
|
||||
// both serialized Genesis and ChainSpec structs supported
|
||||
let genesis: AllGenesisFormats =
|
||||
// try to read json from path first
|
||||
match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) {
|
||||
Ok(raw) => serde_json::from_str(&raw)?,
|
||||
Err(io_err) => {
|
||||
// valid json may start with "\n", but must contain "{"
|
||||
if s.contains('{') {
|
||||
serde_json::from_str(s)?
|
||||
} else {
|
||||
return Err(io_err.into()) // assume invalid path
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Arc::new(genesis.into())
|
||||
}
|
||||
})
|
||||
@ -108,16 +124,110 @@ pub fn parse_socket_address(value: &str) -> eyre::Result<SocketAddr, SocketAddre
|
||||
mod tests {
|
||||
use super::*;
|
||||
use proptest::prelude::Rng;
|
||||
use reth_primitives::{
|
||||
hex, Address, ChainConfig, ChainSpecBuilder, Genesis, GenesisAccount, U256,
|
||||
};
|
||||
use secp256k1::rand::thread_rng;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn parse_chain_spec() {
|
||||
fn parse_known_chain_spec() {
|
||||
for chain in ["mainnet", "sepolia", "goerli", "holesky"] {
|
||||
chain_spec_value_parser(chain).unwrap();
|
||||
genesis_value_parser(chain).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chain_spec_from_memory() {
|
||||
let custom_genesis_from_json = r#"
|
||||
{
|
||||
"nonce": "0x0",
|
||||
"timestamp": "0x653FEE9E",
|
||||
"gasLimit": "0x1388",
|
||||
"difficulty": "0x0",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||
"alloc": {
|
||||
"0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b": {
|
||||
"balance": "0x21"
|
||||
}
|
||||
},
|
||||
"number": "0x0",
|
||||
"gasUsed": "0x0",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"config": {
|
||||
"chainId": 2600,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 0,
|
||||
"terminalTotalDifficulty": 0,
|
||||
"terminalTotalDifficultyPassed": true,
|
||||
"shanghaiTime": 0
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let chain_from_json = genesis_value_parser(custom_genesis_from_json).unwrap();
|
||||
|
||||
// using structs
|
||||
let config = ChainConfig {
|
||||
chain_id: 2600,
|
||||
homestead_block: Some(0),
|
||||
eip150_block: Some(0),
|
||||
eip155_block: Some(0),
|
||||
eip158_block: Some(0),
|
||||
byzantium_block: Some(0),
|
||||
constantinople_block: Some(0),
|
||||
petersburg_block: Some(0),
|
||||
istanbul_block: Some(0),
|
||||
berlin_block: Some(0),
|
||||
london_block: Some(0),
|
||||
shanghai_time: Some(0),
|
||||
terminal_total_difficulty: Some(U256::ZERO),
|
||||
terminal_total_difficulty_passed: true,
|
||||
..Default::default()
|
||||
};
|
||||
let genesis = Genesis {
|
||||
config,
|
||||
nonce: 0,
|
||||
timestamp: 1698688670,
|
||||
gas_limit: 5000,
|
||||
difficulty: U256::ZERO,
|
||||
mix_hash: B256::ZERO,
|
||||
coinbase: Address::ZERO,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// seed accounts after genesis struct created
|
||||
let address = hex!("6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b").into();
|
||||
let account = GenesisAccount::default().with_balance(U256::from(33));
|
||||
let genesis = genesis.extend_accounts(HashMap::from([(address, account)]));
|
||||
|
||||
let custom_genesis_from_struct = serde_json::to_string(&genesis).unwrap();
|
||||
let chain_from_struct = genesis_value_parser(&custom_genesis_from_struct).unwrap();
|
||||
assert_eq!(chain_from_json.genesis(), chain_from_struct.genesis());
|
||||
|
||||
// chain spec
|
||||
let chain_spec = ChainSpecBuilder::default()
|
||||
.chain(2600.into())
|
||||
.genesis(genesis)
|
||||
.cancun_activated()
|
||||
.build();
|
||||
|
||||
let chain_spec_json = serde_json::to_string(&chain_spec).unwrap();
|
||||
let custom_genesis_from_spec = genesis_value_parser(&chain_spec_json).unwrap();
|
||||
|
||||
assert_eq!(custom_genesis_from_spec.chain(), chain_from_struct.chain());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_socket_addresses() {
|
||||
for value in ["localhost:9000", ":9000", "9000"] {
|
||||
|
||||
@ -708,10 +708,10 @@ impl ForkTimestamps {
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum AllGenesisFormats {
|
||||
/// The geth genesis format
|
||||
Geth(Genesis),
|
||||
/// The reth genesis format
|
||||
Reth(ChainSpec),
|
||||
/// The geth genesis format
|
||||
Geth(Genesis),
|
||||
}
|
||||
|
||||
impl From<Genesis> for AllGenesisFormats {
|
||||
@ -1189,10 +1189,13 @@ impl DepositContract {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{b256, hex, NamedChain, B256, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA, U256};
|
||||
use crate::{
|
||||
b256, hex, ChainConfig, GenesisAccount, NamedChain, B256, DEV, GOERLI, HOLESKY, MAINNET,
|
||||
SEPOLIA, U256,
|
||||
};
|
||||
use alloy_rlp::Encodable;
|
||||
use bytes::BytesMut;
|
||||
use std::str::FromStr;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) {
|
||||
for (block, expected_id) in cases {
|
||||
@ -2293,4 +2296,61 @@ Post-merge hard forks (timestamp based):
|
||||
.fork(Hardfork::Paris)
|
||||
.active_at_ttd(HOLESKY.genesis.difficulty, HOLESKY.genesis.difficulty));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_genesis_formats_deserialization() {
|
||||
// custom genesis with chain config
|
||||
let config = ChainConfig {
|
||||
chain_id: 2600,
|
||||
homestead_block: Some(0),
|
||||
eip150_block: Some(0),
|
||||
eip155_block: Some(0),
|
||||
eip158_block: Some(0),
|
||||
byzantium_block: Some(0),
|
||||
constantinople_block: Some(0),
|
||||
petersburg_block: Some(0),
|
||||
istanbul_block: Some(0),
|
||||
berlin_block: Some(0),
|
||||
london_block: Some(0),
|
||||
shanghai_time: Some(0),
|
||||
terminal_total_difficulty: Some(U256::ZERO),
|
||||
terminal_total_difficulty_passed: true,
|
||||
..Default::default()
|
||||
};
|
||||
// genesis
|
||||
let genesis = Genesis {
|
||||
config,
|
||||
nonce: 0,
|
||||
timestamp: 1698688670,
|
||||
gas_limit: 5000,
|
||||
difficulty: U256::ZERO,
|
||||
mix_hash: B256::ZERO,
|
||||
coinbase: Address::ZERO,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// seed accounts after genesis struct created
|
||||
let address = hex!("6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b").into();
|
||||
let account = GenesisAccount::default().with_balance(U256::from(33));
|
||||
let genesis = genesis.extend_accounts(HashMap::from([(address, account)]));
|
||||
|
||||
// ensure genesis is deserialized correctly
|
||||
let serialized_genesis = serde_json::to_string(&genesis).unwrap();
|
||||
let deserialized_genesis: AllGenesisFormats =
|
||||
serde_json::from_str(&serialized_genesis).unwrap();
|
||||
assert!(matches!(deserialized_genesis, AllGenesisFormats::Geth(_)));
|
||||
|
||||
// build chain
|
||||
let chain_spec = ChainSpecBuilder::default()
|
||||
.chain(2600.into())
|
||||
.genesis(genesis)
|
||||
.cancun_activated()
|
||||
.build();
|
||||
|
||||
// ensure chain spec is deserialized correctly
|
||||
let serialized_chain_spec = serde_json::to_string(&chain_spec).unwrap();
|
||||
let deserialized_chain_spec: AllGenesisFormats =
|
||||
serde_json::from_str(&serialized_chain_spec).unwrap();
|
||||
assert!(matches!(deserialized_chain_spec, AllGenesisFormats::Reth(_)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ pub use constants::{
|
||||
#[cfg(feature = "c-kzg")]
|
||||
pub use eip4844::{calculate_excess_blob_gas, kzg_to_versioned_hash};
|
||||
pub use forkid::{ForkFilter, ForkHash, ForkId, ForkTransition, ValidationError};
|
||||
pub use genesis::{Genesis, GenesisAccount};
|
||||
pub use genesis::{ChainConfig, Genesis, GenesisAccount};
|
||||
pub use hardfork::Hardfork;
|
||||
pub use header::{Head, Header, HeadersDirection, SealedHeader};
|
||||
pub use integer_list::IntegerList;
|
||||
|
||||
Reference in New Issue
Block a user