From 131b62917b4e757359cb860de89dd6d23c7b5173 Mon Sep 17 00:00:00 2001 From: ManuelArto Date: Mon, 8 Jun 2026 19:50:23 +0200 Subject: [PATCH 1/4] rpc/jsonrpc: return InvalidParams for malformed sendRawTransaction RLP 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. --- rpc/jsonrpc/send_transaction.go | 2 +- rpc/jsonrpc/send_transaction_test.go | 31 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/rpc/jsonrpc/send_transaction.go b/rpc/jsonrpc/send_transaction.go index fa8c6b74257..bfd55331f37 100644 --- a/rpc/jsonrpc/send_transaction.go +++ b/rpc/jsonrpc/send_transaction.go @@ -21,7 +21,7 @@ import ( func (api *APIImpl) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { txn, err := types.DecodeWrappedTransaction(encodedTx) if err != nil { - return common.Hash{}, err + return common.Hash{}, &rpc.InvalidParamsError{Message: err.Error()} } // If the transaction fee cap is already specified, ensure the diff --git a/rpc/jsonrpc/send_transaction_test.go b/rpc/jsonrpc/send_transaction_test.go index 140798b3a1b..07b79dc1d20 100644 --- a/rpc/jsonrpc/send_transaction_test.go +++ b/rpc/jsonrpc/send_transaction_test.go @@ -18,6 +18,7 @@ package jsonrpc import ( "bytes" + "errors" "testing" "time" @@ -26,6 +27,7 @@ import ( "github.com/erigontech/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/erigontech/erigon/common" + "github.com/erigontech/erigon/common/hexutil" "github.com/erigontech/erigon/execution/execmodule/execmoduletester" "github.com/erigontech/erigon/execution/protocol/params" "github.com/erigontech/erigon/execution/tests/blockgen" @@ -116,3 +118,32 @@ func TestSendRawTransactionUnprotected(t *testing.T) { require.Equal(expectedTxValue, jsonTx.Value.Uint64()) } } + +func TestSendRawTransaction_InvalidParams_OnMalformedRLP(t *testing.T) { + m := execmoduletester.New(t, execmoduletester.WithTxPool()) + require := require.New(t) + ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, m) + txPool := txpoolproto.NewTxpoolClient(conn) + api := newEthApiForTest(newBaseApiForTest(m), m.DB, txPool, nil) + + cases := []struct { + name string + raw string + }{ + {"empty-list", "0xc0"}, + {"truncated-short-list", "0xd4"}, + {"unknown-tx-type", "0x09c0"}, + {"eip4844-truncated-list", "0x03c0"}, + {"eip7702-truncated-list", "0x04c0"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := api.SendRawTransaction(ctx, hexutil.MustDecode(tc.raw)) + require.Error(err) + var ec interface{ ErrorCode() int } + require.True(errors.As(err, &ec), "expected error implementing ErrorCode(), got %T: %v", err, err) + require.Equal(-32602, ec.ErrorCode(), "want InvalidParams (-32602), got %d (%v)", ec.ErrorCode(), err) + }) + } +} From bc3744407f87c6ee57fcb1632de1a6ad9af3552b Mon Sep 17 00:00:00 2001 From: ManuelArto Date: Tue, 9 Jun 2026 17:50:26 +0200 Subject: [PATCH 2/4] rpc/jsonrpc: update TestSendRawTransaction_InvalidParams to use InvalidParamsError --- rpc/jsonrpc/send_transaction_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rpc/jsonrpc/send_transaction_test.go b/rpc/jsonrpc/send_transaction_test.go index 07b79dc1d20..b00b036e5bb 100644 --- a/rpc/jsonrpc/send_transaction_test.go +++ b/rpc/jsonrpc/send_transaction_test.go @@ -31,6 +31,7 @@ import ( "github.com/erigontech/erigon/execution/execmodule/execmoduletester" "github.com/erigontech/erigon/execution/protocol/params" "github.com/erigontech/erigon/execution/tests/blockgen" + "github.com/erigontech/erigon/rpc" "github.com/erigontech/erigon/execution/types" "github.com/erigontech/erigon/node/gointerfaces/txpoolproto" "github.com/erigontech/erigon/rpc/rpchelper" @@ -141,9 +142,9 @@ func TestSendRawTransaction_InvalidParams_OnMalformedRLP(t *testing.T) { t.Run(tc.name, func(t *testing.T) { _, err := api.SendRawTransaction(ctx, hexutil.MustDecode(tc.raw)) require.Error(err) - var ec interface{ ErrorCode() int } - require.True(errors.As(err, &ec), "expected error implementing ErrorCode(), got %T: %v", err, err) - require.Equal(-32602, ec.ErrorCode(), "want InvalidParams (-32602), got %d (%v)", ec.ErrorCode(), err) + var invalid *rpc.InvalidParamsError + require.True(errors.As(err, &invalid), "expected *rpc.InvalidParamsError, got %T: %v", err, err) + require.Equal(-32602, invalid.ErrorCode(), "want InvalidParams (-32602), got %d (%v)", invalid.ErrorCode(), err) }) } } From 3eb7d2615078c4f80de127d2626c4c1c0d4af0b4 Mon Sep 17 00:00:00 2001 From: ManuelArto Date: Sun, 14 Jun 2026 17:50:07 +0200 Subject: [PATCH 3/4] rpc/jsonrpc: fix import order and bind require to subtest t --- rpc/jsonrpc/send_transaction_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/jsonrpc/send_transaction_test.go b/rpc/jsonrpc/send_transaction_test.go index b00b036e5bb..09f7e206943 100644 --- a/rpc/jsonrpc/send_transaction_test.go +++ b/rpc/jsonrpc/send_transaction_test.go @@ -31,9 +31,9 @@ import ( "github.com/erigontech/erigon/execution/execmodule/execmoduletester" "github.com/erigontech/erigon/execution/protocol/params" "github.com/erigontech/erigon/execution/tests/blockgen" - "github.com/erigontech/erigon/rpc" "github.com/erigontech/erigon/execution/types" "github.com/erigontech/erigon/node/gointerfaces/txpoolproto" + "github.com/erigontech/erigon/rpc" "github.com/erigontech/erigon/rpc/rpchelper" "github.com/erigontech/erigon/txnprovider/txpool/txpoolcfg" ) @@ -122,7 +122,6 @@ func TestSendRawTransactionUnprotected(t *testing.T) { func TestSendRawTransaction_InvalidParams_OnMalformedRLP(t *testing.T) { m := execmoduletester.New(t, execmoduletester.WithTxPool()) - require := require.New(t) ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, m) txPool := txpoolproto.NewTxpoolClient(conn) api := newEthApiForTest(newBaseApiForTest(m), m.DB, txPool, nil) @@ -140,6 +139,7 @@ func TestSendRawTransaction_InvalidParams_OnMalformedRLP(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { + require := require.New(t) _, err := api.SendRawTransaction(ctx, hexutil.MustDecode(tc.raw)) require.Error(err) var invalid *rpc.InvalidParamsError From 4e528c5bcbb13ca34b9524f508d59eed94a7cff5 Mon Sep 17 00:00:00 2001 From: ManuelArto Date: Tue, 16 Jun 2026 16:38:45 +0200 Subject: [PATCH 4/4] rpc/jsonrpc: wrap chainId mismatch in InvalidParamsError --- rpc/jsonrpc/send_transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/jsonrpc/send_transaction.go b/rpc/jsonrpc/send_transaction.go index bfd55331f37..c50ce3ba06a 100644 --- a/rpc/jsonrpc/send_transaction.go +++ b/rpc/jsonrpc/send_transaction.go @@ -52,7 +52,7 @@ func (api *APIImpl) SendRawTransaction(ctx context.Context, encodedTx hexutil.By txnChainId := txn.GetChainID() chainId := cc.ChainID if chainId.Cmp(txnChainId) != 0 { - return common.Hash{}, fmt.Errorf("invalid chain id, expected: %d got: %d", chainId, txnChainId) + return common.Hash{}, &rpc.InvalidParamsError{Message: fmt.Sprintf("invalid chain id, expected: %d got: %d", chainId, txnChainId)} } }