PIVX Core  5.6.99
P2P Digital Currency
budget.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2015 The Dash developers
2 // Copyright (c) 2015-2022 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "chainparams.h"
7 #include "budget/budgetmanager.h"
8 #include "budget/budgetutil.h"
9 #include "db.h"
10 #include "evo/deterministicmns.h"
11 #include "key_io.h"
12 #include "masternode-payments.h"
13 #include "masternode-sync.h"
14 #include "masternodeconfig.h"
15 #include "masternodeman.h"
16 #include "messagesigner.h"
18 #include "rpc/server.h"
19 #include "utilmoneystr.h"
20 #ifdef ENABLE_WALLET
21 #include "wallet/wallet.h"
22 #include "wallet/rpcwallet.h"
23 #endif
24 
25 #include <univalue.h>
26 
27 void budgetToJSON(const CBudgetProposal* pbudgetProposal, UniValue& bObj, int nCurrentHeight)
28 {
29  CTxDestination address1;
30  ExtractDestination(pbudgetProposal->GetPayee(), address1);
31 
32  bObj.pushKV("Name", pbudgetProposal->GetName());
33  bObj.pushKV("URL", pbudgetProposal->GetURL());
34  bObj.pushKV("Hash", pbudgetProposal->GetHash().ToString());
35  bObj.pushKV("FeeHash", pbudgetProposal->GetFeeTXHash().ToString());
36  bObj.pushKV("BlockStart", (int64_t)pbudgetProposal->GetBlockStart());
37  bObj.pushKV("BlockEnd", (int64_t)pbudgetProposal->GetBlockEnd());
38  bObj.pushKV("TotalPaymentCount", (int64_t)pbudgetProposal->GetTotalPaymentCount());
39  bObj.pushKV("RemainingPaymentCount", (int64_t)pbudgetProposal->GetRemainingPaymentCount(nCurrentHeight));
40  bObj.pushKV("PaymentAddress", EncodeDestination(address1));
41  bObj.pushKV("Ratio", pbudgetProposal->GetRatio());
42  bObj.pushKV("Yeas", (int64_t)pbudgetProposal->GetYeas());
43  bObj.pushKV("Nays", (int64_t)pbudgetProposal->GetNays());
44  bObj.pushKV("Abstains", (int64_t)pbudgetProposal->GetAbstains());
45  bObj.pushKV("TotalPayment", ValueFromAmount(pbudgetProposal->GetAmount() * pbudgetProposal->GetTotalPaymentCount()));
46  bObj.pushKV("MonthlyPayment", ValueFromAmount(pbudgetProposal->GetAmount()));
47  bObj.pushKV("IsEstablished", pbudgetProposal->IsEstablished());
48  bool fValid = pbudgetProposal->IsValid();
49  bObj.pushKV("IsValid", fValid);
50  if (!fValid)
51  bObj.pushKV("IsInvalidReason", pbudgetProposal->IsInvalidReason());
52  bObj.pushKV("Allotted", ValueFromAmount(pbudgetProposal->GetAllotted()));
53 }
54 
55 void checkBudgetInputs(const UniValue& params, std::string &strProposalName, std::string &strURL,
56  int &nPaymentCount, int &nBlockStart, CTxDestination &address, CAmount &nAmount)
57 {
58  strProposalName = SanitizeString(params[0].get_str());
59  if (strProposalName.size() > 20)
60  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal name, limit of 20 characters.");
61 
62  strURL = SanitizeString(params[1].get_str());
63  std::string strErr;
64  if (!validateURL(strURL, strErr))
65  throw JSONRPCError(RPC_INVALID_PARAMETER, strErr);
66 
67  nPaymentCount = params[2].get_int();
68  if (nPaymentCount < 1)
69  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid payment count, must be more than zero.");
70 
71  int nMaxPayments = Params().GetConsensus().nMaxProposalPayments;
72  if (nPaymentCount > nMaxPayments) {
74  strprintf("Invalid payment count, must be <= %d", nMaxPayments));
75  }
76 
77  CBlockIndex* pindexPrev = GetChainTip();
78  if (!pindexPrev)
79  throw JSONRPCError(RPC_IN_WARMUP, "Try again after active chain is loaded");
80 
81  // Start must be in the next budget cycle or later
82  const int budgetCycleBlocks = Params().GetConsensus().nBudgetCycleBlocks;
83  int pHeight = pindexPrev->nHeight;
84 
85  int nBlockMin = pHeight - (pHeight % budgetCycleBlocks) + budgetCycleBlocks;
86 
87  nBlockStart = params[3].get_int();
88  if ((nBlockStart < nBlockMin) || ((nBlockStart % budgetCycleBlocks) != 0))
89  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nBlockMin));
90 
91  address = DecodeDestination(params[4].get_str());
92  if (!IsValidDestination(address))
93  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
94 
95  nAmount = AmountFromValue(params[5]);
96  if (nAmount < 10 * COIN)
97  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid amount - Payment of %s is less than minimum 10 %s allowed", FormatMoney(nAmount), CURRENCY_UNIT));
98 
99  const CAmount& nTotalBudget = g_budgetman.GetTotalBudget(nBlockStart);
100  if (nAmount > nTotalBudget)
101  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid amount - Payment of %s more than max of %s", FormatMoney(nAmount), FormatMoney(nTotalBudget)));
102 }
103 
105 {
106  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
107 
108  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
109  return NullUniValue;
110 
111  if (request.fHelp || request.params.size() != 6)
112  throw std::runtime_error(
113  "preparebudget \"name\" \"url\" npayments start \"address\" monthly_payment\n"
114  "\nPrepare proposal for network by signing and creating tx\n"
115 
116  "\nArguments:\n"
117  "1. \"name\": (string, required) Desired proposal name (20 character limit)\n"
118  "2. \"url\": (string, required) URL of proposal details (64 character limit)\n"
119  "3. npayments: (numeric, required) Total number of monthly payments\n"
120  "4. start: (numeric, required) Starting super block height\n"
121  "5. \"address\": (string, required) PIVX address to send payments to\n"
122  "6. monthly_payment: (numeric, required) Monthly payment amount\n"
123 
124  "\nResult:\n"
125  "\"xxxx\" (string) proposal fee hash (if successful) or error message (if failed)\n"
126 
127  "\nExamples:\n" +
128  HelpExampleCli("preparebudget", "\"test-proposal\" \"https://forum.pivx.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") +
129  HelpExampleRpc("preparebudget", "\"test-proposal\" \"https://forum.pivx.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500"));
130 
131  LOCK2(cs_main, pwallet->cs_wallet);
132 
133  EnsureWalletIsUnlocked(pwallet);
134 
135  std::string strProposalName;
136  std::string strURL;
137  int nPaymentCount;
138  int nBlockStart;
139  CTxDestination address;
140  CAmount nAmount;
141 
142  checkBudgetInputs(request.params, strProposalName, strURL, nPaymentCount, nBlockStart, address, nAmount);
143 
144  // Parse PIVX address
145  CScript scriptPubKey = GetScriptForDestination(address);
146 
147  // create transaction 15 minutes into the future, to allow for confirmation time
148  CBudgetProposal proposal(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, UINT256_ZERO);
149  const uint256& nHash = proposal.GetHash();
150  if (!proposal.IsWellFormed(g_budgetman.GetTotalBudget(proposal.GetBlockStart())))
151  throw std::runtime_error("Proposal is not valid " + proposal.IsInvalidReason());
152 
153  CTransactionRef wtx;
154  // make our change address
155  CReserveKey keyChange(pwallet);
156  if (!pwallet->CreateBudgetFeeTX(wtx, nHash, keyChange, BUDGET_FEE_TX_OLD)) { // 50 PIV collateral for proposal
157  throw std::runtime_error("Error making collateral transaction for proposal. Please check your wallet balance.");
158  }
159 
160  //send the tx to the network
161  const CWallet::CommitResult& res = pwallet->CommitTransaction(wtx, keyChange, g_connman.get());
163  throw JSONRPCError(RPC_WALLET_ERROR, res.ToString());
164 
165  // Store proposal name as a comment
166  auto it = pwallet->mapWallet.find(wtx->GetHash());
167  assert(it != pwallet->mapWallet.end());
168  it->second.SetComment("Proposal: " + strProposalName);
169 
170  return wtx->GetHash().ToString();
171 }
172 
174 {
175  if (request.fHelp || request.params.size() != 7)
176  throw std::runtime_error(
177  "submitbudget \"name\" \"url\" npayments start \"address\" monthly_payment \"fee_txid\"\n"
178  "\nSubmit proposal to the network\n"
179 
180  "\nArguments:\n"
181  "1. \"name\": (string, required) Desired proposal name (20 character limit)\n"
182  "2. \"url\": (string, required) URL of proposal details (64 character limit)\n"
183  "3. npayments: (numeric, required) Total number of monthly payments\n"
184  "4. start: (numeric, required) Starting super block height\n"
185  "5. \"address\": (string, required) PIVX address to send payments to\n"
186  "6. monthly_payment: (numeric, required) Monthly payment amount\n"
187  "7. \"fee_txid\": (string, required) Transaction hash from preparebudget command\n"
188 
189  "\nResult:\n"
190  "\"xxxx\" (string) proposal hash (if successful) or error message (if failed)\n"
191 
192  "\nExamples:\n" +
193  HelpExampleCli("submitbudget", "\"test-proposal\" \"https://forum.pivx.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") +
194  HelpExampleRpc("submitbudget", "\"test-proposal\" \"https://forum.pivx.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500"));
195 
196  std::string strProposalName;
197  std::string strURL;
198  int nPaymentCount;
199  int nBlockStart;
200  CTxDestination address;
201  CAmount nAmount;
202 
203  checkBudgetInputs(request.params, strProposalName, strURL, nPaymentCount, nBlockStart, address, nAmount);
204 
205  // Parse PIVX address
206  CScript scriptPubKey = GetScriptForDestination(address);
207  const uint256& hash = ParseHashV(request.params[6], "parameter 1");
208 
210  throw std::runtime_error("Must wait for client to sync with masternode network. Try again in a minute or so.");
211  }
212 
213  // create the proposal in case we're the first to make it
214  CBudgetProposal proposal(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, hash);
215  if(!g_budgetman.AddProposal(proposal)) {
216  std::string strError = strprintf("invalid budget proposal - %s", proposal.IsInvalidReason());
217  throw std::runtime_error(strError);
218  }
219  proposal.Relay();
220 
221  return proposal.GetHash().ToString();
222 }
223 
224 static CBudgetVote::VoteDirection parseVote(const std::string& strVote)
225 {
226  if (strVote != "yes" && strVote != "no") throw JSONRPCError(RPC_MISC_ERROR, "You can only vote 'yes' or 'no'");
228  if (strVote == "yes") nVote = CBudgetVote::VOTE_YES;
229  if (strVote == "no") nVote = CBudgetVote::VOTE_NO;
230  return nVote;
231 }
232 
234 {
235  std::string strCommand;
236  if (request.params.size() >= 1) {
237  strCommand = request.params[0].get_str();
238 
239  // Backwards compatibility with legacy `mnbudget` command
240  if (strCommand == "vote") strCommand = "local";
241  if (strCommand == "vote-many") strCommand = "many";
242  if (strCommand == "vote-alias") strCommand = "alias";
243  }
244 
245  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
246 
247  if (request.fHelp || (request.params.size() == 3 && (strCommand != "local" && strCommand != "many")) || (request.params.size() == 4 && strCommand != "alias") ||
248  request.params.size() > 5 || request.params.size() < 3)
249  throw std::runtime_error(
250  "mnbudgetvote \"local|many|alias\" \"hash\" \"yes|no\" ( \"alias\" legacy )\n"
251  "\nVote on a budget proposal\n"
252  "\nAfter V6 enforcement, the deterministic masternode system is used by default. Set the \"legacy\" parameter to true to vote with legacy masternodes."
253 
254  "\nArguments:\n"
255  "1. \"mode\" (string, required) The voting mode. 'local' for voting directly from a masternode, 'many' for voting with a MN controller and casting the same vote for each MN, 'alias' for voting with a MN controller and casting a vote for a single MN\n"
256  "2. \"hash\" (string, required) The budget proposal hash\n"
257  "3. \"votecast\" (string, required) Your vote. 'yes' to vote for the proposal, 'no' to vote against\n"
258  "4. \"alias\" (string, required for 'alias' mode) The MN alias to cast a vote for (for deterministic masternodes it's the hash of the proTx transaction).\n"
259  "5. \"legacy\" (boolean, optional, default=false) Use the legacy masternode system after deterministic masternodes enforcement.\n"
260 
261  "\nResult:\n"
262  "{\n"
263  " \"overall\": \"xxxx\", (string) The overall status message for the vote cast\n"
264  " \"detail\": [\n"
265  " {\n"
266  " \"node\": \"xxxx\", (string) 'local' or the MN alias\n"
267  " \"result\": \"xxxx\", (string) Either 'Success' or 'Failed'\n"
268  " \"error\": \"xxxx\", (string) Error message, if vote failed\n"
269  " }\n"
270  " ,...\n"
271  " ]\n"
272  "}\n"
273 
274  "\nExamples:\n" +
275  HelpExampleCli("mnbudgetvote", "\"alias\" \"ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041\" \"yes\" \"4f9de28fca1f0574a217c5d3c59cc51125ec671de82a2f80b6ceb69673115041\"") +
276  HelpExampleRpc("mnbudgetvote", "\"alias\" \"ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041\" \"yes\" \"4f9de28fca1f0574a217c5d3c59cc51125ec671de82a2f80b6ceb69673115041\""));
277 
278  const uint256& hash = ParseHashV(request.params[1], "parameter 1");
279  CBudgetVote::VoteDirection nVote = parseVote(request.params[2].get_str());
280 
281  bool fLegacyMN = !deterministicMNManager->IsDIP3Enforced() || (request.params.size() > 4 && request.params[4].get_bool());
282 
283  if (strCommand == "local") {
284  if (!fLegacyMN) {
285  throw JSONRPCError(RPC_MISC_ERROR, _("\"local\" vote is no longer available with DMNs. Use \"alias\" from the wallet with the voting key."));
286  }
287  return mnLocalBudgetVoteInner(true, hash, false, nVote);
288  }
289 
290  // DMN require wallet with voting key
291  if (!fLegacyMN) {
292  if (!EnsureWalletIsAvailable(pwallet, false)) {
293  return NullUniValue;
294  }
295  EnsureWalletIsUnlocked(pwallet);
296  }
297 
298  bool isAlias = false;
299  if (strCommand == "many" || (isAlias = strCommand == "alias")) {
300  Optional<std::string> mnAlias = isAlias ? Optional<std::string>(request.params[3].get_str()) : nullopt;
301  return mnBudgetVoteInner(pwallet, fLegacyMN, hash, false, nVote, mnAlias);
302  }
303 
304  return NullUniValue;
305 }
306 
308 {
309  if (request.params.size() != 1)
310  throw std::runtime_error(
311  "getbudgetvotes \"name\"\n"
312  "\nPrint vote information for a budget proposal\n"
313 
314  "\nArguments:\n"
315  "1. \"name\": (string, required) Name of the proposal\n"
316 
317  "\nResult:\n"
318  "[\n"
319  " {\n"
320  " \"mnId\": \"xxxx-x\", (string) Masternode's outpoint collateral transaction (hash-n)\n"
321  " \"nHash\": \"xxxx\", (string) Hash of the vote\n"
322  " \"Vote\": \"YES|NO\", (string) Vote cast ('YES' or 'NO')\n"
323  " \"nTime\": xxxx, (numeric) Time in seconds since epoch the vote was cast\n"
324  " \"fValid\": true|false, (boolean) 'true' if the vote is valid, 'false' otherwise\n"
325  " }\n"
326  " ,...\n"
327  "]\n"
328 
329  "\nExamples:\n" +
330  HelpExampleCli("getbudgetvotes", "\"test-proposal\"") + HelpExampleRpc("getbudgetvotes", "\"test-proposal\""));
331 
332  std::string strProposalName = SanitizeString(request.params[0].get_str());
333  const CBudgetProposal* pbudgetProposal = g_budgetman.FindProposalByName(strProposalName);
334  if (pbudgetProposal == nullptr) throw std::runtime_error("Unknown proposal name");
335  return pbudgetProposal->GetVotesArray();
336 }
337 
339 {
340  if (request.fHelp || request.params.size() != 0)
341  throw std::runtime_error(
342  "getnextsuperblock\n"
343  "\nPrint the next super block height\n"
344 
345  "\nResult:\n"
346  "n (numeric) Block height of the next super block\n"
347 
348  "\nExamples:\n" +
349  HelpExampleCli("getnextsuperblock", "") + HelpExampleRpc("getnextsuperblock", ""));
350 
351  int nChainHeight = WITH_LOCK(cs_main, return chainActive.Height());
352  if (nChainHeight < 0) return "unknown";
353 
354  const int nBlocksPerCycle = Params().GetConsensus().nBudgetCycleBlocks;
355  int nNext = nChainHeight - nChainHeight % nBlocksPerCycle + nBlocksPerCycle;
356  return nNext;
357 }
358 
360 {
361  if (request.fHelp || request.params.size() != 0)
362  throw std::runtime_error(
363  "getbudgetprojection\n"
364  "\nShow the projection of which proposals will be paid the next cycle\n"
365  "Proposal fee tx time need to be +24hrs old from the current time. (Testnet is 5 mins)\n"
366  "Net Votes needs to be above Masternode Count divided by 10\n"
367 
368  "\nResult:\n"
369  "[\n"
370  " {\n"
371  " \"Name\": \"xxxx\", (string) Proposal Name\n"
372  " \"URL\": \"xxxx\", (string) Proposal URL\n"
373  " \"Hash\": \"xxxx\", (string) Proposal vote hash\n"
374  " \"FeeHash\": \"xxxx\", (string) Proposal fee hash\n"
375  " \"BlockStart\": n, (numeric) Proposal starting block\n"
376  " \"BlockEnd\": n, (numeric) Proposal ending block\n"
377  " \"TotalPaymentCount\": n, (numeric) Number of payments\n"
378  " \"RemainingPaymentCount\": n, (numeric) Number of remaining payments\n"
379  " \"PaymentAddress\": \"xxxx\", (string) PIVX address of payment\n"
380  " \"Ratio\": x.xxx, (numeric) Ratio of yeas vs nays\n"
381  " \"Yeas\": n, (numeric) Number of yea votes\n"
382  " \"Nays\": n, (numeric) Number of nay votes\n"
383  " \"Abstains\": n, (numeric) Number of abstains\n"
384  " \"TotalPayment\": xxx.xxx, (numeric) Total payment amount in PIV\n"
385  " \"MonthlyPayment\": xxx.xxx, (numeric) Monthly payment amount in PIV\n"
386  " \"IsEstablished\": true|false, (boolean) Proposal is considered established, 24 hrs after being submitted to network. (Testnet is 5 mins)\n"
387  " \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
388  " \"IsInvalidReason\": \"xxxx\", (string) Error message, if any\n"
389  " \"Allotted\": xxx.xxx, (numeric) Amount of PIV allotted in current period\n"
390  " \"TotalBudgetAllotted\": xxx.xxx (numeric) Total PIV allotted\n"
391  " }\n"
392  " ,...\n"
393  "]\n"
394 
395  "\nExamples:\n" +
396  HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", ""));
397 
399  UniValue resultObj(UniValue::VOBJ);
400  CAmount nTotalAllotted = 0;
401 
402  std::vector<CBudgetProposal> winningProps = g_budgetman.GetBudget();
403  for (const CBudgetProposal& p : winningProps) {
404  UniValue bObj(UniValue::VOBJ);
406  nTotalAllotted += p.GetAllotted();
407  bObj.pushKV("TotalBudgetAllotted", ValueFromAmount(nTotalAllotted));
408  ret.push_back(bObj);
409  }
410 
411  return ret;
412 }
413 
415 {
416  if (request.fHelp || request.params.size() > 1)
417  throw std::runtime_error(
418  "getbudgetinfo ( \"name\" )\n"
419  "\nShow current masternode budgets\n"
420 
421  "\nArguments:\n"
422  "1. \"name\" (string, optional) Proposal name\n"
423 
424  "\nResult:\n"
425  "[\n"
426  " {\n"
427  " \"Name\": \"xxxx\", (string) Proposal Name\n"
428  " \"URL\": \"xxxx\", (string) Proposal URL\n"
429  " \"Hash\": \"xxxx\", (string) Proposal vote hash\n"
430  " \"FeeHash\": \"xxxx\", (string) Proposal fee hash\n"
431  " \"BlockStart\": n, (numeric) Proposal starting block\n"
432  " \"BlockEnd\": n, (numeric) Proposal ending block\n"
433  " \"TotalPaymentCount\": n, (numeric) Number of payments\n"
434  " \"RemainingPaymentCount\": n, (numeric) Number of remaining payments\n"
435  " \"PaymentAddress\": \"xxxx\", (string) PIVX address of payment\n"
436  " \"Ratio\": x.xxx, (numeric) Ratio of yeas vs nays\n"
437  " \"Yeas\": n, (numeric) Number of yea votes\n"
438  " \"Nays\": n, (numeric) Number of nay votes\n"
439  " \"Abstains\": n, (numeric) Number of abstains\n"
440  " \"TotalPayment\": xxx.xxx, (numeric) Total payment amount in PIV\n"
441  " \"MonthlyPayment\": xxx.xxx, (numeric) Monthly payment amount in PIV\n"
442  " \"IsEstablished\": true|false, (boolean) Proposal is considered established, 24 hrs after being submitted to network. (5 mins for Testnet)\n"
443  " \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
444  " \"IsInvalidReason\": \"xxxx\", (string) Error message, if any\n"
445  " }\n"
446  " ,...\n"
447  "]\n"
448 
449  "\nExamples:\n" +
450  HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", ""));
451 
453  int nCurrentHeight = g_budgetman.GetBestHeight();
454 
455  if (request.params.size() == 1) {
456  std::string strProposalName = SanitizeString(request.params[0].get_str());
457  const CBudgetProposal* pbudgetProposal = g_budgetman.FindProposalByName(strProposalName);
458  if (pbudgetProposal == nullptr) throw std::runtime_error("Unknown proposal name");
459  UniValue bObj(UniValue::VOBJ);
460  budgetToJSON(pbudgetProposal, bObj, nCurrentHeight);
461  ret.push_back(bObj);
462  return ret;
463  }
464 
465  std::vector<CBudgetProposal*> winningProps = g_budgetman.GetAllProposalsOrdered();
466  for (CBudgetProposal* pbudgetProposal : winningProps) {
467  if (!pbudgetProposal->IsValid()) continue;
468 
469  UniValue bObj(UniValue::VOBJ);
470  budgetToJSON(pbudgetProposal, bObj, nCurrentHeight);
471  ret.push_back(bObj);
472  }
473 
474  return ret;
475 }
476 
478 {
479  if (request.fHelp || request.params.size() != 6)
480  throw std::runtime_error(
481  "mnbudgetrawvote \"collat_txid\" collat_vout \"hash\" votecast time \"sig\"\n"
482  "\nCompile and relay a proposal vote with provided external signature instead of signing vote internally\n"
483 
484  "\nArguments:\n"
485  "1. \"collat_txid\" (string, required) Transaction hash for the masternode collateral\n"
486  "2. collat_vout (numeric, required) Output index for the masternode collateral\n"
487  "3. \"hash\" (string, required) Budget Proposal hash\n"
488  "4. \"votecast\" (string, required) Your vote. 'yes' to vote for the proposal, 'no' to vote against\n"
489  "5. time (numeric, required) Time since epoch in seconds\n"
490  "6. \"sig\" (string, required) External signature\n"
491 
492  "\nResult:\n"
493  "\"status\" (string) Vote status or error message\n"
494 
495  "\nExamples:\n" +
496  HelpExampleCli("mnbudgetrawvote", "") + HelpExampleRpc("mnbudgetrawvote", ""));
497 
498  const uint256& hashMnTx = ParseHashV(request.params[0], "mn tx hash");
499  int nMnTxIndex = request.params[1].get_int();
500  const CTxIn& vin = CTxIn(hashMnTx, nMnTxIndex);
501 
502  const uint256& hashProposal = ParseHashV(request.params[2], "Proposal hash");
503  CBudgetVote::VoteDirection nVote = parseVote(request.params[3].get_str());
504 
505  int64_t nTime = request.params[4].get_int64();
506  std::string strSig = request.params[5].get_str();
507  bool fInvalid = false;
508  std::vector<unsigned char> vchSig = DecodeBase64(strSig.c_str(), &fInvalid);
509 
510  if (fInvalid)
511  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
512 
513  CMasternode* pmn = mnodeman.Find(vin.prevout);
514  if (!pmn) {
515  return "Failure to find masternode in list : " + vin.ToString();
516  }
517 
518  CBudgetVote vote(vin, hashProposal, nVote);
519  vote.SetTime(nTime);
520  vote.SetVchSig(vchSig);
521 
522  if (!vote.CheckSignature(pmn->pubKeyMasternode.GetID())) {
523  return "Failure to verify signature.";
524  }
525 
526  std::string strError;
527  if (g_budgetman.AddAndRelayProposalVote(vote, strError)) {
528  return "Voted successfully";
529  } else {
530  return "Error voting : " + strError;
531  }
532 }
533 
535 {
536  if (request.fHelp || !request.params.empty())
537  throw std::runtime_error(
538  "mnfinalbudgetsuggest\n"
539  "\nTry to submit a budget finalization\n"
540  "returns the budget hash if it was broadcasted successfully");
541 
542  if (!Params().IsRegTestNet()) {
543  throw JSONRPCError(RPC_MISC_ERROR, "command available only for RegTest network");
544  }
545 
546  const uint256& budgetHash = g_budgetman.SubmitFinalBudget();
547  return (budgetHash.IsNull()) ? NullUniValue : budgetHash.ToString();
548 }
549 
551 {
552  if (request.fHelp || request.params.size() > 4)
553  throw std::runtime_error(
554  "createrawmnfinalbudget\n"
555  "\nTry to submit the raw budget finalization\n"
556  "returns the budget hash if it was broadcasted successfully"
557  "\nArguments:\n"
558  "1. \"budgetname\" (string, required) finalization name\n"
559  "2. \"blockstart\" (numeric, required) superblock height\n"
560  "3. \"proposals\" (string, required) A json array of json objects\n"
561  " [\n"
562  " {\n"
563  " \"proposalid\":\"id\", (string, required) The proposal id\n"
564  " \"payee\":n, (hex, required) The payee script\n"
565  " \"amount\":n (numeric, optional) The payee amount\n"
566  " }\n"
567  " ,...\n"
568  " ]\n"
569  "4. \"feetxid\" (string, optional) the transaction fee hash\n"
570  ""
571  "\nResult:\n"
572  "{\n"
573  "\"result\" (string) Budget suggest broadcast or error\n"
574  "\"id\" (string) id of the fee tx or the finalized budget\n"
575  "}\n"
576  ); // future: add examples.
577 
578  if (!Params().IsRegTestNet()) {
579  throw JSONRPCError(RPC_MISC_ERROR, "command available only for RegTest network");
580  }
581 
582  // future: add inputs error checking..
583  std::string budName = request.params[0].get_str();
584  int nBlockStart = request.params[1].get_int();
585  std::vector<CTxBudgetPayment> vecTxBudgetPayments;
586  UniValue budgetVec = request.params[2].get_array();
587  for (unsigned int idx = 0; idx < budgetVec.size(); idx++) {
588  const UniValue& prop = budgetVec[idx].get_obj();
589  uint256 propId = ParseHashO(prop, "proposalid");
590  std::vector<unsigned char> scriptData(ParseHexO(prop, "payee"));
591  CScript payee = CScript(scriptData.begin(), scriptData.end());
592  CAmount amount = AmountFromValue(find_value(prop, "amount"));
593  vecTxBudgetPayments.emplace_back(propId, payee, amount);
594  }
595 
596  Optional<uint256> txFeeId = nullopt;
597  if (request.params.size() > 3) {
598  txFeeId = ParseHashV(request.params[3], "parameter 4");
599  }
600 
601  if (!txFeeId) {
602  CFinalizedBudget tempBudget(budName, nBlockStart, vecTxBudgetPayments, UINT256_ZERO);
603  const uint256& budgetHash = tempBudget.GetHash();
604 
605  // create fee tx
606  CTransactionRef wtx;
607  CReserveKey keyChange(vpwallets[0]);
608  if (!vpwallets[0]->CreateBudgetFeeTX(wtx, budgetHash, keyChange, BUDGET_FEE_TX)) {
609  throw std::runtime_error("Can't make collateral transaction");
610  }
611  // Send the tx to the network
612  const CWallet::CommitResult& res = vpwallets[0]->CommitTransaction(wtx, keyChange, g_connman.get());
614  if (res.status == CWallet::CommitStatus::OK) {
615  ret.pushKV("result", "tx_fee_sent");
616  ret.pushKV("id", wtx->GetHash().ToString());
617  } else {
618  ret.pushKV("result", "error");
619  }
620  return ret;
621  }
622 
624  // Collateral tx already exists, see if it's mature enough.
625  CFinalizedBudget fb(budName, nBlockStart, vecTxBudgetPayments, *txFeeId);
627  fb.Relay();
628  ret.pushKV("result", "fin_budget_sent");
629  ret.pushKV("id", fb.GetHash().ToString());
630  } else {
631  // future: add proper error
632  ret.pushKV("result", "error");
633  }
634  return ret;
635 }
636 
638 {
639  std::string strCommand;
640  if (request.params.size() >= 1)
641  strCommand = request.params[0].get_str();
642 
643  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
644 
645  if (request.fHelp ||
646  (strCommand != "vote-many" && strCommand != "vote" && strCommand != "show" && strCommand != "getvotes"))
647  throw std::runtime_error(
648  "mnfinalbudget \"command\"... ( \"passphrase\" )\n"
649  "\nVote or show current budgets\n"
650 
651  "\nAvailable commands:\n"
652  " vote-many - Vote on a finalized budget\n"
653  " vote - Vote on a finalized budget with local masternode\n"
654  " show - Show existing finalized budgets\n"
655  " getvotes - Get vote information for each finalized budget\n");
656 
657  if (strCommand == "vote-many" || strCommand == "vote") {
658  if (request.params.size() < 2 || request.params.size() > 3) {
659  throw std::runtime_error(strprintf("Correct usage is 'mnfinalbudget %s BUDGET_HASH (fLegacy)'", strCommand));
660  }
661  const uint256& hash = ParseHashV(request.params[1], "BUDGET_HASH");
662  bool fLegacyMN = !deterministicMNManager->IsDIP3Enforced() || (request.params.size() > 2 && request.params[2].get_bool());
663 
664  // DMN require wallet with operator keys for vote-many
665  if (!fLegacyMN && strCommand == "vote-many" && !EnsureWalletIsAvailable(pwallet, false)) {
666  return NullUniValue;
667  }
668 
669  return (strCommand == "vote-many" ? mnBudgetVoteInner(pwallet, fLegacyMN, hash, true, CBudgetVote::VOTE_YES, nullopt)
670  : mnLocalBudgetVoteInner(fLegacyMN, hash, true, CBudgetVote::VOTE_YES));
671  }
672 
673  if (strCommand == "show") {
674  UniValue resultObj(UniValue::VOBJ);
675 
676  std::vector<CFinalizedBudget*> winningFbs = g_budgetman.GetFinalizedBudgets();
677  for (CFinalizedBudget* finalizedBudget : winningFbs) {
678  const uint256& nHash = finalizedBudget->GetHash();
679  UniValue bObj(UniValue::VOBJ);
680  bObj.pushKV("FeeTX", finalizedBudget->GetFeeTXHash().ToString());
681  bObj.pushKV("BlockStart", (int64_t)finalizedBudget->GetBlockStart());
682  bObj.pushKV("BlockEnd", (int64_t)finalizedBudget->GetBlockEnd());
683  bObj.pushKV("Proposals", finalizedBudget->GetProposalsStr());
684  bObj.pushKV("VoteCount", (int64_t)finalizedBudget->GetVoteCount());
685  bObj.pushKV("Status", g_budgetman.GetFinalizedBudgetStatus(nHash));
686 
687  bool fValid = finalizedBudget->IsValid();
688  bObj.pushKV("IsValid", fValid);
689  if (!fValid)
690  bObj.pushKV("IsInvalidReason", finalizedBudget->IsInvalidReason());
691 
692  std::string strName = strprintf("%s (%s)", finalizedBudget->GetName(), nHash.ToString());
693  resultObj.pushKV(strName, bObj);
694  }
695 
696  return resultObj;
697  }
698 
699  if (strCommand == "getvotes") {
700  if (request.params.size() != 2)
701  throw std::runtime_error("Correct usage is 'mnbudget getvotes budget-hash'");
702 
703  uint256 hash(ParseHashV(request.params[1], "budget-hash"));
704 
706  CFinalizedBudget* pfinalBudget = g_budgetman.FindFinalizedBudget(hash);
707  if (pfinalBudget == nullptr) return "Unknown budget hash";
708  return pfinalBudget->GetVotesObject();
709  }
710 
711  return NullUniValue;
712 }
713 
715 {
716  if (request.fHelp || request.params.size() != 0)
717  throw std::runtime_error(
718  "checkbudgets\n"
719  "\nInitiates a budget check cycle manually\n"
720 
721  "\nExamples:\n" +
722  HelpExampleCli("checkbudgets", "") + HelpExampleRpc("checkbudgets", ""));
723 
725  throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Masternode/Budget sync not finished yet");
726 
728  return NullUniValue;
729 }
730 
732 {
733  if (request.fHelp || request.params.size() > 1)
734  throw std::runtime_error(
735  "cleanbudget ( try_sync )\n"
736  "\nCleans the budget data manually\n"
737  "\nArguments:\n"
738  "1. try_sync (boolean, optional, default=false) resets tier two sync to a pre-budget data request\n"
739  "\nExamples:\n" +
740  HelpExampleCli("cleanbudget", "") + HelpExampleRpc("cleanbudget", ""));
741 
742  g_budgetman.Clear();
743  LogPrintf("Budget data cleaned\n");
744 
745  // reset sync if requested
746  bool reset = request.params.size() > 0 ? request.params[0].get_bool() : false;
747  if (reset) {
750  LogPrintf("Masternode sync restarted\n");
751  }
752  return NullUniValue;
753 }
754 
755 // clang-format off
756 static const CRPCCommand commands[] =
757 { // category name actor (function) okSafe argNames
758  // --------------------- ------------------------ ----------------------- ------ --------
759  { "budget", "checkbudgets", &checkbudgets, true, {} },
760  { "budget", "getbudgetinfo", &getbudgetinfo, true, {"name"} },
761  { "budget", "getbudgetprojection", &getbudgetprojection, true, {} },
762  { "budget", "getbudgetvotes", &getbudgetvotes, true, {"name"} },
763  { "budget", "getnextsuperblock", &getnextsuperblock, true, {} },
764  { "budget", "mnbudgetrawvote", &mnbudgetrawvote, true, {"collat_txid","collat_vout","hash","votecast","time","sig"} },
765  { "budget", "mnbudgetvote", &mnbudgetvote, true, {"mode","hash","votecast","alias","legacy"} },
766  { "budget", "mnfinalbudget", &mnfinalbudget, true, {"command"} },
767  { "budget", "preparebudget", &preparebudget, true, {"name","url","npayments","start","address","monthly_payment"} },
768  { "budget", "submitbudget", &submitbudget, true, {"name","url","npayments","start","address","monthly_payment","fee_txid"} },
769 
771  { "hidden", "mnfinalbudgetsuggest", &mnfinalbudgetsuggest, true, {} },
772  { "hidden", "createrawmnfinalbudget", &createrawmnfinalbudget, true, {"budgetname", "blockstart", "proposals", "feetxid"} },
773  { "hidden", "cleanbudget", &cleanbudget, true, {"try_sync"} },
774 };
775 // clang-format on
776 
778 {
779  for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
780  tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
781 }
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
UniValue getbudgetinfo(const JSONRPCRequest &request)
Definition: budget.cpp:414
UniValue getbudgetprojection(const JSONRPCRequest &request)
Definition: budget.cpp:359
UniValue preparebudget(const JSONRPCRequest &request)
Definition: budget.cpp:104
void budgetToJSON(const CBudgetProposal *pbudgetProposal, UniValue &bObj, int nCurrentHeight)
Definition: budget.cpp:27
UniValue mnfinalbudgetsuggest(const JSONRPCRequest &request)
Definition: budget.cpp:534
UniValue mnfinalbudget(const JSONRPCRequest &request)
Definition: budget.cpp:637
UniValue getnextsuperblock(const JSONRPCRequest &request)
Definition: budget.cpp:338
UniValue mnbudgetvote(const JSONRPCRequest &request)
Definition: budget.cpp:233
UniValue mnbudgetrawvote(const JSONRPCRequest &request)
Definition: budget.cpp:477
void RegisterBudgetRPCCommands(CRPCTable &tableRPC)
Register budget RPC commands.
Definition: budget.cpp:777
UniValue cleanbudget(const JSONRPCRequest &request)
Definition: budget.cpp:731
void checkBudgetInputs(const UniValue &params, std::string &strProposalName, std::string &strURL, int &nPaymentCount, int &nBlockStart, CTxDestination &address, CAmount &nAmount)
Definition: budget.cpp:55
UniValue createrawmnfinalbudget(const JSONRPCRequest &request)
Definition: budget.cpp:550
UniValue checkbudgets(const JSONRPCRequest &request)
Definition: budget.cpp:714
UniValue submitbudget(const JSONRPCRequest &request)
Definition: budget.cpp:173
UniValue getbudgetvotes(const JSONRPCRequest &request)
Definition: budget.cpp:307
CBudgetManager g_budgetman
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
const CChainParams & Params()
Return the currently selected parameters.
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
int GetBestHeight() const
bool AddProposal(CBudgetProposal &budgetProposal)
static CAmount GetTotalBudget(int nHeight)
bool AddFinalizedBudget(CFinalizedBudget &finalizedBudget, CNode *pfrom=nullptr)
RecursiveMutex cs_budgets
Definition: budgetmanager.h:60
std::vector< CBudgetProposal > GetBudget()
const CBudgetProposal * FindProposalByName(const std::string &strProposalName) const
uint256 SubmitFinalBudget()
std::vector< CBudgetProposal * > GetAllProposalsOrdered()
CFinalizedBudget * FindFinalizedBudget(const uint256 &nHash)
std::vector< CFinalizedBudget * > GetFinalizedBudgets()
std::string GetFinalizedBudgetStatus(const uint256 &nHash) const
bool AddAndRelayProposalVote(const CBudgetVote &vote, std::string &strError)
int GetYeas() const
double GetRatio() const
int GetRemainingPaymentCount(int nCurrentHeight) const
int GetBlockStart() const
CAmount GetAllotted() const
std::string GetURL() const
std::string IsInvalidReason() const
std::string GetName() const
const uint256 & GetFeeTXHash() const
CScript GetPayee() const
int GetAbstains() const
bool IsValid() const
int GetBlockEnd() const
CAmount GetAmount() const
bool IsWellFormed(const CAmount &nTotalBudget)
int GetNays() const
uint256 GetHash() const
int GetTotalPaymentCount() const
bool IsEstablished() const
UniValue GetVotesArray() const
void SetTime(const int64_t &_nTime)
Definition: budgetvote.h:65
int Height() const
Return the maximal height in the chain.
Definition: chain.h:450
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
uint256 GetHash() const
UniValue GetVotesObject() const
CPubKey pubKeyMasternode
Definition: masternode.h:99
CMasternode * Find(const COutPoint &collateralOut)
Find an entry.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
std::string name
Definition: server.h:137
PIVX RPC command dispatcher.
Definition: server.h:147
bool appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:314
A key allocated from the key pool.
Definition: wallet.h:1256
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
bool CheckSignature(const CKeyID &keyID) const
void SetVchSig(const std::vector< unsigned char > &vchSigIn)
Definition: messagesigner.h:87
An input of a transaction.
Definition: transaction.h:94
std::string ToString() const
Definition: transaction.cpp:53
COutPoint prevout
Definition: transaction.h:96
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:577
std::map< uint256, CWalletTx > mapWallet
Definition: wallet.h:766
RecursiveMutex cs_wallet
Definition: wallet.h:720
UniValue params
Definition: server.h:47
bool fHelp
Definition: server.h:48
bool IsBlockchainSynced() const
bool IsSynced() const
const std::string & get_str() const
@ VOBJ
Definition: univalue.h:21
@ VARR
Definition: univalue.h:21
int64_t get_int64() const
const UniValue & get_obj() const
size_t size() const
Definition: univalue.h:68
bool empty() const
Definition: univalue.h:66
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool get_bool() const
int get_int() const
std::string ToString() const
Definition: uint256.cpp:65
bool IsNull() const
Definition: uint256.h:36
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
const std::string CURRENCY_UNIT
Definition: feerate.cpp:11
CWallet::CommitResult CommitTransaction(CTransactionRef tx, CReserveKey &opReservekey, CConnman *connman)
Definition: wallet.cpp:3510
bool CreateBudgetFeeTX(CTransactionRef &tx, const uint256 &hash, CReserveKey &keyChange, CAmount fee)
Definition: wallet.cpp:2944
std::string ToString() const
Definition: wallet.cpp:3489
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
@ LOCK
Definition: lockunlock.h:16
CMasternodeSync masternodeSync
CMasternodeMan mnodeman
Masternode manager.
bool IsValidDestination(const CWDestination &address)
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
CWDestination DecodeDestination(const std::string &strAddress)
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
UniValue JSONRPCError(int code, const std::string &message)
Definition: protocol.cpp:53
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:41
@ RPC_INVALID_PARAMETER
Ran out of memory during operation.
Definition: protocol.h:46
@ RPC_IN_WARMUP
Transaction already in chain.
Definition: protocol.h:52
@ RPC_WALLET_ERROR
No valid connection manager instance found.
Definition: protocol.h:70
@ RPC_CLIENT_IN_INITIAL_DOWNLOAD
PIVX is not connected.
Definition: protocol.h:62
@ RPC_INVALID_ADDRESS_OR_KEY
Unexpected type was passed as parameter.
Definition: protocol.h:44
CWallet * GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:39
void EnsureWalletIsUnlocked(CWallet *const pwallet, bool fAllowAnonOnly)
Definition: rpcwallet.cpp:71
bool EnsureWalletIsAvailable(CWallet *const pwallet, bool avoidException)
Definition: rpcwallet.cpp:59
UniValue ValueFromAmount(const CAmount &amount)
Definition: server.cpp:128
std::string HelpExampleCli(std::string methodname, std::string args)
Definition: server.cpp:527
CAmount AmountFromValue(const UniValue &value)
Definition: server.cpp:116
uint256 ParseHashO(const UniValue &o, std::string strKey)
Definition: server.cpp:147
std::vector< unsigned char > ParseHexO(const UniValue &o, std::string strKey)
Definition: server.cpp:160
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: server.cpp:138
std::string HelpExampleRpc(std::string methodname, std::string args)
Definition: server.cpp:532
CRPCTable tableRPC
Definition: server.cpp:565
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:162
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
CWallet::CommitStatus status
Definition: wallet.h:1106
int nMaxProposalPayments
Definition: params.h:195
int nBudgetCycleBlocks
Definition: params.h:178
#define LOCK2(cs1, cs2)
Definition: sync.h:221
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a Optional result.
Definition: system.h:65
TierTwoSyncState g_tiertwo_sync_state
#define strprintf
Definition: tinyformat.h:1056
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
const uint256 UINT256_ZERO
constant uint256 instances
Definition: uint256.h:175
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:234
const UniValue NullUniValue
Definition: univalue.cpp:13
std::string FormatMoney(const CAmount &n, bool fPlus)
Money parsing/formatting utilities.
bool validateURL(const std::string &strURL)
std::vector< unsigned char > DecodeBase64(const char *p, bool *pfInvalid)
std::string SanitizeString(const std::string &str, int rule)
Remove unsafe chars.
#define ARRAYLEN(array)
CBlockIndex * GetChainTip()
Return a reliable pointer (in mapBlockIndex) to the chain's tip index.
Definition: validation.cpp:194
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:84
std::vector< CWalletRef > vpwallets
Definition: wallet.cpp:33