diff --git a/op-service/sources/l1_beacon_client.go b/op-service/sources/l1_beacon_client.go index c791adb4d9e..c193f1bd351 100644 --- a/op-service/sources/l1_beacon_client.go +++ b/op-service/sources/l1_beacon_client.go @@ -9,7 +9,6 @@ import ( "net/http" "net/url" "path" - "slices" "strconv" "sync" @@ -344,9 +343,13 @@ func (cl *L1BeaconClient) beaconBlobs(ctx context.Context, slot uint64, hashes [ return nil, fmt.Errorf("compute blob kzg commitment: %w", err) } got := eth.KZGToVersionedHash(commitment) - idx := slices.IndexFunc(hashes, func(indexedHash eth.IndexedBlobHash) bool { - return got == indexedHash.Hash - }) + idx := -1 + for i, indexedHash := range hashes { + if got == indexedHash.Hash && blobs[i] == nil { + idx = i + break + } + } if idx == -1 { return nil, fmt.Errorf("received a blob hash that does not match any expected hash: %s", got) } diff --git a/op-service/sources/l1_beacon_client_test.go b/op-service/sources/l1_beacon_client_test.go index 63b753805bd..685f5cccf3d 100644 --- a/op-service/sources/l1_beacon_client_test.go +++ b/op-service/sources/l1_beacon_client_test.go @@ -393,3 +393,39 @@ func TestGetBlobs(t *testing.T) { }) } } + +func TestRequestDuplicateBlobHashes(t *testing.T) { + ctx := context.Background() + p := mocks.NewBeaconClient(t) + p.EXPECT().BeaconGenesis(ctx).Return(eth.APIGenesisResponse{Data: eth.ReducedGenesisData{GenesisTime: 10}}, nil) + p.EXPECT().ConfigSpec(ctx).Return(eth.APIConfigResponse{Data: eth.ReducedConfigData{SecondsPerSlot: 2}}, nil) + client := NewL1BeaconClient(p, L1BeaconClientConfig{}) + ref := eth.L1BlockRef{Time: 12} + + hash0, sidecar0 := makeTestBlobSidecar(0) + hash1, sidecar1 := makeTestBlobSidecar(1) + hash2, sidecar2 := makeTestBlobSidecar(2) + sameHash := eth.IndexedBlobHash{ + Index: 3, + Hash: hash0.Hash, + } + sameHashSidecar := ð.BlobSidecar{ + Blob: sidecar0.Blob, + Index: eth.Uint64String(sameHash.Index), + KZGCommitment: sidecar0.KZGCommitment, + KZGProof: sidecar0.KZGProof, + } + hashes := []eth.IndexedBlobHash{hash0, hash2, hash1, sameHash} // Mix up the order. + beaconBlobs := []*eth.Blob{&sidecar0.Blob, &sidecar1.Blob, &sidecar2.Blob, &sameHashSidecar.Blob} + + invalidBlob0 := sidecar0.Blob + invalidBlob0[10]++ + + // construct the mock response for the beacon blobs call + beaconBlobsResponse := eth.APIBeaconBlobsResponse{Data: beaconBlobs} + p.EXPECT().BeaconBlobs(ctx, uint64(1), hashes).Return(beaconBlobsResponse, nil) + + resp, err := client.GetBlobs(ctx, ref, hashes) + require.NoError(t, err) + require.Equal(t, []*eth.Blob{&sidecar0.Blob, &sidecar2.Blob, &sidecar1.Blob, &sameHashSidecar.Blob}, resp) +}