(feat): reserved blockspace block building#2302
Conversation
…ved-blockspace-block-building
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #2302 +/- ##
===========================================
+ Coverage 54.05% 54.16% +0.10%
===========================================
Files 907 909 +2
Lines 161982 162243 +261
===========================================
+ Hits 87564 87882 +318
+ Misses 69000 68939 -61
- Partials 5418 5422 +4
... and 20 files with indirect coverage changes
🚀 New features to boost your workflow:
|
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.
|
@claude review |
There was a problem hiding this comment.
Pull request overview
Implements the miner-side sequencing and header plumbing needed to support “reserved blockspace” block building, by splitting block filling into ordered commit batches (priority → per-reserved-client → normal) and optionally recording reserved-region gas usage into Header.Extra (post-Cancun) for future validation work.
Changes:
- Adds a sequencing stage to partition pending transactions into prioritized, reserved-per-client (quota/ceiling), and normal batches, and commits them in order.
- Extends the miner’s ordering heap with a reserved mode (ascending effective tip, never dropping below-base-fee txs) and introduces a registry interface + test mock.
- Extends
core/types.BlockExtraDatawith an optionalReservedGasUsedfield plus getter/setter and RLP compatibility tests.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| miner/worker.go | Integrates batch sequencing into block filling and writes ReservedGasUsed into header extra data when the reserved pass is active. |
| miner/sequencing.go | Implements batch formation logic (priority extraction, reserved selection by quota/ceiling, deterministic per-block client rotation) and adds producer metrics. |
| miner/reserved_test.go | Adds unit/e2e-style tests for sequencing/quota/ceiling behavior, registry snapshotting, and header field presence/absence. |
| miner/reserved_registry.go | Adds the reserved registry interface plus an in-memory mock registry for tests. |
| miner/ordering.go | Adds reserved-mode ordering (ascending effective tip, clamped below-base-fee) and threads a reserved flag through the heap implementation. |
| miner/ordering_test.go | Adds focused tests for reserved ordering semantics and interrupt/clone behavior. |
| miner/miner.go | Exposes Miner.SetReservedRegistry to wire a registry into the worker. |
| core/types/block.go | Adds ReservedGasUsed to BlockExtraData and implements GetReservedGasUsed / SetReservedGasUsed. |
| core/types/block_test.go | Adds RLP backward-compatibility and getter/setter tests for the new extra-data field. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Beyond the inline findings, this run also examined and ruled out a few adjacent concerns: blob transactions being silently dropped by the new fillTransactions (bor's txpool filter already excludes blob txs, so none are dropped by this change), SetReservedGasUsed corrupting a nil GasTarget/BaseFeeChangeDenominator into an explicit zero (the RLP optional-pointer round-trip preserves the existing nil/zero distinction), and an empty pre-seal commit bypassing writeReservedGasUsed (the write happens unconditionally at the end of fillTransactions, including for empty/interrupted builds).
Extended reasoning...
This is a record of additional areas checked beyond the two inline findings (the dead fillTransactionsOld duplication and the multi-batch BlockSTM TxDependency reset bug), not a guarantee of correctness or an instruction to skip these in future review.
|
|
@claude review |
| type ranked struct { | ||
| id uint64 | ||
| digest []byte | ||
| } | ||
| var buf [40]byte | ||
| copy(buf[8:], parentHash[:]) | ||
| ranks := make([]ranked, len(ids)) | ||
| for i, id := range ids { | ||
| binary.BigEndian.PutUint64(buf[:8], id) | ||
| ranks[i] = ranked{id: id, digest: crypto.Keccak256(buf[:])} | ||
| } | ||
| sort.Slice(ranks, func(i, j int) bool { | ||
| return bytes.Compare(ranks[i].digest, ranks[j].digest) < 0 | ||
| }) |
| if registry == nil || len(registry.Clients()) == 0 { | ||
| return nil | ||
| } | ||
| reservedTxs := filterReservedTxs(pendingTxs, registry) | ||
| if len(reservedTxs) == 0 { | ||
| return nil | ||
| } | ||
|
|
||
| // The global ceiling bounds the summed declared gas selected across all | ||
| // clients. Like per-client quota, it is charged against declared gas | ||
| // limits, not actual gas used. | ||
| ceilingLeft := effectiveCeilingGas(registry) | ||
|
|
||
| clientOrder := orderClients(parentHash, registry.Clients()) | ||
| var clientGroups = make([]*transactionsByPriceAndNonce, 0, len(clientOrder)) |


Summary
This PR implements the sequencing changes needed for reserved blockspace implementation. It partitions each block into reserved and normal transactions during the block building phase.
Here's the spec for more details: https://primer-polygon.up.railway.app/d/019f3716-b491-77ea-8c67-519245e075a9
This PR is It is one slice of the larger feature. Other changes around the feature will be included in a separate PR. Note that the PR doesn't activate the feature. More details below.
What this PR adds, per package
miner— the sequencing pipeline and its inputs:sequencing.go(new):sequenceTxsorders pending transactions into commit batches —priority senders → one batch per reserved client → normal. Reserved selection charges each
client's quota against declared gas limits (
tx.Gas, not actual gas used) so the wholeset is decidable without executing anything — this keeps it compatible with future parallel
(BlockSTM) building and makes validation pre-execution-checkable. A global ceiling bounds the
sum across clients. Quota/ceiling overflow falls back to the normal pass under standard
EIP-1559 rules. Client visit order rotates deterministically per block
(
keccak(clientID ‖ parentHash)) so no client is systematically favored.reserved_registry.go(new): thereservedRegistryinterface the miner consumes (lookup,quotas, ceiling, per-build snapshot pinned to the parent block) plus an in-memory
MockRegistryused by tests. The contract-backed registry lands behind this same interfacein its own PR — swap happens at one setter (
Miner.SetReservedRegistry).ordering.go: a second, reserved-only mode for the existing price/nonce heap — popsascending effective tip (zero-fee first) and never drops below-base-fee transactions,
the opposite of the normal market on both counts. The normal mode is byte-identical to before.
worker.go:fillTransactionsnow commits the sequenced batches in order; the buildaccumulates actual gas used by reserved batches and records it in the header
(
writeReservedGasUsed, written even for interrupt-truncated blocks since those still seal).Two producer-side metrics (
worker/reserved/{gasused,overflow}).core/types— the header surface:BlockExtraDatagains a fifth field,ReservedGasUsed *uint64(rlp:"optional"), followingthe Giugliano
GasTarget/BaseFeeChangeDenominatorprecedent. Pointer on purpose: an explicitzero ("reserved active, none used") stays distinct from the field being absent on the wire.
GetReservedGasUsed/SetReservedGasUsedhelpers. The setter rewritesHeader.Extravia theraw-TxDependency mirror, so it never expands
TxDependencyjust to append one integer.Worth knowing while reviewing
mini-block sequencing may interleave; only quota/accounting are meant for consensus (validation PR).
the breaching tx) — reserved batches commit before normal ones, so anything else would break
per-sender nonce order.
(base-fee check) still reject them until the txpool and EVM slices land. Tests therefore
exercise sequencing with fee-carrying transactions, which works today.
Executed tests
time tie-break,
Shiftre-wrap, clone, interrupt), RLP encode/decode compatibility.BlockExtraDataencodes as the same4-element list as before this PR — headers are byte-identical.
present/absent, and a positional test where a reserved sender's 26 gwei tx is included ahead
of a normal sender's 100 gwei tx.
minersuite under-race: green. Diffguard mutation score on the diff: 99.3 %(147/148; the lone survivor is an equivalent mutant — boundary case where both variants
return nil).
Rollout notes
Safe to merge and deploy now; the feature is dormant. There is no hardfork in this PR and no
production code sets a registry (
Miner.SetReservedRegistryhas no production caller), so:develop, and produced headers arebyte-identical (no
ReservedGasUsedis ever written — test-pinned);Backwards-compatible, no coordination or operator action needed. Activation happens in a later
slice: the contract-backed registry plus a hardfork gate on the header write
(
TODO(reserved-blockspace)marks the spot, following the Giugliano gating pattern).