fix(pxe): UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN should be MAX_PRIVATE_LOGS_PER_TX + headroom, not exactly MAX_PRIVATE_LOGS_PER_TX#24437
Open
vezenovm wants to merge 10 commits into
Conversation
Draft-only experiment: #24429 widened this to MAX_PRIVATE_LOGS_PER_TX alongside adding an address-derived tagging-secret hook to the client-flows bench. Reverting just the constant, on top of that hook, isolates whether the widen was needed to pass CI or whether the hook alone was sufficient.
…stant The reverted comment (copied verbatim from before #24429) still said the value must be larger than MAX_PRIVATE_LOGS_PER_TX while setting it to 20, and cited e2e_l1_with_wall_time, which no longer exists (deleted in #24310). Replace with an accurate description of the real bound and mark the value explicitly as an unsafe test-only setting.
…OGS_PER_TX + 20 MAX_PRIVATE_LOGS_PER_TX is a hard floor (a single tx can tag that many logs with one secret), but it alone leaves no headroom for multiple ordinary, not-yet-mined txs to the same counterparty to stack up before the first is observed as mined -- the scenario that tripped bench_build_block in #24429. The +20 margin reuses the team's prior heuristic for that headroom instead of letting it silently replace the floor, as the pre-#24429 value did. Also drops the old comment's squashing justification for exceeding MAX_PRIVATE_LOGS_PER_TX: reconcileTaggingIndexRangesAgainstSurvivingTags trims the range to surviving indexes post-squash, it doesn't inflate it, and MAX_NOTE_HASHES_PER_TX matches MAX_PRIVATE_LOGS_PER_TX today, so squashing can't push a single tx's consumption past the floor.
vezenovm
commented
Jul 1, 2026
vezenovm
commented
Jul 1, 2026
…ion test Codex review of #24437 flagged that citing MAX_NOTE_HASHES_PER_TX as "confirmation" of the MAX_PRIVATE_LOGS_PER_TX floor was weak evidence (the match looked coincidental). It's not: MAX_PRIVATE_LOGS_PER_TX is defined as MAX_NOTE_HASHES_PER_TX in noir-protocol-circuits' constants.nr, and more to the point, PrivateAccumulatedData.private_logs is the tx-wide, pre-squash accumulator sized to exactly MAX_PRIVATE_LOGS_PER_TX -- every private log from every call in a tx lands there before reset/squashing ever runs, so no tx can tag more than that many logs with one secret, squashed or not. Also add a regression test locking in the actual scenario the +20 margin exists for: a second, ordinary pending tx to the same secret must still be storable after a first tx already used a full MAX_PRIVATE_LOGS_PER_TX-sized burst from a fresh secret, before either is finalized.
…ret ceiling A squash-heavy tx can drive one secret's raw tag index arbitrarily past MAX_PRIVATE_LOGS_PER_TX, since indexes are reserved at log-emission time, before squashing is decided, and the kernel's reset loop isn't bounded by that constant. No fixed window closes this; tracked separately in #24466.
Collaborator
Flakey Tests🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #24429. That PR widened
UNFINALIZED_TAGGING_INDEXES_WINDOW_LENfrom20to exactlyMAX_PRIVATE_LOGS_PER_TX(64). This PR argues that's still not the right value for the scenario #24429 was trying to fix, and proposesMAX_PRIVATE_LOGS_PER_TX + 20.Scope note (see "Known limitation" below): this fixes a real, CI-confirmed problem; multiple ordinary pending txs to the same counterparty stacking up before the first is mined. There is a separate, harder problem captured in F-783. Additional separate breakage follow-up on the sender-side when pending logs exceed the window F-784.
Investigation
MAX_PRIVATE_LOGS_PER_TXis a genuine, protocol-enforced bound for ordinary transaction patterns:noir-protocol-circuitsconstants.nrdefinesMAX_PRIVATE_LOGS_PER_TXdirectly asMAX_NOTE_HASHES_PER_TX. A fresh secret's very first ordinary tx can legitimately consume that many indexes before anything is finalized.But exactly
MAX_PRIVATE_LOGS_PER_TXleaves zero headroom for a second unconfirmed tx to the same counterparty once the first one is already near the max.finalizedonly advances once the sender's own node observes a tx as mined (seesyncSenderTaggingIndexes), so any burst of sends to one counterparty before the first is mined can exhaust the window. This is exactly what happened in #24429'sbench_build_blockfailure:#24387's handshake default added extra per-cold-chain overhead, and the bench builds up a backlog of unmined txs by design, sousedran pastfinalized(which stayed at0) before window20could absorb it.Confirmed live: reproduced on this branch at bare
20To settle whether #24429's bump was actually necessary, we reset this branch's constant back to bare
20and letbench_build_blockrun to completion in CI rather than relying on the reasoning above alone. It failed the same way (see http://ci.aztec-labs.com/4ed074af4b8ab633 from a4feea1, on the currentmerge-train/fairies-v5tip:So this isn't a synthetic worst case: it's a real failure on real CI infrastructure, at index
21, i.e. just one past the window. Not even a large burst of txs.Red/green evidence
Added
sender_tagging_store.test.ts: "allows an ordinary pending tx to stack on a fresh secret already at theMAX_PRIVATE_LOGS_PER_TXfloor" — one tx uses the full worst-case 64-log burst from a fresh secret, then a second, ordinary-sized pending tx to the same secret must still be storable before either is mined.20: the first call in that test already throws, with zero other txs involved:MAX_PRIVATE_LOGS_PER_TX + 20: same scenario passes.This is the key point for review: the
bench_build_blockfailure isn't just "risky under bursty load".20is mathematically incapable of tolerating even one legitimate worst-case single ordinary tx, independent of what CI on this branch shows either way. CI passing at20only means our current test/bench suite doesn't happen to construct a single tx tagging more than 20 logs to one recipient; it was never testing the general safety of the constant, just this specific workload's exposure to it. The live CI failure above is the same underlying gap, just surfaced through a different, real workload instead of a targeted unit test.We also added tests to pin the window's stacking semantics: a run of window+1 one-log pending txs to one secret fits, while the next tx throws.
Why
+ 20, not* 2or another additive constantMAX_PRIVATE_LOGS_PER_TX) covers one worst-case ordinary tx. The failure mode above is about additional, ordinary-sized pending txs to the same counterparty stacking up, not another maxed-out 64-log tx.