@@ -489,7 +489,7 @@ class PeerManagerImpl final : public PeerManager
489489 CTxMemPool& pool, node::Warnings& warnings, Options opts);
490490
491491 /* * Overridden from CValidationInterface. */
492- void ActiveTipChange (const CBlockIndex* new_tip, bool ) override
492+ void ActiveTipChange (const CBlockIndex& new_tip, bool ) override
493493 EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
494494 void BlockConnected (ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override
495495 EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
@@ -780,10 +780,8 @@ class PeerManagerImpl final : public PeerManager
780780 * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects_reconsiderable.
781781 * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_confirmed_transactions.
782782 * - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc).
783- *
784- * m_tx_download_mutex must be acquired before mempool.cs
785783 */
786- Mutex m_tx_download_mutex;
784+ Mutex m_tx_download_mutex ACQUIRED_BEFORE (m_mempool.cs) ;
787785 TxRequestTracker m_txrequest GUARDED_BY (m_tx_download_mutex);
788786 std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
789787
@@ -2070,8 +2068,10 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
20702068 scheduler.scheduleFromNow ([&] { ReattemptInitialBroadcast (scheduler); }, delta);
20712069}
20722070
2073- void PeerManagerImpl::ActiveTipChange (const CBlockIndex* new_tip, bool is_ibd)
2071+ void PeerManagerImpl::ActiveTipChange (const CBlockIndex& new_tip, bool is_ibd)
20742072{
2073+ // Ensure mempool mutex was released, otherwise deadlock may occur if another thread holding
2074+ // m_tx_download_mutex waits on the mempool mutex.
20752075 AssertLockNotHeld (m_mempool.cs );
20762076 AssertLockNotHeld (m_tx_download_mutex);
20772077
@@ -2123,8 +2123,6 @@ void PeerManagerImpl::BlockConnected(
21232123 if (ptx->HasWitness ()) {
21242124 m_recent_confirmed_transactions.insert (ptx->GetWitnessHash ().ToUint256 ());
21252125 }
2126- }
2127- for (const auto & ptx : pblock->vtx ) {
21282126 m_txrequest.ForgetTxHash (ptx->GetHash ());
21292127 m_txrequest.ForgetTxHash (ptx->GetWitnessHash ());
21302128 }
@@ -5336,6 +5334,7 @@ bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer)
53365334
53375335bool PeerManagerImpl::ProcessMessages (CNode* pfrom, std::atomic<bool >& interruptMsgProc)
53385336{
5337+ AssertLockNotHeld (m_tx_download_mutex);
53395338 AssertLockHeld (g_msgproc_mutex);
53405339
53415340 PeerRef peer = GetPeerRef (pfrom->GetId ());
@@ -5827,6 +5826,7 @@ bool PeerManagerImpl::SetupAddressRelay(const CNode& node, Peer& peer)
58275826
58285827bool PeerManagerImpl::SendMessages (CNode* pto)
58295828{
5829+ AssertLockNotHeld (m_tx_download_mutex);
58305830 AssertLockHeld (g_msgproc_mutex);
58315831
58325832 PeerRef peer = GetPeerRef (pto->GetId ());
@@ -6297,32 +6297,33 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
62976297 //
62986298 // Message: getdata (transactions)
62996299 //
6300- LOCK (m_tx_download_mutex);
6301- std::vector<std::pair<NodeId, GenTxid>> expired;
6302- auto requestable = m_txrequest.GetRequestable (pto->GetId (), current_time, &expired);
6303- for (const auto & entry : expired) {
6304- LogPrint (BCLog::NET, " timeout of inflight %s %s from peer=%d\n " , entry.second .IsWtxid () ? " wtx" : " tx" ,
6305- entry.second .GetHash ().ToString (), entry.first );
6306- }
6307- for (const GenTxid& gtxid : requestable) {
6308- // Exclude m_recent_rejects_reconsiderable: we may be requesting a missing parent
6309- // that was previously rejected for being too low feerate.
6310- if (!AlreadyHaveTx (gtxid, /* include_reconsiderable=*/ false )) {
6311- LogPrint (BCLog::NET, " Requesting %s %s peer=%d\n " , gtxid.IsWtxid () ? " wtx" : " tx" ,
6312- gtxid.GetHash ().ToString (), pto->GetId ());
6313- vGetData.emplace_back (gtxid.IsWtxid () ? MSG_WTX : (MSG_TX | GetFetchFlags (*peer)), gtxid.GetHash ());
6314- if (vGetData.size () >= MAX_GETDATA_SZ) {
6315- MakeAndPushMessage (*pto, NetMsgType::GETDATA, vGetData);
6316- vGetData.clear ();
6300+ {
6301+ LOCK (m_tx_download_mutex);
6302+ std::vector<std::pair<NodeId, GenTxid>> expired;
6303+ auto requestable = m_txrequest.GetRequestable (pto->GetId (), current_time, &expired);
6304+ for (const auto & entry : expired) {
6305+ LogPrint (BCLog::NET, " timeout of inflight %s %s from peer=%d\n " , entry.second .IsWtxid () ? " wtx" : " tx" ,
6306+ entry.second .GetHash ().ToString (), entry.first );
6307+ }
6308+ for (const GenTxid& gtxid : requestable) {
6309+ // Exclude m_recent_rejects_reconsiderable: we may be requesting a missing parent
6310+ // that was previously rejected for being too low feerate.
6311+ if (!AlreadyHaveTx (gtxid, /* include_reconsiderable=*/ false )) {
6312+ LogPrint (BCLog::NET, " Requesting %s %s peer=%d\n " , gtxid.IsWtxid () ? " wtx" : " tx" ,
6313+ gtxid.GetHash ().ToString (), pto->GetId ());
6314+ vGetData.emplace_back (gtxid.IsWtxid () ? MSG_WTX : (MSG_TX | GetFetchFlags (*peer)), gtxid.GetHash ());
6315+ if (vGetData.size () >= MAX_GETDATA_SZ) {
6316+ MakeAndPushMessage (*pto, NetMsgType::GETDATA, vGetData);
6317+ vGetData.clear ();
6318+ }
6319+ m_txrequest.RequestedTx (pto->GetId (), gtxid.GetHash (), current_time + GETDATA_TX_INTERVAL);
6320+ } else {
6321+ // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
6322+ // this should already be called whenever a transaction becomes AlreadyHaveTx().
6323+ m_txrequest.ForgetTxHash (gtxid.GetHash ());
63176324 }
6318- m_txrequest.RequestedTx (pto->GetId (), gtxid.GetHash (), current_time + GETDATA_TX_INTERVAL);
6319- } else {
6320- // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
6321- // this should already be called whenever a transaction becomes AlreadyHaveTx().
6322- m_txrequest.ForgetTxHash (gtxid.GetHash ());
63236325 }
6324- }
6325-
6326+ } // release m_tx_download_mutex
63266327
63276328 if (!vGetData.empty ())
63286329 MakeAndPushMessage (*pto, NetMsgType::GETDATA, vGetData);
0 commit comments