Skip to content

rpc/jsonrpc: return InvalidParams for malformed sendRawTransaction RLP - #21701

Open
manusw7 wants to merge 9 commits into
erigontech:mainfrom
manusw7:manusw7/sendrawtransaction-invalid-params
Open

rpc/jsonrpc: return InvalidParams for malformed sendRawTransaction RLP#21701
manusw7 wants to merge 9 commits into
erigontech:mainfrom
manusw7:manusw7/sendrawtransaction-invalid-params

Conversation

@manusw7

@manusw7 manusw7 commented Jun 9, 2026

Copy link
Copy Markdown

Summary

SendRawTransaction returns the bare DecodeWrappedTransaction error (rpc/jsonrpc/send_transaction.go:25). Since decode errors don't implement ErrorCode(), the dispatcher (forked from go-ethereum) falls back to errcodeDefault = -32000. Per JSON-RPC 2.0, malformed params should be -32602.

This wires the existing rpc.InvalidParamsError wrapper into the decode path. SendRawTransactionSync delegates to SendRawTransaction (send_transaction.go:97), so the fix applies transitively.

Changes

--- a/rpc/jsonrpc/send_transaction.go
@@ func (api *APIImpl) SendRawTransaction(...)
        txn, err := types.DecodeWrappedTransaction(encodedTx)
        if err != nil {
-               return common.Hash{}, err
+               return common.Hash{}, &rpc.InvalidParamsError{Message: err.Error()}
        }

rpc is already imported; message passes through unchanged.

Why -32602

The -32000 today is a fallback accident, not a deliberate choice. This matches where the spec is heading: execution-apis#817 (fjl: input-validation conditions on submit methods are just "invalid parameters") and #818 (drops the -32000 "Invalid input" group from eth_sendRawTransaction). Reth and Besu already return -32602 for RLP-decode failures; Erigon and geth default to -32000.

Test plan

Added TestSendRawTransaction_InvalidParams_OnMalformedRLP (rpc/jsonrpc/send_transaction_test.go): 5 decode-failure shapes (0xc0, 0xd4, 0x09c0, 0x03c0, 0x04c0), asserting ErrorCode() == -32602 via errors.As. SendRawTransactionSync covered transitively. All pass; make lint clean.

Out of scope

  • Decoder message wording — unchanged.
  • Non-decode paths (checkTxFee, AllowUnprotectedTxs, chainConfig, txpool Add): not param validation — -32000 stays.

Related

SendRawTransaction currently returns the bare DecodeWrappedTransaction
error to the JSON-RPC layer. Because the underlying decode errors don't
implement rpc.Error.ErrorCode(), the dispatcher falls back to
errcodeDefault = -32000. Per JSON-RPC 2.0, malformed method parameters
should use -32602 (InvalidParams), which is what Reth and Besu emit for
the same input.

Erigon already exports rpc.InvalidParamsError with ErrorCode() = -32602.
Wire it into the decode path and add a parameterised test covering 5
distinct RLP-decode failure shapes. SendRawTransactionSync delegates to
SendRawTransaction (rpc/jsonrpc/send_transaction.go:97) so the fix
propagates transitively.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Aligns eth_sendRawTransaction JSON-RPC error codes with JSON-RPC 2.0 by returning -32602 (InvalidParams) when the submitted raw transaction cannot be RLP-decoded, instead of falling back to the default -32000.

Changes:

  • Wrap types.DecodeWrappedTransaction decode failures in rpc.InvalidParamsError in SendRawTransaction.
  • Add a regression test covering multiple malformed-RLP inputs and asserting the returned RPC error code is -32602.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
rpc/jsonrpc/send_transaction.go Wraps raw-tx decode failures with rpc.InvalidParamsError so the dispatcher emits -32602.
rpc/jsonrpc/send_transaction_test.go Adds a test suite validating malformed RLP inputs map to InvalidParams error code.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rpc/jsonrpc/send_transaction_test.go Outdated

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The mainnet-rpc-integ-tests failure on this PR is structural, not flaky: the erigontech/rpc-tests fixtures integration/mainnet/eth_sendRawTransaction/test_01..03.json (and integration/arb-sepolia/eth_sendRawTransaction/test_01.json) hardcode "code": -32000 — test_02/test_03 use the same 0xd4 vector as the new unit test. Hence the 9 "diff mismatch" failures (3 fixtures × http/http_comp/websocket).

Required to land:

  • A companion rpc-tests PR updating the expected codes to -32602 (messages unchanged), then a new rpc-tests tag and an RPC_VERSION bump in .github/workflows/scripts/rpc_version.env (currently v2.13.0) in this PR, so both land together.
  • A decision on the daily geth/nethermind comparison runs (qa-rpc-integration-tests-clients.yml), which use the same fixtures: geth still returns -32000 on the wire (ethereum/go-ethereum#35129 is unmerged), so updating the shared fixtures turns those runs red until upstream catches up.

Nits:

  • send_transaction_test.go: the github.com/erigontech/erigon/rpc import is inserted out of alphabetical order (between execution/tests/blockgen and execution/types).
  • require := require.New(t) is bound to the parent test but used inside t.Run subtests, so a failing assertion calls FailNow on the parent's t from the subtest goroutine. Bind assertions to the subtest's t instead.

Comment thread rpc/jsonrpc/send_transaction.go Outdated
@yperbasis yperbasis modified the milestones: 3.6.0, 3.7.0, 3.8.0 Jun 16, 2026
@yperbasis yperbasis modified the milestones: 3.8.0, 3.7.0 Jul 2, 2026

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants