Skip to content

Commit a2ba808

Browse files
PastaPastaPastaknst
authored andcommitted
Merge dashpay#6690: feat(qt): add governance voting functionality to Qt wallet
cf4e9e6 fix: move CGovernanceVote inline methods to header for wallet linkage (pasta) 6f0723a chore: run clang-format (pasta) 2db939e fix: address PR review comments (pasta) bd0f59e feat(governance): implement SignGovernanceVote method in CWallet for vote signing (pasta) 13b4117 feat(governance): refactor vote signing logic into a helper function (pasta) 778a0b1 feat(gui): add tooltip for masternode count display in governance tab (pasta) 81d6648 chore: apply clang-format (pasta) edfe1ee refactor(governance): avoid recursion in wallet unlock handling (pasta) 24240a6 docs: add release notes for governance voting GUI feature (pasta) 0caee40 feat(gui): add masternode count display to governance tab (pasta) 5ac8475 feat(gui): add governance voting functionality to Qt wallet (pasta) Pull request description: ## Issue being fixed or feature implemented - Why is this change required? Currently, users must use CLI commands (gobject vote-many) to vote on governance proposals, which is not user-friendly for non-technical users who prefer the GUI wallet. - What problem does it solve? This eliminates the need to use command-line tools for governance voting, making the voting process accessible to all GUI wallet users who own masternodes. ## What was done? This PR adds complete governance voting functionality to the Qt wallet interface: - Added right-click context menu to governance proposals table with "Vote Yes", "Vote No", and "Vote Abstain" options - Implemented voting capability detection that checks if the wallet contains any masternode voting keys - Added vote signing and submission logic that matches the existing RPC implementation (gobject vote-many) - Implemented network-specific signing: - Testnet: Uses SignSpecialTxPayload with vote.GetSignatureHash() - Other networks: Uses SignMessage with vote.GetSignatureString() - Extended interfaces: - Added processVoteAndRelay method to the GOV interface (interfaces/node.h) - Added signSpecialTxPayload method to the wallet interface (interfaces/wallet.h) - Added comprehensive error handling with detailed feedback showing success/failure counts and specific error messages - Implemented wallet unlock handling that prompts for passphrase when needed - Updates vote counts in the governance list after voting ## How Has This Been Tested? - Tested on testnet with multiple masternodes in wallet - Verified voting capability detection correctly identifies wallets with/without voting keys - Confirmed votes are successfully submitted and accepted by the network - Tested wallet unlock flow with encrypted wallets - Verified testnet-specific signing works correctly - Confirmed vote counts update in the governance list after voting Testing environment: macOS, testnet, wallet with 3 masternode voting keys https://github.com/user-attachments/assets/de777bf7-2e05-4751-9e56-98e273703e66 ## Breaking Changes None - this PR only adds new functionality to the GUI without modifying existing behavior. ## 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 (@thephez) - [x] I have assigned this pull request to a milestone (for repository code-owners and collaborators only) ACKs for top commit: UdjinM6: light ACK cf4e9e6 Tree-SHA512: aec92043e2432f66d071dccf91d127b91728d35e84ad1ca9fe88c1e15b5c2545a6730108833e7f19f2ef69ac5fdaf4d08288ce9ea0051d123f5a07f2c5f1c91c
1 parent 1e3de36 commit a2ba808

File tree

14 files changed

+312
-43
lines changed

14 files changed

+312
-43
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GUI changes
2+
-----------
3+
4+
- Added governance proposal voting functionality to the Qt interface. Users with masternode voting keys can now vote on governance proposals directly from the governance tab via right-click context menu (#6690).
5+
- Added masternode count display to governance tab showing how many masternodes the wallet can vote with (#6690).

src/governance/vote.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,6 @@ uint256 CGovernanceVote::GetHash() const
144144
return hash;
145145
}
146146

147-
uint256 CGovernanceVote::GetSignatureHash() const
148-
{
149-
return SerializeHash(*this);
150-
}
151147

152148
bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const
153149
{
@@ -222,13 +218,6 @@ bool CGovernanceVote::IsValid(const CDeterministicMNList& tip_mn_list, bool useV
222218
}
223219
}
224220

225-
std::string CGovernanceVote::GetSignatureString() const
226-
{
227-
return masternodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" +
228-
::ToString(nVoteSignal) + "|" +
229-
::ToString(nVoteOutcome) + "|" +
230-
::ToString(nTime);
231-
}
232221

233222
bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2)
234223
{

src/governance/vote.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
#ifndef BITCOIN_GOVERNANCE_VOTE_H
66
#define BITCOIN_GOVERNANCE_VOTE_H
77

8+
#include <hash.h>
89
#include <primitives/transaction.h>
910
#include <uint256.h>
11+
#include <util/string.h>
1012

1113
class CActiveMasternodeManager;
1214
class CBLSPublicKey;
@@ -100,7 +102,13 @@ class CGovernanceVote
100102
bool Sign(const CActiveMasternodeManager& mn_activeman);
101103
bool CheckSignature(const CBLSPublicKey& pubKey) const;
102104
bool IsValid(const CDeterministicMNList& tip_mn_list, bool useVotingKey) const;
103-
std::string GetSignatureString() const;
105+
std::string GetSignatureString() const
106+
{
107+
return masternodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" +
108+
::ToString(nVoteSignal) + "|" +
109+
::ToString(nVoteOutcome) + "|" +
110+
::ToString(nTime);
111+
}
104112
void Relay(PeerManager& peerman, const CMasternodeSync& mn_sync, const CDeterministicMNList& tip_mn_list) const;
105113

106114
const COutPoint& GetMasternodeOutpoint() const { return masternodeOutpoint; }
@@ -112,7 +120,10 @@ class CGovernanceVote
112120
*/
113121

114122
uint256 GetHash() const;
115-
uint256 GetSignatureHash() const;
123+
uint256 GetSignatureHash() const
124+
{
125+
return SerializeHash(*this);
126+
}
116127

117128
std::string ToString(const CDeterministicMNList& tip_mn_list) const;
118129

@@ -126,4 +137,9 @@ class CGovernanceVote
126137
}
127138
};
128139

