Skip to content

fix(ethereum): prevent unhandled L1 rejections from tx monitor loops during shutdown (v5 line, partial)#24551

Merged
spalladino merged 1 commit into
merge-train/spartan-v5from
cb/fix-flake-sentinel-status-slash-timestamp
Jul 6, 2026
Merged

fix(ethereum): prevent unhandled L1 rejections from tx monitor loops during shutdown (v5 line, partial)#24551
spalladino merged 1 commit into
merge-train/spartan-v5from
cb/fix-flake-sentinel-status-slash-timestamp

Conversation

@AztecBot

@AztecBot AztecBot commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Flake

multi-node/slashing/sentinel_status_slash.parallel.test.ts ("slashes an attestor that gets stopped after the network is running") flaked on PR #24507 (unrelated change). CI log: http://ci.aztec-labs.com/9bb09d2f904e290a

What actually failed

The test itself passed. Immediately after, the node process crashed with an unhandled rejection (ECONNREFUSED on anvil after teardown) — something was still polling L1 after shutdown. Root cause: L1TxUtils.monitorTransaction's loop calls getL1Timestamp() at the top of its loop, outside the loop's own try/catch, and nothing waited for in-flight monitor iterations to actually stop during shutdown.

Scope of this PR (rebased onto merge-train/spartan-v5)

This PR was originally written against next and touched 4 files. After rebasing onto merge-train/spartan-v5, 2 of those files cherry-picked cleanly and are included here:

  • yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.ts — guards the loop-top getL1Timestamp() call to break quietly when interrupted.
  • yarn-project/sequencer-client/src/publisher/sequencer-publisher.ts — adds .catch to a bare fire-and-forget backupDroppedInSim(...) call.

The other 2 files (publisher_manager.ts, checkpoint_proposal_job.ts) have diverged in structure on this branch and needed their own investigation rather than a blind cherry-pick — that's covered separately in #24560, which found publisher_manager.ts had the same defect (fixed there) and checkpoint_proposal_job.ts did not (this branch already routes fire-and-forget L1 requests through a RequestsTracker that attaches its own rejection handler).

No tracked issue exists for this flake; reference only.


Created by claudebox · group: slackbot

@AztecBot AztecBot added ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR. labels Jul 6, 2026
@AztecBot AztecBot changed the base branch from next to merge-train/spartan-v5 July 6, 2026 17:39
@AztecBot AztecBot changed the title fix: prevent unhandled L1 rejections from tx monitor loops during shutdown fix(ethereum): prevent unhandled L1 rejections from tx monitor loops during shutdown (v5 line, partial) Jul 6, 2026
…during shutdown

Guards L1TxUtils.monitorTransaction's loop-top getL1Timestamp() call to
break quietly when interrupted, and adds a .catch to sequencer-publisher's
fire-and-forget backupDroppedInSim call.

Scoped to the 2 files that apply cleanly to merge-train/spartan-v5;
publisher_manager.ts and checkpoint_proposal_job.ts are covered separately
in #24560 since this branch's code has diverged there.
@AztecBot AztecBot force-pushed the cb/fix-flake-sentinel-status-slash-timestamp branch from 06aadfc to 219364d Compare July 6, 2026 21:14
@spalladino spalladino marked this pull request as ready for review July 6, 2026 21:19
@spalladino spalladino enabled auto-merge (squash) July 6, 2026 21:19
@spalladino spalladino merged commit d4d77e3 into merge-train/spartan-v5 Jul 6, 2026
17 of 20 checks passed
@spalladino spalladino deleted the cb/fix-flake-sentinel-status-slash-timestamp branch July 6, 2026 21:45
spalladino pushed a commit that referenced this pull request Jul 6, 2026
…ts during shutdown (v5 line) (#24560)

Ports the remaining part of the `sentinel_status_slash` flake fix to the
v5 line. The flake crashed the jest process after all tests passed: an
in-flight `eth_getBlockByNumber` against the torn-down anvil surfaced as
an unhandled `L1RpcError` (`ECONNREFUSED`). CI log:
http://ci.aztec-labs.com/9bb09d2f904e290a

This complements #24551, which (after retargeting to
`merge-train/spartan-v5`) now carries only the two files that
cherry-picked cleanly from `next` — `l1_tx_utils.ts` (guard the loop-top
`getL1Timestamp()` in `monitorTransaction`) and `sequencer-publisher.ts`
(`.catch` on the fire-and-forget `backupDroppedInSim`). The other two
files had diverged on this branch and are addressed here; #24551's
title/body should be updated to reflect that it covers 2 of the original
4 files, with this PR covering the rest.

### `yarn-project/ethereum/src/publisher_manager.ts` — fixed

This branch's `stop()` (which, unlike `next`, also clears the `started`
flag and supports restart via `start()`) interrupted all publishers and
the funder but returned immediately, so an in-flight tx monitor loop
could still be issuing L1 RPC calls after test teardown. Applied the
equivalent of the `next` fix, fitted to this branch's structure:
`stop()` now awaits `waitMonitoringStopped()` on every publisher and the
funder before returning. `L1TxUtils.waitMonitoringStopped(timeoutSeconds
= 10)` already exists on this branch, is self-bounded, and swallows its
own timeout with a warning, so shutdown cannot hang.

###
`yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts`
— no change needed

On `next`, the votes-only path assigned a bare `pendingL1Submission =
publisher.sendRequestsAt(...)` with no rejection handler, and only the
last job's submission was awaited at shutdown, so an orphaned job's
rejection could crash the process. On this branch that field no longer
exists: both fire-and-forget paths go through
`this.pendingRequests.trackRequest(promise, () => this.interrupt())`,
backed by the sequencer's shared `RequestsTracker`
(`requests_tracker.ts`). `trackRequest` attaches a rejection handler
synchronously at track time (`promise.then(delete, delete)`), so a
tracked promise can never surface as an unhandled rejection regardless
of whether shutdown awaits it. Additionally, `Sequencer.stop()` calls
`pendingRequests.interruptRequests()` followed by `awaitRequests()`, so
all tracked requests — not just the last one — are interrupted and
drained at shutdown. The `next` bug does not exist here, so no change
was forced. (Minor observability note, not a bug: a rejection on the
votes-only path is swallowed silently by the tracker rather than
logged.)

Verified `publisher_manager.ts` parses cleanly; the full workspace
type-check runs in CI (this container lacks the bootstrapped
bb.js/noir/l1-artifacts toolchain).

No tracked issue.

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/0959caa9f03f59fa) ·
group: `slackbot`*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants