PIVX Core  5.6.99
P2P Digital Currency
budgetutil.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021 The PIVX Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or https://www.opensource.org/licenses/mit-license.php.
4 
5 #include "budget/budgetutil.h"
6 
7 #include "budget/budgetmanager.h"
8 #include "masternodeman.h"
9 #include "masternodeconfig.h"
10 #include "util/validation.h"
11 
12 #ifdef ENABLE_WALLET
13 #include "wallet/wallet.h" // future: use interface instead.
14 #endif
15 
16 
17 static UniValue packRetStatus(const std::string& nodeType, const std::string& result, const std::string& error)
18 {
19  UniValue statusObj(UniValue::VOBJ);
20  statusObj.pushKV("node", nodeType);
21  statusObj.pushKV("result", result);
22  statusObj.pushKV("error", error);
23  return statusObj;
24 }
25 
26 static UniValue packErrorRetStatus(const std::string& nodeType, const std::string& error)
27 {
28  return packRetStatus(nodeType, "failed", error);
29 }
30 
31 static UniValue packVoteReturnValue(const UniValue& details, int success, int failed)
32 {
33  UniValue returnObj(UniValue::VOBJ);
34  returnObj.pushKV("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed));
35  returnObj.pushKV("detail", details);
36  return returnObj;
37 }
38 
39 // key, alias and collateral outpoint of a masternode. Struct used to sign proposal/budget votes
40 struct MnKeyData
41 {
42  std::string mnAlias;
44 
45  MnKeyData() = delete;
46  MnKeyData(const std::string& _mnAlias, const COutPoint* _collateralOut, const CKey& _key):
47  mnAlias(_mnAlias),
48  collateralOut(_collateralOut),
49  key(_key),
50  use_bls(false)
51  {}
52  MnKeyData(const std::string& _mnAlias, const COutPoint* _collateralOut, const CBLSSecretKey& _key):
53  mnAlias(_mnAlias),
54  collateralOut(_collateralOut),
55  blsKey(_key),
56  use_bls(true)
57  {}
58 
59  bool Sign(CSignedMessage* msg) const
60  {
61  return use_bls ? msg->Sign(blsKey)
62  : msg->Sign(key, key.GetPubKey().GetID());
63  }
64 
65 private:
68  bool use_bls; // whether to use a CKey (mbv) or blsKey (fbv, mnw) to sign
69 };
70 
71 typedef std::list<MnKeyData> mnKeyList;
72 
73 static UniValue voteProposal(const uint256& propHash, const CBudgetVote::VoteDirection& nVote,
74  const mnKeyList& mnKeys, UniValue resultsObj, int failed)
75 {
76  int success = 0;
77  for (const auto& k : mnKeys) {
78  CBudgetVote vote(CTxIn(*k.collateralOut), propHash, nVote);
79  if (!k.Sign(&vote)) {
80  resultsObj.push_back(packErrorRetStatus(k.mnAlias, "Failure to sign."));
81  failed++;
82  continue;
83  }
84  CValidationState state;
85  if (!g_budgetman.ProcessProposalVote(vote, nullptr, state)) {
86  resultsObj.push_back(packErrorRetStatus(k.mnAlias, FormatStateMessage(state)));
87  failed++;
88  continue;
89  }
90  resultsObj.push_back(packRetStatus(k.mnAlias, "success", ""));
91  success++;
92  }
93 
94  return packVoteReturnValue(resultsObj, success, failed);
95 }
96 
97 static UniValue voteFinalBudget(const uint256& budgetHash,
98  const mnKeyList& mnKeys, UniValue resultsObj, int failed)
99 {
100  int success = 0;
101  for (const auto& k : mnKeys) {
102  CFinalizedBudgetVote vote(CTxIn(*k.collateralOut), budgetHash);
103  if (!k.Sign(&vote)) {
104  resultsObj.push_back(packErrorRetStatus(k.mnAlias, "Failure to sign."));
105  failed++;
106  continue;
107  }
108  CValidationState state;
109  if (!g_budgetman.ProcessFinalizedBudgetVote(vote, nullptr, state)) {
110  resultsObj.push_back(packErrorRetStatus(k.mnAlias, FormatStateMessage(state)));
111  failed++;
112  continue;
113  }
114  resultsObj.push_back(packRetStatus(k.mnAlias, "success", ""));
115  success++;
116  }
117 
118  return packVoteReturnValue(resultsObj, success, failed);
119 }
120 
121 // Legacy masternodes
122 static mnKeyList getMNKeys(const Optional<std::string>& mnAliasFilter,
123  UniValue& resultsObj, int& failed)
124 {
125  mnKeyList mnKeys;
127  if (mnAliasFilter && *mnAliasFilter != mne.getAlias()) continue;
128  CKey mnKey; CPubKey mnPubKey;
129  const std::string& mnAlias = mne.getAlias();
130  if (!CMessageSigner::GetKeysFromSecret(mne.getPrivKey(), mnKey, mnPubKey)) {
131  resultsObj.push_back(packErrorRetStatus(mnAlias, "Could not get key from masternode.conf"));
132  failed++;
133  continue;
134  }
135  CMasternode* pmn = mnodeman.Find(mnPubKey);
136  if (!pmn) {
137  resultsObj.push_back(packErrorRetStatus(mnAlias, "Can't find masternode by pubkey"));
138  failed++;
139  continue;
140  }
141  mnKeys.emplace_back(mnAlias, &pmn->vin.prevout, mnKey);
142  }
143  return mnKeys;
144 }
145 
146 static mnKeyList getMNKeysForActiveMasternode(UniValue& resultsObj)
147 {
148  // local node must be a masternode
149  if (!fMasterNode) {
150  throw std::runtime_error(_("This is not a masternode. 'local' option disabled."));
151  }
152 
153  if (activeMasternode.vin == nullopt) {
154  throw std::runtime_error(_("Active Masternode not initialized."));
155  }
156 
157  CKey mnKey; CPubKey mnPubKey;
158  activeMasternode.GetKeys(mnKey, mnPubKey);
159  CMasternode* pmn = mnodeman.Find(mnPubKey);
160  if (!pmn) {
161  resultsObj.push_back(packErrorRetStatus("local", "Can't find masternode by pubkey"));
162  return mnKeyList();
163  }
164 
165  return {MnKeyData("local", &pmn->vin.prevout, mnKey)};
166 }
167 
168 // Deterministic masternodes
169 static mnKeyList getDMNVotingKeys(CWallet* const pwallet, const Optional<std::string>& mnAliasFilter, bool fFinal, UniValue& resultsObj, int& failed)
170 {
171  if (!pwallet) {
172  throw std::runtime_error( "Wallet (with voting key) not found.");
173  }
174 
175  auto mnList = deterministicMNManager->GetListAtChainTip();
176 
177  CDeterministicMNCPtr mnFilter{nullptr};
178  if (mnAliasFilter) {
179  // vote with a single masternode (identified by ProTx)
180  const uint256& proTxHash = uint256S(*mnAliasFilter);
181  mnFilter = mnList.GetValidMN(proTxHash);
182  if (!mnFilter) {
183  resultsObj.push_back(packErrorRetStatus(*mnAliasFilter, "Invalid or unknown proTxHash"));
184  failed++;
185  return {};
186  }
187  }
188 
189  mnKeyList mnKeys;
190  mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
191  bool filtered = mnFilter && dmn->proTxHash == mnFilter->proTxHash;
192  if (!mnFilter || filtered) {
193  if (fFinal) {
194  // We should never get here. BLS operator key (for active mn) is needed.
195  throw std::runtime_error("Finalized budget voting is allowed only locally, from the masternode");
196  }
197  // Get voting key from the wallet
198  LOCK(pwallet->cs_wallet);
199  CKey mnKey;
200  if (pwallet->GetKey(dmn->pdmnState->keyIDVoting, mnKey)) {
201  mnKeys.emplace_back(dmn->proTxHash.ToString(), &dmn->collateralOutpoint, mnKey);
202  } else if (filtered) {
203  resultsObj.push_back(packErrorRetStatus(*mnAliasFilter, strprintf(
204  "Private key for voting address %s not known by this wallet",
205  EncodeDestination(dmn->pdmnState->keyIDVoting)))
206  );
207  failed++;
208  }
209  }
210  });
211 
212  return mnKeys;
213 }
214 
215 static mnKeyList getDMNKeysForActiveMasternode(UniValue& resultsObj)
216 {
217  // local node must be a masternode
219  throw std::runtime_error(_("This is not a deterministic masternode. 'local' option disabled."));
220  }
221 
223  auto res = activeMasternodeManager->GetOperatorKey(sk, dmn);
224  if (!res) {
225  resultsObj.push_back(packErrorRetStatus("local", res.getError()));
226  return {};
227  }
228 
229  return {MnKeyData("local", &dmn->collateralOutpoint, sk)};
230 }
231 
232 // vote on proposal (finalized budget, if fFinal=true) with all possible keys or a single mn (mnAliasFilter)
233 // Note: for DMNs only proposal voting is allowed with the voting key
234 // (finalized budget voting requires the operator BLS key)
235 UniValue mnBudgetVoteInner(CWallet* const pwallet, bool fLegacyMN, const uint256& budgetHash, bool fFinal,
236  const CBudgetVote::VoteDirection& nVote, const Optional<std::string>& mnAliasFilter)
237 {
238  if (fFinal && !fLegacyMN) {
239  throw std::runtime_error("Finalized budget voting is allowed only locally, from the masternode");
240  }
241  UniValue resultsObj(UniValue::VARR);
242  int failed = 0;
243 
244  mnKeyList mnKeys = fLegacyMN ? getMNKeys(mnAliasFilter, resultsObj, failed)
245  : getDMNVotingKeys(pwallet, mnAliasFilter, fFinal, resultsObj, failed);
246 
247  if (mnKeys.empty()) {
248  return packVoteReturnValue(resultsObj, 0, failed);
249  }
250 
251  return (fFinal ? voteFinalBudget(budgetHash, mnKeys, resultsObj, failed)
252  : voteProposal(budgetHash, nVote, mnKeys, resultsObj, failed));
253 }
254 
255 // vote on proposal (finalized budget, if fFinal=true) with the active local masternode
256 // Note: for DMNs only finalized budget voting is allowed with the operator key
257 // (proposal voting requires the voting key)
258 UniValue mnLocalBudgetVoteInner(bool fLegacyMN, const uint256& budgetHash, bool fFinal,
259  const CBudgetVote::VoteDirection& nVote)
260 {
261  UniValue resultsObj(UniValue::VARR);
262 
263  mnKeyList mnKeys = fLegacyMN ? getMNKeysForActiveMasternode(resultsObj)
264  : getDMNKeysForActiveMasternode(resultsObj);
265 
266  if (mnKeys.empty()) {
267  return packVoteReturnValue(resultsObj, 0, 1);
268  }
269 
270  return (fFinal ? voteFinalBudget(budgetHash, mnKeys, resultsObj, 0)
271  : voteProposal(budgetHash, nVote, mnKeys, resultsObj, 0));
272 }
CActiveDeterministicMasternodeManager * activeMasternodeManager
true
Definition: bls_dkg.cpp:153
false
Definition: bls_dkg.cpp:151
CBudgetManager g_budgetman
std::list< MnKeyData > mnKeyList
Definition: budgetutil.cpp:71
UniValue mnBudgetVoteInner(CWallet *const pwallet, bool fLegacyMN, const uint256 &budgetHash, bool fFinal, const CBudgetVote::VoteDirection &nVote, const Optional< std::string > &mnAliasFilter)
Definition: budgetutil.cpp:235
UniValue mnLocalBudgetVoteInner(bool fLegacyMN, const uint256 &budgetHash, bool fFinal, const CBudgetVote::VoteDirection &nVote)
Definition: budgetutil.cpp:258
OperationResult GetOperatorKey(CBLSSecretKey &key, CDeterministicMNCPtr &dmn) const
Optional< CTxIn > vin
void GetKeys(CKey &privKeyMasternode, CPubKey &pubKeyMasternode) const
bool ProcessProposalVote(CBudgetVote &proposal, CNode *pfrom, CValidationState &state)
bool ProcessFinalizedBudgetVote(CFinalizedBudgetVote &vote, CNode *pfrom, CValidationState &state)
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: crypter.cpp:199
An encapsulated private key.
Definition: key.h:30
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
std::vector< CMasternodeEntry > getEntries()
CTxIn vin
Definition: masternode.h:96
CMasternode * Find(const COutPoint &collateralOut)
Find an entry.
static bool GetKeysFromSecret(const std::string &strSecret, CKey &keyRet, CPubKey &pubkeyRet)
Set the private/public key values, returns true if successful.
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:72
An encapsulated public key.
Definition: pubkey.h:44
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
Base Class for all signed messages on the network.
Definition: messagesigner.h:63
bool Sign(const CKey &key, const CKeyID &keyID)
CSignedMessage Class Functions inherited by network signed-messages.
An input of a transaction.
Definition: transaction.h:94
COutPoint prevout
Definition: transaction.h:96
Capture information about block/transaction validation.
Definition: validation.h:24
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:577
RecursiveMutex cs_wallet
Definition: wallet.h:720
@ VOBJ
Definition: univalue.h:21
@ VARR
Definition: univalue.h:21
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
@ LOCK
Definition: lockunlock.h:16
CMasternodeConfig masternodeConfig
CMasternodeMan mnodeman
Masternode manager.
CActiveMasternode activeMasternode
Keep track of the active Masternode.
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
@ proTxHash
Definition: rpcevo.cpp:50
std::string mnAlias
Definition: budgetutil.cpp:42
MnKeyData(const std::string &_mnAlias, const COutPoint *_collateralOut, const CBLSSecretKey &_key)
Definition: budgetutil.cpp:52
const COutPoint * collateralOut
Definition: budgetutil.cpp:43
bool Sign(CSignedMessage *msg) const
Definition: budgetutil.cpp:59
MnKeyData()=delete
CBLSSecretKey blsKey
Definition: budgetutil.cpp:67
MnKeyData(const std::string &_mnAlias, const COutPoint *_collateralOut, const CKey &_key)
Definition: budgetutil.cpp:46
bool use_bls
Definition: budgetutil.cpp:68
std::atomic< bool > fMasterNode
Definition: system.cpp:87
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a Optional result.
Definition: system.h:65
#define strprintf
Definition: tinyformat.h:1056
uint256 uint256S(const char *str)
Definition: uint256.h:157
std::string FormatStateMessage(const CValidationState &state)
Convert CValidationState to a human-readable message for logging.
Definition: validation.cpp:13