diff --git a/bin/reth/src/args/utils.rs b/bin/reth/src/args/utils.rs index 0f9ef5c6bb8e..ab195311088b 100644 --- a/bin/reth/src/args/utils.rs +++ b/bin/reth/src/args/utils.rs @@ -47,21 +47,47 @@ pub fn genesis_value_parser(s: &str) -> eyre::Result, eyre::Error "holesky" => HOLESKY.clone(), "dev" => DEV.clone(), _ => { - // both serialized Genesis and ChainSpec structs supported - let genesis: AllGenesisFormats = - // try to read json from path first + // try to read json from path first + let mut raw = match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) { - Ok(raw) => serde_json::from_str(&raw)?, + Ok(raw) => raw, Err(io_err) => { // valid json may start with "\n", but must contain "{" if s.contains('{') { - serde_json::from_str(s)? + s.to_string() } else { return Err(io_err.into()) // assume invalid path } } }; + // The ethereum mainnet TTD is 58750000000000000000000, and geth serializes this + // without quotes, because that is how golang `big.Int`s marshal in JSON. Numbers + // are arbitrary precision in JSON, so this is valid JSON. This number is also + // greater than a `u64`. + // + // Unfortunately, serde_json only supports parsing up to `u64`, resorting to `f64` + // once `u64` overflows: + // + // + // + // + // serde_json does have an arbitrary precision feature, but this breaks untagged + // enums in serde: + // + // + // + // To solve this, we surround the mainnet TTD with quotes, which our custom Visitor + // accepts. + if raw.contains("58750000000000000000000") && + !raw.contains("\"58750000000000000000000\"") + { + raw = raw.replacen("58750000000000000000000", "\"58750000000000000000000\"", 1); + } + + // both serialized Genesis and ChainSpec structs supported + let genesis: AllGenesisFormats = serde_json::from_str(&raw)?; + Arc::new(genesis.into()) } }) diff --git a/crates/primitives/src/chain/spec.rs b/crates/primitives/src/chain/spec.rs index 81cce105c40c..9cebf52a8367 100644 --- a/crates/primitives/src/chain/spec.rs +++ b/crates/primitives/src/chain/spec.rs @@ -2253,6 +2253,27 @@ Post-merge hard forks (timestamp based): assert_eq!(genesis.config.cancun_time, Some(4661)); } + #[test] + fn test_parse_cancun_genesis_all_formats() { + let s = r#"{"config":{"ethash":{},"chainId":1337,"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,"cancunTime":4661},"nonce":"0x0","timestamp":"0x0","extraData":"0x","gasLimit":"0x4c4b40","difficulty":"0x1","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"658bdf435d810c91414ec09147daa6db62406379":{"balance":"0x487a9a304539440000"},"aa00000000000000000000000000000000000000":{"code":"0x6042","storage":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x0000000000000000000000000000000000000000000000000000000000000000","0x0100000000000000000000000000000000000000000000000000000000000000":"0x0100000000000000000000000000000000000000000000000000000000000000","0x0200000000000000000000000000000000000000000000000000000000000000":"0x0200000000000000000000000000000000000000000000000000000000000000","0x0300000000000000000000000000000000000000000000000000000000000000":"0x0000000000000000000000000000000000000000000000000000000000000303"},"balance":"0x1","nonce":"0x1"},"bb00000000000000000000000000000000000000":{"code":"0x600154600354","storage":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x0000000000000000000000000000000000000000000000000000000000000000","0x0100000000000000000000000000000000000000000000000000000000000000":"0x0100000000000000000000000000000000000000000000000000000000000000","0x0200000000000000000000000000000000000000000000000000000000000000":"0x0200000000000000000000000000000000000000000000000000000000000000","0x0300000000000000000000000000000000000000000000000000000000000000":"0x0000000000000000000000000000000000000000000000000000000000000303"},"balance":"0x2","nonce":"0x1"}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","baseFeePerGas":"0x3b9aca00"}"#; + let genesis: AllGenesisFormats = serde_json::from_str(s).unwrap(); + + // this should be the genesis format + let genesis = match genesis { + AllGenesisFormats::Geth(genesis) => genesis, + _ => panic!("expected geth genesis format"), + }; + + // assert that the alloc was picked up + let acc = genesis + .alloc + .get(&"0xaa00000000000000000000000000000000000000".parse::
().unwrap()) + .unwrap(); + assert_eq!(acc.balance, U256::from(1)); + // assert that the cancun time was picked up + assert_eq!(genesis.config.cancun_time, Some(4661)); + } + #[test] fn test_default_cancun_header_forkhash() { // set the gas limit from the hive test genesis according to the hash