diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 6e2b56cad4..79c1b7fc1c 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -713,7 +713,7 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re CInv inv(MSG_QUORUM_RECOVERED_SIG, recoveredSig.GetHash()); g_connman->ForEachNode([&](CNode* pnode) { - if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->fSendRecSigs) { + if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->fSendRecSigs && !pnode->fMasternode) { pnode->PushInventory(inv); } }); diff --git a/src/masternode/masternode-utils.cpp b/src/masternode/masternode-utils.cpp index d7e6b4097e..fdff535ae7 100644 --- a/src/masternode/masternode-utils.cpp +++ b/src/masternode/masternode-utils.cpp @@ -39,7 +39,7 @@ void CMasternodeUtils::ProcessMasternodeConnections(CConnman& connman) } connman.ForEachNode(CConnman::AllNodes, [&](CNode* pnode) { - if (pnode->fMasternode && !connman.IsMasternodeQuorumNode(pnode)) { + if (!pnode->fInbound && pnode->fMasternode && !connman.IsMasternodeQuorumNode(pnode)) { #ifdef ENABLE_WALLET bool fFound = false; for (const auto& dmn : vecDmns) { diff --git a/src/net.cpp b/src/net.cpp index 7cee6848ba..b25e572946 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -761,6 +761,7 @@ void CNode::copyStats(CNodeStats &stats) LOCK(cs_mnauth); X(verifiedProRegTxHash); } + X(fMasternode); } #undef X @@ -2947,22 +2948,26 @@ void CConnman::RelayTransaction(const CTransaction& tx) LOCK(cs_vNodes); for (CNode* pnode : vNodes) { + if (pnode->fMasternode) + continue; pnode->PushInventory(inv); } } -void CConnman::RelayInv(CInv &inv, const int minProtoVersion) { +void CConnman::RelayInv(CInv &inv, const int minProtoVersion, bool fAllowMasternodeConnections) { LOCK(cs_vNodes); - for (const auto& pnode : vNodes) - if(pnode->nVersion >= minProtoVersion) - pnode->PushInventory(inv); + for (const auto& pnode : vNodes) { + if (pnode->nVersion < minProtoVersion || (pnode->fMasternode && !fAllowMasternodeConnections)) + continue; + pnode->PushInventory(inv); + } } -void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx, const int minProtoVersion) +void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx, const int minProtoVersion, bool fAllowMasternodeConnections) { LOCK(cs_vNodes); for (const auto& pnode : vNodes) { - if(pnode->nVersion < minProtoVersion) + if (pnode->nVersion < minProtoVersion || (pnode->fMasternode && !fAllowMasternodeConnections)) continue; { LOCK(pnode->cs_filter); @@ -2973,11 +2978,12 @@ void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx, const } } -void CConnman::RelayInvFiltered(CInv &inv, const uint256& relatedTxHash, const int minProtoVersion) +void CConnman::RelayInvFiltered(CInv &inv, const uint256& relatedTxHash, const int minProtoVersion, bool fAllowMasternodeConnections) { LOCK(cs_vNodes); for (const auto& pnode : vNodes) { - if(pnode->nVersion < minProtoVersion) continue; + if (pnode->nVersion < minProtoVersion || (pnode->fMasternode && !fAllowMasternodeConnections)) + continue; { LOCK(pnode->cs_filter); if(pnode->pfilter && !pnode->pfilter->contains(relatedTxHash)) continue; diff --git a/src/net.h b/src/net.h index 893a4bdf3e..461e83619b 100644 --- a/src/net.h +++ b/src/net.h @@ -353,10 +353,10 @@ public: void ReleaseNodeVector(const std::vector& vecNodes); void RelayTransaction(const CTransaction& tx); - void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION); - void RelayInvFiltered(CInv &inv, const CTransaction &relatedTx, const int minProtoVersion = MIN_PEER_PROTO_VERSION); + void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION, bool fAllowMasternodeConnections = false); + void RelayInvFiltered(CInv &inv, const CTransaction &relatedTx, const int minProtoVersion = MIN_PEER_PROTO_VERSION, bool fAllowMasternodeConnections = false); // This overload will not update node filters, so use it only for the cases when other messages will update related transaction data in filters - void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash, const int minProtoVersion = MIN_PEER_PROTO_VERSION); + void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash, const int minProtoVersion = MIN_PEER_PROTO_VERSION, bool fAllowMasternodeConnections = false); void RemoveAskFor(const uint256& hash); // Addrman functions @@ -707,6 +707,7 @@ public: CAddress addrBind; // In case this is a verified MN, this value is the proTx of the MN uint256 verifiedProRegTxHash; + bool fMasternode; }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 80dbfa5693..67712dd0d9 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -321,7 +321,7 @@ void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) } connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes, mnauthChallenge)); + nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes, mnauthChallenge, pnode->fMasternode)); if (fLogIPs) { LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); @@ -955,6 +955,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB } // Relay inventory, but don't relay old inventory during initial block download. connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) { + if (pnode->fMasternode) return; if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) { for (const uint256& hash : reverse_iterate(vHashes)) { pnode->PushBlockHash(hash); @@ -1870,6 +1871,21 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(pfrom->cs_mnauth); vRecv >> pfrom->receivedMNAuthChallenge; } + if (!vRecv.empty()) { + bool fOtherMasternode = false; + vRecv >> fOtherMasternode; + if (pfrom->fInbound) { + pfrom->fMasternode = fOtherMasternode; + if (fOtherMasternode) { + LogPrint(BCLog::NET, "peer=%d is an inbound masternode connection, not relaying anything to it\n", pfrom->GetId()); + if (!fMasternodeMode) { + LogPrint(BCLog::NET, "but we're not a masternode, disconnecting\n"); + pfrom->fDisconnect = true; + return true; + } + } + } + } // Disconnect if we connected to ourself if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce)) { @@ -2309,7 +2325,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; } - pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); + if (!pfrom->fMasternode) { + pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); + } if (--nLimit <= 0) { // When this block is requested, we'll send an inv that'll @@ -3606,7 +3624,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic& interruptM if (pindexBestHeader == nullptr) pindexBestHeader = chainActive.Tip(); bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. - if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { + if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex && !pto->fMasternode) { // Only actively request headers from a single peer, unless we're close to end of initial download. if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) { state.fSyncStarted = true; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index ab34258816..e4d22d2059 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -97,6 +97,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) " \"subver\": \"/Dash Core:x.x.x/\", (string) The string version\n" " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n" " \"addnode\": true|false, (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n" + " \"masternode\": true|false, (boolean) Whether connection was due to masternode connection attempt\n" " \"startingheight\": n, (numeric) The starting height (block) of the peer\n" " \"banscore\": n, (numeric) The ban score\n" " \"synced_headers\": n, (numeric) The last header we have in common with this peer\n" @@ -164,6 +165,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) obj.push_back(Pair("subver", stats.cleanSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); obj.push_back(Pair("addnode", stats.m_manual_connection)); + obj.push_back(Pair("masternode", stats.fMasternode)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); if (fStateStats) { obj.push_back(Pair("banscore", statestats.nMisbehavior)); diff --git a/test/functional/llmq-chainlocks.py b/test/functional/llmq-chainlocks.py index b5277c8bef..76ddd3160c 100755 --- a/test/functional/llmq-chainlocks.py +++ b/test/functional/llmq-chainlocks.py @@ -23,6 +23,13 @@ class LLMQChainLocksTest(DashTestFramework): def run_test(self): + # Connect all nodes to node1 so that we always have the whole network connected + # Otherwise only masternode connections will be established between nodes, which won't propagate TXs/blocks + # Usually node0 is the one that does this, but in this test we isolate it multiple times + for i in range(len(self.nodes)): + if i != 1: + connect_nodes(self.nodes[i], 1) + self.log.info("Wait for dip0008 activation") while self.nodes[0].getblockchaininfo()["bip9_softforks"]["dip0008"]["status"] != "active":