Skip to content

Commit 60dda51

Browse files
PastaPastaPastathepastaclaw
authored andcommitted
Merge dashpay#7176: perf: do linear lookup instead building 2 heavy Hash-Maps
6ffe808 refactor: apply review suggestions (Konstantin Akimov) bb6facd perf: do linear lookup when it's needed instead building 2 heavy Hash-Maps which used almost never (Konstantin Akimov) 9d26734 refactor: remove unused getObjLocalValidity (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented Currently, for each update of masternode list 3 list are generated: list of shared_pointers, hash-map by service, hash-map by protx. Creating these hash-maps creates overhead for every user for every masternode update. It causes excessive battery use, excessive RAM usage while these lookups happens in rare conditions (only for masternode owners during voting; only when "Peer Detail" is open). It's better to do linear lookup _once_ over all masternode in the specific scenario, rather than build these heavy objects for _every_ update of list. Lookup during voting may looks scary due to potential O(N^2). Though, it's not N^2, but N*M (where M is amount of masternodes that belongs to single Owner, M<<N). Secondly, N is relatively small and _voting_ is not assumed to be rapid-fast action (milliseconds); it's okay if user will wait extra 10ms in the worst case scenario for each its vote. ## What was done? Code is updated to do linear lookup instead building heavy hash-maps for every update. Current implementation (in develop) has a bug with dangling pointer and potentially could cause UB: dashpay#7118 (comment) Fixed by this PR ## How Has This Been Tested? N/A ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [ ] 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 _(for repository code-owners and collaborators only)_ ACKs for top commit: UdjinM6: utACK 6ffe808 kwvg: utACK 6ffe808 Tree-SHA512: b401d399767825a0363edfe8aa89dd6f1c44184874ec40aeebcde36917b643d69bc8a670f3b6e6aaa9a35af88d30810e55413137a8c02955103fca89a46e0c0a
1 parent df1ca87 commit 60dda51

File tree

10 files changed

+20
-48
lines changed

10 files changed

+20
-48
lines changed

src/Makefile.qt.include

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ BITCOIN_QT_H = \
200200
qt/transactionrecord.h \
201201
qt/transactiontablemodel.h \
202202
qt/transactionview.h \
203-
qt/util.h \
204203
qt/utilitydialog.h \
205204
qt/walletcontroller.h \
206205
qt/walletframe.h \

src/interfaces/node.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ class GOV
148148
uint16_t m_evo{0};
149149
};
150150
virtual UniqueVoters getObjUniqueVoters(const CGovernanceObject& obj, vote_signal_enum_t vote_signal) = 0;
151-
virtual bool getObjLocalValidity(const CGovernanceObject& obj, std::string& error, bool check_collateral) = 0;
152151
virtual bool existsObj(const uint256& hash) = 0;
153152
virtual bool isEnabled() = 0;
154153
virtual bool processVoteAndRelay(const CGovernanceVote& vote, std::string& error) = 0;

src/node/interfaces.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,14 +263,6 @@ class GOVImpl : public GOV
263263
}
264264
return false;
265265
}
266-
bool getObjLocalValidity(const CGovernanceObject& obj, std::string& error, bool check_collateral) override
267-
{
268-
if (context().govman != nullptr && context().chainman != nullptr && context().dmnman != nullptr) {
269-
LOCK(cs_main);
270-
return obj.IsValidLocally(context().dmnman->GetListAtChainTip(), *(context().chainman), error, check_collateral);
271-
}
272-
return false;
273-
}
274266
bool isEnabled() override
275267
{
276268
if (context().govman != nullptr) {

src/qt/clientfeeds.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <qt/clientmodel.h>
1515
#include <qt/masternodemodel.h>
1616
#include <qt/proposalmodel.h>
17-
#include <qt/util.h>
1817

1918
#include <QDebug>
2019
#include <QThread>
@@ -188,9 +187,7 @@ void MasternodeFeed::fetch()
188187
nNextPayment = nextPaymentIt->second;
189188
}
190189
auto entry = std::make_shared<MasternodeEntry>(dmn, collateralStr, nNextPayment);
191-
ret->m_by_protx[dmn->getProTxHash()] = entry.get();
192-
ret->m_by_service[util::make_array(dmn->getNetInfoPrimary().GetKey())] = entry.get();
193-
ret->m_entries.push_back(std::move(entry));
190+
ret->m_entries.emplace_back(std::move(entry));
194191
});
195192

196193
ret->m_valid = true;

