Skip to content

Commit 7bf3576

Browse files
feat: add the ability to specify the hardfork when running Solidity tests (#1287)
1 parent 214c31c commit 7bf3576

File tree

17 files changed

+633
-112
lines changed

17 files changed

+633
-112
lines changed

.changeset/chatty-radios-draw.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nomicfoundation/edr": minor
3+
---
4+
5+
Added the ability to specify the hardfork when running Solidity tests. Added support for the Osaka hardfork in Solidity tests.

crates/edr_napi/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,8 @@ export interface SolidityTestRunnerConfigArgs {
660660
* Defaults to `31337`.
661661
*/
662662
chainId?: bigint
663+
/** The hardfork to use for EVM execution. */
664+
hardfork: string
663665
/**
664666
* The gas limit for each test case.
665667
* Defaults to `9_223_372_036_854_775_807` (`i64::MAX`).
@@ -700,6 +702,11 @@ export interface SolidityTestRunnerConfigArgs {
700702
* Defaults to false.
701703
*/
702704
disableBlockGasLimit?: boolean
705+
/**
706+
* Whether to enable the EIP-7825 (Osaka) transaction gas limit cap.
707+
* Defaults to false.
708+
*/
709+
enableTxGasLimitCap?: boolean
703710
/**
704711
* The memory limit of the EVM in bytes.
705712
* Defaults to `33_554_432` (2^25 = 32MiB).

crates/edr_napi/src/solidity_tests/config.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ pub struct SolidityTestRunnerConfigArgs {
7575
/// Defaults to `31337`.
7676
#[serde(serialize_with = "serialize_optional_bigint_as_struct")]
7777
pub chain_id: Option<BigInt>,
78+
/// The hardfork to use for EVM execution.
79+
pub hardfork: String,
7880
/// The gas limit for each test case.
7981
/// Defaults to `9_223_372_036_854_775_807` (`i64::MAX`).
8082
#[serde(serialize_with = "serialize_optional_bigint_as_struct")]
@@ -107,6 +109,9 @@ pub struct SolidityTestRunnerConfigArgs {
107109
/// Whether to disable the block gas limit.
108110
/// Defaults to false.
109111
pub disable_block_gas_limit: Option<bool>,
112+
/// Whether to enable the EIP-7825 (Osaka) transaction gas limit cap.
113+
/// Defaults to false.
114+
pub enable_tx_gas_limit_cap: Option<bool>,
110115
/// The memory limit of the EVM in bytes.
111116
/// Defaults to `33_554_432` (2^25 = 32MiB).
112117
#[serde(serialize_with = "serialize_optional_bigint_as_struct")]
@@ -184,6 +189,7 @@ impl SolidityTestRunnerConfigArgs {
184189
initial_balance,
185190
block_number,
186191
chain_id,
192+
hardfork,
187193
gas_limit,
188194
gas_price,
189195
block_base_fee_per_gas,
@@ -192,6 +198,7 @@ impl SolidityTestRunnerConfigArgs {
192198
block_difficulty,
193199
block_gas_limit,
194200
disable_block_gas_limit,
201+
enable_tx_gas_limit_cap,
195202
memory_limit,
196203
local_predeploys,
197204
eth_rpc_url,
@@ -308,6 +315,7 @@ impl SolidityTestRunnerConfigArgs {
308315
initial_balance: initial_balance.map(TryCast::try_cast).transpose()?,
309316
block_number: block_number.map(TryCast::try_cast).transpose()?,
310317
chain_id: chain_id.map(TryCast::try_cast).transpose()?,
318+
hardfork,
311319
gas_limit: gas_limit.map(TryCast::try_cast).transpose()?,
312320
gas_price: gas_price.map(TryCast::try_cast).transpose()?,
313321
block_base_fee_per_gas: block_base_fee_per_gas.map(TryCast::try_cast).transpose()?,
@@ -316,6 +324,7 @@ impl SolidityTestRunnerConfigArgs {
316324
block_difficulty: block_difficulty.map(TryCast::try_cast).transpose()?,
317325
block_gas_limit: block_gas_limit.map(TryCast::try_cast).transpose()?,
318326
disable_block_gas_limit,
327+
enable_tx_gas_limit_cap,
319328
memory_limit: memory_limit.map(TryCast::try_cast).transpose()?,
320329
local_predeploys,
321330
fork_url: eth_rpc_url,

crates/edr_napi/test/coverage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ describe("Code coverage", () => {
248248
const testSuites = artifacts.map((artifact) => artifact.id);
249249
const config = {
250250
projectRoot: __dirname,
251+
hardfork: l1HardforkToString(l1HardforkLatest()),
251252
observability: {
252253
codeCoverage: {
253254
onCollectedCoverageCallback: async (coverage: Uint8Array[]) => {
@@ -279,6 +280,7 @@ describe("Code coverage", () => {
279280
const testSuites = artifacts.map((artifact) => artifact.id);
280281
const config = {
281282
projectRoot: __dirname,
283+
hardfork: l1HardforkToString(l1HardforkLatest()),
282284
observability: {
283285
codeCoverage: {
284286
onCollectedCoverageCallback: async (_coverage: Uint8Array[]) => {

crates/edr_napi/test/op.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ describe("Multi-chain", () => {
325325
const testSuites = artifacts.map((artifact) => artifact.id);
326326
const config = {
327327
projectRoot: __dirname,
328+
hardfork: opHardforkToString(opLatestHardfork()),
328329
};
329330

330331
const [, results] = await runAllSolidityTests(

crates/edr_napi/test/solidity-tests.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { assert } from "chai";
22

3-
import { EdrContext, L1_CHAIN_TYPE, l1SolidityTestRunnerFactory } from "..";
3+
import {
4+
EdrContext,
5+
L1_CHAIN_TYPE,
6+
l1HardforkLatest,
7+
l1HardforkToString,
8+
l1SolidityTestRunnerFactory,
9+
} from "..";
410
import { loadContract, runAllSolidityTests } from "./helpers";
511

612
describe("Solidity Tests", () => {
@@ -22,6 +28,7 @@ describe("Solidity Tests", () => {
2228
const testSuites = artifacts.map((artifact) => artifact.id);
2329
const config = {
2430
projectRoot: __dirname,
31+
hardfork: l1HardforkToString(l1HardforkLatest()),
2532
};
2633

2734
const [, results] = await runAllSolidityTests(
@@ -57,6 +64,7 @@ describe("Solidity Tests", () => {
5764
const testSuites = artifacts.map((artifact) => artifact.id);
5865
const config = {
5966
projectRoot: __dirname,
67+
hardfork: l1HardforkToString(l1HardforkLatest()),
6068
// Memory limit is too large
6169
memoryLimit: 2n ** 65n,
6270
};
@@ -82,6 +90,7 @@ describe("Solidity Tests", () => {
8290
const testSuites = artifacts.map((artifact) => artifact.id);
8391
const config = {
8492
projectRoot: __dirname,
93+
hardfork: l1HardforkToString(l1HardforkLatest()),
8594
};
8695

8796
artifacts[0].contract.bytecode = "invalid bytecode";
@@ -112,6 +121,7 @@ describe("Solidity Tests", () => {
112121
testSuites,
113122
{
114123
projectRoot: __dirname,
124+
hardfork: l1HardforkToString(l1HardforkLatest()),
115125
testPattern: "Multiply",
116126
}
117127
);

crates/edr_napi_core/src/solidity/config.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use std::{collections::HashMap, path::PathBuf};
1+
use std::{collections::HashMap, path::PathBuf, str::FromStr};
22

3-
use edr_primitives::{Address, U256};
3+
use edr_chain_spec::EvmSpecId;
4+
use edr_primitives::{Address, UnknownHardfork, U256};
45
use edr_solidity_tests::{
56
backend::Predeploy,
67
evm_context::HardforkTr,
@@ -117,6 +118,8 @@ pub struct TestRunnerConfig {
117118
/// The value of the `chainid` opcode in tests.
118119
/// Defaults to `31337`.
119120
pub chain_id: Option<u64>,
121+
/// The hardfork to use for EVM execution.
122+
pub hardfork: String,
120123
/// The gas limit for each test case.
121124
/// Defaults to `9_223_372_036_854_775_807` (`i64::MAX`).
122125
pub gas_limit: Option<u64>,
@@ -141,6 +144,9 @@ pub struct TestRunnerConfig {
141144
/// Whether to disable the block gas limit.
142145
/// Defaults to false.
143146
pub disable_block_gas_limit: Option<bool>,
147+
/// Whether to enable the EIP-7825 (Osaka) transaction gas limit cap.
148+
/// Defaults to false.
149+
pub enable_tx_gas_limit_cap: Option<bool>,
144150
/// The memory limit of the EVM in bytes.
145151
/// Defaults to `33_554_432` (2^25 = 32MiB).
146152
pub memory_limit: Option<u64>,
@@ -180,7 +186,22 @@ pub struct TestRunnerConfig {
180186
Option<HashMap<TestFunctionIdentifier, TestFunctionConfigOverride>>,
181187
}
182188

183-
impl<HardforkT: HardforkTr> TryFrom<TestRunnerConfig> for SolidityTestRunnerConfig<HardforkT> {
189+
fn parse_hardfork<HardforkT>(hardfork: String) -> napi::Result<HardforkT>
190+
where
191+
HardforkT: FromStr<Err = UnknownHardfork> + Into<EvmSpecId>,
192+
{
193+
hardfork.parse().map_err(|UnknownHardfork| {
194+
napi::Error::new(
195+
napi::Status::InvalidArg,
196+
format!("Unknown hardfork: {hardfork}"),
197+
)
198+
})
199+
}
200+
201+
impl<HardforkT> TryFrom<TestRunnerConfig> for SolidityTestRunnerConfig<HardforkT>
202+
where
203+
HardforkT: HardforkTr + FromStr<Err = UnknownHardfork> + Into<EvmSpecId>,
204+
{
184205
type Error = napi::Error;
185206

186207
fn try_from(value: TestRunnerConfig) -> Result<Self, Self::Error> {
@@ -193,6 +214,7 @@ impl<HardforkT: HardforkTr> TryFrom<TestRunnerConfig> for SolidityTestRunnerConf
193214
initial_balance,
194215
block_number,
195216
chain_id,
217+
hardfork,
196218
gas_limit,
197219
gas_price,
198220
block_base_fee_per_gas,
@@ -201,6 +223,7 @@ impl<HardforkT: HardforkTr> TryFrom<TestRunnerConfig> for SolidityTestRunnerConf
201223
block_difficulty,
202224
block_gas_limit,
203225
disable_block_gas_limit,
226+
enable_tx_gas_limit_cap,
204227
memory_limit,
205228
local_predeploys,
206229
fork_url,
@@ -224,6 +247,8 @@ impl<HardforkT: HardforkTr> TryFrom<TestRunnerConfig> for SolidityTestRunnerConf
224247

225248
evm_opts.env.chain_id = chain_id;
226249

250+
evm_opts.spec = parse_hardfork(hardfork)?;
251+
227252
evm_opts.env.gas_price = gas_price;
228253

229254
if let Some(block_base_fee_per_gas) = block_base_fee_per_gas {
@@ -280,6 +305,10 @@ impl<HardforkT: HardforkTr> TryFrom<TestRunnerConfig> for SolidityTestRunnerConf
280305
evm_opts.disable_block_gas_limit = disable_block_gas_limit;
281306
}
282307

308+
if let Some(enable_tx_gas_limit_cap) = enable_tx_gas_limit_cap {
309+
evm_opts.enable_tx_gas_limit_cap = enable_tx_gas_limit_cap;
310+
}
311+
283312
let local_predeploys = local_predeploys.unwrap_or_default();
284313

285314
let generate_gas_report = generate_gas_report.unwrap_or(false);

crates/edr_solidity_tests/src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ impl<HardforkT: HardforkTr> SolidityTestRunnerConfig<HardforkT> {
139139
memory_limit: 1 << 25, // 2**25 = 32MiB
140140
isolate: false,
141141
disable_block_gas_limit: false,
142+
enable_tx_gas_limit_cap: false,
142143
fork_headers: None,
143144
}
144145
}

crates/foundry/evm/core/src/fork/init.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515

1616
/// Initializes a REVM block environment based on a forked
1717
/// ethereum provider.
18+
#[allow(clippy::too_many_arguments)]
1819
pub async fn environment<NetworkT, ProviderT, BlockT, TxT, HardforkT>(
1920
provider: &ProviderT,
2021
memory_limit: u64,
@@ -23,6 +24,7 @@ pub async fn environment<NetworkT, ProviderT, BlockT, TxT, HardforkT>(
2324
pin_block: Option<u64>,
2425
origin: Address,
2526
disable_block_gas_limit: bool,
27+
enable_tx_gas_limit_cap: bool,
2628
) -> eyre::Result<(
2729
EvmEnv<BlockT, TxT, HardforkT>,
2830
<NetworkT as Network>::BlockResponse,
@@ -69,6 +71,7 @@ where
6971
override_chain_id.unwrap_or(rpc_chain_id),
7072
memory_limit,
7173
disable_block_gas_limit,
74+
enable_tx_gas_limit_cap,
7275
);
7376

7477
let mut env = EvmEnv {
@@ -105,6 +108,7 @@ pub fn configure_env<HardforkT>(
105108
chain_id: u64,
106109
memory_limit: u64,
107110
disable_block_gas_limit: bool,
111+
enable_tx_gas_limit_cap: bool,
108112
) -> CfgEnv<HardforkT>
109113
where
110114
HardforkT: Default,
@@ -119,5 +123,11 @@ where
119123
cfg.disable_eip3607 = true;
120124
cfg.disable_block_gas_limit = disable_block_gas_limit;
121125
cfg.disable_nonce_check = true;
126+
// By default do not enforce transaction gas limits imposed by Osaka (EIP-7825).
127+
// Users can opt-in to enable these limits by setting `enable_tx_gas_limit` to
128+
// true.
129+
if !enable_tx_gas_limit_cap {
130+
cfg.tx_gas_limit_cap = Some(u64::MAX);
131+
}
122132
cfg
123133
}

crates/foundry/evm/core/src/opts.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ pub struct EvmOpts<HardforkT> {
6767

6868
/// Whether to disable block gas limit checks.
6969
pub disable_block_gas_limit: bool,
70+
71+
/// Whether to enable the EIP-7825 (Osaka) transaction gas limit cap.
72+
pub enable_tx_gas_limit_cap: bool,
7073
}
7174

7275
impl<HardforkT> Default for EvmOpts<HardforkT>
@@ -90,6 +93,7 @@ where
9093
memory_limit: 0,
9194
isolate: false,
9295
disable_block_gas_limit: false,
96+
enable_tx_gas_limit_cap: false,
9397
}
9498
}
9599
}
@@ -137,6 +141,7 @@ where
137141
self.fork_block_number,
138142
self.sender,
139143
self.disable_block_gas_limit,
144+
self.enable_tx_gas_limit_cap,
140145
)
141146
.await
142147
.wrap_err_with(|| {
@@ -160,6 +165,7 @@ where
160165
self.env.chain_id.unwrap_or(edr_defaults::DEV_CHAIN_ID),
161166
self.memory_limit,
162167
self.disable_block_gas_limit,
168+
self.enable_tx_gas_limit_cap,
163169
);
164170

165171
crate::Env {

0 commit comments

Comments
 (0)