beacon/light: use explicit request/response types where possible

This commit is contained in:
Zsolt Felfoldi 2024-01-26 02:03:00 +01:00 committed by Felix Lange
parent 245d166d45
commit 084f23cfa0
3 changed files with 55 additions and 66 deletions

View file

@ -360,11 +360,7 @@ func (s *Scheduler) filterEvents() map[Module][]Event {
filteredEvents := make(map[Module][]Event) filteredEvents := make(map[Module][]Event)
for _, event := range events { for _, event := range events {
server, ok := event.Server.(server) server := event.Server.(server)
if !ok {
log.Error("Server interface type unknown for Scheduler")
continue
}
if _, ok := s.servers[server]; !ok && event.Type != EvRegistered { if _, ok := s.servers[server]; !ok && event.Type != EvRegistered {
continue // before EvRegister or after EvUnregister, discard continue // before EvRegister or after EvUnregister, discard
} }

View file

@ -66,7 +66,7 @@ func (s *CheckpointInit) Process(events []request.Event) {
s.locked = request.ServerAndID{} s.locked = request.ServerAndID{}
} }
if resp != nil { if resp != nil {
if checkpoint, ok := resp.(*types.BootstrapData); ok && checkpoint.Header.Hash() == common.Hash(req.(ReqCheckpointData)) { if checkpoint := resp.(*types.BootstrapData); checkpoint.Header.Hash() == common.Hash(req.(ReqCheckpointData)) {
s.chain.CheckpointInit(*checkpoint) s.chain.CheckpointInit(*checkpoint)
s.initialized = true s.initialized = true
return return
@ -93,7 +93,7 @@ type ForwardUpdateSync struct {
chain committeeChain chain committeeChain
rangeLock rangeLock rangeLock rangeLock
lockedIDs map[request.ServerAndID]struct{} lockedIDs map[request.ServerAndID]struct{}
processQueue []request.Event processQueue []updateResponse
nextSyncPeriod map[request.Server]uint64 nextSyncPeriod map[request.Server]uint64
} }
@ -147,37 +147,27 @@ func (r rangeLock) firstUnlocked(start, maxCount uint64) (first, count uint64) {
// lockRange locks the range belonging to the given update request, unless the // lockRange locks the range belonging to the given update request, unless the
// same request has already been locked // same request has already been locked
func (s *ForwardUpdateSync) lockRange(sid request.ServerAndID, req request.Request) { func (s *ForwardUpdateSync) lockRange(sid request.ServerAndID, req ReqUpdates) {
if _, ok := s.lockedIDs[sid]; ok { if _, ok := s.lockedIDs[sid]; ok {
return return
} }
s.lockedIDs[sid] = struct{}{} s.lockedIDs[sid] = struct{}{}
r := req.(ReqUpdates) s.rangeLock.lock(req.FirstPeriod, req.Count, 1)
s.rangeLock.lock(r.FirstPeriod, r.Count, 1)
} }
// unlockRange unlocks the range belonging to the given update request, unless // unlockRange unlocks the range belonging to the given update request, unless
// same request has already been unlocked // same request has already been unlocked
func (s *ForwardUpdateSync) unlockRange(sid request.ServerAndID, req request.Request) { func (s *ForwardUpdateSync) unlockRange(sid request.ServerAndID, req ReqUpdates) {
if _, ok := s.lockedIDs[sid]; !ok { if _, ok := s.lockedIDs[sid]; !ok {
return return
} }
delete(s.lockedIDs, sid) delete(s.lockedIDs, sid)
r := req.(ReqUpdates) s.rangeLock.lock(req.FirstPeriod, req.Count, -1)
s.rangeLock.lock(r.FirstPeriod, r.Count, -1)
} }
// verifyRange returns true if the number of updates and the individual update // verifyRange returns true if the number of updates and the individual update
// periods in the response match the requested section. // periods in the response match the requested section.
func (s *ForwardUpdateSync) verifyRange(req request.Request, resp request.Response) bool { func (s *ForwardUpdateSync) verifyRange(request ReqUpdates, response RespUpdates) bool {
request, ok := req.(ReqUpdates)
if !ok {
return false
}
response, ok := resp.(RespUpdates)
if !ok {
return false
}
if uint64(len(response.Updates)) != request.Count || uint64(len(response.Committees)) != request.Count { if uint64(len(response.Updates)) != request.Count || uint64(len(response.Committees)) != request.Count {
return false return false
} }
@ -189,41 +179,19 @@ func (s *ForwardUpdateSync) verifyRange(req request.Request, resp request.Respon
return true return true
} }
// processResponse adds the fetched updates and committees to the committee chain. type updateResponse struct {
// Returns true in case of full or partial success. sid request.ServerAndID
func (s *ForwardUpdateSync) processResponse(event request.Event) (success bool) { request ReqUpdates
_, _, resp := event.RequestInfo() response RespUpdates
response, ok := resp.(RespUpdates)
if !ok {
return false
}
for i, update := range response.Updates {
if err := s.chain.InsertUpdate(update, response.Committees[i]); err != nil {
if err == light.ErrInvalidPeriod {
// there is a gap in the update periods; stop processing without
// failing and try again next time
return
}
if err == light.ErrInvalidUpdate || err == light.ErrWrongCommitteeRoot || err == light.ErrCannotReorg {
event.Server.Fail("invalid update received")
} else {
log.Error("Unexpected InsertUpdate error", "error", err)
}
return
}
success = true
}
return
} }
// updateResponseList implements sort.Sort and sorts update request/response events by FirstPeriod. // updateResponseList implements sort.Sort and sorts update request/response events by FirstPeriod.
type updateResponseList []request.Event type updateResponseList []updateResponse
func (u updateResponseList) Len() int { return len(u) } func (u updateResponseList) Len() int { return len(u) }
func (u updateResponseList) Swap(i, j int) { u[i], u[j] = u[j], u[i] } func (u updateResponseList) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
func (u updateResponseList) Less(i, j int) bool { func (u updateResponseList) Less(i, j int) bool {
return u[i].Data.(request.RequestResponse).Request.(ReqUpdates).FirstPeriod < return u[i].request.FirstPeriod < u[j].request.FirstPeriod
u[j].Data.(request.RequestResponse).Request.(ReqUpdates).FirstPeriod
} }
func (s *ForwardUpdateSync) Process(events []request.Event) { func (s *ForwardUpdateSync) Process(events []request.Event) {
@ -231,18 +199,23 @@ func (s *ForwardUpdateSync) Process(events []request.Event) {
switch event.Type { switch event.Type {
case request.EvRequest: case request.EvRequest:
sid, req, _ := event.RequestInfo() sid, req, _ := event.RequestInfo()
s.lockRange(sid, req) s.lockRange(sid, req.(ReqUpdates))
case request.EvResponse, request.EvFail, request.EvTimeout: case request.EvResponse, request.EvFail, request.EvTimeout:
sid, req, resp := event.RequestInfo() sid, rq, rs := event.RequestInfo()
if event.Type == request.EvResponse && !s.verifyRange(req, resp) { req := rq.(ReqUpdates)
event.Server.Fail("invalid update range") var queued bool
resp = nil if event.Type == request.EvResponse {
resp := rs.(RespUpdates)
if s.verifyRange(req, resp) {
// there is a response with a valid format; put it in the process queue
s.processQueue = append(s.processQueue, updateResponse{sid: sid, request: req, response: resp})
s.lockRange(sid, req)
queued = true
} else {
event.Server.Fail("invalid update range")
}
} }
if resp != nil { if !queued {
// there is a response with a valid format; put it in the process queue
s.processQueue = append(s.processQueue, event)
s.lockRange(sid, req)
} else {
s.unlockRange(sid, req) s.unlockRange(sid, req)
} }
case EvNewSignedHead: case EvNewSignedHead:
@ -256,12 +229,11 @@ func (s *ForwardUpdateSync) Process(events []request.Event) {
// try processing ordered list of available responses // try processing ordered list of available responses
sort.Sort(updateResponseList(s.processQueue)) sort.Sort(updateResponseList(s.processQueue))
for s.processQueue != nil { for s.processQueue != nil {
event := s.processQueue[0] u := s.processQueue[0]
if !s.processResponse(event) { if !s.processResponse(u) {
return return
} }
sid, req, _ := event.RequestInfo() s.unlockRange(u.sid, u.request)
s.unlockRange(sid, req)
s.processQueue = s.processQueue[1:] s.processQueue = s.processQueue[1:]
if len(s.processQueue) == 0 { if len(s.processQueue) == 0 {
s.processQueue = nil s.processQueue = nil
@ -269,6 +241,28 @@ func (s *ForwardUpdateSync) Process(events []request.Event) {
} }
} }
// processResponse adds the fetched updates and committees to the committee chain.
// Returns true in case of full or partial success.
func (s *ForwardUpdateSync) processResponse(u updateResponse) (success bool) {
for i, update := range u.response.Updates {
if err := s.chain.InsertUpdate(update, u.response.Committees[i]); err != nil {
if err == light.ErrInvalidPeriod {
// there is a gap in the update periods; stop processing without
// failing and try again next time
return
}
if err == light.ErrInvalidUpdate || err == light.ErrWrongCommitteeRoot || err == light.ErrCannotReorg {
u.sid.Server.Fail("invalid update received")
} else {
log.Error("Unexpected InsertUpdate error", "error", err)
}
return
}
success = true
}
return
}
func (s *ForwardUpdateSync) MakeRequest(server request.Server) (request.Request, float32) { func (s *ForwardUpdateSync) MakeRequest(server request.Server) (request.Request, float32) {
startPeriod, chainInit := s.chain.NextSyncPeriod() startPeriod, chainInit := s.chain.NextSyncPeriod()
if !chainInit { if !chainInit {

View file

@ -70,8 +70,7 @@ func (s *beaconBlockSync) Process(events []request.Event) {
_, req, resp := event.RequestInfo() _, req, resp := event.RequestInfo()
blockRoot := common.Hash(req.(sync.ReqBeaconBlock)) blockRoot := common.Hash(req.(sync.ReqBeaconBlock))
if resp != nil { if resp != nil {
block := resp.(*capella.BeaconBlock) s.recentBlocks.Add(blockRoot, resp.(*capella.BeaconBlock))
s.recentBlocks.Add(blockRoot, block)
} }
delete(s.locked, blockRoot) delete(s.locked, blockRoot)
case sync.EvNewHead: case sync.EvNewHead: