feat: check gas limit consistency with the target#9391
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 34ec0f97aa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // payload sits behind that (EMPTY-parent chains, sibling forks) get IGNORED and will | ||
| // re-enter the validator as the head catches up. | ||
| // TODO GLOAS: drop this guard once fork choice tracks executed-payload gas_limit by hash. | ||
| if (!byteArrayEquals(bid.parentBlockHash, state.latestExecutionPayloadBid.blockHash)) { |
There was a problem hiding this comment.
Check parent hash against executed payload, not latest bid
This guard uses state.latestExecutionPayloadBid.blockHash, but in Gloas that field can diverge from the latest executed EL payload hash after EMPTY-parent transitions (processParentExecutionPayload leaves state.latestBlockHash unchanged while processExecutionPayloadBid still updates latestExecutionPayloadBid). In that state, spec-valid bids with parent_block_hash == state.latestBlockHash are incorrectly IGNORED, and bids pointing to a non-executed bid hash can pass this check. This can cause the node to drop valid gossip bids and accept invalid parent references until head/state alignment changes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Code Review
This pull request implements the is_gas_limit_target_compatible check and the UNKNOWN_PARENT_BLOCK_HASH error for execution payload bid validation in the Gloas fork. It also relocates the getExpectedGasLimit utility to the state-transition package for better accessibility. Feedback was provided to ensure targetGasLimit is explicitly converted to a number for type safety and consistency with other parts of the codebase.
| const bidGasLimit = Number(bid.gasLimit); | ||
| if (bidGasLimit !== proposerPreferences.message.targetGasLimit) { | ||
| const parentGasLimit = Number(state.latestExecutionPayloadBid.gasLimit); | ||
| const targetGasLimit = proposerPreferences.message.targetGasLimit; |
There was a problem hiding this comment.
The targetGasLimit from proposerPreferences.message is likely a bigint (representing a uint64 in the spec). Since isGasLimitTargetCompatible expects a number, it is safer and more consistent with other parts of the codebase (e.g., produceBlockBody.ts) to explicitly convert it using Number().
| const targetGasLimit = proposerPreferences.message.targetGasLimit; | |
| const targetGasLimit = Number(proposerPreferences.message.targetGasLimit); |
Performance Report✔️ no performance regression detected Full benchmark results
|
| const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit; | ||
| const targetGasLimit = proposerPreferences.message.targetGasLimit; | ||
| if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) { | ||
| throw new ExecutionPayloadBidError(GossipAction.REJECT, { |
There was a problem hiding this comment.
| } | ||
|
|
||
| // Parent is Gloas: get the variant that matches the parentBlockHash from bid | ||
| const parentVariant = this.getBlockHexAndBlockHash(parentRootHex, parentBlockHashFromBid); |
There was a problem hiding this comment.
this is not necessary
parentVariant is exactly the same to parentBlock at line 607 above
| // TODO GLOAS: executionPayloadNumber/GasLimit are not tracked in BeaconState post-gloas | ||
| // (EIP-7732 removed latestExecutionPayloadHeader). Using 0 as unavailable fallback — | ||
| // see initializeForkChoiceFromUnfinalizedState for the same caveat on validation. | ||
| executionPayloadNumber: isStatePostGloas(state) ? 0 : state.payloadBlockNumber, | ||
| executionPayloadGasLimit: isStatePostGloas(state) ? 0 : state.latestExecutionPayloadHeader.gasLimit, |
There was a problem hiding this comment.
I am bit confused by this comment, why is it not tracked in the state?
it's in state.latestExecutionPayloadBid.gasLimit, or is there a reason this value is not viable to use?
|
🎉 This PR is included in v1.44.0 🎉 |
Motivation
Description
AI Assistance Disclosure