Skip to content

Commit 2f9210f

Browse files
kwvgUdjinM6
andcommitted
refactor: abstract masternode structures from Qt wallet
Co-authored-by: UdjinM6 <[email protected]>
1 parent dc3f6bd commit 2f9210f

File tree

9 files changed

+247
-67
lines changed

9 files changed

+247
-67
lines changed

src/interfaces/node.h

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <util/settings.h> // For util::SettingsValue
1616
#include <util/translation.h>
1717

18+
#include <evo/types.h>
19+
1820
#include <functional>
1921
#include <memory>
2022
#include <stddef.h>
@@ -29,14 +31,18 @@ class CDeterministicMNList;
2931
class CFeeRate;
3032
class CGovernanceObject;
3133
class CGovernanceVote;
34+
class CKeyID;
3235
class CNodeStats;
3336
class Coin;
37+
class CScript;
38+
class CService;
3439
class RPCTimerInterface;
3540
class UniValue;
3641
class Proxy;
3742
enum class SynchronizationState;
3843
enum class TransactionError;
3944
enum vote_signal_enum_t : int;
45+
enum class MnType : uint16_t;
4046
struct bilingual_str;
4147
struct CNodeStateStats;
4248
namespace node {
@@ -55,12 +61,70 @@ class Loader;
5561
} // namespace CoinJoin
5662
struct BlockTip;
5763

64+
//! Interface for a masternode entry
65+
class MnEntry
66+
{
67+
public:
68+
MnEntry(const CDeterministicMNCPtr& dmn) {}
69+
virtual ~MnEntry() {}
70+
71+
MnEntry() = delete;
72+
73+
virtual bool isBanned() const = 0;
74+
virtual CService getNetInfoPrimary() const = 0;
75+
virtual MnType getType() const = 0;
76+
virtual UniValue toJson() const = 0;
77+
virtual const CKeyID& getKeyIdOwner() const = 0;
78+
virtual const CKeyID& getKeyIdVoting() const = 0;
79+
virtual const COutPoint& getCollateralOutpoint() const = 0;
80+
virtual const CScript& getScriptPayout() const = 0;
81+
virtual const CScript& getScriptOperatorPayout() const = 0;
82+
virtual const int32_t& getLastPaidHeight() const = 0;
83+
virtual const int32_t& getPoSePenalty() const = 0;
84+
virtual const int32_t& getRegisteredHeight() const = 0;
85+
virtual const uint16_t& getOperatorReward() const = 0;
86+
virtual const uint256& getProTxHash() const = 0;
87+
};
88+
89+
using MnEntryCPtr = std::unique_ptr<const MnEntry>;
90+
91+
//! Interface for a list of masternode entries
92+
class MnList
93+
{
94+
public:
95+
MnList(const CDeterministicMNList& mn_list) {}
96+
virtual ~MnList() {}
97+
98+
MnList() = delete;
99+
100+
virtual int32_t getHeight() const = 0;
101+
virtual size_t getAllEvoCount() const = 0;
102+
virtual size_t getAllMNsCount() const = 0;
103+
virtual size_t getValidEvoCount() const = 0;
104+
virtual size_t getValidMNsCount() const = 0;
105+
virtual size_t getValidWeightedMNsCount() const = 0;
106+
virtual uint256 getBlockHash() const = 0;
107+
108+
virtual void forEachMN(bool only_valid, std::function<void(const MnEntry&)> cb) const = 0;
109+
virtual MnEntryCPtr getMN(const uint256& hash) const = 0;
110+
virtual MnEntryCPtr getMNByService(const CService& service) const = 0;
111+
virtual MnEntryCPtr getValidMN(const uint256& hash) const = 0;
112+
virtual std::vector<MnEntryCPtr> getProjectedMNPayees(const CBlockIndex* pindex) const = 0;
113+
114+
virtual void copyContextTo(MnList& mn_list) const = 0;
115+
virtual void setContext(node::NodeContext* context) = 0;
116+
};
117+
118+
using MnListPtr = std::shared_ptr<MnList>;
119+
120+
MnListPtr MakeMNList(const CDeterministicMNList& mn_list);
121+
58122
//! Interface for the src/evo part of a dash node (dashd process).
59123
class EVO
60124
{
61125
public:
62126
virtual ~EVO() {}
63-
virtual std::pair<CDeterministicMNList, const CBlockIndex*> getListAtChainTip() = 0;
127+
virtual std::pair<MnListPtr, const CBlockIndex*> getListAtChainTip() = 0;
64128
virtual void setContext(node::NodeContext* context) {}
65129
};
66130

src/node/interfaces.cpp

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,130 @@ using interfaces::GOV;
8383
using interfaces::Handler;
8484
using interfaces::LLMQ;
8585
using interfaces::MakeHandler;
86+
using interfaces::MnEntry;
87+
using interfaces::MnEntryCPtr;
88+
using interfaces::MnList;
89+
using interfaces::MnListPtr;
8690
using interfaces::Node;
8791
using interfaces::WalletLoader;
8892

8993
namespace node {
9094
namespace {
95+
class MnEntryImpl : public MnEntry
96+
{
97+
private:
98+
CDeterministicMNCPtr m_dmn;
99+
100+
public:
101+
MnEntryImpl(const CDeterministicMNCPtr& dmn) :
102+
MnEntry{dmn},
103+
m_dmn{Assert(dmn)}
104+
{
105+
}
106+
~MnEntryImpl() = default;
107+
108+
bool isBanned() const override { return m_dmn->pdmnState->IsBanned(); }
109+
110+
CService getNetInfoPrimary() const override { return m_dmn->pdmnState->netInfo->GetPrimary(); }
111+
MnType getType() const override { return m_dmn->nType; }
112+
UniValue toJson() const override { return m_dmn->ToJson(); }
113+
const CKeyID& getKeyIdOwner() const override { return m_dmn->pdmnState->keyIDOwner; }
114+
const CKeyID& getKeyIdVoting() const override { return m_dmn->pdmnState->keyIDVoting; }
115+
const COutPoint& getCollateralOutpoint() const override { return m_dmn->collateralOutpoint; }
116+
const CScript& getScriptPayout() const override { return m_dmn->pdmnState->scriptPayout; }
117+
const CScript& getScriptOperatorPayout() const override { return m_dmn->pdmnState->scriptOperatorPayout; }
118+
const int32_t& getLastPaidHeight() const override { return m_dmn->pdmnState->nLastPaidHeight; }
119+
const int32_t& getPoSePenalty() const override { return m_dmn->pdmnState->nPoSePenalty; }
120+
const int32_t& getRegisteredHeight() const override { return m_dmn->pdmnState->nRegisteredHeight; }
121+
const uint16_t& getOperatorReward() const override { return m_dmn->nOperatorReward; }
122+
const uint256& getProTxHash() const override { return m_dmn->proTxHash; }
123+
};
124+
125+
class MnListImpl : public MnList
126+
{
127+
private:
128+
CDeterministicMNList m_list;
129+
130+
public:
131+
MnListImpl(const CDeterministicMNList& mn_list) :
132+
MnList{mn_list},
133+
m_list{mn_list}
134+
{
135+
}
136+
~MnListImpl() = default;
137+
138+
int32_t getHeight() const override { return m_list.GetHeight(); }
139+
size_t getAllEvoCount() const override { return m_list.GetAllEvoCount(); }
140+
size_t getAllMNsCount() const override { return m_list.GetAllMNsCount(); }
141+
size_t getValidEvoCount() const override { return m_list.GetValidEvoCount(); }
142+
size_t getValidMNsCount() const override { return m_list.GetValidMNsCount(); }
143+
size_t getValidWeightedMNsCount() const override { return m_list.GetValidWeightedMNsCount(); }
144+
uint256 getBlockHash() const override { return m_list.GetBlockHash(); }
145+
146+
void forEachMN(bool only_valid, std::function<void(const MnEntry&)> cb) const override
147+
{
148+
m_list.ForEachMNShared(only_valid, [&cb](const auto& dmn) {
149+
cb(MnEntryImpl{dmn});
150+
});
151+
}
152+
MnEntryCPtr getMN(const uint256& hash) const override
153+
{
154+
const auto dmn{m_list.GetMN(hash)};
155+
return dmn ? std::make_unique<const MnEntryImpl>(dmn) : nullptr;
156+
}
157+
MnEntryCPtr getMNByService(const CService& service) const override
158+
{
159+
const auto dmn{m_list.GetMNByService(service)};
160+
return dmn ? std::make_unique<const MnEntryImpl>(dmn) : nullptr;
161+
}
162+
MnEntryCPtr getValidMN(const uint256& hash) const override
163+
{
164+
const auto dmn{m_list.GetValidMN(hash)};
165+
return dmn ? std::make_unique<const MnEntryImpl>(dmn) : nullptr;
166+
}
167+
std::vector<MnEntryCPtr> getProjectedMNPayees(const CBlockIndex* pindex) const override
168+
{
169+
std::vector<MnEntryCPtr> ret;
170+
for (const auto& payee : m_list.GetProjectedMNPayees(pindex)) {
171+
ret.emplace_back(std::make_unique<const MnEntryImpl>(payee));
172+
}
173+
return ret;
174+
}
175+
176+
void copyContextTo(MnList& mn_list) const override
177+
{
178+
if (!m_context) return;
179+
mn_list.setContext(m_context);
180+
}
181+
void setContext(NodeContext* context) override
182+
{
183+
m_context = context;
184+
}
185+
186+
private:
187+
// Note: Currently we do nothing with m_context but in the future, if we have a hard fork
188+
// that requires checking for deployment information in deterministic masternode logic,
189+
// we will need NodeContext::chainman. This has been kept around to retain those code
190+
// paths.
191+
[[maybe_unused]] NodeContext* m_context{nullptr};
192+
};
193+
91194
class EVOImpl : public EVO
92195
{
93196
private:
94197
ChainstateManager& chainman() { return *Assert(m_context->chainman); }
95198
NodeContext& context() { return *Assert(m_context); }
96199

97200
public:
98-
std::pair<CDeterministicMNList, const CBlockIndex*> getListAtChainTip() override
201+
std::pair<MnListPtr, const CBlockIndex*> getListAtChainTip() override
99202
{
100203
const CBlockIndex *tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
101-
CDeterministicMNList mnList{};
204+
MnListImpl mnList{CDeterministicMNList{}};
102205
if (tip != nullptr && context().dmnman != nullptr) {
103206
mnList = context().dmnman->GetListForBlock(tip);
104207
}
105-
return {std::move(mnList), tip};
208+
mnList.setContext(m_context);
209+
return {std::make_shared<MnListImpl>(mnList), tip};
106210
}
107211
void setContext(NodeContext* context) override
108212
{
@@ -1215,4 +1319,5 @@ class ChainImpl : public Chain
12151319
namespace interfaces {
12161320
std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
12171321
std::unique_ptr<Chain> MakeChain(node::NodeContext& node) { return std::make_unique<node::ChainImpl>(node); }
1322+
MnListPtr MakeMNList(const CDeterministicMNList& mn_list) { return std::make_shared<node::MnListImpl>(mn_list); }
12181323
} // namespace interfaces

src/qt/clientmodel.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO
5050
m_peer_table_sort_proxy->setSourceModel(peerTableModel);
5151

5252
banTableModel = new BanTableModel(m_node, this);
53-
mnListCached = std::make_unique<CDeterministicMNList>();
53+
mnListCached = interfaces::MakeMNList(CDeterministicMNList{});
5454

5555
QTimer* timer = new QTimer;
5656
timer->setInterval(MODEL_UPDATE_DELAY);
@@ -99,29 +99,30 @@ int ClientModel::getNumConnections(unsigned int flags) const
9999
return m_node.getNodeCount(connections);
100100
}
101101

102-
void ClientModel::setMasternodeList(const CDeterministicMNList& mnList, const CBlockIndex* tip)
102+
void ClientModel::setMasternodeList(interfaces::MnListPtr mnList, const CBlockIndex* tip)
103103
{
104104
LOCK(cs_mnlist);
105-
if (mnListCached->GetBlockHash() == mnList.GetBlockHash()) {
105+
if (mnListCached->getBlockHash() == mnList->getBlockHash()) {
106106
return;
107107
}
108-
mnListCached = std::make_unique<CDeterministicMNList>(mnList);
108+
mnListCached->copyContextTo(*mnList);
109+
mnListCached = std::move(mnList);
109110
mnListTip = tip;
110111
Q_EMIT masternodeListChanged();
111112
}
112113

113-
std::pair<CDeterministicMNList, const CBlockIndex*> ClientModel::getMasternodeList() const
114+
std::pair<interfaces::MnListPtr, const CBlockIndex*> ClientModel::getMasternodeList() const
114115
{
115116
LOCK(cs_mnlist);
116-
return {*mnListCached, mnListTip};
117+
return {mnListCached, mnListTip};
117118
}
118119

119120
void ClientModel::refreshMasternodeList()
120121
{
121122
auto [mnList, tip] = m_node.evo().getListAtChainTip();
122123

123124
LOCK(cs_mnlist);
124-
setMasternodeList(mnList, tip);
125+
setMasternodeList(std::move(mnList), tip);
125126
}
126127

127128
int ClientModel::getHeaderTipHeight() const
@@ -320,7 +321,7 @@ void ClientModel::subscribeToCoreSignals()
320321
}));
321322
m_event_handlers.emplace_back(m_node.handleNotifyMasternodeListChanged(
322323
[this](const CDeterministicMNList& newList, const CBlockIndex* pindex) {
323-
setMasternodeList(newList, pindex);
324+
setMasternodeList(interfaces::MakeMNList(newList), pindex);
324325
}));
325326
}
326327

