eth/sequencer, ci: trip read breaker on a frozen store tail; add kurtosis sequencer e2e leg - #2423
Merged
Merged
Conversation
Runs the pos-workflows sequence-store suites (functional, rpc, chaos) against a bor built from this checkout, on pushes and pull requests to the sequencing branch. pos-workflows runs the same suites but builds bor from a fixed ref, so it cannot gate a bor PR; this leg supplies the bor under test and borrows the devnet config and test scripts from there. The e2e job runs for trusted refs only: the sequence-store image is a private ghcr package that fork pull_request runs cannot pull. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A gateway cut off from its broker keeps answering reads from an in-memory window that no longer advances. Those reads succeed, so the silence path (isSilent -> readBreaker.silent) never fires, and writeDown covers only the write path. The producer then reads the same held height on every build, sees what looks like a rival already holding it, refuses to seal, re-reads, and refuses again until the fault clears -- a store outage that was meant to pause preconfirmations and nothing else instead slows block production. Treat a live tail whose head does not advance across staleReadsToTrip reads as a path that is not answering. observeLiveTail feeds the live-tail head from the walk to the breaker, which opens on a frozen tail and closes only when the tail advances again; a bare successful (but frozen) read cannot clear it. Once open, reads return errReadPathDown and the pre-seal barrier and seal gate take their existing unreadable -> proceed branch, so production continues at full cadence. This also subsumes a degraded-but-answering (too-slow-to-advance) store, which the silence-only breaker missed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## cffls/sequence-publisher #2423 +/- ##
============================================================
- Coverage 57.17% 57.12% -0.06%
============================================================
Files 953 953
Lines 174875 174893 +18
============================================================
- Hits 99990 99903 -87
- Misses 69219 69310 +91
- Partials 5666 5680 +14
... and 31 files with indirect coverage changes
🚀 New features to boost your workflow:
|
cffls
marked this pull request as ready for review
September 17, 2026 19:36
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
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
Two related changes to keep the sequence store off the block-production critical path, and to make CI prove it against a bor built from the PR.
1.
eth/sequencer: trip the read breaker on a frozen store tailFixes the "frozen tail" liveness fault: a sequence-store gateway cut off from its broker keeps answering reads from an in-memory window that no longer advances, and the producer — reading that same held height on every build — sees what looks like a rival already holding the height, refuses to seal, re-reads, and refuses again until the fault clears. A store outage that is supposed to pause preconfirmations and nothing else instead slows block production.
The gap is that #2406's read breaker keys on silence:
isSilentcounts only timeout /Unavailable/Canceled, and a frozen tail answers (fast, successful, stale), so the breaker never trips;writeDowncovers only the write path, which is healthy during a gateway↔broker partition. This adds staleness detection on the read path:readBreaker.observeLiveTail(head)— the live-tail head (resp.GetNext()at aLivepage inwalk) that does not advance acrossstaleReadsToTrip(6) reads opens the breaker with reasonstale. Any advancement resets the counter and clears the hold.answered()returns early when the hold isstale: a frozen tail still answers, so a bare successful round trip must not clear a staleness hold — only real advancement does. The silence path is unchanged.errReadPathDown, so the pre-seal barrier and seal gate take their existing "unreadable → proceed" branch (SealUnknown) and production continues at full cadence. The 5 s probe re-reads once per interval and clears the hold the moment the tail moves.This also subsumes the degraded-but-answering (too-slow-to-advance) store that the silence-only breaker missed. The companion gateway-readiness fix (fail
/readywhen the broker offset can't be sampled) belongs in the sequence-store service; this makes the producer self-protecting regardless of gateway behavior.writeDown2.
ci: add the Kurtosis sequencer e2e legAdds
Kurtosis Sequencer E2E Tests, running the pos-workflows sequence-store suites (functional ~25 m, rpc ~5 m, chaos ~10 m) against a bor built from this checkout, on pushes and PRs tocffls/sequence-publisherplusworkflow_dispatch. pos-workflows runs the same suites but builds bor from a fixed ref and is not aworkflow_callworkflow, so it cannot gate a bor PR. Mirrors bor'skurtosis-e2e.yml(buildbor:localfrom the PR,heimdall-v2:localfromdevelop, pos-workflows'configs/kurtosis-sequencer-e2e.yml, kurtosis-posv1.4.2, polycliv0.1.103).develop.pull_requestruns cannot pull. Build jobs still run for forks.sequencer-*-image) to avoid colliding with the other kurtosis legs on the same ref.Note: the chaos suite covers
broker stop,gateway pause, andgateway latency, but not the gateway↔broker partition that produces a frozen tail — so it exercises the store-outage paths but does not yet regression-test change 1. A dedicated episode (100 % loss scoped to the broker IP on the gateway container) is a follow-up in pos-workflows.Executed tests
Change 1
Unit (
eth/sequencer/readbreaker_stale_test.go, confirmed to fail without the fix):TestReadBreakerTripsOnFrozenTail(frozen tail opens the breaker; a successful-but-frozen read does not clear it; an advancing tail does) andTestReadBreakerIgnoresAdvancingTail.Full
eth/sequencersuite green on the combined tree (on top of sequencer, rawdb, ethapi: audit the store for the window a node did not watch #2388),gofmtclean.Reproduced end to end on a Kurtosis devnet (3 producers + 4 consumers + 1 RPC, single-instance seqstore, ~1 s cadence). Fault = pumba
netem loss 100%on gateway→redpanda only, ingress→redpanda healthy, 90 s hold:bor:2406):sequencer_publish_state=5(contending) for the entire partition; throughput fell from 8 to ~2–6 blocks / 8 s, recovering only on heal.sequencer_read_breakeropened=1, 131 stale reads refused,breakerclosed=1on heal; producer logSequencer store tail is frozen (answering but not advancing)→Sequencer store tail is advancing again; throughput held 8 blocks / 8 s throughout.(On this 1 s-cadence devnet the fault is a sustained ~50 % slowdown rather than the 4 s-cadence incident's ~123 s stall; mechanism and
publish_state=5match.)Change 2
needsgraph, everysteps.<id>.outcomereferenced in anif:is a defined step id).cffls/sequence-publisher, so the new leg runs here against this PR's bor build — treat a greene2e-testsjob as the acceptance test. First-run watch item:Pull sequence-store imagerelies on this repo's read grant onghcr.io/0xpolygon/sequence-store(aSEQUENCE_STORE_GHCR_TOKENfallback is wired).Rollout notes
Not consensus-affecting; no coordinated upgrade. Change 1 is confined to the sequence-store publisher (off by default), no new knobs, no wire or database changes, no safety-property change — every site touched already returned "proceed" once its budget expired; this changes when the producer stops waiting on a store that cannot inform it, not what it does about it. Reuses the existing
sequencer/read/*metrics. Change 2 is CI only; not wired as a required status check — that is a branch-protection setting to flip once the leg is stable.🤖 Generated with Claude Code