diff --git a/beacon-chain/core/time/slot_epoch.go b/beacon-chain/core/time/slot_epoch.go index ad762db131..c38ea5b4b0 100644 --- a/beacon-chain/core/time/slot_epoch.go +++ b/beacon-chain/core/time/slot_epoch.go @@ -60,6 +60,16 @@ func CanUpgradeToAltair(slot types.Slot) bool { return epochStart && altairEpoch } +// CanUpgradeToMerge returns true if the input `slot` can upgrade to Merge fork. +// +// Spec code: +// If state.slot % SLOTS_PER_EPOCH == 0 and compute_epoch_at_slot(state.slot) == MERGE_FORK_EPOCH +func CanUpgradeToMerge(slot types.Slot) bool { + epochStart := slots.IsEpochStart(slot) + mergeEpoch := slots.ToEpoch(slot) == params.BeaconConfig().MergeForkEpoch + return epochStart && mergeEpoch +} + // CanProcessEpoch checks the eligibility to process epoch. // The epoch can be processed at the end of the last slot of every epoch. // diff --git a/beacon-chain/core/time/slot_epoch_test.go b/beacon-chain/core/time/slot_epoch_test.go index d6aacb653f..de1aa7fe1b 100644 --- a/beacon-chain/core/time/slot_epoch_test.go +++ b/beacon-chain/core/time/slot_epoch_test.go @@ -114,6 +114,40 @@ func TestCanUpgradeToAltair(t *testing.T) { } } +func TestCanUpgradeToMerge(t *testing.T) { + bc := params.BeaconConfig() + bc.MergeForkEpoch = 5 + params.OverrideBeaconConfig(bc) + tests := []struct { + name string + slot types.Slot + want bool + }{ + { + name: "not epoch start", + slot: 1, + want: false, + }, + { + name: "not merge epoch", + slot: params.BeaconConfig().SlotsPerEpoch, + want: false, + }, + { + name: "merge epoch", + slot: types.Slot(params.BeaconConfig().MergeForkEpoch) * params.BeaconConfig().SlotsPerEpoch, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := CanUpgradeToMerge(tt.slot); got != tt.want { + t.Errorf("CanUpgradeToMerge() = %v, want %v", got, tt.want) + } + }) + } +} + func TestCanProcessEpoch_TrueOnEpochsLastSlot(t *testing.T) { tests := []struct { slot types.Slot