src/qt/clientmodel.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ enum NumConnections {
4747
CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
4848
};
4949

50-
class CDeterministicMNList;
5150
class CGovernanceObject;
5251

5352
/** Model for Dash network client. */
@@ -77,8 +76,8 @@ class ClientModel : public QObject
7776
int getHeaderTipHeight() const;
7877
int64_t getHeaderTipTime() const;
7978

80-
void setMasternodeList(const CDeterministicMNList& mnList, const CBlockIndex* tip);
81-
std::pair<CDeterministicMNList, const CBlockIndex*> getMasternodeList() const;
79+
void setMasternodeList(interfaces::MnListPtr mnList, const CBlockIndex* tip);
80+
std::pair<interfaces::MnListPtr, const CBlockIndex*> getMasternodeList() const;
8281
void refreshMasternodeList();
8382

8483
void getAllGovernanceObjects(std::vector<CGovernanceObject> &obj);
@@ -120,7 +119,7 @@ class ClientModel : public QObject
120119
// caches it internally for recent blocks but it's not enough to get consistent
121120
// representation of the list in UI during initial sync/reindex, so we cache it here too.
122121
mutable RecursiveMutex cs_mnlist; // protects mnListCached
123-
std::unique_ptr<CDeterministicMNList> mnListCached GUARDED_BY(cs_mnlist){};
122+
interfaces::MnListPtr mnListCached GUARDED_BY(cs_mnlist){};
124123
const CBlockIndex* mnListTip{nullptr};
125124

126125
void TipChanged(SynchronizationState sync_state, interfaces::BlockTip tip, double verification_progress, bool header) EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex);

src/qt/governancelist.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ void GovernanceList::updateProposalList()
389389
// A proposal is considered passing if (YES votes - NO votes) >= (Total Weight of Masternodes / 10),
390390
// count total valid (ENABLED) masternodes to determine passing threshold.
391391
// Need to query number of masternodes here with access to clientModel.
392-
const int nWeightedMnCount = clientModel->getMasternodeList().first.GetValidWeightedMNsCount();
392+
const int nWeightedMnCount = clientModel->getMasternodeList().first->getValidWeightedMNsCount();
393393
const int nAbsVoteReq = std::max(Params().GetConsensus().nGovernanceMinQuorum, nWeightedMnCount / 10);
394394
proposalModel->setVotingParams(nAbsVoteReq);
395395

@@ -492,11 +492,11 @@ void GovernanceList::updateVotingCapability()
492492
if (!pindex) return;
493493

494494
votableMasternodes.clear();
495-
mn_list.ForEachMN(/*onlyValid=*/true, [&](const auto& dmn) {
495+
mn_list->forEachMN(/*only_valid=*/true, [&](const auto& dmn) {
496496
// Check if wallet owns the voting key using the same logic as RPC
497-
const CScript script = GetScriptForDestination(PKHash(dmn.pdmnState->keyIDVoting));
497+
const CScript script = GetScriptForDestination(PKHash(dmn.getKeyIdVoting()));
498498
if (walletModel->wallet().isSpendable(script)) {
499-
votableMasternodes[dmn.proTxHash] = dmn.pdmnState->keyIDVoting;
499+
votableMasternodes[dmn.getProTxHash()] = dmn.getKeyIdVoting();
500500
}
501501
});
502502

@@ -564,15 +564,15 @@ void GovernanceList::voteForProposal(vote_outcome_enum_t outcome)
564564
// Vote with each masternode
565565
for (const auto& [proTxHash, votingKeyID] : votableMasternodes) {
566566
// Find the masternode
567-
auto dmn = mnList.GetValidMN(proTxHash);
567+
auto dmn = mnList->getValidMN(proTxHash);
568568
if (!dmn) {
569569
nFailed++;
570570
failedMessages.append(tr("Masternode %1 not found").arg(QString::fromStdString(proTxHash.ToString())));
571571
continue;
572572
}
573573

574574
// Create vote
575-
CGovernanceVote vote(dmn->collateralOutpoint, proposalHash, VOTE_SIGNAL_FUNDING, outcome);
575+
CGovernanceVote vote(dmn->getCollateralOutpoint(), proposalHash, VOTE_SIGNAL_FUNDING, outcome);
576576

577577
// Sign vote using CWallet member function
578578
if (!walletModel->wallet().wallet()->SignGovernanceVote(votingKeyID, vote)) {

0 commit comments

Comments
 (0)