diff --git a/Cargo.lock b/Cargo.lock index e4cb2101297f5..8fa33a69245bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1032,7 +1032,7 @@ dependencies = [ [[package]] name = "anvil" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -1098,7 +1098,7 @@ dependencies = [ [[package]] name = "anvil-core" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -1122,7 +1122,7 @@ dependencies = [ [[package]] name = "anvil-rpc" -version = "1.3.1" +version = "1.3.2" dependencies = [ "serde", "serde_json", @@ -1130,7 +1130,7 @@ dependencies = [ [[package]] name = "anvil-server" -version = "1.3.1" +version = "1.3.2" dependencies = [ "anvil-rpc", "async-trait", @@ -2357,7 +2357,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -2458,7 +2458,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chisel" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3789,7 +3789,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "forge" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -3873,7 +3873,7 @@ dependencies = [ [[package]] name = "forge-doc" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "derive_more 2.0.1", @@ -3896,7 +3896,7 @@ dependencies = [ [[package]] name = "forge-fmt" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "ariadne", @@ -3912,7 +3912,7 @@ dependencies = [ [[package]] name = "forge-lint" -version = "1.3.1" +version = "1.3.2" dependencies = [ "foundry-common", "foundry-compilers", @@ -3929,7 +3929,7 @@ dependencies = [ [[package]] name = "forge-script" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -3974,7 +3974,7 @@ dependencies = [ [[package]] name = "forge-script-sequence" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-network", "alloy-primitives", @@ -3990,7 +3990,7 @@ dependencies = [ [[package]] name = "forge-sol-macro-gen" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -4006,7 +4006,7 @@ dependencies = [ [[package]] name = "forge-verify" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4088,7 +4088,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4138,7 +4138,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes-spec" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-sol-types", "foundry-macros", @@ -4149,7 +4149,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -4197,7 +4197,7 @@ dependencies = [ [[package]] name = "foundry-common" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4254,7 +4254,7 @@ dependencies = [ [[package]] name = "foundry-common-fmt" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4381,7 +4381,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-primitives", @@ -4420,7 +4420,7 @@ dependencies = [ [[package]] name = "foundry-debugger" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "crossterm", @@ -4438,7 +4438,7 @@ dependencies = [ [[package]] name = "foundry-evm" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-dyn-abi", "alloy-evm", @@ -4469,7 +4469,7 @@ dependencies = [ [[package]] name = "foundry-evm-abi" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4481,7 +4481,7 @@ dependencies = [ [[package]] name = "foundry-evm-core" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4520,7 +4520,7 @@ dependencies = [ [[package]] name = "foundry-evm-coverage" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "eyre", @@ -4535,7 +4535,7 @@ dependencies = [ [[package]] name = "foundry-evm-fuzz" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4559,7 +4559,7 @@ dependencies = [ [[package]] name = "foundry-evm-traces" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4611,7 +4611,7 @@ dependencies = [ [[package]] name = "foundry-linking" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "foundry-compilers", @@ -4621,7 +4621,7 @@ dependencies = [ [[package]] name = "foundry-macros" -version = "1.3.1" +version = "1.3.2" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -4645,7 +4645,7 @@ dependencies = [ [[package]] name = "foundry-test-utils" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-primitives", "alloy-provider", @@ -4670,7 +4670,7 @@ dependencies = [ [[package]] name = "foundry-wallets" -version = "1.3.1" +version = "1.3.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8671,9 +8671,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" diff --git a/Cargo.toml b/Cargo.toml index 523204a5aacd9..35edccc737b13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.3.1" +version = "1.3.2" edition = "2024" # Remember to update clippy.toml as well rust-version = "1.88" diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 7bb1084d03f1d..02e438d0bba85 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -7,6 +7,7 @@ use crate::{ }; use alloy_consensus::TxEnvelope; use alloy_genesis::{Genesis, GenesisAccount}; +use alloy_network::eip2718::EIP4844_TX_TYPE_ID; use alloy_primitives::{Address, B256, Bytes, U256, map::HashMap}; use alloy_rlp::Decodable; use alloy_sol_types::SolValue; @@ -437,6 +438,8 @@ impl Cheatcode for blobhashesCall { see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844" ); ccx.ecx.tx.blob_hashes.clone_from(hashes); + // force this as 4844 txtype + ccx.ecx.tx.tx_type = EIP4844_TX_TYPE_ID; Ok(Default::default()) } } diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index 8e011609bd5a7..fe0ebae3fe4f8 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -308,7 +308,7 @@ impl ContractsByArtifact { pub fn find_abi_by_name_or_src_path(&self, name_or_path: &str) -> Option<(JsonAbi, String)> { self.iter() .find(|(artifact, _)| { - artifact.name == name_or_path || artifact.source == PathBuf::from(name_or_path) + artifact.name == name_or_path || artifact.source == Path::new(name_or_path) }) .map(|(_, contract)| (contract.abi.clone(), contract.name.clone())) } diff --git a/crates/evm/core/src/fork/init.rs b/crates/evm/core/src/fork/init.rs index 4742d46fcaad2..ddb82bf7798da 100644 --- a/crates/evm/core/src/fork/init.rs +++ b/crates/evm/core/src/fork/init.rs @@ -92,5 +92,7 @@ pub fn configure_env(chain_id: u64, memory_limit: u64, disable_block_gas_limit: cfg.disable_eip3607 = true; cfg.disable_block_gas_limit = disable_block_gas_limit; cfg.disable_nonce_check = true; + // For Osaka EIP-7825 + cfg.tx_gas_limit_cap = Some(u64::MAX); cfg } diff --git a/crates/evm/traces/src/identifier/etherscan.rs b/crates/evm/traces/src/identifier/etherscan.rs index ecfb0d9d59f2b..78a300c73fa96 100644 --- a/crates/evm/traces/src/identifier/etherscan.rs +++ b/crates/evm/traces/src/identifier/etherscan.rs @@ -44,9 +44,19 @@ impl EtherscanIdentifier { if config.offline { return Ok(None); } - let Some(config) = config.get_etherscan_config_with_chain(chain)? else { - return Ok(None); + + let config = match config.get_etherscan_config_with_chain(chain) { + Ok(Some(config)) => config, + Ok(None) => { + warn!(target: "traces::etherscan", "etherscan config not found"); + return Ok(None); + } + Err(err) => { + warn!(?err, "failed to get etherscan config"); + return Ok(None); + } }; + trace!(target: "traces::etherscan", chain=?config.chain, url=?config.api_url, "using etherscan identifier"); Ok(Some(Self { client: Arc::new(config.into_client()?), diff --git a/crates/forge/src/cmd/build.rs b/crates/forge/src/cmd/build.rs index 1dbb334b6227f..4fbc547977bac 100644 --- a/crates/forge/src/cmd/build.rs +++ b/crates/forge/src/cmd/build.rs @@ -1,6 +1,6 @@ use super::{install, watch::WatchArgs}; use clap::Parser; -use eyre::Result; +use eyre::{Result, eyre}; use forge_lint::{linter::Linter, sol::SolidityLinter}; use foundry_cli::{ opts::{BuildOpts, solar_pcx_from_build_opts}, @@ -112,17 +112,18 @@ impl BuildArgs { sh_println!("{}", serde_json::to_string_pretty(&output.output())?)?; } - // Only run the `SolidityLinter` if there are no compilation errors - if output.output().errors.iter().all(|e| !e.is_error()) { - self.lint(&project, &config)?; + // Only run the `SolidityLinter` if lint on build and no compilation errors. + if config.lint.lint_on_build && !output.output().errors.iter().any(|e| e.is_error()) { + self.lint(&project, &config, self.paths.as_deref()) + .map_err(|err| eyre!("Lint failed: {err}"))?; } Ok(output) } - fn lint(&self, project: &Project, config: &Config) -> Result<()> { + fn lint(&self, project: &Project, config: &Config, files: Option<&[PathBuf]>) -> Result<()> { let format_json = shell::is_json(); - if project.compiler.solc.is_some() && config.lint.lint_on_build && !shell::is_quiet() { + if project.compiler.solc.is_some() && !shell::is_quiet() { let linter = SolidityLinter::new(config.project_paths()) .with_json_emitter(format_json) .with_description(!format_json) @@ -156,6 +157,10 @@ impl BuildArgs { .project_paths::() .input_files_iter() .filter(|p| { + // Lint only specified build files, if any. + if let Some(files) = files { + return files.iter().any(|file| &curr_dir.join(file) == p); + } skip.is_match(p) && !(ignored.contains(p) || ignored.contains(&curr_dir.join(p))) }) diff --git a/crates/forge/src/lockfile.rs b/crates/forge/src/lockfile.rs index 9c7339ffbfb43..bbcbc5dedc4e8 100644 --- a/crates/forge/src/lockfile.rs +++ b/crates/forge/src/lockfile.rs @@ -1,14 +1,13 @@ //! foundry.lock handler type. -use std::{ - collections::hash_map::Entry, - path::{Path, PathBuf}, -}; - use alloy_primitives::map::HashMap; use eyre::{OptionExt, Result}; use foundry_cli::utils::Git; use serde::{Deserialize, Serialize}; +use std::{ + collections::{BTreeMap, hash_map::Entry}, + path::{Path, PathBuf}, +}; pub const FOUNDRY_LOCK: &str = "foundry.lock"; @@ -137,7 +136,8 @@ impl<'a> Lockfile<'a> { /// Writes the lockfile to the project root. pub fn write(&self) -> Result<()> { - foundry_common::fs::write_pretty_json_file(&self.lockfile_path, &self.deps)?; + let ordered_deps: BTreeMap<_, _> = self.deps.clone().into_iter().collect(); + foundry_common::fs::write_pretty_json_file(&self.lockfile_path, &ordered_deps)?; trace!(at= ?self.lockfile_path, "wrote lockfile"); Ok(()) @@ -340,6 +340,8 @@ impl std::fmt::Display for DepIdentifier { #[cfg(test)] mod tests { use super::*; + use std::fs; + use tempfile::tempdir; #[test] fn serde_dep_identifier() { @@ -382,4 +384,60 @@ mod tests { assert_eq!(tag, tag_de); assert_eq!(rev, rev_de); } + + #[test] + fn test_write_ordered_deps() { + let dir = tempdir().unwrap(); + let mut lockfile = Lockfile::new(dir.path()); + lockfile.insert( + PathBuf::from("z_dep"), + DepIdentifier::Rev { rev: "3".to_string(), r#override: false }, + ); + lockfile.insert( + PathBuf::from("a_dep"), + DepIdentifier::Rev { rev: "1".to_string(), r#override: false }, + ); + lockfile.insert( + PathBuf::from("c_dep"), + DepIdentifier::Rev { rev: "2".to_string(), r#override: false }, + ); + let _ = lockfile.write(); + let contents = fs::read_to_string(lockfile.lockfile_path).unwrap(); + let expected = r#"{ + "a_dep": { + "rev": "1" + }, + "c_dep": { + "rev": "2" + }, + "z_dep": { + "rev": "3" + } +}"#; + assert_eq!(contents.trim(), expected.trim()); + + let mut lockfile = Lockfile::new(dir.path()); + lockfile.read().unwrap(); + lockfile.insert( + PathBuf::from("x_dep"), + DepIdentifier::Rev { rev: "4".to_string(), r#override: false }, + ); + let _ = lockfile.write(); + let contents = fs::read_to_string(lockfile.lockfile_path).unwrap(); + let expected = r#"{ + "a_dep": { + "rev": "1" + }, + "c_dep": { + "rev": "2" + }, + "x_dep": { + "rev": "4" + }, + "z_dep": { + "rev": "3" + } +}"#; + assert_eq!(contents.trim(), expected.trim()); + } } diff --git a/crates/forge/tests/cli/lint.rs b/crates/forge/tests/cli/lint.rs index 112a800cbbf85..0ae9e7dfee97b 100644 --- a/crates/forge/tests/cli/lint.rs +++ b/crates/forge/tests/cli/lint.rs @@ -48,6 +48,24 @@ const ONLY_IMPORTS: &str = r#" import "./ContractWithLints.sol"; "#; +const COUNTER_A: &str = r#" + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0; + + contract CounterA { + uint256 public CounterA_Fail_Lint; + } + "#; + +const COUNTER_B: &str = r#" + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0; + + contract CounterB { + uint256 public CounterB_Fail_Lint; + } + "#; + forgetest!(can_use_config, |prj, cmd| { prj.wipe_contracts(); prj.add_source("ContractWithLints", CONTRACT).unwrap(); @@ -388,6 +406,48 @@ note[unused-import]: unused imports should be removed "#]]); }); +// +forgetest!(can_lint_only_built_files, |prj, cmd| { + prj.wipe_contracts(); + prj.add_source("CounterAWithLints", COUNTER_A).unwrap(); + prj.add_source("CounterBWithLints", COUNTER_B).unwrap(); + + // Both contracts should be linted on build. + cmd.forge_fuse().args(["build"]).assert_success().stderr_eq(str![[r#" +note[mixed-case-variable]: mutable variables should use mixedCase + [FILE]:6:24 + | +6 | uint256 public CounterA_Fail_Lint; + | ------------------ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + +note[mixed-case-variable]: mutable variables should use mixedCase + [FILE]:6:24 + | +6 | uint256 public CounterB_Fail_Lint; + | ------------------ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + + +"#]]); + // Only contract CounterBWithLints that we build should be linted. + cmd.forge_fuse().args(["build", "src/CounterBWithLints.sol"]).assert_success().stderr_eq(str![ + [r#" +note[mixed-case-variable]: mutable variables should use mixedCase + [FILE]:6:24 + | +6 | uint256 public CounterB_Fail_Lint; + | ------------------ + | + = help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable + + +"#] + ]); +}); + // ------------------------------------------------------------------------------------------------ #[tokio::test] diff --git a/crates/forge/tests/it/repros.rs b/crates/forge/tests/it/repros.rs index b9ed5a2711916..5d1caf5048ca5 100644 --- a/crates/forge/tests/it/repros.rs +++ b/crates/forge/tests/it/repros.rs @@ -416,3 +416,6 @@ test_repro!(10586); // https://github.com/foundry-rs/foundry/issues/10957 test_repro!(10957); + +// https://github.com/foundry-rs/foundry/issues/11353 +test_repro!(11353); diff --git a/testdata/default/repros/Issue11353.t.sol b/testdata/default/repros/Issue11353.t.sol new file mode 100644 index 0000000000000..ae3305bcfc036 --- /dev/null +++ b/testdata/default/repros/Issue11353.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract Blobhash { + function getIndices(uint256[] calldata blobIndices) public view returns (bytes32[] memory) { + bytes32[] memory blobHashes = new bytes32[](blobIndices.length); + for (uint256 i = 0; i < blobIndices.length; i++) { + uint256 blobIndex = blobIndices[i]; + bytes32 blobHash = blobhash(blobIndex); + require(blobHash != 0, "blob not found"); + blobHashes[i] = blobHash; + } + return blobHashes; + } +} + +// https://github.com/foundry-rs/foundry/issues/11353 +contract Issue11353Test is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + Blobhash public blobhashContract; + + function setUp() public { + blobhashContract = new Blobhash(); + } + + function test_blobhashes() public { + uint256[] memory blobIndices = new uint256[](1); + blobIndices[0] = 0; + + bytes32[] memory blobHashes = new bytes32[](1); + blobHashes[0] = keccak256(abi.encode(0)); + vm.blobhashes(blobHashes); + + vm.assertEq(blobhashContract.getIndices(blobIndices), blobHashes); + } +}