Compare commits

...

1 Commits

Author SHA1 Message Date
Kasey Kirkham
c30a1f9aa0 proof of concept for safe slot conversion without error handling 2025-10-14 14:31:14 -05:00
4 changed files with 68 additions and 6 deletions

View File

@@ -283,11 +283,6 @@ func (p *BeaconDbBlocker) Blobs(ctx context.Context, id string, opts ...options.
return make([]*blocks.VerifiedROBlob, 0), nil
}
fuluForkSlot, err := slots.EpochStart(params.BeaconConfig().FuluForkEpoch)
if err != nil {
return nil, &core.RpcError{Err: errors.Wrap(err, "could not calculate Fulu start slot"), Reason: core.Internal}
}
// Convert versioned hashes to indices if provided
indices := cfg.Indices
if len(cfg.VersionedHashes) > 0 {
@@ -328,7 +323,7 @@ func (p *BeaconDbBlocker) Blobs(ctx context.Context, id string, opts ...options.
}
}
if roBlock.Slot() >= fuluForkSlot {
if roBlock.Slot() >= params.SlotOrFarFuture(params.BeaconConfig().FuluForkEpoch) {
roBlock, err := blocks.NewROBlockWithRoot(roSignedBlock, root)
if err != nil {
return nil, &core.RpcError{Err: errors.Wrapf(err, "failed to create roBlock with root %#x", root), Reason: core.Internal}

View File

@@ -587,6 +587,51 @@ func TestGetBlob(t *testing.T) {
require.Equal(t, http.StatusBadRequest, core.ErrorReasonToHTTP(rpcErr.Reason))
require.StringContains(t, "not supported before", rpcErr.Err.Error())
})
t.Run("fulu fork epoch not set (MaxUint64)", func(t *testing.T) {
// Setup with Deneb fork enabled but Fulu fork epoch set to MaxUint64 (not set/far future)
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
cfg.DenebForkEpoch = 1
cfg.FuluForkEpoch = primitives.Epoch(math.MaxUint64) // Not set / far future
params.OverrideBeaconConfig(cfg)
// Create and save Deneb block and blob sidecars
denebSlot := util.SlotAtEpoch(t, cfg.DenebForkEpoch)
_, tempBlobStorage := filesystem.NewEphemeralBlobStorageAndFs(t)
denebBlockWithBlobs, denebBlobSidecars := util.GenerateTestDenebBlockWithSidecar(t, [fieldparams.RootLength]byte{}, denebSlot, 2, util.WithDenebSlot(denebSlot))
denebBlockRoot := denebBlockWithBlobs.Root()
verifiedDenebBlobs := verification.FakeVerifySliceForTest(t, denebBlobSidecars)
for i := range verifiedDenebBlobs {
err := tempBlobStorage.Save(verifiedDenebBlobs[i])
require.NoError(t, err)
}
err := db.SaveBlock(t.Context(), denebBlockWithBlobs)
require.NoError(t, err)
blocker := &BeaconDbBlocker{
GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{
Genesis: time.Now(),
},
BeaconDB: db,
BlobStorage: tempBlobStorage,
}
// Should successfully retrieve blobs even when FuluForkEpoch is not set
retrievedBlobs, rpcErr := blocker.Blobs(ctx, hexutil.Encode(denebBlockRoot[:]))
require.IsNil(t, rpcErr)
require.Equal(t, 2, len(retrievedBlobs))
// Verify blob content matches
for i, retrievedBlob := range retrievedBlobs {
require.NotNil(t, retrievedBlob.BlobSidecar)
require.DeepEqual(t, denebBlobSidecars[i].Blob, retrievedBlob.Blob)
require.DeepEqual(t, denebBlobSidecars[i].KzgCommitment, retrievedBlob.KzgCommitment)
}
})
}
func TestBlobs_CommitmentOrdering(t *testing.T) {

View File

@@ -22,6 +22,8 @@ import (
"github.com/pkg/errors"
)
const MaxSlot = primitives.Slot(math.MaxUint64)
// BeaconChainConfig contains constant configs for node to participate in beacon chain.
type BeaconChainConfig struct {
// Constants (non-configurable)
@@ -322,6 +324,16 @@ type BeaconChainConfig struct {
forkSchedule *NetworkSchedule
bpoSchedule *NetworkSchedule
networkSchedule *NetworkSchedule
maxe primitives.Epoch
}
// MaxEpoch computes the highest epoch value that can be used without overflowing in the conversion to slots.
func (b *BeaconChainConfig) MaxEpoch() primitives.Epoch {
if b.maxe == 0 {
b.maxe = primitives.Epoch(MaxSlot / b.SlotsPerEpoch)
}
return b.maxe
}
func (b *BeaconChainConfig) VersionToForkEpochMap() map[int]primitives.Epoch {

View File

@@ -111,3 +111,13 @@ func genesisNetworkScheduleEntry() NetworkScheduleEntry {
// a properly initialized fork schedule.
return NetworkScheduleEntry{Epoch: b.GenesisEpoch, isFork: true, ForkVersion: to4(b.GenesisForkVersion), VersionEnum: version.Phase0}
}
// SlotOrFarFuture either returns the slot for the given epoch
// or the maximum slot value if the conversion to slot will overflow.
func SlotOrFarFuture(e primitives.Epoch) primitives.Slot {
cfg := BeaconConfig()
if e > cfg.MaxEpoch() {
return MaxSlot
}
return primitives.Slot(e) * cfg.SlotsPerEpoch
}