Skip to content

fix(pxe): cap fresh secret pending tag indexes to the probed window - #24667

Merged
vezenovm merged 20 commits into
merge-train/fairies-v5from
mv/fix-fresh-secret-probe-window
Jul 24, 2026
Merged

vezenovm merged 20 commits into
merge-train/fairies-v5from
mv/fix-fresh-secret-probe-window

Conversation

@vezenovm

@vezenovm vezenovm commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

We essentially have an off by one error for the starting finalized index for a fresh secret.

  • With nothing finalized on a secret, the store permitted pending indexes 0..WINDOW_LEN, but sender sync only probes [0, WINDOW_LEN) and only advances the window after a finalization.
  • A pending tx at index WINDOW_LEN from another store sharing the secret (second PXE, or restored state) was therefore outside the initial probe, so the next locally picked index could reuse its onchain tag.

Fix: cap fresh secrets at 0..WINDOW_LEN - 1, the same WINDOW_LEN indexes allowed after any finalization. Every absolute window bound (sender permit, sender probe, recipient scan) now comes from one helper, unfinalizedTaggingIndexesWindowEnd, which also aligns the recipient's fresh-secret scan instead of leaving it one index wider than anything a sender can create.

Behavior change: fresh secrets hit the "tagging window length configured too low" error at index WINDOW_LEN, one index earlier, and the recipient no longer scans index WINDOW_LEN for fresh secrets.

Tests: the updated store and recipient sync tests are red on base and green with the fix; the existing straddle test pins the sender probe boundary.

…nalized

The store permits pending indexes up to (lastFinalizedIndex ?? 0) +
UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN inclusive, but with nothing
finalized the first sync window probed [0, WINDOW_LEN), one index short
of that bound. Since the sync loop only advances past its first window
on a finalized-index change, a still-pending tx from another PXE at the
boundary index was never discovered, and the next locally chosen index
would collide with its onchain tag. The first window now uses the same
formula as the window advance, changing behavior only for a fresh
secret (one extra probed index).
@vezenovm vezenovm added ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure ci-draft Run CI on draft PRs. labels Jul 13, 2026
Comment thread yarn-project/pxe/src/tagging/sender_sync/sync_sender_tagging_indexes.test.ts Outdated
@vezenovm vezenovm added the claudebox Owned by claudebox. it can push to this PR. label Jul 13, 2026
@AztecBot

Copy link
Copy Markdown
Collaborator

Automatically closing this stale claudebox draft PR (no updates for 5+ days). Re-open if still needed.

@AztecBot AztecBot closed this Jul 20, 2026
@vezenovm vezenovm reopened this Jul 20, 2026
@vezenovm vezenovm removed the claudebox Owned by claudebox. it can push to this PR. label Jul 20, 2026
vezenovm added 4 commits July 23, 2026 15:00
…ex -1

Rework of the fix: instead of widening the sender-sync first probe window
to the store's fresh-secret permit (which made the fresh window WINDOW_LEN + 1
slots wide), tighten the permit so a fresh secret allows exactly WINDOW_LEN
pending indexes (0..WINDOW_LEN - 1), the same allowance as after any real
finalization. The first probe window [0, WINDOW_LEN) is correct again and
UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN stays the single source of truth for
window width. The recipient scan keeps its ?? 0 bound as a deliberate
one-index margin for txs sent by clients predating the tightened permit.
…' into mv/fix-fresh-secret-probe-window

