@@ -199,6 +199,17 @@ struct CBlockReject {
199199 uint256 hashBlock;
200200};
201201
202+ /* *
203+ * Maintain state about nodes, protected by our own lock. Historically we put all
204+ * peer tracking state in CNodeState, however this results in significant cs_main
205+ * contention. Thus, new state tracking should go here, and we should eventually
206+ * move most (non-validation-specific) state here.
207+ */
208+ struct CPeerState {
209+ CPeerState () {}
210+ };
211+
212+
202213/* *
203214 * Maintain validation-specific state about nodes, protected by cs_main, instead
204215 * by CNode's own locks. This simplifies asynchronous operation, where
@@ -393,7 +404,20 @@ struct CNodeState {
393404// Keeps track of the time (in microseconds) when transactions were requested last time
394405limitedmap<uint256, int64_t > g_already_asked_for GUARDED_BY (cs_main)(MAX_INV_SZ);
395406
407+ /* * Note that this must be locked BEFORE cs_main! */
408+ CCriticalSection cs_peerstate;
409+
396410/* * Map maintaining per-node state. */
411+ static std::map<NodeId, CPeerState> mapPeerState GUARDED_BY (cs_peerstate);
412+
413+ static CPeerState *PeerState (NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_peerstate) LOCKS_EXCLUDED(cs_main) {
414+ std::map<NodeId, CPeerState>::iterator it = mapPeerState.find (pnode);
415+ if (it == mapPeerState.end ())
416+ return nullptr ;
417+ return &it->second ;
418+ }
419+
420+ /* * Map maintaining new per-node state. */
397421static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY (cs_main);
398422
399423static CNodeState *State (NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
@@ -771,12 +795,22 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
771795 LOCK (cs_main);
772796 mapNodeState.emplace_hint (mapNodeState.end (), std::piecewise_construct, std::forward_as_tuple (nodeid), std::forward_as_tuple (addr, std::move (addrName), pnode->fInbound , pnode->m_manual_connection ));
773797 }
798+ {
799+ LOCK (cs_peerstate);
800+ mapPeerState.emplace_hint (mapPeerState.end (), nodeid, CPeerState{});
801+ }
802+
774803 if (!pnode->fInbound )
775804 PushNodeVersion (pnode, connman, GetTime ());
776805}
777806
778807void PeerLogicValidation::FinalizeNode (NodeId nodeid, bool & fUpdateConnectionTime ) {
779808 fUpdateConnectionTime = false ;
809+
810+ LOCK (cs_peerstate);
811+ CPeerState* peerstate = PeerState (nodeid);
812+ assert (peerstate != nullptr );
813+
780814 LOCK (cs_main);
781815 CNodeState *state = State (nodeid);
782816 assert (state != nullptr );
@@ -799,13 +833,15 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
799833 assert (g_outbound_peers_with_protect_from_disconnect >= 0 );
800834
801835 mapNodeState.erase (nodeid);
836+ mapPeerState.erase (nodeid);
802837
803838 if (mapNodeState.empty ()) {
804839 // Do a consistency check after the last peer is removed.
805840 assert (mapBlocksInFlight.empty ());
806841 assert (nPreferredDownload == 0 );
807842 assert (nPeersWithValidatedDownloads == 0 );
808843 assert (g_outbound_peers_with_protect_from_disconnect == 0 );
844+ assert (mapPeerState.empty ());
809845 }
810846 LogPrint (BCLog::NET, " Cleared nodestate for peer=%d\n " , nodeid);
811847}
@@ -1843,7 +1879,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
18431879 }
18441880}
18451881
1846- bool static ProcessMessage (CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool >& interruptMsgProc, bool enable_bip61)
1882+ bool static ProcessMessage (CNode* pfrom, CPeerState* peerstate, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool >& interruptMsgProc, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_peerstate )
18471883{
18481884 LogPrint (BCLog::NET, " received: %s (%u bytes) peer=%d\n " , SanitizeString (strCommand), vRecv.size (), pfrom->GetId ());
18491885 if (gArgs .IsArgSet (" -dropmessagestest" ) && GetRand (gArgs .GetArg (" -dropmessagestest" , 0 )) == 0 )
@@ -2785,7 +2821,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
27852821 } // cs_main
27862822
27872823 if (fProcessBLOCKTXN )
2788- return ProcessMessage (pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc, enable_bip61);
2824+ return ProcessMessage (pfrom, peerstate, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc, enable_bip61);
27892825
27902826 if (fRevertToHeaderProcessing ) {
27912827 // Headers received from HB compact block peers are permitted to be
@@ -3231,6 +3267,8 @@ bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_
32313267bool PeerLogicValidation::ProcessMessages (CNode* pfrom, std::atomic<bool >& interruptMsgProc)
32323268{
32333269 const CChainParams& chainparams = Params ();
3270+ LOCK (cs_peerstate);
3271+ CPeerState* peerstate = PeerState (pfrom->GetId ());
32343272 //
32353273 // Message format
32363274 // (4) message start
@@ -3313,7 +3351,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
33133351 bool fRet = false ;
33143352 try
33153353 {
3316- fRet = ProcessMessage (pfrom, strCommand, vRecv, msg.nTime , chainparams, connman, interruptMsgProc, m_enable_bip61);
3354+ fRet = ProcessMessage (pfrom, peerstate, strCommand, vRecv, msg.nTime , chainparams, connman, interruptMsgProc, m_enable_bip61);
33173355 if (interruptMsgProc)
33183356 return false ;
33193357 if (!pfrom->vRecvGetData .empty ())
@@ -3522,6 +3560,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
35223560 // If we get here, the outgoing message serialization version is set and can't change.
35233561 const CNetMsgMaker msgMaker (pto->GetSendVersion ());
35243562
3563+ LOCK (cs_peerstate);
3564+ CPeerState* peerstate = PeerState (pto->GetId ());
3565+
35253566 //
35263567 // Message: ping
35273568 //
0 commit comments