Skip to content

Commit d49f0be

Browse files
committed
Flexible BlobTx JSON codec
This patch removes the requirement of Blob transactions JSON (un)marshaling to contain data. JSON-encoded blob txs returned by JSON-RPC needs this in order to serve transactions from the block body. Otherwise, the marshaling fails as we only persist the minimal representation of transactions in block bodies. We do not use JSON internally for tx message passing. This only affects JSON-RPC and external APIs.
1 parent c09fdfa commit d49f0be

File tree

4 files changed

+64
-24
lines changed

4 files changed

+64
-24
lines changed

core/types/transaction_marshalling.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,11 @@ func (t *Transaction) MarshalJSON() ([]byte, error) {
118118
enc.R = (*hexutil.Big)(r)
119119
enc.S = (*hexutil.Big)(s)
120120
enc.BlobVersionedHashes = tx.Message.BlobVersionedHashes
121-
if t.wrapData == nil {
122-
return nil, fmt.Errorf("expected wrap-data for blob tx")
121+
if t.wrapData != nil {
122+
enc.Blobs = t.wrapData.blobs()
123+
enc.BlobKzgs = t.wrapData.kzgs()
124+
enc.KzgAggregatedProof = t.wrapData.aggregatedProof()
123125
}
124-
enc.Blobs = t.wrapData.blobs()
125-
enc.BlobKzgs = t.wrapData.kzgs()
126-
enc.KzgAggregatedProof = t.wrapData.aggregatedProof()
127126
}
128127
return json.Marshal(&enc)
129128
}
@@ -349,14 +348,17 @@ func (t *Transaction) UnmarshalJSON(input []byte) error {
349348
}
350349
}
351350
itx.Message.BlobVersionedHashes = dec.BlobVersionedHashes
352-
t.wrapData = &BlobTxWrapData{
353-
BlobKzgs: dec.BlobKzgs,
354-
Blobs: dec.Blobs,
355-
KzgAggregatedProof: dec.KzgAggregatedProof,
356-
}
357-
// Verify that versioned hashes match kzgs, and kzgs match blobs.
358-
if err := t.wrapData.verifyBlobs(&itx); err != nil {
359-
return fmt.Errorf("blob wrapping data is invalid: %v", err)
351+
// A BlobTx may not contain data
352+
if len(dec.Blobs) != 0 || len(dec.BlobKzgs) != 0 {
353+
t.wrapData = &BlobTxWrapData{
354+
BlobKzgs: dec.BlobKzgs,
355+
Blobs: dec.Blobs,
356+
KzgAggregatedProof: dec.KzgAggregatedProof,
357+
}
358+
// Verify that versioned hashes match kzgs, and kzgs match blobs.
359+
if err := t.wrapData.verifyBlobs(&itx); err != nil {
360+
return fmt.Errorf("blob wrapping data is invalid: %v", err)
361+
}
360362
}
361363
default:
362364
return ErrTxTypeNotSupported

core/types/transaction_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"time"
2929

3030
"github.com/holiman/uint256"
31+
"github.com/protolambda/go-kzg/bls"
3132
"github.com/protolambda/ztyp/view"
3233

3334
"github.com/ethereum/go-ethereum/common"
@@ -491,10 +492,12 @@ func TestTransactionCoding(t *testing.T) {
491492
BlobVersionedHashes: VersionedHashesView{common.HexToHash("0x01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e")},
492493
},
493494
}
495+
var kzgProof KZGProof
496+
copy(kzgProof[:], bls.ToCompressedG1((*bls.G1Point)(&bls.ZeroG1)))
494497
wrapData = &BlobTxWrapData{
495498
BlobKzgs: BlobKzgs{KZGCommitment{0: 0xc0}},
496499
Blobs: Blobs{Blob{}},
497-
KzgAggregatedProof: KZGProof{0: 0xd0},
500+
KzgAggregatedProof: kzgProof,
498501
}
499502
}
500503
tx, err := SignNewTx(key, signer, txdata, WithTxWrapData(wrapData))
@@ -521,6 +524,41 @@ func TestTransactionCoding(t *testing.T) {
521524
}
522525
}
523526

527+
func TestBlobTransactionMinimalCodec(t *testing.T) {
528+
key, err := crypto.GenerateKey()
529+
if err != nil {
530+
t.Fatalf("could not generate key: %v", err)
531+
}
532+
var (
533+
signer = NewDankSigner(common.Big1)
534+
addr = common.HexToAddress("0x0000000000000000000000000000000000000001")
535+
accesses = AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}}
536+
)
537+
538+
txdata := &SignedBlobTx{
539+
Message: BlobTxMessage{
540+
ChainID: view.Uint256View(*uint256.NewInt(1)),
541+
Nonce: view.Uint64View(1),
542+
Gas: view.Uint64View(123457),
543+
GasTipCap: view.Uint256View(*uint256.NewInt(42)),
544+
GasFeeCap: view.Uint256View(*uint256.NewInt(10)),
545+
AccessList: AccessListView(accesses),
546+
BlobVersionedHashes: VersionedHashesView{common.HexToHash("0x01624652859a6e98ffc1608e2af0147ca4e86e1ce27672d8d3f3c9d4ffd6ef7e")},
547+
},
548+
}
549+
tx, err := SignNewTx(key, signer, txdata)
550+
if err != nil {
551+
t.Fatalf("could not sign transaction: %v", err)
552+
}
553+
parsedTx, err := encodeDecodeJSON(tx)
554+
if err != nil {
555+
t.Fatal(err)
556+
}
557+
if err := assertEqual(parsedTx, tx); err != nil {
558+
t.Fatal(err)
559+
}
560+
}
561+
524562
func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
525563
data, err := json.Marshal(tx)
526564
if err != nil {

core/types/types_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ func benchRLP(b *testing.B, encode bool) {
7575
{
7676
"protodanksharding-header",
7777
&Header{
78-
Difficulty: big.NewInt(10000000000),
79-
Number: big.NewInt(1000),
80-
GasLimit: 8_000_000,
81-
GasUsed: 8_000_000,
82-
Time: 555,
83-
Extra: make([]byte, 32),
84-
BaseFee: big.NewInt(10000000000),
85-
Blobs: 2,
78+
Difficulty: big.NewInt(10000000000),
79+
Number: big.NewInt(1000),
80+
GasLimit: 8_000_000,
81+
GasUsed: 8_000_000,
82+
Time: 555,
83+
Extra: make([]byte, 32),
84+
BaseFee: big.NewInt(10000000000),
85+
ExcessBlobs: 2,
8686
},
8787
},
8888
{

internal/ethapi/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
11781178
"timestamp": hexutil.Uint64(head.Time),
11791179
"transactionsRoot": head.TxHash,
11801180
"receiptsRoot": head.ReceiptHash,
1181-
"excessBlobs": head.ExcessBlobs,
1181+
"excessBlobs": hexutil.Uint64(head.ExcessBlobs),
11821182
}
11831183

11841184
if head.BaseFee != nil {
@@ -1305,7 +1305,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
13051305
al := tx.AccessList()
13061306
result.Accesses = &al
13071307
result.ChainID = (*hexutil.Big)(tx.ChainId())
1308-
case types.DynamicFeeTxType:
1308+
case types.DynamicFeeTxType, types.BlobTxType:
13091309
al := tx.AccessList()
13101310
result.Accesses = &al
13111311
result.ChainID = (*hexutil.Big)(tx.ChainId())

0 commit comments

Comments
 (0)