mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
eth: base protection quota on current peer count, not max capacity
protectTopN used maxPeers (configured capacity) to compute the number of peers to protect. With small droppable sets this could protect everyone, permanently disabling churn. Use len(entries) (current droppable count in each category) instead. With 20 droppable dialed peers and 10% fraction, 2 are protected. With 3 droppable peers, 0 are protected — churn is never blocked.
This commit is contained in:
parent
6d53acfa22
commit
44c8a5b7f4
2 changed files with 14 additions and 9 deletions
|
|
@ -218,8 +218,8 @@ func (cm *dropper) filterProtectedPeers(droppable []*p2p.Peer) []*p2p.Peer {
|
|||
}
|
||||
protectedSet := make(map[*p2p.Peer]struct{})
|
||||
|
||||
protectTopN := func(entries []peerWithStats, maxPeers int, cat protectionCategory) {
|
||||
n := int(float64(maxPeers) * cat.frac)
|
||||
protectTopN := func(entries []peerWithStats, cat protectionCategory) {
|
||||
n := int(float64(len(entries)) * cat.frac)
|
||||
if n == 0 || len(entries) == 0 {
|
||||
return
|
||||
}
|
||||
|
|
@ -238,8 +238,8 @@ func (cm *dropper) filterProtectedPeers(droppable []*p2p.Peer) []*p2p.Peer {
|
|||
dialCopy := make([]peerWithStats, len(dialed))
|
||||
copy(dialCopy, dialed)
|
||||
|
||||
protectTopN(inCopy, cm.maxInboundPeers, cat)
|
||||
protectTopN(dialCopy, cm.maxDialPeers, cat)
|
||||
protectTopN(inCopy, cat)
|
||||
protectTopN(dialCopy, cat)
|
||||
}
|
||||
if len(protectedSet) == 0 {
|
||||
return droppable
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func TestFilterProtectedEmptyStats(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFilterProtectedTopPeer(t *testing.T) {
|
||||
// 20 peers, maxDialPeers=20, 10% = 2 protected per category.
|
||||
// 20 peers, 10% of 20 = 2 protected per category.
|
||||
// NewPeer creates non-inbound peers, so all go to dialed bucket.
|
||||
cm := &dropper{maxDialPeers: 20, maxInboundPeers: 30}
|
||||
|
||||
|
|
@ -108,18 +108,23 @@ func TestFilterProtectedOverlap(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFilterProtectedAllProtected(t *testing.T) {
|
||||
// Only 2 droppable peers, both are top by different categories.
|
||||
// 10 peers: 10% = 1 per category. Give all 10 peers high scores in
|
||||
// one of the two categories so the union covers everyone.
|
||||
cm := &dropper{maxDialPeers: 20, maxInboundPeers: 30}
|
||||
|
||||
peers := makePeers(2)
|
||||
peers := makePeers(10)
|
||||
stats := make(map[string]PeerInclusionStats)
|
||||
// Peer 0 has the highest Finalized → protected by total-finalized.
|
||||
stats[peers[0].ID().String()] = PeerInclusionStats{Finalized: 100}
|
||||
// Peer 1 has the highest RecentIncluded → protected by recent-included.
|
||||
stats[peers[1].ID().String()] = PeerInclusionStats{RecentIncluded: 5.0}
|
||||
|
||||
cm.peerStatsFunc = func() map[string]PeerInclusionStats { return stats }
|
||||
|
||||
result := cm.filterProtectedPeers(peers)
|
||||
if len(result) != 0 {
|
||||
t.Fatalf("expected all peers protected, got %d droppable", len(result))
|
||||
// 10% of 10 = 1 per category, 2 categories = 2 protected.
|
||||
// 10 - 2 = 8 droppable.
|
||||
if len(result) != 8 {
|
||||
t.Fatalf("expected 8 droppable peers, got %d", len(result))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue