Parse Genesis Value from Memory (#5238)

This commit is contained in:
grantkee
2023-11-02 21:58:29 -05:00
committed by GitHub
parent 265dd56f24
commit e6995e5cdf
3 changed files with 180 additions and 10 deletions

View File

@ -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"] {