Skip to content

Commit e7ea396

Browse files
Merge dashpay#6731: perf: optimize GetQuorumQuarterMembersBySnapshot calculation
b7b04e5 fix: rename dmnman to allMns to match declaration and definition of function; and the meaning (Konstantin Akimov) e9e0f58 refactor: inline GetMNUsageBySnapshot to simplify code (Konstantin Akimov) 46383b1 perf: optimize GetQuorumQuarterMembersBySnapshot calculation (Konstantin Akimov) d337579 refactor: use CDeterministicMNList instead CDeterministicMNManager in GetMNUsageBySnapshot (Konstantin Akimov) 790ae0f refactor: use CDeterministicMNList instead of CDeterministicMNManager in ComputeQuorumMembers (Konstantin Akimov) ac934eb refactor: pass CDeterministicMNList instead of CDeterministicMNManager to BuildNewQuorumQuarterMembers (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented Masternodes already sorted with the same modifier inside `GetMNUsageBySnapshot`, no need to re-sort them inside `GetQuorumQuarterMembersBySnapshot`. ## What was done? Removed extra sort of already sorted vectors; removed duplicated calculation of modifier, simplified `GetMNUsageBySnapshot` by inlining it. Also several methods are changed to accept CDeterministicMNList instead of CDeterministicMNManager. ## How Has This Been Tested? It improves significantly performance of `llmq::utils::GetAllQuorumMembers` which is widely used during block validation; for many RPC calls, for processing some network messages, for masternodes participating in quorums. Despite 25% improvement for performance of `llmq::utils::GetAllQuorumMembers` overall improvement for indexing is less than 1% of total CPU time (thanks to caches). `perf` for PR: <img width="838" alt="image" src="https://github.com/user-attachments/assets/cb98a0ef-3a4b-4d21-a674-80c300764712" /> `perf` for develop: <img width="838" alt="image" src="https://github.com/user-attachments/assets/879acdac-facd-4a11-b37a-607f4cb31e48" /> ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: utACK b7b04e5 Tree-SHA512: 069e2a0a2b6ad7dfb092fdfa14e289ecde5bc25a59c7cb0c2fad10a56c9dbacb207b8f4bdd5be0eb88380fd745e0ff21ffc88fe5f24103d376cd3dc83f089787
2 parents 2a94cc3 + b7b04e5 commit e7ea396

File tree

1 file changed

+33
-56
lines changed

1 file changed

+33
-56
lines changed

src/llmq/utils.cpp

Lines changed: 33 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ struct PreviousQuorumQuarters {
5656
};
5757

5858
// Forward declarations
59-
static std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman,
59+
static std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType,
60+
const CDeterministicMNList& mn_list,
6061
const CBlockIndex* pQuorumBaseBlockIndex);
6162
static std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(
6263
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
6364
const CBlockIndex* pCycleQuorumBaseBlockIndex);
6465

6566
static std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(
66-
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
67+
const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, CQuorumSnapshotManager& qsnapman,
6768
const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters);
6869

6970
static PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams,
@@ -75,9 +76,6 @@ static PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::L
7576
static std::vector<std::vector<CDeterministicMNCPtr>> GetQuorumQuarterMembersBySnapshot(
7677
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman,
7778
const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight);
78-
static std::pair<std::vector<CDeterministicMNCPtr>, std::vector<CDeterministicMNCPtr>> GetMNUsageBySnapshot(
79-
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman,
80-
const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight);
8179

8280
static void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns,
8381
const CDeterministicMNList& mnUsedAtH,
@@ -271,15 +269,19 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
271269
std::move(q[i]));
272270
}
273271
} else {
274-
quorumMembers = ComputeQuorumMembers(llmqType, dmnman, pQuorumBaseBlockIndex);
272+
const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex)
273+
? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8)
274+
: pQuorumBaseBlockIndex.get();
275+
CDeterministicMNList mn_list = dmnman.GetListForBlock(pWorkBlockIndex);
276+
quorumMembers = ComputeQuorumMembers(llmqType, mn_list, pQuorumBaseBlockIndex);
275277
}
276278

277279
LOCK(cs_members);
278280
mapQuorumMembers[llmqType].insert(pQuorumBaseBlockIndex->GetBlockHash(), quorumMembers);
279281
return quorumMembers;
280282
}
281283

282-
std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman,
284+
std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, const CDeterministicMNList& mn_list,
283285
const CBlockIndex* pQuorumBaseBlockIndex)
284286
{
285287
bool EvoOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex);
@@ -290,12 +292,8 @@ std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqT
290292
return {};
291293
}
292294

293-
const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) ?
294-
pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) :
295-
pQuorumBaseBlockIndex;
296295
const auto modifier = GetHashModifier(llmq_params_opt.value(), pQuorumBaseBlockIndex);
297-
auto allMns = dmnman.GetListForBlock(pWorkBlockIndex);
298-
return CalculateQuorum(allMns, modifier, llmq_params_opt->size, EvoOnly);
296+
return CalculateQuorum(mn_list, modifier, llmq_params_opt->size, EvoOnly);
299297
}
300298

301299
std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(
@@ -314,7 +312,7 @@ std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRota
314312
const CBlockIndex* pBlockHMinus2CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 2 * cycleLength);
315313
const CBlockIndex* pBlockHMinus3CIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 3 * cycleLength);
316314
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8);
317-
auto allMns = dmnman.GetListForBlock(pWorkBlockIndex);
315+
CDeterministicMNList allMns = dmnman.GetListForBlock(pWorkBlockIndex);
318316
LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", ToUnderlying(llmqType), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount());
319317

320318
PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, dmnman, qsnapman,
@@ -325,7 +323,7 @@ std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRota
325323
size_t nQuorums = static_cast<size_t>(llmqParams.signingActiveQuorumCount);
326324
std::vector<std::vector<CDeterministicMNCPtr>> quorumMembers{nQuorums};
327325

328-
auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, dmnman, qsnapman, pCycleQuorumBaseBlockIndex,
326+
auto newQuarterMembers = BuildNewQuorumQuarterMembers(llmqParams, allMns, qsnapman, pCycleQuorumBaseBlockIndex,
329327
previousQuarters);
330328
//TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice
331329
//assert (!newQuarterMembers.empty());
@@ -415,7 +413,7 @@ PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQPara
415413
}
416414

417415
std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(
418-
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
416+
const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, CQuorumSnapshotManager& qsnapman,
419417
const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters)
420418
{
421419
if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) {
@@ -428,10 +426,8 @@ std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(
428426

429427
size_t quorumSize = static_cast<size_t>(llmqParams.size);
430428
auto quarterSize{quorumSize / 4};
431-
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8);
432429
const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex);
433430

434-
auto allMns = dmnman.GetListForBlock(pWorkBlockIndex);
435431

436432
if (allMns.GetValidMNsCount() < quarterSize) {
437433
return quarterQuorumMembers;
@@ -617,14 +613,28 @@ std::vector<std::vector<CDeterministicMNCPtr>> GetQuorumQuarterMembersBySnapshot
617613

618614
std::vector<CDeterministicMNCPtr> sortedCombinedMns;
619615
{
616+
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(
617+
pCycleQuorumBaseBlockIndex->nHeight - 8);
618+
auto mn_list = dmnman.GetListForBlock(pWorkBlockIndex);
620619
const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex);
621-
auto [MnsUsedAtH, MnsNotUsedAtH] = GetMNUsageBySnapshot(llmqParams, dmnman, pCycleQuorumBaseBlockIndex,
622-
snapshot, nHeight);
623-
// the list begins with all the unused MNs
624-
sortedCombinedMns = CalculateQuorum(std::move(MnsNotUsedAtH), modifier);
620+
auto sortedAllMns = CalculateQuorum(mn_list, modifier);
621+
622+
std::vector<CDeterministicMNCPtr> usedMNs;
623+
size_t i{0};
624+
for (const auto& dmn : sortedAllMns) {
625+
if (snapshot.activeQuorumMembers[i]) {
626+
usedMNs.push_back(dmn);
627+
} else {
628+
if (!dmn->pdmnState->IsBanned()) {
629+
// the list begins with all the unused MNs
630+
sortedCombinedMns.push_back(dmn);
631+
}
632+
}
633+
i++;
634+
}
635+
625636
// Now add the already used MNs to the end of the list
626-
auto sortedMnsUsedAtH = CalculateQuorum(std::move(MnsUsedAtH), modifier);
627-
std::move(sortedMnsUsedAtH.begin(), sortedMnsUsedAtH.end(), std::back_inserter(sortedCombinedMns));
637+
std::move(usedMNs.begin(), usedMNs.end(), std::back_inserter(sortedCombinedMns));
628638
}
629639

630640
if (LogAcceptDebug(BCLog::LLMQ)) {
@@ -700,39 +710,6 @@ std::vector<std::vector<CDeterministicMNCPtr>> GetQuorumQuarterMembersBySnapshot
700710
}
701711
}
702712

703-
static std::pair<std::vector<CDeterministicMNCPtr>, std::vector<CDeterministicMNCPtr>> GetMNUsageBySnapshot(
704-
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman,
705-
const CBlockIndex* pCycleQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight)
706-
{
707-
if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) {
708-
ASSERT_IF_DEBUG(false);
709-
return {};
710-
}
711-
712-
std::vector<CDeterministicMNCPtr> usedMNs;
713-
std::vector<CDeterministicMNCPtr> nonUsedMNs;
714-
715-
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8);
716-
const auto modifier = GetHashModifier(llmqParams, pCycleQuorumBaseBlockIndex);
717-
718-
auto allMns = dmnman.GetListForBlock(pWorkBlockIndex);
719-
auto sortedAllMns = CalculateQuorum(allMns, modifier);
720-
721-
size_t i{0};
722-
for (const auto& dmn : sortedAllMns) {
723-
if (snapshot.activeQuorumMembers[i]) {
724-
usedMNs.push_back(dmn);
725-
} else {
726-
if (!dmn->pdmnState->IsBanned()) {
727-
nonUsedMNs.push_back(dmn);
728-
}
729-
}
730-
i++;
731-
}
732-
733-
return {usedMNs, nonUsedMNs};
734-
}
735-
736713
uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2)
737714
{
738715
// We need to deterministically select who is going to initiate the connection. The naive way would be to simply

0 commit comments

Comments
 (0)