# Conflicts:
#	yarn-project/pxe/src/tagging/recipient_sync/sync_tagged_private_logs.ts
@vezenovm vezenovm changed the title fix(pxe): probe the full permitted window when no tagging index is finalized fix(pxe): align fresh-secret tagging permit with the probed window Jul 23, 2026
it('throws after pending txs exhaust window', async () => {
// One single-index pending tx per index, mirroring how an un-mined backlog accumulates one log per tx on a
// shared secret (e.g. the self-send chain in bench_build_block). A fresh secret treats the
// finalized floor as 0, so indexes 0..WINDOW fit...

@vezenovm vezenovm Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The crux of the issue. We allowed storing WINDOW + 1 indices rather than WINDOW indices for a fresh secret.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤦

@vezenovm vezenovm changed the title fix(pxe): align fresh-secret tagging permit with the probed window fix(pxe): cap fresh-secret pending tag indexes to the probed window Jul 23, 2026
// Process in memory and validate
for (const { range, secretStr, pendingData, finalizedIndex } of rangeData) {
// Check that the highest index is not further than window length from the highest finalized index.
if (range.highestIndex > (finalizedIndex ?? 0) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Highest index can be UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN which is off by one.

// an index the syncs never scan would let two stores sharing a secret pick colliding indexes.
if (range.highestIndex >= unfinalizedTaggingIndexesWindowEnd(finalizedIndex)) {
throw new Error(
`Highest used index ${range.highestIndex} is further than window length from the highest finalized index ${finalizedIndex ?? 0}.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

From my understanding, if there is no finalized index, the highest finalized index is not 0, 0 is still available to be used as a finalized index.

@vezenovm vezenovm added ci-full Run all master checks. port-to-next Forward-port this merged PR into next and removed ci-draft Run CI on draft PRs. labels Jul 23, 2026
@vezenovm
vezenovm marked this pull request as ready for review July 23, 2026 21:01
@vezenovm vezenovm changed the title fix(pxe): cap fresh-secret pending tag indexes to the probed window fix(pxe): cap fresh secret pending tag indexes to the probed window Jul 23, 2026
Comment thread yarn-project/pxe/src/storage/tagging_store/sender_tagging_store.ts Outdated
Comment on lines +29 to +31
export function unfinalizedTaggingIndexesWindowEnd(finalizedIndex: number | undefined): number {
return (finalizedIndex ?? -1) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we make this return number | undefined instead? Not fond of the sentinel value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I didn't want to return undefined as we then have to repeat this logic at every call site which will defeat the purpose of the helper. I switched to clarifying the window start more clearly and removed the clever usage of -1 for both the no finalized index and finalized index cases. Let me know what you think.

@benesjan

benesjan commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

@vezenovm thanks for LMK with these review requests on PRs fixing my code that I am retarded. Greatly appreciated

@vezenovm
vezenovm requested a review from mverzilli July 24, 2026 16:51
@vezenovm
vezenovm merged commit b667a81 into merge-train/fairies-v5 Jul 24, 2026
12 checks passed
@vezenovm
vezenovm deleted the mv/fix-fresh-secret-probe-window branch July 24, 2026 21:25
@AztecBot

Copy link
Copy Markdown
Collaborator

❌ Failed to cherry-pick to next due to conflicts. (🤖) View backport run.

vezenovm added a commit that referenced this pull request Jul 24, 2026
…port #24667) (#24977)

## Summary
Port of #24667 to
`next` via `port-to-next-staging`.

- Added `unfinalizedTaggingIndexesWindowEnd` and used it for sender
pending bounds plus sender/recipient scan windows.
- Preserved the current `next` window length and recipient sync
structure while adapting fresh-secret bounds to `[0, WINDOW_LEN)`.

## Conflicts resolved
- `constants.ts`: kept `next`'s `UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN
= MAX_PRIVATE_LOGS_PER_TX` and added the shared helper.
- Recipient sync and tests were resolved against the current `next`
implementation, without pulling in source-branch-only constrained probe
changes.
- Sender store tests were adapted to assert exactly `WINDOW_LEN` fresh
pending indexes and rejection at `WINDOW_LEN`.

## Testing
- `JEST_MAX_WORKERS=1 yarn workspace @aztec/pxe test
src/storage/tagging_store/sender_tagging_store.test.ts
src/tagging/recipient_sync/sync_tagged_private_logs.test.ts` passed: 61
tests.
- `yarn build` was attempted but this partial checkout is missing
generated dependency outputs such as `@aztec/l1-artifacts`; the failure
was in setup dependencies, not the PXE changes.

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/0ca34c3ad2537dfa/jobs/1)
· group: `slackbot` · [Slack
thread](https://aztecprotocol.slack.com/archives/C0AGN2WT3CP/p1784928640004259?thread_ts=1784928640.004259&cid=C0AGN2WT3CP)*

---------

Co-authored-by: Maxim Vezenov <mvezenov@gmail.com>
rangozd pushed a commit to rangozd/aztec-packages that referenced this pull request Aug 5, 2026
BEGIN_COMMIT_OVERRIDE
fix(foundation): always include a result key in json-rpc responses
(AztecProtocol#24840)
fix(pxe): cap fresh secret pending tag indexes to the probed window
(port AztecProtocol#24667) (AztecProtocol#24977)
fix(archiver): resolve L2-to-L1 witness from a single store snapshot
(AztecProtocol#24754)
fix(sequencer): stop signalling already-executed governance payloads
(AztecProtocol#24764)
fix(archiver): clean up removed blocks from raw rows and ownership-check
tx-effect deletes (AztecProtocol#24765)
fix(node): warm KZG trusted setup at startup (AztecProtocol#24775)
feat(prover-node): stop caching checkpoint txs; re-fetch from the pool
for failure upload (A-1216) (AztecProtocol#24983)
fix(sequencer): log tx failure reason at warn when dropping from mempool
(AztecProtocol#25000)
feat(prover-client): stop duplicating broker job inputs/results in
memory (A-1215) (AztecProtocol#24990)
fix(prover-client): don't retain inline job inputs in the facade without
a failed-proof store (A-1517) (AztecProtocol#25027)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-full Run all master checks. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure port-to-next Forward-port this merged PR into next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants