diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 9905d351b542..fe266149ad9c 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -218,15 +218,35 @@ std::vector CDeterministicMNList::GetProjectedMNPayees(int if (nCount < 0 ) { return {}; } - nCount = std::min(nCount, int(GetValidMNsCount())); + nCount = std::min(nCount, int(GetValidWeightedMNsCount())); std::vector result; result.reserve(nCount); + auto remaining_hpmn_payments = 0; + CDeterministicMNCPtr hpmn_to_be_skipped = nullptr; ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) { - result.emplace_back(dmn); + if (dmn->pdmnState->nLastPaidHeight == nHeight) { + // We found the last MN Payee. + // If the last payee is a HPMN, we need to check its consecutive payments and pay him again if needed + if (dmn->nType == MnType::HighPerformance && dmn->pdmnState->nConsecutivePayments < dmn_types::HighPerformance.voting_weight) { + remaining_hpmn_payments = dmn_types::HighPerformance.voting_weight - dmn->pdmnState->nConsecutivePayments; + for ([[maybe_unused]] auto _ : irange::range(remaining_hpmn_payments)) { + result.emplace_back(dmn); + hpmn_to_be_skipped = dmn; + } + } + } + return; + }); + + ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) { + if (dmn == hpmn_to_be_skipped) return; + for ([[maybe_unused]] auto _ : irange::range(GetMnType(dmn->nType).voting_weight)) { + result.emplace_back(dmn); + } }); - std::sort(result.begin(), result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) { + std::sort(result.begin() + remaining_hpmn_payments, result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) { return CompareByLastPaid(a.get(), b.get()); }); diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index bd7f74d15fa7..108cbbc75f7d 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -19,6 +19,7 @@ #include +#include #include #include @@ -241,6 +242,14 @@ class CDeterministicMNList return ranges::count_if(mnMap, [](const auto& p) { return p.second->nType == MnType::HighPerformance && IsMNValid(*p.second); }); } + [[nodiscard]] size_t GetValidWeightedMNsCount() const + { + return std::accumulate(mnMap.begin(), mnMap.end(), 0, [](auto res, const auto& p) { + if (!IsMNValid(*p.second)) return res; + return res + GetMnType(p.second->nType).voting_weight; + }); + } + /** * Execute a callback on all masternodes in the mnList. This will pass a reference * of each masternode to the callback function. This should be preferred over ForEachMNShared.