Skip to content

feat(fuzz): keep observed calls out of corpus#15817

Open
decofe wants to merge 4 commits into
centaur/immediate-corpus-persistence-1784381329from
centaur/observed-call-dictionary-1784381979
Open

feat(fuzz): keep observed calls out of corpus#15817
decofe wants to merge 4 commits into
centaur/immediate-corpus-persistence-1784381329from
centaur/observed-call-dictionary-1784381979

Conversation

@decofe

@decofe decofe commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Stacked on #15816.

Keep coverage-winning observed calls in a separate, deduplicated generation dictionary, analogous to Echidna GenDict.wholeCalls. Sibling zero-input tests contribute direct observed calls only when their execution adds coverage; they are never persisted or counted as corpus entries. A later fuzz execution must gain coverage before normal corpus promotion.

Validation: cargo +nightly fmt and git diff --check pass. Focused foundry-evm tests are blocked before compilation because Cargo cannot fetch the pinned foundry-rs/optimism Git dependency (HTTP 401).

Prompted by: @0xalpharush

@0xalpharush

Copy link
Copy Markdown
Collaborator

TBD if this is desired 46180e7

I think also mutating immediately upon selecting an observed call remains

mablr added 2 commits July 22, 2026 15:42
Initialize the isolated coverage snapshots in the test-trace seeding path where they are consumed. Remove a stale test variable so the branch remains warning-free.
self.push_observed_sequence(tx_seq)
let mut added = 0;
for call in calls {
if !self.observed_call_pool.iter().any(|existing| {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pool is unbounded and each insertion scans/com­pares every retained call, making distinct observed calls O(N^2) time plus unbounded calldata memory. We could use a dedupe set with a bounded reservoir/LRU.

pub fn new_tx(&self, test_runner: &mut TestRunner) -> Result<BasicTxDetails> {
// Keep synthesizing fresh calls, but regularly use coverage-winning observed shapes as
// generation seeds. They are deliberately separate from corpus selection and persistence.
if !self.observed_call_pool.is_empty() && test_runner.rng().random_ratio(1, 2) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calls to run-local created contracts remain in this pool after those targets are cleared, so this fixed 50% path can increasingly select dead addresses. We could prune/tag dynamic-target entries at run end (and consider making this rate weighted rather than fixed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants