Skip to content

feat(engine): support targetGasLimit in PayloadAttributesV4#11611

Open
LukaszRozmej wants to merge 7 commits into
masterfrom
feat/engine-payload-attrs-target-gas-limit
Open

feat(engine): support targetGasLimit in PayloadAttributesV4#11611
LukaszRozmej wants to merge 7 commits into
masterfrom
feat/engine-payload-attrs-target-gas-limit

Conversation

@LukaszRozmej
Copy link
Copy Markdown
Member

Changes

  • Add TargetGasLimit to PayloadAttributes per execution-apis Remove unnecessary allocations in FrameMacProcessor #796.
    Included in ToString, payload-id hash input, version inference, and
    required-field validation for V4 attributes.
  • IGasLimitCalculator gains an overload accepting an optional target
    override; TargetAdjustedGasLimitCalculator honors it (override takes
    precedence over BlocksConfig.TargetBlockGasLimit).
  • AuRaContractGasLimitOverride forwards the override to its inner
    calculator.
  • BlockProducerBase and TestingRpcModule pass the per-call target
    into the calculator so the standard parent ± delta adjustment applies.

Implements the draft spec in ethereum/execution-apis#796.

Types of changes

  • New feature

Testing

  • Requires testing — Yes (tests added)
    • New V4 validation cases (TargetGasLimit required, SlotNumber
      required) in EngineModuleTests.V1.
    • V6 Amsterdam tests updated to set targetGasLimit and refreshed
      expected payload ids (plain + AuRa override).
    • TargetAdjustedGasLimitCalculatorTests covers override precedence
      and null-override fallback.

Documentation

  • No

Implements ethereum/execution-apis#796, which adds a required
`targetGasLimit` field to `PayloadAttributesV4` so the CL can supply
the per-FCU gas-limit target instead of relying on the EL's static
configuration.

- `PayloadAttributes.TargetGasLimit` is included in `ToString`, the
  payload-id hash input, version inference, and required-field
  validation for V4 attributes.
- `IGasLimitCalculator` gains an overload accepting an optional
  target override; `TargetAdjustedGasLimitCalculator` honors it,
  taking precedence over `BlocksConfig.TargetBlockGasLimit`.
  `AuRaContractGasLimitOverride` forwards the override to its inner
  calculator.
- `BlockProducerBase` and `TestingRpcModule` pass the per-call target
  into the calculator so the standard gas-limit adjustment applies.
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 14, 2026

Claude finished @LukaszRozmej's task in 4m 20s —— View job


PR Review: feat(engine): support targetGasLimit in PayloadAttributesV4

Tasks:

  • Gather context and read changed files
  • Review correctness and spec compliance
  • Review security implications
  • Review performance considerations
  • Check adherence to repo rules
  • Post findings

Summary

The overall approach is sound and well-structured. TargetGasLimit is correctly wired through the payload-ID hash, version inference, field validation, and the calculator chain. The interface default-method pattern for backwards-compatible implementations is a clean choice. There are two Medium issues to resolve before merge and one Low gap in test coverage.


Medium

1. Unchecked ulong?long? narrowing cast (two sites: BlockProducerBase.cs:217, TestingRpcModule.cs:202)

PayloadAttributes.TargetGasLimit is ulong?; both call sites cast it directly to long? without bounds checking. Any value > long.MaxValue silently wraps to a negative long, which the calculator then clamps to spec.MinGasLimit — no error, no log. While real gas limits are nowhere near long.MaxValue, a malformed or adversarial FCU payload can trigger this silently. The cleanest fix is a single bounds-check guard in ValidateFields (e.g. TargetGasLimit > (ulong)long.MaxValue → error); the cast sites then become provably safe. See inline comment on BlockProducerBase.cs:217.

2. AuRaContractGasLimitOverride silently drops the CL targetGasLimit when the contract is active (AuRaContractGasLimitOverride.cs:42)

When GetGasLimitFromContract returns a non-null value the targetGasLimitOverride from the V4 FCU is discarded without any logging or documentation. The PR description says the override is "forwarded to its inner calculator" — that is only true when no contract limit is available. For Amsterdam-capable AuRa chains with an active gas-limit contract the CL's preference is silently overridden. This should at minimum be documented with a comment; a _logger.IsWarn line when a non-null override is dropped would make the precedence rule observable in production. See inline comment on AuRaContractGasLimitOverride.cs:42.


Low

3. No tests for AuRaContractGasLimitOverride.GetGasLimit(BlockHeader, long?)

