Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions beacon/engine/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,13 @@ func TestBlobs(t *testing.T) {
header := types.Header{}
block := types.NewBlock(&header, &types.Body{}, nil, nil)

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

sidecarWithCellProofs := &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{*emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: emptyCellProof,
}
sidecarWithCellProofs := types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, emptyCellProof)
env = BlockToExecutableData(block, common.Big0, []*types.BlobTxSidecar{sidecarWithCellProofs}, nil)
if len(env.BlobsBundle.Proofs) != 128 {
t.Fatalf("Expect 128 proofs in blobs bundle, got %v", len(env.BlobsBundle.Proofs))
Expand Down
16 changes: 4 additions & 12 deletions cmd/devp2p/internal/ethtest/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,11 +879,7 @@ func makeSidecar(data ...byte) *types.BlobTxSidecar {
commitments = append(commitments, c)
proofs = append(proofs, p)
}
return &types.BlobTxSidecar{
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
}
return types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs)
}

func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Transactions) {
Expand Down Expand Up @@ -988,14 +984,10 @@ func (s *Suite) TestBlobViolations(t *utesting.T) {
// data has been modified to produce a different commitment hash.
func mangleSidecar(tx *types.Transaction) *types.Transaction {
sidecar := tx.BlobTxSidecar()
copy := types.BlobTxSidecar{
Blobs: append([]kzg4844.Blob{}, sidecar.Blobs...),
Commitments: append([]kzg4844.Commitment{}, sidecar.Commitments...),
Proofs: append([]kzg4844.Proof{}, sidecar.Proofs...),
}
cpy := sidecar.Copy()
// zero the first commitment to alter the sidecar hash
copy.Commitments[0] = kzg4844.Commitment{}
return tx.WithBlobTxSidecar(&copy)
cpy.Commitments[0] = kzg4844.Commitment{}
return tx.WithBlobTxSidecar(cpy)
}

func (s *Suite) TestBlobTxWithoutSidecar(t *utesting.T) {
Expand Down
12 changes: 2 additions & 10 deletions core/txpool/blobpool/blobpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,7 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa
BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: blobHashes,
Value: uint256.NewInt(100),
Sidecar: &types.BlobTxSidecar{
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs),
}
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
}
Expand All @@ -265,11 +261,7 @@ func makeUnsignedTxWithTestBlob(nonce uint64, gasTipCap uint64, gasFeeCap uint64
BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: []common.Hash{testBlobVHashes[blobIdx]},
Value: uint256.NewInt(100),
Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{*testBlobs[blobIdx]},
Commitments: []kzg4844.Commitment{testBlobCommits[blobIdx]},
Proofs: []kzg4844.Proof{testBlobProofs[blobIdx]},
},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*testBlobs[blobIdx]}, []kzg4844.Commitment{testBlobCommits[blobIdx]}, []kzg4844.Proof{testBlobProofs[blobIdx]}),
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/txpool/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func validateBlobTx(tx *types.Transaction, head *types.Header, opts *ValidationO
}

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

