From 44c86e76d5e37505cd7349a867e64a845b5b9b2d Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:55:59 +0200 Subject: [PATCH 1/8] chore: fix getArtifactPath flaky test (#9339) --- testdata/default/cheats/GetArtifactPath.t.sol | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/testdata/default/cheats/GetArtifactPath.t.sol b/testdata/default/cheats/GetArtifactPath.t.sol index 538c2e6c96ec..4b0df4ba6e6e 100644 --- a/testdata/default/cheats/GetArtifactPath.t.sol +++ b/testdata/default/cheats/GetArtifactPath.t.sol @@ -13,25 +13,15 @@ contract GetArtifactPathTest is DSTest { DummyForGetArtifactPath dummy = new DummyForGetArtifactPath(); bytes memory dummyCreationCode = type(DummyForGetArtifactPath).creationCode; - string memory root = vm.projectRoot(); string memory path = vm.getArtifactPathByCode(dummyCreationCode); - - string memory expectedPath = - string.concat(root, "/out/default/GetArtifactPath.t.sol/DummyForGetArtifactPath.json"); - - assertEq(path, expectedPath); + assertTrue(vm.contains(path, "/out/default/GetArtifactPath.t.sol/DummyForGetArtifactPath.json")); } function testGetArtifactPathByDeployedCode() public { DummyForGetArtifactPath dummy = new DummyForGetArtifactPath(); bytes memory dummyRuntimeCode = address(dummy).code; - string memory root = vm.projectRoot(); string memory path = vm.getArtifactPathByDeployedCode(dummyRuntimeCode); - - string memory expectedPath = - string.concat(root, "/out/default/GetArtifactPath.t.sol/DummyForGetArtifactPath.json"); - - assertEq(path, expectedPath); + assertTrue(vm.contains(path, "/out/default/GetArtifactPath.t.sol/DummyForGetArtifactPath.json")); } } From d275a4901f60a50c5a82fcf10fd5774ddb4598d8 Mon Sep 17 00:00:00 2001 From: Max <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:18:11 +0530 Subject: [PATCH 2/8] fix(cast storage): respect `--json` for layout (#9332) * feat(cast storage): allow ugly printing of layout Prior to this change, `cast storage $ADDRESS --rpc-url $RPC_URL --etherscan-api-key $ETHERSCAN_API_KEY` always provided a prettified output. This change adds a `--pretty` flag to `cast storage` which defaults to `true` thus retaining backwards compatibility. Passing `--pretty=false` to `cast storage` results in the json output of the storage layout being produced instead. * fix: remove default value from help text The default value is accessible via `cast storage --help` * fix(cast storage): provide output json path * test(cast): add storage_layout_simple_json test * fix(cast storage): use `--json` flag to ugly print * fix(cast storage): include values in json mode * fix(cast-storage): quiet compilation in all cases * chore: cargo clippy * use fixtures, assert JSON * only quiet if JSON mode, avoid unnecessary warning (if you pass an API key you already expect to fetch remote, very likely default) --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Co-authored-by: zerosnacks --- crates/cast/bin/cmd/storage.rs | 46 +- crates/cast/tests/cli/main.rs | 33 ++ .../fixtures/storage_layout_complex.json | 397 ++++++++++++++++++ .../tests/fixtures/storage_layout_simple.json | 36 ++ 4 files changed, 503 insertions(+), 9 deletions(-) create mode 100644 crates/cast/tests/fixtures/storage_layout_complex.json create mode 100644 crates/cast/tests/fixtures/storage_layout_simple.json diff --git a/crates/cast/bin/cmd/storage.rs b/crates/cast/bin/cmd/storage.rs index 9fca4172e345..5e2459127001 100644 --- a/crates/cast/bin/cmd/storage.rs +++ b/crates/cast/bin/cmd/storage.rs @@ -17,6 +17,7 @@ use foundry_common::{ abi::find_source, compile::{etherscan_project, ProjectCompiler}, ens::NameOrAddress, + shell, }; use foundry_compilers::{ artifacts::{ConfigurableContractArtifact, StorageLayout}, @@ -31,6 +32,7 @@ use foundry_config::{ impl_figment_convert_cast, Config, }; use semver::Version; +use serde::{Deserialize, Serialize}; use std::str::FromStr; /// The minimum Solc version for outputting storage layouts. @@ -45,7 +47,7 @@ pub struct StorageArgs { #[arg(value_parser = NameOrAddress::from_str)] address: NameOrAddress, - /// The storage slot number. + /// The storage slot number. If not provided, it gets the full storage layout. #[arg(value_parser = parse_slot)] slot: Option, @@ -109,19 +111,22 @@ impl StorageArgs { if project.paths.has_input_files() { // Find in artifacts and pretty print add_storage_layout_output(&mut project); - let out = ProjectCompiler::new().compile(&project)?; + let out = ProjectCompiler::new().quiet(shell::is_json()).compile(&project)?; let artifact = out.artifacts().find(|(_, artifact)| { artifact.get_deployed_bytecode_bytes().is_some_and(|b| *b == address_code) }); if let Some((_, artifact)) = artifact { - return fetch_and_print_storage(provider, address, block, artifact, true).await; + return fetch_and_print_storage( + provider, + address, + block, + artifact, + !shell::is_json(), + ) + .await; } } - // Not a forge project or artifact not found - // Get code from Etherscan - sh_warn!("No matching artifacts found, fetching source code from Etherscan...")?; - if !self.etherscan.has_key() { eyre::bail!("You must provide an Etherscan API key if you're fetching a remote contract's storage."); } @@ -180,7 +185,7 @@ impl StorageArgs { // Clear temp directory root.close()?; - fetch_and_print_storage(provider, address, block, artifact, true).await + fetch_and_print_storage(provider, address, block, artifact, !shell::is_json()).await } } @@ -215,6 +220,14 @@ impl StorageValue { } } +/// Represents the storage layout of a contract and its values. +#[derive(Clone, Debug, Serialize, Deserialize)] +struct StorageReport { + #[serde(flatten)] + layout: StorageLayout, + values: Vec, +} + async fn fetch_and_print_storage, T: Transport + Clone>( provider: P, address: Address, @@ -255,7 +268,22 @@ async fn fetch_storage_slots, T: Transport + Clone>( fn print_storage(layout: StorageLayout, values: Vec, pretty: bool) -> Result<()> { if !pretty { - sh_println!("{}", serde_json::to_string_pretty(&serde_json::to_value(layout)?)?)?; + let values: Vec<_> = layout + .storage + .iter() + .zip(&values) + .map(|(slot, storage_value)| { + let storage_type = layout.types.get(&slot.storage_type); + storage_value.value( + slot.offset, + storage_type.and_then(|t| t.number_of_bytes.parse::().ok()), + ) + }) + .collect(); + sh_println!( + "{}", + serde_json::to_string_pretty(&serde_json::to_value(StorageReport { layout, values })?)? + )?; return Ok(()) } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a88369e97ffe..2483fa479820 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1131,6 +1131,23 @@ casttest!(storage_layout_simple, |_prj, cmd| { "#]]); }); +// +casttest!(storage_layout_simple_json, |_prj, cmd| { + cmd.args([ + "storage", + "--rpc-url", + next_rpc_endpoint(NamedChain::Mainnet).as_str(), + "--block", + "21034138", + "--etherscan-api-key", + next_mainnet_etherscan_api_key().as_str(), + "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", + "--json", + ]) + .assert_success() + .stdout_eq(file!["../fixtures/storage_layout_simple.json": Json]); +}); + // casttest!(storage_layout_complex, |_prj, cmd| { cmd.args([ @@ -1164,6 +1181,22 @@ casttest!(storage_layout_complex, |_prj, cmd| { "#]]); }); +casttest!(storage_layout_complex_json, |_prj, cmd| { + cmd.args([ + "storage", + "--rpc-url", + next_rpc_endpoint(NamedChain::Mainnet).as_str(), + "--block", + "21034138", + "--etherscan-api-key", + next_mainnet_etherscan_api_key().as_str(), + "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "--json", + ]) + .assert_success() + .stdout_eq(file!["../fixtures/storage_layout_complex.json": Json]); +}); + casttest!(balance, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); let usdt = "0xdac17f958d2ee523a2206206994597c13d831ec7"; diff --git a/crates/cast/tests/fixtures/storage_layout_complex.json b/crates/cast/tests/fixtures/storage_layout_complex.json new file mode 100644 index 000000000000..2cad9dc8c221 --- /dev/null +++ b/crates/cast/tests/fixtures/storage_layout_complex.json @@ -0,0 +1,397 @@ +{ + "storage": [ + { + "astId": 3805, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_status", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 9499, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_generalPoolsBalances", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_bytes32,t_struct(IERC20ToBytes32Map)3177_storage)" + }, + { + "astId": 716, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_nextNonce", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 967, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_paused", + "offset": 0, + "slot": "3", + "type": "t_bool" + }, + { + "astId": 8639, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_authorizer", + "offset": 1, + "slot": "3", + "type": "t_contract(IAuthorizer)11086" + }, + { + "astId": 8645, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_approvedRelayers", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_mapping(t_address,t_bool))" + }, + { + "astId": 5769, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_isPoolRegistered", + "offset": 0, + "slot": "5", + "type": "t_mapping(t_bytes32,t_bool)" + }, + { + "astId": 5771, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_nextPoolNonce", + "offset": 0, + "slot": "6", + "type": "t_uint256" + }, + { + "astId": 9915, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_minimalSwapInfoPoolsBalances", + "offset": 0, + "slot": "7", + "type": "t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_bytes32))" + }, + { + "astId": 9919, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_minimalSwapInfoPoolsTokens", + "offset": 0, + "slot": "8", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)3520_storage)" + }, + { + "astId": 10373, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_twoTokenPoolTokens", + "offset": 0, + "slot": "9", + "type": "t_mapping(t_bytes32,t_struct(TwoTokenPoolTokens)10369_storage)" + }, + { + "astId": 4007, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_poolAssetManagers", + "offset": 0, + "slot": "10", + "type": "t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_address))" + }, + { + "astId": 8019, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_internalTokenBalance", + "offset": 0, + "slot": "11", + "type": "t_mapping(t_address,t_mapping(t_contract(IERC20)3793,t_uint256))" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32", + "base": "t_address" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IAuthorizer)11086": { + "encoding": "inplace", + "label": "contract IAuthorizer", + "numberOfBytes": "20" + }, + "t_contract(IERC20)3793": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_mapping(t_address,t_bool))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => bool))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_bool)" + }, + "t_mapping(t_address,t_mapping(t_contract(IERC20)3793,t_uint256))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(contract IERC20 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_contract(IERC20)3793,t_uint256)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_bytes32,t_bool)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_address))": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => mapping(contract IERC20 => address))", + "numberOfBytes": "32", + "value": "t_mapping(t_contract(IERC20)3793,t_address)" + }, + "t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_bytes32))": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => mapping(contract IERC20 => bytes32))", + "numberOfBytes": "32", + "value": "t_mapping(t_contract(IERC20)3793,t_bytes32)" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)3520_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct EnumerableSet.AddressSet)", + "numberOfBytes": "32", + "value": "t_struct(AddressSet)3520_storage" + }, + "t_mapping(t_bytes32,t_struct(IERC20ToBytes32Map)3177_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct EnumerableMap.IERC20ToBytes32Map)", + "numberOfBytes": "32", + "value": "t_struct(IERC20ToBytes32Map)3177_storage" + }, + "t_mapping(t_bytes32,t_struct(TwoTokenPoolBalances)10360_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolBalances)", + "numberOfBytes": "32", + "value": "t_struct(TwoTokenPoolBalances)10360_storage" + }, + "t_mapping(t_bytes32,t_struct(TwoTokenPoolTokens)10369_storage)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolTokens)", + "numberOfBytes": "32", + "value": "t_struct(TwoTokenPoolTokens)10369_storage" + }, + "t_mapping(t_contract(IERC20)3793,t_address)": { + "encoding": "mapping", + "key": "t_contract(IERC20)3793", + "label": "mapping(contract IERC20 => address)", + "numberOfBytes": "32", + "value": "t_address" + }, + "t_mapping(t_contract(IERC20)3793,t_bytes32)": { + "encoding": "mapping", + "key": "t_contract(IERC20)3793", + "label": "mapping(contract IERC20 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + }, + "t_mapping(t_contract(IERC20)3793,t_uint256)": { + "encoding": "mapping", + "key": "t_contract(IERC20)3793", + "label": "mapping(contract IERC20 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_uint256,t_struct(IERC20ToBytes32MapEntry)3166_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct EnumerableMap.IERC20ToBytes32MapEntry)", + "numberOfBytes": "32", + "value": "t_struct(IERC20ToBytes32MapEntry)3166_storage" + }, + "t_struct(AddressSet)3520_storage": { + "encoding": "inplace", + "label": "struct EnumerableSet.AddressSet", + "numberOfBytes": "64", + "members": [ + { + "astId": 3515, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_values", + "offset": 0, + "slot": "0", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 3519, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_indexes", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_uint256)" + } + ] + }, + "t_struct(IERC20ToBytes32Map)3177_storage": { + "encoding": "inplace", + "label": "struct EnumerableMap.IERC20ToBytes32Map", + "numberOfBytes": "96", + "members": [ + { + "astId": 3168, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_length", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 3172, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_entries", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_struct(IERC20ToBytes32MapEntry)3166_storage)" + }, + { + "astId": 3176, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_indexes", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_contract(IERC20)3793,t_uint256)" + } + ] + }, + "t_struct(IERC20ToBytes32MapEntry)3166_storage": { + "encoding": "inplace", + "label": "struct EnumerableMap.IERC20ToBytes32MapEntry", + "numberOfBytes": "64", + "members": [ + { + "astId": 3163, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_key", + "offset": 0, + "slot": "0", + "type": "t_contract(IERC20)3793" + }, + { + "astId": 3165, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "_value", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + } + ] + }, + "t_struct(TwoTokenPoolBalances)10360_storage": { + "encoding": "inplace", + "label": "struct TwoTokenPoolsBalance.TwoTokenPoolBalances", + "numberOfBytes": "64", + "members": [ + { + "astId": 10357, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "sharedCash", + "offset": 0, + "slot": "0", + "type": "t_bytes32" + }, + { + "astId": 10359, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "sharedManaged", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + } + ] + }, + "t_struct(TwoTokenPoolTokens)10369_storage": { + "encoding": "inplace", + "label": "struct TwoTokenPoolsBalance.TwoTokenPoolTokens", + "numberOfBytes": "96", + "members": [ + { + "astId": 10362, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "tokenA", + "offset": 0, + "slot": "0", + "type": "t_contract(IERC20)3793" + }, + { + "astId": 10364, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "tokenB", + "offset": 0, + "slot": "1", + "type": "t_contract(IERC20)3793" + }, + { + "astId": 10368, + "contract": "contracts/vault/Vault.sol:Vault", + "label": "balances", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_bytes32,t_struct(TwoTokenPoolBalances)10360_storage)" + } + ] + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + }, + "values": [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000006048a8c631fb7e77eca533cf9c29784e482391e7", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000006e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] +} \ No newline at end of file diff --git a/crates/cast/tests/fixtures/storage_layout_simple.json b/crates/cast/tests/fixtures/storage_layout_simple.json new file mode 100644 index 000000000000..35f4777d02b3 --- /dev/null +++ b/crates/cast/tests/fixtures/storage_layout_simple.json @@ -0,0 +1,36 @@ +{ + "storage": [ + { + "astId": 7, + "contract": "contracts/Create2Deployer.sol:Create2Deployer", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 122, + "contract": "contracts/Create2Deployer.sol:Create2Deployer", + "label": "_paused", + "offset": 20, + "slot": "0", + "type": "t_bool" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + } + }, + "values": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] +} \ No newline at end of file From 60dd1d7fe9879008a52da40eb74d5b6706d00b78 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 18 Nov 2024 18:24:53 +0200 Subject: [PATCH 3/8] feat(`config`): set default evm version to cancun (#9131) * chore: Update to Cancun * cancun to TEST_DATA_DEFAULT, add TEST_DATA_PARIS * Shanghai compat test * Redact gaswaster address --- crates/config/src/lib.rs | 2 +- crates/forge/src/multi_runner.rs | 2 +- crates/forge/tests/cli/build.rs | 6 +- crates/forge/tests/cli/cmd.rs | 462 +++++++++--------- crates/forge/tests/cli/compiler.rs | 2 +- crates/forge/tests/cli/config.rs | 37 ++ crates/forge/tests/cli/ext_integration.rs | 1 + crates/forge/tests/cli/script.rs | 40 +- crates/forge/tests/cli/test_cmd.rs | 86 ++-- crates/forge/tests/it/cheats.rs | 8 +- crates/forge/tests/it/core.rs | 27 +- crates/forge/tests/it/fork.rs | 8 +- crates/forge/tests/it/fuzz.rs | 4 +- crates/forge/tests/it/repros.rs | 5 +- crates/forge/tests/it/spec.rs | 4 +- crates/forge/tests/it/test_helpers.rs | 28 +- .../cheats/BlobBaseFee.t.sol | 0 .../cheats/Blobhashes.t.sol | 0 testdata/default/cheats/Etch.t.sol | 2 +- testdata/default/repros/Issue5929.t.sol | 4 +- testdata/default/repros/Issue6538.t.sol | 4 +- testdata/default/repros/Issue8006.t.sol | 6 +- testdata/paris/cheats/Fork.t.sol | 125 +++++ .../cheats/GasSnapshots.t.sol | 0 .../cheats/LastCallGas.t.sol | 0 .../core/BeforeTest.t.sol} | 2 +- .../{default => paris}/fork/Transact.t.sol | 2 +- testdata/paris/spec/ShanghaiCompat.t.sol | 29 ++ 28 files changed, 555 insertions(+), 341 deletions(-) rename testdata/{cancun => default}/cheats/BlobBaseFee.t.sol (100%) rename testdata/{cancun => default}/cheats/Blobhashes.t.sol (100%) create mode 100644 testdata/paris/cheats/Fork.t.sol rename testdata/{default => paris}/cheats/GasSnapshots.t.sol (100%) rename testdata/{default => paris}/cheats/LastCallGas.t.sol (100%) rename testdata/{default/repros/Issue1543.t.sol => paris/core/BeforeTest.t.sol} (98%) rename testdata/{default => paris}/fork/Transact.t.sol (99%) create mode 100644 testdata/paris/spec/ShanghaiCompat.t.sol diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 986a0181dd73..b87eadcefa0b 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -2149,7 +2149,7 @@ impl Default for Config { allow_paths: vec![], include_paths: vec![], force: false, - evm_version: EvmVersion::Paris, + evm_version: EvmVersion::Cancun, gas_reports: vec!["*".to_string()], gas_reports_ignore: vec![], gas_reports_include_tests: false, diff --git a/crates/forge/src/multi_runner.rs b/crates/forge/src/multi_runner.rs index e7361db0004f..a9f2a93eb37a 100644 --- a/crates/forge/src/multi_runner.rs +++ b/crates/forge/src/multi_runner.rs @@ -449,7 +449,7 @@ impl MultiContractRunnerBuilder { contracts: deployable_contracts, evm_opts, env, - evm_spec: self.evm_spec.unwrap_or(SpecId::MERGE), + evm_spec: self.evm_spec.unwrap_or(SpecId::CANCUN), sender: self.sender, revert_decoder, fork: self.fork, diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index dd2545995753..51c358612e86 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -78,7 +78,7 @@ forgetest!(initcode_size_exceeds_limit, |prj, cmd| { ... | Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | |--------------|------------------|-------------------|--------------------|---------------------| -| HugeContract | 202 | 49,359 | 24,374 | -207 | +| HugeContract | 194 | 49,344 | 24,382 | -192 | ... "# ]); @@ -105,7 +105,7 @@ forgetest!(initcode_size_limit_can_be_ignored, |prj, cmd| { ... | Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | |--------------|------------------|-------------------|--------------------|---------------------| -| HugeContract | 202 | 49,359 | 24,374 | -207 | +| HugeContract | 194 | 49,344 | 24,382 | -192 | ... "# ]); @@ -145,7 +145,7 @@ forgetest_init!(build_sizes_no_forge_std, |prj, cmd| { ... | Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | |----------|------------------|-------------------|--------------------|---------------------| -| Counter | 247 | 277 | 24,329 | 48,875 | +| Counter | 236 | 263 | 24,340 | 48,889 | ... "# ]); diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 1e887791e569..18f0327f6e90 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1582,25 +1582,25 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]); @@ -1610,48 +1610,48 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } }, { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } }, { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -1666,25 +1666,25 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]); @@ -1694,48 +1694,48 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } }, { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } }, { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -1750,25 +1750,25 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]); @@ -1778,48 +1778,48 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } }, { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } }, { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -1841,25 +1841,25 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]); @@ -1869,48 +1869,48 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } }, { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } }, { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -1932,9 +1932,9 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | ... "#]]); @@ -1944,16 +1944,16 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } } @@ -1970,9 +1970,9 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]); @@ -1982,16 +1982,16 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -2011,9 +2011,9 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | ... "#]]); @@ -2023,16 +2023,16 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } } @@ -2058,17 +2058,17 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]); @@ -2078,32 +2078,32 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } }, { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -2125,17 +2125,17 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | ... "#]]); @@ -2145,32 +2145,32 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } }, { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } } @@ -2203,25 +2203,25 @@ forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101532 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| foo | 45387 | 45387 | 45387 | 45387 | 1 | +| foo | 45370 | 45370 | 45370 | 45370 | 1 | | src/Contracts.sol:ContractThree contract | | | | | | |------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 103591 | 256 | | | | | +| 101748 | 242 | | | | | | Function Name | min | avg | median | max | # calls | -| baz | 260712 | 260712 | 260712 | 260712 | 1 | +| baz | 259210 | 259210 | 259210 | 259210 | 1 | | src/Contracts.sol:ContractTwo contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 103375 | 255 | | | | | +| 101520 | 241 | | | | | | Function Name | min | avg | median | max | # calls | -| bar | 64984 | 64984 | 64984 | 64984 | 1 | +| bar | 64832 | 64832 | 64832 | 64832 | 1 | ... "#]]) .stderr_eq(str![[r#" @@ -2240,48 +2240,48 @@ Warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. { "contract": "src/Contracts.sol:ContractOne", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101532, + "size": 241 }, "functions": { "foo()": { "calls": 1, - "min": 45387, - "mean": 45387, - "median": 45387, - "max": 45387 + "min": 45370, + "mean": 45370, + "median": 45370, + "max": 45370 } } }, { "contract": "src/Contracts.sol:ContractThree", "deployment": { - "gas": 103591, - "size": 256 + "gas": 101748, + "size": 242 }, "functions": { "baz()": { "calls": 1, - "min": 260712, - "mean": 260712, - "median": 260712, - "max": 260712 + "min": 259210, + "mean": 259210, + "median": 259210, + "max": 259210 } } }, { "contract": "src/Contracts.sol:ContractTwo", "deployment": { - "gas": 103375, - "size": 255 + "gas": 101520, + "size": 241 }, "functions": { "bar()": { "calls": 1, - "min": 64984, - "mean": 64984, - "median": 64984, - "max": 64984 + "min": 64832, + "mean": 64832, + "median": 64832, + "max": 64832 } } } @@ -2346,12 +2346,12 @@ contract CounterTest is DSTest { | src/Counter.sol:Counter contract | | | | | | |----------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 101137 | 250 | | | | | +| 99711 | 240 | | | | | | Function Name | min | avg | median | max | # calls | -| a | 2261 | 2261 | 2261 | 2261 | 1 | -| b | 2305 | 2305 | 2305 | 2305 | 1 | -| setNumber(int256) | 23648 | 33604 | 33604 | 43560 | 2 | -| setNumber(uint256) | 23604 | 33560 | 33560 | 43516 | 2 | +| a | 2259 | 2259 | 2259 | 2259 | 1 | +| b | 2304 | 2304 | 2304 | 2304 | 1 | +| setNumber(int256) | 23646 | 33602 | 33602 | 43558 | 2 | +| setNumber(uint256) | 23601 | 33557 | 33557 | 43513 | 2 | ... "#]]); cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( @@ -2360,37 +2360,37 @@ contract CounterTest is DSTest { { "contract": "src/Counter.sol:Counter", "deployment": { - "gas": 101137, - "size": 250 + "gas": 99711, + "size": 240 }, "functions": { "a()": { "calls": 1, - "min": 2261, - "mean": 2261, - "median": 2261, - "max": 2261 + "min": 2259, + "mean": 2259, + "median": 2259, + "max": 2259 }, "b()": { "calls": 1, - "min": 2305, - "mean": 2305, - "median": 2305, - "max": 2305 + "min": 2304, + "mean": 2304, + "median": 2304, + "max": 2304 }, "setNumber(int256)": { "calls": 2, - "min": 23648, - "mean": 33604, - "median": 33604, - "max": 43560 + "min": 23646, + "mean": 33602, + "median": 33602, + "max": 43558 }, "setNumber(uint256)": { "calls": 2, - "min": 23604, - "mean": 33560, - "median": 33560, - "max": 43516 + "min": 23601, + "mean": 33557, + "median": 33557, + "max": 43513 } } } @@ -2973,7 +2973,7 @@ forgetest_init!(can_build_sizes_repeatedly, |prj, cmd| { Compiler run successful! | Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | |----------|------------------|-------------------|--------------------|---------------------| -| Counter | 247 | 277 | 24,329 | 48,875 | +| Counter | 236 | 263 | 24,340 | 48,889 | "#]]); @@ -3042,20 +3042,20 @@ forgetest_init!(gas_report_include_tests, |prj, cmd| { | src/Counter.sol:Counter contract | | | | | | |----------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 106715 | 277 | | | | | +| 104475 | 263 | | | | | | Function Name | min | avg | median | max | # calls | -| increment | 43404 | 43404 | 43404 | 43404 | 1 | -| number | 283 | 283 | 283 | 283 | 1 | -| setNumber | 23582 | 23582 | 23582 | 23582 | 1 | +| increment | 43401 | 43401 | 43401 | 43401 | 1 | +| number | 281 | 281 | 281 | 281 | 1 | +| setNumber | 23579 | 23579 | 23579 | 23579 | 1 | | test/Counter.t.sol:CounterTest contract | | | | | | |-----------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | -| 965418 | 4661 | | | | | +| 938190 | 4522 | | | | | | Function Name | min | avg | median | max | # calls | -| setUp | 168064 | 168064 | 168064 | 168064 | 1 | -| test_Increment | 52367 | 52367 | 52367 | 52367 | 1 | +| setUp | 165834 | 165834 | 165834 | 165834 | 1 | +| test_Increment | 52357 | 52357 | 52357 | 52357 | 1 | ... "#] @@ -3070,53 +3070,53 @@ forgetest_init!(gas_report_include_tests, |prj, cmd| { { "contract": "src/Counter.sol:Counter", "deployment": { - "gas": 106715, - "size": 277 + "gas": 104475, + "size": 263 }, "functions": { "increment()": { "calls": 1, - "min": 43404, - "mean": 43404, - "median": 43404, - "max": 43404 + "min": 43401, + "mean": 43401, + "median": 43401, + "max": 43401 }, "number()": { "calls": 1, - "min": 283, - "mean": 283, - "median": 283, - "max": 283 + "min": 281, + "mean": 281, + "median": 281, + "max": 281 }, "setNumber(uint256)": { "calls": 1, - "min": 23582, - "mean": 23582, - "median": 23582, - "max": 23582 + "min": 23579, + "mean": 23579, + "median": 23579, + "max": 23579 } } }, { "contract": "test/Counter.t.sol:CounterTest", "deployment": { - "gas": 965418, - "size": 4661 + "gas": 938190, + "size": 4522 }, "functions": { "setUp()": { "calls": 1, - "min": 168064, - "mean": 168064, - "median": 168064, - "max": 168064 + "min": 165834, + "mean": 165834, + "median": 165834, + "max": 165834 }, "test_Increment()": { "calls": 1, - "min": 52367, - "mean": 52367, - "median": 52367, - "max": 52367 + "min": 52357, + "mean": 52357, + "median": 52357, + "max": 52357 } } } diff --git a/crates/forge/tests/cli/compiler.rs b/crates/forge/tests/cli/compiler.rs index b8453b67b944..0b58221f2a1d 100644 --- a/crates/forge/tests/cli/compiler.rs +++ b/crates/forge/tests/cli/compiler.rs @@ -242,7 +242,7 @@ Solidity: Vyper: -0.4.0 (<= [..]): +0.4.0 (<= cancun): ├── src/Counter.vy └── src/ICounter.vyi diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 91e0781afb1d..11bcd49e2c40 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -776,6 +776,43 @@ forgetest!(normalize_config_evm_version, |_prj, cmd| { .stdout_lossy(); let config: Config = serde_json::from_str(&output).unwrap(); assert_eq!(config.evm_version, EvmVersion::Istanbul); + + // See + let output = cmd + .forge_fuse() + .args(["config", "--use", "0.8.17", "--json"]) + .assert_success() + .get_output() + .stdout_lossy(); + let config: Config = serde_json::from_str(&output).unwrap(); + assert_eq!(config.evm_version, EvmVersion::London); + + let output = cmd + .forge_fuse() + .args(["config", "--use", "0.8.18", "--json"]) + .assert_success() + .get_output() + .stdout_lossy(); + let config: Config = serde_json::from_str(&output).unwrap(); + assert_eq!(config.evm_version, EvmVersion::Paris); + + let output = cmd + .forge_fuse() + .args(["config", "--use", "0.8.23", "--json"]) + .assert_success() + .get_output() + .stdout_lossy(); + let config: Config = serde_json::from_str(&output).unwrap(); + assert_eq!(config.evm_version, EvmVersion::Shanghai); + + let output = cmd + .forge_fuse() + .args(["config", "--use", "0.8.26", "--json"]) + .assert_success() + .get_output() + .stdout_lossy(); + let config: Config = serde_json::from_str(&output).unwrap(); + assert_eq!(config.evm_version, EvmVersion::Cancun); }); // Tests that root paths are properly resolved even if submodule specifies remappings for them. diff --git a/crates/forge/tests/cli/ext_integration.rs b/crates/forge/tests/cli/ext_integration.rs index f0b1c5144ad3..b2747e3ccb80 100644 --- a/crates/forge/tests/cli/ext_integration.rs +++ b/crates/forge/tests/cli/ext_integration.rs @@ -89,6 +89,7 @@ fn stringutils() { fn lootloose() { ExtTester::new("gakonst", "lootloose", "7b639efe97836155a6a6fc626bf1018d4f8b2495") .install_command(&["make", "install"]) + .args(["--evm-version", "paris"]) .run(); } diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 901ef592211d..82c61ccbc388 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -230,7 +230,7 @@ Traces: ├─ [0] VM::startBroadcast() │ └─ ← [Return] ├─ [..] → new GasWaster@[..] - │ └─ ← [Return] 226 bytes of code + │ └─ ← [Return] 221 bytes of code ├─ [..] GasWaster::wasteGas(200000 [2e5]) │ └─ ← [Stop] └─ ← [Stop] @@ -242,10 +242,10 @@ Script ran successfully. ========================== Simulated On-chain Traces: - [45299] → new GasWaster@[..] - └─ ← [Return] 226 bytes of code + [44291] → new GasWaster@[..] + └─ ← [Return] 221 bytes of code - [226] GasWaster::wasteGas(200000 [2e5]) + [224] GasWaster::wasteGas(200000 [2e5]) └─ ← [Stop] @@ -337,7 +337,7 @@ Traces: ├─ [0] VM::startBroadcast() │ └─ ← [Return] ├─ [..] → new GasWaster@[..] - │ └─ ← [Return] 226 bytes of code + │ └─ ← [Return] 221 bytes of code ├─ [..] GasWaster::wasteGas(200000 [2e5]) │ └─ ← [Stop] └─ ← [Stop] @@ -349,10 +349,10 @@ Script ran successfully. ========================== Simulated On-chain Traces: - [45299] → new GasWaster@[..] - └─ ← [Return] 226 bytes of code + [44291] → new GasWaster@[..] + └─ ← [Return] 221 bytes of code - [226] GasWaster::wasteGas(200000 [2e5]) + [224] GasWaster::wasteGas(200000 [2e5]) └─ ← [Stop] @@ -522,7 +522,7 @@ Traces: ├─ [0] VM::startBroadcast() │ └─ ← [Return] ├─ [..] → new HashChecker@[..] - │ └─ ← [Return] 378 bytes of code + │ └─ ← [Return] 368 bytes of code └─ ← [Stop] @@ -2219,15 +2219,15 @@ contract SimpleScript is Script { [SOLC_VERSION] [ELAPSED] Compiler run successful! Traces: - [104553] SimpleScript::run() + [103771] SimpleScript::run() ├─ [0] VM::startBroadcast() │ └─ ← [Return] - ├─ [23875] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519 - │ └─ ← [Return] 119 bytes of code - ├─ [13367] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 - │ ├─ [146] A::getValue() [staticcall] + ├─ [23273] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519 + │ └─ ← [Return] 116 bytes of code + ├─ [13162] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 + │ ├─ [145] A::getValue() [staticcall] │ │ └─ ← [Return] 100 - │ └─ ← [Return] 63 bytes of code + │ └─ ← [Return] 62 bytes of code └─ ← [Stop] @@ -2237,13 +2237,13 @@ Script ran successfully. ========================== Simulated On-chain Traces: - [23875] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519 - └─ ← [Return] 119 bytes of code + [23273] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519 + └─ ← [Return] 116 bytes of code - [15867] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 - ├─ [146] A::getValue() [staticcall] + [15662] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 + ├─ [145] A::getValue() [staticcall] │ └─ ← [Return] 100 - └─ ← [Return] 63 bytes of code + └─ ← [Return] 62 bytes of code ... "#]]); }); diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 8389c381ef9f..f51cf6703a17 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -575,7 +575,7 @@ Compiler run successful! Ran 1 test for test/Contract.t.sol:USDTCallingTest [PASS] test() ([GAS]) Traces: - [9516] USDTCallingTest::test() + [9406] USDTCallingTest::test() ├─ [0] VM::createSelectFork("[..]") │ └─ ← [Return] 0 ├─ [3110] 0xdAC17F958D2ee523a2206206994597C13D831ec7::name() [staticcall] @@ -621,12 +621,12 @@ Compiler run successful! Ran 2 tests for test/Contract.t.sol:CustomTypesTest [FAIL: PoolNotInitialized()] testErr() ([GAS]) Traces: - [254] CustomTypesTest::testErr() + [253] CustomTypesTest::testErr() └─ ← [Revert] PoolNotInitialized() [PASS] testEvent() ([GAS]) Traces: - [1268] CustomTypesTest::testEvent() + [1267] CustomTypesTest::testEvent() ├─ emit MyEvent(a: 100) └─ ← [Stop] @@ -996,7 +996,7 @@ Compiler run successful! Ran 1 test for test/Contract.t.sol:PrecompileLabelsTest [PASS] testPrecompileLabels() ([GAS]) Traces: - [9474] PrecompileLabelsTest::testPrecompileLabels() + [9383] PrecompileLabelsTest::testPrecompileLabels() ├─ [0] VM::deal(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 1000000000000000000 [1e18]) │ └─ ← [Return] ├─ [0] VM::deal(console: [0x000000000000000000636F6e736F6c652e6c6f67], 1000000000000000000 [1e18]) @@ -1264,17 +1264,17 @@ Compiler run successful! Ran 1 test for test/Simple.sol:SimpleContractTest [PASS] test() ([GAS]) Traces: - [250463] SimpleContractTest::test() - ├─ [171014] → new SimpleContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f - │ └─ ← [Return] 854 bytes of code - ├─ [22638] SimpleContract::increment() - │ ├─ [20150] SimpleContract::_setNum(1) + [244864] SimpleContractTest::test() + ├─ [165406] → new SimpleContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + │ └─ ← [Return] 826 bytes of code + ├─ [22630] SimpleContract::increment() + │ ├─ [20147] SimpleContract::_setNum(1) │ │ └─ ← 0 │ └─ ← [Stop] - ├─ [23219] SimpleContract::setValues(100, 0x0000000000000000000000000000000000000123) - │ ├─ [250] SimpleContract::_setNum(100) + ├─ [23204] SimpleContract::setValues(100, 0x0000000000000000000000000000000000000123) + │ ├─ [247] SimpleContract::_setNum(100) │ │ └─ ← 1 - │ ├─ [22339] SimpleContract::_setAddr(0x0000000000000000000000000000000000000123) + │ ├─ [22336] SimpleContract::_setAddr(0x0000000000000000000000000000000000000123) │ │ └─ ← 0x0000000000000000000000000000000000000000 │ └─ ← [Stop] └─ ← [Stop] @@ -1326,11 +1326,11 @@ contract SimpleContractTest is Test { r#" ... Traces: - [421947] SimpleContractTest::test() - ├─ [385978] → new SimpleContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f - │ └─ ← [Return] 1814 bytes of code - ├─ [2534] SimpleContract::setStr("new value") - │ ├─ [1600] SimpleContract::_setStr("new value") + [406629] SimpleContractTest::test() + ├─ [370554] → new SimpleContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + │ └─ ← [Return] 1737 bytes of code + ├─ [2511] SimpleContract::setStr("new value") + │ ├─ [1588] SimpleContract::_setStr("new value") │ │ └─ ← "initial value" │ └─ ← [Stop] └─ ← [Stop] @@ -1460,10 +1460,10 @@ contract ATest is Test { cmd.args(["test"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... -[PASS] testNormalGas() (gas: 3202) -[PASS] testWeirdGas1() (gas: 3040) -[PASS] testWeirdGas2() (gas: 3148) -[PASS] testWithAssembly() (gas: 3083) +[PASS] testNormalGas() (gas: 3194) +[PASS] testWeirdGas1() (gas: 3032) +[PASS] testWeirdGas2() (gas: 3139) +[PASS] testWithAssembly() (gas: 3075) ... "#]]); }); @@ -1548,9 +1548,9 @@ contract ATest is Test { cmd.args(["test", "-vvvv"]).with_no_redact().assert_success().stdout_eq(str![[r#" ... Logs: - Gas cost: 34468 + Gas cost: 34367 ... -[PASS] test_GasMeter() (gas: 37512) +[PASS] test_GasMeter() (gas: 37407) ... "#]]); }); @@ -1635,33 +1635,33 @@ contract PauseTracingTest is DSTest { cmd.args(["test", "-vvvvv"]).assert_success().stdout_eq(str![[r#" ... Traces: - [7285] PauseTracingTest::setUp() + [7282] PauseTracingTest::setUp() ├─ emit DummyEvent(i: 1) ├─ [0] VM::pauseTracing() [staticcall] │ └─ ← [Return] └─ ← [Stop] - [294725] PauseTracingTest::test() + [282512] PauseTracingTest::test() ├─ [0] VM::resumeTracing() [staticcall] │ └─ ← [Return] - ├─ [18373] TraceGenerator::generate() - │ ├─ [1280] TraceGenerator::call(0) + ├─ [18327] TraceGenerator::generate() + │ ├─ [1278] TraceGenerator::call(0) │ │ ├─ emit DummyEvent(i: 0) │ │ └─ ← [Stop] - │ ├─ [1280] TraceGenerator::call(1) + │ ├─ [1278] TraceGenerator::call(1) │ │ ├─ emit DummyEvent(i: 1) │ │ └─ ← [Stop] - │ ├─ [1280] TraceGenerator::call(2) + │ ├─ [1278] TraceGenerator::call(2) │ │ ├─ emit DummyEvent(i: 2) │ │ └─ ← [Stop] │ ├─ [0] VM::pauseTracing() [staticcall] │ │ └─ ← [Return] │ ├─ [0] VM::resumeTracing() [staticcall] │ │ └─ ← [Return] - │ ├─ [1280] TraceGenerator::call(8) + │ ├─ [1278] TraceGenerator::call(8) │ │ ├─ emit DummyEvent(i: 8) │ │ └─ ← [Stop] - │ ├─ [1280] TraceGenerator::call(9) + │ ├─ [1278] TraceGenerator::call(9) │ │ ├─ emit DummyEvent(i: 9) │ │ └─ ← [Stop] │ └─ ← [Stop] @@ -2357,11 +2357,11 @@ Compiler run successful! Ran 1 test for test/MetadataTraceTest.t.sol:MetadataTraceTest [PASS] test_proxy_trace() ([GAS]) Traces: - [152142] MetadataTraceTest::test_proxy_trace() - ├─ [49499] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f - │ └─ ← [Return] 247 bytes of code - ├─ [37978] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b - │ └─ ← [Return] 63 bytes of code + [149783] MetadataTraceTest::test_proxy_trace() + ├─ [47297] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + │ └─ ← [Return] 236 bytes of code + ├─ [37762] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b + │ └─ ← [Return] 62 bytes of code └─ ← [Stop] Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] @@ -2382,11 +2382,11 @@ Compiler run successful! Ran 1 test for test/MetadataTraceTest.t.sol:MetadataTraceTest [PASS] test_proxy_trace() ([GAS]) Traces: - [130521] MetadataTraceTest::test_proxy_trace() - ├─ [38693] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f - │ └─ ← [Return] 193 bytes of code - ├─ [27175] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b - │ └─ ← [Return] 9 bytes of code + [128142] MetadataTraceTest::test_proxy_trace() + ├─ [36485] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + │ └─ ← [Return] 182 bytes of code + ├─ [26959] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b + │ └─ ← [Return] 8 bytes of code └─ ← [Stop] Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] @@ -2561,7 +2561,7 @@ forgetest_async!(can_get_broadcast_txs, |prj, cmd| { 31337 ); - assertEq(deployedAddress, address(0x030D07c16e2c0a77f74ab16f3C8F10ACeF89FF81)); + assertEq(deployedAddress, address(0x78280279172ED4C0E65BCE5Ee9DFdcd828f837DB)); } function test_getDeployments() public { @@ -2571,7 +2571,7 @@ forgetest_async!(can_get_broadcast_txs, |prj, cmd| { ); assertEq(deployments.length, 2); - assertEq(deployments[0], address(0x030D07c16e2c0a77f74ab16f3C8F10ACeF89FF81)); // Create2 address - latest deployment + assertEq(deployments[0], address(0x78280279172ED4C0E65BCE5Ee9DFdcd828f837DB)); // Create2 address - latest deployment assertEq(deployments[1], address(0x5FbDB2315678afecb367f032d93F642f64180aa3)); // Create address - oldest deployment } diff --git a/crates/forge/tests/it/cheats.rs b/crates/forge/tests/it/cheats.rs index a60602cbc1cc..871cda045fa7 100644 --- a/crates/forge/tests/it/cheats.rs +++ b/crates/forge/tests/it/cheats.rs @@ -3,8 +3,8 @@ use crate::{ config::*, test_helpers::{ - ForgeTestData, RE_PATH_SEPARATOR, TEST_DATA_CANCUN, TEST_DATA_DEFAULT, - TEST_DATA_MULTI_VERSION, + ForgeTestData, RE_PATH_SEPARATOR, TEST_DATA_DEFAULT, TEST_DATA_MULTI_VERSION, + TEST_DATA_PARIS, }, }; use alloy_primitives::U256; @@ -77,6 +77,6 @@ async fn test_cheats_local_multi_version() { } #[tokio::test(flavor = "multi_thread")] -async fn test_cheats_local_cancun() { - test_cheats_local(&TEST_DATA_CANCUN).await +async fn test_cheats_local_paris() { + test_cheats_local(&TEST_DATA_PARIS).await } diff --git a/crates/forge/tests/it/core.rs b/crates/forge/tests/it/core.rs index 17d9f59d88fa..abab87d2866e 100644 --- a/crates/forge/tests/it/core.rs +++ b/crates/forge/tests/it/core.rs @@ -1,6 +1,9 @@ //! Forge tests for core functionality. -use crate::{config::*, test_helpers::TEST_DATA_DEFAULT}; +use crate::{ + config::*, + test_helpers::{TEST_DATA_DEFAULT, TEST_DATA_PARIS}, +}; use forge::result::SuiteResult; use foundry_evm::traces::TraceKind; use foundry_test_utils::Filter; @@ -803,3 +806,25 @@ async fn test_legacy_assertions() { )]), ); } + +/// Test `beforeTest` functionality and `selfdestruct`. +/// See +#[tokio::test(flavor = "multi_thread")] +async fn test_before_setup_with_selfdestruct() { + let filter = Filter::new(".*", ".*BeforeTestSelfDestructTest", ".*"); + let results = TEST_DATA_PARIS.runner().test_collect(&filter); + + assert_multiple( + &results, + BTreeMap::from([( + "paris/core/BeforeTest.t.sol:BeforeTestSelfDestructTest", + vec![ + ("testKill()", true, None, None, None), + ("testA()", true, None, None, None), + ("testSimpleA()", true, None, None, None), + ("testB()", true, None, None, None), + ("testC(uint256)", true, None, None, None), + ], + )]), + ); +} diff --git a/crates/forge/tests/it/fork.rs b/crates/forge/tests/it/fork.rs index 26c45aa184e5..8dc637528ddd 100644 --- a/crates/forge/tests/it/fork.rs +++ b/crates/forge/tests/it/fork.rs @@ -2,7 +2,7 @@ use crate::{ config::*, - test_helpers::{RE_PATH_SEPARATOR, TEST_DATA_DEFAULT}, + test_helpers::{RE_PATH_SEPARATOR, TEST_DATA_DEFAULT, TEST_DATA_PARIS}, }; use alloy_chains::Chain; use forge::result::SuiteResult; @@ -35,9 +35,9 @@ async fn test_cheats_fork_revert() { /// Executes all non-reverting fork cheatcodes #[tokio::test(flavor = "multi_thread")] async fn test_cheats_fork() { - let mut config = TEST_DATA_DEFAULT.config.clone(); + let mut config = TEST_DATA_PARIS.config.clone(); config.fs_permissions = FsPermissions::new(vec![PathPermission::read("./fixtures")]); - let runner = TEST_DATA_DEFAULT.runner_with_config(config); + let runner = TEST_DATA_PARIS.runner_with_config(config); let filter = Filter::new(".*", ".*", &format!(".*cheats{RE_PATH_SEPARATOR}Fork")) .exclude_tests(".*Revert"); TestConfig::with_filter(runner, filter).run().await; @@ -86,7 +86,7 @@ async fn test_launch_fork_ws() { /// Tests that we can transact transactions in forking mode #[tokio::test(flavor = "multi_thread")] async fn test_transact_fork() { - let runner = TEST_DATA_DEFAULT.runner(); + let runner = TEST_DATA_PARIS.runner(); let filter = Filter::new(".*", ".*", &format!(".*fork{RE_PATH_SEPARATOR}Transact")); TestConfig::with_filter(runner, filter).run().await; } diff --git a/crates/forge/tests/it/fuzz.rs b/crates/forge/tests/it/fuzz.rs index d6b047a17a93..8972c9bd98f1 100644 --- a/crates/forge/tests/it/fuzz.rs +++ b/crates/forge/tests/it/fuzz.rs @@ -203,10 +203,10 @@ contract FuzzerDictTest is Test { .unwrap(); // Test that immutable address is used as fuzzed input, causing test to fail. - cmd.args(["test", "--fuzz-seed", "100", "--mt", "testImmutableOwner"]).assert_failure(); + cmd.args(["test", "--fuzz-seed", "119", "--mt", "testImmutableOwner"]).assert_failure(); // Test that storage address is used as fuzzed input, causing test to fail. cmd.forge_fuse() - .args(["test", "--fuzz-seed", "100", "--mt", "testStorageOwner"]) + .args(["test", "--fuzz-seed", "119", "--mt", "testStorageOwner"]) .assert_failure(); }); diff --git a/crates/forge/tests/it/repros.rs b/crates/forge/tests/it/repros.rs index 9f46e3c2ec1f..53185cf97856 100644 --- a/crates/forge/tests/it/repros.rs +++ b/crates/forge/tests/it/repros.rs @@ -377,14 +377,11 @@ test_repro!(8383, false, None, |res| { let test = res.test_results.remove("testP256VerifyOutOfBounds()").unwrap(); assert_eq!(test.status, TestStatus::Success); match test.kind { - TestKind::Unit { gas } => assert_eq!(gas, 3103), + TestKind::Unit { gas } => assert_eq!(gas, 3101), _ => panic!("not a unit test kind"), } }); -// https://github.com/foundry-rs/foundry/issues/1543 -test_repro!(1543); - // https://github.com/foundry-rs/foundry/issues/6643 test_repro!(6643); diff --git a/crates/forge/tests/it/spec.rs b/crates/forge/tests/it/spec.rs index db98a15d1af2..aed2063a0fba 100644 --- a/crates/forge/tests/it/spec.rs +++ b/crates/forge/tests/it/spec.rs @@ -1,13 +1,13 @@ //! Integration tests for EVM specifications. -use crate::{config::*, test_helpers::TEST_DATA_DEFAULT}; +use crate::{config::*, test_helpers::TEST_DATA_PARIS}; use foundry_evm::revm::primitives::SpecId; use foundry_test_utils::Filter; #[tokio::test(flavor = "multi_thread")] async fn test_shanghai_compat() { let filter = Filter::new("", "ShanghaiCompat", ".*spec"); - TestConfig::with_filter(TEST_DATA_DEFAULT.runner(), filter) + TestConfig::with_filter(TEST_DATA_PARIS.runner(), filter) .evm_spec(SpecId::SHANGHAI) .run() .await; diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index eb5a0bf0a3c0..5e540d8c67aa 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -34,7 +34,7 @@ static VYPER: LazyLock = LazyLock::new(|| std::env::temp_dir().join("vy /// Profile for the tests group. Used to configure separate configurations for test runs. pub enum ForgeTestProfile { Default, - Cancun, + Paris, MultiVersion, } @@ -42,16 +42,16 @@ impl fmt::Display for ForgeTestProfile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Default => write!(f, "default"), - Self::Cancun => write!(f, "cancun"), + Self::Paris => write!(f, "paris"), Self::MultiVersion => write!(f, "multi-version"), } } } impl ForgeTestProfile { - /// Returns true if the profile is Cancun. - pub fn is_cancun(&self) -> bool { - matches!(self, Self::Cancun) + /// Returns true if the profile is Paris. + pub fn is_paris(&self) -> bool { + matches!(self, Self::Paris) } pub fn root(&self) -> PathBuf { @@ -66,8 +66,8 @@ impl ForgeTestProfile { let mut settings = Settings { libraries: Libraries::parse(&libs).unwrap(), ..Default::default() }; - if matches!(self, Self::Cancun) { - settings.evm_version = Some(EvmVersion::Cancun); + if matches!(self, Self::Paris) { + settings.evm_version = Some(EvmVersion::Paris); } let settings = SolcConfig::builder().settings(settings).build(); @@ -155,8 +155,8 @@ impl ForgeTestProfile { "fork/Fork.t.sol:DssExecLib:0xfD88CeE74f7D78697775aBDAE53f9Da1559728E4".to_string(), ]; - if self.is_cancun() { - config.evm_version = EvmVersion::Cancun; + if self.is_paris() { + config.evm_version = EvmVersion::Paris; } config @@ -195,8 +195,8 @@ impl ForgeTestData { let mut runner = MultiContractRunnerBuilder::new(Arc::new(self.config.clone())) .sender(self.evm_opts.sender) .with_test_options(self.test_opts.clone()); - if self.profile.is_cancun() { - runner = runner.evm_spec(SpecId::CANCUN); + if self.profile.is_paris() { + runner = runner.evm_spec(SpecId::MERGE); } runner @@ -338,9 +338,9 @@ pub fn get_compiled(project: &mut Project) -> ProjectCompileOutput { pub static TEST_DATA_DEFAULT: LazyLock = LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Default)); -/// Data for tests requiring Cancun support on Solc and EVM level. -pub static TEST_DATA_CANCUN: LazyLock = - LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Cancun)); +/// Data for tests requiring Paris support on Solc and EVM level. +pub static TEST_DATA_PARIS: LazyLock = + LazyLock::new(|| ForgeTestData::new(ForgeTestProfile::Paris)); /// Data for tests requiring Cancun support on Solc and EVM level. pub static TEST_DATA_MULTI_VERSION: LazyLock = diff --git a/testdata/cancun/cheats/BlobBaseFee.t.sol b/testdata/default/cheats/BlobBaseFee.t.sol similarity index 100% rename from testdata/cancun/cheats/BlobBaseFee.t.sol rename to testdata/default/cheats/BlobBaseFee.t.sol diff --git a/testdata/cancun/cheats/Blobhashes.t.sol b/testdata/default/cheats/Blobhashes.t.sol similarity index 100% rename from testdata/cancun/cheats/Blobhashes.t.sol rename to testdata/default/cheats/Blobhashes.t.sol diff --git a/testdata/default/cheats/Etch.t.sol b/testdata/default/cheats/Etch.t.sol index 33eaaf44ef87..f60ea4cad650 100644 --- a/testdata/default/cheats/Etch.t.sol +++ b/testdata/default/cheats/Etch.t.sol @@ -8,7 +8,7 @@ contract EtchTest is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function testEtch() public { - address target = address(10); + address target = address(11); bytes memory code = hex"1010"; vm.etch(target, code); assertEq(string(code), string(target.code)); diff --git a/testdata/default/repros/Issue5929.t.sol b/testdata/default/repros/Issue5929.t.sol index 70c5a4f4ffbd..ced9d6d9b4a3 100644 --- a/testdata/default/repros/Issue5929.t.sol +++ b/testdata/default/repros/Issue5929.t.sol @@ -9,8 +9,8 @@ contract Issue5929Test is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function test_transact_not_working() public { - vm.createSelectFork("mainnet", 15625301); + vm.createSelectFork("mainnet", 21134547); // https://etherscan.io/tx/0x96a129768ec66fd7d65114bf182f4e173bf0b73a44219adaf71f01381a3d0143 - vm.transact(hex"96a129768ec66fd7d65114bf182f4e173bf0b73a44219adaf71f01381a3d0143"); + vm.transact(hex"7dcff74771babf9c23363c4228e55a27f50224d4596b1ba6608b0b45712f94ba"); } } diff --git a/testdata/default/repros/Issue6538.t.sol b/testdata/default/repros/Issue6538.t.sol index 5b318a04c868..34c4e2253a68 100644 --- a/testdata/default/repros/Issue6538.t.sol +++ b/testdata/default/repros/Issue6538.t.sol @@ -9,9 +9,9 @@ contract Issue6538Test is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function test_transact() public { - bytes32 lastHash = 0xdbdce1d5c14a6ca17f0e527ab762589d6a73f68697606ae0bb90df7ac9ec5087; + bytes32 lastHash = 0x4b70ca8c5a0990b43df3064372d424d46efa41dfaab961754b86c5afb2df4f61; vm.createSelectFork("mainnet", lastHash); - bytes32 txhash = 0xadbe5cf9269a001d50990d0c29075b402bcc3a0b0f3258821881621b787b35c6; + bytes32 txhash = 0x7dcff74771babf9c23363c4228e55a27f50224d4596b1ba6608b0b45712f94ba; vm.transact(txhash); } } diff --git a/testdata/default/repros/Issue8006.t.sol b/testdata/default/repros/Issue8006.t.sol index 95b16e6f64fa..efe339d9fef2 100644 --- a/testdata/default/repros/Issue8006.t.sol +++ b/testdata/default/repros/Issue8006.t.sol @@ -18,10 +18,10 @@ contract Mock { contract Issue8006Test is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); IERC20 dai; - bytes32 transaction = 0x67cbad73764049e228495a3f90144aab4a37cb4b5fd697dffc234aa5ed811ace; + bytes32 transaction = 0xb23f389b26eb6f95c08e275ec2c360ab3990169492ff0d3e7b7233a3f81d299f; function setUp() public { - vm.createSelectFork("mainnet", 16261704); + vm.createSelectFork("mainnet", 21134541); dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); } @@ -30,7 +30,7 @@ contract Issue8006Test is DSTest { vm.etch(address(dai), address(new Mock()).code); assertEq(dai.totalSupply(), 1); vm.rollFork(transaction); - assertEq(dai.totalSupply(), 5155217627191887307044676292); + assertEq(dai.totalSupply(), 3324657947511778619416491233); } function testRollForkEtchCalled() public { diff --git a/testdata/paris/cheats/Fork.t.sol b/testdata/paris/cheats/Fork.t.sol new file mode 100644 index 000000000000..2f2e627de131 --- /dev/null +++ b/testdata/paris/cheats/Fork.t.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +interface IWETH { + function deposit() external payable; + function balanceOf(address) external view returns (uint256); +} + +contract ForkTest is DSTest { + address constant WETH_TOKEN_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + uint256 constant mainblock = 14_608_400; + + Vm constant vm = Vm(HEVM_ADDRESS); + IWETH WETH = IWETH(WETH_TOKEN_ADDR); + + uint256 forkA; + uint256 forkB; + + uint256 testValue; + + // this will create two _different_ forks during setup + function setUp() public { + forkA = vm.createFork("mainnet", mainblock); + forkB = vm.createFork("mainnet2", mainblock - 1); + testValue = 999; + } + + // ensures forks use different ids + function testForkIdDiffer() public { + assert(forkA != forkB); + } + + // ensures we can create and select in one step + function testCreateSelect() public { + uint256 fork = vm.createSelectFork("mainnet"); + assertEq(fork, vm.activeFork()); + } + + // ensures forks use different ids + function testCanSwitchForks() public { + vm.selectFork(forkA); + vm.selectFork(forkB); + vm.selectFork(forkB); + vm.selectFork(forkA); + } + + function testForksHaveSeparatedStorage() public { + vm.selectFork(forkA); + // read state from forkA + assert(WETH.balanceOf(0x0000000000000000000000000000000000000000) != 1); + + vm.selectFork(forkB); + // read state from forkB + uint256 forkBbalance = WETH.balanceOf(0x0000000000000000000000000000000000000000); + assert(forkBbalance != 1); + + vm.selectFork(forkA); + + // modify state + bytes32 value = bytes32(uint256(1)); + // "0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff" is the slot storing the balance of zero address for the weth contract + // `cast index address uint 0x0000000000000000000000000000000000000000 3` + bytes32 zero_address_balance_slot = 0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff; + vm.store(WETH_TOKEN_ADDR, zero_address_balance_slot, value); + assertEq( + WETH.balanceOf(0x0000000000000000000000000000000000000000), + 1, + "Cheatcode did not change value at the storage slot." + ); + + // switch forks and ensure the balance on forkB remains untouched + vm.selectFork(forkB); + assert(forkBbalance != 1); + // balance of forkB is untouched + assertEq( + WETH.balanceOf(0x0000000000000000000000000000000000000000), + forkBbalance, + "Cheatcode did not change value at the storage slot." + ); + } + + function testCanShareDataAcrossSwaps() public { + assertEq(testValue, 999); + + uint256 val = 300; + vm.selectFork(forkA); + assertEq(val, 300); + + testValue = 100; + + vm.selectFork(forkB); + assertEq(val, 300); + assertEq(testValue, 100); + + val = 99; + testValue = 300; + + vm.selectFork(forkA); + assertEq(val, 99); + assertEq(testValue, 300); + } + + // ensures forks use different ids + function testCanChangeChainId() public { + vm.selectFork(forkA); + uint256 newChainId = 1337; + vm.chainId(newChainId); + uint256 expected = block.chainid; + assertEq(newChainId, expected); + } + + // ensures forks change chain ids automatically + function testCanAutoUpdateChainId() public { + vm.createSelectFork("sepolia"); + assertEq(block.chainid, 11155111); + } + + // ensures forks storage is cached at block + function testStorageCaching() public { + vm.createSelectFork("mainnet", 19800000); + } +} diff --git a/testdata/default/cheats/GasSnapshots.t.sol b/testdata/paris/cheats/GasSnapshots.t.sol similarity index 100% rename from testdata/default/cheats/GasSnapshots.t.sol rename to testdata/paris/cheats/GasSnapshots.t.sol diff --git a/testdata/default/cheats/LastCallGas.t.sol b/testdata/paris/cheats/LastCallGas.t.sol similarity index 100% rename from testdata/default/cheats/LastCallGas.t.sol rename to testdata/paris/cheats/LastCallGas.t.sol diff --git a/testdata/default/repros/Issue1543.t.sol b/testdata/paris/core/BeforeTest.t.sol similarity index 98% rename from testdata/default/repros/Issue1543.t.sol rename to testdata/paris/core/BeforeTest.t.sol index e58f331c4af9..2b14bcad1d2e 100644 --- a/testdata/default/repros/Issue1543.t.sol +++ b/testdata/paris/core/BeforeTest.t.sol @@ -10,7 +10,7 @@ contract SelfDestructor { } // https://github.com/foundry-rs/foundry/issues/1543 -contract Issue1543Test is DSTest { +contract BeforeTestSelfDestructTest is DSTest { SelfDestructor killer; uint256 a; uint256 b; diff --git a/testdata/default/fork/Transact.t.sol b/testdata/paris/fork/Transact.t.sol similarity index 99% rename from testdata/default/fork/Transact.t.sol rename to testdata/paris/fork/Transact.t.sol index 3756587725eb..92d595f98c51 100644 --- a/testdata/default/fork/Transact.t.sol +++ b/testdata/paris/fork/Transact.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.18; import "ds-test/test.sol"; import "cheats/Vm.sol"; -import "../logs/console.sol"; +import "../../default/logs/console.sol"; interface IERC20 { function transfer(address to, uint256 amount) external returns (bool); diff --git a/testdata/paris/spec/ShanghaiCompat.t.sol b/testdata/paris/spec/ShanghaiCompat.t.sol new file mode 100644 index 000000000000..fd7213b3d070 --- /dev/null +++ b/testdata/paris/spec/ShanghaiCompat.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract ShanghaiCompat is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testPush0() public { + address target = address(uint160(uint256(0xc4f3))); + + bytes memory bytecode = hex"365f5f37365ff3"; + // 36 CALLDATASIZE + // 5F PUSH0 + // 5F PUSH0 + // 37 CALLDATACOPY -> copies calldata at mem[0..calldatasize] + + // 36 CALLDATASIZE + // 5F PUSH0 + // F3 RETURN -> returns mem[0..calldatasize] + + vm.etch(target, bytecode); + + (bool success, bytes memory result) = target.call(bytes("hello PUSH0")); + assertTrue(success); + assertEq(string(result), "hello PUSH0"); + } +} From 550ebd8f473c0f02434ddef9ad9cdca36be4bd54 Mon Sep 17 00:00:00 2001 From: grandizzy <38490174+grandizzy@users.noreply.github.com> Date: Mon, 18 Nov 2024 19:15:25 +0200 Subject: [PATCH 4/8] chore: update test values to cancun (#9344) --- crates/forge/tests/cli/build.rs | 16 ++--- crates/forge/tests/cli/cmd.rs | 110 ++++++++++++++++---------------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index 51c358612e86..9585b216b159 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -87,10 +87,10 @@ forgetest!(initcode_size_exceeds_limit, |prj, cmd| { str![[r#" { "HugeContract":{ - "runtime_size":202, - "init_size":49359, - "runtime_margin":24374, - "init_margin":-207 + "runtime_size":194, + "init_size":49344, + "runtime_margin":24382, + "init_margin":-192 } } "#]] @@ -117,10 +117,10 @@ forgetest!(initcode_size_limit_can_be_ignored, |prj, cmd| { str![[r#" { "HugeContract": { - "runtime_size": 202, - "init_size": 49359, - "runtime_margin": 24374, - "init_margin": -207 + "runtime_size": 194, + "init_size": 49344, + "runtime_margin": 24382, + "init_margin": -192 } } "#]] diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 18f0327f6e90..3cd4ae5edb04 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -2460,16 +2460,16 @@ contract GasReportFallbackTest is Test { Ran 1 test for test/DelegateProxyTest.sol:GasReportFallbackTest [PASS] test_fallback_gas_report() ([GAS]) Traces: - [331067] GasReportFallbackTest::test_fallback_gas_report() - ├─ [106511] → new ProxiedContract@[..] - │ └─ ← [Return] 246 bytes of code - ├─ [108698] → new DelegateProxy@[..] - │ └─ ← [Return] 143 bytes of code - ├─ [29396] DelegateProxy::fallback(100) - │ ├─ [3320] ProxiedContract::deposit(100) [delegatecall] + [327404] GasReportFallbackTest::test_fallback_gas_report() + ├─ [104475] → new ProxiedContract@[..] + │ └─ ← [Return] 236 bytes of code + ├─ [107054] → new DelegateProxy@[..] + │ └─ ← [Return] 135 bytes of code + ├─ [29384] DelegateProxy::fallback(100) + │ ├─ [3316] ProxiedContract::deposit(100) [delegatecall] │ │ └─ ← [Stop] │ └─ ← [Return] - ├─ [21160] DelegateProxy::deposit() + ├─ [21159] DelegateProxy::deposit() │ └─ ← [Stop] └─ ← [Stop] @@ -2477,18 +2477,18 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] | test/DelegateProxyTest.sol:DelegateProxy contract | | | | | | |---------------------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 108698 | 315 | | | | | +| 107054 | 300 | | | | | | Function Name | min | avg | median | max | # calls | -| deposit | 21160 | 21160 | 21160 | 21160 | 1 | -| fallback | 29396 | 29396 | 29396 | 29396 | 1 | +| deposit | 21159 | 21159 | 21159 | 21159 | 1 | +| fallback | 29384 | 29384 | 29384 | 29384 | 1 | | test/DelegateProxyTest.sol:ProxiedContract contract | | | | | | |-----------------------------------------------------|-----------------|------|--------|------|---------| | Deployment Cost | Deployment Size | | | | | -| 106511 | 276 | | | | | +| 104475 | 263 | | | | | | Function Name | min | avg | median | max | # calls | -| deposit | 3320 | 3320 | 3320 | 3320 | 1 | +| deposit | 3316 | 3316 | 3316 | 3316 | 1 | ... "#]]); @@ -2502,39 +2502,39 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] { "contract": "test/DelegateProxyTest.sol:DelegateProxy", "deployment": { - "gas": 108698, - "size": 315 + "gas": 107054, + "size": 300 }, "functions": { "deposit()": { "calls": 1, - "min": 21160, - "mean": 21160, - "median": 21160, - "max": 21160 + "min": 21159, + "mean": 21159, + "median": 21159, + "max": 21159 }, "fallback()": { "calls": 1, - "min": 29396, - "mean": 29396, - "median": 29396, - "max": 29396 + "min": 29384, + "mean": 29384, + "median": 29384, + "max": 29384 } } }, { "contract": "test/DelegateProxyTest.sol:ProxiedContract", "deployment": { - "gas": 106511, - "size": 276 + "gas": 104475, + "size": 263 }, "functions": { "deposit(uint256)": { "calls": 1, - "min": 3320, - "mean": 3320, - "median": 3320, - "max": 3320 + "min": 3316, + "mean": 3316, + "median": 3316, + "max": 3316 } } } @@ -2588,25 +2588,25 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] | test/NestedDeployTest.sol:AnotherChild contract | | | | | | |-------------------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | -| 0 | 130 | | | | | +| 0 | 124 | | | | | | Function Name | min | avg | median | max | # calls | -| w | 21162 | 21162 | 21162 | 21162 | 1 | +| w | 21161 | 21161 | 21161 | 21161 | 1 | | test/NestedDeployTest.sol:Child contract | | | | | | |------------------------------------------|-----------------|-----|--------|-----|---------| | Deployment Cost | Deployment Size | | | | | -| 0 | 498 | | | | | +| 0 | 477 | | | | | | Function Name | min | avg | median | max | # calls | -| child | 325 | 325 | 325 | 325 | 1 | +| child | 323 | 323 | 323 | 323 | 1 | | test/NestedDeployTest.sol:Parent contract | | | | | | |-------------------------------------------|-----------------|-----|--------|-----|---------| | Deployment Cost | Deployment Size | | | | | -| 254857 | 770 | | | | | +| 251997 | 739 | | | | | | Function Name | min | avg | median | max | # calls | -| child | 182 | 182 | 182 | 182 | 1 | +| child | 181 | 181 | 181 | 181 | 1 | ... "#]]); @@ -2620,15 +2620,15 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] "contract": "test/NestedDeployTest.sol:AnotherChild", "deployment": { "gas": 0, - "size": 130 + "size": 124 }, "functions": { "w()": { "calls": 1, - "min": 21162, - "mean": 21162, - "median": 21162, - "max": 21162 + "min": 21161, + "mean": 21161, + "median": 21161, + "max": 21161 } } }, @@ -2636,31 +2636,31 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] "contract": "test/NestedDeployTest.sol:Child", "deployment": { "gas": 0, - "size": 498 + "size": 477 }, "functions": { "child()": { "calls": 1, - "min": 325, - "mean": 325, - "median": 325, - "max": 325 + "min": 323, + "mean": 323, + "median": 323, + "max": 323 } } }, { "contract": "test/NestedDeployTest.sol:Parent", "deployment": { - "gas": 254857, - "size": 770 + "gas": 251997, + "size": 739 }, "functions": { "child()": { "calls": 1, - "min": 182, - "mean": 182, - "median": 182, - "max": 182 + "min": 181, + "mean": 181, + "median": 181, + "max": 181 } } } @@ -2982,10 +2982,10 @@ Compiler run successful! str![[r#" { "Counter": { - "runtime_size": 247, - "init_size": 277, - "runtime_margin": 24329, - "init_margin": 48875 + "runtime_size": 236, + "init_size": 263, + "runtime_margin": 24340, + "init_margin": 48889 } } "#]] From 7e323c23463193f70c025f0df57b559a79db9676 Mon Sep 17 00:00:00 2001 From: mgiagante <5287175+mgiagante@users.noreply.github.com> Date: Mon, 18 Nov 2024 19:42:38 +0000 Subject: [PATCH 5/8] feat(`forge build -vvvvv`): If verbosity level is 5 or higher show files to compile (#9325) * If verbosity level is 1 or higher, it shows dirty files. * Adds verbose message variant for compilation. * Removing `if..else` statement to always display `self.send_msg`. * Changes order of messages. * Removes semicolons and adds comment on message order. * Removes verbose variant in favor of the already existing variant. * nits, sort the dirty files list and prefix with - * Raises verbosity level to 5+ * Update crates/common/src/term.rs Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --------- Co-authored-by: mgiagante <251503-mgiagante@users.noreply.gitlab.com> Co-authored-by: zerosnacks Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- Cargo.lock | 1 + crates/common/Cargo.toml | 1 + crates/common/src/term.rs | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1922c69b89af..7dc745cbf0de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3716,6 +3716,7 @@ dependencies = [ "foundry-compilers", "foundry-config", "foundry-macros", + "itertools 0.13.0", "num-format", "reqwest", "semver 1.0.23", diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 8fa745a13982..033c53e49dba 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -50,6 +50,7 @@ clap = { version = "4", features = ["derive", "env", "unicode", "wrap_help"] } comfy-table.workspace = true dunce.workspace = true eyre.workspace = true +itertools.workspace = true num-format.workspace = true reqwest.workspace = true semver.workspace = true diff --git a/crates/common/src/term.rs b/crates/common/src/term.rs index ead39b5face3..e673987454cb 100644 --- a/crates/common/src/term.rs +++ b/crates/common/src/term.rs @@ -3,6 +3,8 @@ use foundry_compilers::{ artifacts::remappings::Remapping, report::{self, BasicStdoutReporter, Reporter}, }; +use foundry_config::find_project_root; +use itertools::Itertools; use semver::Version; use std::{ io, @@ -17,6 +19,8 @@ use std::{ }; use yansi::Paint; +use crate::shell; + /// Some spinners // https://github.com/gernest/wow/blob/master/spin/spinners.go pub static SPINNERS: &[&[&str]] = &[ @@ -151,6 +155,24 @@ impl Drop for SpinnerReporter { impl Reporter for SpinnerReporter { fn on_compiler_spawn(&self, compiler_name: &str, version: &Version, dirty_files: &[PathBuf]) { + // Verbose message with dirty files displays first to avoid being overlapped + // by the spinner in .tick() which prints repeatedly over the same line. + if shell::verbosity() >= 5 { + let project_root = find_project_root(None); + + self.send_msg(format!( + "Files to compile:\n{}", + dirty_files + .iter() + .map(|path| { + let trimmed_path = path.strip_prefix(&project_root).unwrap_or(path); + format!("- {}", trimmed_path.display()) + }) + .sorted() + .format("\n") + )); + } + self.send_msg(format!( "Compiling {} files with {} {}.{}.{}", dirty_files.len(), From 6625e16e57bd66e4f7d43b1d2d6dfb74c4a88469 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 18 Nov 2024 21:46:06 +0100 Subject: [PATCH 6/8] chore: add some more debugging to forge bind (#9345) --- crates/sol-macro-gen/src/sol_macro_gen.rs | 70 +++++++++++++---------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/crates/sol-macro-gen/src/sol_macro_gen.rs b/crates/sol-macro-gen/src/sol_macro_gen.rs index 7309104fec61..8c146aa05dda 100644 --- a/crates/sol-macro-gen/src/sol_macro_gen.rs +++ b/crates/sol-macro-gen/src/sol_macro_gen.rs @@ -11,7 +11,7 @@ use alloy_sol_macro_expander::expand::expand; use alloy_sol_macro_input::{SolInput, SolInputKind}; -use eyre::{Context, Ok, OptionExt, Result}; +use eyre::{Context, OptionExt, Result}; use foundry_common::fs; use proc_macro2::{Span, TokenStream}; use std::{ @@ -39,7 +39,7 @@ impl SolMacroGen { #path }; - let sol_input: SolInput = syn::parse2(tokens).wrap_err("Failed to parse SolInput {e}")?; + let sol_input: SolInput = syn::parse2(tokens).wrap_err("failed to parse input")?; Ok(sol_input) } @@ -69,24 +69,35 @@ impl MultiSolMacroGen { pub fn generate_bindings(&mut self) -> Result<()> { for instance in &mut self.instances { - let input = instance.get_sol_input()?.normalize_json()?; + Self::generate_binding(instance).wrap_err_with(|| { + format!( + "failed to generate bindings for {}:{}", + instance.path.display(), + instance.name + ) + })?; + } - let SolInput { attrs: _attrs, path: _path, kind } = input; + Ok(()) + } - let tokens = match kind { - SolInputKind::Sol(mut file) => { - let sol_attr: syn::Attribute = syn::parse_quote! { - #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = alloy::contract)] - }; - file.attrs.push(sol_attr); - expand(file).wrap_err("Failed to expand SolInput")? - } - _ => unreachable!(), - }; + fn generate_binding(instance: &mut SolMacroGen) -> Result<()> { + let input = instance.get_sol_input()?.normalize_json()?; - instance.expansion = Some(tokens); - } + let SolInput { attrs: _, path: _, kind } = input; + let tokens = match kind { + SolInputKind::Sol(mut file) => { + let sol_attr: syn::Attribute = syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = alloy::contract)] + }; + file.attrs.push(sol_attr); + expand(file).wrap_err("failed to expand")? + } + _ => unreachable!(), + }; + + instance.expansion = Some(tokens); Ok(()) } @@ -139,27 +150,28 @@ edition = "2021" )?; // Write src + let parse_error = |name: &str| { + format!("failed to parse generated tokens as an AST for {name};\nthis is likely a bug") + }; for instance in &self.instances { - let name = instance.name.to_lowercase(); - let contents = instance.expansion.as_ref().unwrap().to_string(); + let contents = instance.expansion.as_ref().unwrap(); - if !single_file { - let path = src.join(format!("{name}.rs")); - let file = syn::parse_file(&contents)?; - let contents = prettyplease::unparse(&file); - - fs::write(path.clone(), contents).wrap_err("Failed to write file")?; - writeln!(&mut lib_contents, "pub mod {name};")?; - } else { + let name = instance.name.to_lowercase(); + let path = src.join(format!("{name}.rs")); + let file = syn::parse2(contents.clone()) + .wrap_err_with(|| parse_error(&format!("{}:{}", path.display(), name)))?; + let contents = prettyplease::unparse(&file); + if single_file { write!(&mut lib_contents, "{contents}")?; + } else { + fs::write(path, contents).wrap_err("failed to write to file")?; + writeln!(&mut lib_contents, "pub mod {name};")?; } } let lib_path = src.join("lib.rs"); - let lib_file = syn::parse_file(&lib_contents)?; - + let lib_file = syn::parse_file(&lib_contents).wrap_err_with(|| parse_error("lib.rs"))?; let lib_contents = prettyplease::unparse(&lib_file); - fs::write(lib_path, lib_contents).wrap_err("Failed to write lib.rs")?; Ok(()) From 547d8a52ec7d286214511eb9c8ef5d5be601e81b Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 19 Nov 2024 01:11:59 +0400 Subject: [PATCH 7/8] feat: compilation restrictions (#8668) * [wip] feat: compilation restrictions * Cargo.lock * update patch * fixes * update patch * update patch * wip * deps * bytecode hash * fixes * rm patches * pub --- Cargo.lock | 194 ++++++++++++++++--- Cargo.toml | 4 +- crates/cast/bin/cmd/storage.rs | 4 +- crates/cli/src/utils/cmd.rs | 31 ++- crates/config/src/compilation.rs | 115 +++++++++++ crates/config/src/lib.rs | 76 +++++++- crates/forge/bin/cmd/bind_json.rs | 8 +- crates/forge/bin/cmd/compiler.rs | 8 +- crates/forge/bin/cmd/create.rs | 44 ++++- crates/forge/bin/cmd/eip712.rs | 14 +- crates/forge/bin/cmd/test/mod.rs | 4 +- crates/forge/tests/cli/config.rs | 2 + crates/script/src/verify.rs | 1 + crates/verify/src/etherscan/flatten.rs | 2 +- crates/verify/src/etherscan/standard_json.rs | 9 +- crates/verify/src/provider.rs | 11 +- crates/verify/src/verify.rs | 63 +++++- 17 files changed, 500 insertions(+), 90 deletions(-) create mode 100644 crates/config/src/compilation.rs diff --git a/Cargo.lock b/Cargo.lock index 7dc745cbf0de..81adf0f4b1e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -799,6 +799,16 @@ dependencies = [ "libc", ] +[[package]] +name = "annotate-snippets" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" +dependencies = [ + "anstyle", + "unicode-width 0.1.14", +] + [[package]] name = "anstream" version = "0.6.18" @@ -3572,9 +3582,9 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.7.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff37530e7c5deead0f9d7dc2a27b070e683bef79735ab453849ebdee74fa848f" +checksum = "0faa449506113b4969029da2ac1df3a1b3201bf10c99a4a8e6d684977b80c938" dependencies = [ "alloy-chains", "alloy-json-abi", @@ -3755,9 +3765,9 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.11.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4754b3f3bb924202b29bd7f0584ea1446018926342884c86029a7d56ef1a22c1" +checksum = "9edf09554357ebfcd2ea28503badbaca311aac3c947d269a6bae5256543aa172" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -3780,7 +3790,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "solang-parser", + "solar-parse", "svm-rs", "svm-rs-builds", "tempfile", @@ -3793,9 +3803,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.11.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6289da0f17fdb5a0454020dce595502b0abd2a56c15a36d4f6c05bd6c4ff864" +checksum = "134b2499a20136716422f1ae5afd3a5d6c2ef833bf97b7c956285ca96c1d9743" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -3803,9 +3813,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.11.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf322ab7b726f2bafe9a7e6fb67db02801b35584a2b1d122b4feb52d8e9e7f" +checksum = "78a9be34b3a43e77871e5bbd75f4a81d23eebf8f098519ae1ae9e163a0f3d0da" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -3827,9 +3837,9 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.11.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec47f94c7833adfe8049c819d9e31a60c3f440a68cf5baf34c318413d3eb0700" +checksum = "1738950051ebcee2135adac07b3ef1708c6377ffed0c5e9a2bb485f31498befb" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -3842,9 +3852,9 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.11.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61971b34545e8ea01502df9d076e811ad3926f27d31adf2641e0c931ca646933" +checksum = "2ac2d9982eedb0eb3819f82c7efa1e28c1f78e031cdfb6adfa34690364fe5e0d" dependencies = [ "alloy-primitives", "cfg-if", @@ -4700,6 +4710,10 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "hashbrown" @@ -5255,6 +5269,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "index_vec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44faf5bb8861a9c72e20d3fb0fdbd59233e43056e2b80475ab0aacdc2e781355" + [[package]] name = "indexmap" version = "1.9.3" @@ -5576,6 +5596,16 @@ dependencies = [ "regex-automata 0.4.9", ] +[[package]] +name = "lasso" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" +dependencies = [ + "dashmap", + "hashbrown 0.14.5", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -5712,6 +5742,12 @@ dependencies = [ "tendril", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -5890,9 +5926,9 @@ dependencies = [ [[package]] name = "mockall" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" dependencies = [ "cfg-if", "downcast", @@ -5904,9 +5940,9 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" dependencies = [ "cfg-if", "proc-macro2", @@ -6383,28 +6419,29 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -8046,9 +8083,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap 2.6.0", "itoa", @@ -8357,6 +8394,109 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "solar-ast" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5aeaf7a4bd326242c909bd287291226a540b62b36fa5824880248f4b1d4d6af" +dependencies = [ + "alloy-primitives", + "bumpalo", + "either", + "num-bigint", + "num-rational", + "semver 1.0.23", + "solar-data-structures", + "solar-interface", + "solar-macros", + "strum", + "typed-arena", +] + +[[package]] +name = "solar-config" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d00d672a40a1a3620d7696f01a2d3301abf883d8168e1a9da3bf83f0c8e343" +dependencies = [ + "strum", +] + +[[package]] +name = "solar-data-structures" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6e4eb0b72ed7adbb808897c85de08ea99609774a58c72e3dce55c758043ca2" +dependencies = [ + "bumpalo", + "index_vec", + "indexmap 2.6.0", + "parking_lot", + "rayon", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "solar-interface" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21fb8925638f3da1bba7a9a6ebeac3511e5c6354f921f2bb2e1ddce4ac70c107" +dependencies = [ + "annotate-snippets", + "anstream", + "anstyle", + "const-hex", + "derive_builder", + "dunce", + "itertools 0.13.0", + "itoa", + "lasso", + "match_cfg", + "normalize-path", + "rayon", + "scc", + "scoped-tls", + "solar-config", + "solar-data-structures", + "solar-macros", + "thiserror 1.0.69", + "tracing", + "unicode-width 0.2.0", +] + +[[package]] +name = "solar-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0cc54b74e214647c1bbfc098d080cc5deac77f8dcb99aca91747276b01a15ad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "solar-parse" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82c3659c15975cd80e5e1c44591278c230c59ad89082d797837499a4784e1b" +dependencies = [ + "alloy-primitives", + "bitflags 2.6.0", + "bumpalo", + "itertools 0.13.0", + "memchr", + "num-bigint", + "num-rational", + "num-traits", + "smallvec", + "solar-ast", + "solar-data-structures", + "solar-interface", + "tracing", +] + [[package]] name = "soldeer-commands" version = "0.5.1" @@ -9267,6 +9407,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index 0c0962a2d95e..624264cf218e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -168,8 +168,8 @@ foundry-wallets = { path = "crates/wallets" } foundry-linking = { path = "crates/linking" } # solc & compilation utilities -foundry-block-explorers = { version = "0.7.3", default-features = false } -foundry-compilers = { version = "0.11.6", default-features = false } +foundry-block-explorers = { version = "0.9.0", default-features = false } +foundry-compilers = { version = "0.12.1", default-features = false } foundry-fork-db = "0.6.0" solang-parser = "=0.3.3" diff --git a/crates/cast/bin/cmd/storage.rs b/crates/cast/bin/cmd/storage.rs index 5e2459127001..13fa908bc94a 100644 --- a/crates/cast/bin/cmd/storage.rs +++ b/crates/cast/bin/cmd/storage.rs @@ -23,7 +23,7 @@ use foundry_compilers::{ artifacts::{ConfigurableContractArtifact, StorageLayout}, compilers::{ solc::{Solc, SolcCompiler}, - Compiler, CompilerSettings, + Compiler, }, Artifact, Project, }; @@ -316,7 +316,7 @@ fn print_storage(layout: StorageLayout, values: Vec, pretty: bool) fn add_storage_layout_output(project: &mut Project) { project.artifacts.additional_values.storage_layout = true; - project.settings.update_output_selection(|selection| { + project.update_output_selection(|selection| { selection.0.values_mut().for_each(|contract_selection| { contract_selection .values_mut() diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index 2ebdc2539dff..19e4425b54c7 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -3,10 +3,10 @@ use alloy_primitives::Address; use eyre::{Result, WrapErr}; use foundry_common::{fs, TestFunctionExt}; use foundry_compilers::{ - artifacts::{CompactBytecode, CompactDeployedBytecode, Settings}, + artifacts::{CompactBytecode, Settings}, cache::{CacheEntry, CompilerCache}, utils::read_json_file, - Artifact, ProjectCompileOutput, + Artifact, ArtifactId, ProjectCompileOutput, }; use foundry_config::{error::ExtractConfigError, figment::Figment, Chain, Config, NamedChain}; use foundry_debugger::Debugger; @@ -32,17 +32,21 @@ use yansi::Paint; /// Runtime Bytecode of the given contract. #[track_caller] pub fn remove_contract( - output: &mut ProjectCompileOutput, + output: ProjectCompileOutput, path: &Path, name: &str, -) -> Result<(JsonAbi, CompactBytecode, CompactDeployedBytecode)> { - let contract = if let Some(contract) = output.remove(path, name) { - contract - } else { +) -> Result<(JsonAbi, CompactBytecode, ArtifactId)> { + let mut other = Vec::new(); + let Some((id, contract)) = output.into_artifacts().find_map(|(id, artifact)| { + if id.name == name && id.source == path { + Some((id, artifact)) + } else { + other.push(id.name); + None + } + }) else { let mut err = format!("could not find artifact: `{name}`"); - if let Some(suggestion) = - super::did_you_mean(name, output.artifacts().map(|(name, _)| name)).pop() - { + if let Some(suggestion) = super::did_you_mean(name, other).pop() { if suggestion != name { err = format!( r#"{err} @@ -64,12 +68,7 @@ pub fn remove_contract( .ok_or_else(|| eyre::eyre!("contract {} does not contain bytecode", name))? .into_owned(); - let runtime = contract - .get_deployed_bytecode() - .ok_or_else(|| eyre::eyre!("contract {} does not contain deployed bytecode", name))? - .into_owned(); - - Ok((abi, bin, runtime)) + Ok((abi, bin, id)) } /// Helper function for finding a contract by ContractName diff --git a/crates/config/src/compilation.rs b/crates/config/src/compilation.rs new file mode 100644 index 000000000000..b4f00b91b0d9 --- /dev/null +++ b/crates/config/src/compilation.rs @@ -0,0 +1,115 @@ +use crate::{filter::GlobMatcher, serde_helpers}; +use foundry_compilers::{ + artifacts::{BytecodeHash, EvmVersion}, + multi::{MultiCompilerRestrictions, MultiCompilerSettings}, + settings::VyperRestrictions, + solc::{Restriction, SolcRestrictions}, + RestrictionsWithVersion, +}; +use semver::VersionReq; +use serde::{Deserialize, Serialize}; + +/// Keeps possible overrides for default settings which users may configure to construct additional +/// settings profile. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct SettingsOverrides { + pub name: String, + pub via_ir: Option, + #[serde(default, with = "serde_helpers::display_from_str_opt")] + pub evm_version: Option, + pub optimizer: Option, + pub optimizer_runs: Option, + pub bytecode_hash: Option, +} + +impl SettingsOverrides { + /// Applies the overrides to the given settings. + pub fn apply(&self, settings: &mut MultiCompilerSettings) { + if let Some(via_ir) = self.via_ir { + settings.solc.via_ir = Some(via_ir); + } + + if let Some(evm_version) = self.evm_version { + settings.solc.evm_version = Some(evm_version); + settings.vyper.evm_version = Some(evm_version); + } + + if let Some(enabled) = self.optimizer { + settings.solc.optimizer.enabled = Some(enabled); + } + + if let Some(optimizer_runs) = self.optimizer_runs { + settings.solc.optimizer.runs = Some(optimizer_runs); + } + + if let Some(bytecode_hash) = self.bytecode_hash { + if let Some(metadata) = settings.solc.metadata.as_mut() { + metadata.bytecode_hash = Some(bytecode_hash); + } else { + settings.solc.metadata = Some(bytecode_hash.into()); + } + } + } +} + +#[derive(Debug, thiserror::Error)] +pub enum RestrictionsError { + #[error("specified both exact and relative restrictions for {0}")] + BothExactAndRelative(&'static str), +} + +/// Restrictions for compilation of given paths. +/// +/// Only purpose of this type is to accept user input to later construct +/// `RestrictionsWithVersion`. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct CompilationRestrictions { + pub paths: GlobMatcher, + pub version: Option, + pub via_ir: Option, + pub bytecode_hash: Option, + + pub min_optimizer_runs: Option, + pub optimizer_runs: Option, + pub max_optimizer_runs: Option, + + #[serde(default, with = "serde_helpers::display_from_str_opt")] + pub min_evm_version: Option, + #[serde(default, with = "serde_helpers::display_from_str_opt")] + pub evm_version: Option, + #[serde(default, with = "serde_helpers::display_from_str_opt")] + pub max_evm_version: Option, +} + +impl TryFrom for RestrictionsWithVersion { + type Error = RestrictionsError; + + fn try_from(value: CompilationRestrictions) -> Result { + let (min_evm, max_evm) = + match (value.min_evm_version, value.max_evm_version, value.evm_version) { + (None, None, Some(exact)) => (Some(exact), Some(exact)), + (min, max, None) => (min, max), + _ => return Err(RestrictionsError::BothExactAndRelative("evm_version")), + }; + let (min_opt, max_opt) = + match (value.min_optimizer_runs, value.max_optimizer_runs, value.optimizer_runs) { + (None, None, Some(exact)) => (Some(exact), Some(exact)), + (min, max, None) => (min, max), + _ => return Err(RestrictionsError::BothExactAndRelative("optimizer_runs")), + }; + Ok(Self { + restrictions: MultiCompilerRestrictions { + solc: SolcRestrictions { + evm_version: Restriction { min: min_evm, max: max_evm }, + via_ir: value.via_ir, + optimizer_runs: Restriction { min: min_opt, max: max_opt }, + bytecode_hash: value.bytecode_hash, + }, + vyper: VyperRestrictions { + evm_version: Restriction { min: min_evm, max: max_evm }, + }, + }, + version: value.version, + }) + } +} diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index b87eadcefa0b..6444802e3bc9 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -33,8 +33,10 @@ use foundry_compilers::{ Compiler, }, error::SolcError, + multi::{MultiCompilerParsedSource, MultiCompilerRestrictions}, solc::{CliSettings, SolcSettings}, - ConfigurableArtifacts, Project, ProjectPathsConfig, VyperLanguage, + ConfigurableArtifacts, Graph, Project, ProjectPathsConfig, RestrictionsWithVersion, + VyperLanguage, }; use inflector::Inflector; use regex::Regex; @@ -43,6 +45,7 @@ use semver::Version; use serde::{Deserialize, Serialize, Serializer}; use std::{ borrow::Cow, + collections::BTreeMap, fs, path::{Path, PathBuf}, str::FromStr, @@ -116,6 +119,9 @@ use vyper::VyperConfig; mod bind_json; use bind_json::BindJsonConfig; +mod compilation; +use compilation::{CompilationRestrictions, SettingsOverrides}; + /// Foundry configuration /// /// # Defaults @@ -479,6 +485,14 @@ pub struct Config { #[serde(rename = "__warnings", default, skip_serializing)] pub warnings: Vec, + /// Additional settings profiles to use when compiling. + #[serde(default)] + pub additional_compiler_profiles: Vec, + + /// Restrictions on compilation of certain files. + #[serde(default)] + pub compilation_restrictions: Vec, + /// PRIVATE: This structure may grow, As such, constructing this structure should /// _always_ be done using a public constructor or update syntax: /// @@ -867,12 +881,66 @@ impl Config { self.create_project(false, true) } + /// Builds mapping with additional settings profiles. + fn additional_settings( + &self, + base: &MultiCompilerSettings, + ) -> BTreeMap { + let mut map = BTreeMap::new(); + + for profile in &self.additional_compiler_profiles { + let mut settings = base.clone(); + profile.apply(&mut settings); + map.insert(profile.name.clone(), settings); + } + + map + } + + /// Resolves globs and builds a mapping from individual source files to their restrictions + fn restrictions( + &self, + paths: &ProjectPathsConfig, + ) -> Result>, SolcError> + { + let mut map = BTreeMap::new(); + + let graph = Graph::::resolve(paths)?; + let (sources, _) = graph.into_sources(); + + for res in &self.compilation_restrictions { + for source in sources.keys().filter(|path| { + if res.paths.is_match(path) { + true + } else if let Ok(path) = path.strip_prefix(&paths.root) { + res.paths.is_match(path) + } else { + false + } + }) { + let res: RestrictionsWithVersion<_> = + res.clone().try_into().map_err(SolcError::msg)?; + if !map.contains_key(source) { + map.insert(source.clone(), res); + } else { + map.get_mut(source.as_path()).unwrap().merge(res); + } + } + } + + Ok(map) + } + /// Creates a [Project] with the given `cached` and `no_artifacts` flags pub fn create_project(&self, cached: bool, no_artifacts: bool) -> Result { + let settings = self.compiler_settings()?; + let paths = self.project_paths(); let mut builder = Project::builder() .artifacts(self.configured_artifacts_handler()) - .paths(self.project_paths()) - .settings(self.compiler_settings()?) + .additional_settings(self.additional_settings(&settings)) + .restrictions(self.restrictions(&paths)?) + .settings(settings) + .paths(paths) .ignore_error_codes(self.ignored_error_codes.iter().copied().map(Into::into)) .ignore_paths(self.ignored_file_paths.clone()) .set_compiler_severity_filter(if self.deny_warnings { @@ -2243,6 +2311,8 @@ impl Default for Config { eof_version: None, alphanet: false, transaction_timeout: 120, + additional_compiler_profiles: Default::default(), + compilation_restrictions: Default::default(), eof: false, _non_exhaustive: (), } diff --git a/crates/forge/bin/cmd/bind_json.rs b/crates/forge/bin/cmd/bind_json.rs index c6a052836baf..de7a5a7a71aa 100644 --- a/crates/forge/bin/cmd/bind_json.rs +++ b/crates/forge/bin/cmd/bind_json.rs @@ -11,7 +11,7 @@ use foundry_compilers::{ multi::{MultiCompilerLanguage, MultiCompilerParsedSource}, project::ProjectCompiler, solc::SolcLanguage, - CompilerSettings, Graph, Project, + Graph, Project, }; use foundry_config::Config; use itertools::Itertools; @@ -72,7 +72,7 @@ impl BindJsonArgs { // We only generate bindings for a single Solidity version to avoid conflicts. let mut sources = graph // resolve graph into mapping language -> version -> sources - .into_sources_by_version(project.offline, &project.locked_versions, &project.compiler)? + .into_sources_by_version(&project)? .0 .into_iter() // we are only interested in Solidity sources @@ -81,7 +81,7 @@ impl BindJsonArgs { .1 .into_iter() // For now, we are always picking the latest version. - .max_by(|(v1, _), (v2, _)| v1.cmp(v2)) + .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2)) .unwrap() .1; @@ -229,7 +229,7 @@ impl PreprocessedState { fn compile(self) -> Result { let Self { sources, target_path, mut project, config } = self; - project.settings.update_output_selection(|selection| { + project.update_output_selection(|selection| { *selection = OutputSelection::ast_output_selection(); }); diff --git a/crates/forge/bin/cmd/compiler.rs b/crates/forge/bin/cmd/compiler.rs index a7115c4876b8..f5d62b671419 100644 --- a/crates/forge/bin/cmd/compiler.rs +++ b/crates/forge/bin/cmd/compiler.rs @@ -63,18 +63,14 @@ impl ResolveArgs { let project = config.project()?; let graph = Graph::resolve(&project.paths)?; - let (sources, _) = graph.into_sources_by_version( - project.offline, - &project.locked_versions, - &project.compiler, - )?; + let (sources, _) = graph.into_sources_by_version(&project)?; let mut output: BTreeMap> = BTreeMap::new(); for (language, sources) in sources { let mut versions_with_paths: Vec = sources .iter() - .map(|(version, sources)| { + .map(|(version, sources, _)| { let paths: Vec = sources .iter() .filter_map(|(path_file, _)| { diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 83494acb99de..e19feafcc628 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -20,7 +20,9 @@ use foundry_common::{ fmt::parse_tokens, shell, }; -use foundry_compilers::{artifacts::BytecodeObject, info::ContractInfo, utils::canonicalize}; +use foundry_compilers::{ + artifacts::BytecodeObject, info::ContractInfo, utils::canonicalize, ArtifactId, +}; use foundry_config::{ figment::{ self, @@ -106,9 +108,9 @@ impl CreateArgs { project.find_contract_path(&self.contract.name)? }; - let mut output = compile::compile_target(&target_path, &project, shell::is_json())?; + let output = compile::compile_target(&target_path, &project, shell::is_json())?; - let (abi, bin, _) = remove_contract(&mut output, &target_path, &self.contract.name)?; + let (abi, bin, id) = remove_contract(output, &target_path, &self.contract.name)?; let bin = match bin.object { BytecodeObject::Bytecode(_) => bin.object, @@ -148,8 +150,17 @@ impl CreateArgs { if self.unlocked { // Deploy with unlocked account let sender = self.eth.wallet.from.expect("required"); - self.deploy(abi, bin, params, provider, chain_id, sender, config.transaction_timeout) - .await + self.deploy( + abi, + bin, + params, + provider, + chain_id, + sender, + config.transaction_timeout, + id, + ) + .await } else { // Deploy with signer let signer = self.eth.wallet.signer().await?; @@ -157,8 +168,17 @@ impl CreateArgs { let provider = ProviderBuilder::<_, _, AnyNetwork>::default() .wallet(EthereumWallet::new(signer)) .on_provider(provider); - self.deploy(abi, bin, params, provider, chain_id, deployer, config.transaction_timeout) - .await + self.deploy( + abi, + bin, + params, + provider, + chain_id, + deployer, + config.transaction_timeout, + id, + ) + .await } } @@ -177,13 +197,14 @@ impl CreateArgs { &self, constructor_args: Option, chain: u64, + id: &ArtifactId, ) -> Result<()> { // NOTE: this does not represent the same `VerifyArgs` that would be sent after deployment, // since we don't know the address yet. let mut verify = forge_verify::VerifyArgs { address: Default::default(), contract: Some(self.contract.clone()), - compiler_version: None, + compiler_version: Some(id.version.to_string()), constructor_args, constructor_args_path: None, num_of_optimizations: None, @@ -204,6 +225,7 @@ impl CreateArgs { evm_version: self.opts.compiler.evm_version, show_standard_json_input: self.show_standard_json_input, guess_constructor_args: false, + compilation_profile: Some(id.profile.to_string()), }; // Check config for Etherscan API Keys to avoid preflight check failing if no @@ -229,6 +251,7 @@ impl CreateArgs { chain: u64, deployer_address: Address, timeout: u64, + id: ArtifactId, ) -> Result<()> { let bin = bin.into_bytes().unwrap_or_else(|| { panic!("no bytecode found in bin object for {}", self.contract.name) @@ -305,7 +328,7 @@ impl CreateArgs { constructor_args = Some(hex::encode(encoded_args)); } - self.verify_preflight_check(constructor_args.clone(), chain).await?; + self.verify_preflight_check(constructor_args.clone(), chain, &id).await?; } // Deploy the actual contract @@ -339,7 +362,7 @@ impl CreateArgs { let verify = forge_verify::VerifyArgs { address, contract: Some(self.contract), - compiler_version: None, + compiler_version: Some(id.version.to_string()), constructor_args, constructor_args_path: None, num_of_optimizations, @@ -357,6 +380,7 @@ impl CreateArgs { evm_version: self.opts.compiler.evm_version, show_standard_json_input: self.show_standard_json_input, guess_constructor_args: false, + compilation_profile: Some(id.profile.to_string()), }; sh_println!("Waiting for {} to detect contract deployment...", verify.verifier.verifier)?; verify.run().await diff --git a/crates/forge/bin/cmd/eip712.rs b/crates/forge/bin/cmd/eip712.rs index 5014d38d703b..eb1d8dc1d315 100644 --- a/crates/forge/bin/cmd/eip712.rs +++ b/crates/forge/bin/cmd/eip712.rs @@ -2,14 +2,10 @@ use clap::{Parser, ValueHint}; use eyre::{Ok, OptionExt, Result}; use foundry_cli::{opts::CoreBuildArgs, utils::LoadConfig}; use foundry_common::compile::ProjectCompiler; -use foundry_compilers::{ - artifacts::{ - output_selection::OutputSelection, - visitor::{Visitor, Walk}, - ContractDefinition, EnumDefinition, SourceUnit, StructDefinition, TypeDescriptions, - TypeName, - }, - CompilerSettings, +use foundry_compilers::artifacts::{ + output_selection::OutputSelection, + visitor::{Visitor, Walk}, + ContractDefinition, EnumDefinition, SourceUnit, StructDefinition, TypeDescriptions, TypeName, }; use std::{collections::BTreeMap, fmt::Write, path::PathBuf}; @@ -31,7 +27,7 @@ impl Eip712Args { let config = self.try_load_config_emit_warnings()?; let mut project = config.create_project(false, true)?; let target_path = dunce::canonicalize(self.target_path)?; - project.settings.update_output_selection(|selection| { + project.update_output_selection(|selection| { *selection = OutputSelection::ast_output_selection(); }); diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index 613d570785b9..4e811bcbfbf9 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -23,7 +23,7 @@ use foundry_cli::{ use foundry_common::{compile::ProjectCompiler, evm::EvmArgs, fs, shell, TestFunctionExt}; use foundry_compilers::{ artifacts::output_selection::OutputSelection, - compilers::{multi::MultiCompilerLanguage, CompilerSettings, Language}, + compilers::{multi::MultiCompilerLanguage, Language}, utils::source_files_iter, ProjectCompileOutput, }; @@ -203,7 +203,7 @@ impl TestArgs { filter: &ProjectPathsAwareFilter, ) -> Result> { let mut project = config.create_project(true, true)?; - project.settings.update_output_selection(|selection| { + project.update_output_selection(|selection| { *selection = OutputSelection::common_output_selection(["abi".to_string()]); }); diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 11bcd49e2c40..db87a85ba0d1 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -154,6 +154,8 @@ forgetest!(can_extract_config_values, |prj, cmd| { eof_version: None, alphanet: false, transaction_timeout: 120, + additional_compiler_profiles: Default::default(), + compilation_restrictions: Default::default(), eof: false, _non_exhaustive: (), }; diff --git a/crates/script/src/verify.rs b/crates/script/src/verify.rs index 55435c559242..220991703df7 100644 --- a/crates/script/src/verify.rs +++ b/crates/script/src/verify.rs @@ -155,6 +155,7 @@ impl VerifyBundle { evm_version: None, show_standard_json_input: false, guess_constructor_args: false, + compilation_profile: Some(artifact.profile.to_string()), }; return Some(verify) diff --git a/crates/verify/src/etherscan/flatten.rs b/crates/verify/src/etherscan/flatten.rs index ffe1496cad5d..a0b3defd7f90 100644 --- a/crates/verify/src/etherscan/flatten.rs +++ b/crates/verify/src/etherscan/flatten.rs @@ -90,7 +90,7 @@ impl EtherscanFlattenedSource { let out = SolcCompiler::Specific(solc).compile(&input)?; if out.errors.iter().any(|e| e.is_error()) { let mut o = AggregatedCompilerOutput::::default(); - o.extend(version, RawBuildInfo::new(&input, &out, false)?, out); + o.extend(version, RawBuildInfo::new(&input, &out, false)?, "default", out); let diags = o.diagnostics(&[], &[], Default::default()); eyre::bail!( diff --git a/crates/verify/src/etherscan/standard_json.rs b/crates/verify/src/etherscan/standard_json.rs index cab3010fa638..e2fb5d2a47c0 100644 --- a/crates/verify/src/etherscan/standard_json.rs +++ b/crates/verify/src/etherscan/standard_json.rs @@ -18,7 +18,8 @@ impl EtherscanSourceProvider for EtherscanStandardJsonSource { .wrap_err("Failed to get standard json input")? .normalize_evm_version(&context.compiler_version); - input.settings.libraries.libs = input + let mut settings = context.compiler_settings.solc.settings.clone(); + settings.libraries.libs = input .settings .libraries .libs @@ -28,8 +29,12 @@ impl EtherscanSourceProvider for EtherscanStandardJsonSource { }) .collect(); + settings.remappings = input.settings.remappings; + // remove all incompatible settings - input.settings.sanitize(&context.compiler_version, SolcLanguage::Solidity); + settings.sanitize(&context.compiler_version, SolcLanguage::Solidity); + + input.settings = settings; let source = serde_json::to_string(&input).wrap_err("Failed to parse standard json input")?; diff --git a/crates/verify/src/provider.rs b/crates/verify/src/provider.rs index bc01bd9e304d..ab6c5e9f642f 100644 --- a/crates/verify/src/provider.rs +++ b/crates/verify/src/provider.rs @@ -9,7 +9,8 @@ use eyre::{OptionExt, Result}; use foundry_common::compile::ProjectCompiler; use foundry_compilers::{ artifacts::{output_selection::OutputSelection, Metadata, Source}, - compilers::{multi::MultiCompilerParsedSource, solc::SolcCompiler, CompilerSettings}, + compilers::{multi::MultiCompilerParsedSource, solc::SolcCompiler}, + multi::MultiCompilerSettings, solc::Solc, Graph, Project, }; @@ -25,6 +26,7 @@ pub struct VerificationContext { pub target_path: PathBuf, pub target_name: String, pub compiler_version: Version, + pub compiler_settings: MultiCompilerSettings, } impl VerificationContext { @@ -33,6 +35,7 @@ impl VerificationContext { target_name: String, compiler_version: Version, config: Config, + compiler_settings: MultiCompilerSettings, ) -> Result { let mut project = config.project()?; project.no_artifacts = true; @@ -40,13 +43,13 @@ impl VerificationContext { let solc = Solc::find_or_install(&compiler_version)?; project.compiler.solc = Some(SolcCompiler::Specific(solc)); - Ok(Self { config, project, target_name, target_path, compiler_version }) + Ok(Self { config, project, target_name, target_path, compiler_version, compiler_settings }) } /// Compiles target contract requesting only ABI and returns it. pub fn get_target_abi(&self) -> Result { let mut project = self.project.clone(); - project.settings.update_output_selection(|selection| { + project.update_output_selection(|selection| { *selection = OutputSelection::common_output_selection(["abi".to_string()]) }); @@ -65,7 +68,7 @@ impl VerificationContext { /// Compiles target file requesting only metadata and returns it. pub fn get_target_metadata(&self) -> Result { let mut project = self.project.clone(); - project.settings.update_output_selection(|selection| { + project.update_output_selection(|selection| { *selection = OutputSelection::common_output_selection(["metadata".to_string()]); }); diff --git a/crates/verify/src/verify.rs b/crates/verify/src/verify.rs index 89cfd99aa676..9c32ee95f5bf 100644 --- a/crates/verify/src/verify.rs +++ b/crates/verify/src/verify.rs @@ -80,6 +80,10 @@ pub struct VerifyArgs { #[arg(long, value_name = "VERSION")] pub compiler_version: Option, + /// The compilation profile to use to build the smart contract. + #[arg(long, value_name = "PROFILE_NAME")] + pub compilation_profile: Option, + /// The number of optimization runs used to build the smart contract. #[arg(long, visible_alias = "optimizer-runs", value_name = "NUM")] pub num_of_optimizations: Option, @@ -258,6 +262,8 @@ impl VerifyArgs { project.find_contract_path(&contract.name)? }; + let cache = project.read_cache_file().ok(); + let version = if let Some(ref version) = self.compiler_version { version.trim_start_matches('v').parse()? } else if let Some(ref solc) = config.solc { @@ -265,10 +271,8 @@ impl VerifyArgs { SolcReq::Version(version) => version.to_owned(), SolcReq::Local(solc) => Solc::new(solc)?.version, } - } else if let Some(entry) = project - .read_cache_file() - .ok() - .and_then(|mut cache| cache.files.remove(&contract_path)) + } else if let Some(entry) = + cache.as_ref().and_then(|cache| cache.files.get(&contract_path).cloned()) { let unique_versions = entry .artifacts @@ -291,7 +295,48 @@ impl VerifyArgs { eyre::bail!("If cache is disabled, compiler version must be either provided with `--compiler-version` option or set in foundry.toml") }; - VerificationContext::new(contract_path, contract.name.clone(), version, config) + let settings = if let Some(profile) = &self.compilation_profile { + if profile == "default" { + &project.settings + } else if let Some(settings) = project.additional_settings.get(profile.as_str()) { + settings + } else { + eyre::bail!("Unknown compilation profile: {}", profile) + } + } else if let Some((cache, entry)) = cache + .as_ref() + .and_then(|cache| Some((cache, cache.files.get(&contract_path)?.clone()))) + { + let profiles = entry + .artifacts + .get(&contract.name) + .and_then(|artifacts| artifacts.get(&version)) + .map(|artifacts| artifacts.keys().collect::>()) + .unwrap_or_default(); + + if profiles.is_empty() { + eyre::bail!("No matching artifact found for {}", contract.name); + } else if profiles.len() > 1 { + eyre::bail!("Ambiguous compilation profiles found in cache: {}, please specify the profile through `--compilation-profile` flag", profiles.iter().join(", ")) + } + + let profile = profiles.into_iter().next().unwrap().to_owned(); + let settings = cache.profiles.get(&profile).expect("must be present"); + + settings + } else if project.additional_settings.is_empty() { + &project.settings + } else { + eyre::bail!("If cache is disabled, compilation profile must be provided with `--compiler-version` option or set in foundry.toml") + }; + + VerificationContext::new( + contract_path, + contract.name.clone(), + version, + config, + settings.clone(), + ) } else { if config.get_rpc_url().is_none() { eyre::bail!("You have to provide a contract name or a valid RPC URL") @@ -311,11 +356,19 @@ impl VerifyArgs { )) }; + let settings = project + .settings_profiles() + .find_map(|(name, settings)| { + (name == artifact_id.profile.as_str()).then_some(settings) + }) + .expect("must be present"); + VerificationContext::new( artifact_id.source.clone(), artifact_id.name.split('.').next().unwrap().to_owned(), artifact_id.version.clone(), config, + settings.clone(), ) } } From c13d42e850da353c0856a8b0d4123e13cc40045d Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 19 Nov 2024 01:27:51 +0400 Subject: [PATCH 8/8] fix: identification of contracts in scripts (#9346) * fix: identification of contracts in scripts * clippy --- crates/script/src/simulate.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index f8f9c9a3662f..a9798c43e471 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -16,7 +16,7 @@ use eyre::{Context, Result}; use forge_script_sequence::{ScriptSequence, TransactionWithMetadata}; use foundry_cheatcodes::Wallets; use foundry_cli::utils::{has_different_gas_calc, now}; -use foundry_common::{get_contract_name, ContractData}; +use foundry_common::ContractData; use foundry_evm::traces::{decode_trace_arena, render_trace_arena}; use futures::future::{join_all, try_join_all}; use parking_lot::RwLock; @@ -205,9 +205,8 @@ impl PreSimulationState { .contracts .iter() .filter_map(move |(addr, contract_id)| { - let contract_name = get_contract_name(contract_id); if let Ok(Some((_, data))) = - self.build_data.known_contracts.find_by_name_or_identifier(contract_name) + self.build_data.known_contracts.find_by_name_or_identifier(contract_id) { return Some((*addr, data)); }