Fix Blob Reconstruction (#14909)

* Fix Mutating Blob Mask

* Changelog

* Typo
This commit is contained in:
Nishant Das
2025-02-11 21:44:00 +08:00
committed by GitHub
parent 26d35474e9
commit 4b43f13e65
3 changed files with 40 additions and 17 deletions

View File

@@ -543,9 +543,11 @@ func (s *Service) ReconstructBlobSidecars(ctx context.Context, block interfaces.
// Collect KZG hashes for non-existing blobs // Collect KZG hashes for non-existing blobs
var kzgHashes []common.Hash var kzgHashes []common.Hash
var kzgIndexes []int
for i, commitment := range kzgCommitments { for i, commitment := range kzgCommitments {
if !hasIndex(uint64(i)) { if !hasIndex(uint64(i)) {
kzgHashes = append(kzgHashes, primitives.ConvertKzgCommitmentToVersionedHash(commitment)) kzgHashes = append(kzgHashes, primitives.ConvertKzgCommitmentToVersionedHash(commitment))
kzgIndexes = append(kzgIndexes, i)
} }
} }
if len(kzgHashes) == 0 { if len(kzgHashes) == 0 {
@@ -568,27 +570,21 @@ func (s *Service) ReconstructBlobSidecars(ctx context.Context, block interfaces.
// Reconstruct verified blob sidecars // Reconstruct verified blob sidecars
var verifiedBlobs []blocks.VerifiedROBlob var verifiedBlobs []blocks.VerifiedROBlob
for i, blobIndex := 0, 0; i < len(kzgCommitments); i++ { for i := 0; i < len(kzgHashes); i++ {
if hasIndex(uint64(i)) { if blobs[i] == nil {
continue continue
} }
blob := blobs[i]
if blobIndex >= len(blobs) || blobs[blobIndex] == nil { blobIndex := kzgIndexes[i]
blobIndex++ proof, err := blocks.MerkleProofKZGCommitment(blockBody, blobIndex)
continue
}
blob := blobs[blobIndex]
blobIndex++
proof, err := blocks.MerkleProofKZGCommitment(blockBody, i)
if err != nil { if err != nil {
log.WithError(err).WithField("index", i).Error("failed to get Merkle proof for KZG commitment") log.WithError(err).WithField("index", blobIndex).Error("failed to get Merkle proof for KZG commitment")
continue continue
} }
sidecar := &ethpb.BlobSidecar{ sidecar := &ethpb.BlobSidecar{
Index: uint64(i), Index: uint64(blobIndex),
Blob: blob.Blob, Blob: blob.Blob,
KzgCommitment: kzgCommitments[i], KzgCommitment: kzgCommitments[blobIndex],
KzgProof: blob.KzgProof, KzgProof: blob.KzgProof,
SignedBlockHeader: header, SignedBlockHeader: header,
CommitmentInclusionProof: proof, CommitmentInclusionProof: proof,
@@ -596,14 +592,14 @@ func (s *Service) ReconstructBlobSidecars(ctx context.Context, block interfaces.
roBlob, err := blocks.NewROBlobWithRoot(sidecar, blockRoot) roBlob, err := blocks.NewROBlobWithRoot(sidecar, blockRoot)
if err != nil { if err != nil {
log.WithError(err).WithField("index", i).Error("failed to create RO blob with root") log.WithError(err).WithField("index", blobIndex).Error("failed to create RO blob with root")
continue continue
} }
v := s.blobVerifier(roBlob, verification.ELMemPoolRequirements) v := s.blobVerifier(roBlob, verification.ELMemPoolRequirements)
verifiedBlob, err := v.VerifiedROBlob() verifiedBlob, err := v.VerifiedROBlob()
if err != nil { if err != nil {
log.WithError(err).WithField("index", i).Error("failed to verify RO blob") log.WithError(err).WithField("index", blobIndex).Error("failed to verify RO blob")
continue continue
} }

View File

@@ -2455,6 +2455,25 @@ func TestReconstructBlobSidecars(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 3, len(verifiedBlobs)) require.Equal(t, 3, len(verifiedBlobs))
}) })
t.Run("recovered 3 missing blobs with mutated blob mask", func(t *testing.T) {
exists := []bool{true, false, true, false, true, false}
hi := mockSummary(t, exists)
srv := createBlobServer(t, 3, func() {
// Mutate blob mask
exists[1] = true
exists[3] = true
})
defer srv.Close()
rpcClient, client := setupRpcClient(t, srv.URL, client)
defer rpcClient.Close()
verifiedBlobs, err := client.ReconstructBlobSidecars(ctx, sb, r, hi)
require.NoError(t, err)
require.Equal(t, 3, len(verifiedBlobs))
})
} }
func createRandomKzgCommitments(t *testing.T, num int) [][]byte { func createRandomKzgCommitments(t *testing.T, num int) [][]byte {
@@ -2467,12 +2486,16 @@ func createRandomKzgCommitments(t *testing.T, num int) [][]byte {
return kzgCommitments return kzgCommitments
} }
func createBlobServer(t *testing.T, numBlobs int) *httptest.Server { func createBlobServer(t *testing.T, numBlobs int, callbackFuncs ...func()) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
defer func() { defer func() {
require.NoError(t, r.Body.Close()) require.NoError(t, r.Body.Close())
}() }()
// Execute callback functions for each request.
for _, f := range callbackFuncs {
f()
}
blobs := make([]pb.BlobAndProofJson, numBlobs) blobs := make([]pb.BlobAndProofJson, numBlobs)
for i := range blobs { for i := range blobs {

View File

@@ -0,0 +1,4 @@
### Fixed
- We change how we track blob indexes during their reconstruction from the EL to prevent
a mutating blob mask from causing invalid sidecars from being created.