From c9eeb181a598a28c9219821185f4dedb604beb4c Mon Sep 17 00:00:00 2001 From: Christoph Kieslich Date: Wed, 12 Apr 2023 06:00:49 +0200 Subject: [PATCH] feat: append chain network to db directory (#1846) --- bin/reth/src/chain/import.rs | 21 ++++++--- bin/reth/src/chain/init.rs | 7 ++- bin/reth/src/db/mod.rs | 28 +++++++++++- bin/reth/src/dirs.rs | 80 ++++++++++++++++++++++++++++++++++ bin/reth/src/drop_stage.rs | 7 ++- bin/reth/src/dump_stage/mod.rs | 29 ++++++++++-- bin/reth/src/node/mod.rs | 24 ++++++---- bin/reth/src/stage/mod.rs | 5 ++- 8 files changed, 175 insertions(+), 26 deletions(-) diff --git a/bin/reth/src/chain/import.rs b/bin/reth/src/chain/import.rs index 8675d7c1a..6a9b6cbf6 100644 --- a/bin/reth/src/chain/import.rs +++ b/bin/reth/src/chain/import.rs @@ -14,7 +14,7 @@ use reth_downloaders::{ use reth_interfaces::{ consensus::Consensus, p2p::headers::client::NoopStatusUpdater, sync::SyncStateUpdater, }; -use reth_primitives::{ChainSpec, H256}; +use reth_primitives::{Chain, ChainSpec, H256}; use reth_staged_sync::{ utils::{ chainspec::genesis_value_parser, @@ -77,11 +77,14 @@ impl ImportCommand { pub async fn execute(self) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", crate_version!()); - let config: Config = self.load_config()?; - info!(target: "reth::cli", path = %self.db, "Configuration loaded"); + let config: Config = self.load_config_with_chain(self.chain.chain)?; + info!(target: "reth::cli", path = %self.config.with_chain(self.chain.chain), "Configuration loaded"); - info!(target: "reth::cli", path = %self.db, "Opening database"); - let db = Arc::new(init_db(&self.db)?); + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); + + info!(target: "reth::cli", path = ?db_path, "Opening database"); + let db = Arc::new(init_db(db_path)?); info!(target: "reth::cli", "Database opened"); debug!(target: "reth::cli", chain=%self.chain.chain, genesis=?self.chain.genesis_hash(), "Initializing genesis"); @@ -169,8 +172,12 @@ impl ImportCommand { Ok((pipeline, events)) } - fn load_config(&self) -> eyre::Result { - confy::load_path::(&self.config).wrap_err("Could not load config") + /// Loads the reth config based on the intended chain + fn load_config_with_chain(&self, chain: Chain) -> eyre::Result { + // add network name to config directory + let config_path = self.config.with_chain(chain); + confy::load_path::(config_path.clone()) + .wrap_err_with(|| format!("Could not load config file {}", config_path)) } } diff --git a/bin/reth/src/chain/init.rs b/bin/reth/src/chain/init.rs index 0d3f39563..bf5346748 100644 --- a/bin/reth/src/chain/init.rs +++ b/bin/reth/src/chain/init.rs @@ -44,8 +44,11 @@ impl InitCommand { pub async fn execute(&self) -> eyre::Result<()> { info!(target: "reth::cli", "reth init starting"); - info!(target: "reth::cli", path = %self.db, "Opening database"); - let db = Arc::new(init_db(&self.db)?); + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); + + info!(target: "reth::cli", path = %db_path, "Opening database"); + let db = Arc::new(init_db(&db_path)?); info!(target: "reth::cli", "Database opened"); info!(target: "reth::cli", "Writing genesis block"); diff --git a/bin/reth/src/db/mod.rs b/bin/reth/src/db/mod.rs index 00c232931..845be6bc2 100644 --- a/bin/reth/src/db/mod.rs +++ b/bin/reth/src/db/mod.rs @@ -1,4 +1,6 @@ //! Database debugging tool +use std::sync::Arc; + use crate::{ dirs::{DbPath, PlatformPath}, utils::DbTool, @@ -8,6 +10,8 @@ use comfy_table::{Cell, Row, Table as ComfyTable}; 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 tracing::error; /// DB List TUI @@ -26,6 +30,23 @@ pub struct Command { #[arg(global = true, long, value_name = "PATH", verbatim_doc_comment, default_value_t)] db: PlatformPath, + /// The chain this node is running. + /// + /// Possible values are either a built-in chain or the path to a chain specification file. + /// + /// Built-in chains: + /// - mainnet + /// - goerli + /// - sepolia + #[arg( + long, + value_name = "CHAIN_OR_PATH", + verbatim_doc_comment, + default_value = "mainnet", + value_parser = genesis_value_parser + )] + chain: Arc, + #[clap(subcommand)] command: Subcommands, } @@ -65,11 +86,14 @@ pub struct ListArgs { impl Command { /// Execute `db` command pub async fn execute(&self) -> eyre::Result<()> { - std::fs::create_dir_all(&self.db)?; + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); + + std::fs::create_dir_all(&db_path)?; // TODO: Auto-impl for Database trait let db = reth_db::mdbx::Env::::open( - self.db.as_ref(), + db_path.as_ref(), reth_db::mdbx::EnvKind::RW, )?; diff --git a/bin/reth/src/dirs.rs b/bin/reth/src/dirs.rs index c71213bcf..a11bbdb6f 100644 --- a/bin/reth/src/dirs.rs +++ b/bin/reth/src/dirs.rs @@ -1,4 +1,5 @@ //! reth data directories. +use reth_primitives::Chain; use reth_staged_sync::utils::parse_path; use std::{ env::VarError, @@ -7,6 +8,19 @@ use std::{ str::FromStr, }; +/// Constructs a string to be used as a path for configuration and db paths. +pub fn build_config_path_prefix(chain: Chain) -> String { + if chain == Chain::mainnet() { + "mainnet".to_string() + } else if chain == Chain::goerli() { + "goerli".to_string() + } else if chain == Chain::sepolia() { + "sepolia".to_string() + } else { + chain.id().to_string() + } +} + /// Returns the path to the reth data directory. /// /// Refer to [dirs_next::data_dir] for cross-platform behavior. @@ -204,3 +218,69 @@ impl From> for PathBuf { value.0 } } + +impl PlatformPath { + /// Returns the path joined with another path + pub fn join>(&self, path: P) -> PathBuf { + self.0.join(path) + } +} + +impl PlatformPath { + /// Converts the path to a `ChainPath` with the given `Chain`. + /// + /// If the inner path type refers to a file, the chain will be inserted between the parent + /// directory and the file name. If the inner path type refers to a directory, the chain will be + /// inserted between the parent directory and the directory name. + pub fn with_chain(&self, chain: Chain) -> ChainPath { + // extract the parent and final component + let parent = self.0.parent().expect("Could not get parent of path"); + let final_component = self.0.file_name().expect("Could not get file name of path"); + + // put the chain part in the middle + let chain_name = build_config_path_prefix(chain); + let mut path = PathBuf::from(parent); + path.push(chain_name); + path.push(final_component); + + let platform_path = PlatformPath::(path, std::marker::PhantomData); + ChainPath::new(platform_path, chain) + } +} + +/// Wrapper type around PlatformPath that includes a `Chain`, used for separating reth data for +/// different networks. +/// +/// If the chain is either mainnet, goerli, or sepolia, then the path will be: +/// * mainnet: `/mainnet` +/// * goerli: `/goerli` +/// * sepolia: `/sepolia` +/// Otherwise, the path will be dependent on the chain ID: +/// * `/` +#[derive(Clone, Debug, PartialEq)] +pub struct ChainPath(PlatformPath, Chain); + +impl ChainPath { + /// Returns a new `ChainPath` given a `PlatformPath` and a `Chain`. + pub fn new(path: PlatformPath, chain: Chain) -> Self { + Self(path, chain) + } +} + +impl AsRef for ChainPath { + fn as_ref(&self) -> &Path { + self.0.as_ref() + } +} + +impl Display for ChainPath { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From> for PathBuf { + fn from(value: ChainPath) -> Self { + value.0.into() + } +} diff --git a/bin/reth/src/drop_stage.rs b/bin/reth/src/drop_stage.rs index 80ec68110..a6ac04059 100644 --- a/bin/reth/src/drop_stage.rs +++ b/bin/reth/src/drop_stage.rs @@ -53,9 +53,12 @@ pub struct Command { impl Command { /// Execute `db` command pub async fn execute(&self) -> eyre::Result<()> { - std::fs::create_dir_all(&self.db)?; + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); - let db = Env::::open(self.db.as_ref(), reth_db::mdbx::EnvKind::RW)?; + std::fs::create_dir_all(&db_path)?; + + let db = Env::::open(db_path.as_ref(), reth_db::mdbx::EnvKind::RW)?; let tool = DbTool::new(&db)?; diff --git a/bin/reth/src/dump_stage/mod.rs b/bin/reth/src/dump_stage/mod.rs index 9c9829610..338f7dfc4 100644 --- a/bin/reth/src/dump_stage/mod.rs +++ b/bin/reth/src/dump_stage/mod.rs @@ -1,5 +1,7 @@ //! Database debugging tool mod hashing_storage; +use std::sync::Arc; + use hashing_storage::dump_hashing_storage_stage; mod hashing_account; @@ -10,6 +12,7 @@ use execution::dump_execution_stage; mod merkle; use merkle::dump_merkle_stage; +use reth_primitives::ChainSpec; use crate::{ dirs::{DbPath, PlatformPath}, @@ -19,7 +22,7 @@ use clap::Parser; use reth_db::{ cursor::DbCursorRO, database::Database, table::TableImporter, tables, transaction::DbTx, }; -use reth_staged_sync::utils::init::init_db; +use reth_staged_sync::utils::{chainspec::genesis_value_parser, init::init_db}; use tracing::info; /// `reth dump-stage` command @@ -35,6 +38,23 @@ pub struct Command { #[arg(long, value_name = "PATH", verbatim_doc_comment, default_value_t)] db: PlatformPath, + /// The chain this node is running. + /// + /// Possible values are either a built-in chain or the path to a chain specification file. + /// + /// Built-in chains: + /// - mainnet + /// - goerli + /// - sepolia + #[arg( + long, + value_name = "CHAIN_OR_PATH", + verbatim_doc_comment, + default_value = "mainnet", + value_parser = genesis_value_parser + )] + chain: Arc, + #[clap(subcommand)] command: Stages, } @@ -79,11 +99,14 @@ pub struct StageCommand { impl Command { /// Execute `dump-stage` command pub async fn execute(&self) -> eyre::Result<()> { - std::fs::create_dir_all(&self.db)?; + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); + + std::fs::create_dir_all(&db_path)?; // TODO: Auto-impl for Database trait let db = reth_db::mdbx::Env::::open( - self.db.as_ref(), + db_path.as_ref(), reth_db::mdbx::EnvKind::RW, )?; diff --git a/bin/reth/src/node/mod.rs b/bin/reth/src/node/mod.rs index 25fd4cd78..deb3d0c4b 100644 --- a/bin/reth/src/node/mod.rs +++ b/bin/reth/src/node/mod.rs @@ -39,7 +39,7 @@ use reth_interfaces::{ use reth_miner::TestPayloadStore; use reth_network::{error::NetworkError, NetworkConfig, NetworkHandle, NetworkManager}; use reth_network_api::NetworkInfo; -use reth_primitives::{BlockHashOrNumber, ChainSpec, Head, Header, SealedHeader, H256}; +use reth_primitives::{BlockHashOrNumber, Chain, ChainSpec, Head, Header, SealedHeader, H256}; use reth_provider::{BlockProvider, HeaderProvider, ShareableDatabase}; use reth_revm::Factory; use reth_revm_inspectors::stack::Hook; @@ -144,11 +144,14 @@ impl Command { // Does not do anything on windows. raise_fd_limit(); - let mut config: Config = self.load_config()?; - info!(target: "reth::cli", path = %self.config, "Configuration loaded"); + let mut config: Config = self.load_config_with_chain(self.chain.chain)?; + info!(target: "reth::cli", path = %self.config.with_chain(self.chain.chain), "Configuration loaded"); - info!(target: "reth::cli", path = %self.db, "Opening database"); - let db = Arc::new(init_db(&self.db)?); + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); + + info!(target: "reth::cli", path = %db_path, "Opening database"); + let db = Arc::new(init_db(&db_path)?); let shareable_db = ShareableDatabase::new(Arc::clone(&db), Arc::clone(&self.chain)); info!(target: "reth::cli", "Database opened"); @@ -174,6 +177,7 @@ impl Command { info!(target: "reth::cli", "Test transaction pool initialized"); info!(target: "reth::cli", "Connecting to P2P network"); + // let secret_key_path = self.p2p_secret_key.join(chain_prefix); let secret_key = get_secret_key(&self.p2p_secret_key)?; let network_config = self.load_network_config( &config, @@ -401,10 +405,12 @@ impl Command { Ok(pipeline) } - fn load_config(&self) -> eyre::Result { - confy::load_path::(&self.config).wrap_err_with(|| { - format!("Could not load config file {}", self.config.as_ref().display()) - }) + /// Loads the reth config based on the intended chain + fn load_config_with_chain(&self, chain: Chain) -> eyre::Result { + // add network name to config directory + let config_path = self.config.with_chain(chain); + confy::load_path::(config_path.clone()) + .wrap_err_with(|| format!("Could not load config file {}", config_path)) } fn init_trusted_nodes(&self, config: &mut Config) { diff --git a/bin/reth/src/stage/mod.rs b/bin/reth/src/stage/mod.rs index 0b06437f5..0b7cf1609 100644 --- a/bin/reth/src/stage/mod.rs +++ b/bin/reth/src/stage/mod.rs @@ -109,7 +109,10 @@ impl Command { let unwind = UnwindInput { stage_progress: self.to, unwind_to: self.from, bad_block: None }; - let db = Arc::new(init_db(&self.db)?); + // add network name to db directory + let db_path = self.db.with_chain(self.chain.chain); + + let db = Arc::new(init_db(db_path)?); let mut tx = Transaction::new(db.as_ref())?; if let Some(listen_addr) = self.metrics {