Skip to content

fix(forge): classify skips by minted cheatcode payload - #16204

Open
mattsse wants to merge 2 commits into
masterfrom
matt/fix-skip-after-caught-revert
Open

fix(forge): classify skips by minted cheatcode payload#16204
mattsse wants to merge 2 commits into
masterfrom
matt/fix-skip-after-caught-revert

Conversation

@mattsse

@mattsse mattsse commented Aug 15, 2026

Copy link
Copy Markdown
Member

Fixes #16197. The executor only classified a top-level revert as a skip when the skip cheatcode was the first recorded reverter, so any revert caught in setUp before vm.skip claimed that slot and the genuine skip was reported as [FAIL: FOUNDRY::SKIP...]. The previous fix (#16200) addressed this with opcode-level payload provenance tracking in the inspector stack and was reverted in #16202.

This replaces the reverter-identity check with payload identity: the skip cheatcode records each payload it mints in the cheatcode state, result conversion copies the payloads onto RawCallResult, and a revert is classified as a skip iff its data byte-equals a recorded payload. The new RawCallResult::skip_reason helper is shared by the executor error path, fuzz, showmap, and symbolic replay, which previously each paired the reverter check with SkipReason::decode by hand. Reverter attribution itself is untouched, so first-reverter semantics for should_ignore_revert and invariant failure attribution do not change, and no per-opcode tracking is involved. User-crafted FOUNDRY::SKIP revert data still fails the test because no matching payload was minted, including forging different bytes after catching a genuine skip. One semantic is pinned deliberately: a caught genuine skip re-raised byte-identically counts as a skip, since distinguishing manual re-raises from compiler-generated revert bubbling requires exactly the byte-flow tracking #16200 was reverted for, and either way the payload provably originated from vm.skip(true) in the same call.

The issue's reproduction is converted into the issue_16197 repro test (caught revert inside an inherited base setUp before the skip), with further tests covering the minimal caught-revert trigger under --isolate, forged payloads with and without a preceding caught genuine skip, and the identical re-raise.

AI assistance was used for the investigation and implementation.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Changelog found

The deterministic check will validate the changed entry.

stevencartavia
stevencartavia previously approved these changes Aug 15, 2026
Base automatically changed from revert-16200-mablr/skip-setup-after-revert to master August 15, 2026 14:20
@mablr
mablr dismissed stevencartavia’s stale review August 15, 2026 14:20

The base branch was changed.

The executor classified a top-level revert as a skip only when the skip
cheatcode was the first recorded reverter. Any caught revert earlier in
setUp claimed that slot, so a genuine vm.skip bubbled to the top was
reported as [FAIL: FOUNDRY::SKIP...].

The skip cheatcode now records the payload it mints in the cheatcode
state, and a revert is classified as a skip iff its data byte-equals a
recorded payload. Reverter attribution is untouched, and user-crafted
FOUNDRY::SKIP revert data still fails because nothing was minted.

Fixes #16197
@mattsse
mattsse force-pushed the matt/fix-skip-after-caught-revert branch from 1229e54 to e369717 Compare August 15, 2026 17:57

@mablr mablr left a comment

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.

SGTM, just an optional suggestion

cheats.broadcastable_transactions.clear();
cheats.ignored_traces.ignored.clear();
// Skip payloads are scoped to the call they were minted in.
cheats.skip_payloads.clear();

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.

Consider pinning this lifetime boundary with an integration test: catch vm.skip(..., "x") in setUp and return successfully, then have the test revert with the exact FOUNDRY::SKIPx bytes. It should fail, proving minted payloads cannot authenticate a later executor call.

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.

bug(forge): vm.skip in setUp reported as FAIL instead of SKIP when setUp does substantial work (regression)

3 participants