Skip to content

Commit 0dacfef

Browse files
authored
all: define constructor for BlobSidecar (#32213)
The main purpose of this change is to enforce the version setting when constructing the blobSidecar, avoiding creating sidecar with wrong/default version tag.
1 parent a487729 commit 0dacfef

File tree

16 files changed

+97
-122
lines changed

16 files changed

+97
-122
lines changed

beacon/engine/types_test.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,13 @@ func TestBlobs(t *testing.T) {
3434
header := types.Header{}
3535
block := types.NewBlock(&header, &types.Body{}, nil, nil)
3636

37-
sidecarWithoutCellProofs := &types.BlobTxSidecar{
38-
Blobs: []kzg4844.Blob{*emptyBlob},
39-
Commitments: []kzg4844.Commitment{emptyBlobCommit},
40-
Proofs: []kzg4844.Proof{emptyBlobProof},
41-
}
37+
sidecarWithoutCellProofs := types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof})
4238
env := BlockToExecutableData(block, common.Big0, []*types.BlobTxSidecar{sidecarWithoutCellProofs}, nil)
4339
if len(env.BlobsBundle.Proofs) != 1 {
4440
t.Fatalf("Expect 1 proof in blobs bundle, got %v", len(env.BlobsBundle.Proofs))
4541
}
4642

47-
sidecarWithCellProofs := &types.BlobTxSidecar{
48-
Blobs: []kzg4844.Blob{*emptyBlob},
49-
Commitments: []kzg4844.Commitment{emptyBlobCommit},
50-
Proofs: emptyCellProof,
51-
}
43+
sidecarWithCellProofs := types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, emptyCellProof)
5244
env = BlockToExecutableData(block, common.Big0, []*types.BlobTxSidecar{sidecarWithCellProofs}, nil)
5345
if len(env.BlobsBundle.Proofs) != 128 {
5446
t.Fatalf("Expect 128 proofs in blobs bundle, got %v", len(env.BlobsBundle.Proofs))

cmd/devp2p/internal/ethtest/suite.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -879,11 +879,7 @@ func makeSidecar(data ...byte) *types.BlobTxSidecar {
879879
commitments = append(commitments, c)
880880
proofs = append(proofs, p)
881881
}
882-
return &types.BlobTxSidecar{
883-
Blobs: blobs,
884-
Commitments: commitments,
885-
Proofs: proofs,
886-
}
882+
return types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs)
887883
}
888884

889885
func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Transactions) {
@@ -988,14 +984,10 @@ func (s *Suite) TestBlobViolations(t *utesting.T) {
988984
// data has been modified to produce a different commitment hash.
989985
func mangleSidecar(tx *types.Transaction) *types.Transaction {
990986
sidecar := tx.BlobTxSidecar()
991-
copy := types.BlobTxSidecar{
992-
Blobs: append([]kzg4844.Blob{}, sidecar.Blobs...),
993-
Commitments: append([]kzg4844.Commitment{}, sidecar.Commitments...),
994-
Proofs: append([]kzg4844.Proof{}, sidecar.Proofs...),
995-
}
987+
cpy := sidecar.Copy()
996988
// zero the first commitment to alter the sidecar hash
997-
copy.Commitments[0] = kzg4844.Commitment{}
998-
return tx.WithBlobTxSidecar(&copy)
989+
cpy.Commitments[0] = kzg4844.Commitment{}
990+
return tx.WithBlobTxSidecar(cpy)
999991
}
1000992

1001993
func (s *Suite) TestBlobTxWithoutSidecar(t *utesting.T) {

core/txpool/blobpool/blobpool_test.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,7 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa
238238
BlobFeeCap: uint256.NewInt(blobFeeCap),
239239
BlobHashes: blobHashes,
240240
Value: uint256.NewInt(100),
241-
Sidecar: &types.BlobTxSidecar{
242-
Blobs: blobs,
243-
Commitments: commitments,
244-
Proofs: proofs,
245-
},
241+
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs),
246242
}
247243
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
248244
}
@@ -265,11 +261,7 @@ func makeUnsignedTxWithTestBlob(nonce uint64, gasTipCap uint64, gasFeeCap uint64
265261
BlobFeeCap: uint256.NewInt(blobFeeCap),
266262
BlobHashes: []common.Hash{testBlobVHashes[blobIdx]},
267263
Value: uint256.NewInt(100),
268-
Sidecar: &types.BlobTxSidecar{
269-
Blobs: []kzg4844.Blob{*testBlobs[blobIdx]},
270-
Commitments: []kzg4844.Commitment{testBlobCommits[blobIdx]},
271-
Proofs: []kzg4844.Proof{testBlobProofs[blobIdx]},
272-
},
264+
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*testBlobs[blobIdx]}, []kzg4844.Commitment{testBlobCommits[blobIdx]}, []kzg4844.Proof{testBlobProofs[blobIdx]}),
273265
}
274266
}
275267

