From e99ad3675b5d7e8d2eda365e388862f9fe7bd8fd Mon Sep 17 00:00:00 2001 From: Ilya Lukyanov Date: Wed, 18 Feb 2026 12:22:03 +0000 Subject: [PATCH] Fix memory leak in payloadAttributes map cleanup ## Summary - Fix payloadAttributes map entries never being deleted due to incorrect key construction in cleanup loop - Close gzip reader in handleSubmitNewBlock to return flate decompressor to sync.Pool ## Motivation and Context The builder API service exhibited a memory leak. The range variable in the cleanup loop held the full map key ("{parentHash}-{slot}"), but was passed to getPayloadAttributesKey which appended the slot again, producing a key that never matched any entry. Co-Authored-By: Claude Opus 4.6 --- services/api/service.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/api/service.go b/services/api/service.go index 0a23aecd..ca664936 100644 --- a/services/api/service.go +++ b/services/api/service.go @@ -801,9 +801,9 @@ func (api *RelayAPI) processPayloadAttributes(payloadAttributes beaconclient.Pay defer api.payloadAttributesLock.Unlock() // Step 1: clean up old ones - for parentBlockHash, attr := range api.payloadAttributes { + for key, attr := range api.payloadAttributes { if attr.slot < apiHeadSlot { - delete(api.payloadAttributes, getPayloadAttributesKey(parentBlockHash, attr.slot)) + delete(api.payloadAttributes, key) } } @@ -2250,12 +2250,14 @@ func (api *RelayAPI) handleSubmitNewBlock(w http.ResponseWriter, req *http.Reque pf.IsGzip = isGzip log = log.WithField("reqIsGzip", isGzip) if isGzip { - r, err = gzip.NewReader(req.Body) + gzipReader, err := gzip.NewReader(req.Body) if err != nil { log.WithError(err).Warn("could not create gzip reader") api.RespondError(w, http.StatusBadRequest, err.Error()) return } + defer gzipReader.Close() //nolint:errcheck + r = gzipReader } limitReader := io.LimitReader(r, int64(apiMaxPayloadBytes))