From 88327756f6b750fe02eaa8d2207f8916b3afcd07 Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 10 Nov 2025 16:37:57 -0600 Subject: [PATCH 1/4] feat: convert CSigSharesManager to use Mutex instead of RecursiveMutex update lock requirements for various methods. This change enhances thread safety and simplifies locking semantics throughout the class. --- src/llmq/signing_shares.h | 69 +++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index 14e20edce459..bce6f07bf3fe 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -376,7 +376,7 @@ class CSigSharesManager : public CRecoveredSigsListener static constexpr int64_t MAX_SEND_FOR_RECOVERY_TIMEOUT{10000}; static constexpr size_t MAX_MSGS_SIG_SHARES{32}; - RecursiveMutex cs; + Mutex cs; std::thread workThread; CThreadInterrupt workInterrupt; @@ -424,37 +424,37 @@ class CSigSharesManager : public CRecoveredSigsListener const CQuorumManager& _qman, const CSporkManager& sporkman); ~CSigSharesManager() override; - void StartWorkerThread(); - void StopWorkerThread(); - void RegisterAsRecoveredSigsListener(); - void UnregisterAsRecoveredSigsListener(); - void InterruptWorkerThread(); + void StartWorkerThread() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void StopWorkerThread() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void RegisterAsRecoveredSigsListener() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void UnregisterAsRecoveredSigsListener() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void InterruptWorkerThread() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void ProcessMessage(const CNode& pnode, const std::string& msg_type, CDataStream& vRecv); + void ProcessMessage(const CNode& pnode, const std::string& msg_type, CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs); void AsyncSign(CQuorumCPtr quorum, const uint256& id, const uint256& msgHash) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns); - std::optional CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const; - void ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); + EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); + std::optional CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + void ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override; + [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override EXCLUSIVE_LOCKS_REQUIRED(!cs); static CDeterministicMNCPtr SelectMemberForRecovery(const CQuorum& quorum, const uint256& id, int attempt); bool AsyncSignIfMember(Consensus::LLMQType llmqType, CSigningManager& sigman, const uint256& id, const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false, bool allowDiffMsgHashSigning = false) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns); + EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); - void NotifyRecoveredSig(const std::shared_ptr& sig) const; + void NotifyRecoveredSig(const std::shared_ptr& sig) const EXCLUSIVE_LOCKS_REQUIRED(!cs); private: // all of these return false when the currently processed message should be aborted (as each message actually contains multiple messages) - bool ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann); - bool ProcessMessageSigSharesInv(const CNode& pfrom, const CSigSharesInv& inv); - bool ProcessMessageGetSigShares(const CNode& pfrom, const CSigSharesInv& inv); - bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares); - void ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare); + bool ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageSigSharesInv(const CNode& pfrom, const CSigSharesInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageGetSigShares(const CNode& pfrom, const CSigSharesInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare) EXCLUSIVE_LOCKS_REQUIRED(!cs); static bool VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv); static bool PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager, @@ -462,35 +462,32 @@ class CSigSharesManager : public CRecoveredSigsListener bool CollectPendingSigSharesToVerify( size_t maxUniqueSessions, std::unordered_map>& retSigShares, - std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums); - bool ProcessPendingSigShares(); + std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs); void ProcessPendingSigShares( const std::vector& sigSharesToProcess, - const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums); + const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum); - void TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash); + void ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo); + bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo) EXCLUSIVE_LOCKS_REQUIRED(!cs); static CSigShare RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const std::pair& in); - void Cleanup(); + void Cleanup() EXCLUSIVE_LOCKS_REQUIRED(!cs); void RemoveSigSharesForSession(const uint256& signHash) EXCLUSIVE_LOCKS_REQUIRED(cs); - void RemoveBannedNodeStates(); + void RemoveBannedNodeStates() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void BanNode(NodeId nodeId); + void BanNode(NodeId nodeId) EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool SendMessages(); - void CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) - EXCLUSIVE_LOCKS_REQUIRED(cs); - void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend) - EXCLUSIVE_LOCKS_REQUIRED(cs); + bool SendMessages() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) EXCLUSIVE_LOCKS_REQUIRED(cs); + void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend) EXCLUSIVE_LOCKS_REQUIRED(cs); void CollectSigSharesToSendConcentrated(std::unordered_map>& sigSharesToSend, const std::vector& vNodes) EXCLUSIVE_LOCKS_REQUIRED(cs); - void CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) - EXCLUSIVE_LOCKS_REQUIRED(cs); - void SignPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns); - void WorkThreadMain() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns); + void CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) EXCLUSIVE_LOCKS_REQUIRED(cs); + void SignPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); + void WorkThreadMain() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); }; } // namespace llmq From 582e6e4d8e1973bf3745e21028a2ec55ea99c16a Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 10 Nov 2025 17:09:43 -0600 Subject: [PATCH 2/4] chore: run clang-format --- src/llmq/signing_shares.h | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index bce6f07bf3fe..f49c927ed068 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -434,17 +434,19 @@ class CSigSharesManager : public CRecoveredSigsListener void AsyncSign(CQuorumCPtr quorum, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); - std::optional CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - void ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); + std::optional CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id, + const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override EXCLUSIVE_LOCKS_REQUIRED(!cs); + [[nodiscard]] MessageProcessingResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override + EXCLUSIVE_LOCKS_REQUIRED(!cs); static CDeterministicMNCPtr SelectMemberForRecovery(const CQuorum& quorum, const uint256& id, int attempt); bool AsyncSignIfMember(Consensus::LLMQType llmqType, CSigningManager& sigman, const uint256& id, const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false, - bool allowDiffMsgHashSigning = false) - EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); + bool allowDiffMsgHashSigning = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); void NotifyRecoveredSig(const std::shared_ptr& sig) const EXCLUSIVE_LOCKS_REQUIRED(!cs); @@ -453,7 +455,8 @@ class CSigSharesManager : public CRecoveredSigsListener bool ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann) EXCLUSIVE_LOCKS_REQUIRED(!cs); bool ProcessMessageSigSharesInv(const CNode& pfrom, const CSigSharesInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs); bool ProcessMessageGetSigShares(const CNode& pfrom, const CSigSharesInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares) + EXCLUSIVE_LOCKS_REQUIRED(!cs); void ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare) EXCLUSIVE_LOCKS_REQUIRED(!cs); static bool VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv); @@ -462,17 +465,20 @@ class CSigSharesManager : public CRecoveredSigsListener bool CollectPendingSigSharesToVerify( size_t maxUniqueSessions, std::unordered_map>& retSigShares, - std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) EXCLUSIVE_LOCKS_REQUIRED(!cs); + std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& retQuorums) + EXCLUSIVE_LOCKS_REQUIRED(!cs); bool ProcessPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs); void ProcessPendingSigShares( const std::vector& sigSharesToProcess, - const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums) EXCLUSIVE_LOCKS_REQUIRED(!cs); + const std::unordered_map, CQuorumCPtr, StaticSaltedHasher>& quorums) + EXCLUSIVE_LOCKS_REQUIRED(!cs); void ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum) EXCLUSIVE_LOCKS_REQUIRED(!cs); void TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo) EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo) + EXCLUSIVE_LOCKS_REQUIRED(!cs); static CSigShare RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const std::pair& in); void Cleanup() EXCLUSIVE_LOCKS_REQUIRED(!cs); @@ -482,10 +488,13 @@ class CSigSharesManager : public CRecoveredSigsListener void BanNode(NodeId nodeId) EXCLUSIVE_LOCKS_REQUIRED(!cs); bool SendMessages() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) EXCLUSIVE_LOCKS_REQUIRED(cs); - void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend) EXCLUSIVE_LOCKS_REQUIRED(cs); + void CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) + EXCLUSIVE_LOCKS_REQUIRED(cs); + void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend) + EXCLUSIVE_LOCKS_REQUIRED(cs); void CollectSigSharesToSendConcentrated(std::unordered_map>& sigSharesToSend, const std::vector& vNodes) EXCLUSIVE_LOCKS_REQUIRED(cs); - void CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) EXCLUSIVE_LOCKS_REQUIRED(cs); + void CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) + EXCLUSIVE_LOCKS_REQUIRED(cs); void SignPendingSigShares() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); void WorkThreadMain() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); }; From 0a08b2a7a0ffb20ff187436abd302a01b8b992c5 Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 10 Nov 2025 21:24:33 -0600 Subject: [PATCH 3/4] refactor: enhance CSigSharesManager for single-member quorum handling Added a new method, ProcessRecoveredSigUnlocked, to handle recovered signatures outside of the lock to improve thread safety. Updated TryRecoverSig to utilize this new method for single-member quorum cases, ensuring proper lock management during signature processing. --- src/llmq/signing_shares.cpp | 20 ++++++++++++++++---- src/llmq/signing_shares.h | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index ca80f5d45c39..315dcf68c7f7 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -780,6 +780,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, std::vector sigSharesForRecovery; std::vector idsForRecovery; + std::shared_ptr singleMemberRecoveredSig; { LOCK(cs); @@ -802,10 +803,10 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- recover single-node signature. id=%s, msgHash=%s\n", __func__, id.ToString(), msgHash.ToString()); - auto rs = std::make_shared(quorum.params.type, quorum.qc->quorumHash, id, msgHash, + singleMemberRecoveredSig = std::make_shared(quorum.params.type, quorum.qc->quorumHash, id, msgHash, recoveredSig); - sigman.ProcessRecoveredSig(rs, m_peerman); - return; // end of single-quorum processing + // Release lock before calling ProcessRecoveredSig to avoid double lock in HandleNewRecoveredSig + // ProcessRecoveredSig will synchronously call HandleNewRecoveredSig which requires the lock } sigSharesForRecovery.reserve((size_t) quorum.params.threshold); @@ -822,6 +823,12 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, } } + // Handle single-member quorum case after releasing the lock + if (singleMemberRecoveredSig) { + ProcessRecoveredSigUnlocked(singleMemberRecoveredSig); + return; // end of single-quorum processing + } + // now recover it cxxtimer::Timer t(true); CBLSSignature recoveredSig; @@ -850,7 +857,12 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, } } - sigman.ProcessRecoveredSig(rs, m_peerman); + ProcessRecoveredSigUnlocked(rs); +} + +void CSigSharesManager::ProcessRecoveredSigUnlocked(const std::shared_ptr& recoveredSig) +{ + sigman.ProcessRecoveredSig(recoveredSig, m_peerman); } CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorum& quorum, const uint256 &id, int attempt) diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index f49c927ed068..425bfa1cff4c 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -477,6 +477,9 @@ class CSigSharesManager : public CRecoveredSigsListener void ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum) EXCLUSIVE_LOCKS_REQUIRED(!cs); void TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); +private: + void ProcessRecoveredSigUnlocked(const std::shared_ptr& recoveredSig) LOCKS_EXCLUDED(cs); + bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo) EXCLUSIVE_LOCKS_REQUIRED(!cs); static CSigShare RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const std::pair& in); From e98ba126a2a6d9350f1993af697abb71e04abed8 Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 10 Nov 2025 21:32:53 -0600 Subject: [PATCH 4/4] refactor: streamline signature recovery process in CSigSharesManager Removed the ProcessRecoveredSigUnlocked method and directly integrated its functionality into TryRecoverSig. This change simplifies the handling of recovered signatures for single-member quorums, ensuring proper lock management and enhancing code clarity. --- src/llmq/signing_shares.cpp | 11 ++--------- src/llmq/signing_shares.h | 3 --- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index 315dcf68c7f7..9b55774eadea 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -805,8 +805,6 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, singleMemberRecoveredSig = std::make_shared(quorum.params.type, quorum.qc->quorumHash, id, msgHash, recoveredSig); - // Release lock before calling ProcessRecoveredSig to avoid double lock in HandleNewRecoveredSig - // ProcessRecoveredSig will synchronously call HandleNewRecoveredSig which requires the lock } sigSharesForRecovery.reserve((size_t) quorum.params.threshold); @@ -825,7 +823,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, // Handle single-member quorum case after releasing the lock if (singleMemberRecoveredSig) { - ProcessRecoveredSigUnlocked(singleMemberRecoveredSig); + sigman.ProcessRecoveredSig(singleMemberRecoveredSig, m_peerman); return; // end of single-quorum processing } @@ -857,12 +855,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, } } - ProcessRecoveredSigUnlocked(rs); -} - -void CSigSharesManager::ProcessRecoveredSigUnlocked(const std::shared_ptr& recoveredSig) -{ - sigman.ProcessRecoveredSig(recoveredSig, m_peerman); + sigman.ProcessRecoveredSig(rs, m_peerman); } CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorum& quorum, const uint256 &id, int attempt) diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index 425bfa1cff4c..f49c927ed068 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -477,9 +477,6 @@ class CSigSharesManager : public CRecoveredSigsListener void ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum) EXCLUSIVE_LOCKS_REQUIRED(!cs); void TryRecoverSig(const CQuorum& quorum, const uint256& id, const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs); -private: - void ProcessRecoveredSigUnlocked(const std::shared_ptr& recoveredSig) LOCKS_EXCLUDED(cs); - bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo) EXCLUSIVE_LOCKS_REQUIRED(!cs); static CSigShare RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const std::pair& in);