140+
/**
141+
* Sign a governance vote using wallet signing methods
142+
* Handles different signing approaches for different networks
143+
*/
144+
129145
#endif // BITCOIN_GOVERNANCE_VOTE_H

src/interfaces/node.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class CCoinControl;
2828
class CDeterministicMNList;
2929
class CFeeRate;
3030
class CGovernanceObject;
31+
class CGovernanceVote;
3132
class CNodeStats;
3233
class Coin;
3334
class RPCTimerInterface;
@@ -67,6 +68,7 @@ class GOV
6768
virtual int32_t getObjAbsYesCount(const CGovernanceObject& obj, vote_signal_enum_t vote_signal) = 0;
6869
virtual bool getObjLocalValidity(const CGovernanceObject& obj, std::string& error, bool check_collateral) = 0;
6970
virtual bool isEnabled() = 0;
71+
virtual bool processVoteAndRelay(const CGovernanceVote& vote, std::string& error) = 0;
7072
virtual void setContext(NodeContext* context) {}
7173
};
7274

src/interfaces/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ class Wallet
107107
//! Sign message
108108
virtual SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) = 0;
109109

110+
//! Sign special transaction payload
111+
virtual bool signSpecialTxPayload(const uint256& hash, const CKeyID& keyid, std::vector<unsigned char>& vchSig) = 0;
112+
110113
//! Return whether wallet has private key.
111114
virtual bool isSpendable(const CScript& script) = 0;
112115
virtual bool isSpendable(const CTxDestination& dest) = 0;

src/node/interfaces.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
#include <coinjoin/common.h>
1212
#include <deploymentstatus.h>
1313
#include <evo/deterministicmns.h>
14+
#include <governance/exceptions.h>
1415
#include <governance/governance.h>
1516
#include <governance/object.h>
17+
#include <governance/vote.h>
1618
#include <init.h>
1719
#include <interfaces/chain.h>
1820
#include <interfaces/coinjoin.h>
@@ -140,6 +142,19 @@ class GOVImpl : public GOV
140142
}
141143
return false;
142144
}
145+
bool processVoteAndRelay(const CGovernanceVote& vote, std::string& error) override
146+
{
147+
if (context().govman != nullptr && context().connman != nullptr && context().peerman != nullptr) {
148+
CGovernanceException exception;
149+
bool result = context().govman->ProcessVoteAndRelay(vote, exception, *context().connman, *context().peerman);
150+
if (!result) {
151+
error = exception.GetMessage();
152+
}
153+
return result;
154+
}
155+
error = "Governance manager not available";
156+
return false;
157+
}
143158
void setContext(NodeContext* context) override
144159
{
145160
m_context = context;

src/qt/forms/governancelist.ui

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,45 @@
7373
<property name="orientation">
7474
<enum>Qt::Horizontal</enum>
7575
</property>
76+
<property name="sizeType">
77+
<enum>QSizePolicy::Expanding</enum>
78+
</property>
79+
<property name="sizeHint" stdset="0">
80+
<size>
81+
<width>40</width>
82+
<height>20</height>
83+
</size>
84+
</property>
85+
</spacer>
86+
</item>
87+
<item>
88+
<widget class="QLabel" name="label_mn_count">
89+
<property name="text">
90+
<string>Masternode Count:</string>
91+
</property>
92+
<property name="toolTip">
93+
<string>Number of masternodes this wallet can vote with (masternodes for which this wallet holds the voting key)</string>
94+
</property>
95+
</widget>
96+
</item>
97+
<item>
98+
<widget class="QLabel" name="mnCountLabel">
99+
<property name="text">
100+
<string notr="true">0</string>
101+
</property>
102+
</widget>
103+
</item>
104+
<item>
105+
<spacer name="horizontalSpacer_5">
106+
<property name="orientation">
107+
<enum>Qt::Horizontal</enum>
108+
</property>
109+
<property name="sizeType">
110+
<enum>QSizePolicy::Fixed</enum>
111+
</property>
76112
<property name="sizeHint" stdset="0">
77113
<size>
78-
<width>10</width>
114+
<width>20</width>
79115
<height>20</height>
80116
</size>
81117
</property>

0 commit comments

Comments
 (0)