Skip to content

Commit

Permalink
Simplify fcu 4 (#13403)
Browse files Browse the repository at this point in the history
* send two FCU when proposing

* compute voting window at runtime
  • Loading branch information
potuz authored Jan 4, 2024
1 parent d510794 commit 396b8bf
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 37 deletions.
82 changes: 50 additions & 32 deletions beacon-chain/blockchain/process_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,48 +103,44 @@ 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,
headRoot: headRoot,
proposingSlot: proposingSlot,
}
}
isEarly := slots.WithinVotingWindow(uint64(s.genesisTime.Unix()))
shouldOverrideFCU := false
slot := postState.Slot()
if s.isNewHead(headRoot) {
shouldOverrideFCU := false
_, tracked := s.trackedProposer(fcuArgs.headState, proposingSlot)
if tracked {
shouldOverrideFCU = s.shouldOverrideFCU(headRoot, proposingSlot)
fcuArgs.attributes = s.getPayloadAttribute(ctx, fcuArgs.headState, proposingSlot, headRoot[:])
}
if !shouldOverrideFCU {
// 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)
fcuArgs.attributes = s.getPayloadAttribute(ctx, fcuArgs.headState, proposingSlot, headRoot[:])
}
if !shouldOverrideFCU {
if err := s.forkchoiceUpdateWithExecution(ctx, fcuArgs); err != nil {
return err
}
}
}
}
optimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(blockRoot)
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/process_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/helpers/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 1 addition & 3 deletions time/slots/slottime.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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
}

0 comments on commit 396b8bf

Please sign in to comment.