From 088eec67ec9d36d678a232c6dc88f3a335b42c95 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 21 Jul 2018 17:41:23 -0700 Subject: [PATCH] peer: ensure the version negotiation goroutine will always exit In this commit, we patch a goroutine leak within the peer struct. This goroutine leak can happen, if the remote side fails to actually finish negotiation the protocol before our timeout ticker ticks. In this case, the goroutine will be blocked on a send, as the channel is unfired. An example trace from a btcd node I had on testnet showed: ``` 3183 @ 0x42e78a 0x42e83e 0x40540b 0x4051a5 0x872f76 0x45bfc1 ``` So, all instances of the goroutine failing to exit due to the remote peer not finishing the p2p version negotiation handshake. Our fix is simple: make the `negotiateErr' channel unbuffered. With this simple change, we ensure that the goroutine will always exit even in the case that the parent goroutine exists due to a timeout. # Please enter the commit message for your changes. Lines starting --- peer/peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer/peer.go b/peer/peer.go index 9aecab59..2fdf3e42 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -2053,7 +2053,7 @@ func (p *Peer) Disconnect() { func (p *Peer) start() error { log.Tracef("Starting peer %s", p) - negotiateErr := make(chan error) + negotiateErr := make(chan error, 1) go func() { if p.inbound { negotiateErr <- p.negotiateInboundProtocol()