diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index 4a1ac7a6b528..d4218f04aad7 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -517,7 +518,7 @@ void CSigningManager::ProcessPendingReconstructedRecoveredSigs(PeerManager& peer WITH_LOCK(cs_pending, swap(m, pendingReconstructedRecoveredSigs)); for (const auto& p : m) { - ProcessRecoveredSig(p.second, peerman); + ProcessRecoveredSig(p.second, peerman, /*from=*/-1); } } @@ -579,7 +580,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(PeerManager& peerman) continue; } - ProcessRecoveredSig(recSig, peerman); + ProcessRecoveredSig(recSig, peerman, nodeId); } } @@ -587,7 +588,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(PeerManager& peerman) } // signature must be verified already -void CSigningManager::ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman) +void CSigningManager::ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman, NodeId from) { auto llmqType = recoveredSig->getLlmqType(); @@ -630,7 +631,12 @@ void CSigningManager::ProcessRecoveredSig(const std::shared_ptrHandleNewRecoveredSig(*recoveredSig)); } - GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString()); + // TODO refactor to use a better abstraction analogous to IsAllMembersConnectedEnabled + auto proactive_relay = from == -1 && + llmqType != Consensus::LLMQType::LLMQ_100_67 && + llmqType != Consensus::LLMQType::LLMQ_400_60 && + llmqType != Consensus::LLMQType::LLMQ_400_85; + GetMainSignals().NotifyRecoveredSig(recoveredSig, recoveredSig->GetHash().ToString(), proactive_relay); } void CSigningManager::PushReconstructedRecoveredSig(const std::shared_ptr& recoveredSig) diff --git a/src/llmq/signing.h b/src/llmq/signing.h index d4149314c011..e37f79093172 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -220,7 +220,7 @@ class CSigningManager // Used by CSigSharesManager CRecoveredSigsDb& GetDb() { return db; } - void ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman) + void ProcessRecoveredSig(const std::shared_ptr& recoveredSig, PeerManager& peerman, NodeId from) EXCLUSIVE_LOCKS_REQUIRED(!cs_pending, !cs_listeners); // Needed for access to GetDb() and ProcessRecoveredSig() diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index ef899d1b1134..f14116e43383 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -844,7 +844,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, // Handle single-member quorum case after releasing the lock if (singleMemberRecoveredSig) { - sigman.ProcessRecoveredSig(singleMemberRecoveredSig, m_peerman); + sigman.ProcessRecoveredSig(singleMemberRecoveredSig, m_peerman, /*from=*/-1); return; // end of single-quorum processing } @@ -876,7 +876,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorum& quorum, const uint256& id, } } - sigman.ProcessRecoveredSig(rs, m_peerman); + sigman.ProcessRecoveredSig(rs, m_peerman, /*from=*/-1); } CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorum& quorum, const uint256 &id, int attempt) @@ -974,9 +974,9 @@ bool CSigSharesManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigning return true; } -void CSigSharesManager::NotifyRecoveredSig(const std::shared_ptr& sig) const +void CSigSharesManager::NotifyRecoveredSig(const std::shared_ptr& sig, bool proactive_relay) const { - m_peerman.RelayRecoveredSig(Assert(sig)->GetHash()); + m_peerman.RelayRecoveredSig(*Assert(sig), proactive_relay); } void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) diff --git a/src/llmq/signing_shares.h b/src/llmq/signing_shares.h index 24865fec98a8..7e8e23eb17a3 100644 --- a/src/llmq/signing_shares.h +++ b/src/llmq/signing_shares.h @@ -449,7 +449,7 @@ class CSigSharesManager : public CRecoveredSigsListener const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false, bool allowDiffMsgHashSigning = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs); - void NotifyRecoveredSig(const std::shared_ptr& sig) const EXCLUSIVE_LOCKS_REQUIRED(!cs); + void NotifyRecoveredSig(const std::shared_ptr& sig, bool proactive_relay) const EXCLUSIVE_LOCKS_REQUIRED(!cs); private: std::optional CreateSigShareForSingleMember(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const; diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 099f5f74c9b9..be3307675bea 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -858,17 +858,14 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& __func__, isMember, pQuorumBaseBlockIndex->GetBlockHash().ToString()); Uint256HashSet connections; - Uint256HashSet relayMembers; if (isMember) { connections = GetQuorumConnections(llmqParams, dmnman, qsnapman, sporkman, pQuorumBaseBlockIndex, myProTxHash, true); - relayMembers = GetQuorumRelayMembers(llmqParams, dmnman, qsnapman, pQuorumBaseBlockIndex, myProTxHash, true); } else { auto cindexes = CalcDeterministicWatchConnections(llmqParams.type, pQuorumBaseBlockIndex, members.size(), 1); for (auto idx : cindexes) { connections.emplace(members[idx]->proTxHash); } - relayMembers = connections; } if (!connections.empty()) { if (!connman.HasMasternodeQuorumNodes(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash()) && @@ -886,9 +883,7 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& LogPrint(BCLog::NET_NETCONN, debugMsg.c_str()); /* Continued */ } connman.SetMasternodeQuorumNodes(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash(), connections); - } - if (!relayMembers.empty()) { - connman.SetMasternodeQuorumRelayMembers(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash(), relayMembers); + connman.SetMasternodeQuorumRelayMembers(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash(), connections); } return true; } diff --git a/src/masternode/active/notificationinterface.cpp b/src/masternode/active/notificationinterface.cpp index 17340861ae6c..126ba167940b 100644 --- a/src/masternode/active/notificationinterface.cpp +++ b/src/masternode/active/notificationinterface.cpp @@ -29,9 +29,9 @@ void ActiveNotificationInterface::UpdatedBlockTip(const CBlockIndex* pindexNew, m_active_ctx.gov_signer->UpdatedBlockTip(pindexNew); } -void ActiveNotificationInterface::NotifyRecoveredSig(const std::shared_ptr& sig) +void ActiveNotificationInterface::NotifyRecoveredSig(const std::shared_ptr& sig, bool proactive_relay) { - m_active_ctx.shareman->NotifyRecoveredSig(sig); + m_active_ctx.shareman->NotifyRecoveredSig(sig, proactive_relay); } std::unique_ptr g_active_notification_interface; diff --git a/src/masternode/active/notificationinterface.h b/src/masternode/active/notificationinterface.h index 905371e41b7a..fade9ede4130 100644 --- a/src/masternode/active/notificationinterface.h +++ b/src/masternode/active/notificationinterface.h @@ -26,7 +26,7 @@ class ActiveNotificationInterface final : public CValidationInterface protected: // CValidationInterface - void NotifyRecoveredSig(const std::shared_ptr& sig) override; + void NotifyRecoveredSig(const std::shared_ptr& sig, bool proactive_relay) override; void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override; private: diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 9808fb9f646a..c3180f3e8b61 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -632,7 +632,7 @@ class PeerManagerImpl final : public PeerManager void RelayInv(const CInv& inv) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayInv(const CInv& inv, const int minProtoVersion) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - void RelayRecoveredSig(const uint256& sigHash) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayDSQ(const CCoinJoinQueue& queue) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void SetBestHeight(int height) override { m_best_height = height; }; void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); @@ -2536,9 +2536,20 @@ void PeerManagerImpl::_RelayTransaction(const uint256& txid) }; } -void PeerManagerImpl::RelayRecoveredSig(const uint256& sigHash) -{ - const CInv inv{MSG_QUORUM_RECOVERED_SIG, sigHash}; +void PeerManagerImpl::RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) { + if (proactive_relay) { + // We were the peer that recovered this; avoid a bunch of `inv` -> `GetData` spam by proactively sending + m_connman.ForEachNode([this, &sig](CNode* pnode) -> bool { + // Skip nodes that don't want recovered signatures + PeerRef peer = GetPeerRef(pnode->GetId()); + if (peer == nullptr || !peer->m_wants_recsigs) return true; + CNetMsgMaker msgMaker(pnode->GetCommonVersion()); + m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGREC, sig)); + return true; + }); + return; + } + const CInv inv{MSG_QUORUM_RECOVERED_SIG, sig.GetHash()}; READ_LOCK(m_peer_mutex); for (const auto& [_, peer] : m_peer_map) { if (peer->m_wants_recsigs) { diff --git a/src/net_processing.h b/src/net_processing.h index d15298401c24..7dc68e272d53 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -133,7 +133,7 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ virtual void RelayTransaction(const uint256& txid) = 0; /** Relay recovered sigs to all interested peers */ - virtual void RelayRecoveredSig(const uint256& sigHash) = 0; + virtual void RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) = 0; /** Set the best height */ virtual void SetBestHeight(int height) = 0; diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index a71c7ab1f3c5..2fd14b426434 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -312,9 +312,9 @@ void CMainSignals::NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& cu previousTx->GetHash().ToString()); } -void CMainSignals::NotifyRecoveredSig(const std::shared_ptr& sig, const std::string& id) { - auto event = [sig, this] { - m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyRecoveredSig(sig); }); +void CMainSignals::NotifyRecoveredSig(const std::shared_ptr& sig, const std::string& id, bool proactive_relay) { + auto event = [sig, proactive_relay, this] { + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyRecoveredSig(sig, proactive_relay); }); }; ENQUEUE_AND_LOG_EVENT(event, "%s: notify recoveredsig=%s", __func__, id); diff --git a/src/validationinterface.h b/src/validationinterface.h index 271c76f88fa5..563133d29cc4 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -168,7 +168,7 @@ class CValidationInterface { virtual void NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote) {} virtual void NotifyGovernanceObject(const std::shared_ptr& object) {} virtual void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) {} - virtual void NotifyRecoveredSig(const std::shared_ptr& sig) {} + virtual void NotifyRecoveredSig(const std::shared_ptr& sig, bool proactive_relay) {} virtual void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) {} /** * Notifies listeners of the new active block chain on-disk. @@ -236,7 +236,7 @@ class CMainSignals { void NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote, const std::string& id); void NotifyGovernanceObject(const std::shared_ptr& object, const std::string& id); void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef ¤tTx, const CTransactionRef &previousTx); - void NotifyRecoveredSig(const std::shared_ptr &sig, const std::string& id); + void NotifyRecoveredSig(const std::shared_ptr &sig, const std::string& id, bool proactive_relay); void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff); void ChainStateFlushed(const CBlockLocator &); void BlockChecked(const CBlock&, const BlockValidationState&); diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 06e21f8cefef..7528e9ac8d77 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -241,7 +241,7 @@ void CZMQNotificationInterface::NotifyInstantSendDoubleSpendAttempt(const CTrans }); } -void CZMQNotificationInterface::NotifyRecoveredSig(const std::shared_ptr& sig) +void CZMQNotificationInterface::NotifyRecoveredSig(const std::shared_ptr& sig, bool /*proactive_relay*/) { TryForEachAndRemoveFailed(notifiers, [&sig](CZMQAbstractNotifier* notifier) { return notifier->NotifyRecoveredSig(sig); diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index e0de1074f4d3..3f935f407862 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -36,7 +36,7 @@ class CZMQNotificationInterface final : public CValidationInterface void NotifyGovernanceVote(const std::shared_ptr& tip_mn_list, const std::shared_ptr& vote) override; void NotifyGovernanceObject(const std::shared_ptr& object) override; void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) override; - void NotifyRecoveredSig(const std::shared_ptr& sig) override; + void NotifyRecoveredSig(const std::shared_ptr& sig, bool /*proactive_relay*/) override; private: CZMQNotificationInterface();