The existing AuRaContractGasLimitOverrideTests only exercise GetGasLimit(BlockHeader). Neither the "contract wins → override dropped" branch nor the "contract absent → override forwarded" branch is covered by the new overload. See inline comment on TargetAdjustedGasLimitCalculatorTests.cs:55.


Looks good

  • PayloadAttributes changes (version inference, payload-ID hashing, field validation, ToString) are consistent and correct.
  • TargetAdjustedGasLimitCalculator override-precedence logic and tests are clean.
  • IGasLimitCalculator default-method fallback is well-documented and a safe extension point.
  • V4 validation test cases (SlotNumber null, TargetGasLimit null) are complete.
  • TestingRpcModuleTests.cs correctly stubs both GetGasLimit overloads.

Comment thread src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs Outdated
Comment thread src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs Outdated
Comment thread src/Nethermind/Nethermind.Merge.Plugin/TestingRpcModule.cs Outdated
Comment thread src/Nethermind/Nethermind.Consensus.Test/TargetAdjustedGasLimitCalculatorTests.cs Outdated
- Collapse `IGasLimitCalculator.GetGasLimit` to a single method with
  `long? targetGasLimitOverride = null` default; update all
  implementations (TargetAdjusted, AuRa, FollowOtherMiners, Optimism,
  Xdc, ManualGasLimitCalculator).
- Reject `TargetGasLimit > long.MaxValue` in `PayloadAttributes.Validate`
  to prevent silent wrap of the `ulong? -> long?` narrowing. Cast sites
  in BlockProducerBase / TestingRpcModule now use a `checked` cast for
  defense-in-depth on paths that bypass validation.
- AuRa contract override: when the contract returns a limit and the CL
  also supplies a `targetGasLimit`, log a warning so operators know the
  contract takes precedence; otherwise forward the override to the
  inner calculator.
- Add focused unit tests for AuRa: contract wins (override ignored) and
  no-contract (override forwarded). Add a V4 validation case for
  `TargetGasLimit > Int64.MaxValue`.
- Type `TargetGasLimit` as `long?` directly (was `ulong?`), dropping the
  narrowing cast and the upper-bound `> long.MaxValue` validation. Gas
  limits in Nethermind are already stored as `long`.
- Consolidate the parameterless `PayloadAttributes.GetGasLimit()` and
  the duplicated `payloadAttributes?` access at the call site into a
  single `GetGasLimit(BlockHeader parent, IGasLimitCalculator calc)`.
  Base implementation routes `TargetGasLimit` through the calculator;
  Boost/Optimism/Taiko override to return their unadjusted value.
- AuRa: drop the conflict warning and flip precedence — the CL's
  per-FCU `targetGasLimit` now takes priority over the on-chain
  contract value, with the contract acting as fallback when no
  override is supplied.
- Dedup `TargetAdjustedGasLimitCalculatorTests` and the new AuRa
  override tests around small construction helpers.
@github-actions github-actions Bot added the taiko related to the taiko alethia rollup label May 14, 2026
Align with the spec field name (`PayloadAttributesV4.targetGasLimit`).
The "override" suffix was redundant — a non-null value already means
override behavior. Inside `TargetAdjustedGasLimitCalculator`, reuse the
parameter via `??=` instead of an extra local.

Also drop the unused `using Nethermind.Xdc.Spec` in XdcGasLimitCalculator
(left over from the previous expression-body collapse) — was failing the
`IDE0005` lint check.
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 14, 2026

Claude encountered an error —— View job


I'll analyze this and get back to you.

@LukaszRozmej
Copy link
Copy Markdown
Member Author

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 14, 2026

Claude encountered an error —— View job


I'll analyze this and get back to you.

@LukaszRozmej
Copy link
Copy Markdown
Member Author

Review — PayloadAttributesV4 targetGasLimit support

Reviewed at commit 6abd4a3. The two Medium findings raised in the earlier @claude pass (Apr 14 14:55) have been addressed in e217c72 / c3ae2b4:

  • TargetGasLimit is now typed as long? directly — no narrowing cast anywhere.
  • AuRa precedence is now documented (override wins, contract is fallback) with the inline comment in AuRaContractGasLimitOverride.cs.
  • AuRa-specific override tests added (Override_takes_precedence_over_contract_limit, Override_is_forwarded_to_inner_when_no_contract_limit).

Verdict

Mergeable once the in-progress Sync hoodi and integration tests come back green. All build/test checks have passed; the only red checks are the two claude-review automation runs (Claude encountered an error — workflow failure, not a review verdict). mergeable: MERGEABLE; mergeStateStatus: BLOCKED reflects pending required checks, not a real blocker.

