Skip to content

Commit 0d07e78

Browse files
authored
feat(fuzz): add bound and gaussian noise mutators (#11342)
* feat(fuzz): add uint/int gaussian noise mutator * reorg * Mutators take2 * Add bound mutator * Comment nit * Review comments: add instrument, nits * Fix panic on [min, max] ranges
1 parent 4cb8b63 commit 0d07e78

File tree

9 files changed

+424
-53
lines changed

9 files changed

+424
-53
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cheatcodes/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ foundry-common.workspace = true
2020
foundry-compilers.workspace = true
2121
foundry-config.workspace = true
2222
foundry-evm-core.workspace = true
23+
foundry-evm-fuzz.workspace = true
2324
foundry-evm-traces.workspace = true
2425
foundry-wallets.workspace = true
2526
forge-script-sequence.workspace = true

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cheatcodes/spec/src/vm.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2844,6 +2844,10 @@ interface Vm {
28442844
#[cheatcode(group = Utilities)]
28452845
function ensNamehash(string calldata name) external pure returns (bytes32);
28462846

2847+
/// Returns an uint256 value bounded in given range and different from the current one.
2848+
#[cheatcode(group = Utilities)]
2849+
function bound(uint256 current, uint256 min, uint256 max) external view returns (uint256);
2850+
28472851
/// Returns a random uint256 value.
28482852
#[cheatcode(group = Utilities)]
28492853
function randomUint() external view returns (uint256);
@@ -2860,6 +2864,10 @@ interface Vm {
28602864
#[cheatcode(group = Utilities)]
28612865
function randomAddress() external view returns (address);
28622866

2867+
/// Returns an int256 value bounded in given range and different from the current one.
2868+
#[cheatcode(group = Utilities)]
2869+
function bound(int256 current, int256 min, int256 max) external view returns (int256);
2870+
28632871
/// Returns a random `int256` value.
28642872
#[cheatcode(group = Utilities)]
28652873
function randomInt() external view returns (int256);

crates/cheatcodes/src/utils.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::*};
44
use alloy_dyn_abi::{DynSolType, DynSolValue, Resolver, TypedData, eip712_parser::EncodeType};
55
use alloy_ens::namehash;
6-
use alloy_primitives::{B64, Bytes, U256, aliases::B32, keccak256, map::HashMap};
6+
use alloy_primitives::{B64, Bytes, I256, U256, aliases::B32, keccak256, map::HashMap};
77
use alloy_sol_types::SolValue;
88
use foundry_common::{TYPE_BINDING_PREFIX, fs};
99
use foundry_config::fs_permissions::FsAccessKind;
1010
use foundry_evm_core::constants::DEFAULT_CREATE2_DEPLOYER;
11+
use foundry_evm_fuzz::strategies::BoundMutator;
1112
use proptest::prelude::Strategy;
1213
use rand::{Rng, RngCore, seq::SliceRandom};
1314
use revm::context::JournalTr;
@@ -74,6 +75,26 @@ impl Cheatcode for ensNamehashCall {
7475
}
7576
}
7677

78+
impl Cheatcode for bound_0Call {
79+
fn apply(&self, state: &mut Cheatcodes) -> Result {
80+
let Self { current, min, max } = *self;
81+
let Some(mutated) = U256::bound(current, min, max, state.test_runner()) else {
82+
bail!("cannot bound {current} in [{min}, {max}] range")
83+
};
84+
Ok(mutated.abi_encode())
85+
}
86+
}
87+
88+
impl Cheatcode for bound_1Call {
89+
fn apply(&self, state: &mut Cheatcodes) -> Result {
90+
let Self { current, min, max } = *self;
91+
let Some(mutated) = I256::bound(current, min, max, state.test_runner()) else {
92+
bail!("cannot bound {current} in [{min}, {max}] range")
93+
};
94+
Ok(mutated.abi_encode())
95+
}
96+
}
97+
7798
impl Cheatcode for randomUint_0Call {
7899
fn apply(&self, state: &mut Cheatcodes) -> Result {
79100
random_uint(state, None, None)

crates/evm/fuzz/src/strategies/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ mod invariants;
1717
pub use invariants::{fuzz_contract_with_calldata, invariant_strat, override_call_strat};
1818

1919
mod mutators;
20+
pub use mutators::BoundMutator;

0 commit comments

Comments
 (0)