From 4480293d0f6ca675220342d1103f79bf3d609636 Mon Sep 17 00:00:00 2001 From: zark Date: Sun, 25 May 2025 00:04:50 +0300 Subject: [PATCH 1/4] feat(config): warn on unknown config keys in foundry.toml --- crates/config/Cargo.toml | 1 + crates/config/src/lib.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 3bd2fa44b9e6a..e5547116d1989 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -14,6 +14,7 @@ repository.workspace = true workspace = true [dependencies] +serde_ignored = "0.1" foundry-block-explorers = { workspace = true, features = ["foundry-compilers"] } foundry-compilers = { workspace = true, features = ["svm-solc"] } diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 8224b6b203155..1f9fa48f6e87d 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -50,6 +50,8 @@ use std::{ str::FromStr, }; +use tracing::warn; + mod macros; pub mod utils; @@ -641,6 +643,23 @@ impl Config { } fn from_figment(figment: Figment) -> Result { + let file_path = Path::new("foundry.toml"); + if let Ok(raw) = fs::read_to_string(&file_path) { + let deserializer = toml::Deserializer::new(&raw); + let mut ignored = Vec::new(); + let _: Result = serde_ignored::deserialize(deserializer, |path| { + ignored.push(path.to_string()); + }); + + if !ignored.is_empty() { + warn!( + "Found unknown config keys in {}: {}", + file_path.display(), + ignored.join(", ") + ); + } + } + let mut config = figment.extract::().map_err(ExtractConfigError::new)?; config.profile = figment.profile().clone(); From 395148f6ce85c2d36b9c9b7b2b0cf15b44605261 Mon Sep 17 00:00:00 2001 From: zarkk01 Date: Sun, 8 Jun 2025 13:00:58 +0300 Subject: [PATCH 2/4] fix(config): log warning for unknown config keys and add test --- crates/config/Cargo.toml | 3 +- crates/config/src/lib.rs | 90 ++++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index e5547116d1989..bbeabe31ac87e 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -57,6 +57,7 @@ path-slash = "0.2" similar-asserts.workspace = true figment = { workspace = true, features = ["test"] } tempfile.workspace = true +tracing-test = "0.2" [features] -isolate-by-default = [] +isolate-by-default = [] \ No newline at end of file diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 7779b50a608ef..2f1ec46bdd3b3 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -120,7 +120,7 @@ pub mod soldeer; use soldeer::{SoldeerConfig, SoldeerDependencyConfig}; mod vyper; -pub use vyper::{normalize_evm_version_vyper, VyperConfig}; +use vyper::VyperConfig; mod bind_json; use bind_json::BindJsonConfig; @@ -642,23 +642,29 @@ impl Config { Self::from_provider(provider) } - fn from_figment(figment: Figment) -> Result { - let file_path = Path::new("foundry.toml"); - if let Ok(raw) = fs::read_to_string(&file_path) { - let deserializer = toml::Deserializer::new(&raw); + /// Read `foundry.toml`, collect any unknown keys, and log a warning. + fn warn_unknown_keys() -> Result<(), ExtractConfigError> { + let path = Path::new(Self::FILE_NAME); + + // if the file exists & is readable, deserialize and collect ignored keys + if let Ok(raw) = fs::read_to_string(path) { let mut ignored = Vec::new(); - let _: Result = serde_ignored::deserialize(deserializer, |path| { - ignored.push(path.to_string()); - }); + let deserializer = toml::Deserializer::new(&raw); + + // collect every ignored field name + let _: Result = + serde_ignored::deserialize(deserializer, |field| ignored.push(field.to_string())); + // if we found any, log a single warning with a list if !ignored.is_empty() { - warn!( - "Found unknown config keys in {}: {}", - file_path.display(), - ignored.join(", ") - ); + warn!("Found unknown config keys in {}: {}", Self::FILE_NAME, ignored.join(", ")); } } + Ok(()) + } + + fn from_figment(figment: Figment) -> Result { + Self::warn_unknown_keys()?; let mut config = figment.extract::().map_err(ExtractConfigError::new)?; config.profile = figment.profile().clone(); @@ -1139,9 +1145,9 @@ impl Config { /// Whether caching should be enabled for the given chain id pub fn enable_caching(&self, endpoint: &str, chain_id: impl Into) -> bool { - !self.no_storage_caching && - self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) && - self.rpc_storage_caching.enable_for_endpoint(endpoint) + !self.no_storage_caching + && self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) + && self.rpc_storage_caching.enable_for_endpoint(endpoint) } /// Returns the `ProjectPathsConfig` sub set of the config. @@ -1497,7 +1503,7 @@ impl Config { extra_output.push(ContractOutputSelection::Metadata); } - ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().copied()) + ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().cloned()) } /// Parses all libraries in the form of @@ -1568,7 +1574,7 @@ impl Config { /// - evm version pub fn vyper_settings(&self) -> Result { Ok(VyperSettings { - evm_version: Some(normalize_evm_version_vyper(self.evm_version)), + evm_version: Some(self.evm_version), optimize: self.vyper.optimize, bytecode_metadata: None, // TODO: We don't yet have a way to deserialize other outputs correctly, so request only @@ -2030,8 +2036,8 @@ impl Config { let file_name = block.file_name(); let filepath = if file_type.is_dir() { block.path().join("storage.json") - } else if file_type.is_file() && - file_name.to_string_lossy().chars().all(char::is_numeric) + } else if file_type.is_file() + && file_name.to_string_lossy().chars().all(char::is_numeric) { block.path() } else { @@ -2334,7 +2340,7 @@ impl Default for Config { allow_paths: vec![], include_paths: vec![], force: false, - evm_version: EvmVersion::Prague, + evm_version: EvmVersion::Cancun, gas_reports: vec!["*".to_string()], gas_reports_ignore: vec![], gas_reports_include_tests: false, @@ -2599,8 +2605,10 @@ mod tests { }; use similar_asserts::assert_eq; use soldeer_core::remappings::RemappingsLocation; + use std::env; use std::{fs::File, io::Write}; use tempfile::tempdir; + use tracing_test::traced_test; use NamedChain::Moonbeam; // Helper function to clear `__warnings` in config, since it will be populated during loading @@ -4995,4 +5003,44 @@ mod tests { Ok(()) }); } + + #[traced_test] + #[test] + fn warn_unknown_keys_logs_warning_for_unknown_keys() { + let dir = tempdir().expect("failed to create temp dir"); + let path = dir.path().join("foundry.toml"); + fs::write(&path, "optimizor = false\n").expect("Failed to write foundry.toml"); + + let old_dir = env::current_dir().expect("failed to get current dir"); + env::set_current_dir(&dir).expect("failed to set current dir"); + + let _ = Config::warn_unknown_keys(); + + assert!( + logs_contain("Found unknown config keys") && logs_contain("optimizor"), + "Expected a warning log containing 'optimizor'" + ); + + env::set_current_dir(old_dir).expect("failed to restore dir"); + } + + #[traced_test] + #[test] + fn warn_unknown_keys_logs_nothing_for_valid_keys() { + let dir = tempdir().expect("failed to create temp dir"); + let path = dir.path().join("foundry.toml"); + fs::write(&path, "optimizer = false\n").expect("Failed to write foundry.toml"); + + let old_dir = env::current_dir().expect("failed to get current dir"); + env::set_current_dir(&dir).expect("failed to set current dir"); + + let _ = Config::warn_unknown_keys(); + + assert!( + !logs_contain("Found unknown config keys"), + "Did not expect a warning for only valid keys" + ); + + env::set_current_dir(old_dir).expect("failed to restore dir"); + } } From 1cb99a5b2b46bf188dcc487ee6e990b654686b54 Mon Sep 17 00:00:00 2001 From: zark <77061323+zarkk01@users.noreply.github.com> Date: Sun, 8 Jun 2025 13:23:01 +0300 Subject: [PATCH 3/4] feat(config): log warning for unknown config keys and add test --- crates/config/src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 2f1ec46bdd3b3..0b5f424bf243f 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -120,7 +120,7 @@ pub mod soldeer; use soldeer::{SoldeerConfig, SoldeerDependencyConfig}; mod vyper; -use vyper::VyperConfig; +pub use vyper::{normalize_evm_version_vyper, VyperConfig}; mod bind_json; use bind_json::BindJsonConfig; @@ -1145,9 +1145,9 @@ impl Config { /// Whether caching should be enabled for the given chain id pub fn enable_caching(&self, endpoint: &str, chain_id: impl Into) -> bool { - !self.no_storage_caching - && self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) - && self.rpc_storage_caching.enable_for_endpoint(endpoint) + !self.no_storage_caching && + self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) && + self.rpc_storage_caching.enable_for_endpoint(endpoint) } /// Returns the `ProjectPathsConfig` sub set of the config. @@ -1503,7 +1503,7 @@ impl Config { extra_output.push(ContractOutputSelection::Metadata); } - ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().cloned()) + ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().copied()) } /// Parses all libraries in the form of @@ -1574,7 +1574,7 @@ impl Config { /// - evm version pub fn vyper_settings(&self) -> Result { Ok(VyperSettings { - evm_version: Some(self.evm_version), + evm_version: Some(normalize_evm_version_vyper(self.evm_version)), optimize: self.vyper.optimize, bytecode_metadata: None, // TODO: We don't yet have a way to deserialize other outputs correctly, so request only @@ -2036,8 +2036,8 @@ impl Config { let file_name = block.file_name(); let filepath = if file_type.is_dir() { block.path().join("storage.json") - } else if file_type.is_file() - && file_name.to_string_lossy().chars().all(char::is_numeric) + } else if file_type.is_file() && + file_name.to_string_lossy().chars().all(char::is_numeric) { block.path() } else { @@ -2340,7 +2340,7 @@ impl Default for Config { allow_paths: vec![], include_paths: vec![], force: false, - evm_version: EvmVersion::Cancun, + evm_version: EvmVersion::Prague, gas_reports: vec!["*".to_string()], gas_reports_ignore: vec![], gas_reports_include_tests: false, From 75e4ad452c3cd37f8dfe02f1a0861b4e8ae8db4e Mon Sep 17 00:00:00 2001 From: zark <77061323+zarkk01@users.noreply.github.com> Date: Sun, 8 Jun 2025 13:26:32 +0300 Subject: [PATCH 4/4] feat(config): log warning for unknown config keys and add test --- crates/config/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 0b5f424bf243f..59a3d524da263 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -2605,8 +2605,7 @@ mod tests { }; use similar_asserts::assert_eq; use soldeer_core::remappings::RemappingsLocation; - use std::env; - use std::{fs::File, io::Write}; + use std::{env, fs::File, io::Write}; use tempfile::tempdir; use tracing_test::traced_test; use NamedChain::Moonbeam;