core/types: reject blob tx sidecar in JSON

Reject blob sidecar fields during transaction JSON unmarshalling because this decoder is not meant to import blob payloads.
This commit is contained in:
weixie.cui 2026-05-17 23:18:29 +08:00 committed by Weixie Cui
parent 08aaa7c5ff
commit 40929f96e5
2 changed files with 68 additions and 0 deletions

View file

@ -58,6 +58,28 @@ type txJSON struct {
Hash common.Hash `json:"hash"`
}
var errBlobTxSidecarInJSON = errors.New("blob transaction sidecar fields are not supported in JSON")
func (tx *txJSON) UnmarshalJSON(input []byte) error {
type txJSONNoMethod txJSON
dec := struct {
*txJSONNoMethod
Version json.RawMessage `json:"version,omitempty"`
Blobs json.RawMessage `json:"blobs,omitempty"`
Commitments json.RawMessage `json:"commitments,omitempty"`
Proofs json.RawMessage `json:"proofs,omitempty"`
}{
txJSONNoMethod: (*txJSONNoMethod)(tx),
}
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Version != nil || dec.Blobs != nil || dec.Commitments != nil || dec.Proofs != nil {
return errBlobTxSidecarInJSON
}
return nil
}
// yParityValue returns the YParity value from JSON. For backwards-compatibility reasons,
// this can be given in the 'v' field or the 'yParity' field. If both exist, they must match.
func (tx *txJSON) yParityValue() (*big.Int, error) {

View file

@ -18,6 +18,7 @@ package types
import (
"crypto/ecdsa"
"encoding/json"
"testing"
"github.com/ethereum/go-ethereum/common"
@ -74,6 +75,51 @@ func TestBlobTxSize(t *testing.T) {
}
}
func TestBlobTxJSONRejectsSidecar(t *testing.T) {
key, _ := crypto.GenerateKey()
withBlobs := createEmptyBlobTx(key, true)
withBlobsJSON, err := withBlobs.MarshalJSON()
if err != nil {
t.Fatal(err)
}
var decoded Transaction
if err := decoded.UnmarshalJSON(withBlobsJSON); err != errBlobTxSidecarInJSON {
t.Fatalf("wrong error: got %v, want %v", err, errBlobTxSidecarInJSON)
}
withoutBlobsJSON, err := withBlobs.WithoutBlobTxSidecar().MarshalJSON()
if err != nil {
t.Fatal(err)
}
if err := decoded.UnmarshalJSON(withoutBlobsJSON); err != nil {
t.Fatalf("failed to unmarshal tx without sidecar: %v", err)
}
var blobtx map[string]any
if err := json.Unmarshal(withoutBlobsJSON, &blobtx); err != nil {
t.Fatal(err)
}
for _, tc := range []struct {
field string
value any
}{
{field: "version", value: "0x0"},
{field: "blobs", value: []any{}},
{field: "commitments", value: []any{}},
{field: "proofs", value: []any{}},
} {
blobtx[tc.field] = tc.value
payload, err := json.Marshal(blobtx)
if err != nil {
t.Fatal(err)
}
if err := decoded.UnmarshalJSON(payload); err != errBlobTxSidecarInJSON {
t.Fatalf("field %q: wrong error: got %v, want %v", tc.field, err, errBlobTxSidecarInJSON)
}
delete(blobtx, tc.field)
}
}
var (
emptyBlob = new(kzg4844.Blob)
emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob)