beacon/light: request finality update explicitly when necessary

This commit is contained in:
Zsolt Felfoldi 2024-04-17 18:19:06 +02:00
parent 673975b5fa
commit ec3a815196
5 changed files with 23 additions and 4 deletions

View file

@ -139,7 +139,6 @@ func (s *beaconBlockSync) updateEventFeed() {
parent, ok := s.recentBlocks.Get(optimistic.Attested.ParentRoot) parent, ok := s.recentBlocks.Get(optimistic.Attested.ParentRoot)
if !ok || parent.Slot()/params.EpochLength == fe { if !ok || parent.Slot()/params.EpochLength == fe {
return // head is at first slot of next epoch, wait for finality update return // head is at first slot of next epoch, wait for finality update
//TODO: try to fetch finality update directly if subscription does not deliver
} }
} }
} }

View file

@ -83,6 +83,9 @@ func (s *ApiServer) SendRequest(id request.ID, req request.Request) {
case sync.ReqBeaconBlock: case sync.ReqBeaconBlock:
log.Debug("Beacon API: requesting block", "reqid", id, "hash", common.Hash(data)) log.Debug("Beacon API: requesting block", "reqid", id, "hash", common.Hash(data))
resp, err = s.api.GetBeaconBlock(common.Hash(data)) resp, err = s.api.GetBeaconBlock(common.Hash(data))
case sync.ReqFinality:
log.Debug("Beacon API: requesting finality update")
resp, err = s.api.GetFinalityUpdate()
default: default:
} }

View file

@ -548,7 +548,7 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
// established. It can only return nil when the context is canceled. // established. It can only return nil when the context is canceled.
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream { func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) { for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) {
path := "/eth/v1/events?topics=head&topics=light_client_optimistic_update&topics=light_client_finality_update" path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update"
log.Debug("Sending event subscription request") log.Debug("Sending event subscription request")
req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil) req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil)
if err != nil { if err != nil {

View file

@ -24,7 +24,8 @@ import (
type headTracker interface { type headTracker interface {
ValidateOptimistic(update types.OptimisticUpdate) (bool, error) ValidateOptimistic(update types.OptimisticUpdate) (bool, error)
ValidateFinality(update types.FinalityUpdate) (bool, error) ValidateFinality(head types.FinalityUpdate) (bool, error)
ValidatedFinality() (types.FinalityUpdate, bool)
SetPrefetchHead(head types.HeadInfo) SetPrefetchHead(head types.HeadInfo)
} }
@ -41,6 +42,7 @@ type HeadSync struct {
unvalidatedOptimistic map[request.Server]types.OptimisticUpdate unvalidatedOptimistic map[request.Server]types.OptimisticUpdate
unvalidatedFinality map[request.Server]types.FinalityUpdate unvalidatedFinality map[request.Server]types.FinalityUpdate
serverHeads map[request.Server]types.HeadInfo serverHeads map[request.Server]types.HeadInfo
reqFinalityEpoch map[request.Server]uint64 // next epoch to request finality update
headServerCount map[types.HeadInfo]headServerCount headServerCount map[types.HeadInfo]headServerCount
headCounter uint64 headCounter uint64
prefetchHead types.HeadInfo prefetchHead types.HeadInfo
@ -64,6 +66,7 @@ func NewHeadSync(headTracker headTracker, chain committeeChain) *HeadSync {
unvalidatedFinality: make(map[request.Server]types.FinalityUpdate), unvalidatedFinality: make(map[request.Server]types.FinalityUpdate),
serverHeads: make(map[request.Server]types.HeadInfo), serverHeads: make(map[request.Server]types.HeadInfo),
headServerCount: make(map[types.HeadInfo]headServerCount), headServerCount: make(map[types.HeadInfo]headServerCount),
reqFinalityEpoch: make(map[request.Server]uint64),
} }
return s return s
} }
@ -75,9 +78,22 @@ func (s *HeadSync) Process(requester request.Requester, events []request.Event)
case EvNewHead: case EvNewHead:
s.setServerHead(event.Server, event.Data.(types.HeadInfo)) s.setServerHead(event.Server, event.Data.(types.HeadInfo))
case EvNewOptimisticUpdate: case EvNewOptimisticUpdate:
s.newOptimisticUpdate(event.Server, event.Data.(types.OptimisticUpdate)) update := event.Data.(types.OptimisticUpdate)
s.newOptimisticUpdate(event.Server, update)
epoch := update.Attested.Epoch()
if epoch < s.reqFinalityEpoch[event.Server] {
continue
}
if finality, ok := s.headTracker.ValidatedFinality(); ok && finality.Attested.Header.Epoch() >= epoch {
continue
}
requester.Send(event.Server, ReqFinality{})
s.reqFinalityEpoch[event.Server] = epoch + 1
case EvNewFinalityUpdate: case EvNewFinalityUpdate:
s.newFinalityUpdate(event.Server, event.Data.(types.FinalityUpdate)) s.newFinalityUpdate(event.Server, event.Data.(types.FinalityUpdate))
case request.EvResponse:
_, _, resp := event.RequestInfo()
s.newFinalityUpdate(event.Server, resp.(types.FinalityUpdate))
case request.EvUnregistered: case request.EvUnregistered:
s.setServerHead(event.Server, types.HeadInfo{}) s.setServerHead(event.Server, types.HeadInfo{})
delete(s.serverHeads, event.Server) delete(s.serverHeads, event.Server)

View file

@ -43,4 +43,5 @@ type (
} }
ReqCheckpointData common.Hash ReqCheckpointData common.Hash
ReqBeaconBlock common.Hash ReqBeaconBlock common.Hash
ReqFinality struct{}
) )