src/qt/clientfeeds.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,8 @@ class InstantSendFeed : public Feed<InstantSendData> {
151151
struct MasternodeData {
152152
bool m_valid{false};
153153
int m_list_height{0};
154-
interfaces::MnList::Counts m_counts{};
155-
QHash<QByteArray, const MasternodeEntry*> m_by_service{};
156-
std::vector<std::shared_ptr<MasternodeEntry>> m_entries{};
157-
Uint256HashMap<const MasternodeEntry*> m_by_protx{};
154+
interfaces::MnList::Counts m_counts;
155+
std::vector<std::shared_ptr<MasternodeEntry>> m_entries;
158156
};
159157

160158
class MasternodeFeed : public Feed<MasternodeData> {

src/qt/guiutil.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,11 @@ namespace GUIUtil
531531
return false;
532532
}
533533

534+
template <typename T1>
535+
inline QByteArray MakeQByteArray(const T1& data)
536+
{
537+
return QByteArray(reinterpret_cast<const char*>(data.data()), data.size());
538+
}
534539
} // namespace GUIUtil
535540

536541
#endif // BITCOIN_QT_GUIUTIL_H

src/qt/proposallist.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -576,16 +576,19 @@ void ProposalList::voteForProposal(vote_outcome_enum_t outcome)
576576
// Vote with each masternode
577577
for (const auto& [proTxHash, votingKeyID] : votableMasternodes) {
578578
// Find the masternode
579-
const auto* dmn = [&]() -> const MasternodeEntry* {
580-
if (const auto it = data_mn->m_by_protx.find(proTxHash); it != data_mn->m_by_protx.end() && !it->second->isBanned()) {
581-
return it->second;
579+
QString protx_hash{QString::fromStdString(proTxHash.ToString())};
580+
const auto dmn = [&]() -> const std::shared_ptr<MasternodeEntry> {
581+
for (const auto& mn : data_mn->m_entries) {
582+
if (mn->proTxHash() == protx_hash) {
583+
return mn->isBanned() ? nullptr : mn;
584+
}
582585
}
583586
return nullptr;
584587
}();
585588

586589
if (!dmn) {
587590
nFailed++;
588-
failedMessages.append(tr("Masternode %1 not found").arg(QString::fromStdString(proTxHash.ToString())));
591+
failedMessages.append(tr("Masternode %1 not found").arg(protx_hash));
589592
continue;
590593
}
591594

@@ -595,8 +598,7 @@ void ProposalList::voteForProposal(vote_outcome_enum_t outcome)
595598
// Sign vote via wallet interface
596599
if (!walletModel->wallet().signGovernanceVote(votingKeyID, vote)) {
597600
nFailed++;
598-
failedMessages.append(
599-
tr("Failed to sign vote for masternode %1").arg(QString::fromStdString(proTxHash.ToString())));
601+
failedMessages.append(tr("Failed to sign vote for masternode %1").arg(protx_hash));
600602
continue;
601603
}
602604

src/qt/rpcconsole.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <qt/masternodemodel.h>
2121
#include <qt/networkwidget.h>
2222
#include <qt/peertablesortproxy.h>
23-
#include <qt/util.h>
2423
#include <qt/walletcontroller.h>
2524
#include <qt/walletmodel.h>
2625

@@ -1291,12 +1290,12 @@ void RPCConsole::updateDetailWidget()
12911290
}
12921291
ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) : ts.na);
12931292

1294-
const auto addr_key{util::make_array(stats->nodeStats.addr.GetKey())};
1295-
const MasternodeEntry* dmn = [&]() -> const MasternodeEntry* {
1293+
const auto addr_key{GUIUtil::MakeQByteArray(stats->nodeStats.addr.GetKey())};
1294+
const std::shared_ptr<MasternodeEntry> dmn = [&]() -> const std::shared_ptr<MasternodeEntry> {
12961295
if (m_feed_masternode) {
12971296
if (const auto data{m_feed_masternode->data()}; data) {
1298-
if (auto it = data->m_by_service.find(addr_key); it != data->m_by_service.end()) {
1299-
return it.value();
1297+
for (const auto& mn : data->m_entries) {
1298+
if (mn->serviceKey() == addr_key) return mn;
13001299
}
13011300
}
13021301
}

src/qt/util.h

Lines changed: 0 additions & 18 deletions
This file was deleted.

test/util/data/non-backported.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ src/qt/proposalinfo.*
4242
src/qt/proposallist.*
4343
src/qt/proposalmodel.*
4444
src/qt/proposalresume.*
45-
src/qt/util.h
4645
src/rpc/coinjoin.cpp
4746
src/rpc/evo.cpp
4847
src/rpc/evo_util.*

0 commit comments

Comments
 (0)