Skip to content

chore: fix unnecessary and inconsistent side-effect counter increments#22245

Merged
benesjan merged 5 commits intomerge-train/fairiesfrom
nico/f-537-remove-extra-side-effect-counter-increments
Apr 16, 2026
Merged

chore: fix unnecessary and inconsistent side-effect counter increments#22245
benesjan merged 5 commits intomerge-train/fairiesfrom
nico/f-537-remove-extra-side-effect-counter-increments

Conversation

@nventuro
Copy link
Copy Markdown
Contributor

@nventuro nventuro commented Apr 1, 2026

The extra increment had no real consequences, but it made the core mode confusing. I adjusted the log to more clearly show what's been done.

I also removed a TODO that was both stale and incorrect.

@benesjan benesjan enabled auto-merge (squash) April 7, 2026 09:28
@benesjan benesjan force-pushed the nico/f-537-remove-extra-side-effect-counter-increments branch from b6a1d72 to fc00936 Compare April 8, 2026 02:00
Copy link
Copy Markdown
Contributor

benesjan commented Apr 8, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@benesjan benesjan force-pushed the nico/f-537-remove-extra-side-effect-counter-increments branch from fc00936 to 6868ac2 Compare April 8, 2026 02:00
@benesjan
Copy link
Copy Markdown
Contributor

benesjan commented Apr 8, 2026

@nventuro I had to do this fix because it broke this test.

Posting screenshot in case the CI run log disappeared:

image

The issue there was that next_counter function increments the counter but it returns the non-incremented one which then results in the breaking of non-revertible counter being always smaller than revertible one invariant.

Not merging this as I think you should see the fix first.

@benesjan
Copy link
Copy Markdown
Contributor

benesjan commented Apr 8, 2026

My "fix" broke it all and here is AI explanation why:

Why end_setup must bump the side-effect counter twice

The kernel enforces strict inequalities when validating the phase split of a private call. For a given call with min_revertible_side_effect_counter = M:

  • Every non-revertible side effect counter (and any expected_non_revertible_side_effect_counter set via in_revertible_phase() queries) must be strictly less than M.
  • Every revertible side effect counter (including the start_side_effect_counter of nested private call requests) must be strictly greater than M.
  • M itself is added to the sorted side-effect array and must satisfy prev < M < next — i.e. M has to sit in a gap that no actual side effect occupies.

This means end_setup needs to do two things at once:

  1. Ensure M is greater than the current counter (which may already equal the counter read by an earlier in_revertible_phase() call, since that function does not bump the counter).
  2. Ensure the next side effect after end_setup gets a counter strictly greater than M.

A single increment can only satisfy one of these, not both:

Variant min_rev next side effect issue
min_rev = next_counter() (counter: X → X+1) X X+1 expected_non_rev (X) < min_rev (X) fails — PXE unit test end_setup_checking_phases breaks
counter += 1; min_rev = counter (counter: X → X+1) X+1 X+1 min_rev collides with next side effect counter — e2e validate_increasing_counters fails
counter += 1; min_rev = counter; counter += 1 (X → X+2) X+1 X+2 ✅ both invariants hold

The original pre-PR code (self.side_effect_counter += 1; self.min_revertible_side_effect_counter = self.next_counter();) was doing exactly the two-bump dance — the second increment wasn't an "extra" that could be cleaned up, it was load-bearing.

Fix

Restore the two-bump behavior in end_setup, written explicitly so the intent is obvious:

pub fn end_setup(&mut self) {
    // We bump the counter twice: once so that `min_revertible_side_effect_counter` sits strictly above any
    // non-revertible side effect counter (including queries made via `in_revertible_phase` before this call), and
    // once more so that the next revertible side effect counter is strictly greater than
    // `min_revertible_side_effect_counter`. This ensures `min_revertible_side_effect_counter` occupies a gap that
    // no side effect takes, which the kernel relies on when validating the phase split.
    self.side_effect_counter += 1;
    self.min_revertible_side_effect_counter = self.side_effect_counter;
    self.side_effect_counter += 1;
    ...
}

@AztecBot
Copy link
Copy Markdown
Collaborator

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/27a86fa65269ec5a�27a86fa65269ec5a8;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_offchain_payment.test.ts (56s) (code: 0)

@benesjan benesjan merged commit ccf4006 into merge-train/fairies Apr 16, 2026
13 checks passed
@benesjan benesjan deleted the nico/f-537-remove-extra-side-effect-counter-increments branch April 16, 2026 19:11
@AztecBot
Copy link
Copy Markdown
Collaborator

✅ Successfully backported to backport-to-v4-next-staging #22580.

github-merge-queue bot pushed a commit that referenced this pull request Apr 17, 2026
BEGIN_COMMIT_OVERRIDE
feat: check noir release has nargo binaries before releasing (#22551)
chore: cache chainInfo in embeddedwallet (#22592)
fix: wrap external getCapsule in transactionAsync (#22595)
fix(pxe): throw clear error for invalid comparator in pick_notes
(#22585)
refactor(aztec-nr): rename conversion fns to encode_/decode_ naming
(#22576)
fix: adding transactions to PXE stores (#22603)
feat: infrastructure for testing `[new_contract_artfiacts,
old_aztec_stack]` (#22593)
chore: fix unnecessary and inconsistent side-effect counter increments
(#22245)
feat(aztec-nr): new BoundedVec emit private log APIs (#22064)
END_COMMIT_OVERRIDE
Thunkar added a commit that referenced this pull request Apr 17, 2026
BEGIN_COMMIT_OVERRIDE
fix(pxe): cap event filter toBlock to last synced block (#22573)
fix(pxe): round tx expiration timestamp to reduce precision (#22577)
fix: eliminate anvil watcher warp race and false success logs (#22584)
refactor: aztec new and init creating 2 crates (#20681)
test: aztec new scaffold works (#20711)
feat(cli): warning if contract crate has tests (#20723)
feat(cli): auto-recompiling when aztec test is run (#20729)
feat: aztec new supporting multiple contract crates (#21007)
feat: asserts that aztec dep version matches cli (#21245)
chore: backport aztec CLI improvements to v4-next (#22587)
feat: check noir release has nargo binaries before releasing (#22551)
chore: cache chainInfo in embeddedwallet (#22592)
fix: wrap external getCapsule in transactionAsync (#22595)
fix(pxe): throw clear error for invalid comparator in pick_notes
(#22585)
refactor(aztec-nr): rename conversion fns to encode_/decode_ naming
(#22576)
feat: infrastructure for testing `[new_contract_artfiacts,
old_aztec_stack]` (#22593)
chore: fix unnecessary and inconsistent side-effect counter increments
(#22245)
fix: update FaceID wallet redirects and strip anchors in redirect
validation (#22505)
docs: add getting started on testnet guide (#22366)
docs: add getting started on testnet guide (backport #22366) (#22619)
feat(aztec-nr): new BoundedVec emit private log APIs (#22064)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants