internal/ethapi: return invalid params for undecodable raw transactions

eth_sendRawTransaction and eth_sendRawTransactionSync returned the
tx.UnmarshalBinary decode error as a plain error, which surfaces to clients
as -32000. An input that fails to decode into a transaction is an invalid
parameter, so wrap it as invalidParamsError (-32602), consistent with
EIP-1474 and with the other parameter-decode errors in this package
(decodeStorageKey, empty request).
This commit is contained in:
stavrosvl7 2026-07-01 20:55:27 +03:00
parent 00a773dad7
commit 5713e8008a
No known key found for this signature in database
GPG key ID: 3EED9D1D7A71F38F
2 changed files with 28 additions and 2 deletions

View file

@ -1738,7 +1738,7 @@ func (api *TransactionAPI) currentBlobSidecarVersion() byte {
func (api *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { func (api *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) {
tx := new(types.Transaction) tx := new(types.Transaction)
if err := tx.UnmarshalBinary(input); err != nil { if err := tx.UnmarshalBinary(input); err != nil {
return common.Hash{}, err return common.Hash{}, &invalidParamsError{message: err.Error()}
} }
// Convert legacy blob transaction proofs. // Convert legacy blob transaction proofs.
@ -1761,7 +1761,7 @@ func (api *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil
func (api *TransactionAPI) SendRawTransactionSync(ctx context.Context, input hexutil.Bytes, timeoutMs *uint64) (map[string]interface{}, error) { func (api *TransactionAPI) SendRawTransactionSync(ctx context.Context, input hexutil.Bytes, timeoutMs *uint64) (map[string]interface{}, error) {
tx := new(types.Transaction) tx := new(types.Transaction)
if err := tx.UnmarshalBinary(input); err != nil { if err := tx.UnmarshalBinary(input); err != nil {
return nil, err return nil, &invalidParamsError{message: err.Error()}
} }
// Convert legacy blob transaction proofs. // Convert legacy blob transaction proofs.

View file

@ -4132,6 +4132,32 @@ func TestSendRawTransactionSync_Success(t *testing.T) {
} }
} }
func TestSendRawTransaction_InvalidInputReturnsInvalidParams(t *testing.T) {
t.Parallel()
genesis := &core.Genesis{
Config: params.TestChainConfig,
Alloc: types.GenesisAlloc{},
}
b := newTestBackend(t, 0, genesis, ethash.NewFaker(), nil)
api := NewTransactionAPI(b, new(AddrLocker))
// Inputs that fail to decode into a transaction are invalid parameters and
// must surface as -32602, not the generic -32000.
for _, input := range []hexutil.Bytes{{}, {0x02}} {
_, err := api.SendRawTransaction(context.Background(), input)
if err == nil {
t.Fatalf("input %#x: expected error, got nil", []byte(input))
}
var de interface{ ErrorCode() int }
if !errors.As(err, &de) {
t.Fatalf("input %#x: expected coded error, got %T %v", []byte(input), err, err)
}
if de.ErrorCode() != errCodeInvalidParams {
t.Fatalf("input %#x: expected code %d, got %d", []byte(input), errCodeInvalidParams, de.ErrorCode())
}
}
}
func TestSendRawTransactionSync_Timeout(t *testing.T) { func TestSendRawTransactionSync_Timeout(t *testing.T) {
t.Parallel() t.Parallel()