Skip to content

Commit 58cae24

Browse files
authored
fix(forge): do not panic if create fork err (#10231)
fix: propagate error on backend spawn fork
1 parent eb336c5 commit 58cae24

File tree

16 files changed

+119
-92
lines changed

16 files changed

+119
-92
lines changed

crates/cast/src/cmd/call.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,14 @@ impl CallArgs {
198198
InternalTraceMode::None
199199
})
200200
.with_state_changes(shell::verbosity() > 4);
201-
let mut executor =
202-
TracingExecutor::new(env, fork, evm_version, trace_mode, odyssey, create2_deployer);
201+
let mut executor = TracingExecutor::new(
202+
env,
203+
fork,
204+
evm_version,
205+
trace_mode,
206+
odyssey,
207+
create2_deployer,
208+
)?;
203209

204210
let value = tx.value.unwrap_or_default();
205211
let input = tx.inner.input.into_input().unwrap_or_default();

crates/cast/src/cmd/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl RunArgs {
186186
trace_mode,
187187
odyssey,
188188
create2_deployer,
189-
);
189+
)?;
190190
let mut env =
191191
EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), executor.spec_id());
192192

crates/chisel/src/executor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl SessionSource {
133133
};
134134

135135
// Create a new runner
136-
let mut runner = self.prepare_runner(final_pc).await;
136+
let mut runner = self.prepare_runner(final_pc).await?;
137137

138138
// Return [ChiselResult] or bubble up error
139139
runner.run(bytecode.into_owned())
@@ -311,7 +311,7 @@ impl SessionSource {
311311
/// ### Returns
312312
///
313313
/// A configured [ChiselRunner]
314-
async fn prepare_runner(&mut self, final_pc: usize) -> ChiselRunner {
314+
async fn prepare_runner(&mut self, final_pc: usize) -> Result<ChiselRunner> {
315315
let env =
316316
self.config.evm_opts.evm_env().await.expect("Could not instantiate fork environment");
317317

@@ -320,7 +320,7 @@ impl SessionSource {
320320
Some(backend) => backend,
321321
None => {
322322
let fork = self.config.evm_opts.get_fork(&self.config.foundry_config, env.clone());
323-
let backend = Backend::spawn(fork);
323+
let backend = Backend::spawn(fork)?;
324324
self.config.backend = Some(backend.clone());
325325
backend
326326
}
@@ -346,7 +346,7 @@ impl SessionSource {
346346

347347
// Create a [ChiselRunner] with a default balance of [U256::MAX] and
348348
// the sender [Address::zero].
349-
ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone())
349+
Ok(ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone()))
350350
}
351351
}
352352

crates/evm/core/src/backend/mod.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ impl Backend {
461461
///
462462
/// If `fork` is `Some` this will use a `fork` database, otherwise with an in-memory
463463
/// database.
464-
pub fn spawn(fork: Option<CreateFork>) -> Self {
464+
pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {
465465
Self::new(MultiFork::spawn(), fork)
466466
}
467467

@@ -471,7 +471,7 @@ impl Backend {
471471
/// database.
472472
///
473473
/// Prefer using [`spawn`](Self::spawn) instead.
474-
pub fn new(forks: MultiFork, fork: Option<CreateFork>) -> Self {
474+
pub fn new(forks: MultiFork, fork: Option<CreateFork>) -> eyre::Result<Self> {
475475
trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend");
476476
// Note: this will take of registering the `fork`
477477
let inner = BackendInner {
@@ -488,8 +488,7 @@ impl Backend {
488488
};
489489

490490
if let Some(fork) = fork {
491-
let (fork_id, fork, _) =
492-
backend.forks.create_fork(fork).expect("Unable to create fork");
491+
let (fork_id, fork, _) = backend.forks.create_fork(fork)?;
493492
let fork_db = ForkDB::new(fork);
494493
let fork_ids = backend.inner.insert_new_fork(
495494
fork_id.clone(),
@@ -502,17 +501,21 @@ impl Backend {
502501

503502
trace!(target: "backend", forking_mode=? backend.active_fork_ids.is_some(), "created executor backend");
504503

505-
backend
504+
Ok(backend)
506505
}
507506

508507
/// Creates a new instance of `Backend` with fork added to the fork database and sets the fork
509508
/// as active
510-
pub(crate) fn new_with_fork(id: &ForkId, fork: Fork, journaled_state: JournaledState) -> Self {
511-
let mut backend = Self::spawn(None);
509+
pub(crate) fn new_with_fork(
510+
id: &ForkId,
511+
fork: Fork,
512+
journaled_state: JournaledState,
513+
) -> eyre::Result<Self> {
514+
let mut backend = Self::spawn(None)?;
512515
let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);
513516
backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));
514517
backend.active_fork_ids = Some(fork_ids);
515-
backend
518+
Ok(backend)
516519
}
517520

518521
/// Creates a new instance with a `BackendDatabase::InMemory` cache layer for the `CacheDB`
@@ -1944,7 +1947,7 @@ fn commit_transaction(
19441947
let fork = fork.clone();
19451948
let journaled_state = journaled_state.clone();
19461949
let depth = journaled_state.depth;
1947-
let mut db = Backend::new_with_fork(fork_id, fork, journaled_state);
1950+
let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;
19481951

19491952
let mut evm = crate::utils::new_evm_with_inspector(&mut db as _, env, inspector);
19501953
// Adjust inner EVM depth to ensure that inspectors receive accurate data.
@@ -2026,7 +2029,7 @@ mod tests {
20262029
evm_opts,
20272030
};
20282031

2029-
let backend = Backend::spawn(Some(fork));
2032+
let backend = Backend::spawn(Some(fork)).unwrap();
20302033

20312034
// some rng contract from etherscan
20322035
let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap();

crates/evm/evm/src/executors/trace.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ impl TracingExecutor {
2020
trace_mode: TraceMode,
2121
odyssey: bool,
2222
create2_deployer: Address,
23-
) -> Self {
24-
let db = Backend::spawn(fork);
25-
Self {
23+
) -> eyre::Result<Self> {
24+
let db = Backend::spawn(fork)?;
25+
Ok(Self {
2626
// configures a bare version of the evm executor: no cheatcode inspector is enabled,
2727
// tracing will be enabled only for the targeted transaction
2828
executor: ExecutorBuilder::new()
@@ -31,7 +31,7 @@ impl TracingExecutor {
3131
})
3232
.spec_id(evm_spec_id(version.unwrap_or_default(), odyssey))
3333
.build(env, db),
34-
}
34+
})
3535
}
3636

3737
/// Returns the spec id of the executor

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ impl TestArgs {
471471

472472
// Run tests in a non-streaming fashion and collect results for serialization.
473473
if !self.gas_report && !self.summary && shell::is_json() {
474-
let mut results = runner.test_collect(filter);
474+
let mut results = runner.test_collect(filter)?;
475475
results.values_mut().for_each(|suite_result| {
476476
for test_result in suite_result.test_results.values_mut() {
477477
if verbosity >= 2 {
@@ -488,7 +488,7 @@ impl TestArgs {
488488
}
489489

490490
if self.junit {
491-
let results = runner.test_collect(filter);
491+
let results = runner.test_collect(filter)?;
492492
sh_println!("{}", junit_xml_report(&results, verbosity).to_string()?)?;
493493
return Ok(TestOutcome::new(results, self.allow_failure));
494494
}

crates/forge/src/multi_runner.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ impl MultiContractRunner {
136136
/// The same as [`test`](Self::test), but returns the results instead of streaming them.
137137
///
138138
/// Note that this method returns only when all tests have been executed.
139-
pub fn test_collect(&mut self, filter: &dyn TestFilter) -> BTreeMap<String, SuiteResult> {
140-
self.test_iter(filter).collect()
139+
pub fn test_collect(
140+
&mut self,
141+
filter: &dyn TestFilter,
142+
) -> Result<BTreeMap<String, SuiteResult>> {
143+
Ok(self.test_iter(filter)?.collect())
141144
}
142145

143146
/// Executes _all_ tests that match the given `filter`.
@@ -148,10 +151,10 @@ impl MultiContractRunner {
148151
pub fn test_iter(
149152
&mut self,
150153
filter: &dyn TestFilter,
151-
) -> impl Iterator<Item = (String, SuiteResult)> {
154+
) -> Result<impl Iterator<Item = (String, SuiteResult)>> {
152155
let (tx, rx) = mpsc::channel();
153-
self.test(filter, tx, false);
154-
rx.into_iter()
156+
self.test(filter, tx, false)?;
157+
Ok(rx.into_iter())
155158
}
156159

157160
/// Executes _all_ tests that match the given `filter`.
@@ -165,12 +168,12 @@ impl MultiContractRunner {
165168
filter: &dyn TestFilter,
166169
tx: mpsc::Sender<(String, SuiteResult)>,
167170
show_progress: bool,
168-
) {
171+
) -> Result<()> {
169172
let tokio_handle = tokio::runtime::Handle::current();
170173
trace!("running all tests");
171174

172175
// The DB backend that serves all the data.
173-
let db = Backend::spawn(self.fork.take());
176+
let db = Backend::spawn(self.fork.take())?;
174177

175178
let find_timer = Instant::now();
176179
let contracts = self.matching_contracts(filter).collect::<Vec<_>>();
@@ -221,6 +224,8 @@ impl MultiContractRunner {
221224
let _ = tx.send((id.identifier(), result));
222225
})
223226
}
227+
228+
Ok(())
224229
}
225230

226231
fn run_test_suite(

crates/forge/tests/it/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl TestConfig {
4646
}
4747

4848
/// Executes the test runner
49-
pub fn test(&mut self) -> BTreeMap<String, SuiteResult> {
49+
pub fn test(&mut self) -> eyre::Result<BTreeMap<String, SuiteResult>> {
5050
self.runner.test_collect(&self.filter)
5151
}
5252

@@ -60,7 +60,7 @@ impl TestConfig {
6060
/// * filter matched 0 test cases
6161
/// * a test results deviates from the configured `should_fail` setting
6262
pub async fn try_run(&mut self) -> eyre::Result<()> {
63-
let suite_result = self.test();
63+
let suite_result = self.test()?;
6464
if suite_result.is_empty() {
6565
eyre::bail!("empty test result");
6666
}

crates/forge/tests/it/core.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::{collections::BTreeMap, env};
1313
async fn test_core() {
1414
let filter = Filter::new(".*", ".*", ".*core");
1515
let mut runner = TEST_DATA_DEFAULT.runner();
16-
let results = runner.test_collect(&filter);
16+
let results = runner.test_collect(&filter).unwrap();
1717

1818
assert_multiple(
1919
&results,
@@ -77,7 +77,7 @@ async fn test_core() {
7777
async fn test_linking() {
7878
let filter = Filter::new(".*", ".*", ".*linking");
7979
let mut runner = TEST_DATA_DEFAULT.runner();
80-
let results = runner.test_collect(&filter);
80+
let results = runner.test_collect(&filter).unwrap();
8181

8282
assert_multiple(
8383
&results,
@@ -111,7 +111,7 @@ async fn test_linking() {
111111
async fn test_logs() {
112112
let filter = Filter::new(".*", ".*", ".*logs");
113113
let mut runner = TEST_DATA_DEFAULT.runner();
114-
let results = runner.test_collect(&filter);
114+
let results = runner.test_collect(&filter).unwrap();
115115

116116
assert_multiple(
117117
&results,
@@ -722,7 +722,7 @@ async fn test_env_vars() {
722722
async fn test_doesnt_run_abstract_contract() {
723723
let filter = Filter::new(".*", ".*", ".*Abstract.t.sol".to_string().as_str());
724724
let mut runner = TEST_DATA_DEFAULT.runner();
725-
let results = runner.test_collect(&filter);
725+
let results = runner.test_collect(&filter).unwrap();
726726
assert!(!results.contains_key("default/core/Abstract.t.sol:AbstractTestBase"));
727727
assert!(results.contains_key("default/core/Abstract.t.sol:AbstractTest"));
728728
}
@@ -731,7 +731,7 @@ async fn test_doesnt_run_abstract_contract() {
731731
async fn test_trace() {
732732
let filter = Filter::new(".*", ".*", ".*trace");
733733
let mut runner = TEST_DATA_DEFAULT.tracing_runner();
734-
let suite_result = runner.test_collect(&filter);
734+
let suite_result = runner.test_collect(&filter).unwrap();
735735

736736
// TODO: This trace test is very basic - it is probably a good candidate for snapshot
737737
// testing.
@@ -764,7 +764,7 @@ async fn test_assertions_revert_false() {
764764
let mut runner = TEST_DATA_DEFAULT.runner_with(|config| {
765765
config.assertions_revert = false;
766766
});
767-
let results = runner.test_collect(&filter);
767+
let results = runner.test_collect(&filter).unwrap();
768768

769769
assert_multiple(
770770
&results,
@@ -790,7 +790,7 @@ async fn test_legacy_assertions() {
790790
let mut runner = TEST_DATA_DEFAULT.runner_with(|config| {
791791
config.legacy_assertions = true;
792792
});
793-
let results = runner.test_collect(&filter);
793+
let results = runner.test_collect(&filter).unwrap();
794794

795795
assert_multiple(
796796
&results,
@@ -809,7 +809,7 @@ async fn test_legacy_assertions() {
809809
#[tokio::test(flavor = "multi_thread")]
810810
async fn test_before_setup_with_selfdestruct() {
811811
let filter = Filter::new(".*", ".*BeforeTestSelfDestructTest", ".*");
812-
let results = TEST_DATA_PARIS.runner().test_collect(&filter);
812+
let results = TEST_DATA_PARIS.runner().test_collect(&filter).unwrap();
813813

814814
assert_multiple(
815815
&results,

crates/forge/tests/it/fork.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ async fn test_cheats_fork_revert() {
1919
&format!(".*cheats{RE_PATH_SEPARATOR}Fork"),
2020
);
2121
let mut runner = TEST_DATA_DEFAULT.runner();
22-
let suite_result = runner.test_collect(&filter);
22+
let suite_result = runner.test_collect(&filter).unwrap();
2323
assert_eq!(suite_result.len(), 1);
2424

2525
for (_, SuiteResult { test_results, .. }) in suite_result {

0 commit comments

Comments
 (0)