mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
refactor: clean up reth node (#450)
* feat: parse genesis block from a json spec * refactor: clean up `init_genesis`
This commit is contained in:
@ -27,7 +27,7 @@ tracing = "0.1"
|
||||
tracing-futures = "0.2"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
# mics
|
||||
# misc
|
||||
shellexpand = "2.1"
|
||||
|
||||
eyre = "0.6.8"
|
||||
|
||||
26694
bin/reth/res/chainspec/mainnet.json
Normal file
26694
bin/reth/res/chainspec/mainnet.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
//! Main node command
|
||||
//!
|
||||
//! Starts the client
|
||||
use crate::util::chainspec::Genesis;
|
||||
use clap::{crate_version, Parser};
|
||||
use reth_consensus::EthConsensus;
|
||||
use reth_db::{
|
||||
@ -17,16 +18,22 @@ use reth_network::{
|
||||
error::NetworkError,
|
||||
NetworkConfig, NetworkHandle, NetworkManager,
|
||||
};
|
||||
use reth_primitives::{hex_literal::hex, Bytes, Header, H256, U256};
|
||||
use reth_primitives::{hex_literal::hex, Account, Header, H256};
|
||||
use reth_provider::{db_provider::ProviderImpl, BlockProvider, HeaderProvider};
|
||||
use reth_stages::stages::{bodies::BodyStage, headers::HeaderStage, senders::SendersStage};
|
||||
use std::{path::Path, str::FromStr, sync::Arc};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::{debug, info};
|
||||
|
||||
// TODO: Move this out somewhere
|
||||
const MAINNET_GENESIS: &str = include_str!("../../res/chainspec/mainnet.json");
|
||||
|
||||
/// Start the client
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Command {
|
||||
/// Path to database folder
|
||||
/// The path to the database folder.
|
||||
// TODO: This should use dirs-next
|
||||
#[arg(long, default_value = "~/.reth/db")]
|
||||
db: String,
|
||||
@ -38,19 +45,18 @@ impl Command {
|
||||
pub async fn execute(&self) -> eyre::Result<()> {
|
||||
info!("reth {} starting", crate_version!());
|
||||
|
||||
let path = shellexpand::full(&self.db)?.into_owned();
|
||||
let expanded_db_path = Path::new(&path);
|
||||
let db = Arc::new(init_db(expanded_db_path)?);
|
||||
info!("Database ready");
|
||||
let db_path = PathBuf::from(shellexpand::full(&self.db)?.into_owned());
|
||||
info!("Opening database at {}", db_path.display());
|
||||
let db = Arc::new(init_db(db_path)?);
|
||||
info!("Database open");
|
||||
|
||||
// TODO: Write genesis info
|
||||
// TODO: Here we should parse and validate the chainspec and build consensus/networking
|
||||
// stuff off of that
|
||||
// TODO: More info from chainspec (chain ID etc.)
|
||||
let consensus = Arc::new(EthConsensus::new(consensus_config()));
|
||||
init_genesis(db.clone())?;
|
||||
let genesis_hash =
|
||||
init_genesis(db.clone(), serde_json::from_str(MAINNET_GENESIS).unwrap())?;
|
||||
|
||||
info!("Connecting to p2p");
|
||||
let network = start_network(network_config(db.clone())).await?;
|
||||
let network = start_network(network_config(db.clone(), genesis_hash)).await?;
|
||||
|
||||
// TODO: Are most of these Arcs unnecessary? For example, fetch client is completely
|
||||
// cloneable on its own
|
||||
@ -79,7 +85,7 @@ impl Command {
|
||||
},
|
||||
false,
|
||||
)
|
||||
.push(SendersStage { batch_size: 1000, commit_threshold: 100 }, false);
|
||||
.push(SendersStage { batch_size: 100, commit_threshold: 1000 }, false);
|
||||
|
||||
// Run pipeline
|
||||
info!("Starting pipeline");
|
||||
@ -118,45 +124,47 @@ fn init_db<P: AsRef<Path>>(path: P) -> eyre::Result<Env<WriteMap>> {
|
||||
|
||||
/// Write the genesis block if it has not already been written
|
||||
#[allow(clippy::field_reassign_with_default)]
|
||||
fn init_genesis<DB: Database>(db: Arc<DB>) -> Result<(), reth_db::Error> {
|
||||
fn init_genesis<DB: Database>(db: Arc<DB>, genesis: Genesis) -> Result<H256, reth_db::Error> {
|
||||
let tx = db.tx_mut()?;
|
||||
let has_block = tx.cursor::<tables::CanonicalHeaders>()?.first()?.is_some();
|
||||
if has_block {
|
||||
if let Some((_, hash)) = tx.cursor::<tables::CanonicalHeaders>()?.first()? {
|
||||
debug!("Genesis already written, skipping.");
|
||||
return Ok(())
|
||||
return Ok(hash)
|
||||
}
|
||||
|
||||
debug!("Writing genesis block.");
|
||||
|
||||
// TODO: Should be based on a chain spec
|
||||
let mut genesis = Header::default();
|
||||
genesis.gas_limit = 5000;
|
||||
genesis.difficulty = U256::from(0x400000000usize);
|
||||
genesis.nonce = 0x0000000000000042;
|
||||
genesis.extra_data =
|
||||
Bytes::from_str("11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")
|
||||
.unwrap()
|
||||
.0;
|
||||
genesis.state_root =
|
||||
H256(hex!("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"));
|
||||
let genesis = genesis.seal();
|
||||
// Insert account state
|
||||
for (address, account) in &genesis.alloc {
|
||||
tx.put::<tables::PlainAccountState>(
|
||||
*address,
|
||||
Account {
|
||||
nonce: account.nonce.unwrap_or_default(),
|
||||
balance: account.balance,
|
||||
bytecode_hash: None,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
// Insert header
|
||||
let header: Header = genesis.into();
|
||||
let hash = header.hash_slow();
|
||||
tx.put::<tables::CanonicalHeaders>(0, hash)?;
|
||||
tx.put::<tables::HeaderNumbers>(hash, 0)?;
|
||||
tx.put::<tables::CumulativeTxCount>((0, hash).into(), 0)?;
|
||||
tx.put::<tables::HeaderTD>((0, hash).into(), header.difficulty.into())?;
|
||||
tx.put::<tables::Headers>((0, hash).into(), header)?;
|
||||
|
||||
// Insert genesis
|
||||
tx.put::<tables::CanonicalHeaders>(genesis.number, genesis.hash())?;
|
||||
tx.put::<tables::Headers>(genesis.num_hash().into(), genesis.as_ref().clone())?;
|
||||
tx.put::<tables::HeaderNumbers>(genesis.hash(), genesis.number)?;
|
||||
tx.put::<tables::CumulativeTxCount>(genesis.num_hash().into(), 0)?;
|
||||
tx.put::<tables::HeaderTD>(genesis.num_hash().into(), genesis.difficulty.into())?;
|
||||
tx.commit()?;
|
||||
|
||||
// TODO: Account balances
|
||||
Ok(())
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
// TODO: This should be based on some external config
|
||||
fn network_config<DB: Database>(db: Arc<DB>) -> NetworkConfig<ProviderImpl<DB>> {
|
||||
fn network_config<DB: Database>(
|
||||
db: Arc<DB>,
|
||||
genesis_hash: H256,
|
||||
) -> NetworkConfig<ProviderImpl<DB>> {
|
||||
NetworkConfig::builder(Arc::new(ProviderImpl::new(db)), rng_secret_key())
|
||||
.boot_nodes(mainnet_nodes())
|
||||
.genesis_hash(genesis_hash)
|
||||
.build()
|
||||
}
|
||||
|
||||
@ -175,7 +183,7 @@ where
|
||||
NetworkManager::builder(config).await?.request_handler(client).split_with_handle();
|
||||
|
||||
tokio::task::spawn(network);
|
||||
//tokio::task::spawn(txpool);
|
||||
// TODO: tokio::task::spawn(txpool);
|
||||
tokio::task::spawn(eth);
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
60
bin/reth/src/util/chainspec.rs
Normal file
60
bin/reth/src/util/chainspec.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use reth_primitives::{
|
||||
utils::serde_helpers::{deserialize_number, deserialize_stringified_u64},
|
||||
Address, Bytes, Header, H256, U256,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// The genesis block specification.
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Genesis {
|
||||
/// The genesis header nonce.
|
||||
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||
pub nonce: u64,
|
||||
/// The genesis header timestamp.
|
||||
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||
pub timestamp: u64,
|
||||
/// The genesis header extra data.
|
||||
pub extra_data: Bytes,
|
||||
/// The genesis header gas limit.
|
||||
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||
pub gas_limit: u64,
|
||||
/// The genesis header difficulty.
|
||||
#[serde(deserialize_with = "deserialize_number")]
|
||||
pub difficulty: U256,
|
||||
/// The genesis header mix hash.
|
||||
pub mix_hash: H256,
|
||||
/// The genesis header coinbase address.
|
||||
pub coinbase: Address,
|
||||
/// The genesis state root.
|
||||
pub state_root: H256,
|
||||
/// The initial state of accounts in the genesis block.
|
||||
pub alloc: HashMap<Address, GenesisAccount>,
|
||||
}
|
||||
|
||||
impl From<Genesis> for Header {
|
||||
fn from(genesis: Genesis) -> Header {
|
||||
Header {
|
||||
gas_limit: genesis.gas_limit,
|
||||
difficulty: genesis.difficulty,
|
||||
nonce: genesis.nonce,
|
||||
extra_data: genesis.extra_data.0,
|
||||
state_root: genesis.state_root,
|
||||
timestamp: genesis.timestamp,
|
||||
mix_hash: genesis.mix_hash,
|
||||
beneficiary: genesis.coinbase,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An account in the state of the genesis block.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct GenesisAccount {
|
||||
/// The nonce of the account at genesis.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub nonce: Option<u64>,
|
||||
/// The balance of the account at genesis.
|
||||
pub balance: U256,
|
||||
}
|
||||
@ -3,6 +3,9 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
/// Utilities for parsing chainspecs
|
||||
pub mod chainspec;
|
||||
|
||||
pub(crate) fn find_all_files_with_postfix(path: &Path, postfix: &str) -> Vec<PathBuf> {
|
||||
WalkDir::new(path)
|
||||
.into_iter()
|
||||
|
||||
@ -509,7 +509,7 @@ pub enum PeerAction {
|
||||
/// Config type for initiating a [`PeersManager`] instance
|
||||
#[derive(Debug)]
|
||||
pub struct PeersConfig {
|
||||
/// How even to recheck free slots for outbound connections
|
||||
/// How often to recheck free slots for outbound connections
|
||||
pub refill_slots_interval: Duration,
|
||||
/// Restrictions on connections
|
||||
pub connection_info: ConnectionInfo,
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
use crate::{H256, U256};
|
||||
use reth_codecs::{main_codec, Compact};
|
||||
|
||||
/// Account saved in database
|
||||
/// An Ethereum account.
|
||||
#[main_codec]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub struct Account {
|
||||
/// Nonce.
|
||||
/// Account nonce.
|
||||
pub nonce: u64,
|
||||
/// Account balance.
|
||||
pub balance: U256,
|
||||
/// Hash of the bytecode.
|
||||
/// Hash of the account's bytecode.
|
||||
pub bytecode_hash: Option<H256>,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
/// Does account has a bytecode.
|
||||
/// Whether the account has bytecode.
|
||||
pub fn has_bytecode(&self) -> bool {
|
||||
self.bytecode_hash.is_some()
|
||||
}
|
||||
|
||||
@ -83,6 +83,11 @@ mod __reexport {
|
||||
pub use tiny_keccak;
|
||||
}
|
||||
|
||||
/// Various utilities
|
||||
pub mod utils {
|
||||
pub use ethers_core::types::serde_helpers;
|
||||
}
|
||||
|
||||
// Useful reexports
|
||||
pub use __reexport::*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user