mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
feat(llmq): Ensure connections between IS quorums (#4917)
* fix(llmq): Ensure connections between quorums Every masternode will now "watch" a single node from _every other_ quorum in addition to intra-quorum connections. This should make propagation of recsigs produced by one quorum to other quorums much more reliable. * fix: Do this only for masternodes which participate in IS quorums * refactor: rename `CQuorumManager::EnsureQuorumConnections` to better match the actual behaviour (and avoid confusion with `CLLMQUtils::EnsureQuorumConnections`) * refactor: move IS quorums watch logic into `CQuorumManager::CheckQuorumConnections` avoid calling slow `ScanQuorums` (no caching atm) inside the loop * tests: check that inter-quorum connections are added * use `ranges::any_of`
This commit is contained in:
parent
a1f54a6079
commit
9e22801878
@ -243,7 +243,7 @@ void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitial
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& params : Params().GetConsensus().llmqs) {
|
for (auto& params : Params().GetConsensus().llmqs) {
|
||||||
EnsureQuorumConnections(params, pindexNew);
|
CheckQuorumConnections(params, pindexNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -262,7 +262,7 @@ void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitial
|
|||||||
TriggerQuorumDataRecoveryThreads(pindexNew);
|
TriggerQuorumDataRecoveryThreads(pindexNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuorumManager::EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindexNew) const
|
void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindexNew) const
|
||||||
{
|
{
|
||||||
auto lastQuorums = ScanQuorums(llmqParams.type, pindexNew, (size_t)llmqParams.keepOldConnections);
|
auto lastQuorums = ScanQuorums(llmqParams.type, pindexNew, (size_t)llmqParams.keepOldConnections);
|
||||||
|
|
||||||
@ -289,11 +289,36 @@ void CQuorumManager::EnsureQuorumConnections(const Consensus::LLMQParams& llmqPa
|
|||||||
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] keeping mn quorum connections for quorum: [%d:%s]\n", __func__, int(llmqParams.type), pindexNew->nHeight, curDkgHeight, curDkgBlock.ToString());
|
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] keeping mn quorum connections for quorum: [%d:%s]\n", __func__, int(llmqParams.type), pindexNew->nHeight, curDkgHeight, curDkgBlock.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto myProTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
|
||||||
|
bool isISType = llmqParams.type == Params().GetConsensus().llmqTypeInstantSend ||
|
||||||
|
llmqParams.type == Params().GetConsensus().llmqTypeDIP0024InstantSend;
|
||||||
|
|
||||||
|
bool watchOtherISQuorums = isISType && !myProTxHash.IsNull() &&
|
||||||
|
ranges::any_of(lastQuorums, [&myProTxHash](const auto& old_quorum){
|
||||||
|
return old_quorum->IsMember(myProTxHash);
|
||||||
|
});
|
||||||
|
|
||||||
for (const auto& quorum : lastQuorums) {
|
for (const auto& quorum : lastQuorums) {
|
||||||
if (CLLMQUtils::EnsureQuorumConnections(llmqParams, quorum->m_quorum_base_block_index, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) {
|
if (CLLMQUtils::EnsureQuorumConnections(llmqParams, quorum->m_quorum_base_block_index, myProTxHash)) {
|
||||||
if (connmanQuorumsToDelete.erase(quorum->qc->quorumHash) > 0) {
|
if (connmanQuorumsToDelete.erase(quorum->qc->quorumHash) > 0) {
|
||||||
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] keeping mn quorum connections for quorum: [%d:%s]\n", __func__, int(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
|
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] keeping mn quorum connections for quorum: [%d:%s]\n", __func__, int(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
|
||||||
}
|
}
|
||||||
|
} else if (watchOtherISQuorums && !quorum->IsMember(myProTxHash)) {
|
||||||
|
std::set<uint256> connections;
|
||||||
|
const auto& cindexes = CLLMQUtils::CalcDeterministicWatchConnections(llmqParams.type, quorum->m_quorum_base_block_index, quorum->members.size(), 1);
|
||||||
|
for (auto idx : cindexes) {
|
||||||
|
connections.emplace(quorum->members[idx]->proTxHash);
|
||||||
|
}
|
||||||
|
if (!connections.empty()) {
|
||||||
|
if (!g_connman->HasMasternodeQuorumNodes(llmqParams.type, quorum->m_quorum_base_block_index->GetBlockHash())) {
|
||||||
|
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] adding mn inter-quorum connections for quorum: [%d:%s]\n", __func__, int(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
|
||||||
|
g_connman->SetMasternodeQuorumNodes(llmqParams.type, quorum->m_quorum_base_block_index->GetBlockHash(), connections);
|
||||||
|
g_connman->SetMasternodeQuorumRelayMembers(llmqParams.type, quorum->m_quorum_base_block_index->GetBlockHash(), connections);
|
||||||
|
}
|
||||||
|
if (connmanQuorumsToDelete.erase(quorum->qc->quorumHash) > 0) {
|
||||||
|
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] keeping mn inter-quorum connections for quorum: [%d:%s]\n", __func__, int(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto& quorumHash : connmanQuorumsToDelete) {
|
for (const auto& quorumHash : connmanQuorumsToDelete) {
|
||||||
|
@ -224,7 +224,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// all private methods here are cs_main-free
|
// all private methods here are cs_main-free
|
||||||
void EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex *pindexNew) const;
|
void CheckQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex *pindexNew) const;
|
||||||
|
|
||||||
CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) const EXCLUSIVE_LOCKS_REQUIRED(quorumsCacheCs);
|
CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) const EXCLUSIVE_LOCKS_REQUIRED(quorumsCacheCs);
|
||||||
bool BuildQuorumContributions(const CFinalCommitmentPtr& fqc, const std::shared_ptr<CQuorum>& quorum) const;
|
bool BuildQuorumContributions(const CFinalCommitmentPtr& fqc, const std::shared_ptr<CQuorum>& quorum) const;
|
||||||
|
@ -701,13 +701,24 @@ std::set<size_t> CLLMQUtils::CalcDeterministicWatchConnections(Consensus::LLMQTy
|
|||||||
|
|
||||||
bool CLLMQUtils::EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& myProTxHash)
|
bool CLLMQUtils::EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& myProTxHash)
|
||||||
{
|
{
|
||||||
|
if (!fMasternodeMode && !CLLMQUtils::IsWatchQuorumsEnabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto members = GetAllQuorumMembers(llmqParams.type, pQuorumBaseBlockIndex);
|
auto members = GetAllQuorumMembers(llmqParams.type, pQuorumBaseBlockIndex);
|
||||||
|
if (members.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool isMember = std::find_if(members.begin(), members.end(), [&](const auto& dmn) { return dmn->proTxHash == myProTxHash; }) != members.end();
|
bool isMember = std::find_if(members.begin(), members.end(), [&](const auto& dmn) { return dmn->proTxHash == myProTxHash; }) != members.end();
|
||||||
|
|
||||||
if (!isMember && !CLLMQUtils::IsWatchQuorumsEnabled()) {
|
if (!isMember && !CLLMQUtils::IsWatchQuorumsEnabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogPrint(BCLog::NET_NETCONN, "CLLMQUtils::%s -- isMember=%d for quorum %s:\n",
|
||||||
|
__func__, isMember, pQuorumBaseBlockIndex->GetBlockHash().ToString());
|
||||||
|
|
||||||
std::set<uint256> connections;
|
std::set<uint256> connections;
|
||||||
std::set<uint256> relayMembers;
|
std::set<uint256> relayMembers;
|
||||||
if (isMember) {
|
if (isMember) {
|
||||||
|
@ -69,6 +69,20 @@ class LLMQConnections(DashTestFramework):
|
|||||||
|
|
||||||
self.check_reconnects(4)
|
self.check_reconnects(4)
|
||||||
|
|
||||||
|
self.log.info("check that inter-quorum masternode conections are added")
|
||||||
|
added = False
|
||||||
|
for mn in self.mninfo:
|
||||||
|
if len(mn.node.quorum("memberof", mn.proTxHash)) > 0:
|
||||||
|
try:
|
||||||
|
with mn.node.assert_debug_log(['adding mn inter-quorum connections']):
|
||||||
|
self.mine_quorum()
|
||||||
|
added = True
|
||||||
|
except:
|
||||||
|
pass # it's ok to not add connections sometimes
|
||||||
|
if added:
|
||||||
|
break
|
||||||
|
assert added # no way we added none
|
||||||
|
|
||||||
def check_reconnects(self, expected_connection_count):
|
def check_reconnects(self, expected_connection_count):
|
||||||
self.log.info("disable and re-enable networking on all masternodes")
|
self.log.info("disable and re-enable networking on all masternodes")
|
||||||
for mn in self.mninfo:
|
for mn in self.mninfo:
|
||||||
|
Loading…
Reference in New Issue
Block a user