func validateBlobSidecarOsaka(sidecar *types.BlobTxSidecar, hashes []common.Hash) error {
if sidecar.Version != 1 {
if sidecar.Version != types.BlobSidecarVersion1 {
return fmt.Errorf("invalid sidecar version post-osaka: %v", sidecar.Version)
}
if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob {
Expand Down
73 changes: 61 additions & 12 deletions core/types/tx_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ import (
"github.com/holiman/uint256"
)

const (
// BlobSidecarVersion0 includes a single proof for verifying the entire blob
// against its commitment. Used when the full blob is available and needs to
// be checked as a whole.
BlobSidecarVersion0 = byte(0)

// BlobSidecarVersion1 includes multiple cell proofs for verifying specific
// blob elements (cells). Used in scenarios like data availability sampling,
// where only portions of the blob are verified individually.
BlobSidecarVersion1 = byte(1)
)

// BlobTx represents an EIP-4844 transaction.
type BlobTx struct {
ChainID *uint256.Int
Expand Down Expand Up @@ -63,6 +75,16 @@ type BlobTxSidecar struct {
Proofs []kzg4844.Proof // Proofs needed by the blob pool
}

// NewBlobTxSidecar initialises the BlobTxSidecar object with the provided parameters.
func NewBlobTxSidecar(version byte, blobs []kzg4844.Blob, commitments []kzg4844.Commitment, proofs []kzg4844.Proof) *BlobTxSidecar {
return &BlobTxSidecar{
Version: version,
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
}
}

// BlobHashes computes the blob hashes of the given blobs.
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
hasher := sha256.New()
Expand All @@ -76,7 +98,7 @@ func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
// CellProofsAt returns the cell proofs for blob with index idx.
// This method is only valid for sidecars with version 1.
func (sc *BlobTxSidecar) CellProofsAt(idx int) ([]kzg4844.Proof, error) {
if sc.Version != 1 {
if sc.Version != BlobSidecarVersion1 {
return nil, fmt.Errorf("cell proof unsupported, version: %d", sc.Version)
}
if idx < 0 || idx >= len(sc.Blobs) {
Expand All @@ -89,6 +111,25 @@ func (sc *BlobTxSidecar) CellProofsAt(idx int) ([]kzg4844.Proof, error) {
return sc.Proofs[index : index+kzg4844.CellProofsPerBlob], nil
}

// ToV1 converts the BlobSidecar to version 1, attaching the cell proofs.
func (sc *BlobTxSidecar) ToV1() error {
if sc.Version == BlobSidecarVersion1 {
return nil
}
if sc.Version == BlobSidecarVersion0 {
sc.Proofs = make([]kzg4844.Proof, 0, len(sc.Blobs)*kzg4844.CellProofsPerBlob)
for _, blob := range sc.Blobs {
cellProofs, err := kzg4844.ComputeCellProofs(&blob)
if err != nil {
return err
}
sc.Proofs = append(sc.Proofs, cellProofs...)
}
sc.Version = BlobSidecarVersion1
}
return nil
}

// encodedSize computes the RLP size of the sidecar elements. This does NOT return the
// encoded size of the BlobTxSidecar, it's just a helper for tx.Size().
func (sc *BlobTxSidecar) encodedSize() uint64 {
Expand Down Expand Up @@ -121,6 +162,19 @@ func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) erro
return nil
}

// Copy returns a deep-copied BlobTxSidecar object.
func (sc *BlobTxSidecar) Copy() *BlobTxSidecar {
return &BlobTxSidecar{
Version: sc.Version,

// The element of these slice is fix-size byte array,
// therefore slices.Clone will actually deep copy by value.
Blobs: slices.Clone(sc.Blobs),
Commitments: slices.Clone(sc.Commitments),
Proofs: slices.Clone(sc.Proofs),
}
}

// blobTxWithBlobs represents blob tx with its corresponding sidecar.
// This is an interface because sidecars are versioned.
type blobTxWithBlobs interface {
Expand Down Expand Up @@ -148,7 +202,7 @@ func (btx *blobTxWithBlobsV0) tx() *BlobTx {
}

func (btx *blobTxWithBlobsV0) assign(sc *BlobTxSidecar) error {
sc.Version = 0
sc.Version = BlobSidecarVersion0
sc.Blobs = btx.Blobs
sc.Commitments = btx.Commitments
sc.Proofs = btx.Proofs
Expand All @@ -160,10 +214,10 @@ func (btx *blobTxWithBlobsV1) tx() *BlobTx {
}

func (btx *blobTxWithBlobsV1) assign(sc *BlobTxSidecar) error {
if btx.Version != 1 {
if btx.Version != BlobSidecarVersion1 {
return fmt.Errorf("unsupported blob tx version %d", btx.Version)
}
sc.Version = 1
sc.Version = BlobSidecarVersion1
sc.Blobs = btx.Blobs
sc.Commitments = btx.Commitments
sc.Proofs = btx.Proofs
Expand Down Expand Up @@ -217,12 +271,7 @@ func (tx *BlobTx) copy() TxData {
cpy.S.Set(tx.S)
}
if tx.Sidecar != nil {
cpy.Sidecar = &BlobTxSidecar{
Version: tx.Sidecar.Version,
Blobs: slices.Clone(tx.Sidecar.Blobs),
Commitments: slices.Clone(tx.Sidecar.Commitments),
Proofs: slices.Clone(tx.Sidecar.Proofs),
}
cpy.Sidecar = tx.Sidecar.Copy()
}
return cpy
}
Expand Down Expand Up @@ -280,15 +329,15 @@ func (tx *BlobTx) encode(b *bytes.Buffer) error {
case tx.Sidecar == nil:
return rlp.Encode(b, tx)

case tx.Sidecar.Version == 0:
case tx.Sidecar.Version == BlobSidecarVersion0:
return rlp.Encode(b, &blobTxWithBlobsV0{
BlobTx: tx,
Blobs: tx.Sidecar.Blobs,
Commitments: tx.Sidecar.Commitments,
Proofs: tx.Sidecar.Proofs,
})

case tx.Sidecar.Version == 1:
case tx.Sidecar.Version == BlobSidecarVersion1:
return rlp.Encode(b, &blobTxWithBlobsV1{
BlobTx: tx,
Version: tx.Sidecar.Version,
Expand Down
6 changes: 1 addition & 5 deletions core/types/tx_blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,7 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
}

func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
sidecar := &BlobTxSidecar{
Blobs: []kzg4844.Blob{*emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
}
sidecar := NewBlobTxSidecar(BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof})
blobtx := &BlobTx{
ChainID: uint256.NewInt(1),
Nonce: 5,
Expand Down
8 changes: 3 additions & 5 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,10 +527,10 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
if len(hashes) > 128 {
return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes)))
}

available := api.eth.BlobTxPool().AvailableBlobs(hashes)
getBlobsRequestedCounter.Inc(int64(len(hashes)))
getBlobsAvailableCounter.Inc(int64(available))

// Optimization: check first if all blobs are available, if not, return empty response
if available != len(hashes) {
getBlobsV2RequestMiss.Inc(1)
Expand All @@ -557,7 +557,7 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
// not found, return empty response
return nil, nil
}
if sidecar.Version != 1 {
if sidecar.Version != types.BlobSidecarVersion1 {
log.Info("GetBlobs queried V0 transaction: index %v, blobhashes %v", index, sidecar.BlobHashes())
return nil, nil
}
Expand All @@ -566,9 +566,7 @@ func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProo
if idxes, ok := index[hash]; ok {
proofs, err := sidecar.CellProofsAt(bIdx)
if err != nil {
// TODO @rjl @marius we should return an error
log.Info("Failed to get cell proof", "err", err)
return nil, nil
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure it's the correct way to return the error in engine API. @lightclient @MariusVanDerWijden please check it out

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InvalidParams is probably the most correct in this case

return nil, engine.InvalidParams.With(err)
}
var cellProofs []hexutil.Bytes
for _, proof := range proofs {
Expand Down
9 changes: 2 additions & 7 deletions eth/catalyst/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1511,13 +1511,8 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
}

txs = append(txs, types.NewTx(&inner))
sidecars := []*types.BlobTxSidecar{
{
Blobs: make([]kzg4844.Blob, 1),
Commitments: make([]kzg4844.Commitment, 1),
Proofs: make([]kzg4844.Proof, 1),
},
}
sidecar := types.NewBlobTxSidecar(types.BlobSidecarVersion0, make([]kzg4844.Blob, 1), make([]kzg4844.Commitment, 1), make([]kzg4844.Proof, 1))
sidecars := []*types.BlobTxSidecar{sidecar}

block := types.NewBlock(&header, &types.Body{Transactions: txs}, nil, trie.NewStackTrie(nil))
envelope := engine.BlockToExecutableData(block, nil, sidecars, nil)
Expand Down
6 changes: 1 addition & 5 deletions eth/protocols/eth/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,11 +661,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) {
To: testAddr,
BlobHashes: []common.Hash{emptyBlobHash},
BlobFeeCap: uint256.MustFromBig(common.Big1),
Sidecar: &types.BlobTxSidecar{
Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}),
})
if err != nil {
t.Fatal(err)
Expand Down
6 changes: 1 addition & 5 deletions ethclient/simulated/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,7 @@ func newBlobTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error)
To: addr,
AccessList: nil,
BlobHashes: []common.Hash{testBlobVHash},
Sidecar: &types.BlobTxSidecar{
Blobs: []kzg4844.Blob{*testBlob},
Commitments: []kzg4844.Commitment{testBlobCommit},
Proofs: []kzg4844.Proof{testBlobProof},
},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*testBlob}, []kzg4844.Commitment{testBlobCommit}, []kzg4844.Proof{testBlobProof}),
})
return types.SignTx(tx, types.LatestSignerForChainID(chainid), key)
}
Expand Down
6 changes: 1 addition & 5 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1603,11 +1603,7 @@ func (api *TransactionAPI) SignTransaction(ctx context.Context, args Transaction
// no longer retains the blobs, only the blob hashes. In this step, we need
// to put back the blob(s).
if args.IsEIP4844() {
signed = signed.WithBlobTxSidecar(&types.BlobTxSidecar{
Blobs: args.Blobs,
Commitments: args.Commitments,
Proofs: args.Proofs,
})
signed = signed.WithBlobTxSidecar(types.NewBlobTxSidecar(types.BlobSidecarVersion0, args.Blobs, args.Commitments, args.Proofs))
}
data, err := signed.MarshalBinary()
if err != nil {
Expand Down
24 changes: 6 additions & 18 deletions internal/ethapi/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2758,12 +2758,8 @@ func TestFillBlobTransaction(t *testing.T) {
Proofs: []kzg4844.Proof{emptyBlobProof},
},
want: &result{
Hashes: []common.Hash{emptyBlobHash},
Sidecar: &types.BlobTxSidecar{
Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
},
Hashes: []common.Hash{emptyBlobHash},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}),
},
},
{
Expand All @@ -2778,12 +2774,8 @@ func TestFillBlobTransaction(t *testing.T) {
Proofs: []kzg4844.Proof{emptyBlobProof},
},
want: &result{
Hashes: []common.Hash{emptyBlobHash},
Sidecar: &types.BlobTxSidecar{
Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
},
Hashes: []common.Hash{emptyBlobHash},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}),
},
},
{
Expand All @@ -2808,12 +2800,8 @@ func TestFillBlobTransaction(t *testing.T) {
Blobs: emptyBlobs,
},
want: &result{
Hashes: []common.Hash{emptyBlobHash},
Sidecar: &types.BlobTxSidecar{
Blobs: emptyBlobs,
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Proofs: []kzg4844.Proof{emptyBlobProof},
},
Hashes: []common.Hash{emptyBlobHash},
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}),
},
},
}
Expand Down
Loading
Loading