From 63badaedc469961f87fa2dfca74a54990c67a1db Mon Sep 17 00:00:00 2001 From: Eugene Siegel Date: Tue, 9 Jun 2026 13:59:40 -0400 Subject: [PATCH] net: move cs_main up in FetchBlock to fix rpc assert crash FetchBlock (used by the getblockfrompeer RPC) acquired a PeerRef before locking cs_main. If the peer was being finalized on a net thread in between, FinalizeNode could erase the peer's CNodeState, and BlockRequested would then hit assert(state != nullptr) and crash the node. Take cs_main before GetPeerRef so the CNodeState cannot be removed while FetchBlock runs. The lock order (cs_main, then m_peer_mutex) matches FinalizeNode. Github-Pull: bitcoin/bitcoin#35498 Rebased-From: 359680b74db840c2424b944af358ed215aff3019 --- src/net_processing.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 1c7ba35de335..ea29c99c61fb 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2051,6 +2051,12 @@ std::optional PeerManagerImpl::FetchBlock(NodeId peer_id, const uin { if (m_chainman.m_blockman.LoadingBlocks()) return "Loading blocks ..."; + // The lock must be taken here before fetching Peer so another thread does + // not delete the CNodeState from under the current thread, causing an + // assertion failure in BlockRequested. This lock can be replaced with a + // net-specific lock when more of CNodeState is moved into Peer. + LOCK(cs_main); + // Ensure this peer exists and hasn't been disconnected PeerRef peer = GetPeerRef(peer_id); if (peer == nullptr) return "Peer does not exist"; @@ -2058,8 +2064,6 @@ std::optional PeerManagerImpl::FetchBlock(NodeId peer_id, const uin // Ignore pre-segwit peers if (!CanServeWitnesses(*peer)) return "Pre-SegWit peer"; - LOCK(cs_main); - if (IsBlockRequestedFromPeer(hash, peer_id)) return "Already requested from this peer"; // Mark block as in-flight unless we don't have the header.