Skip to content

fix(l1): return -38003 for FCUv2 payloadAttributes mismatch#6353

Merged
iovoid merged 2 commits into
lambdaclass:mainfrom
Muzry:fix-fcuv2-return-38003
Mar 17, 2026
Merged

fix(l1): return -38003 for FCUv2 payloadAttributes mismatch#6353
iovoid merged 2 commits into
lambdaclass:mainfrom
Muzry:fix-fcuv2-return-38003

Conversation

@Muzry
Copy link
Copy Markdown
Contributor

@Muzry Muzry commented Mar 10, 2026

This PR updates engine_forkchoiceUpdatedV2 to return -38003: Invalid payload attributes when the wrong payloadAttributes version is used.

In particular, FCUv2 payload-attribute version mismatches such as:

  • missing withdrawals at or after Shanghai
  • unexpected withdrawals before Shanghai

should be treated as Invalid payload attributes, not Invalid params.

Why

This change aligns the client with the latest Engine API spec update in:

It also follows the implementation discussion and prior client-side change in:

The spec was clarified so that FCUv2 now behaves consistently with newer forkchoiceUpdated versions for payloadAttributes structure/version
mismatches.

What changed

  • Updated FCUv2 payload attributes validation to return -38003 for payloadAttributes version mismatches.
  • Added/updated regression coverage for the affected FCUv2 cases.

Hive impact

This fixes the Hive engine-withdrawals failure caused by returning the wrong error code for FCUv2 payloadAttributes mismatches.

Relevant Hive failure:

After this change, the client returns the expected error code for the affected FCUv2 cases.

If my understanding or interpretation of the spec change is incorrect, please let me know and I can adjust the implementation accordingly.

@Muzry Muzry requested a review from a team as a code owner March 10, 2026 15:50
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 10, 2026

Greptile Summary

