@@ -490,9 +490,9 @@ class PeerManagerImpl final : public PeerManager
490490
491491 /* * Overridden from CValidationInterface. */
492492 void BlockConnected (ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override
493- EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex);
493+ EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex );
494494 void BlockDisconnected (const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override
495- EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex);
495+ EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex );
496496 void UpdatedBlockTip (const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload ) override
497497 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
498498 void BlockChecked (const CBlock& block, const BlockValidationState& state) override
@@ -501,13 +501,13 @@ class PeerManagerImpl final : public PeerManager
501501 EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex);
502502
503503 /* * Implement NetEventsInterface */
504- void InitializeNode (const CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
505- void FinalizeNode (const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex);
504+ void InitializeNode (const CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_tx_download_mutex );
505+ void FinalizeNode (const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, !m_tx_download_mutex );
506506 bool HasAllDesirableServiceFlags (ServiceFlags services) const override ;
507507 bool ProcessMessages (CNode* pfrom, std::atomic<bool >& interrupt) override
508- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
508+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex );
509509 bool SendMessages (CNode* pto) override
510- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex);
510+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex );
511511
512512 /* * Implement PeerManager */
513513 void StartScheduledTasks (CScheduler& scheduler) override ;
@@ -526,7 +526,7 @@ class PeerManagerImpl final : public PeerManager
526526 void UnitTestMisbehaving (NodeId peer_id) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving (*Assert (GetPeerRef (peer_id)), " " ); };
527527 void ProcessMessage (CNode& pfrom, const std::string& msg_type, DataStream& vRecv,
528528 const std::chrono::microseconds time_received, const std::atomic<bool >& interruptMsgProc) override
529- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
529+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex );
530530 void UpdateLastBlockAnnounceTime (NodeId node, int64_t time_in_seconds) override ;
531531 ServiceFlags GetDesirableServiceFlags (ServiceFlags services) const override ;
532532
@@ -585,12 +585,12 @@ class PeerManagerImpl final : public PeerManager
585585 * Updates m_txrequest, m_recent_rejects, m_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact. */
586586 void ProcessInvalidTx (NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
587587 bool maybe_add_extra_compact_tx)
588- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main );
588+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex );
589589
590590 /* * Handle a transaction whose result was MempoolAcceptResult::ResultType::VALID.
591591 * Updates m_txrequest, m_orphanage, and vExtraTxnForCompact. Also queues the tx for relay. */
592592 void ProcessValidTx (NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions)
593- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main );
593+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex );
594594
595595 struct PackageToValidate {
596596 const Package m_txns;
@@ -620,13 +620,13 @@ class PeerManagerImpl final : public PeerManager
620620 * individual transactions, and caches rejection for the package as a group.
621621 */
622622 void ProcessPackageResult (const PackageToValidate& package_to_validate, const PackageMempoolAcceptResult& package_result)
623- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main );
623+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex );
624624
625625 /* * Look for a child of this transaction in the orphanage to form a 1-parent-1-child package,
626626 * skipping any combinations that have already been tried. Return the resulting package along with
627627 * the senders of its respective transactions, or std::nullopt if no package is found. */
628628 std::optional<PackageToValidate> Find1P1CPackage (const CTransactionRef& ptx, NodeId nodeid)
629- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main );
629+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex );
630630
631631 /* *
632632 * Reconsider orphan transactions after a parent has been accepted to the mempool.
@@ -640,7 +640,7 @@ class PeerManagerImpl final : public PeerManager
640640 * will be empty.
641641 */
642642 bool ProcessOrphanTx (Peer& peer)
643- EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex);
643+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, !m_tx_download_mutex );
644644
645645 /* * Process a single headers message from a peer.
646646 *
@@ -722,7 +722,7 @@ class PeerManagerImpl final : public PeerManager
722722 * peer. The announcement parameters are decided in PeerManager and then
723723 * passed to TxRequestTracker. */
724724 void AddTxAnnouncement (const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time)
725- EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
725+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_tx_download_mutex );
726726
727727 /* * Send a message to a peer */
728728 void PushMessage (CNode& node, CSerializedNetMsg&& msg) const { m_connman.PushMessage (&node, std::move (msg)); }
@@ -770,7 +770,19 @@ class PeerManagerImpl final : public PeerManager
770770 BanMan* const m_banman;
771771 ChainstateManager& m_chainman;
772772 CTxMemPool& m_mempool;
773- TxRequestTracker m_txrequest GUARDED_BY (::cs_main);
773+
774+ /* * Synchronizes tx download including TxRequestTracker, rejection filters, and TxOrphanage.
775+ * Lock invariants:
776+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_orphanage.
777+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects.
778+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects_reconsiderable.
779+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_confirmed_transactions.
780+ * - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc).
781+ *
782+ * m_tx_download_mutex must be acquired before mempool.cs
783+ */
784+ Mutex m_tx_download_mutex;
785+ TxRequestTracker m_txrequest GUARDED_BY (m_tx_download_mutex);
774786 std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
775787
776788 /* * The height of the best chain */
@@ -851,7 +863,7 @@ class PeerManagerImpl final : public PeerManager
851863 * chain tip has changed.
852864 * */
853865 bool AlreadyHaveTx (const GenTxid& gtxid, bool include_reconsiderable)
854- EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex);
866+ EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex, m_tx_download_mutex );
855867
856868 /* *
857869 * Filter for transactions that were recently rejected by the mempool.
@@ -887,10 +899,10 @@ class PeerManagerImpl final : public PeerManager
887899 *
888900 * Memory used: 1.3 MB
889901 */
890- CRollingBloomFilter m_recent_rejects GUARDED_BY (::cs_main ){120'000 , 0.000'001 };
902+ CRollingBloomFilter m_recent_rejects GUARDED_BY (m_tx_download_mutex ){120'000 , 0.000'001 };
891903 /* * Block hash of chain tip the last time we reset m_recent_rejects and
892904 * m_recent_rejects_reconsiderable. */
893- uint256 hashRecentRejectsChainTip GUARDED_BY (cs_main );
905+ uint256 hashRecentRejectsChainTip GUARDED_BY (m_tx_download_mutex );
894906
895907 /* *
896908 * Filter for:
@@ -912,7 +924,7 @@ class PeerManagerImpl final : public PeerManager
912924 *
913925 * Parameters are picked to be the same as m_recent_rejects, with the same rationale.
914926 */
915- CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY (::cs_main ){120'000 , 0.000'001 };
927+ CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY (m_tx_download_mutex ){120'000 , 0.000'001 };
916928
917929 /*
918930 * Filter for transactions that have been recently confirmed.
@@ -1067,7 +1079,7 @@ class PeerManagerImpl final : public PeerManager
10671079 int m_peers_downloading_from GUARDED_BY (cs_main) = 0;
10681080
10691081 /* * Storage for orphan information */
1070- TxOrphanage m_orphanage;
1082+ TxOrphanage m_orphanage GUARDED_BY (m_tx_download_mutex) ;
10711083
10721084 void AddToCompactExtraTransactions (const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
10731085
@@ -1630,7 +1642,8 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer)
16301642
16311643void PeerManagerImpl::AddTxAnnouncement (const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time)
16321644{
1633- AssertLockHeld (::cs_main); // For m_txrequest
1645+ AssertLockHeld (::cs_main); // for State
1646+ AssertLockHeld (m_tx_download_mutex); // For m_txrequest
16341647 NodeId nodeid = node.GetId ();
16351648 if (!node.HasPermission (NetPermissionFlags::Relay) && m_txrequest.Count (nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) {
16361649 // Too many queued announcements from this peer
@@ -1666,8 +1679,11 @@ void PeerManagerImpl::InitializeNode(const CNode& node, ServiceFlags our_service
16661679{
16671680 NodeId nodeid = node.GetId ();
16681681 {
1669- LOCK (cs_main);
1682+ LOCK (cs_main); // For m_node_states
16701683 m_node_states.emplace_hint (m_node_states.end (), std::piecewise_construct, std::forward_as_tuple (nodeid), std::forward_as_tuple (node.IsInboundConn ()));
1684+ }
1685+ {
1686+ LOCK (m_tx_download_mutex);
16711687 assert (m_txrequest.Count (nodeid) == 0 );
16721688 }
16731689
@@ -1735,8 +1751,11 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
17351751 }
17361752 }
17371753 }
1738- m_orphanage.EraseForPeer (nodeid);
1739- m_txrequest.DisconnectedPeer (nodeid);
1754+ {
1755+ LOCK (m_tx_download_mutex);
1756+ m_orphanage.EraseForPeer (nodeid);
1757+ m_txrequest.DisconnectedPeer (nodeid);
1758+ }
17401759 if (m_txreconciliation) m_txreconciliation->ForgetPeer (nodeid);
17411760 m_num_preferred_download_peers -= state->fPreferredDownload ;
17421761 m_peers_downloading_from -= (!state->vBlocksInFlight .empty ());
@@ -1753,6 +1772,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
17531772 assert (m_peers_downloading_from == 0 );
17541773 assert (m_outbound_peers_with_protect_from_disconnect == 0 );
17551774 assert (m_wtxid_relay_peers == 0 );
1775+ LOCK (m_tx_download_mutex);
17561776 assert (m_txrequest.Size () == 0 );
17571777 assert (m_orphanage.Size () == 0 );
17581778 }
@@ -2084,6 +2104,7 @@ void PeerManagerImpl::BlockConnected(
20842104 if (role == ChainstateRole::BACKGROUND) {
20852105 return ;
20862106 }
2107+ LOCK (m_tx_download_mutex);
20872108 m_orphanage.EraseForBlock (*pblock);
20882109
20892110 {
@@ -2096,7 +2117,6 @@ void PeerManagerImpl::BlockConnected(
20962117 }
20972118 }
20982119 {
2099- LOCK (cs_main);
21002120 for (const auto & ptx : pblock->vtx ) {
21012121 m_txrequest.ForgetTxHash (ptx->GetHash ());
21022122 m_txrequest.ForgetTxHash (ptx->GetWitnessHash ());
@@ -2254,6 +2274,9 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
22542274
22552275bool PeerManagerImpl::AlreadyHaveTx (const GenTxid& gtxid, bool include_reconsiderable)
22562276{
2277+ AssertLockHeld (::cs_main);
2278+ AssertLockHeld (m_tx_download_mutex);
2279+
22572280 if (m_chainman.ActiveChain ().Tip ()->GetBlockHash () != hashRecentRejectsChainTip) {
22582281 // If the chain tip has changed previously rejected transactions
22592282 // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
@@ -3154,7 +3177,7 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
31543177{
31553178 AssertLockNotHeld (m_peer_mutex);
31563179 AssertLockHeld (g_msgproc_mutex);
3157- AssertLockHeld (cs_main );
3180+ AssertLockHeld (m_tx_download_mutex );
31583181
31593182 LogDebug (BCLog::MEMPOOLREJ, " %s (wtxid=%s) from peer=%d was not accepted: %s\n " ,
31603183 ptx->GetHash ().ToString (),
@@ -3219,7 +3242,7 @@ void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, c
32193242{
32203243 AssertLockNotHeld (m_peer_mutex);
32213244 AssertLockHeld (g_msgproc_mutex);
3222- AssertLockHeld (cs_main );
3245+ AssertLockHeld (m_tx_download_mutex );
32233246
32243247 // As this version of the transaction was acceptable, we can forget about any requests for it.
32253248 // No-op if the tx is not in txrequest.
@@ -3247,7 +3270,7 @@ void PeerManagerImpl::ProcessPackageResult(const PackageToValidate& package_to_v
32473270{
32483271 AssertLockNotHeld (m_peer_mutex);
32493272 AssertLockHeld (g_msgproc_mutex);
3250- AssertLockHeld (cs_main );
3273+ AssertLockHeld (m_tx_download_mutex );
32513274
32523275 const auto & package = package_to_validate.m_txns ;
32533276 const auto & senders = package_to_validate.m_senders ;
@@ -3303,7 +3326,7 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka
33033326{
33043327 AssertLockNotHeld (m_peer_mutex);
33053328 AssertLockHeld (g_msgproc_mutex);
3306- AssertLockHeld (cs_main );
3329+ AssertLockHeld (m_tx_download_mutex );
33073330
33083331 const auto & parent_wtxid{ptx->GetWitnessHash ()};
33093332
@@ -3356,7 +3379,7 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka
33563379bool PeerManagerImpl::ProcessOrphanTx (Peer& peer)
33573380{
33583381 AssertLockHeld (g_msgproc_mutex);
3359- LOCK ( cs_main);
3382+ LOCK2 (:: cs_main, m_tx_download_mutex );
33603383
33613384 CTransactionRef porphanTx = nullptr ;
33623385
@@ -4173,7 +4196,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
41734196
41744197 const bool reject_tx_invs{RejectIncomingTxs (pfrom)};
41754198
4176- LOCK (cs_main);
4199+ LOCK2 (cs_main, m_tx_download_mutex );
41774200
41784201 const auto current_time{GetTime<std::chrono::microseconds>()};
41794202 uint256* best_block{nullptr };
@@ -4506,7 +4529,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
45064529 const uint256& hash = peer->m_wtxid_relay ? wtxid : txid;
45074530 AddKnownTx (*peer, hash);
45084531
4509- LOCK (cs_main);
4532+ LOCK2 (cs_main, m_tx_download_mutex );
45104533
45114534 m_txrequest.ReceivedResponse (pfrom.GetId (), txid);
45124535 if (tx.HasWitness ()) m_txrequest.ReceivedResponse (pfrom.GetId (), wtxid);
@@ -5263,7 +5286,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
52635286 std::vector<CInv> vInv;
52645287 vRecv >> vInv;
52655288 if (vInv.size () <= MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
5266- LOCK (::cs_main );
5289+ LOCK (m_tx_download_mutex );
52675290 for (CInv &inv : vInv) {
52685291 if (inv.IsGenTxMsg ()) {
52695292 // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as
@@ -5388,6 +5411,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
53885411 // by another peer that was already processed; in that case,
53895412 // the extra work may not be noticed, possibly resulting in an
53905413 // unnecessary 100ms delay)
5414+ LOCK (m_tx_download_mutex);
53915415 if (m_orphanage.HaveTxToReconsider (peer->m_id )) fMoreWork = true ;
53925416 } catch (const std::exception& e) {
53935417 LogPrint (BCLog::NET, " %s(%s, %u bytes): Exception '%s' (%s) caught\n " , __func__, SanitizeString (msg.m_type ), msg.m_message_size , e.what (), typeid (e).name ());
@@ -6281,6 +6305,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
62816305 //
62826306 // Message: getdata (transactions)
62836307 //
6308+ LOCK (m_tx_download_mutex);
62846309 std::vector<std::pair<NodeId, GenTxid>> expired;
62856310 auto requestable = m_txrequest.GetRequestable (pto->GetId (), current_time, &expired);
62866311 for (const auto & entry : expired) {
0 commit comments