From d62853e10393d7f28c50f1f141c4d827209e19e0 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Wed, 19 Feb 2025 15:37:30 -0800 Subject: [PATCH] core/txpool,core/types,eth: when receiving blob txs via PooledTransactions, validate that the 'blob_versioned_hashes' in the tx header is produced from the commitments in the sidecar. --- core/txpool/validation.go | 14 ++------------ core/types/tx_blob.go | 23 +++++++++++++++++++++++ eth/handler_eth.go | 11 ++++++++++- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 4d53c386b6..f9f90ab812 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -17,7 +17,6 @@ package txpool import ( - "crypto/sha256" "errors" "fmt" "math/big" @@ -170,20 +169,11 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err if len(sidecar.Blobs) != len(hashes) { return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) } - if len(sidecar.Commitments) != len(hashes) { - return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes)) - } if len(sidecar.Proofs) != len(hashes) { return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(sidecar.Proofs), len(hashes)) } - // Blob quantities match up, validate that the provers match with the - // transaction hash before getting to the cryptography - hasher := sha256.New() - for i, vhash := range hashes { - computed := kzg4844.CalcBlobHashV1(hasher, &sidecar.Commitments[i]) - if vhash != computed { - return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, computed, vhash) - } + if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil { + return err } // Blob commitments match with the hashes in the transaction, verify the // blobs themselves via KZG diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 88251ab957..482b47da27 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -19,6 +19,7 @@ package types import ( "bytes" "crypto/sha256" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -85,6 +86,28 @@ func (sc *BlobTxSidecar) encodedSize() uint64 { return rlp.ListSize(blobs) + rlp.ListSize(commitments) + rlp.ListSize(proofs) } +func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) error { + if len(sc.Blobs) != len(hashes) { + return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sc.Blobs), len(hashes)) + } + if len(sc.Commitments) != len(hashes) { + return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sc.Commitments), len(hashes)) + } + if len(sc.Proofs) != len(hashes) { + return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(sc.Proofs), len(hashes)) + } + // Blob quantities match up, validate that the provers match with the + // transaction hash before getting to the cryptography + hasher := sha256.New() + for i, vhash := range hashes { + computed := kzg4844.CalcBlobHashV1(hasher, &sc.Commitments[i]) + if vhash != computed { + return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, computed, vhash) + } + } + return nil +} + // blobTxWithBlobs is used for encoding of transactions when blobs are present. type blobTxWithBlobs struct { BlobTx *BlobTx diff --git a/eth/handler_eth.go b/eth/handler_eth.go index b2cd52a221..45f7c2c532 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -19,7 +19,6 @@ package eth import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/protocols/eth" @@ -69,6 +68,16 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { return h.txFetcher.Enqueue(peer.ID(), *packet, false) case *eth.PooledTransactionsResponse: + for _, tx := range *packet { + if tx.Type() == types.BlobTxType { + if tx.BlobTxSidecar() == nil { + return errors.New("received sidecar-less blob transaction") + } + if err := tx.BlobTxSidecar().ValidateBlobCommitmentHashes(tx.BlobHashes()); err != nil { + return err + } + } + } return h.txFetcher.Enqueue(peer.ID(), *packet, true) default: