mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
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>
This commit is contained in:
@@ -14,6 +14,9 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// errOverflow is returned when a slot calculation would overflow.
|
||||
var errOverflow = errors.New("slot calculation overflows")
|
||||
|
||||
// MaxSlotBuffer specifies the max buffer given to slots from
|
||||
// incoming objects. (24 mins with mainnet spec)
|
||||
const MaxSlotBuffer = uint64(1 << 7)
|
||||
@@ -108,7 +111,7 @@ func ToForkVersion(slot primitives.Slot) int {
|
||||
func EpochStart(epoch primitives.Epoch) (primitives.Slot, error) {
|
||||
slot, err := params.BeaconConfig().SlotsPerEpoch.SafeMul(uint64(epoch))
|
||||
if err != nil {
|
||||
return slot, errors.Errorf("start slot calculation overflows: %v", err)
|
||||
return slot, errors.Wrap(errOverflow, "epoch start")
|
||||
}
|
||||
return slot, nil
|
||||
}
|
||||
@@ -127,7 +130,7 @@ func UnsafeEpochStart(epoch primitives.Epoch) primitives.Slot {
|
||||
// current epoch.
|
||||
func EpochEnd(epoch primitives.Epoch) (primitives.Slot, error) {
|
||||
if epoch == math.MaxUint64 {
|
||||
return 0, errors.New("start slot calculation overflows")
|
||||
return 0, errors.Wrap(errOverflow, "epoch end")
|
||||
}
|
||||
slot, err := EpochStart(epoch + 1)
|
||||
if err != nil {
|
||||
@@ -284,8 +287,26 @@ func WithinVotingWindow(genesis time.Time, slot primitives.Slot) bool {
|
||||
}
|
||||
|
||||
// MaxSafeEpoch gives the largest epoch value that can be safely converted to a slot.
|
||||
// Note that just dividing max uint64 by slots per epoch is not sufficient,
|
||||
// because the resulting slot could still be the start of an epoch that would overflow
|
||||
// in the end slot computation. So we subtract 1 to ensure that the final epoch can always
|
||||
// have 32 slots.
|
||||
func MaxSafeEpoch() primitives.Epoch {
|
||||
return primitives.Epoch(math.MaxUint64 / uint64(params.BeaconConfig().SlotsPerEpoch))
|
||||
return primitives.Epoch(math.MaxUint64/uint64(params.BeaconConfig().SlotsPerEpoch)) - 1
|
||||
}
|
||||
|
||||
// SafeEpochStartOrMax returns the start slot of the given epoch if it will not overflow,
|
||||
// otherwise it takes the highest epoch that won't overflow,
|
||||
// and to introduce a little margin for error, returns the slot beginning the prior epoch.
|
||||
func SafeEpochStartOrMax(e primitives.Epoch) primitives.Slot {
|
||||
// The max value converted to a slot can't be the start of a conceptual epoch,
|
||||
// because the first slot of that epoch would be overflow
|
||||
// so use the start slot of the epoch right before that value.
|
||||
me := MaxSafeEpoch()
|
||||
if e > me {
|
||||
return UnsafeEpochStart(me)
|
||||
}
|
||||
return UnsafeEpochStart(e)
|
||||
}
|
||||
|
||||
// SecondsUntilNextEpochStart returns how many seconds until the next Epoch start from the current time and slot
|
||||
|
||||
@@ -117,7 +117,7 @@ func TestEpochStartSlot_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.startSlot, ss, "EpochStart(%d)", tt.epoch)
|
||||
} else {
|
||||
require.ErrorContains(t, "start slot calculation overflow", err)
|
||||
require.ErrorIs(t, err, errOverflow)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ func TestEpochEndSlot_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.startSlot, ss, "EpochStart(%d)", tt.epoch)
|
||||
} else {
|
||||
require.ErrorContains(t, "start slot calculation overflow", err)
|
||||
require.ErrorIs(t, err, errOverflow)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -700,3 +700,75 @@ func TestSlotTickerReplayBehaviour(t *testing.T) {
|
||||
|
||||
require.Equal(t, ticks, counter)
|
||||
}
|
||||
|
||||
func TestSafeEpochStartOrMax(t *testing.T) {
|
||||
farFuture := params.BeaconConfig().FarFutureEpoch
|
||||
// ensure FAR_FUTURE_EPOCH is indeed larger than MaxSafeEpoch
|
||||
require.Equal(t, true, farFuture > MaxSafeEpoch())
|
||||
// demonstrate overflow in naive usage of FAR_FUTURE_EPOCH
|
||||
require.Equal(t, true, farFuture*primitives.Epoch(params.BeaconConfig().SlotsPerEpoch) < farFuture)
|
||||
|
||||
// sanity check that example "ordinary" epoch does not overflow
|
||||
fulu, err := EpochStart(params.BeaconConfig().FuluForkEpoch)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, primitives.Slot(params.BeaconConfig().FuluForkEpoch)*params.BeaconConfig().SlotsPerEpoch, fulu)
|
||||
|
||||
maxEpochStart := primitives.Slot(math.MaxUint64) - 63
|
||||
tests := []struct {
|
||||
name string
|
||||
epoch primitives.Epoch
|
||||
want primitives.Slot
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "genesis",
|
||||
epoch: 0,
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "ordinary epoch",
|
||||
epoch: params.BeaconConfig().FuluForkEpoch,
|
||||
want: primitives.Slot(params.BeaconConfig().FuluForkEpoch) * params.BeaconConfig().SlotsPerEpoch,
|
||||
},
|
||||
{
|
||||
name: "max epoch without overflow",
|
||||
epoch: MaxSafeEpoch(),
|
||||
want: maxEpochStart,
|
||||
},
|
||||
{
|
||||
name: "max epoch causing overflow",
|
||||
epoch: primitives.Epoch(math.MaxUint64),
|
||||
want: maxEpochStart,
|
||||
err: errOverflow,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := SafeEpochStartOrMax(tt.epoch)
|
||||
require.Equal(t, tt.want, got)
|
||||
// If we expect an error, it should be present for both start and end calculations
|
||||
_, startErr := EpochStart(tt.epoch)
|
||||
_, endErr := EpochEnd(tt.epoch)
|
||||
if tt.err != nil {
|
||||
require.ErrorIs(t, startErr, tt.err)
|
||||
require.ErrorIs(t, endErr, tt.err)
|
||||
} else {
|
||||
require.NoError(t, startErr)
|
||||
require.NoError(t, endErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxEpoch(t *testing.T) {
|
||||
maxEpoch := MaxSafeEpoch()
|
||||
_, err := EpochStart(maxEpoch + 2)
|
||||
require.ErrorIs(t, err, errOverflow)
|
||||
_, err = EpochEnd(maxEpoch + 1)
|
||||
require.ErrorIs(t, err, errOverflow)
|
||||
require.Equal(t, primitives.Slot(math.MaxUint64)-63, primitives.Slot(maxEpoch)*params.BeaconConfig().SlotsPerEpoch)
|
||||
_, err = EpochEnd(maxEpoch)
|
||||
require.NoError(t, err)
|
||||
_, err = EpochStart(maxEpoch)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user