mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-06 22:23:56 -05:00
**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>
676 lines
20 KiB
Go
676 lines
20 KiB
Go
package das
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/OffchainLabs/prysm/v7/time/slots"
|
|
)
|
|
|
|
// TestNeedSpanAt tests the needSpan.at() method for range checking.
|
|
func TestNeedSpanAt(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
span NeedSpan
|
|
slots []primitives.Slot
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "within bounds",
|
|
span: NeedSpan{Begin: 100, End: 200},
|
|
slots: []primitives.Slot{101, 150, 199},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "before begin / at end boundary (exclusive)",
|
|
span: NeedSpan{Begin: 100, End: 200},
|
|
slots: []primitives.Slot{99, 200, 201},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "empty span (begin == end)",
|
|
span: NeedSpan{Begin: 100, End: 100},
|
|
slots: []primitives.Slot{100},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "slot 0 with span starting at 0",
|
|
span: NeedSpan{Begin: 0, End: 100},
|
|
slots: []primitives.Slot{0},
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
for _, sl := range tc.slots {
|
|
t.Run(fmt.Sprintf("%s at slot %d, ", tc.name, sl), func(t *testing.T) {
|
|
result := tc.span.At(sl)
|
|
require.Equal(t, tc.expected, result)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestSyncEpochOffset tests the syncEpochOffset helper function.
|
|
func TestSyncEpochOffset(t *testing.T) {
|
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
|
|
|
cases := []struct {
|
|
name string
|
|
current primitives.Slot
|
|
subtract primitives.Epoch
|
|
expected primitives.Slot
|
|
}{
|
|
{
|
|
name: "typical offset - 5 epochs back",
|
|
current: primitives.Slot(10000),
|
|
subtract: 5,
|
|
expected: primitives.Slot(10000 - 5*slotsPerEpoch),
|
|
},
|
|
{
|
|
name: "zero subtract returns current",
|
|
current: primitives.Slot(5000),
|
|
subtract: 0,
|
|
expected: primitives.Slot(5000),
|
|
},
|
|
{
|
|
name: "subtract 1 epoch from mid-range slot",
|
|
current: primitives.Slot(1000),
|
|
subtract: 1,
|
|
expected: primitives.Slot(1000 - slotsPerEpoch),
|
|
},
|
|
{
|
|
name: "offset equals current - underflow protection",
|
|
current: primitives.Slot(slotsPerEpoch),
|
|
subtract: 1,
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "offset exceeds current - underflow protection",
|
|
current: primitives.Slot(50),
|
|
subtract: 1000,
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "current very close to 0",
|
|
current: primitives.Slot(10),
|
|
subtract: 1,
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "subtract MaxSafeEpoch",
|
|
current: primitives.Slot(1000000),
|
|
subtract: slots.MaxSafeEpoch(),
|
|
expected: 1, // underflow protection
|
|
},
|
|
{
|
|
name: "result exactly at slot 1",
|
|
current: primitives.Slot(1 + slotsPerEpoch),
|
|
subtract: 1,
|
|
expected: 1,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result := syncEpochOffset(tc.current, tc.subtract)
|
|
require.Equal(t, tc.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSyncNeedsInitialize tests the syncNeeds.initialize() method.
|
|
func TestSyncNeedsInitialize(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
|
minBlobEpochs := params.BeaconConfig().MinEpochsForBlobsSidecarsRequest
|
|
minColEpochs := params.BeaconConfig().MinEpochsForDataColumnSidecarsRequest
|
|
|
|
currentSlot := primitives.Slot(10000)
|
|
currentFunc := func() primitives.Slot { return currentSlot }
|
|
|
|
cases := []struct {
|
|
invalidOldestFlag bool
|
|
expectValidOldest bool
|
|
oldestSlotFlagPtr *primitives.Slot
|
|
blobRetentionFlag primitives.Epoch
|
|
expectedBlob primitives.Epoch
|
|
expectedCol primitives.Epoch
|
|
name string
|
|
input SyncNeeds
|
|
}{
|
|
{
|
|
name: "basic initialization with no flags",
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
blobRetentionFlag: 0,
|
|
},
|
|
{
|
|
name: "blob retention flag less than spec minimum",
|
|
blobRetentionFlag: minBlobEpochs - 1,
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
},
|
|
{
|
|
name: "blob retention flag greater than spec minimum",
|
|
blobRetentionFlag: minBlobEpochs + 10,
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs + 10,
|
|
expectedCol: minBlobEpochs + 10,
|
|
},
|
|
{
|
|
name: "oldestSlotFlagPtr is nil",
|
|
blobRetentionFlag: 0,
|
|
oldestSlotFlagPtr: nil,
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
},
|
|
{
|
|
name: "valid oldestSlotFlagPtr (earlier than spec minimum)",
|
|
blobRetentionFlag: 0,
|
|
oldestSlotFlagPtr: func() *primitives.Slot {
|
|
slot := primitives.Slot(10)
|
|
return &slot
|
|
}(),
|
|
expectValidOldest: true,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
},
|
|
{
|
|
name: "invalid oldestSlotFlagPtr (later than spec minimum)",
|
|
blobRetentionFlag: 0,
|
|
oldestSlotFlagPtr: func() *primitives.Slot {
|
|
// Make it way past the spec minimum
|
|
slot := currentSlot - primitives.Slot(params.BeaconConfig().MinEpochsForBlockRequests-1)*slotsPerEpoch
|
|
return &slot
|
|
}(),
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
invalidOldestFlag: true,
|
|
},
|
|
{
|
|
name: "oldestSlotFlagPtr at boundary (exactly at spec minimum)",
|
|
blobRetentionFlag: 0,
|
|
oldestSlotFlagPtr: func() *primitives.Slot {
|
|
slot := currentSlot - primitives.Slot(params.BeaconConfig().MinEpochsForBlockRequests)*slotsPerEpoch
|
|
return &slot
|
|
}(),
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
invalidOldestFlag: true,
|
|
},
|
|
{
|
|
name: "both blob retention flag and oldest slot set",
|
|
blobRetentionFlag: minBlobEpochs + 5,
|
|
oldestSlotFlagPtr: func() *primitives.Slot {
|
|
slot := primitives.Slot(100)
|
|
return &slot
|
|
}(),
|
|
expectValidOldest: true,
|
|
expectedBlob: minBlobEpochs + 5,
|
|
expectedCol: minBlobEpochs + 5,
|
|
},
|
|
{
|
|
name: "zero blob retention uses spec minimum",
|
|
blobRetentionFlag: 0,
|
|
expectValidOldest: false,
|
|
expectedBlob: minBlobEpochs,
|
|
expectedCol: minColEpochs,
|
|
},
|
|
{
|
|
name: "large blob retention value",
|
|
blobRetentionFlag: 5000,
|
|
expectValidOldest: false,
|
|
expectedBlob: 5000,
|
|
expectedCol: 5000,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result, err := NewSyncNeeds(currentFunc, tc.oldestSlotFlagPtr, tc.blobRetentionFlag)
|
|
require.NoError(t, err)
|
|
|
|
// Check that current, deneb, fulu are set correctly
|
|
require.Equal(t, currentSlot, result.current())
|
|
|
|
// Check retention calculations
|
|
require.Equal(t, tc.expectedBlob, result.blobRetention)
|
|
require.Equal(t, tc.expectedCol, result.colRetention)
|
|
|
|
if tc.invalidOldestFlag {
|
|
require.IsNil(t, result.validOldestSlotPtr)
|
|
} else {
|
|
require.Equal(t, tc.oldestSlotFlagPtr, result.validOldestSlotPtr)
|
|
}
|
|
|
|
// Check blockRetention is always spec minimum
|
|
require.Equal(t, primitives.Epoch(params.BeaconConfig().MinEpochsForBlockRequests), result.blockRetention)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSyncNeedsBlockSpan tests the syncNeeds.blockSpan() method.
|
|
func TestSyncNeedsBlockSpan(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
minBlockEpochs := params.BeaconConfig().MinEpochsForBlockRequests
|
|
|
|
cases := []struct {
|
|
name string
|
|
validOldest *primitives.Slot
|
|
blockRetention primitives.Epoch
|
|
current primitives.Slot
|
|
expectedBegin primitives.Slot
|
|
expectedEnd primitives.Slot
|
|
}{
|
|
{
|
|
name: "with validOldestSlotPtr set",
|
|
validOldest: func() *primitives.Slot { s := primitives.Slot(500); return &s }(),
|
|
blockRetention: primitives.Epoch(minBlockEpochs),
|
|
current: 10000,
|
|
expectedBegin: 500,
|
|
expectedEnd: 10000,
|
|
},
|
|
{
|
|
name: "without validOldestSlotPtr (nil)",
|
|
validOldest: nil,
|
|
blockRetention: primitives.Epoch(minBlockEpochs),
|
|
current: 10000,
|
|
expectedBegin: syncEpochOffset(10000, primitives.Epoch(minBlockEpochs)),
|
|
expectedEnd: 10000,
|
|
},
|
|
{
|
|
name: "very low current slot",
|
|
validOldest: nil,
|
|
blockRetention: primitives.Epoch(minBlockEpochs),
|
|
current: 100,
|
|
expectedBegin: 1, // underflow protection
|
|
expectedEnd: 100,
|
|
},
|
|
{
|
|
name: "very high current slot",
|
|
validOldest: nil,
|
|
blockRetention: primitives.Epoch(minBlockEpochs),
|
|
current: 1000000,
|
|
expectedBegin: syncEpochOffset(1000000, primitives.Epoch(minBlockEpochs)),
|
|
expectedEnd: 1000000,
|
|
},
|
|
{
|
|
name: "validOldestSlotPtr at boundary value",
|
|
validOldest: func() *primitives.Slot { s := primitives.Slot(1); return &s }(),
|
|
blockRetention: primitives.Epoch(minBlockEpochs),
|
|
current: 5000,
|
|
expectedBegin: 1,
|
|
expectedEnd: 5000,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
sn := SyncNeeds{
|
|
validOldestSlotPtr: tc.validOldest,
|
|
blockRetention: tc.blockRetention,
|
|
}
|
|
result := sn.blockSpan(tc.current)
|
|
require.Equal(t, tc.expectedBegin, result.Begin)
|
|
require.Equal(t, tc.expectedEnd, result.End)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSyncNeedsCurrently tests the syncNeeds.currently() method.
|
|
func TestSyncNeedsCurrently(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
|
|
|
denebSlot := primitives.Slot(1000)
|
|
fuluSlot := primitives.Slot(2000)
|
|
|
|
cases := []struct {
|
|
name string
|
|
current primitives.Slot
|
|
blobRetention primitives.Epoch
|
|
colRetention primitives.Epoch
|
|
blockRetention primitives.Epoch
|
|
validOldest *primitives.Slot
|
|
// Expected block span
|
|
expectBlockBegin primitives.Slot
|
|
expectBlockEnd primitives.Slot
|
|
// Expected blob span
|
|
expectBlobBegin primitives.Slot
|
|
expectBlobEnd primitives.Slot
|
|
// Expected column span
|
|
expectColBegin primitives.Slot
|
|
expectColEnd primitives.Slot
|
|
}{
|
|
{
|
|
name: "pre-Deneb - only blocks needed",
|
|
current: 500,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(500, 5),
|
|
expectBlockEnd: 500,
|
|
expectBlobBegin: denebSlot, // adjusted to deneb
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot, // adjusted to fulu
|
|
expectColEnd: 500,
|
|
},
|
|
{
|
|
name: "between Deneb and Fulu - blocks and blobs needed",
|
|
current: 1500,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(1500, 5),
|
|
expectBlockEnd: 1500,
|
|
expectBlobBegin: max(syncEpochOffset(1500, 10), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot, // adjusted to fulu
|
|
expectColEnd: 1500,
|
|
},
|
|
{
|
|
name: "post-Fulu - all resources needed",
|
|
current: 3000,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(3000, 5),
|
|
expectBlockEnd: 3000,
|
|
expectBlobBegin: max(syncEpochOffset(3000, 10), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: max(syncEpochOffset(3000, 10), fuluSlot),
|
|
expectColEnd: 3000,
|
|
},
|
|
{
|
|
name: "exactly at Deneb boundary",
|
|
current: denebSlot,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(denebSlot, 5),
|
|
expectBlockEnd: denebSlot,
|
|
expectBlobBegin: denebSlot,
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot,
|
|
expectColEnd: denebSlot,
|
|
},
|
|
{
|
|
name: "exactly at Fulu boundary",
|
|
current: fuluSlot,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(fuluSlot, 5),
|
|
expectBlockEnd: fuluSlot,
|
|
expectBlobBegin: max(syncEpochOffset(fuluSlot, 10), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot,
|
|
expectColEnd: fuluSlot,
|
|
},
|
|
{
|
|
name: "small retention periods",
|
|
current: 5000,
|
|
blobRetention: 1,
|
|
colRetention: 2,
|
|
blockRetention: 1,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(5000, 1),
|
|
expectBlockEnd: 5000,
|
|
expectBlobBegin: max(syncEpochOffset(5000, 1), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: max(syncEpochOffset(5000, 2), fuluSlot),
|
|
expectColEnd: 5000,
|
|
},
|
|
{
|
|
name: "large retention periods",
|
|
current: 10000,
|
|
blobRetention: 100,
|
|
colRetention: 100,
|
|
blockRetention: 50,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(10000, 50),
|
|
expectBlockEnd: 10000,
|
|
expectBlobBegin: max(syncEpochOffset(10000, 100), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: max(syncEpochOffset(10000, 100), fuluSlot),
|
|
expectColEnd: 10000,
|
|
},
|
|
{
|
|
name: "with validOldestSlotPtr for blocks",
|
|
current: 8000,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: func() *primitives.Slot { s := primitives.Slot(100); return &s }(),
|
|
expectBlockBegin: 100,
|
|
expectBlockEnd: 8000,
|
|
expectBlobBegin: max(syncEpochOffset(8000, 10), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: max(syncEpochOffset(8000, 10), fuluSlot),
|
|
expectColEnd: 8000,
|
|
},
|
|
{
|
|
name: "retention approaching current slot",
|
|
current: primitives.Slot(2000 + 5*slotsPerEpoch),
|
|
blobRetention: 5,
|
|
colRetention: 5,
|
|
blockRetention: 3,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(primitives.Slot(2000+5*slotsPerEpoch), 3),
|
|
expectBlockEnd: primitives.Slot(2000 + 5*slotsPerEpoch),
|
|
expectBlobBegin: max(syncEpochOffset(primitives.Slot(2000+5*slotsPerEpoch), 5), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: max(syncEpochOffset(primitives.Slot(2000+5*slotsPerEpoch), 5), fuluSlot),
|
|
expectColEnd: primitives.Slot(2000 + 5*slotsPerEpoch),
|
|
},
|
|
{
|
|
name: "current just after Deneb",
|
|
current: denebSlot + 10,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(denebSlot+10, 5),
|
|
expectBlockEnd: denebSlot + 10,
|
|
expectBlobBegin: denebSlot,
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot,
|
|
expectColEnd: denebSlot + 10,
|
|
},
|
|
{
|
|
name: "current just after Fulu",
|
|
current: fuluSlot + 10,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(fuluSlot+10, 5),
|
|
expectBlockEnd: fuluSlot + 10,
|
|
expectBlobBegin: max(syncEpochOffset(fuluSlot+10, 10), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot,
|
|
expectColEnd: fuluSlot + 10,
|
|
},
|
|
{
|
|
name: "blob retention would start before Deneb",
|
|
current: denebSlot + primitives.Slot(5*slotsPerEpoch),
|
|
blobRetention: 100, // very large retention
|
|
colRetention: 10,
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(denebSlot+primitives.Slot(5*slotsPerEpoch), 5),
|
|
expectBlockEnd: denebSlot + primitives.Slot(5*slotsPerEpoch),
|
|
expectBlobBegin: denebSlot, // clamped to deneb
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot,
|
|
expectColEnd: denebSlot + primitives.Slot(5*slotsPerEpoch),
|
|
},
|
|
{
|
|
name: "column retention would start before Fulu",
|
|
current: fuluSlot + primitives.Slot(5*slotsPerEpoch),
|
|
blobRetention: 10,
|
|
colRetention: 100, // very large retention
|
|
blockRetention: 5,
|
|
validOldest: nil,
|
|
expectBlockBegin: syncEpochOffset(fuluSlot+primitives.Slot(5*slotsPerEpoch), 5),
|
|
expectBlockEnd: fuluSlot + primitives.Slot(5*slotsPerEpoch),
|
|
expectBlobBegin: max(syncEpochOffset(fuluSlot+primitives.Slot(5*slotsPerEpoch), 10), denebSlot),
|
|
expectBlobEnd: fuluSlot,
|
|
expectColBegin: fuluSlot, // clamped to fulu
|
|
expectColEnd: fuluSlot + primitives.Slot(5*slotsPerEpoch),
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
sn := SyncNeeds{
|
|
current: func() primitives.Slot { return tc.current },
|
|
deneb: denebSlot,
|
|
fulu: fuluSlot,
|
|
validOldestSlotPtr: tc.validOldest,
|
|
blockRetention: tc.blockRetention,
|
|
blobRetention: tc.blobRetention,
|
|
colRetention: tc.colRetention,
|
|
}
|
|
|
|
result := sn.Currently()
|
|
|
|
// Verify block span
|
|
require.Equal(t, tc.expectBlockBegin, result.Block.Begin,
|
|
"block.begin mismatch")
|
|
require.Equal(t, tc.expectBlockEnd, result.Block.End,
|
|
"block.end mismatch")
|
|
|
|
// Verify blob span
|
|
require.Equal(t, tc.expectBlobBegin, result.Blob.Begin,
|
|
"blob.begin mismatch")
|
|
require.Equal(t, tc.expectBlobEnd, result.Blob.End,
|
|
"blob.end mismatch")
|
|
|
|
// Verify column span
|
|
require.Equal(t, tc.expectColBegin, result.Col.Begin,
|
|
"col.begin mismatch")
|
|
require.Equal(t, tc.expectColEnd, result.Col.End,
|
|
"col.end mismatch")
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestCurrentNeedsIntegration verifies the complete currentNeeds workflow.
|
|
func TestCurrentNeedsIntegration(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
|
|
denebSlot := primitives.Slot(1000)
|
|
fuluSlot := primitives.Slot(2000)
|
|
|
|
cases := []struct {
|
|
name string
|
|
current primitives.Slot
|
|
blobRetention primitives.Epoch
|
|
colRetention primitives.Epoch
|
|
testSlots []primitives.Slot
|
|
expectBlockAt []bool
|
|
expectBlobAt []bool
|
|
expectColAt []bool
|
|
}{
|
|
{
|
|
name: "pre-Deneb slot - only blocks",
|
|
current: 500,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
testSlots: []primitives.Slot{100, 250, 499, 500, 1000, 2000},
|
|
expectBlockAt: []bool{true, true, true, false, false, false},
|
|
expectBlobAt: []bool{false, false, false, false, true, false},
|
|
expectColAt: []bool{false, false, false, false, false, false},
|
|
},
|
|
{
|
|
name: "between Deneb and Fulu - blocks and blobs",
|
|
current: 1500,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
testSlots: []primitives.Slot{500, 1000, 1200, 1499, 1500, 2000},
|
|
expectBlockAt: []bool{true, true, true, true, false, false},
|
|
expectBlobAt: []bool{false, false, true, true, true, false},
|
|
expectColAt: []bool{false, false, false, false, false, false},
|
|
},
|
|
{
|
|
name: "post-Fulu - all resources",
|
|
current: 3000,
|
|
blobRetention: 10,
|
|
colRetention: 10,
|
|
testSlots: []primitives.Slot{1000, 1500, 2000, 2500, 2999, 3000},
|
|
expectBlockAt: []bool{true, true, true, true, true, false},
|
|
expectBlobAt: []bool{false, false, false, false, false, false},
|
|
expectColAt: []bool{false, false, false, false, true, false},
|
|
},
|
|
{
|
|
name: "at Deneb boundary",
|
|
current: denebSlot,
|
|
blobRetention: 5,
|
|
colRetention: 5,
|
|
testSlots: []primitives.Slot{500, 999, 1000, 1500, 2000},
|
|
expectBlockAt: []bool{true, true, false, false, false},
|
|
expectBlobAt: []bool{false, false, true, true, false},
|
|
expectColAt: []bool{false, false, false, false, false},
|
|
},
|
|
{
|
|
name: "at Fulu boundary",
|
|
current: fuluSlot,
|
|
blobRetention: 5,
|
|
colRetention: 5,
|
|
testSlots: []primitives.Slot{1000, 1500, 1999, 2000, 2001},
|
|
expectBlockAt: []bool{true, true, true, false, false},
|
|
expectBlobAt: []bool{false, false, true, false, false},
|
|
expectColAt: []bool{false, false, false, false, false},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
sn := SyncNeeds{
|
|
current: func() primitives.Slot { return tc.current },
|
|
deneb: denebSlot,
|
|
fulu: fuluSlot,
|
|
blockRetention: 100,
|
|
blobRetention: tc.blobRetention,
|
|
colRetention: tc.colRetention,
|
|
}
|
|
|
|
cn := sn.Currently()
|
|
|
|
// Verify block.end == current
|
|
require.Equal(t, tc.current, cn.Block.End, "block.end should equal current")
|
|
|
|
// Verify blob.end == fulu
|
|
require.Equal(t, fuluSlot, cn.Blob.End, "blob.end should equal fulu")
|
|
|
|
// Verify col.end == current
|
|
require.Equal(t, tc.current, cn.Col.End, "col.end should equal current")
|
|
|
|
// Test each slot
|
|
for i, slot := range tc.testSlots {
|
|
require.Equal(t, tc.expectBlockAt[i], cn.Block.At(slot),
|
|
"block.at(%d) mismatch at index %d", slot, i)
|
|
require.Equal(t, tc.expectBlobAt[i], cn.Blob.At(slot),
|
|
"blob.at(%d) mismatch at index %d", slot, i)
|
|
require.Equal(t, tc.expectColAt[i], cn.Col.At(slot),
|
|
"col.at(%d) mismatch at index %d", slot, i)
|
|
}
|
|
})
|
|
}
|
|
}
|