Skip to content

Commit 4ca3904

Browse files
PastaPastaPastaknst
authored andcommitted
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
1 parent 5d7470a commit 4ca3904

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
@@ -57,14 +57,15 @@ struct PreviousQuorumQuarters {
5757
};
5858

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

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

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

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

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

283-
std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman,
285+
std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, const CDeterministicMNList& mn_list,
284286
const CBlockIndex* pQuorumBaseBlockIndex)
285287
{
286288
bool EvoOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex);
@@ -291,12 +293,8 @@ std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqT
291293
return {};
292294
}
293295

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

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

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

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

418416
std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(
419-
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
417+
const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, CQuorumSnapshotManager& qsnapman,
420418
const CBlockIndex* pCycleQuorumBaseBlockIndex, const PreviousQuorumQuarters& previousQuarters)
421419
{
422420
if (!llmqParams.useRotation || pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval != 0) {
@@ -429,10 +427,8 @@ std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(
429427

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

435-
auto allMns = dmnman.GetListForBlock(pWorkBlockIndex);
436432

437433
if (allMns.GetValidMNsCount() < quarterSize) {
438434
return quarterQuorumMembers;
@@ -618,14 +614,28 @@ std::vector<std::vector<CDeterministicMNCPtr>> GetQuorumQuarterMembersBySnapshot
618614

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

631641
if (LogAcceptDebug(BCLog::LLMQ)) {
@@ -701,39 +711,6 @@ std::vector<std::vector<CDeterministicMNCPtr>> GetQuorumQuarterMembersBySnapshot
701711
}
702712
}
703713

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

0 commit comments

Comments
 (0)