From 429e7141f2f41c1d66dd4dd711a47ca9e0f0c2cb Mon Sep 17 00:00:00 2001
From: Nishant Das <nishdas93@gmail.com>
Date: Thu, 26 Nov 2020 05:16:36 +0800
Subject: [PATCH] p2p/discover: fix deadlock in discv5 message dispatch
 (#21858)

This fixes a deadlock that could occur when a response packet arrived
after a call had already received enough responses and was about to
signal completion to the dispatch loop.

Co-authored-by: Felix Lange <fjl@twurst.com>
---
 p2p/discover/v5_udp.go | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go
index c95317a00..9dd2b3173 100644
--- a/p2p/discover/v5_udp.go
+++ b/p2p/discover/v5_udp.go
@@ -454,9 +454,20 @@ func (t *UDPv5) call(node *enode.Node, responseType byte, packet v5wire.Packet)
 
 // callDone tells dispatch that the active call is done.
 func (t *UDPv5) callDone(c *callV5) {
-	select {
-	case t.callDoneCh <- c:
-	case <-t.closeCtx.Done():
+	// This needs a loop because further responses may be incoming until the
+	// send to callDoneCh has completed. Such responses need to be discarded
+	// in order to avoid blocking the dispatch loop.
+	for {
+		select {
+		case <-c.ch:
+			// late response, discard.
+		case <-c.err:
+			// late error, discard.
+		case t.callDoneCh <- c:
+			return
+		case <-t.closeCtx.Done():
+			return
+		}
 	}
 }
 
-- 
GitLab