eth/sequencer: cap coalesced published records at the store message limit - #2400
Merged
Merged
Conversation
…imit The send path coalesces up to 64 transactions into one published record (commit 89143d7). It bounded a record only by that count and the 32 MB pending-input limit, never by the store's Redpanda max.message.bytes, so a run of large transactions (e.g. 64 x 32 KiB) produced a >1 MiB record. That draws a permanent MESSAGE_TOO_LARGE on produce; the ingress treats a produce failure as a fence and takeover replays the same record, so one oversized record wedges the writer and nothing behind it is preconfirmed. Cap a coalesced record at maxRecordBytes (max.message.bytes less a 4 KiB reserve for per-transaction protobuf framing, the prefix commitment, and the ingress's own recordFraming allowance), so bor never builds a record the ingress would reject. A lone transaction over the cap is still emitted and left for the store to judge, not dropped. Also give the terminal MALFORMED ack path a clearer message: with the cap in place a MALFORMED means the store's max.message.bytes is below this build's record cap, not an oversized record. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cffls
force-pushed
the
cffls/preconf-record-size-cap
branch
from
September 10, 2026 05:57
1d91d1c to
cd7ea97
Compare
cffls
marked this pull request as ready for review
September 10, 2026 06:17
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.
vbhattaccmu
self-requested a review
September 10, 2026 06:25
vbhattaccmu
approved these changes
Sep 10, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## cffls/sequence-publisher #2400 +/- ##
============================================================
+ Coverage 56.97% 56.99% +0.01%
============================================================
Files 951 951
Lines 174328 174330 +2
============================================================
+ Hits 99328 99351 +23
+ Misses 69320 69309 -11
+ Partials 5680 5670 -10
... and 24 files with indirect coverage changes
🚀 New features to boost your workflow:
|
pratikspatil024
approved these changes
Sep 10, 2026
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
The send path coalesces up to 64 transactions into one published record (commit 89143d7), bounded only by that count and a 32 MB pending-input limit — never by the store's Redpanda
max.message.bytes. A run of large transactions (e.g. 64 × 32 KiB) produced a >1 MiB record, which draws a permanentMESSAGE_TOO_LARGEon produce. The ingress treats a produce failure as a fence and takeover replays the same record, so one oversized record wedges the writer and starves every preconfirmation behind it — the "nothing gets preconfirmed under load" report from the Amoy stress test.This caps a coalesced record at
maxRecordBytes=maxMessageBytes(1 MiB) less a 4 KiB reserve for per-transaction protobuf framing, the prefix commitment, and the ingress's ownrecordFramingallowance — so bor never builds a record the ingress would reject. A lone transaction over the cap is still emitted and left for the store to judge, not silently dropped. The limit is a package constant (maxMessageBytes), matched to the store side.The store-side half (reject oversized instead of self-fencing) is 0xPolygon/sequence-store#12.
Executed tests
stream_test.go:TestCoalesceRecordByteCap(40 × 32 KiB → byte-capped prefix,proto.Sizeunder the ingress limit, fold commitment preserved),TestCoalesceRecordByteCapBoundary(exact-fill is inclusive),TestCoalesceRecordCountCap(the 64-tx count cap still binds below the byte cap).go test ./eth/sequencer/green; diffguard clean with mutation testing.MESSAGE_TOO_LARGE, with preconf serving throughout — versus the wedge this reproduces without the cap.Rollout notes
Producer-side only; not consensus-affecting (changes what a producer batches into a store record, not block content). Backwards-compatible. Pairs with sequence-store#12 — either side alone prevents the wedge; together they keep bor's records provably under the store limit.
🤖 Generated with Claude Code