diff --git a/crates/common/src/evm.rs b/crates/common/src/evm.rs index e23c1da339ec..4b2a94f4377d 100644 --- a/crates/common/src/evm.rs +++ b/crates/common/src/evm.rs @@ -272,6 +272,10 @@ pub struct EnvArgs { #[arg(long, value_name = "MEMORY_LIMIT")] #[serde(skip_serializing_if = "Option::is_none")] pub memory_limit: Option, + + /// Whether to disable the block gas limit checks. + #[arg(long, visible_alias = "no-gas-limit")] + pub disable_block_gas_limit: bool, } impl EvmArgs { diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 5c704d6c7bf6..89e1c3658688 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -379,6 +379,9 @@ pub struct Config { /// Useful for more correct gas accounting and EVM behavior in general. pub isolate: bool, + /// Whether to disable the block gas limit. + pub disable_block_gas_limit: bool, + /// Address labels pub labels: HashMap, @@ -1889,6 +1892,7 @@ impl Default for Config { block_difficulty: 0, block_prevrandao: Default::default(), block_gas_limit: None, + disable_block_gas_limit: false, memory_limit: 1 << 27, // 2**27 = 128MiB = 134_217_728 bytes eth_rpc_url: None, eth_rpc_jwt: None, diff --git a/crates/evm/core/src/fork/init.rs b/crates/evm/core/src/fork/init.rs index 11e65916498d..84830d5a2b83 100644 --- a/crates/evm/core/src/fork/init.rs +++ b/crates/evm/core/src/fork/init.rs @@ -17,6 +17,7 @@ pub async fn environment( override_chain_id: Option, pin_block: Option, origin: Address, + disable_block_gas_limit: bool, ) -> eyre::Result<(Env, Block)> { let block_number = if let Some(pin_block) = pin_block { pin_block @@ -55,6 +56,7 @@ pub async fn environment( // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the caller // is a contract. So we disable the check by default. cfg.disable_eip3607 = true; + cfg.disable_block_gas_limit = disable_block_gas_limit; let mut env = Env { cfg, diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index 510f14254ad7..2dee3a9b59b3 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -64,6 +64,9 @@ pub struct EvmOpts { /// Whether to enable isolation of calls. pub isolate: bool, + + /// Whether to disable block gas limit checks. + pub disable_block_gas_limit: bool, } impl EvmOpts { @@ -96,6 +99,7 @@ impl EvmOpts { self.env.chain_id, self.fork_block_number, self.sender, + self.disable_block_gas_limit, ) .await .wrap_err_with(|| { @@ -114,6 +118,7 @@ impl EvmOpts { // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the // caller is a contract. So we disable the check by default. cfg.disable_eip3607 = true; + cfg.disable_block_gas_limit = self.disable_block_gas_limit; revm::primitives::Env { block: BlockEnv { diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index 2a66ac76280d..94152a444486 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -467,9 +467,13 @@ impl InspectorStack { data.env.tx.value = value; data.env.tx.nonce = Some(nonce); // Add 21000 to the gas limit to account for the base cost of transaction. - // We might have modified block gas limit earlier and revm will reject tx with gas limit > - // block gas limit, so we adjust. - data.env.tx.gas_limit = std::cmp::min(gas_limit + 21000, data.env.block.gas_limit.to()); + data.env.tx.gas_limit = gas_limit + 21000; + // If we haven't disabled gas limit checks, ensure that transaction gas limit will not + // exceed block gas limit. + if !data.env.cfg.disable_block_gas_limit { + data.env.tx.gas_limit = + std::cmp::min(data.env.tx.gas_limit, data.env.block.gas_limit.to()); + } data.env.tx.gas_price = U256::ZERO; self.inner_context_data = Some(InnerContextData { diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index f2dbf22c7aac..20bbb8e1b596 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -85,6 +85,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { block_difficulty: 10, block_prevrandao: B256::random(), block_gas_limit: Some(100u64.into()), + disable_block_gas_limit: false, memory_limit: 1 << 27, eth_rpc_url: Some("localhost".to_string()), eth_rpc_jwt: None, diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 61cbab489e77..f449a0ac0501 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -490,3 +490,39 @@ contract TransientTest is Test { cmd.args(["test", "-vvvv", "--isolate", "--evm-version", "cancun"]).assert_success(); }); + +forgetest_init!(can_disable_block_gas_limit, |prj, cmd| { + prj.wipe_contracts(); + + let endpoint = rpc::next_http_archive_rpc_endpoint(); + + prj.add_test( + "Contract.t.sol", + &r#"pragma solidity 0.8.24; +import {Test} from "forge-std/Test.sol"; + +contract C is Test {} + +contract GasWaster { + function waste() public { + for (uint256 i = 0; i < 100; i++) { + new C(); + } + } +} + +contract GasLimitTest is Test { + function test() public { + vm.createSelectFork(""); + + GasWaster waster = new GasWaster(); + waster.waste(); + } +} + "# + .replace("", &endpoint), + ) + .unwrap(); + + cmd.args(["test", "-vvvv", "--isolate", "--disable-block-gas-limit"]).assert_success(); +});