diff --git a/bin/reth/src/args/network_args.rs b/bin/reth/src/args/network_args.rs index d4a9d868b..342bd4cc6 100644 --- a/bin/reth/src/args/network_args.rs +++ b/bin/reth/src/args/network_args.rs @@ -1,10 +1,9 @@ //! clap [Args](clap::Args) for network related arguments. -use crate::dirs::{KnownPeersPath, MaybePlatformPath}; use clap::Args; use reth_net_nat::NatResolver; use reth_network::NetworkConfigBuilder; -use reth_primitives::{mainnet_nodes, Chain, ChainSpec, NodeRecord}; +use reth_primitives::{mainnet_nodes, ChainSpec, NodeRecord}; use reth_staged_sync::Config; use secp256k1::SecretKey; use std::{path::PathBuf, sync::Arc}; @@ -32,14 +31,13 @@ pub struct NetworkArgs { #[arg(long, value_delimiter = ',')] pub bootnodes: Option>, - /// The path to the known peers file. Connected peers are - /// dumped to this file on node shutdown, and read on startup. - /// Cannot be used with --no-persist-peers - #[arg(long, value_name = "FILE", verbatim_doc_comment, default_value_t)] - pub peers_file: MaybePlatformPath, + /// The path to the known peers file. Connected peers are dumped to this file on nodes + /// shutdown, and read on startup. Cannot be used with `--no-persist-peers`. + #[arg(long, value_name = "FILE", verbatim_doc_comment, conflicts_with = "no_persist_peers")] + pub peers_file: Option, - /// Do not persist peers. Cannot be used with --peers-file - #[arg(long, verbatim_doc_comment, conflicts_with = "peers_file")] + /// Do not persist peers. + #[arg(long, verbatim_doc_comment)] pub no_persist_peers: bool, /// NAT resolution method. @@ -54,16 +52,22 @@ pub struct NetworkArgs { impl NetworkArgs { /// Build a [`NetworkConfigBuilder`] from a [`Config`] and a [`ChainSpec`], in addition to the /// values in this option struct. + /// + /// The `default_peers_file` will be used as the default location to store the persistent peers + /// file if `no_persist_peers` is false, and there is no provided `peers_file`. pub fn network_config( &self, config: &Config, chain_spec: Arc, secret_key: SecretKey, + default_peers_file: PathBuf, ) -> NetworkConfigBuilder { let chain_bootnodes = chain_spec.chain.bootnodes().unwrap_or_else(mainnet_nodes); + let peers_file = self.peers_file.clone().unwrap_or(default_peers_file); + let network_config_builder = config - .network_config(self.nat, self.persistent_peers_file(chain_spec.chain), secret_key) + .network_config(self.nat, self.persistent_peers_file(peers_file), secret_key) .boot_nodes(self.bootnodes.clone().unwrap_or(chain_bootnodes)) .chain_spec(chain_spec); @@ -74,16 +78,13 @@ impl NetworkArgs { // === impl NetworkArgs === impl NetworkArgs { - /// If `no_persist_peers` is true then this returns the path to the persistent peers file - /// - /// Uses the input chain to determine a chain-specific path to the known peers file. - pub fn persistent_peers_file(&self, chain: Chain) -> Option { + /// If `no_persist_peers` is true then this returns the path to the persistent peers file path. + pub fn persistent_peers_file(&self, peers_file: PathBuf) -> Option { if self.no_persist_peers { return None } - let peers_file = self.peers_file.clone().unwrap_or_chain_default(chain); - Some(peers_file.into()) + Some(peers_file) } } diff --git a/bin/reth/src/args/rpc_server_args.rs b/bin/reth/src/args/rpc_server_args.rs index 98c18e192..98e131e9d 100644 --- a/bin/reth/src/args/rpc_server_args.rs +++ b/bin/reth/src/args/rpc_server_args.rs @@ -1,6 +1,5 @@ //! clap [Args](clap::Args) for RPC related arguments. -use crate::dirs::{JwtSecretPath, PlatformPath}; use clap::Args; use futures::FutureExt; use reth_network_api::{NetworkInfo, Peers}; @@ -20,7 +19,7 @@ use reth_tasks::TaskSpawner; use reth_transaction_pool::TransactionPool; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, - path::Path, + path::{Path, PathBuf}, }; use tracing::info; @@ -86,7 +85,7 @@ pub struct RpcServerArgs { /// Path to a JWT secret to use for authenticated RPC endpoints #[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false)] - auth_jwtsecret: Option>, + auth_jwtsecret: Option, } impl RpcServerArgs { @@ -100,18 +99,19 @@ impl RpcServerArgs { /// If such a parameter is not given, the client SHOULD generate such a token, valid for the /// duration of the execution, and SHOULD store the hex-encoded secret as a jwt.hex file on /// the filesystem. This file can then be used to provision the counterpart client. - pub(crate) fn jwt_secret(&self) -> Result { + /// + /// The `default_jwt_path` provided as an argument will be used as the default location for the + /// jwt secret in case the `auth_jwtsecret` argument is not provided. + pub(crate) fn jwt_secret(&self, default_jwt_path: PathBuf) -> Result { let arg = self.auth_jwtsecret.as_ref(); let path: Option<&Path> = arg.map(|p| p.as_ref()); match path { Some(fpath) => JwtSecret::from_file(fpath), None => { - let default_path = PlatformPath::::default(); - let fpath = default_path.as_ref(); - if fpath.exists() { - JwtSecret::from_file(fpath) + if default_jwt_path.exists() { + JwtSecret::from_file(&default_jwt_path) } else { - JwtSecret::try_create(fpath) + JwtSecret::try_create(&default_jwt_path) } } } @@ -122,6 +122,7 @@ impl RpcServerArgs { /// Returns the handles for the launched regular RPC server(s) (if any) and the server handle /// for the auth server that handles the `engine_` API that's accessed by the consensus /// layer. + #[allow(clippy::too_many_arguments)] pub async fn start_servers( &self, client: Client, @@ -130,6 +131,7 @@ impl RpcServerArgs { executor: Tasks, events: Events, engine_api: Engine, + jwt_secret: JwtSecret, ) -> Result<(RpcServerHandle, AuthServerHandle), RpcError> where Client: BlockProvider @@ -145,7 +147,7 @@ impl RpcServerArgs { Events: CanonStateSubscriptions + Clone + 'static, Engine: EngineApiServer, { - let auth_config = self.auth_server_config()?; + let auth_config = self.auth_server_config(jwt_secret)?; let (rpc_modules, auth_module) = RpcModuleBuilder::default() .with_client(client) @@ -213,6 +215,7 @@ impl RpcServerArgs { network: Network, executor: Tasks, engine_api: EngineApi, + jwt_secret: JwtSecret, ) -> Result where Client: BlockProvider @@ -230,7 +233,7 @@ impl RpcServerArgs { self.auth_addr.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), self.auth_port.unwrap_or(constants::DEFAULT_AUTH_PORT), ); - let secret = self.jwt_secret().map_err(|err| RpcError::Custom(err.to_string()))?; + reth_rpc_builder::auth::launch( client, pool, @@ -238,7 +241,7 @@ impl RpcServerArgs { executor, engine_api, socket_address, - secret, + jwt_secret, ) .await } @@ -294,14 +297,13 @@ impl RpcServerArgs { } /// Creates the [AuthServerConfig] from cli args. - fn auth_server_config(&self) -> Result { - let secret = self.jwt_secret().map_err(|err| RpcError::Custom(err.to_string()))?; + fn auth_server_config(&self, jwt_secret: JwtSecret) -> Result { let address = SocketAddr::new( self.auth_addr.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), self.auth_port.unwrap_or(constants::DEFAULT_AUTH_PORT), ); - Ok(AuthServerConfig::builder(secret).socket_addr(address).build()) + Ok(AuthServerConfig::builder(jwt_secret).socket_addr(address).build()) } } diff --git a/bin/reth/src/args/secret_key.rs b/bin/reth/src/args/secret_key.rs index a2648ab65..c449a0087 100644 --- a/bin/reth/src/args/secret_key.rs +++ b/bin/reth/src/args/secret_key.rs @@ -1,4 +1,3 @@ -use crate::dirs::{PlatformPath, SecretKeyPath}; use hex::encode as hex_encode; use reth_network::config::rng_secret_key; use secp256k1::{Error as SecretKeyBaseError, SecretKey}; @@ -15,31 +14,26 @@ pub enum SecretKeyError { IOError(#[from] std::io::Error), } -/// Attempts to load a [`SecretKey`] from a specified path. If no file exists -/// there, then it generates a secret key and stores it in the default path. I/O -/// errors might occur during write operations in the form of a -/// [`SecretKeyError`] -pub fn get_secret_key(secret_key_path: impl AsRef) -> Result { - let fpath = secret_key_path.as_ref(); - let exists = fpath.try_exists(); +/// Attempts to load a [`SecretKey`] from a specified path. If no file exists there, then it +/// generates a secret key and stores it in the provided path. I/O errors might occur during write +/// operations in the form of a [`SecretKeyError`] +pub fn get_secret_key(secret_key_path: &Path) -> Result { + let exists = secret_key_path.try_exists(); match exists { Ok(true) => { - let contents = read_to_string(fpath)?; + let contents = read_to_string(secret_key_path)?; (contents.as_str().parse::()).map_err(SecretKeyError::SecretKeyDecodeError) } Ok(false) => { - let default_path = PlatformPath::::default(); - let fpath = default_path.as_ref(); - - if let Some(dir) = fpath.parent() { + if let Some(dir) = secret_key_path.parent() { // Create parent directory std::fs::create_dir_all(dir)? } let secret = rng_secret_key(); let hex = hex_encode(secret.as_ref()); - std::fs::write(fpath, hex)?; + std::fs::write(secret_key_path, hex)?; Ok(secret) } Err(e) => Err(SecretKeyError::IOError(e)), diff --git a/bin/reth/src/chain/import.rs b/bin/reth/src/chain/import.rs index 742893bcf..e6cac01c5 100644 --- a/bin/reth/src/chain/import.rs +++ b/bin/reth/src/chain/import.rs @@ -1,5 +1,5 @@ use crate::{ - dirs::{ConfigPath, DbPath, MaybePlatformPath, PlatformPath}, + dirs::{DataDirPath, MaybePlatformPath}, node::events::{handle_events, NodeEvent}, }; use clap::{crate_version, Parser}; @@ -14,7 +14,7 @@ use reth_downloaders::{ use reth_interfaces::{ consensus::Consensus, p2p::headers::client::NoopStatusUpdater, sync::SyncStateUpdater, }; -use reth_primitives::{Chain, ChainSpec, H256}; +use reth_primitives::{ChainSpec, H256}; use reth_staged_sync::{ utils::{ chainspec::genesis_value_parser, @@ -26,7 +26,7 @@ use reth_stages::{ prelude::*, stages::{ExecutionStage, HeaderSyncMode, SenderRecoveryStage, TotalDifficultyStage}, }; -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use tokio::sync::watch; use tracing::{debug, info}; @@ -34,18 +34,18 @@ use tracing::{debug, info}; #[derive(Debug, Parser)] pub struct ImportCommand { /// The path to the configuration file to use. - #[arg(long, value_name = "FILE", verbatim_doc_comment, default_value_t)] - config: MaybePlatformPath, + #[arg(long, value_name = "FILE", verbatim_doc_comment)] + config: Option, - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, /// The chain this node is running. /// @@ -69,7 +69,7 @@ pub struct ImportCommand { /// The online stages (headers and bodies) are replaced by a file import, after which the /// remaining stages are executed. #[arg(value_name = "IMPORT_PATH", verbatim_doc_comment)] - path: PlatformPath, + path: PathBuf, } impl ImportCommand { @@ -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_with_chain(self.chain.chain)?; - info!(target: "reth::cli", path = %self.config.unwrap_or_chain_default(self.chain.chain), "Configuration loaded"); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + let config_path = self.config.clone().unwrap_or(data_dir.config_path()); - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + let config: Config = self.load_config(config_path.clone())?; + info!(target: "reth::cli", path = ?config_path, "Configuration loaded"); + + let db_path = data_dir.db_path(); info!(target: "reth::cli", path = ?db_path, "Opening database"); let db = Arc::new(init_db(db_path)?); @@ -177,12 +180,10 @@ impl ImportCommand { Ok((pipeline, events)) } - /// 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.unwrap_or_chain_default(chain); + /// Loads the reth config + fn load_config(&self, config_path: PathBuf) -> eyre::Result { confy::load_path::(config_path.clone()) - .wrap_err_with(|| format!("Could not load config file {}", config_path)) + .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 ab349344b..046da04d6 100644 --- a/bin/reth/src/chain/init.rs +++ b/bin/reth/src/chain/init.rs @@ -1,25 +1,30 @@ -use crate::dirs::{DbPath, MaybePlatformPath}; +use crate::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 std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use tracing::info; /// Initializes the database with the genesis block. #[derive(Debug, Parser)] pub struct InitCommand { - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + + /// The path to the database folder. If not specified, it will be set in the data dir for the + /// chain being used. + #[arg(long, value_name = "PATH", verbatim_doc_comment)] + db: Option, /// The chain this node is running. /// @@ -44,10 +49,13 @@ impl InitCommand { pub async fn execute(self) -> eyre::Result<()> { info!(target: "reth::cli", "reth init starting"); - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); - info!(target: "reth::cli", path = %db_path, "Opening database"); + // use the overridden db path if specified + let db_path = self.db.clone().unwrap_or(data_dir.db_path()); + + info!(target: "reth::cli", path = ?db_path, "Opening database"); let db = Arc::new(init_db(&db_path)?); info!(target: "reth::cli", "Database opened"); diff --git a/bin/reth/src/config.rs b/bin/reth/src/config.rs index 766186eab..ef8527baf 100644 --- a/bin/reth/src/config.rs +++ b/bin/reth/src/config.rs @@ -1,16 +1,16 @@ //! CLI command to show configs +use std::path::PathBuf; + use clap::Parser; use eyre::{bail, WrapErr}; use reth_staged_sync::Config; -use crate::dirs::{ConfigPath, PlatformPath}; - /// `reth config` command #[derive(Debug, Parser)] pub struct Command { /// The path to the configuration file to use. #[arg(long, value_name = "FILE", verbatim_doc_comment)] - config: Option>, + config: Option, /// Show the default config #[arg(long, verbatim_doc_comment, conflicts_with = "config")] @@ -25,12 +25,11 @@ impl Command { } else { let path = self.config.clone().unwrap_or_default(); // confy will create the file if it doesn't exist; we don't want this - if !path.as_ref().exists() { - bail!("Config file does not exist: {}", path.as_ref().display()); + if !path.exists() { + bail!("Config file does not exist: {}", path.display()); } - confy::load_path::(path.as_ref()).wrap_err_with(|| { - format!("Could not load config file: {}", path.as_ref().display()) - })? + confy::load_path::(&path) + .wrap_err_with(|| format!("Could not load config file: {}", path.display()))? }; println!("{}", toml::to_string_pretty(&config)?); Ok(()) diff --git a/bin/reth/src/db/mod.rs b/bin/reth/src/db/mod.rs index 3a2dfa41d..b6de7c778 100644 --- a/bin/reth/src/db/mod.rs +++ b/bin/reth/src/db/mod.rs @@ -1,6 +1,6 @@ //! Database debugging tool use crate::{ - dirs::{DbPath, MaybePlatformPath}, + dirs::{DataDirPath, MaybePlatformPath}, utils::DbTool, }; use clap::{Parser, Subcommand}; @@ -10,7 +10,7 @@ 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 std::{path::PathBuf, sync::Arc}; use tracing::error; /// DB List TUI @@ -19,15 +19,20 @@ mod tui; /// `reth db` command #[derive(Debug, Parser)] pub struct Command { - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(global = true, long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + + /// The path to the database folder. If not specified, it will be set in the data dir for the + /// chain being used. + #[arg(long, value_name = "PATH", verbatim_doc_comment)] + db: Option, /// The chain this node is running. /// @@ -85,8 +90,11 @@ pub struct ListArgs { impl Command { /// Execute `db` command pub async fn execute(self) -> eyre::Result<()> { - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + + // use the overridden db path if specified + let db_path = self.db.clone().unwrap_or(data_dir.db_path()); std::fs::create_dir_all(&db_path)?; @@ -211,7 +219,7 @@ impl Command { ]); } Subcommands::Drop => { - tool.drop(self.db.unwrap_or_chain_default(self.chain.chain))?; + tool.drop(db_path)?; } } diff --git a/bin/reth/src/dirs.rs b/bin/reth/src/dirs.rs index e36bc74ed..3e5c50b24 100644 --- a/bin/reth/src/dirs.rs +++ b/bin/reth/src/dirs.rs @@ -56,76 +56,17 @@ pub fn logs_dir() -> Option { cache_dir().map(|root| root.join("logs")) } -/// Returns the path to the reth jwtsecret directory. +/// Returns the path to the reth data dir. /// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -pub fn jwt_secret_dir() -> Option { - data_dir().map(|root| root.join("jwtsecret")) -} - -/// Returns the path to the reth net directory. -/// -/// Refer to [dirs_next::data_dir] -pub fn net_dir() -> Option { - data_dir().map(|root| root.join("net")) -} - -/// Returns the path to the reth secret key directory. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -pub fn p2p_secret_key_dir() -> Option { - data_dir().map(|root| root.join("p2p")) -} - -/// Returns the path to the reth database. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. +/// The data dir should contain a subdirectory for each chain, and those chain directories will +/// include all information for that chain, such as the p2p secret. #[derive(Default, Debug, Clone)] #[non_exhaustive] -pub struct DbPath; +pub struct DataDirPath; -impl XdgPath for DbPath { +impl XdgPath for DataDirPath { fn resolve() -> Option { - database_path() - } -} - -/// Returns the path to the default JWT secret hex file. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -#[derive(Default, Debug, Clone, PartialEq)] -#[non_exhaustive] -pub struct JwtSecretPath; - -impl XdgPath for JwtSecretPath { - fn resolve() -> Option { - jwt_secret_dir().map(|p| p.join("jwt.hex")) - } -} - -/// Returns the path to the default reth configuration file. -/// -/// Refer to [dirs_next::config_dir] for cross-platform behavior. -#[derive(Default, Debug, Clone)] -#[non_exhaustive] -pub struct ConfigPath; - -impl XdgPath for ConfigPath { - fn resolve() -> Option { - config_dir().map(|p| p.join("reth.toml")) - } -} - -/// Returns the path to the default reth known peers file. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -#[derive(Default, Debug, Clone)] -#[non_exhaustive] -pub struct KnownPeersPath; - -impl XdgPath for KnownPeersPath { - fn resolve() -> Option { - net_dir().map(|p| p.join("known-peers.json")) + data_dir() } } @@ -142,19 +83,6 @@ impl XdgPath for LogsDir { } } -/// Returns the path to the default reth secret key directory. -/// -/// Refer to [dirs_next::data_dir] for cross-platform behavior. -#[derive(Default, Debug, Clone)] -#[non_exhaustive] -pub struct SecretKeyPath; - -impl XdgPath for SecretKeyPath { - fn resolve() -> Option { - p2p_secret_key_dir().map(|p| p.join("secret")) - } -} - /// A small helper trait for unit structs that represent a standard path following the XDG /// path specification. pub trait XdgPath { @@ -171,13 +99,13 @@ pub trait XdgPath { /// # Example /// /// ``` -/// use reth::dirs::{PlatformPath, DbPath}; +/// use reth::dirs::{PlatformPath, DataDirPath}; /// use std::str::FromStr; /// /// // Resolves to the platform-specific database path -/// let default: PlatformPath = PlatformPath::default(); -/// // Resolves to `$(pwd)/my/path/to/db` -/// let custom: PlatformPath = PlatformPath::from_str("my/path/to/db").unwrap(); +/// let default: PlatformPath = PlatformPath::default(); +/// // Resolves to `$(pwd)/my/path/to/datadir` +/// let custom: PlatformPath = PlatformPath::from_str("my/path/to/datadir").unwrap(); /// /// assert_ne!(default.as_ref(), custom.as_ref()); /// ``` @@ -227,25 +155,18 @@ impl From> for PathBuf { impl PlatformPath { /// Returns the path joined with another path - pub fn join>(&self, path: P) -> PathBuf { - self.0.join(path) + pub fn join>(&self, path: P) -> PlatformPath { + PlatformPath::(self.0.join(path), std::marker::PhantomData) } } 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 directory - 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 + // extract chain name let chain_name = config_path_prefix(chain); - let path = parent.join(chain_name).join(final_component); + + let path = self.0.join(chain_name); let platform_path = PlatformPath::(path, std::marker::PhantomData); ChainPath::new(platform_path, chain) @@ -254,7 +175,7 @@ impl PlatformPath { /// An Optional wrapper type around [PlatformPath]. /// -/// This is useful for when a path is optional, such as the `--db-path` flag. +/// This is useful for when a path is optional, such as the `--data-dir` flag. #[derive(Clone, Debug, PartialEq)] pub struct MaybePlatformPath(Option>); @@ -262,8 +183,17 @@ pub struct MaybePlatformPath(Option>); impl MaybePlatformPath { /// Returns the path if it is set, otherwise returns the default path for the given chain. - pub fn unwrap_or_chain_default(&self, chain: Chain) -> PlatformPath { - self.0.clone().unwrap_or_else(|| PlatformPath::default().with_chain(chain).0) + pub fn unwrap_or_chain_default(&self, chain: Chain) -> ChainPath { + ChainPath( + self.0.clone().unwrap_or_else(|| PlatformPath::default().with_chain(chain).0), + chain, + ) + } + + /// Returns the path if it is set, otherwise returns the default path, without any chain + /// directory. + pub fn unwrap_or_default(&self) -> PlatformPath { + self.0.clone().unwrap_or_default() } } @@ -318,6 +248,31 @@ impl ChainPath { pub fn new(path: PlatformPath, chain: Chain) -> Self { Self(path, chain) } + + /// Returns the path to the db directory for this chain. + pub fn db_path(&self) -> PathBuf { + self.0.join("db").into() + } + + /// Returns the path to the reth p2p secret key for this chain. + pub fn p2p_secret_path(&self) -> PathBuf { + self.0.join("discovery-secret").into() + } + + /// Returns the path to the known peers file for this chain. + pub fn known_peers_path(&self) -> PathBuf { + self.0.join("known-peers.json").into() + } + + /// Returns the path to the config file for this chain. + pub fn config_path(&self) -> PathBuf { + self.0.join("reth.toml").into() + } + + /// Returns the path to the jwtsecret file for this chain. + pub fn jwt_path(&self) -> PathBuf { + self.0.join("jwt.hex").into() + } } impl AsRef for ChainPath { @@ -343,24 +298,16 @@ mod tests { use super::*; #[test] - fn test_maybe_db_platform_path() { - let path = MaybePlatformPath::::default(); + fn test_maybe_data_dir_path() { + let path = MaybePlatformPath::::default(); let path = path.unwrap_or_chain_default(Chain::mainnet()); - assert!(path.as_ref().ends_with("reth/mainnet/db"), "{:?}", path); + assert!(path.as_ref().ends_with("reth/mainnet"), "{:?}", path); - let path = MaybePlatformPath::::from_str("my/path/to/db").unwrap(); - let path = path.unwrap_or_chain_default(Chain::mainnet()); - assert!(path.as_ref().ends_with("my/path/to/db"), "{:?}", path); - } + let db_path = path.db_path(); + assert!(db_path.ends_with("reth/mainnet/db"), "{:?}", db_path); - #[test] - fn test_maybe_config_platform_path() { - let path = MaybePlatformPath::::default(); + let path = MaybePlatformPath::::from_str("my/path/to/datadir").unwrap(); let path = path.unwrap_or_chain_default(Chain::mainnet()); - assert!(path.as_ref().ends_with("reth/mainnet/reth.toml"), "{:?}", path); - - let path = MaybePlatformPath::::from_str("my/path/to/reth.toml").unwrap(); - let path = path.unwrap_or_chain_default(Chain::mainnet()); - assert!(path.as_ref().ends_with("my/path/to/reth.toml"), "{:?}", path); + assert!(path.as_ref().ends_with("my/path/to/datadir"), "{:?}", path); } } diff --git a/bin/reth/src/drop_stage.rs b/bin/reth/src/drop_stage.rs index 8ce5d6bd0..0444661da 100644 --- a/bin/reth/src/drop_stage.rs +++ b/bin/reth/src/drop_stage.rs @@ -1,7 +1,7 @@ //! Database debugging tool use crate::{ args::StageEnum, - dirs::{DbPath, MaybePlatformPath}, + dirs::{DataDirPath, MaybePlatformPath}, utils::DbTool, }; use clap::Parser; @@ -17,21 +17,26 @@ use reth_stages::stages::{ ACCOUNT_HASHING, EXECUTION, INDEX_ACCOUNT_HISTORY, INDEX_STORAGE_HISTORY, MERKLE_EXECUTION, MERKLE_UNWIND, STORAGE_HASHING, }; -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use tracing::info; /// `reth drop-stage` command #[derive(Debug, Parser)] pub struct Command { - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(global = true, long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + + /// The path to the database folder. If not specified, it will be set in the data dir for the + /// chain being used. + #[arg(long, value_name = "PATH", verbatim_doc_comment)] + db: Option, /// The chain this node is running. /// @@ -56,8 +61,11 @@ pub struct Command { impl Command { /// Execute `db` command pub async fn execute(self) -> eyre::Result<()> { - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + + // use the overridden db path if specified + let db_path = self.db.clone().unwrap_or(data_dir.db_path()); std::fs::create_dir_all(&db_path)?; diff --git a/bin/reth/src/dump_stage/execution.rs b/bin/reth/src/dump_stage/execution.rs index 75dd8fad6..05cd5de59 100644 --- a/bin/reth/src/dump_stage/execution.rs +++ b/bin/reth/src/dump_stage/execution.rs @@ -1,8 +1,4 @@ -use crate::{ - dirs::{DbPath, PlatformPath}, - dump_stage::setup, - utils::DbTool, -}; +use crate::{dump_stage::setup, utils::DbTool}; use eyre::Result; use reth_db::{ cursor::DbCursorRO, database::Database, table::TableImporter, tables, transaction::DbTx, @@ -10,14 +6,14 @@ use reth_db::{ use reth_primitives::MAINNET; use reth_provider::Transaction; use reth_stages::{stages::ExecutionStage, Stage, StageId, UnwindInput}; -use std::{ops::DerefMut, sync::Arc}; +use std::{ops::DerefMut, path::PathBuf, sync::Arc}; use tracing::info; pub(crate) async fn dump_execution_stage( db_tool: &mut DbTool<'_, DB>, from: u64, to: u64, - output_db: &PlatformPath, + output_db: &PathBuf, should_run: bool, ) -> Result<()> { let (output_db, tip_block_number) = setup::(from, to, output_db, db_tool)?; diff --git a/bin/reth/src/dump_stage/hashing_account.rs b/bin/reth/src/dump_stage/hashing_account.rs index 1692a8021..7851500bc 100644 --- a/bin/reth/src/dump_stage/hashing_account.rs +++ b/bin/reth/src/dump_stage/hashing_account.rs @@ -1,21 +1,17 @@ -use crate::{ - dirs::{DbPath, PlatformPath}, - dump_stage::setup, - utils::DbTool, -}; +use crate::{dump_stage::setup, utils::DbTool}; use eyre::Result; use reth_db::{database::Database, table::TableImporter, tables}; use reth_primitives::BlockNumber; use reth_provider::Transaction; use reth_stages::{stages::AccountHashingStage, Stage, StageId, UnwindInput}; -use std::ops::DerefMut; +use std::{ops::DerefMut, path::PathBuf}; use tracing::info; pub(crate) async fn dump_hashing_account_stage( db_tool: &mut DbTool<'_, DB>, from: BlockNumber, to: BlockNumber, - output_db: &PlatformPath, + output_db: &PathBuf, should_run: bool, ) -> Result<()> { let (output_db, tip_block_number) = setup::(from, to, output_db, db_tool)?; diff --git a/bin/reth/src/dump_stage/hashing_storage.rs b/bin/reth/src/dump_stage/hashing_storage.rs index 2d992a8fd..d9c4ea7c8 100644 --- a/bin/reth/src/dump_stage/hashing_storage.rs +++ b/bin/reth/src/dump_stage/hashing_storage.rs @@ -1,20 +1,16 @@ -use crate::{ - dirs::{DbPath, PlatformPath}, - dump_stage::setup, - utils::DbTool, -}; +use crate::{dump_stage::setup, utils::DbTool}; use eyre::Result; use reth_db::{database::Database, table::TableImporter, tables}; use reth_provider::Transaction; use reth_stages::{stages::StorageHashingStage, Stage, StageId, UnwindInput}; -use std::ops::DerefMut; +use std::{ops::DerefMut, path::PathBuf}; use tracing::info; pub(crate) async fn dump_hashing_storage_stage( db_tool: &mut DbTool<'_, DB>, from: u64, to: u64, - output_db: &PlatformPath, + output_db: &PathBuf, should_run: bool, ) -> Result<()> { let (output_db, tip_block_number) = setup::(from, to, output_db, db_tool)?; diff --git a/bin/reth/src/dump_stage/merkle.rs b/bin/reth/src/dump_stage/merkle.rs index 5208be41c..bc85223ad 100644 --- a/bin/reth/src/dump_stage/merkle.rs +++ b/bin/reth/src/dump_stage/merkle.rs @@ -1,8 +1,4 @@ -use crate::{ - dirs::{DbPath, PlatformPath}, - dump_stage::setup, - utils::DbTool, -}; +use crate::{dump_stage::setup, utils::DbTool}; use eyre::Result; use reth_db::{database::Database, table::TableImporter, tables}; use reth_primitives::{BlockNumber, MAINNET}; @@ -11,14 +7,14 @@ use reth_stages::{ stages::{AccountHashingStage, ExecutionStage, MerkleStage, StorageHashingStage}, Stage, StageId, UnwindInput, }; -use std::{ops::DerefMut, sync::Arc}; +use std::{ops::DerefMut, path::PathBuf, sync::Arc}; use tracing::info; pub(crate) async fn dump_merkle_stage( db_tool: &mut DbTool<'_, DB>, from: BlockNumber, to: BlockNumber, - output_db: &PlatformPath, + output_db: &PathBuf, should_run: bool, ) -> Result<()> { let (output_db, tip_block_number) = setup::(from, to, output_db, db_tool)?; diff --git a/bin/reth/src/dump_stage/mod.rs b/bin/reth/src/dump_stage/mod.rs index 54403f7bd..aff3eb34c 100644 --- a/bin/reth/src/dump_stage/mod.rs +++ b/bin/reth/src/dump_stage/mod.rs @@ -1,6 +1,6 @@ //! Database debugging tool use crate::{ - dirs::{DbPath, MaybePlatformPath, PlatformPath}, + dirs::{DataDirPath, MaybePlatformPath}, utils::DbTool, }; use clap::Parser; @@ -9,7 +9,7 @@ use reth_db::{ }; use reth_primitives::ChainSpec; use reth_staged_sync::utils::{chainspec::genesis_value_parser, init::init_db}; -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use tracing::info; mod hashing_storage; @@ -27,15 +27,20 @@ use merkle::dump_merkle_stage; /// `reth dump-stage` command #[derive(Debug, Parser)] pub struct Command { - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + + /// The path to the database folder. If not specified, it will be set in the data dir for the + /// chain being used. + #[arg(long, value_name = "PATH", verbatim_doc_comment)] + db: Option, /// The chain this node is running. /// @@ -75,14 +80,9 @@ pub enum Stages { #[derive(Debug, Clone, Parser)] pub struct StageCommand { /// The path to the new database folder. - /// - /// Defaults to the OS-specific data directory: - /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(long, value_name = "OUTPUT_PATH", verbatim_doc_comment, default_value_t)] - output_db: PlatformPath, + #[arg(long, value_name = "OUTPUT_PATH", verbatim_doc_comment)] + output_db: PathBuf, + /// From which block. #[arg(long, short)] from: u64, @@ -98,9 +98,13 @@ pub struct StageCommand { impl Command { /// Execute `dump-stage` command pub async fn execute(self) -> eyre::Result<()> { - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + // use the overridden db path if specified + let db_path = self.db.clone().unwrap_or(data_dir.db_path()); + + info!(target: "reth::cli", path = ?db_path, "Opening database"); std::fs::create_dir_all(&db_path)?; // TODO: Auto-impl for Database trait @@ -135,12 +139,12 @@ impl Command { pub(crate) fn setup( from: u64, to: u64, - output_db: &PlatformPath, + output_db: &PathBuf, db_tool: &mut DbTool<'_, DB>, ) -> eyre::Result<(reth_db::mdbx::Env, u64)> { assert!(from < to, "FROM block should be bigger than TO block."); - info!(target: "reth::cli", "Creating separate db at {}", output_db); + info!(target: "reth::cli", ?output_db, "Creating separate db"); let output_db = init_db(output_db)?; diff --git a/bin/reth/src/merkle_debug.rs b/bin/reth/src/merkle_debug.rs index 86669c43a..6e518f50f 100644 --- a/bin/reth/src/merkle_debug.rs +++ b/bin/reth/src/merkle_debug.rs @@ -1,5 +1,5 @@ //! Command for debugging merkle trie calculation. -use crate::dirs::{DbPath, MaybePlatformPath}; +use crate::dirs::{DataDirPath, MaybePlatformPath}; use clap::Parser; use reth_db::{cursor::DbCursorRO, tables, transaction::DbTx}; use reth_primitives::ChainSpec; @@ -12,20 +12,25 @@ use reth_stages::{ }, ExecInput, Stage, }; -use std::{ops::Deref, sync::Arc}; +use std::{ops::Deref, path::PathBuf, sync::Arc}; /// `reth merkle-debug` command #[derive(Debug, Parser)] pub struct Command { - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(global = true, long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + + /// The path to the database folder. If not specified, it will be set in the data dir for the + /// chain being used. + #[arg(long, value_name = "PATH", verbatim_doc_comment)] + db: Option, /// The chain this node is running. /// @@ -56,8 +61,11 @@ pub struct Command { impl Command { /// Execute `merkle-debug` command pub async fn execute(self) -> eyre::Result<()> { - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + + // use the overridden db path if specified + let db_path = self.db.clone().unwrap_or(data_dir.db_path()); std::fs::create_dir_all(&db_path)?; diff --git a/bin/reth/src/node/mod.rs b/bin/reth/src/node/mod.rs index 2edb2ca7a..bc416e3a9 100644 --- a/bin/reth/src/node/mod.rs +++ b/bin/reth/src/node/mod.rs @@ -3,7 +3,7 @@ //! Starts the client use crate::{ args::{get_secret_key, DebugArgs, NetworkArgs, RpcServerArgs}, - dirs::{ConfigPath, DbPath, SecretKeyPath}, + dirs::DataDirPath, prometheus_exporter, runner::CliContext, utils::get_single_header, @@ -39,7 +39,7 @@ use reth_interfaces::{ }; use reth_network::{error::NetworkError, NetworkConfig, NetworkHandle, NetworkManager}; use reth_network_api::NetworkInfo; -use reth_primitives::{BlockHashOrNumber, Chain, ChainSpec, Head, Header, SealedHeader, H256}; +use reth_primitives::{BlockHashOrNumber, ChainSpec, Head, Header, SealedHeader, H256}; use reth_provider::{BlockProvider, CanonStateSubscriptions, HeaderProvider, ShareableDatabase}; use reth_revm::Factory; use reth_revm_inspectors::stack::Hook; @@ -78,19 +78,31 @@ pub mod events; /// Start the node #[derive(Debug, Parser)] pub struct Command { - /// The path to the configuration file to use. - #[arg(long, value_name = "FILE", verbatim_doc_comment, default_value_t)] - config: MaybePlatformPath, - - /// The path to the database folder. + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + + /// The path to the configuration file to use. + #[arg(long, value_name = "FILE", verbatim_doc_comment)] + config: Option, + + /// The path to the database folder. If not specified, it will be set in the data dir for the + /// chain being used. + #[arg(long, value_name = "PATH", verbatim_doc_comment)] + db: Option, + + /// Secret key to use for this node. + /// + /// This will also deterministically set the peer ID. If not specified, it will be set in the + /// data dir for the chain being used. + #[arg(long, value_name = "PATH", global = true, required = false)] + p2p_secret_key: Option, /// The chain this node is running. /// @@ -109,12 +121,6 @@ pub struct Command { )] chain: Arc, - /// Secret key to use for this node. - /// - /// This also will deterministically set the peer ID. - #[arg(long, value_name = "PATH", global = true, required = false, default_value_t)] - p2p_secret_key: MaybePlatformPath, - /// Enable Prometheus metrics. /// /// The metrics will be served at the given interface and port. @@ -144,13 +150,19 @@ impl Command { // Does not do anything on windows. raise_fd_limit(); - let mut config: Config = self.load_config_with_chain(self.chain.chain)?; - info!(target: "reth::cli", path = %self.config.unwrap_or_chain_default(self.chain.chain), "Configuration loaded"); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + let config_path = self.config.clone().unwrap_or(data_dir.config_path()); - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + let mut config: Config = self.load_config(config_path.clone())?; - info!(target: "reth::cli", path = %db_path, "Opening database"); + // always store reth.toml in the data dir, not the chain specific data dir + info!(target: "reth::cli", path = ?config_path, "Configuration loaded"); + + // use the overridden db path if specified + let db_path = self.db.clone().unwrap_or(data_dir.db_path()); + + info!(target: "reth::cli", path = ?db_path, "Opening database"); let db = Arc::new(init_db(&db_path)?); info!(target: "reth::cli", "Database opened"); @@ -217,16 +229,23 @@ impl Command { } info!(target: "reth::cli", "Connecting to P2P network"); - let secret_key = - get_secret_key(self.p2p_secret_key.unwrap_or_chain_default(self.chain.chain))?; + let default_secret_key_path = data_dir.p2p_secret_path(); + let default_peers_path = data_dir.known_peers_path(); + let secret_key = get_secret_key(&default_secret_key_path)?; let network_config = self.load_network_config( &config, Arc::clone(&db), ctx.task_executor.clone(), secret_key, + default_peers_path.clone(), ); let network = self - .start_network(network_config, &ctx.task_executor, transaction_pool.clone()) + .start_network( + network_config, + &ctx.task_executor, + transaction_pool.clone(), + default_peers_path, + ) .await?; info!(target: "reth::cli", peer_id = %network.peer_id(), local_addr = %network.local_addr(), "Connected to P2P network"); debug!(target: "reth::cli", peer_id = ?network.peer_id(), "Full peer ID"); @@ -358,6 +377,10 @@ impl Command { ); info!(target: "reth::cli", "Engine API handler initialized"); + // extract the jwt secret from the the args if possible + let default_jwt_path = data_dir.jwt_path(); + let jwt_secret = self.rpc.jwt_secret(default_jwt_path)?; + // Start RPC servers let (_rpc_server, _auth_server) = self .rpc @@ -368,6 +391,7 @@ impl Command { ctx.task_executor.clone(), blockchain_tree, engine_api, + jwt_secret, ) .await?; @@ -437,12 +461,10 @@ impl Command { Ok(pipeline) } - /// 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.unwrap_or_chain_default(chain); + /// Loads the reth config with the given datadir root + fn load_config(&self, config_path: PathBuf) -> eyre::Result { confy::load_path::(config_path.clone()) - .wrap_err_with(|| format!("Could not load config file {}", config_path)) + .wrap_err_with(|| format!("Could not load config file {:?}", config_path)) } fn init_trusted_nodes(&self, config: &mut Config) { @@ -473,6 +495,7 @@ impl Command { config: NetworkConfig, task_executor: &TaskExecutor, pool: Pool, + default_peers_path: PathBuf, ) -> Result where C: BlockProvider + HeaderProvider + Clone + Unpin + 'static, @@ -485,7 +508,7 @@ impl Command { .request_handler(client) .split_with_handle(); - let known_peers_file = self.network.persistent_peers_file(self.chain.chain); + let known_peers_file = self.network.persistent_peers_file(default_peers_path); task_executor.spawn_critical_with_signal("p2p network task", |shutdown| { run_network_until_shutdown(shutdown, network, known_peers_file) }); @@ -581,11 +604,12 @@ impl Command { db: Arc>, executor: TaskExecutor, secret_key: SecretKey, + default_peers_path: PathBuf, ) -> NetworkConfig>>> { let head = self.lookup_head(Arc::clone(&db)).expect("the head block is missing"); self.network - .network_config(config, self.chain.clone(), secret_key) + .network_config(config, self.chain.clone(), secret_key, default_peers_path) .with_task_executor(Box::new(executor)) .set_head(head) .listener_addr(SocketAddr::V4(SocketAddrV4::new( @@ -755,35 +779,29 @@ mod tests { #[test] fn parse_config_path() { let cmd = Command::try_parse_from(["reth", "--config", "my/path/to/reth.toml"]).unwrap(); - assert_eq!( - cmd.config.unwrap_or_chain_default(cmd.chain.chain).as_ref(), - Path::new("my/path/to/reth.toml") - ); + // always store reth.toml in the data dir, not the chain specific data dir + let data_dir = cmd.datadir.unwrap_or_chain_default(cmd.chain.chain); + let config_path = cmd.config.unwrap_or(data_dir.config_path()); + assert_eq!(config_path, Path::new("my/path/to/reth.toml")); let cmd = Command::try_parse_from(["reth"]).unwrap(); - assert!( - cmd.config - .unwrap_or_chain_default(cmd.chain.chain) - .as_ref() - .ends_with("reth/mainnet/reth.toml"), - "{:?}", - cmd.config - ); + + // always store reth.toml in the data dir, not the chain specific data dir + let data_dir = cmd.datadir.unwrap_or_chain_default(cmd.chain.chain); + let config_path = cmd.config.clone().unwrap_or(data_dir.config_path()); + assert!(config_path.ends_with("reth/mainnet/reth.toml"), "{:?}", cmd.config); } #[test] fn parse_db_path() { let cmd = Command::try_parse_from(["reth", "--db", "my/path/to/db"]).unwrap(); - assert_eq!( - cmd.db.unwrap_or_chain_default(cmd.chain.chain).as_ref(), - Path::new("my/path/to/db") - ); + let data_dir = cmd.datadir.unwrap_or_chain_default(cmd.chain.chain); + let db_path = cmd.db.unwrap_or(data_dir.db_path()); + assert_eq!(db_path, Path::new("my/path/to/db")); let cmd = Command::try_parse_from(["reth"]).unwrap(); - assert!( - cmd.db.unwrap_or_chain_default(cmd.chain.chain).as_ref().ends_with("reth/mainnet/db"), - "{:?}", - cmd.config - ); + let data_dir = cmd.datadir.unwrap_or_chain_default(cmd.chain.chain); + let db_path = cmd.db.unwrap_or(data_dir.db_path()); + assert!(db_path.ends_with("reth/mainnet/db"), "{:?}", cmd.config); } } diff --git a/bin/reth/src/p2p/mod.rs b/bin/reth/src/p2p/mod.rs index f3dcbaffd..f15dee7e9 100644 --- a/bin/reth/src/p2p/mod.rs +++ b/bin/reth/src/p2p/mod.rs @@ -1,7 +1,7 @@ //! P2P Debugging tool use crate::{ args::{get_secret_key, DiscoveryArgs}, - dirs::{ConfigPath, PlatformPath, SecretKeyPath}, + dirs::{DataDirPath, MaybePlatformPath}, utils::get_single_header, }; use backon::{ConstantBuilder, Retryable}; @@ -15,14 +15,14 @@ use reth_staged_sync::{ utils::{chainspec::chain_spec_value_parser, hash_or_num_value_parser}, Config, }; -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; /// `reth p2p` command #[derive(Debug, Parser)] pub struct Command { /// The path to the configuration file to use. - #[arg(long, value_name = "FILE", verbatim_doc_comment, default_value_t)] - config: PlatformPath, + #[arg(long, value_name = "FILE", verbatim_doc_comment)] + config: Option, /// The chain this node is running. /// @@ -41,11 +41,21 @@ pub struct Command { )] chain: Arc, + /// The path to the data dir for all reth files and subdirectories. + /// + /// Defaults to the OS-specific data directory: + /// + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, + /// Secret key to use for this node. /// /// This also will deterministically set the peer ID. - #[arg(long, value_name = "PATH", global = true, required = false, default_value_t)] - p2p_secret_key: PlatformPath, + #[arg(long, value_name = "PATH", global = true, required = false)] + p2p_secret_key: Option, /// Disable the discovery service. #[command(flatten)] @@ -92,7 +102,11 @@ impl Command { let tempdir = tempfile::TempDir::new()?; let noop_db = Arc::new(Env::::open(&tempdir.into_path(), EnvKind::RW)?); - let mut config: Config = confy::load_path(&self.config).unwrap_or_default(); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + let config_path = self.config.clone().unwrap_or(data_dir.config_path()); + + let mut config: Config = confy::load_path(&config_path).unwrap_or_default(); if let Some(peer) = self.trusted_peer { config.peers.trusted_nodes.insert(peer); @@ -104,7 +118,9 @@ impl Command { config.peers.connect_trusted_nodes_only = self.trusted_only; - let p2p_secret_key = get_secret_key(&self.p2p_secret_key)?; + let default_secret_key_path = data_dir.p2p_secret_path(); + let secret_key_path = self.p2p_secret_key.clone().unwrap_or(default_secret_key_path); + let p2p_secret_key = get_secret_key(&secret_key_path)?; let mut network_config_builder = config.network_config(self.nat, None, p2p_secret_key).chain_spec(self.chain.clone()); diff --git a/bin/reth/src/stage/mod.rs b/bin/reth/src/stage/mod.rs index 8fd40c952..f0dbd2ba4 100644 --- a/bin/reth/src/stage/mod.rs +++ b/bin/reth/src/stage/mod.rs @@ -3,7 +3,7 @@ //! Stage debugging tool use crate::{ args::{get_secret_key, NetworkArgs, StageEnum}, - dirs::{ConfigPath, DbPath, MaybePlatformPath, PlatformPath, SecretKeyPath}, + dirs::{DataDirPath, MaybePlatformPath}, prometheus_exporter, }; use clap::Parser; @@ -19,25 +19,25 @@ use reth_stages::{ stages::{BodyStage, ExecutionStage, MerkleStage, SenderRecoveryStage, TransactionLookupStage}, ExecInput, Stage, StageId, UnwindInput, }; -use std::{net::SocketAddr, sync::Arc}; +use std::{net::SocketAddr, path::PathBuf, sync::Arc}; use tracing::*; /// `reth stage` command #[derive(Debug, Parser)] pub struct Command { - /// The path to the database folder. + /// The path to the configuration file to use. + #[arg(long, value_name = "FILE", verbatim_doc_comment)] + config: Option, + + /// The path to the data dir for all reth files and subdirectories. /// /// Defaults to the OS-specific data directory: /// - /// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db` - /// - Windows: `{FOLDERID_RoamingAppData}/reth/db` - /// - macOS: `$HOME/Library/Application Support/reth/db` - #[arg(long, value_name = "PATH", verbatim_doc_comment, default_value_t)] - db: MaybePlatformPath, - - /// The path to the configuration file to use. - #[arg(long, value_name = "FILE", verbatim_doc_comment, default_value_t)] - config: MaybePlatformPath, + /// - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + /// - Windows: `{FOLDERID_RoamingAppData}/reth/` + /// - macOS: `$HOME/Library/Application Support/reth/` + #[arg(long, value_name = "DATA_DIR", verbatim_doc_comment, default_value_t)] + datadir: MaybePlatformPath, /// The chain this node is running. /// @@ -59,8 +59,8 @@ pub struct Command { /// Secret key to use for this node. /// /// This also will deterministically set the peer ID. - #[arg(long, value_name = "PATH", global = true, required = false, default_value_t)] - p2p_secret_key: PlatformPath, + #[arg(long, value_name = "PATH", global = true, required = false)] + p2p_secret_key: Option, /// Enable Prometheus metrics. /// @@ -99,9 +99,11 @@ impl Command { // Does not do anything on windows. fdlimit::raise_fd_limit(); - let config: Config = - confy::load_path(self.config.unwrap_or_chain_default(self.chain.chain)) - .unwrap_or_default(); + // add network name to data dir + let data_dir = self.datadir.unwrap_or_chain_default(self.chain.chain); + let config_path = self.config.clone().unwrap_or(data_dir.config_path()); + + let config: Config = confy::load_path(config_path).unwrap_or_default(); info!(target: "reth::cli", "reth {} starting stage {:?}", clap::crate_version!(), self.stage); let input = ExecInput { @@ -111,9 +113,10 @@ impl Command { let unwind = UnwindInput { stage_progress: self.to, unwind_to: self.from, bad_block: None }; - // add network name to db directory - let db_path = self.db.unwrap_or_chain_default(self.chain.chain); + // use the overridden db path if specified + let db_path = data_dir.db_path(); + info!(target: "reth::cli", path = ?db_path, "Opening database"); let db = Arc::new(init_db(db_path)?); let mut tx = Transaction::new(db.as_ref())?; @@ -136,11 +139,14 @@ impl Command { }); } - let p2p_secret_key = get_secret_key(&self.p2p_secret_key)?; + let default_secret_key_path = data_dir.p2p_secret_path(); + let p2p_secret_key = get_secret_key(&default_secret_key_path)?; + + let default_peers_path = data_dir.known_peers_path(); let network = self .network - .network_config(&config, self.chain.clone(), p2p_secret_key) + .network_config(&config, self.chain.clone(), p2p_secret_key, default_peers_path) .build(Arc::new(ShareableDatabase::new(db.clone(), self.chain.clone()))) .start_network() .await?;