From 966a16e80eb7149e2559d231d7decbdf80b6e53c Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 6 Aug 2021 15:25:41 +0300 Subject: [PATCH] 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. --- pkg/network/server.go | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/pkg/network/server.go b/pkg/network/server.go index 2818d5de7..268abb175 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -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 // peer is considered invalid if it returns false). 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. peers := s.getPeers(peerOK) - if len(peers) == 0 { + peerN = len(peers) + if peerN == 0 { return } - mrand.Shuffle(len(peers), func(i, j int) { + mrand.Shuffle(peerN, func(i, j int) { peers[i], peers[j] = peers[j], peers[i] }) pkt, err := msg.Bytes() @@ -1157,39 +1160,47 @@ func (s *Server) iteratePeersWithSendMsg(msg *Message, send func(Peer, bool, []b return } - success := make([]bool, len(peers)) - okCount := 0 - sentCount := 0 + // If true, this node isn't counted any more, either it's dead or we + // have already sent an Inv to it. + finished := make([]bool, peerN) + for i, peer := range peers { - okCount++ - if err := send(peer, false, pkt); err != nil { + err := send(peer, false, pkt) + switch err { + case nil: + if msg.Command == CMDGetAddr { + peer.AddGetAddrSent() + } + sentN++ + case errBusy: continue + default: + deadN++ } - if msg.Command == CMDGetAddr { - peer.AddGetAddrSent() - } - success[i] = true - sentCount++ + finished[i] = true } // Send to at least 2/3 of good peers. - if 3*sentCount >= 2*okCount { + if 3*sentN >= 2*(peerN-deadN) { return } // Perform blocking send now. for i, peer := range peers { - if success[i] { + if finished[i] { continue } if err := send(peer, true, pkt); err != nil { + if err != errBusy { + deadN++ + } continue } if msg.Command == CMDGetAddr { peer.AddGetAddrSent() } - sentCount++ - if 3*sentCount >= 2*okCount { + sentN++ + if 3*sentN >= 2*(peerN-deadN) { return } }