Skip to content

Commit

Permalink
Changes after review: introduce FuzzTestTimer
Browse files Browse the repository at this point in the history
  • Loading branch information
grandizzy committed Nov 28, 2024
1 parent 4111e13 commit da87095
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 29 deletions.
23 changes: 6 additions & 17 deletions crates/evm/evm/src/executors/fuzz/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::executors::{Executor, RawCallResult};
use crate::executors::{Executor, FuzzTestTimer, RawCallResult};
use alloy_dyn_abi::JsonAbiExt;
use alloy_json_abi::Function;
use alloy_primitives::{map::HashMap, Address, Bytes, Log, U256};
Expand All @@ -17,11 +17,7 @@ use foundry_evm_fuzz::{
use foundry_evm_traces::SparsedTraceArena;
use indicatif::ProgressBar;
use proptest::test_runner::{TestCaseError, TestError, TestRunner};
use std::{
cell::RefCell,
collections::BTreeMap,
time::{Duration, Instant},
};
use std::{cell::RefCell, collections::BTreeMap};

mod types;
pub use types::{CaseOutcome, CounterExampleOutcome, FuzzOutcome};
Expand Down Expand Up @@ -102,15 +98,13 @@ impl FuzzedExecutor {
let max_traces_to_collect = std::cmp::max(1, self.config.gas_report_samples) as usize;
let show_logs = self.config.show_logs;

// Start a timer if timeout is set.
let start_time = start_timer(self.config.timeout);
// Start timer for this fuzz test.
let timer = FuzzTestTimer::new(self.config.timeout);

let run_result = self.runner.clone().run(&strategy, |calldata| {
// Check if the timeout has been reached.
if let Some((start_time, timeout)) = start_time {
if start_time.elapsed() > timeout {
return Err(TestCaseError::fail(TEST_TIMEOUT));
}
if timer.is_timed_out() {
return Err(TestCaseError::fail(TEST_TIMEOUT));
}

let fuzz_res = self.single_fuzz(address, should_fail, calldata)?;
Expand Down Expand Up @@ -288,8 +282,3 @@ impl FuzzedExecutor {
}
}
}

/// Starts timer for fuzz test, if any timeout configured.
pub(crate) fn start_timer(timeout: Option<u32>) -> Option<(Instant, Duration)> {
timeout.map(|timeout| (Instant::now(), Duration::from_secs(timeout.into())))
}
20 changes: 9 additions & 11 deletions crates/evm/evm/src/executors/invariant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub use result::InvariantFuzzTestResult;
use serde::{Deserialize, Serialize};

mod shrink;
use crate::executors::{fuzz::start_timer, EvmError};
use crate::executors::{EvmError, FuzzTestTimer};
pub use shrink::check_sequence;

sol! {
Expand Down Expand Up @@ -333,8 +333,8 @@ impl<'a> InvariantExecutor<'a> {
let (invariant_test, invariant_strategy) =
self.prepare_test(&invariant_contract, fuzz_fixtures)?;

// Start a timer if timeout is set.
let start_time = start_timer(self.config.timeout);
// Start timer for this invariant test.
let timer = FuzzTestTimer::new(self.config.timeout);

let _ = self.runner.run(&invariant_strategy, |first_input| {
// Create current invariant run data.
Expand All @@ -352,14 +352,12 @@ impl<'a> InvariantExecutor<'a> {

while current_run.depth < self.config.depth {
// Check if the timeout has been reached.
if let Some((start_time, timeout)) = start_time {
if start_time.elapsed() > timeout {
// Since we never record a revert here the test is still considered
// successful even though it timed out. We *want*
// this behavior for now, so that's ok, but
// future developers should be aware of this.
return Err(TestCaseError::fail(TEST_TIMEOUT));
}
if timer.is_timed_out() {
// Since we never record a revert here the test is still considered
// successful even though it timed out. We *want*
// this behavior for now, so that's ok, but
// future developers should be aware of this.
return Err(TestCaseError::fail(TEST_TIMEOUT));
}

let tx = current_run.inputs.last().ok_or_else(|| {
Expand Down
22 changes: 21 additions & 1 deletion crates/evm/evm/src/executors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ use revm::{
ResultAndState, SignedAuthorization, SpecId, TxEnv, TxKind,
},
};
use std::borrow::Cow;
use std::{
borrow::Cow,
time::{Duration, Instant},
};

mod builder;
pub use builder::ExecutorBuilder;
Expand Down Expand Up @@ -952,3 +955,20 @@ fn convert_executed_result(
chisel_state,
})
}

/// Timer for a fuzz test.
pub struct FuzzTestTimer {
/// Inner fuzz test timer - (test start time, test duration).
inner: Option<(Instant, Duration)>,
}

impl FuzzTestTimer {
pub fn new(timeout: Option<u32>) -> Self {
Self { inner: timeout.map(|timeout| (Instant::now(), Duration::from_secs(timeout.into()))) }
}

/// Whether the current fuzz test timed out and should be stopped.
pub fn is_timed_out(&self) -> bool {
self.inner.is_some_and(|(start, duration)| start.elapsed() > duration)
}
}

0 comments on commit da87095

Please sign in to comment.