add: remove parity cells before storing blobs to the blobpool

This commit is contained in:
healthykim 2025-09-11 16:43:05 +09:00
parent 435ad70195
commit 61c55eb1e5
5 changed files with 61 additions and 16 deletions

View file

@ -174,7 +174,7 @@ func (ptx *PooledBlobTx) Convert() (*types.Transaction, error) {
return nil, errors.New("cell sidecar missing")
}
cellSidecar := ptx.Sidecar
blobs, err := kzg4844.RecoverBlobs(cellSidecar.Cells, cellSidecar.CellIndices.Indices())
blobs, err := kzg4844.RecoverBlobs(cellSidecar.Cells, cellSidecar.Custody.Indices())
if err != nil {
return nil, err
}
@ -183,6 +183,35 @@ func (ptx *PooledBlobTx) Convert() (*types.Transaction, error) {
return ptx.Transaction.WithBlobTxSidecar(sidecar), nil
}
func (ptx *PooledBlobTx) RemoveParity() error {
sc := ptx.Sidecar
custodySize := sc.Custody.OneCount()
if custodySize == 0 {
return errors.New("blobless transaction")
}
blobCount := len(sc.Cells) / custodySize
var cellsWithoutParity []kzg4844.Cell
pos := 0
for range blobCount {
for bit := 0; bit < kzg4844.CellsPerBlob; bit++ {
if sc.Custody.IsSet(uint(bit)) {
cell := sc.Cells[pos]
pos++
if bit < kzg4844.DataPerBlob {
cellsWithoutParity = append(cellsWithoutParity, cell)
}
}
}
}
sc.Cells = cellsWithoutParity
for bit := 64; bit < kzg4844.CellsPerBlob; bit++ {
sc.Custody.Clear(uint(bit))
}
return nil
}
// BlobPool is the transaction pool dedicated to EIP-4844 blob transactions.
//
// Blob transactions are special snowflakes that are designed for a very specific
@ -1204,9 +1233,11 @@ func (p *BlobPool) checkDelegationLimit(tx *types.Transaction) error {
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (p *BlobPool) validateTx(tx *types.Transaction, cellSidecars *types.BlobTxCellSidecar) error {
if err := txpool.ValidateBlobSidecar(tx, cellSidecars, p.head, &txpool.ValidationOptions{
func (p *BlobPool) validateTx(tx *types.Transaction, cellSidecar *types.BlobTxCellSidecar) error {
if tx.BlobTxSidecar() != nil || cellSidecar == nil {
return errors.New("malformed transaction and cellSidecar")
}
if err := txpool.ValidateBlobSidecar(tx, cellSidecar, p.head, &txpool.ValidationOptions{
Config: p.chain.Config(),
MaxBlobCount: maxBlobsPerTx,
}); err != nil {
@ -1607,6 +1638,9 @@ func (p *BlobPool) add(tx *types.Transaction, cellSidecar *types.BlobTxCellSidec
// Transaction permitted into the pool from a nonce and cost perspective,
// insert it into the database and update the indices
pooledTx := NewPooledBlobTx(tx, cellSidecar)
if pooledTx.RemoveParity() != nil {
return err
}
blob, err := rlp.EncodeToBytes(pooledTx)
if err != nil {

View file

@ -150,7 +150,7 @@ func ValidateBlobSidecar(tx *types.Transaction, sidecar *types.BlobTxCellSidecar
return fmt.Errorf("%w: blob fee cap %v, minimum needed %v", ErrTxGasPriceTooLow, tx.BlobGasFeeCap(), blobTxMinBlobGasPrice)
}
// Verify whether the blob count is consistent with other parts of the sidecar and the transaction
blobCount := len(sidecar.Cells) / sidecar.CellIndices.OneCount()
blobCount := len(sidecar.Cells) / sidecar.Custody.OneCount()
hashes := tx.BlobHashes()
if blobCount == 0 {
return errors.New("blobless blob transaction")
@ -181,7 +181,7 @@ func validateBlobSidecarLegacy(sidecar *types.BlobTxCellSidecar, hashes []common
if len(sidecar.Proofs) != len(hashes) {
return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes))
}
blobs, err := kzg4844.RecoverBlobs(sidecar.Cells, sidecar.CellIndices.Indices())
blobs, err := kzg4844.RecoverBlobs(sidecar.Cells, sidecar.Custody.Indices())
if err != nil {
return err
}
@ -200,7 +200,7 @@ func validateBlobSidecarOsaka(sidecar *types.BlobTxCellSidecar, hashes []common.
if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob {
return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes)*kzg4844.CellProofsPerBlob)
}
return kzg4844.VerifyCells(sidecar.Cells, sidecar.Commitments, sidecar.Proofs, sidecar.CellIndices.Indices())
return kzg4844.VerifyCells(sidecar.Cells, sidecar.Commitments, sidecar.Proofs, sidecar.Custody.Indices())
}
// ValidationOptionsWithState define certain differences between stateful transaction

View file

@ -3,15 +3,15 @@ package types
import (
"errors"
"math/bits"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
)
// `CustodyBitmap` is a bitmap to represent which custody index to store (little endian)
type CustodyBitmap [16]byte
const CustodySize = 128
func (b CustodyBitmap) IsSet(i uint) bool {
if i >= CustodySize {
if i >= uint(kzg4844.CellsPerBlob) {
return false
}
index := i / 8
@ -21,7 +21,7 @@ func (b CustodyBitmap) IsSet(i uint) bool {
// Set ith bit
func (b *CustodyBitmap) Set(i uint) error {
if i >= CustodySize {
if i >= uint(kzg4844.CellsPerBlob) {
return errors.New("bit index out of range")
}
index := i / 8
@ -32,7 +32,7 @@ func (b *CustodyBitmap) Set(i uint) error {
// Clear ith bit
func (b *CustodyBitmap) Clear(i uint) error {
if i >= CustodySize {
if i >= uint(kzg4844.CellsPerBlob) {
return errors.New("bit index out of range")
}
index := i / 8
@ -67,7 +67,7 @@ func (b CustodyBitmap) Indices() []uint64 {
func (b CustodyBitmap) SetIndices(indices []uint64) error {
for _, i := range indices {
if i >= CustodySize {
if i >= uint64(kzg4844.CellsPerBlob) {
return errors.New("bit index out of range")
}
byteIdx := i / 8
@ -83,3 +83,10 @@ func (b CustodyBitmap) SetAll() CustodyBitmap {
}
return b
}
func (b CustodyBitmap) SetData() CustodyBitmap {
for i := 0; i < kzg4844.DataPerBlob/8; i++ {
b[i] = 0xFF
}
return b
}

View file

@ -186,7 +186,7 @@ func (sc *BlobTxSidecar) ToBlobTxCellSidecar() (*BlobTxCellSidecar, error) {
Cells: cells,
Commitments: sc.Commitments,
Proofs: sc.Proofs,
CellIndices: CustodyBitmap{}.SetAll(),
Custody: CustodyBitmap{}.SetAll(),
}, nil
}
@ -195,7 +195,7 @@ type BlobTxCellSidecar struct {
Cells []kzg4844.Cell
Commitments []kzg4844.Commitment
Proofs []kzg4844.Proof
CellIndices CustodyBitmap
Custody CustodyBitmap
}
// ValidateBlobCommitmentHashes checks whether the given hashes correspond to the

View file

@ -37,7 +37,11 @@ var (
cellT = reflect.TypeFor[Cell]()
)
const CellProofsPerBlob = 128
const (
CellProofsPerBlob = 128
CellsPerBlob = 128
DataPerBlob = 64
)
type Cell [2048]byte