Skip to content

Commit 8c044be

Browse files
authored
chore: bump default memory limit to 128MiB (#6338)
* chore: bump default memory limit to 128MiB * docs * add traces to test fails * fix: test memory limit
1 parent 9b04724 commit 8c044be

File tree

12 files changed

+90
-80
lines changed

12 files changed

+90
-80
lines changed

crates/common/src/evm.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,10 @@ pub struct EnvArgs {
242242
#[serde(skip_serializing_if = "Option::is_none")]
243243
pub block_gas_limit: Option<u64>,
244244

245-
/// The memory limit of the EVM in bytes (32 MB by default)
245+
/// The memory limit per EVM execution in bytes.
246+
/// If this limit is exceeded, a `MemoryLimitOOG` result is thrown.
247+
///
248+
/// The default is 128MiB.
246249
#[clap(long, value_name = "MEMORY_LIMIT")]
247250
#[serde(skip_serializing_if = "Option::is_none")]
248251
pub memory_limit: Option<u64>,

crates/config/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ block_timestamp = 0
131131
block_difficulty = 0
132132
block_prevrandao = '0x0000000000000000000000000000000000000000'
133133
block_gas_limit = 30000000
134-
memory_limit = 33554432
134+
memory_limit = 134217728
135135
extra_output = ["metadata"]
136136
extra_output_files = []
137137
names = false

crates/config/src/lib.rs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -252,58 +252,65 @@ pub struct Config {
252252
/// The chain name or EIP-155 chain ID.
253253
#[serde(rename = "chain_id", alias = "chain")]
254254
pub chain: Option<Chain>,
255-
/// Block gas limit
255+
/// Block gas limit.
256256
pub gas_limit: GasLimit,
257257
/// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests.
258258
pub code_size_limit: Option<usize>,
259-
/// `tx.gasprice` value during EVM execution"
259+
/// `tx.gasprice` value during EVM execution.
260260
///
261261
/// This is an Option, so we can determine in fork mode whether to use the config's gas price
262-
/// (if set by user) or the remote client's gas price
262+
/// (if set by user) or the remote client's gas price.
263263
pub gas_price: Option<u64>,
264-
/// the base fee in a block
264+
/// The base fee in a block.
265265
pub block_base_fee_per_gas: u64,
266-
/// the `block.coinbase` value during EVM execution
266+
/// The `block.coinbase` value during EVM execution.
267267
pub block_coinbase: Address,
268-
/// the `block.timestamp` value during EVM execution
268+
/// The `block.timestamp` value during EVM execution.
269269
pub block_timestamp: u64,
270-
/// the `block.difficulty` value during EVM execution
270+
/// The `block.difficulty` value during EVM execution.
271271
pub block_difficulty: u64,
272-
/// Before merge the `block.max_hash` after merge it is `block.prevrandao`
272+
/// Before merge the `block.max_hash`, after merge it is `block.prevrandao`.
273273
pub block_prevrandao: B256,
274274
/// the `block.gaslimit` value during EVM execution
275275
pub block_gas_limit: Option<GasLimit>,
276-
/// The memory limit of the EVM (32 MB by default)
276+
/// The memory limit per EVM execution in bytes.
277+
/// If this limit is exceeded, a `MemoryLimitOOG` result is thrown.
278+
///
279+
/// The default is 128MiB.
277280
pub memory_limit: u64,
278-
/// Additional output selection for all contracts
279-
/// such as "ir", "devdoc", "storageLayout", etc.
280-
/// See [Solc Compiler Api](https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-api)
281+
/// Additional output selection for all contracts, such as "ir", "devdoc", "storageLayout",
282+
/// etc.
283+
///
284+
/// See the [Solc Compiler Api](https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-api) for more information.
281285
///
282-
/// The following values are always set because they're required by `forge`
283-
//{
284-
// "*": [
285-
// "abi",
286-
// "evm.bytecode",
287-
// "evm.deployedBytecode",
288-
// "evm.methodIdentifiers"
289-
// ]
290-
// }
291-
// "#
286+
/// The following values are always set because they're required by `forge`:
287+
/// ```json
288+
/// {
289+
/// "*": [
290+
/// "abi",
291+
/// "evm.bytecode",
292+
/// "evm.deployedBytecode",
293+
/// "evm.methodIdentifiers"
294+
/// ]
295+
/// }
296+
/// ```
292297
#[serde(default)]
293298
pub extra_output: Vec<ContractOutputSelection>,
294-
/// If set , a separate `json` file will be emitted for every contract depending on the
299+
/// If set, a separate JSON file will be emitted for every contract depending on the
295300
/// selection, eg. `extra_output_files = ["metadata"]` will create a `metadata.json` for
296-
/// each contract in the project. See [Contract Metadata](https://docs.soliditylang.org/en/latest/metadata.html)
301+
/// each contract in the project.
302+
///
303+
/// See [Contract Metadata](https://docs.soliditylang.org/en/latest/metadata.html) for more information.
297304
///
298305
/// The difference between `extra_output = ["metadata"]` and
299306
/// `extra_output_files = ["metadata"]` is that the former will include the
300307
/// contract's metadata in the contract's json artifact, whereas the latter will emit the
301308
/// output selection as separate files.
302309
#[serde(default)]
303310
pub extra_output_files: Vec<ContractOutputSelection>,
304-
/// Print the names of the compiled contracts
311+
/// Whether to print the names of the compiled contracts.
305312
pub names: bool,
306-
/// Print the sizes of the compiled contracts
313+
/// Whether to print the sizes of the compiled contracts.
307314
pub sizes: bool,
308315
/// If set to true, changes compilation pipeline to go through the Yul intermediate
309316
/// representation.
@@ -1795,7 +1802,7 @@ impl Default for Config {
17951802
block_difficulty: 0,
17961803
block_prevrandao: Default::default(),
17971804
block_gas_limit: None,
1798-
memory_limit: 1 << 25, // 32MiB = 33554432 bytes
1805+
memory_limit: 1 << 27, // 2**27 = 128MiB = 134_217_728 bytes
17991806
eth_rpc_url: None,
18001807
eth_rpc_jwt: None,
18011808
etherscan_api_key: None,
@@ -3379,7 +3386,7 @@ mod tests {
33793386
initial_balance = '0xffffffffffffffffffffffff'
33803387
libraries = []
33813388
libs = ['lib']
3382-
memory_limit = 33554432
3389+
memory_limit = 134217728
33833390
names = false
33843391
no_storage_caching = false
33853392
no_rpc_rate_limit = false

crates/evm/core/src/opts.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,48 @@ use serde::{Deserialize, Deserializer, Serialize};
1212

1313
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1414
pub struct EvmOpts {
15+
/// The EVM environment configuration.
1516
#[serde(flatten)]
1617
pub env: Env,
1718

18-
/// Fetch state over a remote instead of starting from empty state
19+
/// Fetch state over a remote instead of starting from empty state.
1920
#[serde(rename = "eth_rpc_url")]
2021
pub fork_url: Option<RpcUrl>,
2122

22-
/// pins the block number for the state fork
23+
/// Pins the block number for the state fork.
2324
pub fork_block_number: Option<u64>,
2425

25-
/// The number of retries
26+
/// The number of retries.
2627
pub fork_retries: Option<u32>,
2728

28-
/// initial retry backoff
29+
/// Initial retry backoff.
2930
pub fork_retry_backoff: Option<u64>,
3031

31-
/// The available compute units per second
32+
/// The available compute units per second.
33+
///
34+
/// See also <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>
3235
pub compute_units_per_second: Option<u64>,
3336

34-
/// Disables rate limiting entirely.
37+
/// Disables RPC rate limiting entirely.
3538
pub no_rpc_rate_limit: bool,
3639

3740
/// Disables storage caching entirely.
3841
pub no_storage_caching: bool,
3942

40-
/// the initial balance of each deployed test contract
43+
/// The initial balance of each deployed test contract.
4144
pub initial_balance: U256,
4245

43-
/// the address which will be executing all tests
46+
/// The address which will be executing all tests.
4447
pub sender: Address,
4548

46-
/// enables the FFI cheatcode
49+
/// Enables the FFI cheatcode.
4750
pub ffi: bool,
4851

49-
/// Verbosity mode of EVM output as number of occurrences
52+
/// Verbosity mode of EVM output as number of occurrences.
5053
pub verbosity: u8,
5154

52-
/// The memory limit of the EVM in bytes.
55+
/// The memory limit per EVM execution in bytes.
56+
/// If this limit is exceeded, a `MemoryLimitOOG` result is thrown.
5357
pub memory_limit: u64,
5458
}
5559

crates/evm/evm/src/executors/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -489,26 +489,24 @@ impl Executor {
489489

490490
// If this test failed any asserts, then this changeset will contain changes `false -> true`
491491
// for the contract's `failed` variable and the `globalFailure` flag in the state of the
492-
// cheatcode address which are both read when call `"failed()(bool)"` in the next step
492+
// cheatcode address which are both read when we call `"failed()(bool)"` in the next step
493493
backend.commit(state_changeset);
494-
let executor =
495-
Executor::new(backend, self.env.clone(), self.inspector.clone(), self.gas_limit);
496494

497495
let mut success = !reverted;
498496
if success {
499497
// Check if a DSTest assertion failed
500-
let call =
501-
executor.call::<_, _>(CALLER, address, "failed()(bool)", vec![], U256::ZERO, None);
502-
498+
let executor =
499+
Executor::new(backend, self.env.clone(), self.inspector.clone(), self.gas_limit);
500+
let call = executor.call(CALLER, address, "failed()(bool)", vec![], U256::ZERO, None);
503501
if let Ok(CallResult { result: failed, .. }) = call {
504-
let failed = failed
505-
.as_bool()
506-
.expect("Failed to decode DSTest `failed` variable. This is a bug");
507-
success = !failed;
502+
debug!(?failed, "DSTest");
503+
success = !failed.as_bool().unwrap();
508504
}
509505
}
510506

511-
Ok(should_fail ^ success)
507+
let result = should_fail ^ success;
508+
debug!(should_fail, success, result);
509+
Ok(result)
512510
}
513511

514512
/// Creates the environment to use when executing a transaction in a test context

crates/forge/bin/cmd/test/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,10 @@ impl TestArgs {
208208
filter.args_mut().test_pattern = self.debug.clone();
209209
let num_filtered = runner.matching_test_function_count(&filter);
210210
if num_filtered != 1 {
211-
return Err(
212-
eyre::eyre!("{num_filtered} tests matched your criteria, but exactly 1 test must match in order to run the debugger.\n
213-
\n
214-
Use --match-contract and --match-path to further limit the search."));
211+
eyre::bail!(
212+
"{num_filtered} tests matched your criteria, but exactly 1 test must match in order to run the debugger.\n\n\
213+
Use --match-contract and --match-path to further limit the search."
214+
);
215215
}
216216
let test_funcs = runner.get_matching_test_functions(&filter);
217217
// if we debug a fuzz test, we should not collect data on the first run
@@ -441,7 +441,7 @@ impl Test {
441441
}
442442

443443
/// Represents the bundled results of all tests
444-
#[derive(Clone)]
444+
#[derive(Clone, Debug)]
445445
pub struct TestOutcome {
446446
/// Whether failures are allowed
447447
pub allow_failure: bool,

crates/forge/src/runner.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl<'a> ContractRunner<'a> {
183183
let needs_setup = setup_fns.len() == 1 && setup_fns[0].name == "setUp";
184184

185185
// There is a single miss-cased `setUp` function, so we add a warning
186-
for setup_fn in setup_fns.iter() {
186+
for &setup_fn in setup_fns.iter() {
187187
if setup_fn.name != "setUp" {
188188
warnings.push(format!(
189189
"Found invalid setup function \"{}\" did you mean \"setUp()\"?",
@@ -387,8 +387,10 @@ impl<'a> ContractRunner<'a> {
387387
// Record test execution time
388388
debug!(
389389
duration = ?start.elapsed(),
390-
%success,
391-
%gas
390+
gas,
391+
reverted,
392+
should_fail,
393+
success,
392394
);
393395

394396
TestResult {

crates/forge/tests/cli/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ forgetest!(can_extract_config_values, |prj, cmd| {
7979
block_difficulty: 10,
8080
block_prevrandao: B256::random(),
8181
block_gas_limit: Some(100u64.into()),
82-
memory_limit: 2u64.pow(25),
82+
memory_limit: 1 << 27,
8383
eth_rpc_url: Some("localhost".to_string()),
8484
eth_rpc_jwt: None,
8585
etherscan_api_key: None,

crates/forge/tests/cli/ext_integration.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ forgetest_external!(
1616
// `run: pnpm --version` is ok, `Command::new("pnpm")` isn't. Good job Windows.
1717
#[cfg_attr(windows, ignore = "Windows cannot find installed programs")]
1818
snekmate,
19-
"pcaversaccio/snekmate",
20-
// 64MiB memory limit:
21-
// - https://github.com/foundry-rs/foundry/pull/6281
22-
// - https://github.com/bluealloy/revm/issues/865
23-
&["--memory-limit", &(1u64 << 26).to_string()]
19+
"pcaversaccio/snekmate"
2420
);
2521

2622
// Forking tests

crates/forge/tests/it/config.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ use foundry_evm::{
1313
decode::decode_console_logs, inspectors::CheatsConfig, revm::primitives::SpecId,
1414
};
1515
use foundry_test_utils::Filter;
16-
use std::{
17-
collections::BTreeMap,
18-
path::{Path, PathBuf},
19-
};
16+
use itertools::Itertools;
17+
use std::{collections::BTreeMap, path::Path};
2018

2119
/// How to execute a a test run
2220
pub struct TestConfig {
@@ -82,11 +80,12 @@ impl TestConfig {
8280
let outcome = if self.should_fail { "fail" } else { "pass" };
8381

8482
eyre::bail!(
85-
"Test {} did not {} as expected.\nReason: {:?}\nLogs:\n{}",
83+
"Test {} did not {} as expected.\nReason: {:?}\nLogs:\n{}\n\nTraces:\n{}",
8684
test_name,
8785
outcome,
8886
result.reason,
89-
logs.join("\n")
87+
logs.join("\n"),
88+
result.traces.iter().map(|(_, a)| a).format("\n"),
9089
)
9190
}
9291
}
@@ -136,14 +135,14 @@ pub(crate) fn init_tracing() {
136135
.try_init();
137136
}
138137

139-
pub fn manifest_root() -> PathBuf {
138+
pub fn manifest_root() -> &'static Path {
140139
let mut root = Path::new(env!("CARGO_MANIFEST_DIR"));
141140
// need to check here where we're executing the test from, if in `forge` we need to also allow
142141
// `testdata`
143142
if root.ends_with("forge") {
144143
root = root.parent().unwrap();
145144
}
146-
root.to_path_buf()
145+
root
147146
}
148147

149148
/// Builds a base runner
@@ -161,7 +160,7 @@ pub async fn runner() -> MultiContractRunner {
161160
/// Builds a non-tracing runner
162161
pub async fn runner_with_config(mut config: Config) -> MultiContractRunner {
163162
config.rpc_endpoints = rpc_endpoints();
164-
config.allow_paths.push(manifest_root());
163+
config.allow_paths.push(manifest_root().to_path_buf());
165164

166165
let root = &PROJECT.paths.root;
167166
let opts = &*EVM_OPTS;

crates/forge/tests/it/test_helpers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ pub static EVM_OPTS: Lazy<EvmOpts> = Lazy::new(|| EvmOpts {
7272
sender: Config::DEFAULT_SENDER,
7373
initial_balance: U256::MAX,
7474
ffi: true,
75-
memory_limit: 1 << 24,
75+
verbosity: 3,
76+
memory_limit: 1 << 26,
7677
..Default::default()
7778
});
7879

testdata/foundry.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[profile.default]
2-
solc = "0.8.19"
2+
solc = "0.8.18"
33
block_base_fee_per_gas = 0
44
block_coinbase = "0x0000000000000000000000000000000000000000"
55
block_difficulty = 0
@@ -36,10 +36,10 @@ remappings = ["ds-test/=lib/ds-test/src/"]
3636
sender = "0x00a329c0648769a73afac7f9381e08fb43dbea72"
3737
sizes = false
3838
sparse_mode = false
39-
src = "src"
40-
test = "test"
39+
src = "./"
40+
test = "./"
4141
tx_origin = "0x00a329c0648769a73afac7f9381e08fb43dbea72"
42-
verbosity = 0
42+
verbosity = 3
4343
via_ir = false
4444
fs_permissions = [{ access = "read-write", path = "./" }]
4545

0 commit comments

Comments
 (0)