diff --git a/src/evo/mnauth.cpp b/src/evo/mnauth.cpp index 9db16dd2cabaf..272c9305419e8 100644 --- a/src/evo/mnauth.cpp +++ b/src/evo/mnauth.cpp @@ -13,6 +13,7 @@ #include "llmq/quorums_utils.h" #include "util/system.h" // for fMasternode and gArgs access #include "net_processing.h" // for cs_main +#include "tiertwo/net_masternodes.h" #include "version.h" // for MNAUTH_NODE_VER_VERSION void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman) @@ -189,7 +190,15 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash(); } - // todo: add iqr connection, send interest in plain LLMQ recovered signatures. + if (!pnode->m_masternode_iqr_connection && connman.GetTierTwoConnMan()->isMasternodeQuorumRelayMember(pnode->verifiedProRegTxHash)) { + // Tell our peer that we're interested in plain LLMQ recovered signatures. + // Otherwise, the peer would only announce/send messages resulting from QRECSIG, + // future e.g. tx locks or chainlocks. SPV and regular full nodes should not send + // this message as they are usually only interested in the higher level messages. + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::QSENDRECSIGS, true)); + pnode->m_masternode_iqr_connection = true; + } LogPrint(BCLog::NET_MN, "CMNAuth::%s -- Valid MNAUTH for %s, peer=%d\n", __func__, mnauth.proRegTxHash.ToString(), pnode->GetId()); } diff --git a/src/net.h b/src/net.h index 5244a1aad6057..bf08cd7b9856e 100644 --- a/src/net.h +++ b/src/net.h @@ -346,6 +346,8 @@ class CConnman unsigned int GetReceiveFloodSize() const; void SetAsmap(std::vector asmap) { addrman.m_asmap = std::move(asmap); } + /** Unique tier two connections manager */ + TierTwoConnMan* GetTierTwoConnMan() { return m_tiertwo_conn_man.get(); }; private: struct ListenSocket { SOCKET socket; @@ -565,6 +567,8 @@ class CNodeStats bool m_masternode_connection{false}; // If 'true' this node will be disconnected after MNAUTH bool m_masternode_probe_connection{false}; + // If 'true', we identified it as an intra-quorum relay connection + bool m_masternode_iqr_connection{false}; // In case this is a verified MN, this value is the proTx of the MN uint256 verifiedProRegTxHash; // In case this is a verified MN, this value is the hashed operator pubkey of the MN @@ -661,7 +665,8 @@ class CNode bool fOneShot; bool fAddnode; bool m_masternode_connection{false}; // If true this node is only used for quorum related messages. - bool m_masternode_probe_connection{false}; // If true this will be disconnected right after the verack + bool m_masternode_probe_connection{false}; // If true this will be disconnected right after the verack. + bool m_masternode_iqr_connection{false}; // If 'true', we identified it as an intra-quorum relay connection. bool fClient; const bool fInbound; /** @@ -917,8 +922,7 @@ class CNode //! Sets the addrName only if it was not previously set void MaybeSetAddrName(const std::string& addrNameIn); - // todo: add iqr connection - bool CanRelay() const { return !m_masternode_connection; } + bool CanRelay() const { return !m_masternode_connection || m_masternode_iqr_connection; } }; class CExplicitNetCleanup diff --git a/src/tiertwo/net_masternodes.cpp b/src/tiertwo/net_masternodes.cpp index cb2d31485a4dd..36d15d5c63b9d 100644 --- a/src/tiertwo/net_masternodes.cpp +++ b/src/tiertwo/net_masternodes.cpp @@ -10,6 +10,7 @@ #include "scheduler.h" #include "tiertwo/masternode_meta_manager.h" // for g_mmetaman #include "masternode-sync.h" // for IsBlockchainSynced +#include "netmessagemaker.h" TierTwoConnMan::TierTwoConnMan(CConnman* _connman) : connman(_connman) {} TierTwoConnMan::~TierTwoConnMan() { connman = nullptr; } @@ -37,6 +38,30 @@ void TierTwoConnMan::removeQuorumNodes(Consensus::LLMQType llmqType, const uint2 masternodeQuorumNodes.erase(std::make_pair(llmqType, quorumHash)); } +void TierTwoConnMan::setMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::set& proTxHashes) +{ + { + LOCK(cs_vPendingMasternodes); + auto it = masternodeQuorumRelayMembers.emplace(std::make_pair(llmqType, quorumHash), proTxHashes); + if (!it.second) { + it.first->second = proTxHashes; + } + } + + // Update existing connections + connman->ForEachNode([&](CNode* pnode) { + if (!pnode->verifiedProRegTxHash.IsNull() && !pnode->m_masternode_iqr_connection && isMasternodeQuorumRelayMember(pnode->verifiedProRegTxHash)) { + // Tell our peer that we're interested in plain LLMQ recovered signatures. + // Otherwise, the peer would only announce/send messages resulting from QRECSIG, + // future e.g. tx locks or chainlocks. SPV and regular full nodes should not send + // this message as they are usually only interested in the higher level messages. + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSENDRECSIGS, true)); + pnode->m_masternode_iqr_connection = true; + } + }); +} + bool TierTwoConnMan::isMasternodeQuorumNode(const CNode* pnode) { // Let's see if this is an outgoing connection to an address that is known to be a masternode @@ -67,6 +92,20 @@ bool TierTwoConnMan::isMasternodeQuorumNode(const CNode* pnode) return false; } +bool TierTwoConnMan::isMasternodeQuorumRelayMember(const uint256& protxHash) +{ + if (protxHash.IsNull()) { + return false; + } + LOCK(cs_vPendingMasternodes); + for (const auto& p : masternodeQuorumRelayMembers) { + if (p.second.count(protxHash) > 0) { + return true; + } + } + return false; +} + bool TierTwoConnMan::addPendingMasternode(const uint256& proTxHash) { LOCK(cs_vPendingMasternodes); diff --git a/src/tiertwo/net_masternodes.h b/src/tiertwo/net_masternodes.h index c86d89ee95563..0a7919d16be95 100644 --- a/src/tiertwo/net_masternodes.h +++ b/src/tiertwo/net_masternodes.h @@ -40,9 +40,15 @@ class TierTwoConnMan // Remove the registered quorum from the pending/protected MN connections void removeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash); + // Add MNs to the active quorum relay members map and push QSENDRECSIGS to the verified connected peers that are part of this new quorum. + void setMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::set& proTxHashes); + // Returns true if the node has the same address as a MN. bool isMasternodeQuorumNode(const CNode* pnode); + // Whether protxHash an active quorum relay member + bool isMasternodeQuorumRelayMember(const uint256& protxHash); + // Add DMN to the pending connection list bool addPendingMasternode(const uint256& proTxHash); @@ -63,6 +69,7 @@ class TierTwoConnMan std::vector vPendingMasternodes GUARDED_BY(cs_vPendingMasternodes); typedef std::pair QuorumTypeAndHash; std::map> masternodeQuorumNodes GUARDED_BY(cs_vPendingMasternodes); + std::map> masternodeQuorumRelayMembers GUARDED_BY(cs_vPendingMasternodes); std::set masternodePendingProbes GUARDED_BY(cs_vPendingMasternodes); // parent connections manager