refactor: move cli-only utils out of staged-sync (#2984)

This commit is contained in:
Bjerg
2023-06-05 15:47:08 +02:00
committed by GitHub
parent df8ca352ec
commit 9206a7dea0
18 changed files with 187 additions and 192 deletions

View File

@ -24,4 +24,6 @@ mod stage_args;
pub use stage_args::StageEnum;
mod gas_price_oracle_args;
pub mod utils;
pub use gas_price_oracle_args::GasPriceOracleArgs;

View File

@ -1,4 +1,4 @@
use crate::{utils::parse_duration_from_secs, version::default_extradata};
use crate::{args::utils::parse_duration_from_secs, version::default_extradata};
use clap::{
builder::{RangedU64ValueParser, TypedValueParser},
Arg, Args, Command,

138
bin/reth/src/args/utils.rs Normal file
View File

@ -0,0 +1,138 @@
//! Clap parser utilities
use reth_primitives::{AllGenesisFormats, BlockHashOrNumber, ChainSpec, GOERLI, MAINNET, SEPOLIA};
use reth_revm::primitives::B256 as H256;
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs},
path::PathBuf,
str::FromStr,
sync::Arc,
time::Duration,
};
/// Helper to parse a [Duration] from seconds
pub fn parse_duration_from_secs(arg: &str) -> eyre::Result<Duration, std::num::ParseIntError> {
let seconds = arg.parse()?;
Ok(Duration::from_secs(seconds))
}
/// Clap value parser for [ChainSpec]s that takes either a built-in chainspec or the path
/// to a custom one.
pub fn chain_spec_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
Ok(Arc::new(match s {
"mainnet" => MAINNET.clone(),
"goerli" => GOERLI.clone(),
"sepolia" => SEPOLIA.clone(),
_ => {
let raw = std::fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned()))?;
serde_json::from_str(&raw)?
}
}))
}
/// Clap value parser for [ChainSpec]s that takes either a built-in genesis format or the path
/// to a custom one.
pub fn genesis_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
Ok(Arc::new(match s {
"mainnet" => MAINNET.clone(),
"goerli" => GOERLI.clone(),
"sepolia" => SEPOLIA.clone(),
_ => {
let raw = std::fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned()))?;
let genesis: AllGenesisFormats = serde_json::from_str(&raw)?;
genesis.into()
}
}))
}
/// Parse [BlockHashOrNumber]
pub fn hash_or_num_value_parser(value: &str) -> eyre::Result<BlockHashOrNumber, eyre::Error> {
match H256::from_str(value) {
Ok(hash) => Ok(BlockHashOrNumber::Hash(hash)),
Err(_) => Ok(BlockHashOrNumber::Number(value.parse()?)),
}
}
/// Error thrown while parsing a socket address.
#[derive(thiserror::Error, Debug)]
pub enum SocketAddressParsingError {
/// Failed to convert the string into a socket addr
#[error("Cannot parse socket address: {0}")]
Io(#[from] std::io::Error),
/// Input must not be empty
#[error("Cannot parse socket address from empty string")]
Empty,
/// Failed to parse the address
#[error("Could not parse socket address from {0}")]
Parse(String),
/// Failed to parse port
#[error("Could not parse port: {0}")]
Port(#[from] std::num::ParseIntError),
}
/// Parse a [SocketAddr] from a `str`.
///
/// The following formats are checked:
///
/// - If the value can be parsed as a `u16` or starts with `:` it is considered a port, and the
/// hostname is set to `localhost`.
/// - If the value contains `:` it is assumed to be the format `<host>:<port>`
/// - Otherwise it is assumed to be a hostname
///
/// An error is returned if the value is empty.
pub fn parse_socket_address(value: &str) -> eyre::Result<SocketAddr, SocketAddressParsingError> {
if value.is_empty() {
return Err(SocketAddressParsingError::Empty)
}
if let Some(port) = value.strip_prefix(':').or_else(|| value.strip_prefix("localhost:")) {
let port: u16 = port.parse()?;
return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port))
}
if let Ok(port) = value.parse::<u16>() {
return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port))
}
value
.to_socket_addrs()?
.next()
.ok_or_else(|| SocketAddressParsingError::Parse(value.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::Rng;
use secp256k1::rand::thread_rng;
#[test]
fn parse_chain_spec() {
for chain in ["mainnet", "sepolia", "goerli"] {
chain_spec_value_parser(chain).unwrap();
genesis_value_parser(chain).unwrap();
}
}
#[test]
fn parse_socket_addresses() {
for value in ["localhost:9000", ":9000", "9000"] {
let socket_addr = parse_socket_address(value)
.unwrap_or_else(|_| panic!("could not parse socket address: {value}"));
assert!(socket_addr.ip().is_loopback());
assert_eq!(socket_addr.port(), 9000);
}
}
#[test]
fn parse_socket_address_random() {
let port: u16 = thread_rng().gen();
for value in [format!("localhost:{port}"), format!(":{port}"), port.to_string()] {
let socket_addr = parse_socket_address(&value)
.unwrap_or_else(|_| panic!("could not parse socket address: {value}"));
assert!(socket_addr.ip().is_loopback());
assert_eq!(socket_addr.port(), port);
}
}
}

View File

@ -8,6 +8,7 @@ use eyre::Context;
use futures::{Stream, StreamExt};
use reth_beacon_consensus::BeaconConsensus;
use crate::args::utils::genesis_value_parser;
use reth_config::Config;
use reth_db::database::Database;
use reth_downloaders::{
@ -16,10 +17,7 @@ use reth_downloaders::{
};
use reth_interfaces::consensus::Consensus;
use reth_primitives::{ChainSpec, H256};
use reth_staged_sync::utils::{
chainspec::genesis_value_parser,
init::{init_db, init_genesis},
};
use reth_staged_sync::utils::init::{init_db, init_genesis};
use reth_stages::{
prelude::*,
stages::{

View File

@ -1,10 +1,10 @@
use crate::dirs::{DataDirPath, MaybePlatformPath};
use crate::{
args::utils::genesis_value_parser,
dirs::{DataDirPath, MaybePlatformPath},
};
use clap::Parser;
use reth_primitives::ChainSpec;
use reth_staged_sync::utils::{
chainspec::genesis_value_parser,
init::{init_db, init_genesis},
};
use reth_staged_sync::utils::init::{init_db, init_genesis};
use std::sync::Arc;
use tracing::info;

View File

@ -1,5 +1,6 @@
//! Database debugging tool
use crate::{
args::utils::genesis_value_parser,
dirs::{DataDirPath, MaybePlatformPath},
utils::DbTool,
};
@ -9,7 +10,6 @@ use eyre::WrapErr;
use human_bytes::human_bytes;
use reth_db::{database::Database, tables};
use reth_primitives::ChainSpec;
use reth_staged_sync::utils::chainspec::genesis_value_parser;
use std::sync::Arc;
use tracing::error;

View File

@ -27,10 +27,9 @@ use reth_network::NetworkHandle;
use reth_network_api::NetworkInfo;
use reth_primitives::{stage::StageId, BlockHashOrNumber, BlockNumber, ChainSpec, H256};
use reth_provider::{providers::get_stage_checkpoint, ShareableDatabase, Transaction};
use reth_staged_sync::utils::{
chainspec::genesis_value_parser,
init::{init_db, init_genesis},
};
use reth_staged_sync::utils::init::{init_db, init_genesis};
use crate::args::utils::genesis_value_parser;
use reth_stages::{
sets::DefaultStages,
stages::{

View File

@ -1,5 +1,8 @@
//! Command for debugging merkle trie calculation.
use crate::dirs::{DataDirPath, MaybePlatformPath};
use crate::{
args::utils::genesis_value_parser,
dirs::{DataDirPath, MaybePlatformPath},
};
use clap::Parser;
use reth_db::{cursor::DbCursorRO, tables, transaction::DbTx};
use reth_primitives::{
@ -7,7 +10,7 @@ use reth_primitives::{
ChainSpec,
};
use reth_provider::Transaction;
use reth_staged_sync::utils::{chainspec::genesis_value_parser, init::init_db};
use reth_staged_sync::utils::init::init_db;
use reth_stages::{
stages::{
AccountHashingStage, ExecutionStage, ExecutionStageThresholds, MerkleStage,

View File

@ -1,6 +1,6 @@
//! reth data directories.
use crate::utils::parse_path;
use reth_primitives::Chain;
use reth_staged_sync::utils::parse_path;
use std::{
env::VarError,
fmt::{Debug, Display, Formatter},

View File

@ -51,11 +51,7 @@ use reth_provider::{
use reth_revm::Factory;
use reth_revm_inspectors::stack::Hook;
use reth_rpc_engine_api::EngineApi;
use reth_staged_sync::utils::{
chainspec::genesis_value_parser,
init::{init_db, init_genesis},
parse_socket_address,
};
use reth_staged_sync::utils::init::{init_db, init_genesis};
use reth_stages::{
prelude::*,
stages::{
@ -74,7 +70,13 @@ use std::{
use tokio::sync::{mpsc::unbounded_channel, oneshot, watch};
use tracing::*;
use crate::{args::PayloadBuilderArgs, dirs::MaybePlatformPath};
use crate::{
args::{
utils::{genesis_value_parser, parse_socket_address},
PayloadBuilderArgs,
},
dirs::MaybePlatformPath,
};
use reth_interfaces::p2p::headers::client::HeadersClient;
use reth_payload_builder::PayloadBuilderService;
use reth_primitives::bytes::BytesMut;

View File

@ -1,6 +1,10 @@
//! P2P Debugging tool
use crate::{
args::{get_secret_key, DiscoveryArgs},
args::{
get_secret_key,
utils::{chain_spec_value_parser, hash_or_num_value_parser},
DiscoveryArgs,
},
dirs::{DataDirPath, MaybePlatformPath},
utils::get_single_header,
};
@ -12,7 +16,6 @@ use reth_discv4::NatResolver;
use reth_interfaces::p2p::bodies::client::BodiesClient;
use reth_primitives::{BlockHashOrNumber, ChainSpec, NodeRecord};
use reth_provider::ShareableDatabase;
use reth_staged_sync::utils::{chainspec::chain_spec_value_parser, hash_or_num_value_parser};
use std::{path::PathBuf, sync::Arc};
/// `reth p2p` command

View File

@ -1,6 +1,6 @@
//! Database debugging tool
use crate::{
args::StageEnum,
args::{utils::genesis_value_parser, StageEnum},
dirs::{DataDirPath, MaybePlatformPath},
utils::DbTool,
};
@ -12,7 +12,7 @@ use reth_db::{
transaction::DbTxMut,
};
use reth_primitives::{stage::StageId, ChainSpec};
use reth_staged_sync::utils::{chainspec::genesis_value_parser, init::insert_genesis_state};
use reth_staged_sync::utils::init::insert_genesis_state;
use std::sync::Arc;
use tracing::info;

View File

@ -8,7 +8,7 @@ use reth_db::{
cursor::DbCursorRO, database::Database, table::TableImporter, tables, transaction::DbTx,
};
use reth_primitives::ChainSpec;
use reth_staged_sync::utils::{chainspec::genesis_value_parser, init::init_db};
use reth_staged_sync::utils::init::init_db;
use std::{path::PathBuf, sync::Arc};
use tracing::info;
@ -22,6 +22,7 @@ mod execution;
use execution::dump_execution_stage;
mod merkle;
use crate::args::utils::genesis_value_parser;
use merkle::dump_merkle_stage;
/// `reth dump-stage` command

View File

@ -2,7 +2,7 @@
//!
//! Stage debugging tool
use crate::{
args::{get_secret_key, NetworkArgs, StageEnum},
args::{get_secret_key, utils::chain_spec_value_parser, NetworkArgs, StageEnum},
dirs::{DataDirPath, MaybePlatformPath},
prometheus_exporter,
version::SHORT_VERSION,
@ -16,7 +16,7 @@ use reth_primitives::{
ChainSpec,
};
use reth_provider::{ShareableDatabase, Transaction};
use reth_staged_sync::utils::{chainspec::chain_spec_value_parser, init::init_db};
use reth_staged_sync::utils::init::init_db;
use reth_stages::{
stages::{
BodyStage, ExecutionStage, ExecutionStageThresholds, IndexAccountHistoryStage,

View File

@ -10,9 +10,9 @@ use reth_db::{
};
use reth_primitives::{BlockHashOrNumber, ChainSpec};
use reth_provider::Transaction;
use reth_staged_sync::utils::chainspec::genesis_value_parser;
use std::{ops::RangeInclusive, sync::Arc};
use crate::args::utils::genesis_value_parser;
use reth_db::cursor::DbCursorRO;
/// `reth stage unwind` command

View File

@ -12,14 +12,17 @@ use reth_interfaces::p2p::{
priority::Priority,
};
use reth_primitives::{BlockHashOrNumber, HeadersDirection, SealedHeader};
use std::{path::Path, time::Duration};
use std::{
env::VarError,
path::{Path, PathBuf},
};
use tracing::info;
/// Get a single header from network
pub async fn get_single_header<Client>(
client: Client,
id: BlockHashOrNumber,
) -> eyre::Result<SealedHeader>
) -> Result<SealedHeader>
where
Client: HeadersClient,
{
@ -104,8 +107,8 @@ impl<'a, DB: Database> DbTool<'a, DB> {
}
}
/// Helper to parse a [Duration] from seconds
pub fn parse_duration_from_secs(arg: &str) -> Result<Duration, std::num::ParseIntError> {
let seconds = arg.parse()?;
Ok(Duration::from_secs(seconds))
/// Parses a user-specified path with support for environment variables and common shorthands (e.g.
/// ~ for the user's home directory).
pub fn parse_path(value: &str) -> Result<PathBuf, shellexpand::LookupError<VarError>> {
shellexpand::full(value).map(|path| PathBuf::from(path.into_owned()))
}