0diff --git i/src/net.cpp w/src/net.cpp
1index c2160e945f..c8ee95a3d0 100644
2--- i/src/net.cpp
3+++ w/src/net.cpp
4@@ -886,12 +886,14 @@ size_t CConnman::SocketSendData(CNode& node) const
5 * to forge. In order to partition a node the attacker must be
6 * simultaneously better at all of them than honest peers.
7 * If we find a candidate perform the eviction.
8 */
9 bool CConnman::AttemptToEvictConnection()
10 {
11+ AssertLockNotHeld(m_nodes_disconnected_mutex);
12+
13 std::vector<NodeEvictionCandidate> vEvictionCandidates;
14 {
15
16 LOCK(m_nodes_mutex);
17 for (const CNode* node : m_nodes) {
18 if (node->fDisconnect)
19@@ -937,12 +939,14 @@ bool CConnman::AttemptToEvictConnection()
20 return true;
21 }
22 return false;
23 }
24
25 void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
26+ AssertLockNotHeld(m_nodes_disconnected_mutex);
27+
28 struct sockaddr_storage sockaddr;
29 socklen_t len = sizeof(sockaddr);
30 auto sock = hListenSocket.sock->Accept((struct sockaddr*)&sockaddr, &len);
31 CAddress addr;
32
33 if (!sock) {
34@@ -1107,23 +1111,27 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
35 OpenNetworkConnection(CAddress(), false, &grant, address.c_str(), conn_type);
36 return true;
37 }
38
39 void CConnman::DeleteDisconnectedNode(CNode* pnode)
40 {
41+ AssertLockNotHeld(m_nodes_disconnected_mutex);
42+
43 // Destroy the object only after other threads have stopped using it.
44 // Prevent double free by setting nRefCount to -1 before delete.
45 int expectedRefCount = 0;
46 if (pnode->nRefCount.compare_exchange_strong(expectedRefCount, -1)) {
47 WITH_LOCK(m_nodes_disconnected_mutex, m_nodes_disconnected.remove(pnode));
48 DeleteNode(pnode);
49 }
50 }
51
52 void CConnman::DisconnectAndReleaseNode(CNode* pnode)
53 {
54+ AssertLockNotHeld(m_nodes_disconnected_mutex);
55+
56 LOCK(m_nodes_mutex);
57 if (std::find(m_nodes.begin(), m_nodes.end(), pnode) != m_nodes.end()) {
58
59 // remove from m_nodes
60 m_nodes.erase(remove(m_nodes.begin(), m_nodes.end(), pnode), m_nodes.end());
61
62@@ -1138,12 +1146,14 @@ void CConnman::DisconnectAndReleaseNode(CNode* pnode)
63 WITH_LOCK(m_nodes_disconnected_mutex, m_nodes_disconnected.push_back(pnode));
64 }
65 }
66
67 void CConnman::DisconnectNodes()
68 {
69+ AssertLockNotHeld(m_nodes_disconnected_mutex);
70+
71 {
72 LOCK(m_nodes_mutex);
73
74 if (!fNetworkActive) {
75 // Disconnect any connected nodes
76 for (CNode* pnode : m_nodes) {
77@@ -1270,12 +1280,13 @@ Sock::EventsPerSock CConnman::GenerateWaitSockets(Span<CNode* const> nodes)
78
79 return events_per_sock;
80 }
81
82 void CConnman::SocketHandler()
83 {
84+ AssertLockNotHeld(m_nodes_disconnected_mutex);
85 AssertLockNotHeld(m_total_bytes_sent_mutex);
86
87 Sock::EventsPerSock events_per_sock;
88
89 {
90 const NodesSnapshot snap{*this, /*shuffle=*/false};
91@@ -1381,12 +1392,14 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
92 if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
93 }
94 }
95
96 void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
97 {
98+ AssertLockNotHeld(m_nodes_disconnected_mutex);
99+
100 for (const ListenSocket& listen_socket : vhListenSocket) {
101 if (interruptNet) {
102 return;
103 }
104 const auto it = events_per_sock.find(listen_socket.sock);
105 if (it != events_per_sock.end() && it->second.occurred & Sock::RECV) {
106@@ -1394,12 +1407,13 @@ void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock
107 }
108 }
109 }
110
111 void CConnman::ThreadSocketHandler()
112 {
113+ AssertLockNotHeld(m_nodes_disconnected_mutex);
114 AssertLockNotHeld(m_total_bytes_sent_mutex);
115
116 while (!interruptNet)
117 {
118 DisconnectNodes();
119 NotifyNumConnectionsChanged();
120@@ -2093,12 +2107,14 @@ void CConnman::ThreadMessageHandler()
121 fMsgProcWake = false;
122 }
123 }
124
125 void CConnman::ThreadI2PAcceptIncoming()
126 {
127+ AssertLockNotHeld(m_nodes_disconnected_mutex);
128+
129 static constexpr auto err_wait_begin = 1s;
130 static constexpr auto err_wait_cap = 5min;
131 auto err_wait = err_wait_begin;
132
133 bool advertising_listen_addr = false;
134 i2p::Connection conn;
135@@ -2481,12 +2497,14 @@ void CConnman::StopThreads()
136 if (threadSocketHandler.joinable())
137 threadSocketHandler.join();
138 }
139
140 void CConnman::StopNodes()
141 {
142+ AssertLockNotHeld(m_nodes_disconnected_mutex);
143+
144 if (fAddressesInitialized) {
145 DumpAddresses();
146 fAddressesInitialized = false;
147
148 if (m_use_addrman_outgoing) {
149 // Anchor connections are only dumped during clean shutdown.
150diff --git i/src/net.h w/src/net.h
151index d5833d7e2d..d45f3c606f 100644
152--- i/src/net.h
153+++ w/src/net.h
154@@ -760,15 +760,17 @@ public:
155
156 ~CConnman();
157
158 bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !m_added_nodes_mutex, !m_addr_fetches_mutex, !mutexMsgProc);
159
160 void StopThreads();
161- void StopNodes();
162- void Stop()
163+ void StopNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
164+ void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex)
165 {
166+ AssertLockNotHeld(m_nodes_disconnected_mutex);
167+
168 StopThreads();
169 StopNodes();
170 };
171
172 void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
173 bool GetNetworkActive() const { return fNetworkActive; };
174@@ -917,31 +919,31 @@ private:
175
176 void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex);
177 void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
178 void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex);
179 void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex);
180 void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
181- void ThreadI2PAcceptIncoming();
182- void AcceptConnection(const ListenSocket& hListenSocket);
183+ void ThreadI2PAcceptIncoming() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
184+ void AcceptConnection(const ListenSocket& hListenSocket) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
185
186 /**
187 * Create a `CNode` object from a socket that has just been accepted and add the node to
188 * the `m_nodes` member.
189 * [@param](/bitcoin-bitcoin/contributor/param/)[in] sock Connected socket to communicate with the peer.
190 * [@param](/bitcoin-bitcoin/contributor/param/)[in] permission_flags The peer's permissions.
191 * [@param](/bitcoin-bitcoin/contributor/param/)[in] addr_bind The address and port at our side of the connection.
192 * [@param](/bitcoin-bitcoin/contributor/param/)[in] addr The address and port at the peer's side of the connection.
193 */
194 void CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
195 NetPermissionFlags permission_flags,
196 const CAddress& addr_bind,
197- const CAddress& addr);
198+ const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
199
200- void DeleteDisconnectedNode(CNode* pnode);
201- void DisconnectAndReleaseNode(CNode* pnode);
202- void DisconnectNodes();
203+ void DeleteDisconnectedNode(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
204+ void DisconnectAndReleaseNode(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
205+ void DisconnectNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
206 void NotifyNumConnectionsChanged();
207 /** Return true if the peer is inactive and should be disconnected. */
208 bool InactivityCheck(const CNode& node) const;
209
210 /**
211 * Generate a collection of sockets to check for IO readiness.
212@@ -950,13 +952,13 @@ private:
213 */
214 Sock::EventsPerSock GenerateWaitSockets(Span<CNode* const> nodes);
215
216 /**
217 * Check connected and listening sockets for IO readiness and process them accordingly.
218 */
219- void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc);
220+ void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex, !m_total_bytes_sent_mutex, !mutexMsgProc);
221
222 /**
223 * Do the read/write for connected sockets that are ready for IO.
224 * [@param](/bitcoin-bitcoin/contributor/param/)[in] nodes Nodes to process. The socket of each node is checked against `what`.
225 * [@param](/bitcoin-bitcoin/contributor/param/)[in] events_per_sock Sockets that are ready for IO.
226 */
227@@ -965,15 +967,15 @@ private:
228 EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc);
229
230 /**
231 * Accept incoming connections, one from each read-ready listening socket.
232 * [@param](/bitcoin-bitcoin/contributor/param/)[in] events_per_sock Sockets that are ready for IO.
233 */
234- void SocketHandlerListening(const Sock::EventsPerSock& events_per_sock);
235+ void SocketHandlerListening(const Sock::EventsPerSock& events_per_sock) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
236
237- void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc);
238+ void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex, !m_total_bytes_sent_mutex, !mutexMsgProc);
239 void ThreadDNSAddressSeed() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex);
240
241 uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
242
243 CNode* FindNode(const CNetAddr& ip);
244 CNode* FindNode(const CSubNet& subNet);
245@@ -983,13 +985,13 @@ private:
246 /**
247 * Determine whether we're already connected to a given address, in order to
248 * avoid initiating duplicate connections.
249 */
250 bool AlreadyConnectedToAddress(const CAddress& addr);
251
252- bool AttemptToEvictConnection();
253+ bool AttemptToEvictConnection() EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_disconnected_mutex);
254 CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
255 void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
256
257 void DeleteNode(CNode* pnode);
258
259 NodeId GetNewNodeId();
260@@ -1042,13 +1044,13 @@ private:
261 const NetGroupManager& m_netgroupman;
262 std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
263 Mutex m_addr_fetches_mutex;
264 std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
265 mutable Mutex m_added_nodes_mutex;
266 std::vector<CNode*> m_nodes GUARDED_BY(m_nodes_mutex);
267- GlobalMutex m_nodes_disconnected_mutex;
268+ Mutex m_nodes_disconnected_mutex;
269 std::list<CNode*> m_nodes_disconnected GUARDED_BY(m_nodes_disconnected_mutex);
270 mutable RecursiveMutex m_nodes_mutex;
271 std::atomic<NodeId> nLastNodeId{0};
272 unsigned int nPrevNodeCount{0};
273
274 /**