diff --git a/.gitignore b/.gitignore index 417fe75a8a6..ab4230b0a19 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ version-compatibility/Cargo.lock benches/benches-outputs/Cargo.lock benches/benches-outputs/src/test_gas_costs_output.rs .idea +.env diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ec976d4bf0..f302be9f78b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Description of the upcoming release here. ### Added +- [#1308](https://github.com/FuelLabs/fuel-core/pull/1308): Add support for loading .env files when compiling with the `env` feature. This allows users to conveniently supply CLI arguments in a secure and IDE-agnostic way. - [#1263](https://github.com/FuelLabs/fuel-core/pull/1263): Add gas benchmarks for `ED19` and `ECR1` instructions. - [#1286](https://github.com/FuelLabs/fuel-core/pull/1286): Include readable names for test cases where missing. - [#1304](https://github.com/FuelLabs/fuel-core/pull/1304): Implemented `submit_and_await_commit_with_receipts` method for `FuelClient`. diff --git a/Cargo.lock b/Cargo.lock index 9689fbb9a94..1c8cbd1d73d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1968,6 +1968,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "downcast" version = "0.11.0" @@ -2688,6 +2694,7 @@ dependencies = [ "clap", "const_format", "dirs", + "dotenvy", "fuel-core", "humantime", "lazy_static", diff --git a/bin/fuel-core/Cargo.toml b/bin/fuel-core/Cargo.toml index 950f0aae0db..cc2fa27e4aa 100644 --- a/bin/fuel-core/Cargo.toml +++ b/bin/fuel-core/Cargo.toml @@ -20,6 +20,7 @@ anyhow = { workspace = true } clap = { workspace = true, features = ["derive", "env"] } const_format = { version = "0.2", optional = true } dirs = "4.0" +dotenvy = { version = "0.15", optional = true } fuel-core = { workspace = true } humantime = "2.1" lazy_static = { workspace = true } @@ -38,12 +39,13 @@ url = { version = "2.2", optional = true } test-case = { workspace = true } [features] -debug = ["fuel-core/debug"] +debug = ["env", "fuel-core/debug"] default = ["debug", "metrics", "relayer", "rocksdb"] +env = ["dep:dotenvy"] metrics = ["fuel-core/metrics"] p2p = ["fuel-core/p2p", "const_format"] relayer = ["fuel-core/relayer", "dep:url", "dep:serde_json"] rocksdb = ["fuel-core/rocksdb"] rocksdb-production = ["fuel-core/rocksdb-production"] # features to enable in production, but increase build times -production = ["metrics", "relayer", "rocksdb-production", "p2p"] +production = ["env", "metrics", "relayer", "rocksdb-production", "p2p"] diff --git a/bin/fuel-core/src/cli.rs b/bin/fuel-core/src/cli.rs index c9e9d99ee66..4bfe17cc87b 100644 --- a/bin/fuel-core/src/cli.rs +++ b/bin/fuel-core/src/cli.rs @@ -4,7 +4,10 @@ use std::{ path::PathBuf, str::FromStr, }; -use tracing::warn; +use tracing::{ + info, + warn, +}; use tracing_subscriber::{ filter::EnvFilter, layer::SubscriberExt, @@ -12,6 +15,11 @@ use tracing_subscriber::{ Layer, }; +#[cfg(feature = "env")] +use dotenvy::dotenv; +#[cfg(feature = "env")] +use tracing::error; + lazy_static::lazy_static! { pub static ref DEFAULT_DB_PATH: PathBuf = dirs::home_dir().unwrap().join(".fuel").join("db"); } @@ -41,6 +49,22 @@ pub enum Fuel { pub const LOG_FILTER: &str = "RUST_LOG"; pub const HUMAN_LOGGING: &str = "HUMAN_LOGGING"; +#[cfg(feature = "env")] +fn init_environment() -> Option { + match dotenv() { + Ok(path) => Some(path), + Err(e) => { + error!("Unable to load .env environment variables: {e}. Please check that you have created a .env file in your working directory."); + None + } + } +} + +#[cfg(not(feature = "env"))] +fn init_environment() -> Option { + None +} + pub async fn init_logging() -> anyhow::Result<()> { let filter = match env::var_os(LOG_FILTER) { Some(_) => { @@ -87,6 +111,11 @@ pub async fn init_logging() -> anyhow::Result<()> { } pub async fn run_cli() -> anyhow::Result<()> { + init_logging().await?; + if let Some(path) = init_environment() { + let path = path.display(); + info!("Loading environment variables from {path}"); + } let opt = Opt::try_parse(); if opt.is_err() { let command = run::Command::try_parse(); diff --git a/bin/fuel-core/src/cli/run.rs b/bin/fuel-core/src/cli/run.rs index 75833853ec3..6379bb0fd98 100644 --- a/bin/fuel-core/src/cli/run.rs +++ b/bin/fuel-core/src/cli/run.rs @@ -1,7 +1,6 @@ #![allow(unused_variables)] use crate::{ cli::{ - init_logging, run::consensus::PoATriggerArgs, DEFAULT_DB_PATH, }, @@ -333,7 +332,6 @@ impl Command { } pub async fn exec(command: Command) -> anyhow::Result<()> { - init_logging().await?; let config = command.get_config()?; let network_name = { #[cfg(feature = "p2p")] diff --git a/bin/fuel-core/src/cli/run/relayer.rs b/bin/fuel-core/src/cli/run/relayer.rs index 382f56c314e..bfa212bf5ad 100644 --- a/bin/fuel-core/src/cli/run/relayer.rs +++ b/bin/fuel-core/src/cli/run/relayer.rs @@ -25,7 +25,7 @@ pub struct RelayerArgs { #[arg(long = "relayer", env)] #[arg(required_if_eq("enable_relayer", "true"))] #[arg(requires_if(IsPresent, "enable_relayer"))] - pub eth_client: Option, + pub relayer: Option, /// Ethereum contract address. Create EthAddress into fuel_types #[arg(long = "relayer-v2-listening-contracts", value_parser = parse_h160, env)] @@ -71,7 +71,7 @@ impl RelayerArgs { let config = Config { da_deploy_height: DaBlockHeight(self.da_deploy_height), da_finalization: DaBlockHeight(self.da_finalization), - eth_client: self.eth_client, + relayer: self.relayer, eth_v2_listening_contracts: self.eth_v2_listening_contracts, log_page_size: self.log_page_size, sync_minimum_duration: Duration::from_secs(self.sync_minimum_duration_secs), diff --git a/bin/fuel-core/src/cli/snapshot.rs b/bin/fuel-core/src/cli/snapshot.rs index 9a96b1e88a0..6ee6c9912d2 100644 --- a/bin/fuel-core/src/cli/snapshot.rs +++ b/bin/fuel-core/src/cli/snapshot.rs @@ -51,7 +51,6 @@ pub async fn exec(command: Command) -> anyhow::Result<()> { #[cfg(any(feature = "rocksdb", feature = "rocksdb-production"))] pub async fn exec(command: Command) -> anyhow::Result<()> { - use crate::cli::init_logging; use anyhow::Context; use fuel_core::{ chain_config::{ @@ -60,7 +59,6 @@ pub async fn exec(command: Command) -> anyhow::Result<()> { }, database::Database, }; - init_logging().await?; let path = command.database_path; let data_source = fuel_core::state::rocks_db::RocksDb::default_open(&path, None).context( diff --git a/crates/services/relayer/src/config.rs b/crates/services/relayer/src/config.rs index 4cb884c7663..adc8752808c 100644 --- a/crates/services/relayer/src/config.rs +++ b/crates/services/relayer/src/config.rs @@ -22,7 +22,7 @@ pub struct Config { /// Number of da blocks after which messages/stakes/validators become finalized. pub da_finalization: DaBlockHeight, /// Uri address to ethereum client. - pub eth_client: Option, + pub relayer: Option, // TODO: Create `EthAddress` into `fuel_core_types`. /// Ethereum contract address. pub eth_v2_listening_contracts: Vec, @@ -58,7 +58,7 @@ impl Default for Config { Self { da_deploy_height: DaBlockHeight::from(Self::DEFAULT_DA_DEPLOY_HEIGHT), da_finalization: DaBlockHeight::from(Self::DEFAULT_DA_FINALIZATION), - eth_client: None, + relayer: None, eth_v2_listening_contracts: vec![H160::from_str( "0x03E4538018285e1c03CCce2F92C9538c87606911", ) diff --git a/crates/services/relayer/src/service.rs b/crates/services/relayer/src/service.rs index d760f75f918..72522be6ea9 100644 --- a/crates/services/relayer/src/service.rs +++ b/crates/services/relayer/src/service.rs @@ -348,7 +348,7 @@ pub fn new_service(database: D, config: Config) -> anyhow::Result> where D: RelayerDb + Clone + 'static, { - let url = config.eth_client.clone().ok_or_else(|| { + let url = config.relayer.clone().ok_or_else(|| { anyhow::anyhow!( "Tried to start Relayer without setting an eth_client in the config" ) diff --git a/tests/tests/relayer.rs b/tests/tests/relayer.rs index 52459d640d1..81d60b04ab9 100644 --- a/tests/tests/relayer.rs +++ b/tests/tests/relayer.rs @@ -95,7 +95,7 @@ async fn relayer_can_download_logs() { let eth_node = Arc::new(eth_node); let eth_node_handle = spawn_eth_node(eth_node).await; - relayer_config.eth_client = Some( + relayer_config.relayer = Some( format!("http://{}", eth_node_handle.address) .as_str() .try_into() @@ -153,7 +153,7 @@ async fn messages_are_spendable_after_relayer_is_synced() { let eth_node = Arc::new(eth_node); let eth_node_handle = spawn_eth_node(eth_node).await; - relayer_config.eth_client = Some( + relayer_config.relayer = Some( format!("http://{}", eth_node_handle.address) .as_str() .try_into()