Simplify fcu 4 (#13403)

* send two FCU when proposing

* compute voting window at runtime
This commit is contained in:
Potuz 2024-01-04 10:43:57 -03:00 committed by GitHub
parent d5107942a1
commit 396b8bf970
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 37 deletions

View File

@ -103,30 +103,6 @@ func (s *Service) postBlockProcess(ctx context.Context, signed interfaces.ReadOn
proposingSlot: proposingSlot,
}
} else {
// Updating next slot state cache can happen in the background
// except in the epoch boundary in which case we lock to handle
// the shuffling and proposer caches updates.
// We handle these caches only on canonical
// blocks, otherwise this will be handled by lateBlockTasks
slot := postState.Slot()
if slots.IsEpochEnd(slot) {
if err := transition.UpdateNextSlotCache(ctx, blockRoot[:], postState); err != nil {
return errors.Wrap(err, "could not update next slot state cache")
}
if err := s.handleEpochBoundary(ctx, slot, postState, blockRoot[:]); err != nil {
return errors.Wrap(err, "could not handle epoch boundary")
}
} else {
go func() {
slotCtx, cancel := context.WithTimeout(context.Background(), slotDeadline)
defer cancel()
if err := transition.UpdateNextSlotCache(slotCtx, blockRoot[:], postState); err != nil {
log.WithError(err).Error("could not update next slot state cache")
}
}()
}
// verify conditions for FCU, notifies FCU, and saves the new head.
// This function also prunes attestations, other similar operations happen in prunePostBlockOperationPools.
fcuArgs = &fcuConfig{
headState: postState,
headBlock: signed,
@ -134,8 +110,27 @@ func (s *Service) postBlockProcess(ctx context.Context, signed interfaces.ReadOn
proposingSlot: proposingSlot,
}
}
if s.isNewHead(headRoot) {
isEarly := slots.WithinVotingWindow(uint64(s.genesisTime.Unix()))
shouldOverrideFCU := false
slot := postState.Slot()
if s.isNewHead(headRoot) {
// if the block is early send FCU without any payload attributes
if isEarly {
if err := s.forkchoiceUpdateWithExecution(ctx, fcuArgs); err != nil {
return err
}
} else {
// if the block is late lock and update the caches
if blockRoot == headRoot {
if err := transition.UpdateNextSlotCache(ctx, blockRoot[:], postState); err != nil {
return errors.Wrap(err, "could not update next slot state cache")
}
if slots.IsEpochEnd(slot) {
if err := s.handleEpochBoundary(ctx, slot, postState, blockRoot[:]); err != nil {
return errors.Wrap(err, "could not handle epoch boundary")
}
}
}
_, tracked := s.trackedProposer(fcuArgs.headState, proposingSlot)
if tracked {
shouldOverrideFCU = s.shouldOverrideFCU(headRoot, proposingSlot)
@ -147,6 +142,7 @@ func (s *Service) postBlockProcess(ctx context.Context, signed interfaces.ReadOn
}
}
}
}
optimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(blockRoot)
if err != nil {
log.WithError(err).Debug("Could not check if block is optimistic")
@ -163,7 +159,29 @@ func (s *Service) postBlockProcess(ctx context.Context, signed interfaces.ReadOn
Optimistic: optimistic,
},
})
if blockRoot == headRoot && isEarly {
go func() {
slotCtx, cancel := context.WithTimeout(context.Background(), slotDeadline)
defer cancel()
if err := transition.UpdateNextSlotCache(slotCtx, blockRoot[:], postState); err != nil {
log.WithError(err).Error("could not update next slot state cache")
}
if slots.IsEpochEnd(slot) {
if err := s.handleEpochBoundary(ctx, slot, postState, blockRoot[:]); err != nil {
log.WithError(err).Error("could not handle epoch boundary")
}
}
if _, tracked := s.trackedProposer(fcuArgs.headState, proposingSlot); !tracked {
return
}
fcuArgs.attributes = s.getPayloadAttribute(ctx, fcuArgs.headState, proposingSlot, headRoot[:])
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
if _, err := s.notifyForkchoiceUpdate(ctx, fcuArgs); err != nil {
log.WithError(err).Error("could not update forkchoice with payload attributes for proposal")
}
}()
}
defer reportAttestationInclusion(b)
onBlockProcessingTime.Observe(float64(time.Since(startTime).Milliseconds()))
return nil

View File

@ -2045,7 +2045,7 @@ func TestFillMissingBlockPayloadId_PrepareAllPayloads(t *testing.T) {
// Helper function to simulate the block being on time or delayed for proposer
// boost. It alters the genesisTime tracked by the store.
func driftGenesisTime(s *Service, slot, delay int64) {
offset := slot*int64(params.BeaconConfig().SecondsPerSlot) - delay
offset := slot*int64(params.BeaconConfig().SecondsPerSlot) + delay
s.SetGenesisTime(time.Unix(time.Now().Unix()-offset, 0))
}

View File

@ -302,7 +302,7 @@ func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconSt
return pid, nil
}
if err := UpdateProposerIndicesInCache(ctx, state, e); err != nil {
return 0, errors.Wrap(err, "could not update committee cache")
return 0, errors.Wrap(err, "could not update proposer index cache")
}
pid, err = cachedProposerIndexAtSlot(slot, [32]byte(r))
if err == nil {

View File

@ -16,9 +16,6 @@ import (
// incoming objects. (24 mins with mainnet spec)
const MaxSlotBuffer = uint64(1 << 7)
// votingWindow specifies the deadline for attestations
var votingWindow = params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
// startFromTime returns the slot start in terms of genesis time.Time
func startFromTime(genesis time.Time, slot primitives.Slot) time.Time {
duration := time.Second * time.Duration(slot.Mul(params.BeaconConfig().SecondsPerSlot))
@ -271,5 +268,6 @@ func TimeIntoSlot(genesisTime uint64) time.Duration {
// WithinVotingWindow returns whether the current time is within the voting window
// (eg. 4 seconds on mainnet) of the current slot.
func WithinVotingWindow(genesisTime uint64) bool {
votingWindow := params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
return TimeIntoSlot(genesisTime) < time.Duration(votingWindow)*time.Second
}