Skip to content

beacon/engine, eth/catalyst, miner: honor targetGasLimit from payload attributes#35353

Open
qu0b wants to merge 1 commit into
ethereum:glamsterdam-devnet-7from
qu0b:qu0b/fix/gloas-target-gas-limit
Open

beacon/engine, eth/catalyst, miner: honor targetGasLimit from payload attributes#35353
qu0b wants to merge 1 commit into
ethereum:glamsterdam-devnet-7from
qu0b:qu0b/fix/gloas-target-gas-limit

Conversation

@qu0b

@qu0b qu0b commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Problem

On glamsterdam-devnet-7 the block gas limit is now driven by the consensus layer: PayloadAttributesV4 carries a required targetGasLimit field (execution-apis#796) that the CL supplies with every engine_forkchoiceUpdatedV4, replacing the static EL-side flag for local building.

geth's PayloadAttributes struct has no such field, so the JSON key is silently dropped and payload building falls back to the local miner gas ceiling (default 60M). In a 12-node devnet-7 network (geth/ethrex/nethermind × lighthouse/teku/lodestar/prysm) with genesis at 150M, the CLs registering 300M, and no EL gas-limit flags, all 58 geth proposals over 166 Gloas blocks stepped the gas limit down by the maximum parent/1024, under all four CLs alike, while every ethrex and nethermind proposal stepped up toward the target. geth proposers permanently fight the CL-configured gas limit.

Fix

  • decode targetGasLimit in PayloadAttributes (hex-quantity, mirroring slotNumber)
  • reject forkchoiceUpdatedV4 attributes without it (the spec lists it as required), like slotNumber
  • thread it through BuildPayloadArgs — included in the payload id, with a tag byte so an args set with only slotNum cannot collide with one with only targetGasLimit (both encode as 8 big-endian bytes) — into the worker, where it takes precedence over miner.config.GasCeil in CalcGasLimit
  • internal callers that leave it unset (simulated beacon, testing payloads) keep the existing gas-ceiling behavior

Testing

  • TestPayloadAttributesJSON: decodes CL-shaped fcuV4 attributes JSON + round trip
  • TestBuildPayloadTargetGasLimit: built payload steers up toward a target above parent, down toward one below, and falls back to GasCeil when unset
  • TestForkchoiceUpdatedV4TargetGasLimit: missing field → Invalid payload attributes (-38003); present → proceeds to the fork check
  • TestPayloadId: id distinctness for slotNum/targetGasLimit combinations
  • full miner, beacon/engine, eth/catalyst suites pass

Devnet validation

Kurtosis network of 4× geth (this branch) under lighthouse, teku, lodestar and prysm; minimal preset, genesis gasLimit 150M, every CL configured to register 300M (--gas-limit / --validators-builder-registration-default-gas-limit / --defaultGasLimit / --suggested-gas-limit), no EL-side gas-limit flags:

  • pre-Gloas (fulu, fcuV3) blocks steer down toward the 60M ceiling, as before
  • from the Gloas fork on, every geth-built payload steps up at the maximum +parent/1024 rate under all four CLs — 97 up-steps, 150M → 163.5M over ~100 slots and climbing toward 300M
  • the only exceptions were a handful of proposals in the first four minutes where teku supplied its own default target before validator registrations were applied — CL-side warm-up, independent of this change

Without the fix (stock glamsterdam-devnet-7 image), the same setup produces 58/58 maximum down-steps on geth proposals.

🤖 Generated with Claude Code

… attributes

PayloadAttributesV4 carries a required targetGasLimit field
(execution-apis#796) through which the consensus layer supplies the
desired gas limit with each payload request. The field was previously
dropped during JSON decoding, so locally built payloads always steered
the gas limit towards the miner's configured gas ceiling (default 60M)
regardless of the CL-registered value.

On glamsterdam-devnet-7 this made every geth proposal step the block
gas limit down by the maximum parent/1024 step while the other ELs
honored the 300M target registered on the CL side.

- decode targetGasLimit in PayloadAttributes
- reject forkchoiceUpdatedV4 attributes without it, like slotNumber
- thread it through BuildPayloadArgs (and the payload id) into the
  worker, where it takes precedence over miner.config.GasCeil;
  internal callers that leave it unset (simulated beacon, testing
  payloads) keep the gas-ceiling behavior

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@qu0b qu0b marked this pull request as ready for review July 14, 2026 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant