diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 8d57dce444..25efc40478 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -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 { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index a594413771..0fb4104a05 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -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 diff --git a/core/types/custody_bitmap.go b/core/types/custody_bitmap.go index d7a0606c21..8f5083e9e1 100644 --- a/core/types/custody_bitmap.go +++ b/core/types/custody_bitmap.go @@ -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 +} diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index bb990c3faa..32df5d4a11 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -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 diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 22e888218e..b8c7f87b8b 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -37,7 +37,11 @@ var ( cellT = reflect.TypeFor[Cell]() ) -const CellProofsPerBlob = 128 +const ( + CellProofsPerBlob = 128 + CellsPerBlob = 128 + DataPerBlob = 64 +) type Cell [2048]byte