diff --git a/beacon-chain/blockchain/head_sync_committee_info.go b/beacon-chain/blockchain/head_sync_committee_info.go index 7d2e5266a..aac515071 100644 --- a/beacon-chain/blockchain/head_sync_committee_info.go +++ b/beacon-chain/blockchain/head_sync_committee_info.go @@ -157,11 +157,9 @@ func (s *Service) getSyncCommitteeHeadState(ctx context.Context, slot types.Slot if headState == nil || headState.IsNil() { return nil, errors.New("nil state") } - if slot > headState.Slot() { - headState, err = transition.ProcessSlots(ctx, headState, slot) - if err != nil { - return nil, err - } + headState, err = transition.ProcessSlotsIfPossible(ctx, headState, slot) + if err != nil { + return nil, err } syncHeadStateMiss.Inc() err = syncCommitteeHeadStateCache.Put(slot, headState) diff --git a/beacon-chain/blockchain/process_attestation_helpers.go b/beacon-chain/blockchain/process_attestation_helpers.go index 20f81d2c3..2bdf76342 100644 --- a/beacon-chain/blockchain/process_attestation_helpers.go +++ b/beacon-chain/blockchain/process_attestation_helpers.go @@ -42,11 +42,9 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (stat if err != nil { return nil, err } - if epochStartSlot > baseState.Slot() { - baseState, err = transition.ProcessSlots(ctx, baseState, epochStartSlot) - if err != nil { - return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch) - } + baseState, err = transition.ProcessSlotsIfPossible(ctx, baseState, epochStartSlot) + if err != nil { + return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch) } // Sharing the same state across caches is perfectly fine here, the fetching diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index 43a64ae40..4b32ee836 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -151,15 +151,22 @@ func ProcessSlotsUsingNextSlotCache( // Since next slot cache only advances state by 1 slot, // we check if there's more slots that need to process. - if slot > parentState.Slot() { - parentState, err = ProcessSlots(ctx, parentState, slot) - if err != nil { - return nil, errors.Wrap(err, "could not process slots") - } + parentState, err = ProcessSlotsIfPossible(ctx, parentState, slot) + if err != nil { + return nil, errors.Wrap(err, "could not process slots") } return parentState, nil } +// ProcessSlotsIfPossible executes ProcessSlots on the input state when target slot is above the state's slot. +// Otherwise, it returns the input state unchanged. +func ProcessSlotsIfPossible(ctx context.Context, state state.BeaconState, targetSlot types.Slot) (state.BeaconState, error) { + if targetSlot > state.Slot() { + return ProcessSlots(ctx, state, targetSlot) + } + return state, nil +} + // ProcessSlots process through skip slots and apply epoch transition when it's needed // // Spec pseudocode definition: diff --git a/beacon-chain/core/transition/transition_test.go b/beacon-chain/core/transition/transition_test.go index 77aa55004..19212e021 100644 --- a/beacon-chain/core/transition/transition_test.go +++ b/beacon-chain/core/transition/transition_test.go @@ -610,3 +610,29 @@ func TestProcessSlotsUsingNextSlotCache(t *testing.T) { require.NoError(t, err) require.Equal(t, types.Slot(5), s.Slot()) } + +func TestProcessSlotsConditionally(t *testing.T) { + ctx := context.Background() + s, _ := util.DeterministicGenesisState(t, 1) + + t.Run("target slot below current slot", func(t *testing.T) { + require.NoError(t, s.SetSlot(5)) + s, err := transition.ProcessSlotsIfPossible(ctx, s, 4) + require.NoError(t, err) + assert.Equal(t, types.Slot(5), s.Slot()) + }) + + t.Run("target slot equal current slot", func(t *testing.T) { + require.NoError(t, s.SetSlot(5)) + s, err := transition.ProcessSlotsIfPossible(ctx, s, 5) + require.NoError(t, err) + assert.Equal(t, types.Slot(5), s.Slot()) + }) + + t.Run("target slot above current slot", func(t *testing.T) { + require.NoError(t, s.SetSlot(5)) + s, err := transition.ProcessSlotsIfPossible(ctx, s, 6) + require.NoError(t, err) + assert.Equal(t, types.Slot(6), s.Slot()) + }) +} diff --git a/beacon-chain/rpc/eth/validator/validator.go b/beacon-chain/rpc/eth/validator/validator.go index 1376da661..f7fcd954c 100644 --- a/beacon-chain/rpc/eth/validator/validator.go +++ b/beacon-chain/rpc/eth/validator/validator.go @@ -666,11 +666,9 @@ func advanceState(ctx context.Context, s state.BeaconState, requestedEpoch, curr return nil, errors.Wrap(err, "Could not obtain epoch's start slot") } } - if s.Slot() < epochStartSlot { - s, err = transition.ProcessSlots(ctx, s, epochStartSlot) - if err != nil { - return nil, errors.Wrapf(err, "Could not process slots up to %d", epochStartSlot) - } + s, err = transition.ProcessSlotsIfPossible(ctx, s, epochStartSlot) + if err != nil { + return nil, errors.Wrapf(err, "Could not process slots up to %d", epochStartSlot) } return s, nil