network: keep track of dead peers in iteratePeersWithSendMsg()

send() can return errStateMismatch, errGone and errBusy. errGone means the
peer is dead and it won't ever be active again, it doesn't make sense retrying
sends to it. errStateMismatch is technically "not yet ready", but we can't
wait for it either, no one knows how much will it take to complete
handshake. So only errBusy means we can retry.

So keep track of dead peers and adjust tries counting appropriately.
This commit is contained in:
Roman Khimov 2021-08-06 15:25:41 +03:00
parent 80f3ec2312
commit 966a16e80e

View file

@ -1144,12 +1144,15 @@ func (s *Server) requestTx(hashes ...util.Uint256) {
// passed, one is to send the message and the other is to filtrate peers (the // passed, one is to send the message and the other is to filtrate peers (the
// peer is considered invalid if it returns false). // peer is considered invalid if it returns false).
func (s *Server) iteratePeersWithSendMsg(msg *Message, send func(Peer, bool, []byte) error, peerOK func(Peer) bool) { func (s *Server) iteratePeersWithSendMsg(msg *Message, send func(Peer, bool, []byte) error, peerOK func(Peer) bool) {
var deadN, peerN, sentN int
// Get a copy of s.peers to avoid holding a lock while sending. // Get a copy of s.peers to avoid holding a lock while sending.
peers := s.getPeers(peerOK) peers := s.getPeers(peerOK)
if len(peers) == 0 { peerN = len(peers)
if peerN == 0 {
return return
} }
mrand.Shuffle(len(peers), func(i, j int) { mrand.Shuffle(peerN, func(i, j int) {
peers[i], peers[j] = peers[j], peers[i] peers[i], peers[j] = peers[j], peers[i]
}) })
pkt, err := msg.Bytes() pkt, err := msg.Bytes()
@ -1157,39 +1160,47 @@ func (s *Server) iteratePeersWithSendMsg(msg *Message, send func(Peer, bool, []b
return return
} }
success := make([]bool, len(peers)) // If true, this node isn't counted any more, either it's dead or we
okCount := 0 // have already sent an Inv to it.
sentCount := 0 finished := make([]bool, peerN)
for i, peer := range peers { for i, peer := range peers {
okCount++ err := send(peer, false, pkt)
if err := send(peer, false, pkt); err != nil { switch err {
case nil:
if msg.Command == CMDGetAddr {
peer.AddGetAddrSent()
}
sentN++
case errBusy:
continue continue
default:
deadN++
} }
if msg.Command == CMDGetAddr { finished[i] = true
peer.AddGetAddrSent()
}
success[i] = true
sentCount++
} }
// Send to at least 2/3 of good peers. // Send to at least 2/3 of good peers.
if 3*sentCount >= 2*okCount { if 3*sentN >= 2*(peerN-deadN) {
return return
} }
// Perform blocking send now. // Perform blocking send now.
for i, peer := range peers { for i, peer := range peers {
if success[i] { if finished[i] {
continue continue
} }
if err := send(peer, true, pkt); err != nil { if err := send(peer, true, pkt); err != nil {
if err != errBusy {
deadN++
}
continue continue
} }
if msg.Command == CMDGetAddr { if msg.Command == CMDGetAddr {
peer.AddGetAddrSent() peer.AddGetAddrSent()
} }
sentCount++ sentN++
if 3*sentCount >= 2*okCount { if 3*sentN >= 2*(peerN-deadN) {
return return
} }
} }