Files
prysm/beacon-chain/sync/backfill/blobs_test.go
kasey 61de11e2c4 Backfill data columns (#15580)
**What type of PR is this?**

Feature

**What does this PR do? Why is it needed?**

Adds data column support to backfill.

**Acknowledgements**

- [x] I have read
[CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md).
- [x] I have included a uniquely named [changelog fragment
file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd).
- [x] I have added a description to this PR with sufficient context for
reviewers to understand this PR.

---------

Co-authored-by: Kasey <kasey@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Preston Van Loon <preston@pvl.dev>
2025-12-02 15:19:32 +00:00

155 lines
4.9 KiB
Go

package backfill
import (
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/das"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db/filesystem"
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
"github.com/OffchainLabs/prysm/v7/time/slots"
)
const testBlobGenBlobCount = 3
func testBlobGen(t *testing.T, start primitives.Slot, n int) ([]blocks.ROBlock, [][]blocks.ROBlob) {
blks := make([]blocks.ROBlock, n)
blobs := make([][]blocks.ROBlob, n)
for i := range n {
bk, bl := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, start+primitives.Slot(i), testBlobGenBlobCount)
blks[i] = bk
blobs[i] = bl
}
return blks, blobs
}
func setupCurrentNeeds(t *testing.T, current primitives.Slot) das.SyncNeeds {
cs := func() primitives.Slot { return current }
sn, err := das.NewSyncNeeds(cs, nil, 0)
require.NoError(t, err)
return sn
}
func TestValidateNext_happy(t *testing.T) {
startSlot := util.SlotAtEpoch(t, params.BeaconConfig().DenebForkEpoch)
current := startSlot + 65
blks, blobs := testBlobGen(t, startSlot, 4)
cfg := &blobSyncConfig{
nbv: testNewBlobVerifier(),
store: filesystem.NewEphemeralBlobStorage(t),
currentNeeds: mockCurrentNeedsFunc(0, current+1),
}
//expected :=
expected, err := verifiedROBlocks(blks).blobIdents(cfg.currentNeeds)
require.NoError(t, err)
require.Equal(t, len(blks)*testBlobGenBlobCount, len(expected))
bsync, err := newBlobSync(current, blks, cfg)
require.NoError(t, err)
nb := 0
for i := range blobs {
bs := blobs[i]
for ib := range bs {
require.NoError(t, bsync.validateNext(bs[ib]))
nb += 1
}
}
require.Equal(t, nb, bsync.next)
// we should get an error if we read another blob.
require.ErrorIs(t, bsync.validateNext(blobs[0][0]), errUnexpectedResponseSize)
}
func TestValidateNext_cheapErrors(t *testing.T) {
denebSlot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
require.NoError(t, err)
current := primitives.Slot(128)
syncNeeds := setupCurrentNeeds(t, current)
cfg := &blobSyncConfig{
nbv: testNewBlobVerifier(),
store: filesystem.NewEphemeralBlobStorage(t),
currentNeeds: syncNeeds.Currently,
}
blks, blobs := testBlobGen(t, denebSlot, 2)
bsync, err := newBlobSync(current, blks, cfg)
require.NoError(t, err)
require.ErrorIs(t, bsync.validateNext(blobs[len(blobs)-1][0]), errUnexpectedResponseContent)
}
func TestValidateNext_sigMatch(t *testing.T) {
denebSlot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
require.NoError(t, err)
current := primitives.Slot(128)
syncNeeds := setupCurrentNeeds(t, current)
cfg := &blobSyncConfig{
nbv: testNewBlobVerifier(),
store: filesystem.NewEphemeralBlobStorage(t),
currentNeeds: syncNeeds.Currently,
}
blks, blobs := testBlobGen(t, denebSlot, 1)
bsync, err := newBlobSync(current, blks, cfg)
require.NoError(t, err)
blobs[0][0].SignedBlockHeader.Signature = bytesutil.PadTo([]byte("derp"), 48)
require.ErrorIs(t, bsync.validateNext(blobs[0][0]), verification.ErrInvalidProposerSignature)
}
func TestValidateNext_errorsFromVerifier(t *testing.T) {
ds := util.SlotAtEpoch(t, params.BeaconConfig().DenebForkEpoch)
current := primitives.Slot(ds + 96)
blks, blobs := testBlobGen(t, ds+31, 1)
cn := mockCurrentNeedsFunc(0, current+1)
cases := []struct {
name string
err error
cb func(*verification.MockBlobVerifier)
}{
{
name: "index oob",
err: verification.ErrBlobIndexInvalid,
cb: func(v *verification.MockBlobVerifier) {
v.ErrBlobIndexInBounds = verification.ErrBlobIndexInvalid
},
},
{
name: "not inclusion proven",
err: verification.ErrSidecarInclusionProofInvalid,
cb: func(v *verification.MockBlobVerifier) {
v.ErrSidecarInclusionProven = verification.ErrSidecarInclusionProofInvalid
},
},
{
name: "not kzg proof valid",
err: verification.ErrSidecarKzgProofInvalid,
cb: func(v *verification.MockBlobVerifier) {
v.ErrSidecarKzgProofVerified = verification.ErrSidecarKzgProofInvalid
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
cfg := &blobSyncConfig{
nbv: testNewBlobVerifier(c.cb),
store: filesystem.NewEphemeralBlobStorage(t),
currentNeeds: cn,
}
bsync, err := newBlobSync(current, blks, cfg)
require.NoError(t, err)
require.ErrorIs(t, bsync.validateNext(blobs[0][0]), c.err)
})
}
}
func testNewBlobVerifier(opts ...func(*verification.MockBlobVerifier)) verification.NewBlobVerifier {
return func(b blocks.ROBlob, reqs []verification.Requirement) verification.BlobVerifier {
v := &verification.MockBlobVerifier{}
for i := range opts {
opts[i](v)
}
return v
}
}