Notes worth a second look (not blocking)

  1. AuRa block validation vs. CL override. AuRaContractGasLimitOverride.GetGasLimit now lets a CL targetGasLimit bypass the on-chain contract during production, but IsGasLimitValid (used by AuRaBlockProcessor/AuRaMergeBlockProcessor to validate incoming blocks) still consults the contract only. On an AuRa chain that (a) has BlockGasLimitContractTransitions active and (b) activates EIP-7843, a producer setting a non-contract targetGasLimit would create blocks that other AuRa nodes reject with Invalid gas limit, expected value from contract .... Today this is latent (no AuRa chain activates V4 yet), but worth either:

    • adding a one-liner comment on IsGasLimitValid flagging the asymmetry, or
    • making the validator honor the same override path (probably out of scope here).
  2. Optimism awkwardness. OptimismPayloadAttributes.GetGasLimit ignores TargetGasLimit (uses the rollup-supplied GasLimit), but OptimismPayloadAttributes.Validate calls base.Validate, so V4 attributes on an OP chain would still require a targetGasLimit field that is effectively unused. Probably fine — OP chains don't follow L1 fork activations 1:1 — but worth keeping in mind when OP ever lands on a V4-equivalent.

  3. Taiko sidesteps both points: its Validate short-circuits before base.Validate, and GetGasLimit returns BlockMetadata!.GasLimit unconditionally. ✅

Looks good

  • PayloadAttributes payload-id hashing, ToString, version inference, and ValidateFields are consistent — TargetGasLimit writes 8 bytes big-endian, accounted for in ComputePayloadIdMembersSize.
  • TargetAdjustedGasLimitCalculator precedence (targetGasLimit ??= _blocksConfig.TargetBlockGasLimit) and its parameterized tests are clean. Refactor of the test file into a Calc(...) helper is a nice win on duplication.
  • IGasLimitCalculator becomes a single-method interface with an optional parameter — minimal blast radius, default value keeps all subclass overrides additive.
  • Boost's new behavior (GasLimit ?? base.GetGasLimit(...)) is a small functional improvement over master (previously it dropped to a non-target calculator path when GasLimit was null).
  • V4 validation matrix in EngineModuleTests.V1 covers all four missing-required-field cases. V6 expected payloadIds updated to reflect the new hash input.

— Posted by Claude Opus 4.7 via Claude Code

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 14, 2026

Claude encountered an error —— View job


I'll analyze this and get back to you.

`AuRaContractGasLimitOverride.GetGasLimit` prefers the CL-supplied
`targetGasLimit` (PayloadAttributesV4) over the on-chain contract
value, but `IsGasLimitValid` — called from `AuRaBlockProcessor` —
still strictly required the block to match the contract. On an AuRa
chain with an active gas-limit contract that ever activates
EIP-7843, a producer using the override path would emit a block its
own validator rejects.

Accept any block gas limit within parent ± delta when it differs
from the contract value (HeaderValidator independently enforces the
full consensus rule). Inject `ISpecProvider` so the bound divisor is
read from the active release spec instead of being hardcoded.
`AuRaContractGasLimitOverride.IsGasLimitValid` now round-trips the
candidate gas limit through `_innerCalculator` (a
`TargetAdjustedGasLimitCalculator` in production): if the calculator
returns the candidate unchanged it's within the standard parent ±
delta range, otherwise it's been clamped. Drops the duplicated delta
math and the `ISpecProvider` dependency added in the previous commit.

Also strip the verbose XML doc comments added on `TargetGasLimit`,
`PayloadAttributes.GetGasLimit`, `IGasLimitCalculator.GetGasLimit`,
and the explanatory test comments.
@benaadams
Copy link
Copy Markdown
Member

Do we need to wait till on devnet? i.e. is this breaking change

@LukaszRozmej LukaszRozmej added the amsterdam Amsterdam hard fork label May 15, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (4a3d582) to head (e60c92c).
⚠️ Report is 12 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##           master   #11611       +/-   ##
===========================================
- Coverage   74.87%        0   -74.88%     
===========================================
  Files        2884        0     -2884     
  Lines      118618        0   -118618     
  Branches    17147        0    -17147     
===========================================
- Hits        88815        0    -88815     
+ Misses      26842        0    -26842     
+ Partials     2961        0     -2961     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@barnabasbusa
Copy link
Copy Markdown

your original description points to PR 796 from nethermind's repo instead of ethereum/execution-apis#796

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

amsterdam Amsterdam hard fork new feature optimism taiko related to the taiko alethia rollup xdc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants