From ecfdaa69c6abda07b8b721fcdcdd184cd176201d Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 10 Apr 2026 12:07:19 +0200 Subject: [PATCH] eth: replace topN helper with stdlib slices.SortedFunc + DeleteFunc Remove the custom topN generic function. Use slices.SortedFunc (creates a sorted copy from an iterator) + slices.DeleteFunc (filters score <= 0) from the standard library. No custom generics needed. --- eth/dropper.go | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/eth/dropper.go b/eth/dropper.go index 6a8554eb83..2c73396065 100644 --- a/eth/dropper.go +++ b/eth/dropper.go @@ -17,9 +17,9 @@ package eth import ( + "cmp" mrand "math/rand" "slices" - "sort" "sync" "time" @@ -189,25 +189,6 @@ func (cm *dropper) dropRandomPeer() bool { return true } -// topN returns the top n elements from items by score (descending). -// Only elements with score > 0 are included. The input slice is not modified. -func topN[T any](items []T, n int, score func(T) float64) []T { - if n == 0 || len(items) == 0 { - return nil - } - cp := make([]T, len(items)) - copy(cp, items) - sort.Slice(cp, func(i, j int) bool { return score(cp[i]) > score(cp[j]) }) - - var result []T - for i := 0; i < n && i < len(cp); i++ { - if score(cp[i]) > 0 { - result = append(result, cp[i]) - } - } - return result -} - // protectedPeers computes the set of peers that should not be dropped based // on inclusion stats. Each protection category independently selects its // top-N peers per inbound/dialed pool; the union is returned. @@ -228,18 +209,29 @@ func (cm *dropper) protectedPeers(peers []*p2p.Peer) map[*p2p.Peer]bool { dialed = append(dialed, p) } } + // protectPool selects the top-frac peers from pool by score and adds them to result. result := make(map[*p2p.Peer]bool) + protectPool := func(pool []*p2p.Peer, score func(*p2p.Peer) float64, frac float64) { + n := int(float64(len(pool)) * frac) + if n == 0 { + return + } + sorted := slices.SortedFunc(slices.Values(pool), func(a, b *p2p.Peer) int { + return cmp.Compare(score(b), score(a)) // descending + }) + top := slices.DeleteFunc(sorted[:min(n, len(sorted))], func(p *p2p.Peer) bool { + return score(p) <= 0 + }) + for _, p := range top { + result[p] = true + } + } for _, cat := range protectionCategories { - // Build a score function that looks up the peer's stats. score := func(p *p2p.Peer) float64 { return cat.score(stats[p.ID().String()]) } - for _, p := range topN(inbound, int(float64(len(inbound))*cat.frac), score) { - result[p] = true - } - for _, p := range topN(dialed, int(float64(len(dialed))*cat.frac), score) { - result[p] = true - } + protectPool(inbound, score, cat.frac) + protectPool(dialed, score, cat.frac) } if len(result) > 0 { log.Debug("Protecting high-value peers from drop", "protected", len(result))