mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
eth/txtracker: prevent disconnected peers from leaking back into stats
NotifyPeerDrop deleted t.peers[peer] but left t.txs entries pointing to that peer. When those txs later finalized, checkFinalization recreated the peer entry, and the EMA loop decayed it forever. Fix: create peer entries in NotifyAccepted (when txs are first accepted), not in handleChainHead or checkFinalization. Both chain event handlers now skip peers with no entry — disconnected peers whose entries were deleted by NotifyPeerDrop stay deleted.
This commit is contained in:
parent
7f1720b3dc
commit
e2b620ab44
2 changed files with 14 additions and 11 deletions
|
|
@ -131,6 +131,10 @@ func (t *Tracker) NotifyAccepted(peer string, hashes []common.Hash) {
|
|||
t.txs[hash] = peer
|
||||
t.order = append(t.order, hash)
|
||||
}
|
||||
// Ensure the delivering peer has a stats entry.
|
||||
if len(hashes) > 0 && t.peers[peer] == nil {
|
||||
t.peers[peer] = &peerStats{}
|
||||
}
|
||||
// Evict oldest entries if over capacity.
|
||||
for len(t.txs) > maxTracked {
|
||||
oldest := t.order[0]
|
||||
|
|
@ -192,12 +196,9 @@ func (t *Tracker) handleChainHead(ev core.ChainHeadEvent) {
|
|||
blockIncl[peer]++
|
||||
}
|
||||
}
|
||||
// Ensure peers with inclusions in this block have entries.
|
||||
for peer := range blockIncl {
|
||||
if t.peers[peer] == nil {
|
||||
t.peers[peer] = &peerStats{}
|
||||
}
|
||||
}
|
||||
// Only credit peers that are still tracked (not disconnected).
|
||||
// Don't create entries for unknown peers — they may have been
|
||||
// removed by NotifyPeerDrop and should not be resurrected.
|
||||
// Update EMA for all tracked peers (decay inactive ones).
|
||||
for peer, ps := range t.peers {
|
||||
ps.recentIncluded = (1-emaAlpha)*ps.recentIncluded + emaAlpha*float64(blockIncl[peer])
|
||||
|
|
@ -231,8 +232,7 @@ func (t *Tracker) checkFinalization() {
|
|||
}
|
||||
ps := t.peers[peer]
|
||||
if ps == nil {
|
||||
ps = &peerStats{}
|
||||
t.peers[peer] = ps
|
||||
continue // peer disconnected, skip credit
|
||||
}
|
||||
ps.finalized++
|
||||
credited++
|
||||
|
|
|
|||
|
|
@ -110,10 +110,13 @@ func TestNotifyReceived(t *testing.T) {
|
|||
txs := []*types.Transaction{makeTx(1), makeTx(2), makeTx(3)}
|
||||
tr.NotifyAccepted("peerA", hashTxs(txs))
|
||||
|
||||
// No chain events yet — stats should be empty.
|
||||
// No chain events yet — peer entry exists but with zero stats.
|
||||
stats := tr.GetAllPeerStats()
|
||||
if len(stats) != 0 {
|
||||
t.Fatalf("expected empty stats before any chain events, got %d peers", len(stats))
|
||||
if stats["peerA"].Finalized != 0 {
|
||||
t.Fatalf("expected zero Finalized before chain events, got %d", stats["peerA"].Finalized)
|
||||
}
|
||||
if stats["peerA"].RecentIncluded != 0 {
|
||||
t.Fatalf("expected zero RecentIncluded before chain events, got %f", stats["peerA"].RecentIncluded)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue