Skip to content

Commit 1493f08

Browse files
Merge #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
2 parents 6abc608 + cf4e9e6 commit 1493f08

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
@@ -140,10 +140,6 @@ uint256 CGovernanceVote::GetHash() const
140140
return hash;
141141
}
142142

143-
uint256 CGovernanceVote::GetSignatureHash() const
144-
{
145-
return SerializeHash(*this);
146-
}
147143

148144
bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const
149145
{
@@ -218,13 +214,6 @@ bool CGovernanceVote::IsValid(const CDeterministicMNList& tip_mn_list, bool useV
218214
}
219215
}
220216

221-
std::string CGovernanceVote::GetSignatureString() const
222-
{
223-
return masternodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" +
224-
::ToString(nVoteSignal) + "|" +
225-
::ToString(nVoteOutcome) + "|" +
226-
::ToString(nTime);
227-
}
228217

229218
bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2)
230219
{

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
@@ -27,6 +27,7 @@ class CBlockIndex;
2727
class CDeterministicMNList;
2828
class CFeeRate;
2929
class CGovernanceObject;
30+
class CGovernanceVote;
3031
class CNodeStats;
3132
class Coin;
3233
class RPCTimerInterface;
@@ -70,6 +71,7 @@ class GOV
7071
virtual int32_t getObjAbsYesCount(const CGovernanceObject& obj, vote_signal_enum_t vote_signal) = 0;
7172
virtual bool getObjLocalValidity(const CGovernanceObject& obj, std::string& error, bool check_collateral) = 0;
7273
virtual bool isEnabled() = 0;
74+
virtual bool processVoteAndRelay(const CGovernanceVote& vote, std::string& error) = 0;
7375
virtual void setContext(node::NodeContext* context) {}
7476
};
7577

src/interfaces/wallet.h

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

123+
//! Sign special transaction payload
124+
virtual bool signSpecialTxPayload(const uint256& hash, const CKeyID& keyid, std::vector<unsigned char>& vchSig) = 0;
125+
123126
//! Return whether wallet has private key.
124127
virtual bool isSpendable(const CScript& script) = 0;
125128
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)