core/txpool/validation.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ func validateBlobTx(tx *types.Transaction, head *types.Header, opts *ValidationO
185185
}
186186

187187
func validateBlobSidecarLegacy(sidecar *types.BlobTxSidecar, hashes []common.Hash) error {
188-
if sidecar.Version != 0 {
188+
if sidecar.Version != types.BlobSidecarVersion0 {
189189
return fmt.Errorf("invalid sidecar version pre-osaka: %v", sidecar.Version)
190190
}
191191
if len(sidecar.Proofs) != len(hashes) {
@@ -200,7 +200,7 @@ func validateBlobSidecarLegacy(sidecar *types.BlobTxSidecar, hashes []common.Has
200200
}
201201

202202
func validateBlobSidecarOsaka(sidecar *types.BlobTxSidecar, hashes []common.Hash) error {
203-
if sidecar.Version != 1 {
203+
if sidecar.Version != types.BlobSidecarVersion1 {
204204
return fmt.Errorf("invalid sidecar version post-osaka: %v", sidecar.Version)
205205
}
206206
if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob {

core/types/tx_blob.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ import (
3131
"github.com/holiman/uint256"
3232
)
3333

34+
const (
35+
// BlobSidecarVersion0 includes a single proof for verifying the entire blob
36+
// against its commitment. Used when the full blob is available and needs to
37+
// be checked as a whole.
38+
BlobSidecarVersion0 = byte(0)
39+
40+
// BlobSidecarVersion1 includes multiple cell proofs for verifying specific
41+
// blob elements (cells). Used in scenarios like data availability sampling,
42+
// where only portions of the blob are verified individually.
43+
BlobSidecarVersion1 = byte(1)
44+
)
45+
3446
// BlobTx represents an EIP-4844 transaction.
3547
type BlobTx struct {
3648
ChainID *uint256.Int
@@ -63,6 +75,16 @@ type BlobTxSidecar struct {
6375
Proofs []kzg4844.Proof // Proofs needed by the blob pool
6476
}
6577

78+
// NewBlobTxSidecar initialises the BlobTxSidecar object with the provided parameters.
79+
func NewBlobTxSidecar(version byte, blobs []kzg4844.Blob, commitments []kzg4844.Commitment, proofs []kzg4844.Proof) *BlobTxSidecar {
80+
return &BlobTxSidecar{
81+
Version: version,
82+
Blobs: blobs,
83+
Commitments: commitments,
84+
Proofs: proofs,
85+
}
86+
}
87+
6688
// BlobHashes computes the blob hashes of the given blobs.
6789
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
6890
hasher := sha256.New()
@@ -76,7 +98,7 @@ func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
7698
// CellProofsAt returns the cell proofs for blob with index idx.
7799
// This method is only valid for sidecars with version 1.
78100
func (sc *BlobTxSidecar) CellProofsAt(idx int) ([]kzg4844.Proof, error) {
79-
if sc.Version != 1 {
101+
if sc.Version != BlobSidecarVersion1 {
80102
return nil, fmt.Errorf("cell proof unsupported, version: %d", sc.Version)
81103
}
82104
if idx < 0 || idx >= len(sc.Blobs) {
@@ -89,6 +111,25 @@ func (sc *BlobTxSidecar) CellProofsAt(idx int) ([]kzg4844.Proof, error) {
89111
return sc.Proofs[index : index+kzg4844.CellProofsPerBlob], nil
90112
}
91113

114+
// ToV1 converts the BlobSidecar to version 1, attaching the cell proofs.
115+
func (sc *BlobTxSidecar) ToV1() error {
116+
if sc.Version == BlobSidecarVersion1 {
117+
return nil
118+
}
119+
if sc.Version == BlobSidecarVersion0 {
120+
sc.Proofs = make([]kzg4844.Proof, 0, len(sc.Blobs)*kzg4844.CellProofsPerBlob)
121+
for _, blob := range sc.Blobs {
122+
cellProofs, err := kzg4844.ComputeCellProofs(&blob)
123+
if err != nil {
124+
return err
125+
}
126+
sc.Proofs = append(sc.Proofs, cellProofs...)
127+
}
128+
sc.Version = BlobSidecarVersion1
129+
}
130+
return nil
131+
}
132+
92133
// encodedSize computes the RLP size of the sidecar elements. This does NOT return the
93134
// encoded size of the BlobTxSidecar, it's just a helper for tx.Size().
94135
func (sc *BlobTxSidecar) encodedSize() uint64 {
@@ -121,6 +162,19 @@ func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) erro
121162
return nil
122163
}
123164

165+
// Copy returns a deep-copied BlobTxSidecar object.
166+
func (sc *BlobTxSidecar) Copy() *BlobTxSidecar {
167+
return &BlobTxSidecar{
168+
Version: sc.Version,
169+
170+
// The element of these slice is fix-size byte array,
171+
// therefore slices.Clone will actually deep copy by value.
172+
Blobs: slices.Clone(sc.Blobs),
173+
Commitments: slices.Clone(sc.Commitments),
174+
Proofs: slices.Clone(sc.Proofs),
175+
}
176+
}
177+
124178
// blobTxWithBlobs represents blob tx with its corresponding sidecar.
125179
// This is an interface because sidecars are versioned.
126180
type blobTxWithBlobs interface {
@@ -148,7 +202,7 @@ func (btx *blobTxWithBlobsV0) tx() *BlobTx {
148202
}
149203

150204
func (btx *blobTxWithBlobsV0) assign(sc *BlobTxSidecar) error {
151-
sc.Version = 0
205+
sc.Version = BlobSidecarVersion0
152206
sc.Blobs = btx.Blobs
153207
sc.Commitments = btx.Commitments
154208
sc.Proofs = btx.Proofs
@@ -160,10 +214,10 @@ func (btx *blobTxWithBlobsV1) tx() *BlobTx {
160214
}
161215

162216
func (btx *blobTxWithBlobsV1) assign(sc *BlobTxSidecar) error {
163-
if btx.Version != 1 {
217+
if btx.Version != BlobSidecarVersion1 {
164218
return fmt.Errorf("unsupported blob tx version %d", btx.Version)
165219
}
166-
sc.Version = 1
220+
sc.Version = BlobSidecarVersion1
167221
sc.Blobs = btx.Blobs
168222
sc.Commitments = btx.Commitments
169223
sc.Proofs = btx.Proofs
@@ -217,12 +271,7 @@ func (tx *BlobTx) copy() TxData {
217271
cpy.S.Set(tx.S)
218272
}
219273
if tx.Sidecar != nil {
220-
cpy.Sidecar = &BlobTxSidecar{
221-
Version: tx.Sidecar.Version,
222-
Blobs: slices.Clone(tx.Sidecar.Blobs),
223-
Commitments: slices.Clone(tx.Sidecar.Commitments),
224-
Proofs: slices.Clone(tx.Sidecar.Proofs),
225-
}
274+
cpy.Sidecar = tx.Sidecar.Copy()
226275
}
227276
return cpy
228277
}
@@ -280,15 +329,15 @@ func (tx *BlobTx) encode(b *bytes.Buffer) error {
280329
case tx.Sidecar == nil:
281330
return rlp.Encode(b, tx)
282331

283-
case tx.Sidecar.Version == 0:
332+
case tx.Sidecar.Version == BlobSidecarVersion0:
284333
return rlp.Encode(b, &blobTxWithBlobsV0{
285334
BlobTx: tx,
286335
Blobs: tx.Sidecar.Blobs,
287336
Commitments: tx.Sidecar.Commitments,
288337
Proofs: tx.Sidecar.Proofs,
289338
})
290339

291-
case tx.Sidecar.Version == 1:
340+
case tx.Sidecar.Version == BlobSidecarVersion1:
292341
return rlp.Encode(b, &blobTxWithBlobsV1{
293342
BlobTx: tx,
294343
Version: tx.Sidecar.Version,

core/types/tx_blob_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,7 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
8787
}
8888

8989
func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
90-
sidecar := &BlobTxSidecar{
91-
Blobs: []kzg4844.Blob{*emptyBlob},
92-
Commitments: []kzg4844.Commitment{emptyBlobCommit},
93-
Proofs: []kzg4844.Proof{emptyBlobProof},
94-
}
90+
sidecar := NewBlobTxSidecar(BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof})
9591
blobtx := &BlobTx{
9692
ChainID: uint256.NewInt(1),
9793
Nonce: 5,

eth/catalyst/api.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,10 +527,10 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
527527
if len(hashes) > 128 {
528528
return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes)))
529529
}
530-
531530
available := api.eth.BlobTxPool().AvailableBlobs(hashes)
532531
getBlobsRequestedCounter.Inc(int64(len(hashes)))
533532
getBlobsAvailableCounter.Inc(int64(available))
533+
534534
// Optimization: check first if all blobs are available, if not, return empty response
535535
if available != len(hashes) {
536536
getBlobsV2RequestMiss.Inc(1)
@@ -557,7 +557,7 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
557557
// not found, return empty response
558558
return nil, nil
559559
}
560-
if sidecar.Version != 1 {
560+
if sidecar.Version != types.BlobSidecarVersion1 {
561561
log.Info("GetBlobs queried V0 transaction: index %v, blobhashes %v", index, sidecar.BlobHashes())
562562
return nil, nil
563563
}
@@ -566,9 +566,7 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
566566
if idxes, ok := index[hash]; ok {
567567
proofs, err := sidecar.CellProofsAt(bIdx)
568568
if err != nil {
569-
// TODO @rjl @marius we should return an error
570-
log.Info("Failed to get cell proof", "err", err)
571-
return nil, nil
569+
return nil, engine.InvalidParams.With(err)
572570
}
573571
var cellProofs []hexutil.Bytes
574572
for _, proof := range proofs {

eth/catalyst/api_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,13 +1511,8 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
15111511
}
15121512

15131513
txs = append(txs, types.NewTx(&inner))
1514-
sidecars := []*types.BlobTxSidecar{
1515-
{
1516-
Blobs: make([]kzg4844.Blob, 1),
1517-
Commitments: make([]kzg4844.Commitment, 1),
1518-
Proofs: make([]kzg4844.Proof, 1),
1519-
},
1520-
}
1514+
sidecar := types.NewBlobTxSidecar(types.BlobSidecarVersion0, make([]kzg4844.Blob, 1), make([]kzg4844.Commitment, 1), make([]kzg4844.Proof, 1))
1515+
sidecars := []*types.BlobTxSidecar{sidecar}
15211516

15221517
block := types.NewBlock(&header, &types.Body{Transactions: txs}, nil, trie.NewStackTrie(nil))
15231518
envelope := engine.BlockToExecutableData(block, nil, sidecars, nil)

eth/protocols/eth/handler_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -661,11 +661,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) {
661661
To: testAddr,
662662
BlobHashes: []common.Hash{emptyBlobHash},
663663
BlobFeeCap: uint256.MustFromBig(common.Big1),
664-
Sidecar: &types.BlobTxSidecar{
665-
Blobs: emptyBlobs,
666-
Commitments: []kzg4844.Commitment{emptyBlobCommit},
667-
Proofs: []kzg4844.Proof{emptyBlobProof},
668-
},
664+
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}),
669665
})
670666
if err != nil {
671667
t.Fatal(err)

ethclient/simulated/backend_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,7 @@ func newBlobTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error)
8383
To: addr,
8484
AccessList: nil,
8585
BlobHashes: []common.Hash{testBlobVHash},
86-
Sidecar: &types.BlobTxSidecar{
87-
Blobs: []kzg4844.Blob{*testBlob},
88-
Commitments: []kzg4844.Commitment{testBlobCommit},
89-
Proofs: []kzg4844.Proof{testBlobProof},
90-
},
86+
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*testBlob}, []kzg4844.Commitment{testBlobCommit}, []kzg4844.Proof{testBlobProof}),
9187
})
9288
return types.SignTx(tx, types.LatestSignerForChainID(chainid), key)
9389
}

0 commit comments

Comments
 (0)