From 09d522d5a43f78a01be2789af17b572139db767f Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 21 Dec 2025 17:15:55 +0530 Subject: [PATCH 01/15] move-only: move `llmq/util.cpp` internals to anonymous namespace Also reorder them to help us get rid of the forward declarations, review with `git log -p -n1 --color-moved=dimmed_zebra`. --- src/llmq/snapshot.h | 7 +- src/llmq/utils.cpp | 670 +++++++++++++++++++++----------------------- 2 files changed, 325 insertions(+), 352 deletions(-) diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 7d64404c3610..1df138e296ab 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -20,12 +20,12 @@ class CBlockIndex; class CEvoDB; struct RPCResult; - -class UniValue; - namespace llmq { class CQuorumBlockProcessor; class CQuorumManager; +} // namespace llmq + +class UniValue; //TODO use enum class (probably) enum SnapshotSkipMode : int { @@ -35,6 +35,7 @@ enum SnapshotSkipMode : int { MODE_ALL_SKIPPED = 3 }; +namespace llmq { class CQuorumSnapshot { public: diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 405bc34e9c1b..f1b930a1b6b3 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -24,25 +24,12 @@ #include #include -class CBLSSignature; - /** * Forward declarations */ std::optional> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex); -static bool IsV19Active(gsl::not_null pindexPrev) -{ - return DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19); -} - -static bool IsV20Active(gsl::not_null pindexPrev) -{ - return DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20); -} - -namespace llmq { -namespace utils { +namespace { // QuorumMembers per quorumIndex at heights H-Cycle, H-2Cycles, H-3Cycles struct PreviousQuorumQuarters { std::vector> quarterHMinusC; @@ -52,34 +39,32 @@ struct PreviousQuorumQuarters { quarterHMinusC(s), quarterHMinus2C(s), quarterHMinus3C(s) {} }; -// Forward declarations -static std::vector ComputeQuorumMembers(Consensus::LLMQType llmqType, - const CDeterministicMNList& mn_list, - const CBlockIndex* pQuorumBaseBlockIndex); -static std::vector> ComputeQuorumMembersByQuarterRotation( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, const CBlockIndex* pCycleQuorumBaseBlockIndex); - -static std::vector> BuildNewQuorumQuarterMembers( - const Consensus::LLMQParams& llmqParams, CQuorumSnapshotManager& qsnapman, const CDeterministicMNList& allMns, - const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters); - -static PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, - CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, - const CBlockIndex* pBlockHMinusCIndex, - const CBlockIndex* pBlockHMinus2CIndex, - const CBlockIndex* pBlockHMinus3CIndex, int nHeight); -static std::vector> GetQuorumQuarterMembersBySnapshot( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, - const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight); +bool IsV19Active(gsl::not_null pindexPrev) +{ + return DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19); +} + +bool IsV20Active(gsl::not_null pindexPrev) +{ + return DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20); +} -static void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, - const CDeterministicMNList& mnUsedAtH, - std::vector& sortedCombinedMns, CQuorumSnapshot& quorumSnapshot, - int nHeight, std::vector& skipList, const CBlockIndex* pCycleQuorumBaseBlockIndex); +arith_uint256 calculateQuorumScore(const CDeterministicMNCPtr& dmn, const uint256& modifier) +{ + // calculate sha256(sha256(proTxHash, confirmedHash), modifier) per MN + // Please note that this is not a double-sha256 but a single-sha256 + // The first part is already precalculated (confirmedHashWithProRegTxHash) + // TODO When https://github.com/bitcoin/bitcoin/pull/13191 gets backported, implement something that is similar but for single-sha256 + uint256 h; + CSHA256 sha256; + sha256.Write(dmn->pdmnState->confirmedHashWithProRegTxHash.begin(), + dmn->pdmnState->confirmedHashWithProRegTxHash.size()); + sha256.Write(modifier.begin(), modifier.size()); + sha256.Finalize(h.begin()); + return UintToArith256(h); +} -static uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex) +uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex) { ASSERT_IF_DEBUG(pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval == 0); const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); @@ -103,23 +88,8 @@ static uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not return ::SerializeHash(std::make_pair(llmqParams.type, pCycleQuorumBaseBlockIndex->GetBlockHash())); } -static arith_uint256 calculateQuorumScore(const CDeterministicMNCPtr& dmn, const uint256& modifier) -{ - // calculate sha256(sha256(proTxHash, confirmedHash), modifier) per MN - // Please note that this is not a double-sha256 but a single-sha256 - // The first part is already precalculated (confirmedHashWithProRegTxHash) - // TODO When https://github.com/bitcoin/bitcoin/pull/13191 gets backported, implement something that is similar but for single-sha256 - uint256 h; - CSHA256 sha256; - sha256.Write(dmn->pdmnState->confirmedHashWithProRegTxHash.begin(), - dmn->pdmnState->confirmedHashWithProRegTxHash.size()); - sha256.Write(modifier.begin(), modifier.size()); - sha256.Finalize(h.begin()); - return UintToArith256(h); -} - -static std::vector> CalculateScoresForQuorum( - std::vector&& dmns, const uint256& modifier, const bool onlyEvoNodes) +std::vector> + CalculateScoresForQuorum(std::vector&& dmns, const uint256& modifier, const bool onlyEvoNodes) { std::vector> scores; scores.reserve(dmns.size()); @@ -139,8 +109,8 @@ static std::vector> CalculateScor return scores; } -static std::vector> CalculateScoresForQuorum( - const CDeterministicMNList& mn_list, const uint256& modifier, const bool onlyEvoNodes) +std::vector> + CalculateScoresForQuorum(const CDeterministicMNList& mn_list, const uint256& modifier, const bool onlyEvoNodes) { std::vector> scores; scores.reserve(mn_list.GetAllMNsCount()); @@ -160,13 +130,12 @@ static std::vector> CalculateScor return scores; } - /** * Calculate a quorum based on the modifier. The resulting list is deterministically sorted by score */ template -static std::vector CalculateQuorum(List&& mn_list, const uint256& modifier, size_t maxSize = 0, - const bool onlyEvoNodes = false) +std::vector CalculateQuorum(List&& mn_list, const uint256& modifier, size_t maxSize = 0, + const bool onlyEvoNodes = false) { auto scores = CalculateScoresForQuorum(std::forward(mn_list), modifier, onlyEvoNodes); @@ -195,88 +164,112 @@ static std::vector CalculateQuorum(List&& mn_list, const u return result; } -std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, - bool reset_cache) +std::vector> GetQuorumQuarterMembersBySnapshot( + const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, + const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight) { - static RecursiveMutex cs_members; - static std::map>> mapQuorumMembers GUARDED_BY( - cs_members); - static RecursiveMutex cs_indexed_members; - static std::map, std::vector, StaticSaltedHasher>> mapIndexedQuorumMembers GUARDED_BY(cs_indexed_members); - if (!chainman.IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) { + if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { + ASSERT_IF_DEBUG(false); return {}; } - std::vector quorumMembers; + + std::vector sortedCombinedMns; { - LOCK(cs_members); - if (mapQuorumMembers.empty()) { - InitQuorumsCache(mapQuorumMembers); + const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor( + pCycleQuorumBaseBlockIndex->nHeight - 8); + auto mn_list = dmnman.GetListForBlock(pWorkBlockIndex); + const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); + auto sortedAllMns = CalculateQuorum(mn_list, modifier); + + std::vector usedMNs; + size_t i{0}; + for (const auto& dmn : sortedAllMns) { + if (snapshot.activeQuorumMembers[i]) { + usedMNs.push_back(dmn); + } else { + if (!dmn->pdmnState->IsBanned()) { + // the list begins with all the unused MNs + sortedCombinedMns.push_back(dmn); + } + } + i++; } - if (reset_cache) { - mapQuorumMembers[llmqType].clear(); - } else if (mapQuorumMembers[llmqType].get(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers)) { - return quorumMembers; + + // Now add the already used MNs to the end of the list + std::move(usedMNs.begin(), usedMNs.end(), std::back_inserter(sortedCombinedMns)); + } + + if (LogAcceptDebug(BCLog::LLMQ)) { + std::stringstream ss; + ss << " ["; + for (const auto &m: sortedCombinedMns) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; } + ss << "]"; + LogPrint(BCLog::LLMQ, "GetQuorumQuarterMembersBySnapshot h[%d] from[%d] sortedCombinedMns[%s]\n", + pCycleQuorumBaseBlockIndex->nHeight, nHeight, ss.str()); } - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); - assert(llmq_params_opt.has_value()); - const auto& llmq_params = llmq_params_opt.value(); + size_t numQuorums = static_cast(llmqParams.signingActiveQuorumCount); + size_t quorumSize = static_cast(llmqParams.size); + auto quarterSize{quorumSize / 4}; - if (IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex)) { - if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) { - InitQuorumsCache(mapIndexedQuorumMembers); - } - /* - * Quorums created with rotation are now created in a different way. All signingActiveQuorumCount are created during the period of dkgInterval. - * But they are not created exactly in the same block, they are spread overtime: one quorum in each block until all signingActiveQuorumCount are created. - * The new concept of quorumIndex is introduced in order to identify them. - * In every dkgInterval blocks (also called CycleQuorumBaseBlock), the spread quorum creation starts like this: - * For quorumIndex = 0 : signingActiveQuorumCount - * Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex - */ + std::vector> quarterQuorumMembers(numQuorums); - int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval; - if (quorumIndex >= llmq_params.signingActiveQuorumCount) { - return {}; - } - int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex; - const CBlockIndex* pCycleQuorumBaseBlockIndex = pQuorumBaseBlockIndex->GetAncestor(cycleQuorumBaseHeight); + if (sortedCombinedMns.empty()) { + return quarterQuorumMembers; + } - /* - * Since mapQuorumMembers stores Quorum members per block hash, and we don't know yet the block hashes of blocks for all quorumIndexes (since these blocks are not created yet) - * We store them in a second cache mapIndexedQuorumMembers which stores them by {CycleQuorumBaseBlockHash, quorumIndex} - */ - if (reset_cache) { - LOCK(cs_indexed_members); - mapIndexedQuorumMembers[llmqType].clear(); - } else if (LOCK(cs_indexed_members); mapIndexedQuorumMembers[llmqType].get(std::pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), quorumIndex), quorumMembers)) { - LOCK(cs_members); - mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers); - return quorumMembers; + switch (snapshot.mnSkipListMode) { + case SnapshotSkipMode::MODE_NO_SKIPPING: + { + auto itm = sortedCombinedMns.begin(); + for (const size_t i : irange::range(numQuorums)) { + while (quarterQuorumMembers[i].size() < quarterSize) { + quarterQuorumMembers[i].push_back(*itm); + itm++; + if (itm == sortedCombinedMns.end()) { + itm = sortedCombinedMns.begin(); + } + } + } + return quarterQuorumMembers; } + case SnapshotSkipMode::MODE_SKIPPING_ENTRIES: // List holds entries to be skipped + { + size_t first_entry_index{0}; + std::vector processesdSkipList; + for (const auto& s : snapshot.mnSkipList) { + if (first_entry_index == 0) { + first_entry_index = s; + processesdSkipList.push_back(s); + } else { + processesdSkipList.push_back(first_entry_index + s); + } + } - auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, dmnman, qsnapman, chainman, pCycleQuorumBaseBlockIndex); - quorumMembers = q[quorumIndex]; - - LOCK(cs_indexed_members); - for (const size_t i : irange::range(q.size())) { - mapIndexedQuorumMembers[llmqType].emplace(std::make_pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), i), - std::move(q[i])); + int idx = 0; + auto itsk = processesdSkipList.begin(); + for (const size_t i : irange::range(numQuorums)) { + while (quarterQuorumMembers[i].size() < quarterSize) { + if (itsk != processesdSkipList.end() && idx == *itsk) { + itsk++; + } else { + quarterQuorumMembers[i].push_back(sortedCombinedMns[idx]); + } + idx++; + if (idx == static_cast(sortedCombinedMns.size())) { + idx = 0; + } + } + } + return quarterQuorumMembers; } - } else { - const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) - ? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) - : pQuorumBaseBlockIndex.get(); - CDeterministicMNList mn_list = dmnman.GetListForBlock(pWorkBlockIndex); - quorumMembers = ComputeQuorumMembers(llmqType, mn_list, pQuorumBaseBlockIndex); + case SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES: // List holds entries to be kept + case SnapshotSkipMode::MODE_ALL_SKIPPED: // Every node was skipped. Returning empty quarterQuorumMembers + default: + return quarterQuorumMembers; } - - LOCK(cs_members); - mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers); - return quorumMembers; } std::vector ComputeQuorumMembers(Consensus::LLMQType llmqType, const CDeterministicMNList& mn_list, @@ -294,124 +287,44 @@ std::vector ComputeQuorumMembers(Consensus::LLMQType llmqT return CalculateQuorum(mn_list, modifier, llmq_params_opt->size, EvoOnly); } -std::vector> ComputeQuorumMembersByQuarterRotation( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, const CBlockIndex* pCycleQuorumBaseBlockIndex) +void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, + const CDeterministicMNList& mnUsedAtH, std::vector& sortedCombinedMns, + llmq::CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, + const CBlockIndex* pCycleQuorumBaseBlockIndex) { - const Consensus::LLMQType llmqType = llmqParams.type; - - const int cycleLength = llmqParams.dkgInterval; if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); - return {}; + return; } - const CBlockIndex* pBlockHMinusCIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - cycleLength); - const CBlockIndex* pBlockHMinus2CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 2 * cycleLength); - const CBlockIndex* pBlockHMinus3CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 3 * cycleLength); - const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); - CDeterministicMNList allMns = dmnman.GetListForBlock(pWorkBlockIndex); - LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqType), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount()); + quorumSnapshot.activeQuorumMembers.resize(allMns.GetAllMNsCount()); + const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); + auto sortedAllMns = CalculateQuorum(allMns, modifier); - PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, dmnman, qsnapman, - pBlockHMinusCIndex, pBlockHMinus2CIndex, - pBlockHMinus3CIndex, - pCycleQuorumBaseBlockIndex->nHeight); + LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pCycleQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); - size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); - std::vector> quorumMembers{nQuorums}; + std::fill(quorumSnapshot.activeQuorumMembers.begin(), + quorumSnapshot.activeQuorumMembers.end(), + false); + size_t index = {}; + for (const auto& dmn : sortedAllMns) { + if (mnUsedAtH.HasMN(dmn->proTxHash)) { + quorumSnapshot.activeQuorumMembers[index] = true; + } + index++; + } - auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, qsnapman, allMns, pCycleQuorumBaseBlockIndex, - previousQuarters); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!newQuarterMembers.empty()); - - if (LogAcceptDebug(BCLog::LLMQ)) { - for (const size_t i : irange::range(nQuorums)) { - std::stringstream ss; - - ss << " 3Cmns["; - for (const auto &m: previousQuarters.quarterHMinus3C[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ] 2Cmns["; - for (const auto &m: previousQuarters.quarterHMinus2C[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ] Cmns["; - for (const auto &m: previousQuarters.quarterHMinusC[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ] new["; - for (const auto &m: newQuarterMembers[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ]"; - LogPrint(BCLog::LLMQ, "QuarterComposition h[%d] i[%d]:%s\n", pCycleQuorumBaseBlockIndex->nHeight, i, - ss.str()); - } - } - - for (const size_t i : irange::range(nQuorums)) { - // Move elements from previous quarters into quorumMembers - std::move(previousQuarters.quarterHMinus3C[i].begin(), previousQuarters.quarterHMinus3C[i].end(), std::back_inserter(quorumMembers[i])); - std::move(previousQuarters.quarterHMinus2C[i].begin(), previousQuarters.quarterHMinus2C[i].end(), std::back_inserter(quorumMembers[i])); - std::move(previousQuarters.quarterHMinusC[i].begin(), previousQuarters.quarterHMinusC[i].end(), std::back_inserter(quorumMembers[i])); - std::move(newQuarterMembers[i].begin(), newQuarterMembers[i].end(), std::back_inserter(quorumMembers[i])); - - if (LogAcceptDebug(BCLog::LLMQ)) { - std::stringstream ss; - ss << " ["; - for (const auto &m: quorumMembers[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << "]"; - LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]:%s\n", pCycleQuorumBaseBlockIndex->nHeight, i, - ss.str()); - } - } - - return quorumMembers; -} - -PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, - CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const CBlockIndex* pBlockHMinusCIndex, - const CBlockIndex* pBlockHMinus2CIndex, - const CBlockIndex* pBlockHMinus3CIndex, int nHeight) -{ - size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); - PreviousQuorumQuarters quarters{nQuorums}; - - std::optional quSnapshotHMinusC = qsnapman.GetSnapshotForBlock(llmqParams.type, - pBlockHMinusCIndex); - if (quSnapshotHMinusC.has_value()) { - quarters.quarterHMinusC = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinusCIndex, quSnapshotHMinusC.value(), nHeight); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!quarterHMinusC.empty()); - - std::optional quSnapshotHMinus2C = qsnapman.GetSnapshotForBlock(llmqParams.type, - pBlockHMinus2CIndex); - if (quSnapshotHMinus2C.has_value()) { - quarters.quarterHMinus2C = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinus2CIndex, quSnapshotHMinus2C.value(), nHeight); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!quarterHMinusC.empty()); - - std::optional quSnapshotHMinus3C = qsnapman.GetSnapshotForBlock(llmqParams.type, - pBlockHMinus3CIndex); - if (quSnapshotHMinus3C.has_value()) { - quarters.quarterHMinus3C = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinus3CIndex, quSnapshotHMinus3C.value(), nHeight); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!quarterHMinusC.empty()); - } - } - } - - return quarters; -} + if (skipList.empty()) { + quorumSnapshot.mnSkipListMode = SnapshotSkipMode::MODE_NO_SKIPPING; + quorumSnapshot.mnSkipList.clear(); + } else { + quorumSnapshot.mnSkipListMode = SnapshotSkipMode::MODE_SKIPPING_ENTRIES; + quorumSnapshot.mnSkipList = std::move(skipList); + } +} std::vector> BuildNewQuorumQuarterMembers( - const Consensus::LLMQParams& llmqParams, CQuorumSnapshotManager& qsnapman, const CDeterministicMNList& allMns, + const Consensus::LLMQParams& llmqParams, llmq::CQuorumSnapshotManager& qsnapman, const CDeterministicMNList& allMns, const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters) { if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { @@ -555,7 +468,7 @@ std::vector> BuildNewQuorumQuarterMembers( } } - CQuorumSnapshot quorumSnapshot = {}; + llmq::CQuorumSnapshot quorumSnapshot = {}; BuildQuorumSnapshot(llmqParams, allMns, MnsUsedAtH, sortedCombinedMnsList, quorumSnapshot, pCycleQuorumBaseBlockIndex->nHeight, skipList, pCycleQuorumBaseBlockIndex); @@ -564,148 +477,207 @@ std::vector> BuildNewQuorumQuarterMembers( return quarterQuorumMembers; } -void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, - const CDeterministicMNList& mnUsedAtH, std::vector& sortedCombinedMns, - CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, - const CBlockIndex* pCycleQuorumBaseBlockIndex) +PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, + CDeterministicMNManager& dmnman, llmq::CQuorumSnapshotManager& qsnapman, + const CBlockIndex* pBlockHMinusCIndex, + const CBlockIndex* pBlockHMinus2CIndex, + const CBlockIndex* pBlockHMinus3CIndex, int nHeight) { - if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { - ASSERT_IF_DEBUG(false); - return; - } + size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); + PreviousQuorumQuarters quarters{nQuorums}; - quorumSnapshot.activeQuorumMembers.resize(allMns.GetAllMNsCount()); - const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); - auto sortedAllMns = CalculateQuorum(allMns, modifier); + std::optional quSnapshotHMinusC = qsnapman.GetSnapshotForBlock(llmqParams.type, + pBlockHMinusCIndex); + if (quSnapshotHMinusC.has_value()) { + quarters.quarterHMinusC = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinusCIndex, quSnapshotHMinusC.value(), nHeight); + //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice + //assert (!quarterHMinusC.empty()); - LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pCycleQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); + std::optional quSnapshotHMinus2C = qsnapman.GetSnapshotForBlock(llmqParams.type, + pBlockHMinus2CIndex); + if (quSnapshotHMinus2C.has_value()) { + quarters.quarterHMinus2C = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinus2CIndex, quSnapshotHMinus2C.value(), nHeight); + //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice + //assert (!quarterHMinusC.empty()); - std::fill(quorumSnapshot.activeQuorumMembers.begin(), - quorumSnapshot.activeQuorumMembers.end(), - false); - size_t index = {}; - for (const auto& dmn : sortedAllMns) { - if (mnUsedAtH.HasMN(dmn->proTxHash)) { - quorumSnapshot.activeQuorumMembers[index] = true; + std::optional quSnapshotHMinus3C = qsnapman.GetSnapshotForBlock(llmqParams.type, + pBlockHMinus3CIndex); + if (quSnapshotHMinus3C.has_value()) { + quarters.quarterHMinus3C = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinus3CIndex, quSnapshotHMinus3C.value(), nHeight); + //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice + //assert (!quarterHMinusC.empty()); + } } - index++; } - if (skipList.empty()) { - quorumSnapshot.mnSkipListMode = SnapshotSkipMode::MODE_NO_SKIPPING; - quorumSnapshot.mnSkipList.clear(); - } else { - quorumSnapshot.mnSkipListMode = SnapshotSkipMode::MODE_SKIPPING_ENTRIES; - quorumSnapshot.mnSkipList = std::move(skipList); - } + return quarters; } -std::vector> GetQuorumQuarterMembersBySnapshot( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, - const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight) +std::vector> ComputeQuorumMembersByQuarterRotation( + const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, llmq::CQuorumSnapshotManager& qsnapman, + const ChainstateManager& chainman, const CBlockIndex* pCycleQuorumBaseBlockIndex) { + const Consensus::LLMQType llmqType = llmqParams.type; + + const int cycleLength = llmqParams.dkgInterval; if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); return {}; } - std::vector sortedCombinedMns; - { - const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor( - pCycleQuorumBaseBlockIndex->nHeight - 8); - auto mn_list = dmnman.GetListForBlock(pWorkBlockIndex); - const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); - auto sortedAllMns = CalculateQuorum(mn_list, modifier); + const CBlockIndex* pBlockHMinusCIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - cycleLength); + const CBlockIndex* pBlockHMinus2CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 2 * cycleLength); + const CBlockIndex* pBlockHMinus3CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 3 * cycleLength); + const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); + CDeterministicMNList allMns = dmnman.GetListForBlock(pWorkBlockIndex); + LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqType), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount()); - std::vector usedMNs; - size_t i{0}; - for (const auto& dmn : sortedAllMns) { - if (snapshot.activeQuorumMembers[i]) { - usedMNs.push_back(dmn); - } else { - if (!dmn->pdmnState->IsBanned()) { - // the list begins with all the unused MNs - sortedCombinedMns.push_back(dmn); - } + PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, dmnman, qsnapman, + pBlockHMinusCIndex, pBlockHMinus2CIndex, + pBlockHMinus3CIndex, + pCycleQuorumBaseBlockIndex->nHeight); + + size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); + std::vector> quorumMembers{nQuorums}; + + auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, qsnapman, allMns, pCycleQuorumBaseBlockIndex, + previousQuarters); + //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice + //assert (!newQuarterMembers.empty()); + + if (LogAcceptDebug(BCLog::LLMQ)) { + for (const size_t i : irange::range(nQuorums)) { + std::stringstream ss; + + ss << " 3Cmns["; + for (const auto &m: previousQuarters.quarterHMinus3C[i]) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; } - i++; + ss << " ] 2Cmns["; + for (const auto &m: previousQuarters.quarterHMinus2C[i]) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; + } + ss << " ] Cmns["; + for (const auto &m: previousQuarters.quarterHMinusC[i]) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; + } + ss << " ] new["; + for (const auto &m: newQuarterMembers[i]) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; + } + ss << " ]"; + LogPrint(BCLog::LLMQ, "QuarterComposition h[%d] i[%d]:%s\n", pCycleQuorumBaseBlockIndex->nHeight, i, + ss.str()); } + } - // Now add the already used MNs to the end of the list - std::move(usedMNs.begin(), usedMNs.end(), std::back_inserter(sortedCombinedMns)); + for (const size_t i : irange::range(nQuorums)) { + // Move elements from previous quarters into quorumMembers + std::move(previousQuarters.quarterHMinus3C[i].begin(), previousQuarters.quarterHMinus3C[i].end(), std::back_inserter(quorumMembers[i])); + std::move(previousQuarters.quarterHMinus2C[i].begin(), previousQuarters.quarterHMinus2C[i].end(), std::back_inserter(quorumMembers[i])); + std::move(previousQuarters.quarterHMinusC[i].begin(), previousQuarters.quarterHMinusC[i].end(), std::back_inserter(quorumMembers[i])); + std::move(newQuarterMembers[i].begin(), newQuarterMembers[i].end(), std::back_inserter(quorumMembers[i])); + + if (LogAcceptDebug(BCLog::LLMQ)) { + std::stringstream ss; + ss << " ["; + for (const auto &m: quorumMembers[i]) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; + } + ss << "]"; + LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]:%s\n", pCycleQuorumBaseBlockIndex->nHeight, i, + ss.str()); + } } - if (LogAcceptDebug(BCLog::LLMQ)) { - std::stringstream ss; - ss << " ["; - for (const auto &m: sortedCombinedMns) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; + return quorumMembers; +} +} // anonymous namespace + +namespace llmq { +namespace utils { +std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, + CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, + gsl::not_null pQuorumBaseBlockIndex, + bool reset_cache) +{ + static RecursiveMutex cs_members; + static std::map>> mapQuorumMembers GUARDED_BY( + cs_members); + static RecursiveMutex cs_indexed_members; + static std::map, std::vector, StaticSaltedHasher>> mapIndexedQuorumMembers GUARDED_BY(cs_indexed_members); + if (!chainman.IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) { + return {}; + } + std::vector quorumMembers; + { + LOCK(cs_members); + if (mapQuorumMembers.empty()) { + InitQuorumsCache(mapQuorumMembers); + } + if (reset_cache) { + mapQuorumMembers[llmqType].clear(); + } else if (mapQuorumMembers[llmqType].get(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers)) { + return quorumMembers; } - ss << "]"; - LogPrint(BCLog::LLMQ, "GetQuorumQuarterMembersBySnapshot h[%d] from[%d] sortedCombinedMns[%s]\n", - pCycleQuorumBaseBlockIndex->nHeight, nHeight, ss.str()); } - size_t numQuorums = static_cast(llmqParams.signingActiveQuorumCount); - size_t quorumSize = static_cast(llmqParams.size); - auto quarterSize{quorumSize / 4}; + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt.has_value()); + const auto& llmq_params = llmq_params_opt.value(); - std::vector> quarterQuorumMembers(numQuorums); + if (IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex)) { + if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) { + InitQuorumsCache(mapIndexedQuorumMembers); + } + /* + * Quorums created with rotation are now created in a different way. All signingActiveQuorumCount are created during the period of dkgInterval. + * But they are not created exactly in the same block, they are spread overtime: one quorum in each block until all signingActiveQuorumCount are created. + * The new concept of quorumIndex is introduced in order to identify them. + * In every dkgInterval blocks (also called CycleQuorumBaseBlock), the spread quorum creation starts like this: + * For quorumIndex = 0 : signingActiveQuorumCount + * Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex + */ - if (sortedCombinedMns.empty()) { - return quarterQuorumMembers; - } + int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval; + if (quorumIndex >= llmq_params.signingActiveQuorumCount) { + return {}; + } + int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex; + const CBlockIndex* pCycleQuorumBaseBlockIndex = pQuorumBaseBlockIndex->GetAncestor(cycleQuorumBaseHeight); - switch (snapshot.mnSkipListMode) { - case SnapshotSkipMode::MODE_NO_SKIPPING: - { - auto itm = sortedCombinedMns.begin(); - for (const size_t i : irange::range(numQuorums)) { - while (quarterQuorumMembers[i].size() < quarterSize) { - quarterQuorumMembers[i].push_back(*itm); - itm++; - if (itm == sortedCombinedMns.end()) { - itm = sortedCombinedMns.begin(); - } - } - } - return quarterQuorumMembers; + /* + * Since mapQuorumMembers stores Quorum members per block hash, and we don't know yet the block hashes of blocks for all quorumIndexes (since these blocks are not created yet) + * We store them in a second cache mapIndexedQuorumMembers which stores them by {CycleQuorumBaseBlockHash, quorumIndex} + */ + if (reset_cache) { + LOCK(cs_indexed_members); + mapIndexedQuorumMembers[llmqType].clear(); + } else if (LOCK(cs_indexed_members); mapIndexedQuorumMembers[llmqType].get(std::pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), quorumIndex), quorumMembers)) { + LOCK(cs_members); + mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers); + return quorumMembers; } - case SnapshotSkipMode::MODE_SKIPPING_ENTRIES: // List holds entries to be skipped - { - size_t first_entry_index{0}; - std::vector processesdSkipList; - for (const auto& s : snapshot.mnSkipList) { - if (first_entry_index == 0) { - first_entry_index = s; - processesdSkipList.push_back(s); - } else { - processesdSkipList.push_back(first_entry_index + s); - } - } - int idx = 0; - auto itsk = processesdSkipList.begin(); - for (const size_t i : irange::range(numQuorums)) { - while (quarterQuorumMembers[i].size() < quarterSize) { - if (itsk != processesdSkipList.end() && idx == *itsk) { - itsk++; - } else { - quarterQuorumMembers[i].push_back(sortedCombinedMns[idx]); - } - idx++; - if (idx == static_cast(sortedCombinedMns.size())) { - idx = 0; - } - } - } - return quarterQuorumMembers; + auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, dmnman, qsnapman, chainman, pCycleQuorumBaseBlockIndex); + quorumMembers = q[quorumIndex]; + + LOCK(cs_indexed_members); + for (const size_t i : irange::range(q.size())) { + mapIndexedQuorumMembers[llmqType].emplace(std::make_pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), i), + std::move(q[i])); } - case SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES: // List holds entries to be kept - case SnapshotSkipMode::MODE_ALL_SKIPPED: // Every node was skipped. Returning empty quarterQuorumMembers - default: - return quarterQuorumMembers; + } else { + const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) + ? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) + : pQuorumBaseBlockIndex.get(); + CDeterministicMNList mn_list = dmnman.GetListForBlock(pWorkBlockIndex); + quorumMembers = ComputeQuorumMembers(llmqType, mn_list, pQuorumBaseBlockIndex); } + + LOCK(cs_members); + mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers); + return quorumMembers; } uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2) From afb442838c2b9be2fbed7c294d68ba9a34ba3025 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 21 Dec 2025 17:22:38 +0530 Subject: [PATCH 02/15] move-only: move `InitQuorumsCache()` to header, drop specializations --- src/llmq/utils.cpp | 25 ------------------------- src/llmq/utils.h | 14 +++++++++++--- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index f1b930a1b6b3..6cf70b58a44e 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -926,30 +926,5 @@ bool BlsCheck::operator()() } return true; } - -template -void InitQuorumsCache(CacheType& cache, bool limit_by_connections) -{ - for (const auto& llmq : Params().GetConsensus().llmqs) { - cache.emplace(std::piecewise_construct, std::forward_as_tuple(llmq.type), - std::forward_as_tuple(limit_by_connections ? llmq.keepOldConnections : llmq.keepOldKeys)); - } -} -template void InitQuorumsCache>>( - std::map>& cache, bool limit_by_connections); -template void InitQuorumsCache>>>( - std::map>>& cache, bool limit_by_connections); -template void InitQuorumsCache< - std::map>, std::less, - std::allocator>>>>>( - std::map>, std::less, - std::allocator>>>>& cache, - bool limit_by_connections); -template void InitQuorumsCache>>( - std::map>& cache, bool limit_by_connections); -template void InitQuorumsCache>>( - std::map>& cache, bool limit_by_connections); -template void InitQuorumsCache>>>( - std::map>>& cache, bool limit_by_connections); } // namespace utils } // namespace llmq diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 75d773ca9066..1f375e4a13a5 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -8,8 +8,9 @@ #include #include #include - #include + +#include #include #include @@ -28,10 +29,11 @@ class CDeterministicMNManager; class ChainstateManager; class CMasternodeMetaMan; class CSporkManager; - namespace llmq { class CQuorumSnapshotManager; +} // namespace llmq +namespace llmq { namespace utils { // includes members which failed DKG std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, @@ -95,7 +97,13 @@ struct BlsCheck { }; template -void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true); +inline void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true) +{ + for (const auto& llmq : Params().GetConsensus().llmqs) { + cache.emplace(std::piecewise_construct, std::forward_as_tuple(llmq.type), + std::forward_as_tuple(limit_by_connections ? llmq.keepOldConnections : llmq.keepOldKeys)); + } +} } // namespace utils } // namespace llmq From a3a6a7da432e0ec2afc72c623fb81623deeb9ff9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 21 Dec 2025 17:30:20 +0530 Subject: [PATCH 03/15] refactor: move `llmq::utils::BlsCheck` {c,d}tors and functions to source --- src/llmq/utils.cpp | 61 +++++++++++++++++++++++++++++++--------------- src/llmq/utils.h | 44 ++++++++++++--------------------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 6cf70b58a44e..ea62c7d410f0 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -22,6 +22,7 @@ #include #include +#include #include /** @@ -596,6 +597,46 @@ std::vector> ComputeQuorumMembersByQuarterRota namespace llmq { namespace utils { +BlsCheck::BlsCheck() = default; + +BlsCheck::BlsCheck(CBLSSignature sig, std::vector pubkeys, uint256 msg_hash, std::string id_string) : + m_sig(sig), + m_pubkeys(pubkeys), + m_msg_hash(msg_hash), + m_id_string(id_string) +{ +} + +BlsCheck::~BlsCheck() = default; + +bool BlsCheck::operator()() +{ + if (m_pubkeys.size() > 1) { + if (!m_sig.VerifySecureAggregated(m_pubkeys, m_msg_hash)) { + LogPrint(BCLog::LLMQ, "%s\n", m_id_string); + return false; + } + } else if (m_pubkeys.size() == 1) { + if (!m_sig.VerifyInsecure(m_pubkeys.back(), m_msg_hash)) { + LogPrint(BCLog::LLMQ, "%s\n", m_id_string); + return false; + } + } else { + // we should not get there ever + LogPrint(BCLog::LLMQ, "%s - no public keys are provided\n", m_id_string); + return false; + } + return true; +} + +void BlsCheck::swap(BlsCheck& obj) +{ + std::swap(m_sig, obj.m_sig); + std::swap(m_pubkeys, obj.m_pubkeys); + std::swap(m_msg_hash, obj.m_msg_hash); + std::swap(m_id_string, obj.m_id_string); +} + std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, gsl::not_null pQuorumBaseBlockIndex, @@ -906,25 +947,5 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman connman.AddPendingProbeConnections(probeConnections); } } - -bool BlsCheck::operator()() -{ - if (m_pubkeys.size() > 1) { - if (!m_sig.VerifySecureAggregated(m_pubkeys, m_msg_hash)) { - LogPrint(BCLog::LLMQ, "%s\n", m_id_string); - return false; - } - } else if (m_pubkeys.size() == 1) { - if (!m_sig.VerifyInsecure(m_pubkeys.back(), m_msg_hash)) { - LogPrint(BCLog::LLMQ, "%s\n", m_id_string); - return false; - } - } else { - // we should not get there ever - LogPrint(BCLog::LLMQ, "%s - no public keys are provided\n", m_id_string); - return false; - } - return true; -} } // namespace utils } // namespace llmq diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 1f375e4a13a5..48a16a08bafe 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -16,9 +16,7 @@ #include -#include #include -#include #include class CBlockIndex; @@ -35,6 +33,21 @@ class CQuorumSnapshotManager; namespace llmq { namespace utils { +struct BlsCheck { + CBLSSignature m_sig; + std::vector m_pubkeys; + uint256 m_msg_hash; + std::string m_id_string; + +public: + BlsCheck(); + BlsCheck(CBLSSignature sig, std::vector pubkeys, uint256 msg_hash, std::string id_string); + ~BlsCheck(); + + bool operator()(); + void swap(BlsCheck& obj); +}; + // includes members which failed DKG std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, @@ -69,33 +82,6 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman const CSporkManager& sporkman, const CDeterministicMNList& tip_mn_list, gsl::not_null pQuorumBaseBlockIndex, const uint256& myProTxHash); -struct BlsCheck { - CBLSSignature m_sig; - std::vector m_pubkeys; - uint256 m_msg_hash; - std::string m_id_string; - - BlsCheck() = default; - - BlsCheck(CBLSSignature sig, std::vector pubkeys, uint256 msg_hash, std::string id_string) : - m_sig(sig), - m_pubkeys(pubkeys), - m_msg_hash(msg_hash), - m_id_string(id_string) - { - } - - void swap(BlsCheck& obj) - { - std::swap(m_sig, obj.m_sig); - std::swap(m_pubkeys, obj.m_pubkeys); - std::swap(m_msg_hash, obj.m_msg_hash); - std::swap(m_id_string, obj.m_id_string); - } - - bool operator()(); -}; - template inline void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true) { From 17f5d88ba54def4565cc777f71b8aaa98f30d9ce Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 21 Dec 2025 03:11:43 +0530 Subject: [PATCH 04/15] refactor: make `SnapshotSkipMode` an `enum class` --- src/llmq/core_write.cpp | 2 +- src/llmq/snapshot.h | 8 +++--- src/test/llmq_snapshot_tests.cpp | 47 ++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp index 91375c7b644c..a13517bda095 100644 --- a/src/llmq/core_write.cpp +++ b/src/llmq/core_write.cpp @@ -242,7 +242,7 @@ UniValue CQuorumSnapshot::ToJson() const activeQ.push_back(h); } obj.pushKV("activeQuorumMembers", activeQ); - obj.pushKV("mnSkipListMode", mnSkipListMode); + obj.pushKV("mnSkipListMode", ToUnderlying(mnSkipListMode)); UniValue skipList(UniValue::VARR); for (const auto& h : mnSkipList) { // cppcheck-suppress useStlAlgorithm diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 1df138e296ab..66f7fa01e124 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -27,24 +27,24 @@ class CQuorumManager; class UniValue; -//TODO use enum class (probably) -enum SnapshotSkipMode : int { +enum class SnapshotSkipMode : int { MODE_NO_SKIPPING = 0, MODE_SKIPPING_ENTRIES = 1, MODE_NO_SKIPPING_ENTRIES = 2, MODE_ALL_SKIPPED = 3 }; +template<> struct is_serializable_enum : std::true_type {}; namespace llmq { class CQuorumSnapshot { public: std::vector activeQuorumMembers; - int mnSkipListMode = 0; + SnapshotSkipMode mnSkipListMode{SnapshotSkipMode::MODE_NO_SKIPPING}; std::vector mnSkipList; CQuorumSnapshot() = default; - CQuorumSnapshot(std::vector _activeQuorumMembers, int _mnSkipListMode, std::vector _mnSkipList) : + CQuorumSnapshot(std::vector _activeQuorumMembers, SnapshotSkipMode _mnSkipListMode, std::vector _mnSkipList) : activeQuorumMembers(std::move(_activeQuorumMembers)), mnSkipListMode(_mnSkipListMode), mnSkipList(std::move(_mnSkipList)) diff --git a/src/test/llmq_snapshot_tests.cpp b/src/test/llmq_snapshot_tests.cpp index 52b638625763..aa9d1dae2023 100644 --- a/src/test/llmq_snapshot_tests.cpp +++ b/src/test/llmq_snapshot_tests.cpp @@ -25,12 +25,12 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_construction_test) // Test default constructor CQuorumSnapshot snapshot1; BOOST_CHECK(snapshot1.activeQuorumMembers.empty()); - BOOST_CHECK_EQUAL(snapshot1.mnSkipListMode, 0); + BOOST_CHECK_EQUAL(snapshot1.mnSkipListMode, SnapshotSkipMode::MODE_NO_SKIPPING); BOOST_CHECK(snapshot1.mnSkipList.empty()); // Test parameterized constructor std::vector activeMembers = {true, false, true, true, false}; - int skipMode = MODE_SKIPPING_ENTRIES; + auto skipMode = SnapshotSkipMode::MODE_SKIPPING_ENTRIES; std::vector skipList = {1, 3, 5, 7}; CQuorumSnapshot snapshot2(activeMembers, skipMode, skipList); @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_serialization_test) { // Test with various configurations std::vector activeMembers = CreateBitVector(10, {0, 2, 4, 6, 8}); - int skipMode = MODE_SKIPPING_ENTRIES; + auto skipMode = SnapshotSkipMode::MODE_SKIPPING_ENTRIES; std::vector skipList = {10, 20, 30}; CQuorumSnapshot snapshot(activeMembers, skipMode, skipList); @@ -71,9 +71,14 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_serialization_test) BOOST_AUTO_TEST_CASE(quorum_snapshot_skip_modes_test) { // Test all skip modes - std::vector skipModes = {MODE_NO_SKIPPING, MODE_SKIPPING_ENTRIES, MODE_NO_SKIPPING_ENTRIES, MODE_ALL_SKIPPED}; - - for (int mode : skipModes) { + constexpr std::array skipModes{ + SnapshotSkipMode::MODE_NO_SKIPPING, + SnapshotSkipMode::MODE_SKIPPING_ENTRIES, + SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES, + SnapshotSkipMode::MODE_ALL_SKIPPED + }; + + for (auto mode : skipModes) { CQuorumSnapshot snapshot({true, false, true}, mode, {1, 2, 3}); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -101,7 +106,7 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_large_data_test) largeSkipList.push_back(i * 4); } - CQuorumSnapshot snapshot(largeActiveMembers, MODE_SKIPPING_ENTRIES, largeSkipList); + CQuorumSnapshot snapshot(largeActiveMembers, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, largeSkipList); // Test serialization with large data // Test serialization manually instead of using roundtrip helper @@ -116,17 +121,17 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_large_data_test) BOOST_AUTO_TEST_CASE(quorum_snapshot_empty_data_test) { // Test with empty data - CQuorumSnapshot emptySnapshot({}, MODE_NO_SKIPPING, {}); + CQuorumSnapshot emptySnapshot({}, SnapshotSkipMode::MODE_NO_SKIPPING, {}); // Test serialization roundtrip BOOST_CHECK(TestSerializationRoundtrip(emptySnapshot)); // Test with empty active members but non-empty skip list - CQuorumSnapshot snapshot1({}, MODE_SKIPPING_ENTRIES, {1, 2, 3}); + CQuorumSnapshot snapshot1({}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {1, 2, 3}); BOOST_CHECK(TestSerializationRoundtrip(snapshot1)); // Test with non-empty active members but empty skip list - CQuorumSnapshot snapshot2({true, false, true}, MODE_NO_SKIPPING, {}); + CQuorumSnapshot snapshot2({true, false, true}, SnapshotSkipMode::MODE_NO_SKIPPING, {}); BOOST_CHECK(TestSerializationRoundtrip(snapshot2)); } @@ -135,15 +140,15 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_bit_serialization_test) // Test bit vector serialization edge cases // Test single bit - CQuorumSnapshot snapshot1({true}, MODE_NO_SKIPPING, {}); + CQuorumSnapshot snapshot1({true}, SnapshotSkipMode::MODE_NO_SKIPPING, {}); BOOST_CHECK(TestSerializationRoundtrip(snapshot1)); // Test 8 bits (full byte) - CQuorumSnapshot snapshot8(std::vector(8, true), MODE_NO_SKIPPING, {}); + CQuorumSnapshot snapshot8(std::vector(8, true), SnapshotSkipMode::MODE_NO_SKIPPING, {}); BOOST_CHECK(TestSerializationRoundtrip(snapshot8)); // Test 9 bits (more than one byte) - CQuorumSnapshot snapshot9(std::vector(9, false), MODE_NO_SKIPPING, {}); + CQuorumSnapshot snapshot9(std::vector(9, false), SnapshotSkipMode::MODE_NO_SKIPPING, {}); snapshot9.activeQuorumMembers[8] = true; // Set last bit BOOST_CHECK(TestSerializationRoundtrip(snapshot9)); @@ -152,7 +157,7 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_bit_serialization_test) for (size_t i = 0; i < alternating.size(); i++) { alternating[i] = (i % 2 == 0); } - CQuorumSnapshot snapshotAlt(alternating, MODE_NO_SKIPPING, {}); + CQuorumSnapshot snapshotAlt(alternating, SnapshotSkipMode::MODE_NO_SKIPPING, {}); BOOST_CHECK(TestSerializationRoundtrip(snapshotAlt)); } @@ -201,9 +206,9 @@ BOOST_AUTO_TEST_CASE(quorum_rotation_info_serialization_test) CQuorumRotationInfo rotInfo; // Set up basic required fields - rotInfo.quorumSnapshotAtHMinusC = CQuorumSnapshot({true, false, true}, MODE_SKIPPING_ENTRIES, {1, 2}); - rotInfo.quorumSnapshotAtHMinus2C = CQuorumSnapshot({false, true, false}, MODE_NO_SKIPPING, {}); - rotInfo.quorumSnapshotAtHMinus3C = CQuorumSnapshot({true, true, false}, MODE_ALL_SKIPPED, {3}); + rotInfo.quorumSnapshotAtHMinusC = CQuorumSnapshot({true, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {1, 2}); + rotInfo.quorumSnapshotAtHMinus2C = CQuorumSnapshot({false, true, false}, SnapshotSkipMode::MODE_NO_SKIPPING, {}); + rotInfo.quorumSnapshotAtHMinus3C = CQuorumSnapshot({true, true, false}, SnapshotSkipMode::MODE_ALL_SKIPPED, {3}); // Test without extraShare rotInfo.extraShare = false; @@ -214,12 +219,12 @@ BOOST_AUTO_TEST_CASE(quorum_rotation_info_serialization_test) BOOST_CHECK(TestSerializationRoundtrip(rotInfo)); // Test with extraShare and initialized snapshot - rotInfo.quorumSnapshotAtHMinus4C = CQuorumSnapshot({false, false, true}, MODE_SKIPPING_ENTRIES, {4, 5, 6}); + rotInfo.quorumSnapshotAtHMinus4C = CQuorumSnapshot({false, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {4, 5, 6}); BOOST_CHECK(TestSerializationRoundtrip(rotInfo)); CFinalCommitment commitment{GetLLMQParams(Consensus::LLMQType::LLMQ_TEST), uint256::ONE}; rotInfo.lastCommitmentPerIndex.push_back(commitment); - rotInfo.quorumSnapshotList.push_back(CQuorumSnapshot({false, false, true}, MODE_SKIPPING_ENTRIES, {7, 8})); + rotInfo.quorumSnapshotList.push_back(CQuorumSnapshot({false, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {7, 8})); BOOST_CHECK(TestSerializationRoundtrip(rotInfo)); } @@ -227,7 +232,7 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_json_test) { // Create snapshot with test data std::vector activeMembers = {true, false, true, true, false, false, true}; - int skipMode = MODE_SKIPPING_ENTRIES; + auto skipMode = SnapshotSkipMode::MODE_SKIPPING_ENTRIES; std::vector skipList = {10, 20, 30, 40}; CQuorumSnapshot snapshot(activeMembers, skipMode, skipList); @@ -249,7 +254,7 @@ BOOST_AUTO_TEST_CASE(quorum_snapshot_json_test) BOOST_AUTO_TEST_CASE(quorum_snapshot_malformed_data_test) { // Create valid snapshot - CQuorumSnapshot snapshot({true, false, true}, MODE_SKIPPING_ENTRIES, {1, 2, 3}); + CQuorumSnapshot snapshot({true, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {1, 2, 3}); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << snapshot; From 3b6d997e6d760f554ee63941bb8faf1f83fb4ed1 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:52:53 +0530 Subject: [PATCH 05/15] refactor: extract quorum cycle data into struct, move ctors to source --- src/llmq/core_write.cpp | 16 ++++---- src/llmq/snapshot.cpp | 44 +++++++++++++++------ src/llmq/snapshot.h | 68 +++++++++++++++----------------- src/test/llmq_snapshot_tests.cpp | 13 +++--- 4 files changed, 79 insertions(+), 62 deletions(-) diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp index a13517bda095..4bb3e9364bbe 100644 --- a/src/llmq/core_write.cpp +++ b/src/llmq/core_write.cpp @@ -182,22 +182,22 @@ UniValue CQuorumRotationInfo::ToJson() const UniValue obj(UniValue::VOBJ); obj.pushKV("extraShare", extraShare); - obj.pushKV("quorumSnapshotAtHMinusC", quorumSnapshotAtHMinusC.ToJson()); - obj.pushKV("quorumSnapshotAtHMinus2C", quorumSnapshotAtHMinus2C.ToJson()); - obj.pushKV("quorumSnapshotAtHMinus3C", quorumSnapshotAtHMinus3C.ToJson()); + obj.pushKV("quorumSnapshotAtHMinusC", cycleHMinusC.m_snap.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus2C", cycleHMinus2C.m_snap.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus3C", cycleHMinus3C.m_snap.ToJson()); if (extraShare) { - obj.pushKV("quorumSnapshotAtHMinus4C", quorumSnapshotAtHMinus4C.ToJson()); + obj.pushKV("quorumSnapshotAtHMinus4C", CHECK_NONFATAL(cycleHMinus4C)->m_snap.ToJson()); } obj.pushKV("mnListDiffTip", mnListDiffTip.ToJson()); obj.pushKV("mnListDiffH", mnListDiffH.ToJson()); - obj.pushKV("mnListDiffAtHMinusC", mnListDiffAtHMinusC.ToJson()); - obj.pushKV("mnListDiffAtHMinus2C", mnListDiffAtHMinus2C.ToJson()); - obj.pushKV("mnListDiffAtHMinus3C", mnListDiffAtHMinus3C.ToJson()); + obj.pushKV("mnListDiffAtHMinusC", cycleHMinusC.m_diff.ToJson()); + obj.pushKV("mnListDiffAtHMinus2C", cycleHMinus2C.m_diff.ToJson()); + obj.pushKV("mnListDiffAtHMinus3C", cycleHMinus3C.m_diff.ToJson()); if (extraShare) { - obj.pushKV("mnListDiffAtHMinus4C", mnListDiffAtHMinus4C.ToJson()); + obj.pushKV("mnListDiffAtHMinus4C", CHECK_NONFATAL(cycleHMinus4C)->m_diff.ToJson()); } UniValue hqclists(UniValue::VARR); for (const auto& qc : lastCommitmentPerIndex) { diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index cf744f6c781a..23a1a8e4a630 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -146,7 +146,7 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinusCIndex, use_legacy_construction), - pWorkBlockHMinusCIndex->GetBlockHash(), response.mnListDiffAtHMinusC, errorRet)) { + pWorkBlockHMinusCIndex->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { return false; } } @@ -156,14 +156,14 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan errorRet = strprintf("Can not find quorum snapshot at H-C"); return false; } else { - response.quorumSnapshotAtHMinusC = std::move(snapshotHMinusC.value()); + response.cycleHMinusC.m_snap = std::move(snapshotHMinusC.value()); } if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus2CIndex, use_legacy_construction), - pWorkBlockHMinus2CIndex->GetBlockHash(), response.mnListDiffAtHMinus2C, errorRet)) { + pWorkBlockHMinus2CIndex->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { return false; } } @@ -173,14 +173,14 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan errorRet = strprintf("Can not find quorum snapshot at H-2C"); return false; } else { - response.quorumSnapshotAtHMinus2C = std::move(snapshotHMinus2C.value()); + response.cycleHMinus2C.m_snap = std::move(snapshotHMinus2C.value()); } if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus3CIndex, use_legacy_construction), - pWorkBlockHMinus3CIndex->GetBlockHash(), response.mnListDiffAtHMinus3C, errorRet)) { + pWorkBlockHMinus3CIndex->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { return false; } } @@ -190,7 +190,7 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan errorRet = strprintf("Can not find quorum snapshot at H-3C"); return false; } else { - response.quorumSnapshotAtHMinus3C = std::move(snapshotHMinus3C.value()); + response.cycleHMinus3C.m_snap = std::move(snapshotHMinus3C.value()); } if (request.extraShare) { @@ -201,24 +201,28 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan return false; } + CycleData extraCycle; auto snapshotHMinus4C = qsnapman.GetSnapshotForBlock(llmqType, pBlockHMinus4CIndex); if (!snapshotHMinus4C.has_value()) { errorRet = strprintf("Can not find quorum snapshot at H-4C"); return false; } else { - response.quorumSnapshotAtHMinus4C = std::move(snapshotHMinus4C.value()); + extraCycle.m_snap = std::move(snapshotHMinus4C.value()); } if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus4CIndex, use_legacy_construction), - pWorkBlockHMinus4CIndex->GetBlockHash(), response.mnListDiffAtHMinus4C, errorRet)) { - response.mnListDiffAtHMinus4C = {}; + pWorkBlockHMinus4CIndex->GetBlockHash(), extraCycle.m_diff, errorRet)) { + extraCycle.m_diff = {}; return false; } + if (!use_legacy_construction) { baseBlockIndexes.push_back(pWorkBlockHMinus4CIndex); } + + response.cycleHMinus4C = extraCycle; } else { response.extraShare = false; } @@ -283,7 +287,7 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus3CIndex, use_legacy_construction), - pWorkBlockHMinus3CIndex->GetBlockHash(), response.mnListDiffAtHMinus3C, errorRet)) { + pWorkBlockHMinus3CIndex->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { return false; } baseBlockIndexes.push_back(pWorkBlockHMinus3CIndex); @@ -291,14 +295,14 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus2CIndex, use_legacy_construction), - pWorkBlockHMinus2CIndex->GetBlockHash(), response.mnListDiffAtHMinus2C, errorRet)) { + pWorkBlockHMinus2CIndex->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { return false; } baseBlockIndexes.push_back(pWorkBlockHMinus2CIndex); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinusCIndex, use_legacy_construction), - pWorkBlockHMinusCIndex->GetBlockHash(), response.mnListDiffAtHMinusC, errorRet)) { + pWorkBlockHMinusCIndex->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { return false; } baseBlockIndexes.push_back(pWorkBlockHMinusCIndex); @@ -335,6 +339,22 @@ uint256 GetLastBaseBlockHash(Span baseBlockIndexes, const CB return hash; } +CQuorumSnapshot::CQuorumSnapshot() = default; + +CQuorumSnapshot::CQuorumSnapshot(std::vector active_quorum_members, SnapshotSkipMode skip_mode, + std::vector skip_list) : + activeQuorumMembers(std::move(active_quorum_members)), + mnSkipListMode(skip_mode), + mnSkipList(std::move(skip_list)) +{ +} + +CQuorumSnapshot::~CQuorumSnapshot() = default; + +CQuorumRotationInfo::CQuorumRotationInfo() = default; + +CQuorumRotationInfo::~CQuorumRotationInfo() = default; + CQuorumSnapshotManager::CQuorumSnapshotManager(CEvoDB& evoDb) : m_evoDb{evoDb}, quorumSnapshotCache{32} diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 66f7fa01e124..1e70c1b74955 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -43,13 +43,10 @@ class CQuorumSnapshot SnapshotSkipMode mnSkipListMode{SnapshotSkipMode::MODE_NO_SKIPPING}; std::vector mnSkipList; - CQuorumSnapshot() = default; - CQuorumSnapshot(std::vector _activeQuorumMembers, SnapshotSkipMode _mnSkipListMode, std::vector _mnSkipList) : - activeQuorumMembers(std::move(_activeQuorumMembers)), - mnSkipListMode(_mnSkipListMode), - mnSkipList(std::move(_mnSkipList)) - { - } +public: + CQuorumSnapshot(); + CQuorumSnapshot(std::vector active_quorum_members, SnapshotSkipMode skip_mode, std::vector skip_list); + ~CQuorumSnapshot(); template inline void SerializationOpBase(Stream& s, Operation ser_action) @@ -102,42 +99,41 @@ class CGetQuorumRotationInfo } }; -//TODO Maybe we should split the following class: -// CQuorumSnaphot should include {creationHeight, activeQuorumMembers H_C H_2C H_3C, and skipLists H_C H_2C H3_C} -// Maybe we need to include also blockHash for heights H_C H_2C H_3C -// CSnapshotInfo should include CQuorumSnaphot + mnListDiff Tip H H_C H_2C H3_C +struct CycleData { + CQuorumSnapshot m_snap; + CSimplifiedMNListDiff m_diff; +}; + class CQuorumRotationInfo { public: - CQuorumSnapshot quorumSnapshotAtHMinusC; - CQuorumSnapshot quorumSnapshotAtHMinus2C; - CQuorumSnapshot quorumSnapshotAtHMinus3C; - + bool extraShare{false}; + CycleData cycleHMinusC; + CycleData cycleHMinus2C; + CycleData cycleHMinus3C; + std::optional cycleHMinus4C; CSimplifiedMNListDiff mnListDiffTip; CSimplifiedMNListDiff mnListDiffH; - CSimplifiedMNListDiff mnListDiffAtHMinusC; - CSimplifiedMNListDiff mnListDiffAtHMinus2C; - CSimplifiedMNListDiff mnListDiffAtHMinus3C; - - bool extraShare{false}; - CQuorumSnapshot quorumSnapshotAtHMinus4C; - CSimplifiedMNListDiff mnListDiffAtHMinus4C; - std::vector lastCommitmentPerIndex; std::vector quorumSnapshotList; std::vector mnListDiffList; +public: + CQuorumRotationInfo(); + CQuorumRotationInfo(const CQuorumRotationInfo& dmn) = delete; + ~CQuorumRotationInfo(); + template inline void SerializationOpBase(Stream& s, Operation ser_action) { - READWRITE(quorumSnapshotAtHMinusC, - quorumSnapshotAtHMinus2C, - quorumSnapshotAtHMinus3C, + READWRITE(cycleHMinusC.m_snap, + cycleHMinus2C.m_snap, + cycleHMinus3C.m_snap, mnListDiffTip, mnListDiffH, - mnListDiffAtHMinusC, - mnListDiffAtHMinus2C, - mnListDiffAtHMinus3C, + cycleHMinusC.m_diff, + cycleHMinus2C.m_diff, + cycleHMinus3C.m_diff, extraShare); } @@ -147,8 +143,9 @@ class CQuorumRotationInfo const_cast(this)->SerializationOpBase(s, CSerActionSerialize()); if (extraShare) { - ::Serialize(s, quorumSnapshotAtHMinus4C); - ::Serialize(s, mnListDiffAtHMinus4C); + // Needed to maintain compatibility with existing on-disk format + ::Serialize(s, cycleHMinus4C.value_or(CycleData{}).m_snap); + ::Serialize(s, cycleHMinus4C.value_or(CycleData{}).m_diff); } WriteCompactSize(s, lastCommitmentPerIndex.size()); @@ -173,8 +170,10 @@ class CQuorumRotationInfo SerializationOpBase(s, CSerActionUnserialize()); if (extraShare) { - ::Unserialize(s, quorumSnapshotAtHMinus4C); - ::Unserialize(s, mnListDiffAtHMinus4C); + CycleData val{}; + ::Unserialize(s, val.m_snap); + ::Unserialize(s, val.m_diff); + cycleHMinus4C = val; } size_t cnt = ReadCompactSize(s); @@ -199,9 +198,6 @@ class CQuorumRotationInfo } } - CQuorumRotationInfo() = default; - CQuorumRotationInfo(const CQuorumRotationInfo& dmn) {} - [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/test/llmq_snapshot_tests.cpp b/src/test/llmq_snapshot_tests.cpp index aa9d1dae2023..6e5b61aa838c 100644 --- a/src/test/llmq_snapshot_tests.cpp +++ b/src/test/llmq_snapshot_tests.cpp @@ -167,8 +167,7 @@ BOOST_AUTO_TEST_CASE(quorum_rotation_info_construction_test) // Test default state BOOST_CHECK(!rotInfo.extraShare); - BOOST_CHECK_EQUAL(::SerializeHash(rotInfo.quorumSnapshotAtHMinus4C), ::SerializeHash(CQuorumSnapshot())); - BOOST_CHECK_EQUAL(::SerializeHash(rotInfo.mnListDiffAtHMinus4C), ::SerializeHash(CSimplifiedMNListDiff())); + BOOST_CHECK(!rotInfo.cycleHMinus4C.has_value()); BOOST_CHECK(rotInfo.lastCommitmentPerIndex.empty()); BOOST_CHECK(rotInfo.quorumSnapshotList.empty()); BOOST_CHECK(rotInfo.mnListDiffList.empty()); @@ -206,9 +205,9 @@ BOOST_AUTO_TEST_CASE(quorum_rotation_info_serialization_test) CQuorumRotationInfo rotInfo; // Set up basic required fields - rotInfo.quorumSnapshotAtHMinusC = CQuorumSnapshot({true, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {1, 2}); - rotInfo.quorumSnapshotAtHMinus2C = CQuorumSnapshot({false, true, false}, SnapshotSkipMode::MODE_NO_SKIPPING, {}); - rotInfo.quorumSnapshotAtHMinus3C = CQuorumSnapshot({true, true, false}, SnapshotSkipMode::MODE_ALL_SKIPPED, {3}); + rotInfo.cycleHMinusC.m_snap = CQuorumSnapshot({true, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {1, 2}); + rotInfo.cycleHMinus2C.m_snap = CQuorumSnapshot({false, true, false}, SnapshotSkipMode::MODE_NO_SKIPPING, {}); + rotInfo.cycleHMinus3C.m_snap = CQuorumSnapshot({true, true, false}, SnapshotSkipMode::MODE_ALL_SKIPPED, {3}); // Test without extraShare rotInfo.extraShare = false; @@ -219,7 +218,9 @@ BOOST_AUTO_TEST_CASE(quorum_rotation_info_serialization_test) BOOST_CHECK(TestSerializationRoundtrip(rotInfo)); // Test with extraShare and initialized snapshot - rotInfo.quorumSnapshotAtHMinus4C = CQuorumSnapshot({false, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {4, 5, 6}); + llmq::CycleData extra_cycle; + extra_cycle.m_snap = CQuorumSnapshot({false, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {4, 5, 6}); + rotInfo.cycleHMinus4C = extra_cycle; BOOST_CHECK(TestSerializationRoundtrip(rotInfo)); CFinalCommitment commitment{GetLLMQParams(Consensus::LLMQType::LLMQ_TEST), uint256::ONE}; From 1eb13309381b749e43c0d967f8e44d3c6bba4e5c Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 24 Dec 2025 00:45:50 +0530 Subject: [PATCH 06/15] refactor: introduce `QuorumQuarter` struct to reduce code duplication --- src/llmq/utils.cpp | 188 ++++++++++++++++----------------------------- 1 file changed, 67 insertions(+), 121 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index ea62c7d410f0..1d897ed1ffdf 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -31,13 +31,27 @@ std::optional> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex); namespace { +struct QuorumQuarter { + llmq::CQuorumSnapshot m_snap; + std::vector> m_members; + //! memory only + const CBlockIndex* m_cycle_index{nullptr}; + +public: + explicit QuorumQuarter(size_t size) : m_members(size) {} +}; + // QuorumMembers per quorumIndex at heights H-Cycle, H-2Cycles, H-3Cycles struct PreviousQuorumQuarters { - std::vector> quarterHMinusC; - std::vector> quarterHMinus2C; - std::vector> quarterHMinus3C; - explicit PreviousQuorumQuarters(size_t s) : - quarterHMinusC(s), quarterHMinus2C(s), quarterHMinus3C(s) {} + QuorumQuarter quarterHMinusC; + QuorumQuarter quarterHMinus2C; + QuorumQuarter quarterHMinus3C; + +public: + explicit PreviousQuorumQuarters(size_t s) : quarterHMinusC(s), quarterHMinus2C(s), quarterHMinus3C(s) {} + + std::vector GetCycles() { return {&quarterHMinusC, &quarterHMinus2C, &quarterHMinus3C}; } + std::vector GetCycles() const { return {&quarterHMinusC, &quarterHMinus2C, &quarterHMinus3C}; } }; bool IsV19Active(gsl::not_null pindexPrev) @@ -350,53 +364,23 @@ std::vector> BuildNewQuorumQuarterMembers( bool skipRemovedMNs = IsV19Active(pCycleQuorumBaseBlockIndex) || (Params().NetworkIDString() == CBaseChainParams::TESTNET); - for (const size_t i : irange::range(nQuorums)) { - for (const auto& mn : previousQuarters.quarterHMinusC[i]) { - if (skipRemovedMNs && !allMns.HasMN(mn->proTxHash)) { - continue; - } - if (allMns.IsMNPoSeBanned(mn->proTxHash)) { - continue; - } - try { - MnsUsedAtH.AddMN(mn); - } catch (const std::runtime_error& e) { - } - try { - MnsUsedAtHIndexed[i].AddMN(mn); - } catch (const std::runtime_error& e) { - } - } - for (const auto& mn : previousQuarters.quarterHMinus2C[i]) { - if (skipRemovedMNs && !allMns.HasMN(mn->proTxHash)) { - continue; - } - if (allMns.IsMNPoSeBanned(mn->proTxHash)) { - continue; - } - try { - MnsUsedAtH.AddMN(mn); - } catch (const std::runtime_error& e) { - } - try { - MnsUsedAtHIndexed[i].AddMN(mn); - } catch (const std::runtime_error& e) { - } - } - for (const auto& mn : previousQuarters.quarterHMinus3C[i]) { - if (skipRemovedMNs && !allMns.HasMN(mn->proTxHash)) { - continue; - } - if (allMns.IsMNPoSeBanned(mn->proTxHash)) { - continue; - } - try { - MnsUsedAtH.AddMN(mn); - } catch (const std::runtime_error& e) { - } - try { - MnsUsedAtHIndexed[i].AddMN(mn); - } catch (const std::runtime_error& e) { + for (const size_t idx : irange::range(nQuorums)) { + for (auto* prev_cycle : previousQuarters.GetCycles()) { + for (const auto& mn : prev_cycle->m_members[idx]) { + if (skipRemovedMNs && !allMns.HasMN(mn->proTxHash)) { + continue; + } + if (allMns.IsMNPoSeBanned(mn->proTxHash)) { + continue; + } + try { + MnsUsedAtH.AddMN(mn); + } catch (const std::runtime_error& e) { + } + try { + MnsUsedAtHIndexed[idx].AddMN(mn); + } catch (const std::runtime_error& e) { + } } } } @@ -478,91 +462,52 @@ std::vector> BuildNewQuorumQuarterMembers( return quarterQuorumMembers; } -PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, - CDeterministicMNManager& dmnman, llmq::CQuorumSnapshotManager& qsnapman, - const CBlockIndex* pBlockHMinusCIndex, - const CBlockIndex* pBlockHMinus2CIndex, - const CBlockIndex* pBlockHMinus3CIndex, int nHeight) -{ - size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); - PreviousQuorumQuarters quarters{nQuorums}; - - std::optional quSnapshotHMinusC = qsnapman.GetSnapshotForBlock(llmqParams.type, - pBlockHMinusCIndex); - if (quSnapshotHMinusC.has_value()) { - quarters.quarterHMinusC = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinusCIndex, quSnapshotHMinusC.value(), nHeight); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!quarterHMinusC.empty()); - - std::optional quSnapshotHMinus2C = qsnapman.GetSnapshotForBlock(llmqParams.type, - pBlockHMinus2CIndex); - if (quSnapshotHMinus2C.has_value()) { - quarters.quarterHMinus2C = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinus2CIndex, quSnapshotHMinus2C.value(), nHeight); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!quarterHMinusC.empty()); - - std::optional quSnapshotHMinus3C = qsnapman.GetSnapshotForBlock(llmqParams.type, - pBlockHMinus3CIndex); - if (quSnapshotHMinus3C.has_value()) { - quarters.quarterHMinus3C = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, pBlockHMinus3CIndex, quSnapshotHMinus3C.value(), nHeight); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!quarterHMinusC.empty()); - } - } - } - - return quarters; -} - std::vector> ComputeQuorumMembersByQuarterRotation( const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const CBlockIndex* pCycleQuorumBaseBlockIndex) { - const Consensus::LLMQType llmqType = llmqParams.type; - const int cycleLength = llmqParams.dkgInterval; if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); return {}; } + const auto nQuorums{static_cast(llmqParams.signingActiveQuorumCount)}; - const CBlockIndex* pBlockHMinusCIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - cycleLength); - const CBlockIndex* pBlockHMinus2CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 2 * cycleLength); - const CBlockIndex* pBlockHMinus3CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 3 * cycleLength); const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); CDeterministicMNList allMns = dmnman.GetListForBlock(pWorkBlockIndex); - LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqType), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount()); - - PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, dmnman, qsnapman, - pBlockHMinusCIndex, pBlockHMinus2CIndex, - pBlockHMinus3CIndex, - pCycleQuorumBaseBlockIndex->nHeight); + LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqParams.type), + pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount()); - size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); - std::vector> quorumMembers{nQuorums}; + PreviousQuorumQuarters previousQuarters(nQuorums); + auto prev_cycles{previousQuarters.GetCycles()}; + for (size_t idx{0}; idx < prev_cycles.size(); idx++) { + prev_cycles[idx]->m_cycle_index = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - (cycleLength * (idx + 1))); + if (auto opt_snap = qsnapman.GetSnapshotForBlock(llmqParams.type, prev_cycles[idx]->m_cycle_index); opt_snap.has_value()) { + prev_cycles[idx]->m_snap = opt_snap.value(); + } else { + // TODO: Check if it is triggered from outside (P2P, block validation) and maybe throw an exception + // assert(false); + break; + } + prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, prev_cycles[idx]->m_cycle_index, + prev_cycles[idx]->m_snap, pCycleQuorumBaseBlockIndex->nHeight); + } - auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, qsnapman, allMns, pCycleQuorumBaseBlockIndex, - previousQuarters); - //TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice - //assert (!newQuarterMembers.empty()); + auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, qsnapman, allMns, pCycleQuorumBaseBlockIndex, previousQuarters); + // TODO: Check if it is triggered from outside (P2P, block validation) and maybe throw an exception + // assert (!newQuarterMembers.empty()); if (LogAcceptDebug(BCLog::LLMQ)) { for (const size_t i : irange::range(nQuorums)) { std::stringstream ss; - - ss << " 3Cmns["; - for (const auto &m: previousQuarters.quarterHMinus3C[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ] 2Cmns["; - for (const auto &m: previousQuarters.quarterHMinus2C[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ] Cmns["; - for (const auto &m: previousQuarters.quarterHMinusC[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; + for (size_t idx = prev_cycles.size(); idx-- > 0;) { + ss << strprintf(" %dCmns[", idx); + for (const auto &m: prev_cycles[idx]->m_members[i]) { + ss << m->proTxHash.ToString().substr(0, 4) << "|"; + } + ss << " ]"; } - ss << " ] new["; + ss << " new["; for (const auto &m: newQuarterMembers[i]) { ss << m->proTxHash.ToString().substr(0, 4) << "|"; } @@ -572,11 +517,12 @@ std::vector> ComputeQuorumMembersByQuarterRota } } + std::vector> quorumMembers(nQuorums); for (const size_t i : irange::range(nQuorums)) { // Move elements from previous quarters into quorumMembers - std::move(previousQuarters.quarterHMinus3C[i].begin(), previousQuarters.quarterHMinus3C[i].end(), std::back_inserter(quorumMembers[i])); - std::move(previousQuarters.quarterHMinus2C[i].begin(), previousQuarters.quarterHMinus2C[i].end(), std::back_inserter(quorumMembers[i])); - std::move(previousQuarters.quarterHMinusC[i].begin(), previousQuarters.quarterHMinusC[i].end(), std::back_inserter(quorumMembers[i])); + for (auto* prev_cycle : prev_cycles | std::views::reverse) { + std::move(prev_cycle->m_members[i].begin(), prev_cycle->m_members[i].end(), std::back_inserter(quorumMembers[i])); + } std::move(newQuarterMembers[i].begin(), newQuarterMembers[i].end(), std::back_inserter(quorumMembers[i])); if (LogAcceptDebug(BCLog::LLMQ)) { From 85221d4524dd21fd75a6fad5cef5bed9c9b5dce4 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 22 Dec 2025 06:08:12 +0530 Subject: [PATCH 07/15] refactor: introduce `UtilParameters` struct to slim down arguments We can take the most commonly used functions and pass them through a struct to make the internal code more readable. --- src/evo/specialtxman.cpp | 3 +- src/llmq/blockprocessor.cpp | 2 +- src/llmq/commitment.cpp | 4 +- src/llmq/debug.cpp | 2 +- src/llmq/dkgsession.cpp | 6 +- src/llmq/dkgsessionhandler.cpp | 9 ++- src/llmq/dkgsessionmgr.cpp | 4 +- src/llmq/quorums.cpp | 7 +- src/llmq/utils.cpp | 116 +++++++++++++++------------------ src/llmq/utils.h | 54 +++++++-------- src/rpc/quorums.cpp | 10 +-- 11 files changed, 100 insertions(+), 117 deletions(-) diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index b87182f9de49..0135292c83c6 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -442,8 +442,7 @@ bool CSpecialTxProcessor::RebuildListFromBlock(const CBlock& block, gsl::not_nul // The commitment has already been validated at this point, so it's safe to use members of it - const auto members = llmq::utils::GetAllQuorumMembers(opt_qc->commitment.llmqType, m_dmnman, m_qsnapman, - m_chainman, pQuorumBaseBlockIndex); + const auto members = llmq::utils::GetAllQuorumMembers(opt_qc->commitment.llmqType, {m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex}); HandleQuorumCommitment(opt_qc->commitment, members, debugLogs, newList); } } diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index dbffa4e06e1d..98a6aac30c8c 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -32,7 +32,7 @@ static void PreComputeQuorumMembers(CDeterministicMNManager& dmnman, llmq::CQuor { for (const Consensus::LLMQParams& params : llmq::GetEnabledQuorumParams(chainman, pindex->pprev)) { if (llmq::IsQuorumRotationEnabled(params, pindex) && (pindex->nHeight % params.dkgInterval == 0)) { - llmq::utils::GetAllQuorumMembers(params.type, dmnman, qsnapman, chainman, pindex, reset_cache); + llmq::utils::GetAllQuorumMembers(params.type, {dmnman, qsnapman, chainman, pindex}, reset_cache); } } } diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 697cb28dae28..64866e62d8b9 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -33,7 +33,7 @@ bool CFinalCommitment::VerifySignatureAsync(CDeterministicMNManager& dmnman, CQu gsl::not_null pQuorumBaseBlockIndex, CCheckQueueControl* queue_control) const { - auto members = utils::GetAllQuorumMembers(llmqType, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex); + auto members = utils::GetAllQuorumMembers(llmqType, {dmnman, qsnapman, chainman, pQuorumBaseBlockIndex}); const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid llmqType=%d\n", quorumHash.ToString(), @@ -152,7 +152,7 @@ bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotMa LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid vvecSig\n", quorumHash.ToString()); return false; } - auto members = utils::GetAllQuorumMembers(llmqType, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex); + auto members = utils::GetAllQuorumMembers(llmqType, {dmnman, qsnapman, chainman, pQuorumBaseBlockIndex}); if (LogAcceptDebug(BCLog::LLMQ)) { std::stringstream ss; std::stringstream ss2; diff --git a/src/llmq/debug.cpp b/src/llmq/debug.cpp index 71bdf45ab461..5d48d36682d4 100644 --- a/src/llmq/debug.cpp +++ b/src/llmq/debug.cpp @@ -28,7 +28,7 @@ UniValue CDKGDebugSessionStatus::ToJson(CDeterministicMNManager& dmnman, CQuorum if (detailLevel == 2) { const CBlockIndex* pindex = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(quorumHash)); if (pindex != nullptr) { - dmnMembers = utils::GetAllQuorumMembers(llmqType, dmnman, qsnapman, chainman, pindex); + dmnMembers = utils::GetAllQuorumMembers(llmqType, {dmnman, qsnapman, chainman, pindex}); } } diff --git a/src/llmq/dkgsession.cpp b/src/llmq/dkgsession.cpp index 989d69862736..53497fc40b91 100644 --- a/src/llmq/dkgsession.cpp +++ b/src/llmq/dkgsession.cpp @@ -92,7 +92,7 @@ CDKGSession::CDKGSession(const CBlockIndex* pQuorumBaseBlockIndex, const Consens bool CDKGSession::Init(const uint256& _myProTxHash, int _quorumIndex) { - const auto mns = utils::GetAllQuorumMembers(params.type, m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index); + const auto mns = utils::GetAllQuorumMembers(params.type, {m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index}); quorumIndex = _quorumIndex; members.resize(mns.size()); memberIds.resize(members.size()); @@ -137,8 +137,8 @@ bool CDKGSession::Init(const uint256& _myProTxHash, int _quorumIndex) if (!myProTxHash.IsNull()) { dkgDebugManager.InitLocalSessionStatus(params, quorumIndex, m_quorum_base_block_index->GetBlockHash(), m_quorum_base_block_index->nHeight); - relayMembers = utils::GetQuorumRelayMembers(params, m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index, - myProTxHash, true); + relayMembers = utils::GetQuorumRelayMembers(params, {m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index}, myProTxHash, + /*onlyOutbound=*/true); if (LogAcceptDebug(BCLog::LLMQ)) { std::stringstream ss; for (const auto& r : relayMembers) { diff --git a/src/llmq/dkgsessionhandler.cpp b/src/llmq/dkgsessionhandler.cpp index 48ba7d2b7f73..e90979c44272 100644 --- a/src/llmq/dkgsessionhandler.cpp +++ b/src/llmq/dkgsessionhandler.cpp @@ -565,12 +565,11 @@ void CDKGSessionHandler::HandleDKGRound(CConnman& connman, PeerManager& peerman) } const auto tip_mn_list = m_dmnman.GetListAtChainTip(); - utils::EnsureQuorumConnections(params, connman, m_dmnman, m_qsnapman, m_chainman, m_sporkman, tip_mn_list, - pQuorumBaseBlockIndex, curSession->myProTxHash, - /*is_masternode=*/m_mn_activeman != nullptr, m_quorums_watch); + utils::EnsureQuorumConnections(params, connman, m_sporkman, {m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex}, tip_mn_list, + curSession->myProTxHash, /*is_masternode=*/m_mn_activeman != nullptr, m_quorums_watch); if (curSession->AreWeMember()) { - utils::AddQuorumProbeConnections(params, connman, m_dmnman, m_mn_metaman, m_qsnapman, m_chainman, m_sporkman, - tip_mn_list, pQuorumBaseBlockIndex, curSession->myProTxHash); + utils::AddQuorumProbeConnections(params, connman, m_mn_metaman, m_sporkman, {m_dmnman, m_qsnapman, m_chainman, + pQuorumBaseBlockIndex}, tip_mn_list, curSession->myProTxHash); } WaitForNextPhase(QuorumPhase::Initialized, QuorumPhase::Contribute, curQuorumHash); diff --git a/src/llmq/dkgsessionmgr.cpp b/src/llmq/dkgsessionmgr.cpp index 6303a41184a3..7021490c94b1 100644 --- a/src/llmq/dkgsessionmgr.cpp +++ b/src/llmq/dkgsessionmgr.cpp @@ -295,7 +295,7 @@ void CDKGSessionManager::WriteEncryptedContributions(Consensus::LLMQType llmqTyp bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, std::vector& skContributionsRet) const { - auto members = utils::GetAllQuorumMembers(llmqType, m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex); + auto members = utils::GetAllQuorumMembers(llmqType, {m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex}); memberIndexesRet.clear(); vvecsRet.clear(); @@ -344,7 +344,7 @@ bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, bool CDKGSessionManager::GetEncryptedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector& validMembers, const uint256& nProTxHash, std::vector>& vecRet) const { - auto members = utils::GetAllQuorumMembers(llmqType, m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex); + auto members = utils::GetAllQuorumMembers(llmqType, {m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex}); vecRet.clear(); vecRet.reserve(members.size()); diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index efd432a2101c..a55da096d464 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -368,9 +368,8 @@ void CQuorumManager::CheckQuorumConnections(CConnman& connman, const Consensus:: }); for (const auto& quorum : lastQuorums) { - if (utils::EnsureQuorumConnections(llmqParams, connman, m_dmnman, m_qsnapman, m_chainman, m_sporkman, - m_dmnman.GetListAtChainTip(), quorum->m_quorum_base_block_index, myProTxHash, - /*is_masternode=*/m_mn_activeman != nullptr, m_quorums_watch)) { + if (utils::EnsureQuorumConnections(llmqParams, connman, m_sporkman, {m_dmnman, m_qsnapman, m_chainman, quorum->m_quorum_base_block_index}, + m_dmnman.GetListAtChainTip(), myProTxHash, /*is_masternode=*/m_mn_activeman != nullptr, m_quorums_watch)) { 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__, ToUnderlying(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString()); } @@ -412,7 +411,7 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); auto quorum = std::make_shared(llmq_params_opt.value(), blsWorker); - auto members = utils::GetAllQuorumMembers(qc.llmqType, m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex); + auto members = utils::GetAllQuorumMembers(qc.llmqType, {m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex}); quorum->Init(std::make_unique(std::move(qc)), pQuorumBaseBlockIndex, minedBlockHash, members); diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 1d897ed1ffdf..b77e00c6e252 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -462,38 +462,37 @@ std::vector> BuildNewQuorumQuarterMembers( return quarterQuorumMembers; } -std::vector> ComputeQuorumMembersByQuarterRotation( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, llmq::CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, const CBlockIndex* pCycleQuorumBaseBlockIndex) +std::vector> + ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const llmq::utils::UtilParameters& util_params) { const int cycleLength = llmqParams.dkgInterval; - if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { + if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); return {}; } const auto nQuorums{static_cast(llmqParams.signingActiveQuorumCount)}; - const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); - CDeterministicMNList allMns = dmnman.GetListForBlock(pWorkBlockIndex); + const CBlockIndex* pWorkBlockIndex = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - 8); + CDeterministicMNList allMns = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqParams.type), - pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount()); + util_params.m_base_index->nHeight, allMns.GetValidMNsCount()); PreviousQuorumQuarters previousQuarters(nQuorums); auto prev_cycles{previousQuarters.GetCycles()}; for (size_t idx{0}; idx < prev_cycles.size(); idx++) { - prev_cycles[idx]->m_cycle_index = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - (cycleLength * (idx + 1))); - if (auto opt_snap = qsnapman.GetSnapshotForBlock(llmqParams.type, prev_cycles[idx]->m_cycle_index); opt_snap.has_value()) { + prev_cycles[idx]->m_cycle_index = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - (cycleLength * (idx + 1))); + if (auto opt_snap = util_params.m_qsnapman.GetSnapshotForBlock(llmqParams.type, prev_cycles[idx]->m_cycle_index); opt_snap.has_value()) { prev_cycles[idx]->m_snap = opt_snap.value(); } else { // TODO: Check if it is triggered from outside (P2P, block validation) and maybe throw an exception // assert(false); break; } - prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, dmnman, prev_cycles[idx]->m_cycle_index, - prev_cycles[idx]->m_snap, pCycleQuorumBaseBlockIndex->nHeight); + prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, util_params.m_dmnman, prev_cycles[idx]->m_cycle_index, + prev_cycles[idx]->m_snap, util_params.m_base_index->nHeight); } - auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, qsnapman, allMns, pCycleQuorumBaseBlockIndex, previousQuarters); + auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, util_params.m_qsnapman, allMns, util_params.m_base_index, previousQuarters); // TODO: Check if it is triggered from outside (P2P, block validation) and maybe throw an exception // assert (!newQuarterMembers.empty()); @@ -512,7 +511,7 @@ std::vector> ComputeQuorumMembersByQuarterRota ss << m->proTxHash.ToString().substr(0, 4) << "|"; } ss << " ]"; - LogPrint(BCLog::LLMQ, "QuarterComposition h[%d] i[%d]:%s\n", pCycleQuorumBaseBlockIndex->nHeight, i, + LogPrint(BCLog::LLMQ, "QuarterComposition h[%d] i[%d]:%s\n", util_params.m_base_index->nHeight, i, ss.str()); } } @@ -532,7 +531,7 @@ std::vector> ComputeQuorumMembersByQuarterRota ss << m->proTxHash.ToString().substr(0, 4) << "|"; } ss << "]"; - LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]:%s\n", pCycleQuorumBaseBlockIndex->nHeight, i, + LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]:%s\n", util_params.m_base_index->nHeight, i, ss.str()); } } @@ -583,17 +582,14 @@ void BlsCheck::swap(BlsCheck& obj) std::swap(m_id_string, obj.m_id_string); } -std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, - bool reset_cache) +std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParameters& util_params, bool reset_cache) { static RecursiveMutex cs_members; static std::map>> mapQuorumMembers GUARDED_BY( cs_members); static RecursiveMutex cs_indexed_members; static std::map, std::vector, StaticSaltedHasher>> mapIndexedQuorumMembers GUARDED_BY(cs_indexed_members); - if (!chainman.IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) { + if (!util_params.m_chainman.IsQuorumTypeEnabled(llmqType, util_params.m_base_index->pprev)) { return {}; } std::vector quorumMembers; @@ -604,7 +600,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy } if (reset_cache) { mapQuorumMembers[llmqType].clear(); - } else if (mapQuorumMembers[llmqType].get(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers)) { + } else if (mapQuorumMembers[llmqType].get(util_params.m_base_index->GetBlockHash(), quorumMembers)) { return quorumMembers; } } @@ -613,7 +609,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy assert(llmq_params_opt.has_value()); const auto& llmq_params = llmq_params_opt.value(); - if (IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex)) { + if (IsQuorumRotationEnabled(llmq_params, util_params.m_base_index)) { if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) { InitQuorumsCache(mapIndexedQuorumMembers); } @@ -626,12 +622,12 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy * Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex */ - int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval; + int quorumIndex = util_params.m_base_index->nHeight % llmq_params.dkgInterval; if (quorumIndex >= llmq_params.signingActiveQuorumCount) { return {}; } - int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex; - const CBlockIndex* pCycleQuorumBaseBlockIndex = pQuorumBaseBlockIndex->GetAncestor(cycleQuorumBaseHeight); + int cycleQuorumBaseHeight = util_params.m_base_index->nHeight - quorumIndex; + const CBlockIndex* pCycleQuorumBaseBlockIndex = util_params.m_base_index->GetAncestor(cycleQuorumBaseHeight); /* * Since mapQuorumMembers stores Quorum members per block hash, and we don't know yet the block hashes of blocks for all quorumIndexes (since these blocks are not created yet) @@ -642,11 +638,11 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy mapIndexedQuorumMembers[llmqType].clear(); } else if (LOCK(cs_indexed_members); mapIndexedQuorumMembers[llmqType].get(std::pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), quorumIndex), quorumMembers)) { LOCK(cs_members); - mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers); + mapQuorumMembers[llmqType].insert(util_params.m_base_index->GetBlockHash(), quorumMembers); return quorumMembers; } - auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, dmnman, qsnapman, chainman, pCycleQuorumBaseBlockIndex); + auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, util_params.replace_index(pCycleQuorumBaseBlockIndex)); quorumMembers = q[quorumIndex]; LOCK(cs_indexed_members); @@ -655,15 +651,15 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy std::move(q[i])); } } else { - const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) - ? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) - : pQuorumBaseBlockIndex.get(); - CDeterministicMNList mn_list = dmnman.GetListForBlock(pWorkBlockIndex); - quorumMembers = ComputeQuorumMembers(llmqType, mn_list, pQuorumBaseBlockIndex); + const CBlockIndex* pWorkBlockIndex = IsV20Active(util_params.m_base_index) + ? util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - 8) + : util_params.m_base_index.get(); + CDeterministicMNList mn_list = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); + quorumMembers = ComputeQuorumMembers(llmqType, mn_list, util_params.m_base_index); } LOCK(cs_members); - mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers); + mapQuorumMembers[llmqType].insert(util_params.m_base_index->GetBlockHash(), quorumMembers); return quorumMembers; } @@ -689,13 +685,11 @@ uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256 return proTxHash2; } -Uint256HashSet GetQuorumConnections(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const CSporkManager& sporkman, gsl::not_null pQuorumBaseBlockIndex, - const uint256& forMember, bool onlyOutbound) +Uint256HashSet GetQuorumConnections(const Consensus::LLMQParams& llmqParams, const CSporkManager& sporkman, + const UtilParameters& util_params, const uint256& forMember, bool onlyOutbound) { if (IsAllMembersConnectedEnabled(llmqParams.type, sporkman)) { - auto mns = GetAllQuorumMembers(llmqParams.type, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex); + auto mns = GetAllQuorumMembers(llmqParams.type, util_params); Uint256HashSet result; for (const auto& dmn : mns) { @@ -712,15 +706,13 @@ Uint256HashSet GetQuorumConnections(const Consensus::LLMQParams& llmqParams, CDe } return result; } - return GetQuorumRelayMembers(llmqParams, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex, forMember, onlyOutbound); + return GetQuorumRelayMembers(llmqParams, util_params, forMember, onlyOutbound); } -Uint256HashSet GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, const uint256& forMember, - bool onlyOutbound) +Uint256HashSet GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, const UtilParameters& util_params, + const uint256& forMember, bool onlyOutbound) { - auto mns = GetAllQuorumMembers(llmqParams.type, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex); + auto mns = GetAllQuorumMembers(llmqParams.type, util_params); Uint256HashSet result; auto calcOutbound = [&](size_t i, const uint256& proTxHash) { @@ -793,17 +785,15 @@ std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, return result; } -bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const CSporkManager& sporkman, const CDeterministicMNList& tip_mn_list, - gsl::not_null pQuorumBaseBlockIndex, const uint256& myProTxHash, - bool is_masternode, bool quorums_watch) +bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, const CSporkManager& sporkman, + const UtilParameters& util_params, const CDeterministicMNList& tip_mn_list, + const uint256& myProTxHash, bool is_masternode, bool quorums_watch) { if (!is_masternode && !quorums_watch) { return false; } - auto members = GetAllQuorumMembers(llmqParams.type, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex); + auto members = GetAllQuorumMembers(llmqParams.type, util_params); if (members.empty()) { return false; } @@ -814,23 +804,21 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& return false; } - LogPrint(BCLog::NET_NETCONN, "%s -- isMember=%d for quorum %s:\n", - __func__, isMember, pQuorumBaseBlockIndex->GetBlockHash().ToString()); + LogPrint(BCLog::NET_NETCONN, "%s -- isMember=%d for quorum %s:\n", __func__, isMember, util_params.m_base_index->GetBlockHash().ToString()); Uint256HashSet connections; if (isMember) { - connections = GetQuorumConnections(llmqParams, dmnman, qsnapman, chainman, sporkman, pQuorumBaseBlockIndex, - myProTxHash, /*onlyOutbound=*/true); + connections = GetQuorumConnections(llmqParams, sporkman, util_params, myProTxHash, /*onlyOutbound=*/true); } else { - auto cindexes = CalcDeterministicWatchConnections(llmqParams.type, pQuorumBaseBlockIndex, members.size(), 1); + auto cindexes = CalcDeterministicWatchConnections(llmqParams.type, util_params.m_base_index, members.size(), 1); for (auto idx : cindexes) { connections.emplace(members[idx]->proTxHash); } } if (!connections.empty()) { - if (!connman.HasMasternodeQuorumNodes(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash()) && + if (!connman.HasMasternodeQuorumNodes(llmqParams.type, util_params.m_base_index->GetBlockHash()) && LogAcceptDebug(BCLog::LLMQ)) { - std::string debugMsg = strprintf("%s -- adding masternodes quorum connections for quorum %s:\n", __func__, pQuorumBaseBlockIndex->GetBlockHash().ToString()); + std::string debugMsg = strprintf("%s -- adding masternodes quorum connections for quorum %s:\n", __func__, util_params.m_base_index->GetBlockHash().ToString()); for (const auto& c : connections) { auto dmn = tip_mn_list.GetValidMN(c); if (!dmn) { @@ -842,17 +830,15 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& } LogPrint(BCLog::NET_NETCONN, debugMsg.c_str()); /* Continued */ } - connman.SetMasternodeQuorumNodes(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash(), connections); - connman.SetMasternodeQuorumRelayMembers(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash(), connections); + connman.SetMasternodeQuorumNodes(llmqParams.type, util_params.m_base_index->GetBlockHash(), connections); + connman.SetMasternodeQuorumRelayMembers(llmqParams.type, util_params.m_base_index->GetBlockHash(), connections); } return true; } -void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, - CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const CSporkManager& sporkman, const CDeterministicMNList& tip_mn_list, - gsl::not_null pQuorumBaseBlockIndex, const uint256& myProTxHash) +void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, CMasternodeMetaMan& mn_metaman, + const CSporkManager& sporkman, const UtilParameters& util_params, + const CDeterministicMNList& tip_mn_list, const uint256& myProTxHash) { assert(mn_metaman.IsValid()); @@ -860,7 +846,7 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman return; } - auto members = GetAllQuorumMembers(llmqParams.type, dmnman, qsnapman, chainman, pQuorumBaseBlockIndex); + auto members = GetAllQuorumMembers(llmqParams.type, util_params); auto curTime = GetTime().count(); std::set probeConnections; @@ -878,7 +864,7 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman if (!probeConnections.empty()) { if (LogAcceptDebug(BCLog::LLMQ)) { - std::string debugMsg = strprintf("%s -- adding masternodes probes for quorum %s:\n", __func__, pQuorumBaseBlockIndex->GetBlockHash().ToString()); + std::string debugMsg = strprintf("%s -- adding masternodes probes for quorum %s:\n", __func__, util_params.m_base_index->GetBlockHash().ToString()); for (const auto& c : probeConnections) { auto dmn = tip_mn_list.GetValidMN(c); if (!dmn) { diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 48a16a08bafe..02c976388328 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -48,39 +48,39 @@ struct BlsCheck { void swap(BlsCheck& obj); }; -// includes members which failed DKG -std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, - bool reset_cache = false); - uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2); -Uint256HashSet GetQuorumConnections(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const CSporkManager& sporkman, gsl::not_null pQuorumBaseBlockIndex, - const uint256& forMember, bool onlyOutbound); - -Uint256HashSet GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, const uint256& forMember, - bool onlyOutbound); - std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, gsl::not_null pQuorumBaseBlockIndex, size_t memberCount, size_t connectionCount); -bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, CDeterministicMNManager& dmnman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const CSporkManager& sporkman, const CDeterministicMNList& tip_mn_list, - gsl::not_null pQuorumBaseBlockIndex, const uint256& myProTxHash, - bool is_masternode, bool quorums_watch); - -void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, - CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const CSporkManager& sporkman, const CDeterministicMNList& tip_mn_list, - gsl::not_null pQuorumBaseBlockIndex, const uint256& myProTxHash); +struct UtilParameters { + CDeterministicMNManager& m_dmnman; + CQuorumSnapshotManager& m_qsnapman; + const ChainstateManager& m_chainman; + gsl::not_null m_base_index; + +public: + UtilParameters replace_index(gsl::not_null base_index) const { return {m_dmnman, m_qsnapman, m_chainman, base_index}; } +}; + +// includes members which failed DKG +std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParameters& util_params, + bool reset_cache = false); + +Uint256HashSet GetQuorumConnections(const Consensus::LLMQParams& llmqParams, const CSporkManager& sporkman, + const UtilParameters& util_params, const uint256& forMember, bool onlyOutbound); + +Uint256HashSet GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, const UtilParameters& util_params, + const uint256& forMember, bool onlyOutbound); + +bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, const CSporkManager& sporkman, + const UtilParameters& util_params, const CDeterministicMNList& tip_mn_list, + const uint256& myProTxHash, bool is_masternode, bool quorums_watch); + +void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, CMasternodeMetaMan& mn_metaman, + const CSporkManager& sporkman, const UtilParameters& util_params, + const CDeterministicMNList& tip_mn_list, const uint256& myProTxHash); template inline void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true) diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index f2638fc2d195..8a39d057f1d1 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -377,12 +377,12 @@ static RPCHelpMan quorum_dkgstatus() obj.pushKV("quorumHash", pQuorumBaseBlockIndex->GetBlockHash().ToString()); obj.pushKV("pindexTip", pindexTip->nHeight); - auto allConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.dmnman, - *llmq_ctx.qsnapman, chainman, *node.sporkman, - pQuorumBaseBlockIndex, proTxHash, false); - auto outboundConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.dmnman, + auto allConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.sporkman, {*node.dmnman, + *llmq_ctx.qsnapman, chainman, + pQuorumBaseBlockIndex}, proTxHash, false); + auto outboundConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.sporkman, {*node.dmnman, *llmq_ctx.qsnapman, chainman, - *node.sporkman, pQuorumBaseBlockIndex, + pQuorumBaseBlockIndex}, proTxHash, true); std::map foundConnections; connman.ForEachNode([&](const CNode* pnode) { From 8c4f83bb82e23e6798d95aad856cace0cfdab394 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 22 Dec 2025 01:50:55 +0530 Subject: [PATCH 08/15] refactor: introduce `MasternodeScore` for better docs --- src/llmq/utils.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index b77e00c6e252..a197bba2bd24 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -31,6 +31,11 @@ std::optional> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex); namespace { +struct MasternodeScore { + arith_uint256 m_score; + CDeterministicMNCPtr m_node; +}; + struct QuorumQuarter { llmq::CQuorumSnapshot m_snap; std::vector> m_members; @@ -103,10 +108,9 @@ uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_nullGetBlockHash())); } -std::vector> - CalculateScoresForQuorum(std::vector&& dmns, const uint256& modifier, const bool onlyEvoNodes) +std::vector CalculateScoresForQuorum(std::vector&& dmns, const uint256& modifier, const bool onlyEvoNodes) { - std::vector> scores; + std::vector scores; scores.reserve(dmns.size()); for (auto& dmn : dmns) { @@ -124,10 +128,9 @@ std::vector> return scores; } -std::vector> - CalculateScoresForQuorum(const CDeterministicMNList& mn_list, const uint256& modifier, const bool onlyEvoNodes) +std::vector CalculateScoresForQuorum(const CDeterministicMNList& mn_list, const uint256& modifier, const bool onlyEvoNodes) { - std::vector> scores; + std::vector scores; scores.reserve(mn_list.GetAllMNsCount()); mn_list.ForEachMNShared(/*onlyValid=*/true, [&](const auto& dmn) { @@ -156,14 +159,13 @@ std::vector CalculateQuorum(List&& mn_list, const uint256& // sort is descending order std::sort(scores.rbegin(), scores.rend(), - [](const std::pair& a, - const std::pair& b) { - if (a.first == b.first) { + [](const MasternodeScore& a, const MasternodeScore& b) { + if (a.m_score == b.m_score) { // this should actually never happen, but we should stay compatible with how the non-deterministic MNs did the sorting // TODO - add assert ? - return a.second->collateralOutpoint < b.second->collateralOutpoint; + return a.m_node->collateralOutpoint < b.m_node->collateralOutpoint; } - return a.first < b.first; + return a.m_score < b.m_score; }); // return top maxSize entries only (if specified) @@ -173,8 +175,8 @@ std::vector CalculateQuorum(List&& mn_list, const uint256& std::vector result; result.reserve(scores.size()); - for (auto& score : scores) { - result.emplace_back(std::move(score.second)); + for (auto& [_, node] : scores) { + result.emplace_back(std::move(node)); } return result; } From 515163a98b1d8a828a97ea6271a2840f6c91f675 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 22 Dec 2025 05:56:21 +0530 Subject: [PATCH 09/15] refactor: simplify `BuildQuorumRotationInfo()` (1/n) --- src/llmq/snapshot.cpp | 135 ++++++++++++++++-------------------------- src/llmq/snapshot.h | 8 ++- src/llmq/utils.cpp | 5 +- 3 files changed, 60 insertions(+), 88 deletions(-) diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 23a1a8e4a630..1b3d531c111d 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -101,57 +101,32 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan } } - const CBlockIndex* pBlockHMinusCIndex = tipBlockIndex->GetAncestor(hBlockIndex->nHeight - cycleLength); - if (!pBlockHMinusCIndex) { - errorRet = strprintf("Can not find block H-C"); - return false; - } - const CBlockIndex* pWorkBlockHMinusCIndex = pBlockHMinusCIndex->GetAncestor(pBlockHMinusCIndex->nHeight - workDiff); - if (!pWorkBlockHMinusCIndex) { - errorRet = strprintf("Can not find work block H-C"); - return false; - } - - const CBlockIndex* pBlockHMinus2CIndex = pBlockHMinusCIndex->GetAncestor(hBlockIndex->nHeight - 2 * cycleLength); - if (!pBlockHMinus2CIndex) { - errorRet = strprintf("Can not find block H-2C"); - return false; - } - const CBlockIndex* pWorkBlockHMinus2CIndex = pBlockHMinus2CIndex->GetAncestor(pBlockHMinus2CIndex->nHeight - workDiff); - if (!pWorkBlockHMinus2CIndex) { - errorRet = strprintf("Can not find work block H-2C"); - return false; - } - - const CBlockIndex* pBlockHMinus3CIndex = pBlockHMinusCIndex->GetAncestor(hBlockIndex->nHeight - 3 * cycleLength); - if (!pBlockHMinus3CIndex) { - errorRet = strprintf("Can not find block H-3C"); - return false; - } - const CBlockIndex* pWorkBlockHMinus3CIndex = pBlockHMinus3CIndex->GetAncestor(pBlockHMinus3CIndex->nHeight - workDiff); - if (!pWorkBlockHMinus3CIndex) { - errorRet = strprintf("Can not find work block H-3C"); - return false; - } - - const CBlockIndex* pBlockHMinus4CIndex = pBlockHMinusCIndex->GetAncestor(hBlockIndex->nHeight - 4 * cycleLength); - if (!pBlockHMinus4CIndex) { - errorRet = strprintf("Can not find block H-4C"); - return false; + response.extraShare = request.extraShare; + + auto target_cycles{response.GetCycles()}; + for (size_t idx{0}; idx < target_cycles.size(); idx++) { + auto* cycle{target_cycles[idx]}; + cycle->m_cycle_index = tipBlockIndex->GetAncestor(hBlockIndex->nHeight - (cycleLength * (idx + 1))); + if (!cycle->m_cycle_index) { + errorRet = strprintf("Cannot find block H-%dC", idx + 1); + return false; + } + cycle->m_work_index = cycle->m_cycle_index->GetAncestor(cycle->m_cycle_index->nHeight - workDiff); + if (!cycle->m_work_index) { + errorRet = strprintf("Cannot find work block H-%dC", idx + 1); + return false; + } } - const CBlockIndex* pWorkBlockHMinus4CIndex = pBlockHMinus4CIndex->GetAncestor(pBlockHMinus4CIndex->nHeight - workDiff); - //Checked later if extraShare is on - if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinusCIndex, use_legacy_construction), - pWorkBlockHMinusCIndex->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinusC.m_work_index, use_legacy_construction), + response.cycleHMinusC.m_work_index->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { return false; } } - auto snapshotHMinusC = qsnapman.GetSnapshotForBlock(llmqType, pBlockHMinusCIndex); + auto snapshotHMinusC = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinusC.m_cycle_index); if (!snapshotHMinusC.has_value()) { errorRet = strprintf("Can not find quorum snapshot at H-C"); return false; @@ -161,14 +136,13 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus2CIndex, - use_legacy_construction), - pWorkBlockHMinus2CIndex->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus2C.m_work_index, use_legacy_construction), + response.cycleHMinus2C.m_work_index->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { return false; } } - auto snapshotHMinus2C = qsnapman.GetSnapshotForBlock(llmqType, pBlockHMinus2CIndex); + auto snapshotHMinus2C = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinus2C.m_cycle_index); if (!snapshotHMinus2C.has_value()) { errorRet = strprintf("Can not find quorum snapshot at H-2C"); return false; @@ -178,14 +152,13 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus3CIndex, - use_legacy_construction), - pWorkBlockHMinus3CIndex->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus3C.m_work_index, use_legacy_construction), + response.cycleHMinus3C.m_work_index->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { return false; } } - auto snapshotHMinus3C = qsnapman.GetSnapshotForBlock(llmqType, pBlockHMinus3CIndex); + auto snapshotHMinus3C = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinus3C.m_cycle_index); if (!snapshotHMinus3C.has_value()) { errorRet = strprintf("Can not find quorum snapshot at H-3C"); return false; @@ -194,37 +167,27 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan } if (request.extraShare) { - response.extraShare = true; - - if (!pWorkBlockHMinus4CIndex) { + if (!Assert(response.cycleHMinus4C)->m_work_index) { errorRet = strprintf("Can not find work block H-4C"); return false; } - CycleData extraCycle; - auto snapshotHMinus4C = qsnapman.GetSnapshotForBlock(llmqType, pBlockHMinus4CIndex); + auto snapshotHMinus4C = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinus4C->m_cycle_index); if (!snapshotHMinus4C.has_value()) { errorRet = strprintf("Can not find quorum snapshot at H-4C"); return false; - } else { - extraCycle.m_snap = std::move(snapshotHMinus4C.value()); } + response.cycleHMinus4C->m_snap = std::move(snapshotHMinus4C.value()); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus4CIndex, - use_legacy_construction), - pWorkBlockHMinus4CIndex->GetBlockHash(), extraCycle.m_diff, errorRet)) { - extraCycle.m_diff = {}; + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus4C->m_work_index, use_legacy_construction), + response.cycleHMinus4C->m_work_index->GetBlockHash(), response.cycleHMinus4C->m_diff, errorRet)) { return false; } if (!use_legacy_construction) { - baseBlockIndexes.push_back(pWorkBlockHMinus4CIndex); + baseBlockIndexes.push_back(response.cycleHMinus4C->m_work_index); } - - response.cycleHMinus4C = extraCycle; - } else { - response.extraShare = false; } std::set snapshotHeightsNeeded; @@ -245,11 +208,9 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan snapshotHeightsNeeded.insert(quorumCycleStartHeight - 3 * cycleLength); } - snapshotHeightsNeeded.erase(pBlockHMinusCIndex->nHeight); - snapshotHeightsNeeded.erase(pBlockHMinus2CIndex->nHeight); - snapshotHeightsNeeded.erase(pBlockHMinus3CIndex->nHeight); - if (request.extraShare) - snapshotHeightsNeeded.erase(pBlockHMinus4CIndex->nHeight); + for (auto* cycle : target_cycles) { + snapshotHeightsNeeded.erase(cycle->m_cycle_index->nHeight); + } for (const auto& h : snapshotHeightsNeeded) { const CBlockIndex* pNeededBlockIndex = tipBlockIndex->GetAncestor(h); @@ -285,27 +246,25 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan if (!use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus3CIndex, - use_legacy_construction), - pWorkBlockHMinus3CIndex->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus3C.m_work_index, use_legacy_construction), + response.cycleHMinus3C.m_work_index->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { return false; } - baseBlockIndexes.push_back(pWorkBlockHMinus3CIndex); + baseBlockIndexes.push_back(response.cycleHMinus3C.m_work_index); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinus2CIndex, - use_legacy_construction), - pWorkBlockHMinus2CIndex->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus2C.m_work_index, use_legacy_construction), + response.cycleHMinus2C.m_work_index->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { return false; } - baseBlockIndexes.push_back(pWorkBlockHMinus2CIndex); + baseBlockIndexes.push_back(response.cycleHMinus2C.m_work_index); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHMinusCIndex, use_legacy_construction), - pWorkBlockHMinusCIndex->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinusC.m_work_index, use_legacy_construction), + response.cycleHMinusC.m_work_index->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { return false; } - baseBlockIndexes.push_back(pWorkBlockHMinusCIndex); + baseBlockIndexes.push_back(response.cycleHMinusC.m_work_index); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHIndex, use_legacy_construction), @@ -355,6 +314,16 @@ CQuorumRotationInfo::CQuorumRotationInfo() = default; CQuorumRotationInfo::~CQuorumRotationInfo() = default; +std::vector CQuorumRotationInfo::GetCycles() +{ + std::vector ret{&cycleHMinusC, &cycleHMinus2C, &cycleHMinus3C}; + if (extraShare) { + if (!cycleHMinus4C.has_value()) { cycleHMinus4C = CycleData{}; } + ret.emplace_back(&(cycleHMinus4C.value())); + } + return ret; +} + CQuorumSnapshotManager::CQuorumSnapshotManager(CEvoDB& evoDb) : m_evoDb{evoDb}, quorumSnapshotCache{32} diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 1e70c1b74955..5e7119e0b242 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -99,9 +99,14 @@ class CGetQuorumRotationInfo } }; -struct CycleData { +struct CycleBase { CQuorumSnapshot m_snap; + const CBlockIndex* m_cycle_index{nullptr}; +}; + +struct CycleData : public CycleBase { CSimplifiedMNListDiff m_diff; + const CBlockIndex* m_work_index{nullptr}; }; class CQuorumRotationInfo @@ -198,6 +203,7 @@ class CQuorumRotationInfo } } + std::vector GetCycles(); [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); [[nodiscard]] UniValue ToJson() const; }; diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index a197bba2bd24..be30c3d1bc7f 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -36,11 +36,8 @@ struct MasternodeScore { CDeterministicMNCPtr m_node; }; -struct QuorumQuarter { - llmq::CQuorumSnapshot m_snap; +struct QuorumQuarter : public llmq::CycleBase { std::vector> m_members; - //! memory only - const CBlockIndex* m_cycle_index{nullptr}; public: explicit QuorumQuarter(size_t size) : m_members(size) {} From 3e5e273930b7de7643a2bd4667d44e1947d4a4a1 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 21 Dec 2025 19:24:32 +0530 Subject: [PATCH 10/15] refactor: simplify `BuildQuorumRotationInfo()` (2/n) --- src/llmq/snapshot.cpp | 121 +++++++++--------------------------------- 1 file changed, 25 insertions(+), 96 deletions(-) diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 1b3d531c111d..7565f58ee9bb 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -106,96 +106,35 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan auto target_cycles{response.GetCycles()}; for (size_t idx{0}; idx < target_cycles.size(); idx++) { auto* cycle{target_cycles[idx]}; - cycle->m_cycle_index = tipBlockIndex->GetAncestor(hBlockIndex->nHeight - (cycleLength * (idx + 1))); + const auto depth{idx + 1}; + cycle->m_cycle_index = tipBlockIndex->GetAncestor(hBlockIndex->nHeight - (cycleLength * depth)); if (!cycle->m_cycle_index) { - errorRet = strprintf("Cannot find block H-%dC", idx + 1); + errorRet = strprintf("Cannot find block H-%dC", depth); return false; } cycle->m_work_index = cycle->m_cycle_index->GetAncestor(cycle->m_cycle_index->nHeight - workDiff); if (!cycle->m_work_index) { - errorRet = strprintf("Cannot find work block H-%dC", idx + 1); + errorRet = strprintf("Cannot find work block H-%dC", depth); return false; } - } - - if (use_legacy_construction) { - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinusC.m_work_index, use_legacy_construction), - response.cycleHMinusC.m_work_index->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { - return false; - } - } - - auto snapshotHMinusC = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinusC.m_cycle_index); - if (!snapshotHMinusC.has_value()) { - errorRet = strprintf("Can not find quorum snapshot at H-C"); - return false; - } else { - response.cycleHMinusC.m_snap = std::move(snapshotHMinusC.value()); - } - - if (use_legacy_construction) { - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus2C.m_work_index, use_legacy_construction), - response.cycleHMinus2C.m_work_index->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { - return false; - } - } - - auto snapshotHMinus2C = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinus2C.m_cycle_index); - if (!snapshotHMinus2C.has_value()) { - errorRet = strprintf("Can not find quorum snapshot at H-2C"); - return false; - } else { - response.cycleHMinus2C.m_snap = std::move(snapshotHMinus2C.value()); - } - - if (use_legacy_construction) { - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus3C.m_work_index, use_legacy_construction), - response.cycleHMinus3C.m_work_index->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { - return false; - } - } - - auto snapshotHMinus3C = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinus3C.m_cycle_index); - if (!snapshotHMinus3C.has_value()) { - errorRet = strprintf("Can not find quorum snapshot at H-3C"); - return false; - } else { - response.cycleHMinus3C.m_snap = std::move(snapshotHMinus3C.value()); - } - - if (request.extraShare) { - if (!Assert(response.cycleHMinus4C)->m_work_index) { - errorRet = strprintf("Can not find work block H-4C"); - return false; - } - - auto snapshotHMinus4C = qsnapman.GetSnapshotForBlock(llmqType, response.cycleHMinus4C->m_cycle_index); - if (!snapshotHMinus4C.has_value()) { - errorRet = strprintf("Can not find quorum snapshot at H-4C"); - return false; - } - response.cycleHMinus4C->m_snap = std::move(snapshotHMinus4C.value()); - - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus4C->m_work_index, use_legacy_construction), - response.cycleHMinus4C->m_work_index->GetBlockHash(), response.cycleHMinus4C->m_diff, errorRet)) { + if (auto opt_snap = qsnapman.GetSnapshotForBlock(llmqType, cycle->m_cycle_index); opt_snap.has_value()) { + cycle->m_snap = std::move(opt_snap.value()); + } else { + errorRet = strprintf("Cannot find quorum snapshot at H-%dC", depth); return false; } - - if (!use_legacy_construction) { - baseBlockIndexes.push_back(response.cycleHMinus4C->m_work_index); + if (use_legacy_construction) { + if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, + GetLastBaseBlockHash(baseBlockIndexes, cycle->m_work_index, use_legacy_construction), + cycle->m_work_index->GetBlockHash(), cycle->m_diff, errorRet)) + { + return false; + } } } std::set snapshotHeightsNeeded; - - std::vector qdata = qblockman.GetLastMinedCommitmentsPerQuorumIndexUntilBlock(llmqType, - blockIndex, 0); - - for (const auto& obj : qdata) { + for (const auto& obj : qblockman.GetLastMinedCommitmentsPerQuorumIndexUntilBlock(llmqType, blockIndex, /*cycle=*/0)) { auto [qc, minedBlockHash] = qblockman.GetMinedCommitment(llmqType, obj->GetBlockHash()); if (minedBlockHash == uint256::ZERO) { return false; @@ -245,26 +184,16 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan } if (!use_legacy_construction) { - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus3C.m_work_index, use_legacy_construction), - response.cycleHMinus3C.m_work_index->GetBlockHash(), response.cycleHMinus3C.m_diff, errorRet)) { - return false; - } - baseBlockIndexes.push_back(response.cycleHMinus3C.m_work_index); - - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinus2C.m_work_index, use_legacy_construction), - response.cycleHMinus2C.m_work_index->GetBlockHash(), response.cycleHMinus2C.m_diff, errorRet)) { - return false; - } - baseBlockIndexes.push_back(response.cycleHMinus2C.m_work_index); - - if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, response.cycleHMinusC.m_work_index, use_legacy_construction), - response.cycleHMinusC.m_work_index->GetBlockHash(), response.cycleHMinusC.m_diff, errorRet)) { - return false; + for (size_t idx = target_cycles.size(); idx-- > 0;) { + auto* cycle{target_cycles[idx]}; + if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, + GetLastBaseBlockHash(baseBlockIndexes, cycle->m_work_index, use_legacy_construction), + cycle->m_work_index->GetBlockHash(), cycle->m_diff, errorRet)) + { + return false; + } + baseBlockIndexes.push_back(cycle->m_work_index); } - baseBlockIndexes.push_back(response.cycleHMinusC.m_work_index); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHIndex, use_legacy_construction), From 6a6a240ff49c92bb3c9fdcd738a0d151be01d5d1 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 24 Dec 2025 00:46:48 +0530 Subject: [PATCH 11/15] refactor: simplify `BuildQuorumRotationInfo()` (3/n) --- src/llmq/snapshot.cpp | 110 ++++++++++++++++++++---------------------- src/llmq/snapshot.h | 2 + src/llmq/utils.cpp | 8 +-- 3 files changed, 57 insertions(+), 63 deletions(-) diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 7565f58ee9bb..8ce488a3bb18 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -10,13 +10,42 @@ #include #include #include -#include #include -namespace llmq { +#include + +namespace { +constexpr std::string_view DB_QUORUM_SNAPSHOT{"llmq_S"}; -static const std::string DB_QUORUM_SNAPSHOT = "llmq_S"; +//! Constructs a llmq::CycleData and populate it with metadata +std::optional ConstructCycle(llmq::CQuorumSnapshotManager& qsnapman, const Consensus::LLMQType& llmq_type, + bool skip_snap, int32_t height, gsl::not_null index_tip, + std::string& error) +{ + llmq::CycleData ret; + ret.m_cycle_index = index_tip->GetAncestor(height); + if (!ret.m_cycle_index) { + error = "Cannot find block"; + return std::nullopt; + } + ret.m_work_index = ret.m_cycle_index->GetAncestor(ret.m_cycle_index->nHeight - llmq::WORK_DIFF_DEPTH); + if (!ret.m_work_index) { + error = "Cannot find work block"; + return std::nullopt; + } + if (!skip_snap) { + if (auto opt_snap = qsnapman.GetSnapshotForBlock(llmq_type, ret.m_cycle_index); opt_snap.has_value()) { + ret.m_snap = opt_snap.value(); + } else { + error = "Cannot find quorum snapshot"; + return std::nullopt; + } + } + return ret; +} +} // anonymous namespace +namespace llmq { bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const CQuorumManager& qman, const CQuorumBlockProcessor& qblockman, const CGetQuorumRotationInfo& request, @@ -70,7 +99,7 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan return false; } - //Quorum rotation is enabled only for InstantSend atm. + // Quorum rotation is enabled only for InstantSend atm. Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; // Since the returned quorums are in reversed order, the most recent one is at index 0 @@ -78,25 +107,16 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan assert(llmq_params_opt.has_value()); const int cycleLength = llmq_params_opt->dkgInterval; - constexpr int workDiff = 8; - - const CBlockIndex* hBlockIndex = blockIndex->GetAncestor(blockIndex->nHeight - (blockIndex->nHeight % cycleLength)); - if (!hBlockIndex) { - errorRet = strprintf("Can not find block H"); - return false; - } - const CBlockIndex* pWorkBlockHIndex = hBlockIndex->GetAncestor(hBlockIndex->nHeight - workDiff); - if (!pWorkBlockHIndex) { - errorRet = strprintf("Can not find work block H"); + auto cycle_base_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/true, /*height=*/blockIndex->nHeight - (blockIndex->nHeight % cycleLength), blockIndex, errorRet); + if (!cycle_base_opt.has_value()) { return false; } - if (use_legacy_construction) { // Build MN list Diff always with highest baseblock if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHIndex, use_legacy_construction), - pWorkBlockHIndex->GetBlockHash(), response.mnListDiffH, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, cycle_base_opt->m_work_index, use_legacy_construction), + cycle_base_opt->m_work_index->GetBlockHash(), response.mnListDiffH, errorRet)) { return false; } } @@ -105,32 +125,18 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan auto target_cycles{response.GetCycles()}; for (size_t idx{0}; idx < target_cycles.size(); idx++) { - auto* cycle{target_cycles[idx]}; - const auto depth{idx + 1}; - cycle->m_cycle_index = tipBlockIndex->GetAncestor(hBlockIndex->nHeight - (cycleLength * depth)); - if (!cycle->m_cycle_index) { - errorRet = strprintf("Cannot find block H-%dC", depth); - return false; - } - cycle->m_work_index = cycle->m_cycle_index->GetAncestor(cycle->m_cycle_index->nHeight - workDiff); - if (!cycle->m_work_index) { - errorRet = strprintf("Cannot find work block H-%dC", depth); - return false; - } - if (auto opt_snap = qsnapman.GetSnapshotForBlock(llmqType, cycle->m_cycle_index); opt_snap.has_value()) { - cycle->m_snap = std::move(opt_snap.value()); - } else { - errorRet = strprintf("Cannot find quorum snapshot at H-%dC", depth); + auto cycle_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/false, /*height=*/cycle_base_opt->m_cycle_index->nHeight - (cycleLength * (idx + 1)), tipBlockIndex, errorRet); + if (!cycle_opt.has_value()) { return false; } if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, cycle->m_work_index, use_legacy_construction), - cycle->m_work_index->GetBlockHash(), cycle->m_diff, errorRet)) - { + GetLastBaseBlockHash(baseBlockIndexes, cycle_opt->m_work_index, use_legacy_construction), + cycle_opt->m_work_index->GetBlockHash(), cycle_opt->m_diff, errorRet)) { return false; } } + *target_cycles[idx] = cycle_opt.value(); } std::set snapshotHeightsNeeded; @@ -152,33 +158,19 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan } for (const auto& h : snapshotHeightsNeeded) { - const CBlockIndex* pNeededBlockIndex = tipBlockIndex->GetAncestor(h); - if (!pNeededBlockIndex) { - errorRet = strprintf("Can not find needed block H(%d)", h); - return false; - } - const CBlockIndex* pNeededWorkBlockIndex = pNeededBlockIndex->GetAncestor(pNeededBlockIndex->nHeight - workDiff); - if (!pNeededWorkBlockIndex) { - errorRet = strprintf("Can not find needed work block H(%d)", h); - return false; - } - - auto snapshotNeededH = qsnapman.GetSnapshotForBlock(llmqType, pNeededBlockIndex); - if (!snapshotNeededH.has_value()) { - errorRet = strprintf("Can not find quorum snapshot at H(%d)", h); + auto cycle_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/false, /*height=*/h, tipBlockIndex, errorRet); + if (!cycle_opt.has_value()) { return false; - } else { - response.quorumSnapshotList.push_back(snapshotNeededH.value()); } - + response.quorumSnapshotList.push_back(cycle_opt->m_snap); CSimplifiedMNListDiff mnhneeded; if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pNeededWorkBlockIndex, use_legacy_construction), - pNeededWorkBlockIndex->GetBlockHash(), mnhneeded, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, cycle_opt->m_work_index, use_legacy_construction), + cycle_opt->m_work_index->GetBlockHash(), mnhneeded, errorRet)) { return false; } if (!use_legacy_construction) { - baseBlockIndexes.push_back(pNeededWorkBlockIndex); + baseBlockIndexes.push_back(cycle_opt->m_work_index); } response.mnListDiffList.push_back(mnhneeded); } @@ -196,11 +188,11 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan } if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, pWorkBlockHIndex, use_legacy_construction), - pWorkBlockHIndex->GetBlockHash(), response.mnListDiffH, errorRet)) { + GetLastBaseBlockHash(baseBlockIndexes, cycle_base_opt->m_work_index, use_legacy_construction), + cycle_base_opt->m_work_index->GetBlockHash(), response.mnListDiffH, errorRet)) { return false; } - baseBlockIndexes.push_back(pWorkBlockHIndex); + baseBlockIndexes.push_back(cycle_base_opt->m_work_index); if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, GetLastBaseBlockHash(baseBlockIndexes, tipBlockIndex, use_legacy_construction), diff --git a/src/llmq/snapshot.h b/src/llmq/snapshot.h index 5e7119e0b242..d85758dd84df 100644 --- a/src/llmq/snapshot.h +++ b/src/llmq/snapshot.h @@ -36,6 +36,8 @@ enum class SnapshotSkipMode : int { template<> struct is_serializable_enum : std::true_type {}; namespace llmq { +constexpr int WORK_DIFF_DEPTH{8}; + class CQuorumSnapshot { public: diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index be30c3d1bc7f..8b8a3d7e6c3c 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -84,7 +84,7 @@ arith_uint256 calculateQuorumScore(const CDeterministicMNCPtr& dmn, const uint25 uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex) { ASSERT_IF_DEBUG(pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval == 0); - const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); + const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - llmq::WORK_DIFF_DEPTH); if (IsV20Active(pWorkBlockIndex)) { // v20 is active: calculate modifier using the new way. @@ -190,7 +190,7 @@ std::vector> GetQuorumQuarterMembersBySnapshot std::vector sortedCombinedMns; { const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor( - pCycleQuorumBaseBlockIndex->nHeight - 8); + pCycleQuorumBaseBlockIndex->nHeight - llmq::WORK_DIFF_DEPTH); auto mn_list = dmnman.GetListForBlock(pWorkBlockIndex); const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); auto sortedAllMns = CalculateQuorum(mn_list, modifier); @@ -471,7 +471,7 @@ std::vector> } const auto nQuorums{static_cast(llmqParams.signingActiveQuorumCount)}; - const CBlockIndex* pWorkBlockIndex = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - 8); + const CBlockIndex* pWorkBlockIndex = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - llmq::WORK_DIFF_DEPTH); CDeterministicMNList allMns = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqParams.type), util_params.m_base_index->nHeight, allMns.GetValidMNsCount()); @@ -651,7 +651,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy } } else { const CBlockIndex* pWorkBlockIndex = IsV20Active(util_params.m_base_index) - ? util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - 8) + ? util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - WORK_DIFF_DEPTH) : util_params.m_base_index.get(); CDeterministicMNList mn_list = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); quorumMembers = ComputeQuorumMembers(llmqType, mn_list, util_params.m_base_index); From 8a3d852b81be4d5dd58336d9f2a5cfe795b821d9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 22 Dec 2025 05:33:32 +0530 Subject: [PATCH 12/15] refactor: misc. refactoring in `llmq/utils.cpp` - Introduce `QuorumMembers` type alias - Inline `IsV{19,20}Active()` helpers - Deduplicate quorum member printing logic --- src/llmq/utils.cpp | 109 ++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 71 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 8b8a3d7e6c3c..c300cc73f045 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -31,13 +31,24 @@ std::optional> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex); namespace { +using QuorumMembers = std::vector; + +std::string ToString(const QuorumMembers& members) +{ + std::stringstream ss; + for (const auto& mn : members) { + ss << mn->proTxHash.ToString().substr(0, 4) << "|"; + } + return ss.str(); +} + struct MasternodeScore { arith_uint256 m_score; CDeterministicMNCPtr m_node; }; struct QuorumQuarter : public llmq::CycleBase { - std::vector> m_members; + std::vector m_members; public: explicit QuorumQuarter(size_t size) : m_members(size) {} @@ -56,16 +67,6 @@ struct PreviousQuorumQuarters { std::vector GetCycles() const { return {&quarterHMinusC, &quarterHMinus2C, &quarterHMinus3C}; } }; -bool IsV19Active(gsl::not_null pindexPrev) -{ - return DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19); -} - -bool IsV20Active(gsl::not_null pindexPrev) -{ - return DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20); -} - arith_uint256 calculateQuorumScore(const CDeterministicMNCPtr& dmn, const uint256& modifier) { // calculate sha256(sha256(proTxHash, confirmedHash), modifier) per MN @@ -86,7 +87,7 @@ uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_nullnHeight % llmqParams.dkgInterval == 0); const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - llmq::WORK_DIFF_DEPTH); - if (IsV20Active(pWorkBlockIndex)) { + if (DeploymentActiveAfter(pWorkBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) { // v20 is active: calculate modifier using the new way. auto cbcl = GetNonNullCoinbaseChainlock(pWorkBlockIndex); if (cbcl.has_value()) { @@ -105,7 +106,7 @@ uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_nullGetBlockHash())); } -std::vector CalculateScoresForQuorum(std::vector&& dmns, const uint256& modifier, const bool onlyEvoNodes) +std::vector CalculateScoresForQuorum(QuorumMembers&& dmns, const uint256& modifier, const bool onlyEvoNodes) { std::vector scores; scores.reserve(dmns.size()); @@ -139,7 +140,6 @@ std::vector CalculateScoresForQuorum(const CDeterministicMNList if (onlyEvoNodes && dmn->nType != MnType::Evo) { return; } - scores.emplace_back(calculateQuorumScore(dmn, modifier), dmn); }); return scores; @@ -149,8 +149,7 @@ std::vector CalculateScoresForQuorum(const CDeterministicMNList * Calculate a quorum based on the modifier. The resulting list is deterministically sorted by score */ template -std::vector CalculateQuorum(List&& mn_list, const uint256& modifier, size_t maxSize = 0, - const bool onlyEvoNodes = false) +QuorumMembers CalculateQuorum(List&& mn_list, const uint256& modifier, size_t maxSize = 0, const bool onlyEvoNodes = false) { auto scores = CalculateScoresForQuorum(std::forward(mn_list), modifier, onlyEvoNodes); @@ -170,7 +169,7 @@ std::vector CalculateQuorum(List&& mn_list, const uint256& scores.resize(maxSize); } - std::vector result; + QuorumMembers result; result.reserve(scores.size()); for (auto& [_, node] : scores) { result.emplace_back(std::move(node)); @@ -178,7 +177,7 @@ std::vector CalculateQuorum(List&& mn_list, const uint256& return result; } -std::vector> GetQuorumQuarterMembersBySnapshot( +std::vector GetQuorumQuarterMembersBySnapshot( const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight) { @@ -214,21 +213,14 @@ std::vector> GetQuorumQuarterMembersBySnapshot } if (LogAcceptDebug(BCLog::LLMQ)) { - std::stringstream ss; - ss << " ["; - for (const auto &m: sortedCombinedMns) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << "]"; - LogPrint(BCLog::LLMQ, "GetQuorumQuarterMembersBySnapshot h[%d] from[%d] sortedCombinedMns[%s]\n", - pCycleQuorumBaseBlockIndex->nHeight, nHeight, ss.str()); + LogPrint(BCLog::LLMQ, "%s h[%d] from[%d] sortedCombinedMns[%s]\n", __func__, pCycleQuorumBaseBlockIndex->nHeight, nHeight, ToString(sortedCombinedMns)); } size_t numQuorums = static_cast(llmqParams.signingActiveQuorumCount); size_t quorumSize = static_cast(llmqParams.size); auto quarterSize{quorumSize / 4}; - std::vector> quarterQuorumMembers(numQuorums); + std::vector quarterQuorumMembers(numQuorums); if (sortedCombinedMns.empty()) { return quarterQuorumMembers; @@ -286,10 +278,9 @@ std::vector> GetQuorumQuarterMembersBySnapshot } } -std::vector ComputeQuorumMembers(Consensus::LLMQType llmqType, const CDeterministicMNList& mn_list, - const CBlockIndex* pQuorumBaseBlockIndex) +QuorumMembers ComputeQuorumMembers(Consensus::LLMQType llmqType, const CDeterministicMNList& mn_list, const CBlockIndex* pQuorumBaseBlockIndex) { - bool EvoOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex); + bool EvoOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && DeploymentActiveAfter(pQuorumBaseBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19); const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); if (llmq_params_opt->useRotation || pQuorumBaseBlockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { @@ -337,7 +328,7 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDetermi } } -std::vector> BuildNewQuorumQuarterMembers( +std::vector BuildNewQuorumQuarterMembers( const Consensus::LLMQParams& llmqParams, llmq::CQuorumSnapshotManager& qsnapman, const CDeterministicMNList& allMns, const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters) { @@ -347,7 +338,7 @@ std::vector> BuildNewQuorumQuarterMembers( } size_t nQuorums = static_cast(llmqParams.signingActiveQuorumCount); - std::vector> quarterQuorumMembers{nQuorums}; + std::vector quarterQuorumMembers{nQuorums}; size_t quorumSize = static_cast(llmqParams.size); auto quarterSize{quorumSize / 4}; @@ -361,7 +352,7 @@ std::vector> BuildNewQuorumQuarterMembers( auto MnsUsedAtH = CDeterministicMNList(); std::vector MnsUsedAtHIndexed{nQuorums}; - bool skipRemovedMNs = IsV19Active(pCycleQuorumBaseBlockIndex) || (Params().NetworkIDString() == CBaseChainParams::TESTNET); + bool skipRemovedMNs = DeploymentActiveAfter(pCycleQuorumBaseBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19) || (Params().NetworkIDString() == CBaseChainParams::TESTNET); for (const size_t idx : irange::range(nQuorums)) { for (auto* prev_cycle : previousQuarters.GetCycles()) { @@ -400,14 +391,7 @@ std::vector> BuildNewQuorumQuarterMembers( } if (LogAcceptDebug(BCLog::LLMQ)) { - std::stringstream ss; - ss << " ["; - for (const auto &m: sortedCombinedMnsList) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << "]"; - LogPrint(BCLog::LLMQ, "BuildNewQuorumQuarterMembers h[%d] sortedCombinedMns[%s]\n", - pCycleQuorumBaseBlockIndex->nHeight, ss.str()); + LogPrint(BCLog::LLMQ, "%s h[%d] sortedCombinedMns[%s]\n", __func__, pCycleQuorumBaseBlockIndex->nHeight, ToString(sortedCombinedMnsList)); } std::vector skipList; @@ -444,7 +428,7 @@ std::vector> BuildNewQuorumQuarterMembers( // we made full "while" loop if (!updated) { // there are not enough MNs, there is nothing we can do here - return std::vector>(nQuorums); + return std::vector(nQuorums); } // reset and try again updated = false; @@ -461,8 +445,7 @@ std::vector> BuildNewQuorumQuarterMembers( return quarterQuorumMembers; } -std::vector> - ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const llmq::utils::UtilParameters& util_params) +std::vector ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const llmq::utils::UtilParameters& util_params) { const int cycleLength = llmqParams.dkgInterval; if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { @@ -499,39 +482,22 @@ std::vector> for (const size_t i : irange::range(nQuorums)) { std::stringstream ss; for (size_t idx = prev_cycles.size(); idx-- > 0;) { - ss << strprintf(" %dCmns[", idx); - for (const auto &m: prev_cycles[idx]->m_members[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << " ]"; - } - ss << " new["; - for (const auto &m: newQuarterMembers[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; + ss << strprintf(" %dCmns[%s]", idx, ToString(prev_cycles[idx]->m_members[i])); } - ss << " ]"; - LogPrint(BCLog::LLMQ, "QuarterComposition h[%d] i[%d]:%s\n", util_params.m_base_index->nHeight, i, - ss.str()); + ss << strprintf(" new[%s]", ToString(newQuarterMembers[i])); + LogPrint(BCLog::LLMQ, "QuarterComposition h[%d] i[%d]:%s\n", util_params.m_base_index->nHeight, i, ss.str()); } } - std::vector> quorumMembers(nQuorums); + std::vector quorumMembers(nQuorums); for (const size_t i : irange::range(nQuorums)) { // Move elements from previous quarters into quorumMembers for (auto* prev_cycle : prev_cycles | std::views::reverse) { std::move(prev_cycle->m_members[i].begin(), prev_cycle->m_members[i].end(), std::back_inserter(quorumMembers[i])); } std::move(newQuarterMembers[i].begin(), newQuarterMembers[i].end(), std::back_inserter(quorumMembers[i])); - if (LogAcceptDebug(BCLog::LLMQ)) { - std::stringstream ss; - ss << " ["; - for (const auto &m: quorumMembers[i]) { - ss << m->proTxHash.ToString().substr(0, 4) << "|"; - } - ss << "]"; - LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]:%s\n", util_params.m_base_index->nHeight, i, - ss.str()); + LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]: [%s]\n", util_params.m_base_index->nHeight, i, ToString(quorumMembers[i])); } } @@ -581,16 +547,17 @@ void BlsCheck::swap(BlsCheck& obj) std::swap(m_id_string, obj.m_id_string); } -std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParameters& util_params, bool reset_cache) +QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParameters& util_params, bool reset_cache) { static RecursiveMutex cs_members; - static std::map>> mapQuorumMembers GUARDED_BY( - cs_members); + static std::map> mapQuorumMembers GUARDED_BY(cs_members); static RecursiveMutex cs_indexed_members; - static std::map, std::vector, StaticSaltedHasher>> mapIndexedQuorumMembers GUARDED_BY(cs_indexed_members); + static std::map, QuorumMembers, StaticSaltedHasher>> mapIndexedQuorumMembers GUARDED_BY(cs_indexed_members); + if (!util_params.m_chainman.IsQuorumTypeEnabled(llmqType, util_params.m_base_index->pprev)) { return {}; } + std::vector quorumMembers; { LOCK(cs_members); @@ -650,7 +617,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy std::move(q[i])); } } else { - const CBlockIndex* pWorkBlockIndex = IsV20Active(util_params.m_base_index) + const CBlockIndex* pWorkBlockIndex = DeploymentActiveAfter(util_params.m_base_index, Params().GetConsensus(), Consensus::DEPLOYMENT_V20) ? util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - WORK_DIFF_DEPTH) : util_params.m_base_index.get(); CDeterministicMNList mn_list = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); From ff71875efb7d2d9fe12943e11b3be8aef143abab Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 21 Dec 2025 20:34:54 +0530 Subject: [PATCH 13/15] refactor: drop `Params()` use in `llmq/utils.cpp` --- src/evo/cbtx.cpp | 2 +- src/llmq/blockprocessor.cpp | 2 +- src/llmq/dkgsessionmgr.cpp | 2 +- src/llmq/quorums.cpp | 4 +-- src/llmq/utils.cpp | 63 ++++++++++++++++++------------------- src/llmq/utils.h | 5 ++- 6 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/evo/cbtx.cpp b/src/evo/cbtx.cpp index 8954ba5f63cc..b89f743834c9 100644 --- a/src/evo/cbtx.cpp +++ b/src/evo/cbtx.cpp @@ -72,7 +72,7 @@ auto CachedGetQcHashesQcIndexedHashes(const CBlockIndex* pindexPrev, const llmq: qcHashes_cached.clear(); qcIndexedHashes_cached.clear(); if (qc_hashes_cached.empty()) { - llmq::utils::InitQuorumsCache(qc_hashes_cached); + llmq::utils::InitQuorumsCache(qc_hashes_cached, Params().GetConsensus()); } for (const auto& [llmqType, vecBlockIndexes] : quorums) { diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index 98a6aac30c8c..538d75971080 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -52,7 +52,7 @@ CQuorumBlockProcessor::CQuorumBlockProcessor(CChainState& chainstate, CDetermini m_evoDb{evoDb}, m_qsnapman{qsnapman} { - utils::InitQuorumsCache(mapHasMinedCommitmentCache); + utils::InitQuorumsCache(mapHasMinedCommitmentCache, m_chainstate.m_chainman.GetConsensus()); LogPrintf("BLS verification uses %d additional threads\n", bls_threads); m_bls_queue.StartWorkerThreads(bls_threads); } diff --git a/src/llmq/dkgsessionmgr.cpp b/src/llmq/dkgsessionmgr.cpp index 7021490c94b1..7397c3ebe792 100644 --- a/src/llmq/dkgsessionmgr.cpp +++ b/src/llmq/dkgsessionmgr.cpp @@ -144,7 +144,7 @@ MessageProcessingResult CDKGSessionManager::ProcessMessage(CNode& pfrom, bool is { LOCK(cs_indexedQuorumsCache); if (indexedQuorumsCache.empty()) { - utils::InitQuorumsCache(indexedQuorumsCache); + utils::InitQuorumsCache(indexedQuorumsCache, m_chainman.GetConsensus()); } indexedQuorumsCache[llmqType].get(quorumHash, quorumIndex); } diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index a55da096d464..3d07ea9b20c5 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -226,7 +226,7 @@ CQuorumManager::CQuorumManager(CBLSWorker& _blsWorker, CDeterministicMNManager& m_quorums_watch{quorums_watch}, db{util::MakeDbWrapper({db_params.path / "llmq" / "quorumdb", db_params.memory, db_params.wipe, /*cache_size=*/1 << 20})} { - utils::InitQuorumsCache(mapQuorumsCache, false); + utils::InitQuorumsCache(mapQuorumsCache, m_chainman.GetConsensus(), /*limit_by_connections=*/false); quorumThreadInterrupt.reset(); MigrateOldQuorumDB(_evoDb); } @@ -1114,7 +1114,7 @@ void CQuorumManager::StartCleanupOldQuorumDataThread(gsl::not_null dbKeysToSkip; if (LOCK(cs_cleanup); cleanupQuorumsCache.empty()) { - utils::InitQuorumsCache(cleanupQuorumsCache, false); + utils::InitQuorumsCache(cleanupQuorumsCache, m_chainman.GetConsensus(), /*limit_by_connections=*/false); } for (const auto& params : Params().GetConsensus().llmqs) { if (quorumThreadInterrupt) { diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index c300cc73f045..4d903e106c9e 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -82,12 +82,13 @@ arith_uint256 calculateQuorumScore(const CDeterministicMNCPtr& dmn, const uint25 return UintToArith256(h); } -uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex) +uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, const Consensus::Params& consensus_params, + gsl::not_null pCycleQuorumBaseBlockIndex) { ASSERT_IF_DEBUG(pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval == 0); const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - llmq::WORK_DIFF_DEPTH); - if (DeploymentActiveAfter(pWorkBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) { + if (DeploymentActiveAfter(pWorkBlockIndex, consensus_params, Consensus::DEPLOYMENT_V20)) { // v20 is active: calculate modifier using the new way. auto cbcl = GetNonNullCoinbaseChainlock(pWorkBlockIndex); if (cbcl.has_value()) { @@ -178,7 +179,7 @@ QuorumMembers CalculateQuorum(List&& mn_list, const uint256& modifier, size_t ma } std::vector GetQuorumQuarterMembersBySnapshot( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, + const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const Consensus::Params& consensus_params, const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight) { if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { @@ -191,7 +192,7 @@ std::vector GetQuorumQuarterMembersBySnapshot( const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor( pCycleQuorumBaseBlockIndex->nHeight - llmq::WORK_DIFF_DEPTH); auto mn_list = dmnman.GetListForBlock(pWorkBlockIndex); - const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmqParams, consensus_params, pCycleQuorumBaseBlockIndex); auto sortedAllMns = CalculateQuorum(mn_list, modifier); std::vector usedMNs; @@ -278,24 +279,24 @@ std::vector GetQuorumQuarterMembersBySnapshot( } } -QuorumMembers ComputeQuorumMembers(Consensus::LLMQType llmqType, const CDeterministicMNList& mn_list, const CBlockIndex* pQuorumBaseBlockIndex) +QuorumMembers ComputeQuorumMembers(Consensus::LLMQType llmqType, const CChainParams& chainparams, + const CDeterministicMNList& mn_list, const CBlockIndex* pQuorumBaseBlockIndex) { - bool EvoOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && DeploymentActiveAfter(pQuorumBaseBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19); - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + bool EvoOnly = (chainparams.GetConsensus().llmqTypePlatform == llmqType) && DeploymentActiveAfter(pQuorumBaseBlockIndex, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V19); + const auto& llmq_params_opt = chainparams.GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); if (llmq_params_opt->useRotation || pQuorumBaseBlockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { ASSERT_IF_DEBUG(false); return {}; } - const auto modifier = GetHashModifier(llmq_params_opt.value(), pQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmq_params_opt.value(), chainparams.GetConsensus(), pQuorumBaseBlockIndex); return CalculateQuorum(mn_list, modifier, llmq_params_opt->size, EvoOnly); } -void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, +void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensus::Params& consensus_params, const CDeterministicMNList& allMns, const CDeterministicMNList& mnUsedAtH, std::vector& sortedCombinedMns, - llmq::CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, - const CBlockIndex* pCycleQuorumBaseBlockIndex) + llmq::CQuorumSnapshot& quorumSnapshot, std::vector& skipList, const CBlockIndex* pCycleQuorumBaseBlockIndex) { if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); @@ -303,7 +304,7 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDetermi } quorumSnapshot.activeQuorumMembers.resize(allMns.GetAllMNsCount()); - const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmqParams, consensus_params, pCycleQuorumBaseBlockIndex); auto sortedAllMns = CalculateQuorum(allMns, modifier); LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pCycleQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); @@ -328,11 +329,10 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDetermi } } -std::vector BuildNewQuorumQuarterMembers( - const Consensus::LLMQParams& llmqParams, llmq::CQuorumSnapshotManager& qsnapman, const CDeterministicMNList& allMns, - const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters) +std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const llmq::utils::UtilParameters& util_params, + const CDeterministicMNList& allMns, const PreviousQuorumQuarters& previousQuarters) { - if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { + if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); return {}; } @@ -342,8 +342,7 @@ std::vector BuildNewQuorumQuarterMembers( size_t quorumSize = static_cast(llmqParams.size); auto quarterSize{quorumSize / 4}; - const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex); - + const auto modifier = GetHashModifier(llmqParams, util_params.m_chainman.GetConsensus(), util_params.m_base_index); if (allMns.GetValidMNsCount() < quarterSize) { return quarterQuorumMembers; @@ -352,7 +351,7 @@ std::vector BuildNewQuorumQuarterMembers( auto MnsUsedAtH = CDeterministicMNList(); std::vector MnsUsedAtHIndexed{nQuorums}; - bool skipRemovedMNs = DeploymentActiveAfter(pCycleQuorumBaseBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19) || (Params().NetworkIDString() == CBaseChainParams::TESTNET); + bool skipRemovedMNs = DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V19) || (util_params.m_chainman.GetParams().NetworkIDString() == CBaseChainParams::TESTNET); for (const size_t idx : irange::range(nQuorums)) { for (auto* prev_cycle : previousQuarters.GetCycles()) { @@ -391,7 +390,7 @@ std::vector BuildNewQuorumQuarterMembers( } if (LogAcceptDebug(BCLog::LLMQ)) { - LogPrint(BCLog::LLMQ, "%s h[%d] sortedCombinedMns[%s]\n", __func__, pCycleQuorumBaseBlockIndex->nHeight, ToString(sortedCombinedMnsList)); + LogPrint(BCLog::LLMQ, "%s h[%d] sortedCombinedMns[%s]\n", __func__, util_params.m_base_index->nHeight, ToString(sortedCombinedMnsList)); } std::vector skipList; @@ -436,11 +435,9 @@ std::vector BuildNewQuorumQuarterMembers( } } - llmq::CQuorumSnapshot quorumSnapshot = {}; - - BuildQuorumSnapshot(llmqParams, allMns, MnsUsedAtH, sortedCombinedMnsList, quorumSnapshot, pCycleQuorumBaseBlockIndex->nHeight, skipList, pCycleQuorumBaseBlockIndex); - - qsnapman.StoreSnapshotForBlock(llmqParams.type, pCycleQuorumBaseBlockIndex, quorumSnapshot); + llmq::CQuorumSnapshot quorumSnapshot{}; + BuildQuorumSnapshot(llmqParams, util_params.m_chainman.GetConsensus(), allMns, MnsUsedAtH, sortedCombinedMnsList, quorumSnapshot, skipList, util_params.m_base_index); + util_params.m_qsnapman.StoreSnapshotForBlock(llmqParams.type, util_params.m_base_index, quorumSnapshot); return quarterQuorumMembers; } @@ -470,11 +467,11 @@ std::vector ComputeQuorumMembersByQuarterRotation(const Consensus // assert(false); break; } - prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, util_params.m_dmnman, prev_cycles[idx]->m_cycle_index, - prev_cycles[idx]->m_snap, util_params.m_base_index->nHeight); + prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, util_params.m_dmnman, util_params.m_chainman.GetConsensus(), + prev_cycles[idx]->m_cycle_index, prev_cycles[idx]->m_snap, util_params.m_base_index->nHeight); } - auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, util_params.m_qsnapman, allMns, util_params.m_base_index, previousQuarters); + auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, util_params, allMns, previousQuarters); // TODO: Check if it is triggered from outside (P2P, block validation) and maybe throw an exception // assert (!newQuarterMembers.empty()); @@ -562,7 +559,7 @@ QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParame { LOCK(cs_members); if (mapQuorumMembers.empty()) { - InitQuorumsCache(mapQuorumMembers); + InitQuorumsCache(mapQuorumMembers, util_params.m_chainman.GetConsensus()); } if (reset_cache) { mapQuorumMembers[llmqType].clear(); @@ -571,13 +568,13 @@ QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParame } } - const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + const auto& llmq_params_opt = util_params.m_chainman.GetParams().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); const auto& llmq_params = llmq_params_opt.value(); if (IsQuorumRotationEnabled(llmq_params, util_params.m_base_index)) { if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) { - InitQuorumsCache(mapIndexedQuorumMembers); + InitQuorumsCache(mapIndexedQuorumMembers, util_params.m_chainman.GetConsensus()); } /* * Quorums created with rotation are now created in a different way. All signingActiveQuorumCount are created during the period of dkgInterval. @@ -617,11 +614,11 @@ QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParame std::move(q[i])); } } else { - const CBlockIndex* pWorkBlockIndex = DeploymentActiveAfter(util_params.m_base_index, Params().GetConsensus(), Consensus::DEPLOYMENT_V20) + const CBlockIndex* pWorkBlockIndex = DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V20) ? util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - WORK_DIFF_DEPTH) : util_params.m_base_index.get(); CDeterministicMNList mn_list = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); - quorumMembers = ComputeQuorumMembers(llmqType, mn_list, util_params.m_base_index); + quorumMembers = ComputeQuorumMembers(llmqType, util_params.m_chainman.GetParams(), mn_list, util_params.m_base_index); } LOCK(cs_members); diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 02c976388328..3a16126b7fa1 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -21,7 +21,6 @@ class CBlockIndex; class CConnman; -class CDeterministicMN; class CDeterministicMNList; class CDeterministicMNManager; class ChainstateManager; @@ -83,9 +82,9 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman const CDeterministicMNList& tip_mn_list, const uint256& myProTxHash); template -inline void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true) +inline void InitQuorumsCache(CacheType& cache, const Consensus::Params& consensus_params, bool limit_by_connections = true) { - for (const auto& llmq : Params().GetConsensus().llmqs) { + for (const auto& llmq : consensus_params.llmqs) { cache.emplace(std::piecewise_construct, std::forward_as_tuple(llmq.type), std::forward_as_tuple(limit_by_connections ? llmq.keepOldConnections : llmq.keepOldKeys)); } From 3ba6daacf968bbc8cfd67146d7abce86e85965fe Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 22 Dec 2025 17:24:38 +0530 Subject: [PATCH 14/15] refactor: use `UtilParameters` in more LLMQ code --- src/evo/specialtxman.cpp | 2 +- src/llmq/blockprocessor.cpp | 6 ++--- src/llmq/commitment.cpp | 50 ++++++++++++++++--------------------- src/llmq/commitment.h | 15 +++++------ src/llmq/dkgsession.cpp | 4 +-- src/llmq/utils.cpp | 4 +-- src/llmq/utils.h | 20 +++++++-------- 7 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 0135292c83c6..a7da7e704a98 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -130,7 +130,7 @@ static bool CheckSpecialTxInner(CDeterministicMNManager& dmnman, llmq::CQuorumSn } } case TRANSACTION_QUORUM_COMMITMENT: - return llmq::CheckLLMQCommitment(dmnman, qsnapman, chainman, tx, pindexPrev, state); + return llmq::CheckLLMQCommitment({dmnman, qsnapman, chainman, pindexPrev}, tx, state); case TRANSACTION_MNHF_SIGNAL: return CheckMNHFTx(chainman, qman, tx, pindexPrev, state); case TRANSACTION_ASSET_LOCK: diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index 538d75971080..86b9617ff004 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -145,7 +145,7 @@ MessageProcessingResult CQuorumBlockProcessor::ProcessMessage(const CNode& peer, } } - if (!qc.Verify(m_dmnman, m_qsnapman, m_chainstate.m_chainman, pQuorumBaseBlockIndex, /*checkSigs=*/true)) { + if (!qc.Verify({m_dmnman, m_qsnapman, m_chainstate.m_chainman, pQuorumBaseBlockIndex}, /*checkSigs=*/true)) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- commitment for quorum %s:%d is not valid quorumIndex[%d] nversion[%d], peer=%d\n", __func__, qc.quorumHash.ToString(), ToUnderlying(qc.llmqType), qc.quorumIndex, qc.nVersion, peer.GetId()); @@ -215,7 +215,7 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, gsl::not_nullnHeight, qc.quorumHash.ToString()); return false; } - qc.VerifySignatureAsync(m_dmnman, m_qsnapman, m_chainstate.m_chainman, pQuorumBaseBlockIndex, &queue_control); + qc.VerifySignatureAsync({m_dmnman, m_qsnapman, m_chainstate.m_chainman, pQuorumBaseBlockIndex}, &queue_control); } if (!queue_control.Wait()) { @@ -337,7 +337,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH } // we don't validate signatures here; they already validated on previous step - if (!qc.Verify(m_dmnman, m_qsnapman, m_chainstate.m_chainman, pQuorumBaseBlockIndex, /*checksigs=*/false)) { + if (!qc.Verify({m_dmnman, m_qsnapman, m_chainstate.m_chainman, pQuorumBaseBlockIndex}, /*checksigs=*/false)) { LogPrint(BCLog::LLMQ, /* Continued */ "%s -- height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, " "quorumPublicKey=%s qc verify failed.\n", diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 64866e62d8b9..57fde1cc4dea 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -28,12 +28,9 @@ CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const ui { } -bool CFinalCommitment::VerifySignatureAsync(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, - CCheckQueueControl* queue_control) const +bool CFinalCommitment::VerifySignatureAsync(const llmq::UtilParameters& util_params, CCheckQueueControl* queue_control) const { - auto members = utils::GetAllQuorumMembers(llmqType, {dmnman, qsnapman, chainman, pQuorumBaseBlockIndex}); + auto members = utils::GetAllQuorumMembers(llmqType, util_params); const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid llmqType=%d\n", quorumHash.ToString(), @@ -96,9 +93,7 @@ bool CFinalCommitment::VerifySignatureAsync(CDeterministicMNManager& dmnman, CQu } -bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, bool checkSigs) const +bool CFinalCommitment::Verify(const llmq::UtilParameters& util_params, bool checkSigs) const { const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { @@ -107,19 +102,19 @@ bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotMa } const auto& llmq_params = llmq_params_opt.value(); - const uint16_t expected_nversion{CFinalCommitment::GetVersion(IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex), - DeploymentActiveAfter(pQuorumBaseBlockIndex, chainman.GetConsensus(), Consensus::DEPLOYMENT_V19))}; + const uint16_t expected_nversion{CFinalCommitment::GetVersion(IsQuorumRotationEnabled(llmq_params, util_params.m_base_index), + DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V19))}; if (nVersion == 0 || nVersion != expected_nversion) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid nVersion=%d expected=%d\n", quorumHash.ToString(), nVersion, expected_nversion); return false; } - if (pQuorumBaseBlockIndex->GetBlockHash() != quorumHash) { + if (util_params.m_base_index->GetBlockHash() != quorumHash) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid quorumHash\n", quorumHash.ToString()); return false; } - if ((pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval) != quorumIndex) { + if ((util_params.m_base_index->nHeight % llmq_params.dkgInterval) != quorumIndex) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid quorumIndex=%d\n", quorumHash.ToString(), quorumIndex); return false; } @@ -152,7 +147,7 @@ bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotMa LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid vvecSig\n", quorumHash.ToString()); return false; } - auto members = utils::GetAllQuorumMembers(llmqType, {dmnman, qsnapman, chainman, pQuorumBaseBlockIndex}); + auto members = utils::GetAllQuorumMembers(llmqType, util_params); if (LogAcceptDebug(BCLog::LLMQ)) { std::stringstream ss; std::stringstream ss2; @@ -176,7 +171,7 @@ bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotMa // sigs are only checked when the block is processed if (checkSigs) { - if (!VerifySignatureAsync(dmnman, qsnapman, chainman, pQuorumBaseBlockIndex, nullptr)) { + if (!VerifySignatureAsync(util_params, /*queue_control=*/nullptr)) { return false; } } @@ -215,20 +210,18 @@ bool CFinalCommitment::VerifySizes(const Consensus::LLMQParams& params) const return true; } -bool CheckLLMQCommitment(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, const CTransaction& tx, - gsl::not_null pindexPrev, TxValidationState& state) +bool CheckLLMQCommitment(const llmq::UtilParameters& util_params, const CTransaction& tx, TxValidationState& state) { const auto opt_qcTx = GetTxPayload(tx); if (!opt_qcTx) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetTxPayload LLMQCommitment failed\n", pindexPrev->nHeight); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetTxPayload LLMQCommitment failed\n", util_params.m_base_index->nHeight); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-payload"); } auto& qcTx = *opt_qcTx; const auto& llmq_params_opt = Params().GetLLMQ(qcTx.commitment.llmqType); if (!llmq_params_opt.has_value()) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetLLMQ failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType)); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetLLMQ failed for llmqType[%d]\n", util_params.m_base_index->nHeight, ToUnderlying(qcTx.commitment.llmqType)); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-commitment-type"); } @@ -242,40 +235,39 @@ bool CheckLLMQCommitment(CDeterministicMNManager& dmnman, CQuorumSnapshotManager } if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nVersion[%d]\n", pindexPrev->nHeight, qcTx.nVersion); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nVersion[%d]\n", util_params.m_base_index->nHeight, qcTx.nVersion); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-version"); } - if (qcTx.nHeight != uint32_t(pindexPrev->nHeight + 1)) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nHeight[%d]\n", pindexPrev->nHeight, qcTx.nHeight); + if (qcTx.nHeight != uint32_t(util_params.m_base_index->nHeight + 1)) { + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nHeight[%d]\n", util_params.m_base_index->nHeight, qcTx.nHeight); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-height"); } - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); + const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main, return util_params.m_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); if (pQuorumBaseBlockIndex == nullptr) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash"); } - - if (pQuorumBaseBlockIndex != pindexPrev->GetAncestor(pQuorumBaseBlockIndex->nHeight)) { + if (pQuorumBaseBlockIndex != util_params.m_base_index->GetAncestor(pQuorumBaseBlockIndex->nHeight)) { // not part of active chain return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash"); } if (qcTx.commitment.IsNull()) { if (!qcTx.commitment.VerifyNull()) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", util_params.m_base_index->nHeight, qcTx.commitment.quorumHash.ToString()); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid-null"); } return true; } - if (!qcTx.commitment.Verify(dmnman, qsnapman, chainman, pQuorumBaseBlockIndex, false)) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] Verify failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); + if (!qcTx.commitment.Verify(util_params.replace_index(pQuorumBaseBlockIndex), false)) { + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] Verify failed\n", util_params.m_base_index->nHeight, qcTx.commitment.quorumHash.ToString()); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid"); } - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] CheckLLMQCommitment VALID\n", pindexPrev->nHeight); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] CheckLLMQCommitment VALID\n", util_params.m_base_index->nHeight); return true; } diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index aaf0a63d507a..846db0d9c52f 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -30,13 +30,15 @@ class TxValidationState; template class CCheckQueueControl; struct RPCResult; - namespace llmq { class CQuorumSnapshotManager; +struct UtilParameters; namespace utils { struct BlsCheck; } // namespace utils +} // namespace llmq +namespace llmq { // This message is an aggregation of all received premature commitments and only valid if // enough (>=threshold) premature commitments were aggregated // This is mined on-chain as part of TRANSACTION_QUORUM_COMMITMENT @@ -74,11 +76,8 @@ class CFinalCommitment return int(std::count(validMembers.begin(), validMembers.end(), true)); } - bool VerifySignatureAsync(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, gsl::not_null pQuorumBaseBlockIndex, - CCheckQueueControl* queue_control) const; - bool Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - gsl::not_null pQuorumBaseBlockIndex, bool checkSigs) const; + bool VerifySignatureAsync(const llmq::UtilParameters& util_params, CCheckQueueControl* queue_control) const; + bool Verify(const llmq::UtilParameters& util_params, bool checkSigs) const; bool VerifyNull() const; bool VerifySizes(const Consensus::LLMQParams& params) const; @@ -164,9 +163,7 @@ class CFinalCommitmentTxPayload [[nodiscard]] UniValue ToJson() const; }; -bool CheckLLMQCommitment(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, const CTransaction& tx, - gsl::not_null pindexPrev, TxValidationState& state); +bool CheckLLMQCommitment(const llmq::UtilParameters& util_params, const CTransaction& tx, TxValidationState& state); uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash); diff --git a/src/llmq/dkgsession.cpp b/src/llmq/dkgsession.cpp index 53497fc40b91..77725529fd8d 100644 --- a/src/llmq/dkgsession.cpp +++ b/src/llmq/dkgsession.cpp @@ -1280,7 +1280,7 @@ std::vector CDKGSession::FinalizeCommitments() t2.stop(); cxxtimer::Timer t3(true); - if (!fqc.Verify(m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index, true)) { + if (!fqc.Verify({m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index}, true)) { logger.Batch("failed to verify final commitment"); continue; } @@ -1343,7 +1343,7 @@ CFinalCommitment CDKGSession::FinalizeSingleCommitment() fqc.quorumSig = fqc.membersSig; } - if (!fqc.Verify(m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index, true)) { + if (!fqc.Verify({m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index}, true)) { logger.Batch("failed to verify final commitment"); assert(false); } diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 4d903e106c9e..733850fb6489 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -329,7 +329,7 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensu } } -std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const llmq::utils::UtilParameters& util_params, +std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const llmq::UtilParameters& util_params, const CDeterministicMNList& allMns, const PreviousQuorumQuarters& previousQuarters) { if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { @@ -442,7 +442,7 @@ std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQPar return quarterQuorumMembers; } -std::vector ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const llmq::utils::UtilParameters& util_params) +std::vector ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const llmq::UtilParameters& util_params) { const int cycleLength = llmqParams.dkgInterval; if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 3a16126b7fa1..233e7abfe11b 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -31,6 +31,16 @@ class CQuorumSnapshotManager; } // namespace llmq namespace llmq { +struct UtilParameters { + CDeterministicMNManager& m_dmnman; + CQuorumSnapshotManager& m_qsnapman; + const ChainstateManager& m_chainman; + gsl::not_null m_base_index; + +public: + UtilParameters replace_index(gsl::not_null base_index) const { return {m_dmnman, m_qsnapman, m_chainman, base_index}; } +}; + namespace utils { struct BlsCheck { CBLSSignature m_sig; @@ -53,16 +63,6 @@ std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, gsl::not_null pQuorumBaseBlockIndex, size_t memberCount, size_t connectionCount); -struct UtilParameters { - CDeterministicMNManager& m_dmnman; - CQuorumSnapshotManager& m_qsnapman; - const ChainstateManager& m_chainman; - gsl::not_null m_base_index; - -public: - UtilParameters replace_index(gsl::not_null base_index) const { return {m_dmnman, m_qsnapman, m_chainman, base_index}; } -}; - // includes members which failed DKG std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParameters& util_params, bool reset_cache = false); From 7c1dc2d8f7d68167dbc0c5b478364112bb886b1f Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:53:28 +0530 Subject: [PATCH 15/15] lint: apply most `clang-format` suggestions --- src/evo/specialtxman.cpp | 4 +- src/llmq/commitment.cpp | 30 +++-- src/llmq/commitment.h | 3 +- src/llmq/snapshot.cpp | 33 +++-- src/llmq/utils.cpp | 218 ++++++++++++++++++------------- src/llmq/utils.h | 5 +- src/rpc/quorums.cpp | 13 +- src/test/llmq_snapshot_tests.cpp | 3 +- 8 files changed, 182 insertions(+), 127 deletions(-) diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index a7da7e704a98..8d3c317dc815 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -442,7 +442,9 @@ bool CSpecialTxProcessor::RebuildListFromBlock(const CBlock& block, gsl::not_nul // The commitment has already been validated at this point, so it's safe to use members of it - const auto members = llmq::utils::GetAllQuorumMembers(opt_qc->commitment.llmqType, {m_dmnman, m_qsnapman, m_chainman, pQuorumBaseBlockIndex}); + const auto members = llmq::utils::GetAllQuorumMembers(opt_qc->commitment.llmqType, + {m_dmnman, m_qsnapman, m_chainman, + pQuorumBaseBlockIndex}); HandleQuorumCommitment(opt_qc->commitment, members, debugLogs, newList); } } diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 57fde1cc4dea..7ee08a9fbd5d 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -28,7 +28,8 @@ CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const ui { } -bool CFinalCommitment::VerifySignatureAsync(const llmq::UtilParameters& util_params, CCheckQueueControl* queue_control) const +bool CFinalCommitment::VerifySignatureAsync(const llmq::UtilParameters& util_params, + CCheckQueueControl* queue_control) const { auto members = utils::GetAllQuorumMembers(llmqType, util_params); const auto& llmq_params_opt = Params().GetLLMQ(llmqType); @@ -102,8 +103,10 @@ bool CFinalCommitment::Verify(const llmq::UtilParameters& util_params, bool chec } const auto& llmq_params = llmq_params_opt.value(); - const uint16_t expected_nversion{CFinalCommitment::GetVersion(IsQuorumRotationEnabled(llmq_params, util_params.m_base_index), - DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V19))}; + const uint16_t expected_nversion{ + CFinalCommitment::GetVersion(IsQuorumRotationEnabled(llmq_params, util_params.m_base_index), + DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), + Consensus::DEPLOYMENT_V19))}; if (nVersion == 0 || nVersion != expected_nversion) { LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid nVersion=%d expected=%d\n", quorumHash.ToString(), nVersion, expected_nversion); return false; @@ -214,14 +217,16 @@ bool CheckLLMQCommitment(const llmq::UtilParameters& util_params, const CTransac { const auto opt_qcTx = GetTxPayload(tx); if (!opt_qcTx) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetTxPayload LLMQCommitment failed\n", util_params.m_base_index->nHeight); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetTxPayload LLMQCommitment failed\n", + util_params.m_base_index->nHeight); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-payload"); } auto& qcTx = *opt_qcTx; const auto& llmq_params_opt = Params().GetLLMQ(qcTx.commitment.llmqType); if (!llmq_params_opt.has_value()) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetLLMQ failed for llmqType[%d]\n", util_params.m_base_index->nHeight, ToUnderlying(qcTx.commitment.llmqType)); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] GetLLMQ failed for llmqType[%d]\n", + util_params.m_base_index->nHeight, ToUnderlying(qcTx.commitment.llmqType)); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-commitment-type"); } @@ -235,16 +240,19 @@ bool CheckLLMQCommitment(const llmq::UtilParameters& util_params, const CTransac } if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nVersion[%d]\n", util_params.m_base_index->nHeight, qcTx.nVersion); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nVersion[%d]\n", + util_params.m_base_index->nHeight, qcTx.nVersion); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-version"); } if (qcTx.nHeight != uint32_t(util_params.m_base_index->nHeight + 1)) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nHeight[%d]\n", util_params.m_base_index->nHeight, qcTx.nHeight); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.nHeight[%d]\n", util_params.m_base_index->nHeight, + qcTx.nHeight); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-height"); } - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main, return util_params.m_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); + const CBlockIndex* pQuorumBaseBlockIndex = + WITH_LOCK(::cs_main, return util_params.m_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); if (pQuorumBaseBlockIndex == nullptr) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-quorum-hash"); } @@ -256,14 +264,16 @@ bool CheckLLMQCommitment(const llmq::UtilParameters& util_params, const CTransac if (qcTx.commitment.IsNull()) { if (!qcTx.commitment.VerifyNull()) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", util_params.m_base_index->nHeight, qcTx.commitment.quorumHash.ToString()); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", + util_params.m_base_index->nHeight, qcTx.commitment.quorumHash.ToString()); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid-null"); } return true; } if (!qcTx.commitment.Verify(util_params.replace_index(pQuorumBaseBlockIndex), false)) { - LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] Verify failed\n", util_params.m_base_index->nHeight, qcTx.commitment.quorumHash.ToString()); + LogPrint(BCLog::LLMQ, "CFinalCommitment -- h[%d] invalid qcTx.commitment[%s] Verify failed\n", + util_params.m_base_index->nHeight, qcTx.commitment.quorumHash.ToString()); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-invalid"); } diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 846db0d9c52f..3a8337b62746 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -76,7 +76,8 @@ class CFinalCommitment return int(std::count(validMembers.begin(), validMembers.end(), true)); } - bool VerifySignatureAsync(const llmq::UtilParameters& util_params, CCheckQueueControl* queue_control) const; + bool VerifySignatureAsync(const llmq::UtilParameters& util_params, + CCheckQueueControl* queue_control) const; bool Verify(const llmq::UtilParameters& util_params, bool checkSigs) const; bool VerifyNull() const; bool VerifySizes(const Consensus::LLMQParams& params) const; diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 8ce488a3bb18..81043f98729d 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -18,9 +18,9 @@ namespace { constexpr std::string_view DB_QUORUM_SNAPSHOT{"llmq_S"}; //! Constructs a llmq::CycleData and populate it with metadata -std::optional ConstructCycle(llmq::CQuorumSnapshotManager& qsnapman, const Consensus::LLMQType& llmq_type, - bool skip_snap, int32_t height, gsl::not_null index_tip, - std::string& error) +std::optional ConstructCycle(llmq::CQuorumSnapshotManager& qsnapman, + const Consensus::LLMQType& llmq_type, bool skip_snap, int32_t height, + gsl::not_null index_tip, std::string& error) { llmq::CycleData ret; ret.m_cycle_index = index_tip->GetAncestor(height); @@ -108,14 +108,17 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan const int cycleLength = llmq_params_opt->dkgInterval; - auto cycle_base_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/true, /*height=*/blockIndex->nHeight - (blockIndex->nHeight % cycleLength), blockIndex, errorRet); + auto cycle_base_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/true, + /*height=*/blockIndex->nHeight - (blockIndex->nHeight % cycleLength), + blockIndex, errorRet); if (!cycle_base_opt.has_value()) { return false; } if (use_legacy_construction) { // Build MN list Diff always with highest baseblock if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, cycle_base_opt->m_work_index, use_legacy_construction), + GetLastBaseBlockHash(baseBlockIndexes, cycle_base_opt->m_work_index, + use_legacy_construction), cycle_base_opt->m_work_index->GetBlockHash(), response.mnListDiffH, errorRet)) { return false; } @@ -125,13 +128,16 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan auto target_cycles{response.GetCycles()}; for (size_t idx{0}; idx < target_cycles.size(); idx++) { - auto cycle_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/false, /*height=*/cycle_base_opt->m_cycle_index->nHeight - (cycleLength * (idx + 1)), tipBlockIndex, errorRet); + auto cycle_opt = ConstructCycle(qsnapman, llmqType, /*skip_snap=*/false, + /*height=*/cycle_base_opt->m_cycle_index->nHeight - (cycleLength * (idx + 1)), + tipBlockIndex, errorRet); if (!cycle_opt.has_value()) { return false; } if (use_legacy_construction) { if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, cycle_opt->m_work_index, use_legacy_construction), + GetLastBaseBlockHash(baseBlockIndexes, cycle_opt->m_work_index, + use_legacy_construction), cycle_opt->m_work_index->GetBlockHash(), cycle_opt->m_diff, errorRet)) { return false; } @@ -165,7 +171,8 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan response.quorumSnapshotList.push_back(cycle_opt->m_snap); CSimplifiedMNListDiff mnhneeded; if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, cycle_opt->m_work_index, use_legacy_construction), + GetLastBaseBlockHash(baseBlockIndexes, cycle_opt->m_work_index, + use_legacy_construction), cycle_opt->m_work_index->GetBlockHash(), mnhneeded, errorRet)) { return false; } @@ -179,16 +186,17 @@ bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotMan for (size_t idx = target_cycles.size(); idx-- > 0;) { auto* cycle{target_cycles[idx]}; if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, cycle->m_work_index, use_legacy_construction), - cycle->m_work_index->GetBlockHash(), cycle->m_diff, errorRet)) - { + GetLastBaseBlockHash(baseBlockIndexes, cycle->m_work_index, + use_legacy_construction), + cycle->m_work_index->GetBlockHash(), cycle->m_diff, errorRet)) { return false; } baseBlockIndexes.push_back(cycle->m_work_index); } if (!BuildSimplifiedMNListDiff(dmnman, chainman, qblockman, qman, - GetLastBaseBlockHash(baseBlockIndexes, cycle_base_opt->m_work_index, use_legacy_construction), + GetLastBaseBlockHash(baseBlockIndexes, cycle_base_opt->m_work_index, + use_legacy_construction), cycle_base_opt->m_work_index->GetBlockHash(), response.mnListDiffH, errorRet)) { return false; } @@ -282,5 +290,4 @@ void CQuorumSnapshotManager::StoreSnapshotForBlock(const Consensus::LLMQType llm m_evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_SNAPSHOT, snapshotHash), snapshot); quorumSnapshotCache.insert(snapshotHash, snapshot); } - } // namespace llmq diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 733850fb6489..71720b6a3ba1 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -64,7 +64,10 @@ struct PreviousQuorumQuarters { explicit PreviousQuorumQuarters(size_t s) : quarterHMinusC(s), quarterHMinus2C(s), quarterHMinus3C(s) {} std::vector GetCycles() { return {&quarterHMinusC, &quarterHMinus2C, &quarterHMinus3C}; } - std::vector GetCycles() const { return {&quarterHMinusC, &quarterHMinus2C, &quarterHMinus3C}; } + std::vector GetCycles() const + { + return {&quarterHMinusC, &quarterHMinus2C, &quarterHMinus3C}; + } }; arith_uint256 calculateQuorumScore(const CDeterministicMNCPtr& dmn, const uint256& modifier) @@ -127,7 +130,8 @@ std::vector CalculateScoresForQuorum(QuorumMembers&& dmns, cons return scores; } -std::vector CalculateScoresForQuorum(const CDeterministicMNList& mn_list, const uint256& modifier, const bool onlyEvoNodes) +std::vector CalculateScoresForQuorum(const CDeterministicMNList& mn_list, const uint256& modifier, + const bool onlyEvoNodes) { std::vector scores; scores.reserve(mn_list.GetAllMNsCount()); @@ -155,15 +159,14 @@ QuorumMembers CalculateQuorum(List&& mn_list, const uint256& modifier, size_t ma auto scores = CalculateScoresForQuorum(std::forward(mn_list), modifier, onlyEvoNodes); // sort is descending order - std::sort(scores.rbegin(), scores.rend(), - [](const MasternodeScore& a, const MasternodeScore& b) { - if (a.m_score == b.m_score) { - // this should actually never happen, but we should stay compatible with how the non-deterministic MNs did the sorting - // TODO - add assert ? - return a.m_node->collateralOutpoint < b.m_node->collateralOutpoint; - } - return a.m_score < b.m_score; - }); + std::sort(scores.rbegin(), scores.rend(), [](const MasternodeScore& a, const MasternodeScore& b) { + if (a.m_score == b.m_score) { + // this should actually never happen, but we should stay compatible with how the non-deterministic MNs did the sorting + // TODO - add assert ? + return a.m_node->collateralOutpoint < b.m_node->collateralOutpoint; + } + return a.m_score < b.m_score; + }); // return top maxSize entries only (if specified) if (maxSize > 0 && scores.size() > maxSize) { @@ -178,9 +181,11 @@ QuorumMembers CalculateQuorum(List&& mn_list, const uint256& modifier, size_t ma return result; } -std::vector GetQuorumQuarterMembersBySnapshot( - const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const Consensus::Params& consensus_params, - const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight) +std::vector GetQuorumQuarterMembersBySnapshot(const Consensus::LLMQParams& llmqParams, + CDeterministicMNManager& dmnman, + const Consensus::Params& consensus_params, + const CBlockIndex* pCycleQuorumBaseBlockIndex, + const llmq::CQuorumSnapshot& snapshot, int nHeight) { if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); @@ -214,7 +219,8 @@ std::vector GetQuorumQuarterMembersBySnapshot( } if (LogAcceptDebug(BCLog::LLMQ)) { - LogPrint(BCLog::LLMQ, "%s h[%d] from[%d] sortedCombinedMns[%s]\n", __func__, pCycleQuorumBaseBlockIndex->nHeight, nHeight, ToString(sortedCombinedMns)); + LogPrint(BCLog::LLMQ, "%s h[%d] from[%d] sortedCombinedMns[%s]\n", __func__, + pCycleQuorumBaseBlockIndex->nHeight, nHeight, ToString(sortedCombinedMns)); } size_t numQuorums = static_cast(llmqParams.signingActiveQuorumCount); @@ -228,61 +234,61 @@ std::vector GetQuorumQuarterMembersBySnapshot( } switch (snapshot.mnSkipListMode) { - case SnapshotSkipMode::MODE_NO_SKIPPING: - { - auto itm = sortedCombinedMns.begin(); - for (const size_t i : irange::range(numQuorums)) { - while (quarterQuorumMembers[i].size() < quarterSize) { - quarterQuorumMembers[i].push_back(*itm); - itm++; - if (itm == sortedCombinedMns.end()) { - itm = sortedCombinedMns.begin(); - } + case SnapshotSkipMode::MODE_NO_SKIPPING: { + auto itm = sortedCombinedMns.begin(); + for (const size_t i : irange::range(numQuorums)) { + while (quarterQuorumMembers[i].size() < quarterSize) { + quarterQuorumMembers[i].push_back(*itm); + itm++; + if (itm == sortedCombinedMns.end()) { + itm = sortedCombinedMns.begin(); } } - return quarterQuorumMembers; - } - case SnapshotSkipMode::MODE_SKIPPING_ENTRIES: // List holds entries to be skipped - { - size_t first_entry_index{0}; - std::vector processesdSkipList; - for (const auto& s : snapshot.mnSkipList) { - if (first_entry_index == 0) { - first_entry_index = s; - processesdSkipList.push_back(s); - } else { - processesdSkipList.push_back(first_entry_index + s); - } + } + return quarterQuorumMembers; + } + case SnapshotSkipMode::MODE_SKIPPING_ENTRIES: // List holds entries to be skipped + { + size_t first_entry_index{0}; + std::vector processesdSkipList; + for (const auto& s : snapshot.mnSkipList) { + if (first_entry_index == 0) { + first_entry_index = s; + processesdSkipList.push_back(s); + } else { + processesdSkipList.push_back(first_entry_index + s); } + } - int idx = 0; - auto itsk = processesdSkipList.begin(); - for (const size_t i : irange::range(numQuorums)) { - while (quarterQuorumMembers[i].size() < quarterSize) { - if (itsk != processesdSkipList.end() && idx == *itsk) { - itsk++; - } else { - quarterQuorumMembers[i].push_back(sortedCombinedMns[idx]); - } - idx++; - if (idx == static_cast(sortedCombinedMns.size())) { - idx = 0; - } + int idx = 0; + auto itsk = processesdSkipList.begin(); + for (const size_t i : irange::range(numQuorums)) { + while (quarterQuorumMembers[i].size() < quarterSize) { + if (itsk != processesdSkipList.end() && idx == *itsk) { + itsk++; + } else { + quarterQuorumMembers[i].push_back(sortedCombinedMns[idx]); + } + idx++; + if (idx == static_cast(sortedCombinedMns.size())) { + idx = 0; } } - return quarterQuorumMembers; } - case SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES: // List holds entries to be kept - case SnapshotSkipMode::MODE_ALL_SKIPPED: // Every node was skipped. Returning empty quarterQuorumMembers - default: - return quarterQuorumMembers; + return quarterQuorumMembers; + } + case SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES: // List holds entries to be kept + case SnapshotSkipMode::MODE_ALL_SKIPPED: // Every node was skipped. Returning empty quarterQuorumMembers + default: + return quarterQuorumMembers; } } QuorumMembers ComputeQuorumMembers(Consensus::LLMQType llmqType, const CChainParams& chainparams, const CDeterministicMNList& mn_list, const CBlockIndex* pQuorumBaseBlockIndex) { - bool EvoOnly = (chainparams.GetConsensus().llmqTypePlatform == llmqType) && DeploymentActiveAfter(pQuorumBaseBlockIndex, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V19); + bool EvoOnly = (chainparams.GetConsensus().llmqTypePlatform == llmqType) && + DeploymentActiveAfter(pQuorumBaseBlockIndex, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V19); const auto& llmq_params_opt = chainparams.GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); if (llmq_params_opt->useRotation || pQuorumBaseBlockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { @@ -294,9 +300,10 @@ QuorumMembers ComputeQuorumMembers(Consensus::LLMQType llmqType, const CChainPar return CalculateQuorum(mn_list, modifier, llmq_params_opt->size, EvoOnly); } -void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensus::Params& consensus_params, const CDeterministicMNList& allMns, - const CDeterministicMNList& mnUsedAtH, std::vector& sortedCombinedMns, - llmq::CQuorumSnapshot& quorumSnapshot, std::vector& skipList, const CBlockIndex* pCycleQuorumBaseBlockIndex) +void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensus::Params& consensus_params, + const CDeterministicMNList& allMns, const CDeterministicMNList& mnUsedAtH, + std::vector& sortedCombinedMns, llmq::CQuorumSnapshot& quorumSnapshot, + std::vector& skipList, const CBlockIndex* pCycleQuorumBaseBlockIndex) { if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); @@ -307,11 +314,10 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensu const auto modifier = GetHashModifier(llmqParams, consensus_params, pCycleQuorumBaseBlockIndex); auto sortedAllMns = CalculateQuorum(allMns, modifier); - LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pCycleQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); + LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pCycleQuorumBaseBlockIndex->nHeight, + allMns.GetAllMNsCount()); - std::fill(quorumSnapshot.activeQuorumMembers.begin(), - quorumSnapshot.activeQuorumMembers.end(), - false); + std::fill(quorumSnapshot.activeQuorumMembers.begin(), quorumSnapshot.activeQuorumMembers.end(), false); size_t index = {}; for (const auto& dmn : sortedAllMns) { if (mnUsedAtH.HasMN(dmn->proTxHash)) { @@ -329,8 +335,10 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensu } } -std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const llmq::UtilParameters& util_params, - const CDeterministicMNList& allMns, const PreviousQuorumQuarters& previousQuarters) +std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, + const llmq::UtilParameters& util_params, + const CDeterministicMNList& allMns, + const PreviousQuorumQuarters& previousQuarters) { if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { ASSERT_IF_DEBUG(false); @@ -351,7 +359,9 @@ std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQPar auto MnsUsedAtH = CDeterministicMNList(); std::vector MnsUsedAtHIndexed{nQuorums}; - bool skipRemovedMNs = DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V19) || (util_params.m_chainman.GetParams().NetworkIDString() == CBaseChainParams::TESTNET); + bool skipRemovedMNs = DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), + Consensus::DEPLOYMENT_V19) || + (util_params.m_chainman.GetParams().NetworkIDString() == CBaseChainParams::TESTNET); for (const size_t idx : irange::range(nQuorums)) { for (auto* prev_cycle : previousQuarters.GetCycles()) { @@ -390,7 +400,8 @@ std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQPar } if (LogAcceptDebug(BCLog::LLMQ)) { - LogPrint(BCLog::LLMQ, "%s h[%d] sortedCombinedMns[%s]\n", __func__, util_params.m_base_index->nHeight, ToString(sortedCombinedMnsList)); + LogPrint(BCLog::LLMQ, "%s h[%d] sortedCombinedMns[%s]\n", __func__, util_params.m_base_index->nHeight, + ToString(sortedCombinedMnsList)); } std::vector skipList; @@ -436,13 +447,15 @@ std::vector BuildNewQuorumQuarterMembers(const Consensus::LLMQPar } llmq::CQuorumSnapshot quorumSnapshot{}; - BuildQuorumSnapshot(llmqParams, util_params.m_chainman.GetConsensus(), allMns, MnsUsedAtH, sortedCombinedMnsList, quorumSnapshot, skipList, util_params.m_base_index); + BuildQuorumSnapshot(llmqParams, util_params.m_chainman.GetConsensus(), allMns, MnsUsedAtH, sortedCombinedMnsList, + quorumSnapshot, skipList, util_params.m_base_index); util_params.m_qsnapman.StoreSnapshotForBlock(llmqParams.type, util_params.m_base_index, quorumSnapshot); return quarterQuorumMembers; } -std::vector ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const llmq::UtilParameters& util_params) +std::vector ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, + const llmq::UtilParameters& util_params) { const int cycleLength = llmqParams.dkgInterval; if (!llmqParams.useRotation || util_params.m_base_index->nHeight % llmqParams.dkgInterval != 0) { @@ -451,24 +464,30 @@ std::vector ComputeQuorumMembersByQuarterRotation(const Consensus } const auto nQuorums{static_cast(llmqParams.signingActiveQuorumCount)}; - const CBlockIndex* pWorkBlockIndex = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - llmq::WORK_DIFF_DEPTH); + const CBlockIndex* pWorkBlockIndex = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - + llmq::WORK_DIFF_DEPTH); CDeterministicMNList allMns = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); - LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqParams.type), - util_params.m_base_index->nHeight, allMns.GetValidMNsCount()); + LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", + ToUnderlying(llmqParams.type), util_params.m_base_index->nHeight, allMns.GetValidMNsCount()); PreviousQuorumQuarters previousQuarters(nQuorums); auto prev_cycles{previousQuarters.GetCycles()}; for (size_t idx{0}; idx < prev_cycles.size(); idx++) { - prev_cycles[idx]->m_cycle_index = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - (cycleLength * (idx + 1))); - if (auto opt_snap = util_params.m_qsnapman.GetSnapshotForBlock(llmqParams.type, prev_cycles[idx]->m_cycle_index); opt_snap.has_value()) { + prev_cycles[idx]->m_cycle_index = util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - + (cycleLength * (idx + 1))); + if (auto opt_snap = util_params.m_qsnapman.GetSnapshotForBlock(llmqParams.type, prev_cycles[idx]->m_cycle_index); + opt_snap.has_value()) { prev_cycles[idx]->m_snap = opt_snap.value(); } else { // TODO: Check if it is triggered from outside (P2P, block validation) and maybe throw an exception // assert(false); break; } - prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, util_params.m_dmnman, util_params.m_chainman.GetConsensus(), - prev_cycles[idx]->m_cycle_index, prev_cycles[idx]->m_snap, util_params.m_base_index->nHeight); + prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot(llmqParams, util_params.m_dmnman, + util_params.m_chainman.GetConsensus(), + prev_cycles[idx]->m_cycle_index, + prev_cycles[idx]->m_snap, + util_params.m_base_index->nHeight); } auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, util_params, allMns, previousQuarters); @@ -490,11 +509,13 @@ std::vector ComputeQuorumMembersByQuarterRotation(const Consensus for (const size_t i : irange::range(nQuorums)) { // Move elements from previous quarters into quorumMembers for (auto* prev_cycle : prev_cycles | std::views::reverse) { - std::move(prev_cycle->m_members[i].begin(), prev_cycle->m_members[i].end(), std::back_inserter(quorumMembers[i])); + std::move(prev_cycle->m_members[i].begin(), prev_cycle->m_members[i].end(), + std::back_inserter(quorumMembers[i])); } std::move(newQuarterMembers[i].begin(), newQuarterMembers[i].end(), std::back_inserter(quorumMembers[i])); if (LogAcceptDebug(BCLog::LLMQ)) { - LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]: [%s]\n", util_params.m_base_index->nHeight, i, ToString(quorumMembers[i])); + LogPrint(BCLog::LLMQ, "QuorumComposition h[%d] i[%d]: [%s]\n", util_params.m_base_index->nHeight, i, + ToString(quorumMembers[i])); } } @@ -577,12 +598,12 @@ QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParame InitQuorumsCache(mapIndexedQuorumMembers, util_params.m_chainman.GetConsensus()); } /* - * Quorums created with rotation are now created in a different way. All signingActiveQuorumCount are created during the period of dkgInterval. - * But they are not created exactly in the same block, they are spread overtime: one quorum in each block until all signingActiveQuorumCount are created. - * The new concept of quorumIndex is introduced in order to identify them. - * In every dkgInterval blocks (also called CycleQuorumBaseBlock), the spread quorum creation starts like this: - * For quorumIndex = 0 : signingActiveQuorumCount - * Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex + * Quorums created with rotation are now created in a different way. All signingActiveQuorumCount are created + * during the period of dkgInterval. But they are not created exactly in the same block, they are spread + * overtime: one quorum in each block until all signingActiveQuorumCount are created. The new concept of + * quorumIndex is introduced in order to identify them. In every dkgInterval blocks (also called + * CycleQuorumBaseBlock), the spread quorum creation starts like this: For quorumIndex = 0 : + * signingActiveQuorumCount Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex */ int quorumIndex = util_params.m_base_index->nHeight % llmq_params.dkgInterval; @@ -593,13 +614,15 @@ QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParame const CBlockIndex* pCycleQuorumBaseBlockIndex = util_params.m_base_index->GetAncestor(cycleQuorumBaseHeight); /* - * Since mapQuorumMembers stores Quorum members per block hash, and we don't know yet the block hashes of blocks for all quorumIndexes (since these blocks are not created yet) - * We store them in a second cache mapIndexedQuorumMembers which stores them by {CycleQuorumBaseBlockHash, quorumIndex} + * Since mapQuorumMembers stores Quorum members per block hash, and we don't know yet the block hashes of blocks + * for all quorumIndexes (since these blocks are not created yet) We store them in a second cache + * mapIndexedQuorumMembers which stores them by {CycleQuorumBaseBlockHash, quorumIndex} */ if (reset_cache) { LOCK(cs_indexed_members); mapIndexedQuorumMembers[llmqType].clear(); - } else if (LOCK(cs_indexed_members); mapIndexedQuorumMembers[llmqType].get(std::pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), quorumIndex), quorumMembers)) { + } else if (LOCK(cs_indexed_members); mapIndexedQuorumMembers[llmqType].get( + std::pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), quorumIndex), quorumMembers)) { LOCK(cs_members); mapQuorumMembers[llmqType].insert(util_params.m_base_index->GetBlockHash(), quorumMembers); return quorumMembers; @@ -614,11 +637,15 @@ QuorumMembers GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParame std::move(q[i])); } } else { - const CBlockIndex* pWorkBlockIndex = DeploymentActiveAfter(util_params.m_base_index, util_params.m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V20) - ? util_params.m_base_index->GetAncestor(util_params.m_base_index->nHeight - WORK_DIFF_DEPTH) + const CBlockIndex* pWorkBlockIndex = DeploymentActiveAfter(util_params.m_base_index, + util_params.m_chainman.GetConsensus(), + Consensus::DEPLOYMENT_V20) + ? util_params.m_base_index->GetAncestor( + util_params.m_base_index->nHeight - WORK_DIFF_DEPTH) : util_params.m_base_index.get(); CDeterministicMNList mn_list = util_params.m_dmnman.GetListForBlock(pWorkBlockIndex); - quorumMembers = ComputeQuorumMembers(llmqType, util_params.m_chainman.GetParams(), mn_list, util_params.m_base_index); + quorumMembers = ComputeQuorumMembers(llmqType, util_params.m_chainman.GetParams(), mn_list, + util_params.m_base_index); } LOCK(cs_members); @@ -767,7 +794,8 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& return false; } - LogPrint(BCLog::NET_NETCONN, "%s -- isMember=%d for quorum %s:\n", __func__, isMember, util_params.m_base_index->GetBlockHash().ToString()); + LogPrint(BCLog::NET_NETCONN, "%s -- isMember=%d for quorum %s:\n", __func__, isMember, + util_params.m_base_index->GetBlockHash().ToString()); Uint256HashSet connections; if (isMember) { @@ -781,7 +809,8 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& if (!connections.empty()) { if (!connman.HasMasternodeQuorumNodes(llmqParams.type, util_params.m_base_index->GetBlockHash()) && LogAcceptDebug(BCLog::LLMQ)) { - std::string debugMsg = strprintf("%s -- adding masternodes quorum connections for quorum %s:\n", __func__, util_params.m_base_index->GetBlockHash().ToString()); + std::string debugMsg = strprintf("%s -- adding masternodes quorum connections for quorum %s:\n", __func__, + util_params.m_base_index->GetBlockHash().ToString()); for (const auto& c : connections) { auto dmn = tip_mn_list.GetValidMN(c); if (!dmn) { @@ -827,7 +856,8 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman if (!probeConnections.empty()) { if (LogAcceptDebug(BCLog::LLMQ)) { - std::string debugMsg = strprintf("%s -- adding masternodes probes for quorum %s:\n", __func__, util_params.m_base_index->GetBlockHash().ToString()); + std::string debugMsg = strprintf("%s -- adding masternodes probes for quorum %s:\n", __func__, + util_params.m_base_index->GetBlockHash().ToString()); for (const auto& c : probeConnections) { auto dmn = tip_mn_list.GetValidMN(c); if (!dmn) { diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 233e7abfe11b..5279baf8cf4c 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -38,7 +38,10 @@ struct UtilParameters { gsl::not_null m_base_index; public: - UtilParameters replace_index(gsl::not_null base_index) const { return {m_dmnman, m_qsnapman, m_chainman, base_index}; } + UtilParameters replace_index(gsl::not_null base_index) const + { + return {m_dmnman, m_qsnapman, m_chainman, base_index}; + } }; namespace utils { diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index 8a39d057f1d1..210d81d5de8f 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -377,12 +377,13 @@ static RPCHelpMan quorum_dkgstatus() obj.pushKV("quorumHash", pQuorumBaseBlockIndex->GetBlockHash().ToString()); obj.pushKV("pindexTip", pindexTip->nHeight); - auto allConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.sporkman, {*node.dmnman, - *llmq_ctx.qsnapman, chainman, - pQuorumBaseBlockIndex}, proTxHash, false); - auto outboundConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.sporkman, {*node.dmnman, - *llmq_ctx.qsnapman, chainman, - pQuorumBaseBlockIndex}, + auto allConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.sporkman, + {*node.dmnman, *llmq_ctx.qsnapman, chainman, + pQuorumBaseBlockIndex}, + proTxHash, false); + auto outboundConnections = llmq::utils::GetQuorumConnections(llmq_params, *node.sporkman, + {*node.dmnman, *llmq_ctx.qsnapman, + chainman, pQuorumBaseBlockIndex}, proTxHash, true); std::map foundConnections; connman.ForEachNode([&](const CNode* pnode) { diff --git a/src/test/llmq_snapshot_tests.cpp b/src/test/llmq_snapshot_tests.cpp index 6e5b61aa838c..7e3b1d191ece 100644 --- a/src/test/llmq_snapshot_tests.cpp +++ b/src/test/llmq_snapshot_tests.cpp @@ -225,7 +225,8 @@ BOOST_AUTO_TEST_CASE(quorum_rotation_info_serialization_test) CFinalCommitment commitment{GetLLMQParams(Consensus::LLMQType::LLMQ_TEST), uint256::ONE}; rotInfo.lastCommitmentPerIndex.push_back(commitment); - rotInfo.quorumSnapshotList.push_back(CQuorumSnapshot({false, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {7, 8})); + rotInfo.quorumSnapshotList.push_back( + CQuorumSnapshot({false, false, true}, SnapshotSkipMode::MODE_SKIPPING_ENTRIES, {7, 8})); BOOST_CHECK(TestSerializationRoundtrip(rotInfo)); }