mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: Support testnet genesis
This commit is contained in:
@ -8,7 +8,7 @@ use reth_primitives::{Header, SealedHeader};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Chains supported by reth. First value should be used as the default.
|
||||
pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "holesky", "dev"];
|
||||
pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "testnet", "sepolia", "holesky", "dev"];
|
||||
|
||||
static GENESIS_HASH: B256 =
|
||||
b256!("d8fcc13b6a195b88b7b2da3722ff6cad767b13a8c1e9ffb1c73aa9d216d895f0");
|
||||
@ -92,6 +92,7 @@ pub static HL_MAINNET: Lazy<alloc::sync::Arc<ChainSpec>> = Lazy::new(|| {
|
||||
pub fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
Ok(match s {
|
||||
"mainnet" => HL_MAINNET.clone(),
|
||||
"testnet" => Arc::new(super::hl_testnet::load_hl_testnet()),
|
||||
"sepolia" => SEPOLIA.clone(),
|
||||
"holesky" => HOLESKY.clone(),
|
||||
"dev" => DEV.clone(),
|
||||
|
||||
113
crates/ethereum/cli/src/hl_testnet.rs
Normal file
113
crates/ethereum/cli/src/hl_testnet.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use alloy_consensus::Header;
|
||||
use alloy_genesis::{ChainConfig, Genesis};
|
||||
use alloy_primitives::U256;
|
||||
use alloy_rlp::Decodable;
|
||||
use reqwest::blocking::get;
|
||||
use reth_chainspec::{ChainSpec, DEV_HARDFORKS};
|
||||
use reth_primitives::SealedHeader;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub(crate) fn load_hl_testnet() -> ChainSpec {
|
||||
const TESTNET_GENESIS_URL: &str = "https://raw.githubusercontent.com/sprites0/hl-testnet-genesis/main/19386700.rlp";
|
||||
|
||||
fn download_testnet_genesis() -> Result<&'static str, Box<dyn std::error::Error>> {
|
||||
let path = "/tmp/hl_testnet.rmp.lz4";
|
||||
println!("Downloading testnet genesis");
|
||||
let mut response = get(TESTNET_GENESIS_URL)?;
|
||||
if let Some(length) = response.content_length() {
|
||||
// Check if the file exists
|
||||
if let Ok(metadata) = std::fs::metadata(path) {
|
||||
if metadata.len() == length {
|
||||
println!("Already downloaded");
|
||||
return Ok(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut file = File::create(path)?;
|
||||
let mut downloaded = 0;
|
||||
let total_size = response.content_length().unwrap_or(0);
|
||||
let mut buffer = vec![0; 0x100000];
|
||||
|
||||
loop {
|
||||
let size = response.read(buffer.as_mut_slice())?;
|
||||
if size == 0 {
|
||||
break;
|
||||
}
|
||||
file.write_all(&buffer[..size])?;
|
||||
downloaded += size as u64;
|
||||
println!(
|
||||
"Downloaded {} of {} bytes ({}%)",
|
||||
downloaded,
|
||||
total_size,
|
||||
(downloaded as f64 / total_size as f64 * 100.0).round()
|
||||
);
|
||||
}
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
let path = download_testnet_genesis().expect("Failed to download testnet genesis");
|
||||
let mut file = File::open(path).expect("Failed to open testnet genesis");
|
||||
let mut buffer = Vec::new();
|
||||
file.read_to_end(&mut buffer).expect("Failed to read testnet genesis");
|
||||
let mut header = Header::decode(&mut &buffer[..]).expect("Failed to decode testnet genesis");
|
||||
|
||||
let config = ChainConfig {
|
||||
chain_id: 998,
|
||||
homestead_block: Some(0),
|
||||
dao_fork_block: Some(0),
|
||||
dao_fork_support: false,
|
||||
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),
|
||||
muir_glacier_block: Some(0),
|
||||
berlin_block: Some(0),
|
||||
london_block: Some(0),
|
||||
arrow_glacier_block: Some(0),
|
||||
gray_glacier_block: Some(0),
|
||||
merge_netsplit_block: Some(0),
|
||||
shanghai_time: Some(0),
|
||||
cancun_time: Some(0),
|
||||
prague_time: Some(0),
|
||||
osaka_time: Some(0),
|
||||
terminal_total_difficulty: Some(U256::ZERO),
|
||||
terminal_total_difficulty_passed: true,
|
||||
ethash: None,
|
||||
clique: None,
|
||||
parlia: None,
|
||||
extra_fields: Default::default(),
|
||||
deposit_contract_address: None,
|
||||
blob_schedule: Default::default(),
|
||||
};
|
||||
header.number = 0;
|
||||
let genesis_header = SealedHeader::new(header.clone(), header.hash_slow());
|
||||
let genesis = Genesis {
|
||||
config,
|
||||
nonce: header.nonce.into(),
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
gas_limit: header.gas_limit,
|
||||
difficulty: header.difficulty,
|
||||
mix_hash: header.mix_hash,
|
||||
coinbase: header.beneficiary,
|
||||
alloc: BTreeMap::default(),
|
||||
base_fee_per_gas: header.base_fee_per_gas.map(|x| x.into()),
|
||||
excess_blob_gas: header.excess_blob_gas,
|
||||
blob_gas_used: header.blob_gas_used,
|
||||
number: None,
|
||||
};
|
||||
|
||||
ChainSpec {
|
||||
chain: alloy_chains::Chain::from_id(998),
|
||||
genesis: genesis.into(),
|
||||
genesis_header,
|
||||
hardforks: DEV_HARDFORKS.clone(),
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,8 @@
|
||||
/// Chain specification parser.
|
||||
pub mod chainspec;
|
||||
|
||||
mod hl_testnet;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use clap::Parser;
|
||||
|
||||
Reference in New Issue
Block a user