diff --git a/server/get_header.go b/server/get_header.go index 5e89788c..dc168b32 100644 --- a/server/get_header.go +++ b/server/get_header.go @@ -62,7 +62,15 @@ func (m *BoostService) getHeader(log *logrus.Entry, slot phase0.Slot, pubkey, pa // Log how late into the slot the request starts slotStartTimestamp := m.genesisTime + uint64(slot)*config.SlotTimeSec - msIntoSlot := uint64(time.Now().UTC().UnixMilli()) - slotStartTimestamp*1000 + // The request can arrive before the slot start (e.g. scheduling jitter + // between VC and BN), which would underflow the unsigned subtraction and + // trip the late-in-slot guard below. Clamp negative values to zero, i.e. + // treat an early request as arriving exactly at slot start. + msIntoSlotSigned := time.Now().UTC().UnixMilli() - int64(slotStartTimestamp*1000) + var msIntoSlot uint64 + if msIntoSlotSigned > 0 { + msIntoSlot = uint64(msIntoSlotSigned) + } log.WithFields(logrus.Fields{ "genesisTime": m.genesisTime, "slotTimeSec": config.SlotTimeSec, diff --git a/server/service_test.go b/server/service_test.go index 5e78893d..4297e98c 100644 --- a/server/service_test.go +++ b/server/service_test.go @@ -326,6 +326,22 @@ func TestGetHeader(t *testing.T) { require.Equal(t, 1, backend.relays[0].GetRequestCount(path)) }) + t.Run("Request arriving before slot start still queries relays", func(t *testing.T) { + header := make(http.Header) + header.Set(HeaderAccept, MediaTypeJSON) + + backend := newTestBackend(t, 1, time.Second) + // setting genesisTime so slot 1 starts several seconds in the future, + // making msIntoSlot reliably negative regardless of the Unix() + // second-truncation. Without clamping, the unsigned subtraction wraps + // and the late-in-slot guard skips all relays. + backend.boost.genesisTime = uint64(time.Now().Unix()) - 7 + + rr := backend.request(t, http.MethodGet, path, header, nil) + require.Equal(t, http.StatusOK, rr.Code, rr.Body.String()) + require.Equal(t, 1, backend.relays[0].GetRequestCount(path)) + }) + t.Run("Okay response from relay deneb", func(t *testing.T) { header := make(http.Header) header.Set(HeaderAccept, MediaTypeJSON)