Skip to content

Commit c33ae3f

Browse files
committed
feat(cheatcodes): additional random cheatcodes to aid in symbolic testing
1 parent 41d4e54 commit c33ae3f

File tree

10 files changed

+468
-51
lines changed

10 files changed

+468
-51
lines changed

crates/cheatcodes/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,4 @@ thiserror.workspace = true
6565
toml = { workspace = true, features = ["preserve_order"] }
6666
tracing.workspace = true
6767
walkdir.workspace = true
68-
69-
[dev-dependencies]
7068
proptest.workspace = true

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 166 additions & 6 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: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,15 +2297,18 @@ interface Vm {
22972297
function ensNamehash(string calldata name) external pure returns (bytes32);
22982298

22992299
/// Returns a random uint256 value.
2300-
#[cheatcode(group = Utilities)]
2300+
/// `randomUint` is being deprecated in favor of `arbitraryUint`. It will be removed in future versions.
2301+
#[cheatcode(group = Utilities, status = Deprecated)]
23012302
function randomUint() external returns (uint256);
23022303

23032304
/// Returns random uin256 value between the provided range (=min..=max).
2304-
#[cheatcode(group = Utilities)]
2305+
/// `randomUint` is being deprecated in favor of `arbitraryUint`. It will be removed in future versions.
2306+
#[cheatcode(group = Utilities, status = Deprecated)]
23052307
function randomUint(uint256 min, uint256 max) external returns (uint256);
23062308

23072309
/// Returns a random `address`.
2308-
#[cheatcode(group = Utilities)]
2310+
/// `randomAddress` is being deprecated in favor of `arbitraryAddress`. It will be removed in future versions
2311+
#[cheatcode(group = Utilities, status = Deprecated)]
23092312
function randomAddress() external returns (address);
23102313

23112314
/// Pauses collection of call traces. Useful in cases when you want to skip tracing of
@@ -2324,6 +2327,39 @@ interface Vm {
23242327
/// Utility cheatcode to set arbitrary storage for given target address.
23252328
#[cheatcode(group = Utilities)]
23262329
function setArbitraryStorage(address target) external;
2330+
2331+
/// Returns an arbitrary `uint256` value.
2332+
#[cheatcode(group = Utilities)]
2333+
function arbitraryUint() external view returns (uint256);
2334+
2335+
/// Returns an arbitrary `uint256` value between the provided range (=min..=max).
2336+
/// `randomUint` is being deprecated in favor of `arbitraryUint`. It will be removed in future versions.
2337+
#[cheatcode(group = Utilities)]
2338+
function arbitraryUint(uint256 min, uint256 max) external view returns (uint256);
2339+
2340+
/// Returns an arbitrary `uint256` value of given bits.
2341+
#[cheatcode(group = Utilities)]
2342+
function arbitraryUint(uint256 bits) external view returns (uint256);
2343+
2344+
/// Returns an arbitrary `int256` value.
2345+
#[cheatcode(group = Utilities)]
2346+
function arbitraryInt() external view returns (int256);
2347+
2348+
/// Returns an arbitrary `int256` value of given bits.
2349+
#[cheatcode(group = Utilities)]
2350+
function arbitraryInt(uint256 bits) external view returns (int256);
2351+
2352+
/// Returns an arbitrary `address`.
2353+
#[cheatcode(group = Utilities)]
2354+
function arbitraryAddress() external view returns (address);
2355+
2356+
/// Returns an arbitrary `bool`.
2357+
#[cheatcode(group = Utilities)]
2358+
function arbitraryBool() external view returns (bool);
2359+
2360+
/// Returns an arbitrary byte array value of the given length.
2361+
#[cheatcode(group = Utilities)]
2362+
function arbitraryBytes(uint256 len) external view returns (bytes memory);
23272363
}
23282364
}
23292365

crates/cheatcodes/src/evm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl Cheatcode for loadCall {
9696
if ccx.state.has_arbitrary_storage(&target) {
9797
// If storage slot is untouched and load from a target with arbitrary storage,
9898
// then set random value for current slot.
99-
let rand_value = ccx.state.rng().gen();
99+
let rand_value = ccx.state.test_runner().rng().gen();
100100
ccx.state.arbitrary_storage.as_mut().unwrap().save(
101101
ccx.ecx,
102102
target,
@@ -108,7 +108,7 @@ impl Cheatcode for loadCall {
108108
// If storage slot is untouched and load from a target that copies storage from
109109
// a source address with arbitrary storage, then copy existing arbitrary value.
110110
// If no arbitrary value generated yet, then the random one is saved and set.
111-
let rand_value = ccx.state.rng().gen();
111+
let rand_value = ccx.state.test_runner().rng().gen();
112112
val.data = ccx.state.arbitrary_storage.as_mut().unwrap().copy(
113113
ccx.ecx,
114114
target,

crates/cheatcodes/src/inspector.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ use foundry_evm_core::{
3434
};
3535
use foundry_evm_traces::TracingInspector;
3636
use itertools::Itertools;
37-
use rand::{rngs::StdRng, Rng, SeedableRng};
37+
use proptest::test_runner::{RngAlgorithm, TestRng, TestRunner};
38+
use rand::Rng;
3839
use revm::{
3940
interpreter::{
4041
opcode as op, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome,
@@ -439,8 +440,8 @@ pub struct Cheatcodes {
439440
/// `char -> (address, pc)`
440441
pub breakpoints: Breakpoints,
441442

442-
/// Optional RNG algorithm.
443-
rng: Option<StdRng>,
443+
/// Optional cheatcodes `TestRunner`.
444+
test_runner: Option<TestRunner>,
444445

445446
/// Ignored traces.
446447
pub ignored_traces: IgnoredTraces,
@@ -488,7 +489,7 @@ impl Cheatcodes {
488489
mapping_slots: Default::default(),
489490
pc: Default::default(),
490491
breakpoints: Default::default(),
491-
rng: Default::default(),
492+
test_runner: Default::default(),
492493
ignored_traces: Default::default(),
493494
arbitrary_storage: Default::default(),
494495
}
@@ -1064,10 +1065,13 @@ impl Cheatcodes {
10641065
None
10651066
}
10661067

1067-
pub fn rng(&mut self) -> &mut impl Rng {
1068-
self.rng.get_or_insert_with(|| match self.config.seed {
1069-
Some(seed) => StdRng::from_seed(seed.to_be_bytes::<32>()),
1070-
None => StdRng::from_entropy(),
1068+
pub fn test_runner(&mut self) -> &mut TestRunner {
1069+
self.test_runner.get_or_insert_with(|| match self.config.seed {
1070+
Some(seed) => TestRunner::new_with_rng(
1071+
proptest::test_runner::Config::default(),
1072+
TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>()),
1073+
),
1074+
None => TestRunner::new(proptest::test_runner::Config::default()),
10711075
})
10721076
}
10731077

@@ -1598,15 +1602,15 @@ impl Cheatcodes {
15981602

15991603
if value.is_cold && value.data.is_zero() {
16001604
if self.has_arbitrary_storage(&target_address) {
1601-
let arbitrary_value = self.rng().gen();
1605+
let arbitrary_value = self.test_runner().rng().gen();
16021606
self.arbitrary_storage.as_mut().unwrap().save(
16031607
&mut ecx.inner,
16041608
target_address,
16051609
key,
16061610
arbitrary_value,
16071611
);
16081612
} else if self.is_arbitrary_storage_copy(&target_address) {
1609-
let arbitrary_value = self.rng().gen();
1613+
let arbitrary_value = self.test_runner().rng().gen();
16101614
self.arbitrary_storage.as_mut().unwrap().copy(
16111615
&mut ecx.inner,
16121616
target_address,

0 commit comments

Comments
 (0)