@@ -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.
3547type 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.
6789func (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.
78100func (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().
94135func (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.
126180type blobTxWithBlobs interface {
@@ -148,7 +202,7 @@ func (btx *blobTxWithBlobsV0) tx() *BlobTx {
148202}
149203
150204func (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
162216func (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 ,
0 commit comments