This PR aligns engine_forkchoiceUpdatedV2 with the updated Engine API spec (ethereum/execution-apis#761) by returning -38003 Invalid payload attributes (instead of -32602 Invalid params) for FCUv2 payloadAttributes version mismatches — specifically when withdrawals is absent at or after Shanghai, or unexpectedly present before Shanghai.

Key changes:

  • validate_attributes_v2: error for a missing withdrawals field changed from RpcErr::WrongParam (-32602) to RpcErr::InvalidPayloadAttributes (-38003).
  • New validate_attributes_v2_pre_shanghai function: used instead of validate_attributes_v1 in the pre-Shanghai branch of FCUv2, returning -38003 when withdrawals is unexpectedly present.
  • validate_attributes_v1 (used only by FCUv1) is deliberately left unchanged at -32602, which is correct per spec since the update only applies to FCUv2.
  • Unit tests added to cover both new error paths.

Minor observation:

  • Both validate_attributes_v2 and validate_attributes_v2_pre_shanghai use the identical error message string "withdrawals" despite representing opposite conditions (missing vs. unexpected). A more descriptive message like "unexpected withdrawals before Shanghai" would improve debuggability.

Confidence Score: 4/5

  • This PR is safe to merge; the logic change is narrow, spec-aligned, and covered by new tests.
  • The change is small and targeted — a two-line logic swap and a new helper function. The intent matches the referenced spec update and the go-ethereum implementation. The only concern is a cosmetic ambiguity in the error message string shared between the missing-withdrawals and unexpected-withdrawals paths.
  • No files require special attention beyond the minor error message wording in validate_attributes_v2_pre_shanghai.

Important Files Changed

Filename Overview
crates/networking/rpc/engine/fork_choice.rs FCUv2 payload attribute validation updated: validate_attributes_v2 now returns -38003 instead of -32602 when withdrawals is missing post-Shanghai; new validate_attributes_v2_pre_shanghai returns -38003 when withdrawals is unexpectedly present pre-Shanghai; unit tests added for both cases.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[FCUv2 handle - payloadAttributes present] --> B{is_cancun_activated?}
    B -- Yes --> C[Return UnsupportedFork error]
    B -- No --> D{is_shanghai_activated?}
    D -- Yes --> E[validate_attributes_v2]
    D -- No --> F[validate_attributes_v2_pre_shanghai]
    E --> G{withdrawals is None?}
    G -- Yes --> H[Return -38003 InvalidPayloadAttributes]
    G -- No --> I[validate_timestamp]
    F --> J{withdrawals is Some?}
    J -- Yes --> K[Return -38003 InvalidPayloadAttributes]
    J -- No --> L[validate_timestamp]
    I --> M{timestamp <= head_block.timestamp?}
    L --> M
    M -- Yes --> N[Return -38003 InvalidPayloadAttributes - invalid timestamp]
    M -- No --> O[build_payload]
Loading

Last reviewed commit: 559aa86

Comment on lines +381 to 389
fn validate_attributes_v2_pre_shanghai(
attributes: &PayloadAttributesV3,
head_block: &BlockHeader,
) -> Result<(), RpcErr> {
if attributes.withdrawals.is_some() {
return Err(RpcErr::InvalidPayloadAttributes("withdrawals".to_string()));
}
validate_timestamp(attributes, head_block)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ambiguous error message for pre-Shanghai withdrawals case

Both validate_attributes_v2 (missing withdrawals) and validate_attributes_v2_pre_shanghai (unexpected withdrawals) produce RpcErr::InvalidPayloadAttributes("withdrawals".to_string()). This makes it harder to distinguish the two failure modes when debugging. A more descriptive message would help differentiate them.

Suggested change
fn validate_attributes_v2_pre_shanghai(
attributes: &PayloadAttributesV3,
head_block: &BlockHeader,
) -> Result<(), RpcErr> {
if attributes.withdrawals.is_some() {
return Err(RpcErr::InvalidPayloadAttributes("withdrawals".to_string()));
}
validate_timestamp(attributes, head_block)
}
fn validate_attributes_v2_pre_shanghai(
attributes: &PayloadAttributesV3,
head_block: &BlockHeader,
) -> Result<(), RpcErr> {
if attributes.withdrawals.is_some() {
return Err(RpcErr::InvalidPayloadAttributes(
"unexpected withdrawals before Shanghai".to_string(),
));
}
validate_timestamp(attributes, head_block)
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/networking/rpc/engine/fork_choice.rs
Line: 381-389

Comment:
**Ambiguous error message for pre-Shanghai `withdrawals` case**

Both `validate_attributes_v2` (missing `withdrawals`) and `validate_attributes_v2_pre_shanghai` (unexpected `withdrawals`) produce `RpcErr::InvalidPayloadAttributes("withdrawals".to_string())`. This makes it harder to distinguish the two failure modes when debugging. A more descriptive message would help differentiate them.

```suggestion
fn validate_attributes_v2_pre_shanghai(
    attributes: &PayloadAttributesV3,
    head_block: &BlockHeader,
) -> Result<(), RpcErr> {
    if attributes.withdrawals.is_some() {
        return Err(RpcErr::InvalidPayloadAttributes(
            "unexpected withdrawals before Shanghai".to_string(),
        ));
    }
    validate_timestamp(attributes, head_block)
}
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

@ElFantasma ElFantasma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Greptile suggestion is a nice to have, but not blocking. Thanks for the contribution!

@iovoid iovoid changed the title engine: return -38003 for FCUv2 payloadAttributes mismatch fix(l1): return -38003 for FCUv2 payloadAttributes mismatch Mar 11, 2026
Copy link
Copy Markdown
Collaborator

@Arkenan Arkenan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Arkenan
Copy link
Copy Markdown
Collaborator

Arkenan commented Mar 16, 2026

Hey, @Muzry! Your commits are showing as Unverified, which is blocking the merge. To fix this, you need to set up commit signature verification on GitHub.

Quickest fix (SSH signing — no GPG needed):

# 1. Tell git to sign commits with your SSH key                                                                                                                                                                                                                                                                                                                                                                                        
git config --global gpg.format ssh                                                                                                                                                                                                                                                                                                                                                                                                     
git config --global user.signingkey ~/.ssh/id_ed25519.pub  # or whatever key you use with GitHub                                                                                                                                                                                                                                                                                                                                       
git config --global commit.gpgsign true                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                         
# 2. Add the same key as a **Signing Key** on GitHub:                                                                                                                                                                                                                                                                                                                                                                                  
#    → https://github.com/settings/keys → "New SSH Key" → Key type: **Signing Key**
                                                                                                                                                                                                                                                                                                                                                                                                                                         
# 3. Re-sign your commits on this branch (rebase onto the base branch)                                                                                                                                                                                                                                                                                                                                                                 
git rebase main --exec 'git commit --amend --no-edit -S'                                                                                                                                                                                                                                                                                                                                                                               
git push --force-with-lease                                                                                                                                                                                                                                                                                                                                                                                                            

Make sure the email in git config user.email matches your GitHub account (or is added in https://github.com/settings/emails).

Full docs: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature verification

@Muzry Muzry force-pushed the fix-fcuv2-return-38003 branch from ee28d75 to e3171a5 Compare March 17, 2026 01:47
@Muzry Muzry force-pushed the fix-fcuv2-return-38003 branch 4 times, most recently from b2f857e to 8810591 Compare March 17, 2026 02:03
@Muzry Muzry force-pushed the fix-fcuv2-return-38003 branch from 8810591 to 6052034 Compare March 17, 2026 02:11
@Muzry
Copy link
Copy Markdown
Contributor Author

Muzry commented Mar 17, 2026

@Arkenan Thanks. I’ve updated the branch and re-signed the commits with my SSH signing key. The commits are now verified on GitHub. Please take another look when you have a moment.

@iovoid iovoid added this pull request to the merge queue Mar 17, 2026
Merged via the queue into lambdaclass:main with commit 674c520 Mar 17, 2026
48 checks passed
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.

4 participants