Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

rpcevo.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2020 The Dash Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <base58.h>
6 #include <consensus/validation.h>
7 #include <core_io.h>
8 #include <init.h>
9 #include <messagesigner.h>
10 #include <rpc/safemode.h>
11 #include <rpc/server.h>
12 #include <txmempool.h>
13 #include <utilmoneystr.h>
14 #include <validation.h>
15 
16 #ifdef ENABLE_WALLET
17 #include <wallet/coincontrol.h>
18 #include <wallet/wallet.h>
19 #include <wallet/rpcwallet.h>
20 #endif//ENABLE_WALLET
21 
22 #include <netbase.h>
23 
24 #include <evo/specialtx.h>
25 #include <evo/providertx.h>
26 #include <evo/deterministicmns.h>
27 #include <evo/simplifiedmns.h>
28 
29 #include <bls/bls.h>
30 
32 
33 #ifdef ENABLE_WALLET
34 extern UniValue signrawtransaction(const JSONRPCRequest& request);
35 extern UniValue sendrawtransaction(const JSONRPCRequest& request);
36 #endif//ENABLE_WALLET
37 
38 std::string GetHelpString(int nParamNum, std::string strParamName)
39 {
40  static const std::map<std::string, std::string> mapParamHelp = {
41  {"collateralAddress",
42  "%d. \"collateralAddress\" (string, required) The dash address to send the collateral to.\n"
43  },
44  {"collateralHash",
45  "%d. \"collateralHash\" (string, required) The collateral transaction hash.\n"
46  },
47  {"collateralIndex",
48  "%d. collateralIndex (numeric, required) The collateral transaction output index.\n"
49  },
50  {"feeSourceAddress",
51  "%d. \"feeSourceAddress\" (string, optional) If specified wallet will only use coins from this address to fund ProTx.\n"
52  " If not specified, payoutAddress is the one that is going to be used.\n"
53  " The private key belonging to this address must be known in your wallet.\n"
54  },
55  {"fundAddress",
56  "%d. \"fundAddress\" (string, optional) If specified wallet will only use coins from this address to fund ProTx.\n"
57  " If not specified, payoutAddress is the one that is going to be used.\n"
58  " The private key belonging to this address must be known in your wallet.\n"
59  },
60  {"ipAndPort",
61  "%d. \"ipAndPort\" (string, required) IP and port in the form \"IP:PORT\".\n"
62  " Must be unique on the network. Can be set to 0, which will require a ProUpServTx afterwards.\n"
63  },
64  {"operatorKey",
65  "%d. \"operatorKey\" (string, required) The operator BLS private key associated with the\n"
66  " registered operator public key.\n"
67  },
68  {"operatorPayoutAddress",
69  "%d. \"operatorPayoutAddress\" (string, optional) The address used for operator reward payments.\n"
70  " Only allowed when the ProRegTx had a non-zero operatorReward value.\n"
71  " If set to an empty string, the currently active payout address is reused.\n"
72  },
73  {"operatorPubKey_register",
74  "%d. \"operatorPubKey\" (string, required) The operator BLS public key. The BLS private key does not have to be known.\n"
75  " It has to match the BLS private key which is later used when operating the masternode.\n"
76  },
77  {"operatorPubKey_update",
78  "%d. \"operatorPubKey\" (string, required) The operator BLS public key. The BLS private key does not have to be known.\n"
79  " It has to match the BLS private key which is later used when operating the masternode.\n"
80  " If set to an empty string, the currently active operator BLS public key is reused.\n"
81  },
82  {"operatorReward",
83  "%d. \"operatorReward\" (numeric, required) The fraction in %% to share with the operator. The value must be\n"
84  " between 0.00 and 100.00.\n"
85  },
86  {"ownerAddress",
87  "%d. \"ownerAddress\" (string, required) The dash address to use for payee updates and proposal voting.\n"
88  " The private key belonging to this address must be known in your wallet. The address must\n"
89  " be unused and must differ from the collateralAddress\n"
90  },
91  {"payoutAddress_register",
92  "%d. \"payoutAddress\" (string, required) The dash address to use for masternode reward payments.\n"
93  },
94  {"payoutAddress_update",
95  "%d. \"payoutAddress\" (string, required) The dash address to use for masternode reward payments.\n"
96  " If set to an empty string, the currently active payout address is reused.\n"
97  },
98  {"proTxHash",
99  "%d. \"proTxHash\" (string, required) The hash of the initial ProRegTx.\n"
100  },
101  {"reason",
102  "%d. reason (numeric, optional) The reason for masternode service revocation.\n"
103  },
104  {"votingAddress_register",
105  "%d. \"votingAddress\" (string, required) The voting key address. The private key does not have to be known by your wallet.\n"
106  " It has to match the private key which is later used when voting on proposals.\n"
107  " If set to an empty string, ownerAddress will be used.\n"
108  },
109  {"votingAddress_update",
110  "%d. \"votingAddress\" (string, required) The voting key address. The private key does not have to be known by your wallet.\n"
111  " It has to match the private key which is later used when voting on proposals.\n"
112  " If set to an empty string, the currently active voting key address is reused.\n"
113  },
114  };
115 
116  auto it = mapParamHelp.find(strParamName);
117  if (it == mapParamHelp.end())
118  throw std::runtime_error(strprintf("FIXME: WRONG PARAM NAME %s!", strParamName));
119 
120  return strprintf(it->second, nParamNum);
121 }
122 
123 // Allows to specify Dash address or priv key. In case of Dash address, the priv key is taken from the wallet
124 static CKey ParsePrivKey(CWallet* pwallet, const std::string &strKeyOrAddress, bool allowAddresses = true) {
125  CTxDestination dest = DecodeDestination(strKeyOrAddress);
126  if (allowAddresses && IsValidDestination(dest)) {
127 #ifdef ENABLE_WALLET
128  if (!pwallet) {
129  throw std::runtime_error("addresses not supported when wallet is disabled");
130  }
131  EnsureWalletIsUnlocked(pwallet);
132  const CKeyID *keyID = boost::get<CKeyID>(&dest);
133  CKey key;
134  if (!keyID || !pwallet->GetKey(*keyID, key))
135  throw std::runtime_error(strprintf("non-wallet or invalid address %s", strKeyOrAddress));
136  return key;
137 #else//ENABLE_WALLET
138  throw std::runtime_error("addresses not supported in no-wallet builds");
139 #endif//ENABLE_WALLET
140  }
141 
142  CBitcoinSecret secret;
143  if (!secret.SetString(strKeyOrAddress) || !secret.IsValid()) {
144  throw std::runtime_error(strprintf("invalid priv-key/address %s", strKeyOrAddress));
145  }
146  return secret.GetKey();
147 }
148 
149 static CKeyID ParsePubKeyIDFromAddress(const std::string& strAddress, const std::string& paramName)
150 {
151  CTxDestination dest = DecodeDestination(strAddress);
152  const CKeyID *keyID = boost::get<CKeyID>(&dest);
153  if (!keyID) {
154  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid P2PKH address, not %s", paramName, strAddress));
155  }
156  return *keyID;
157 }
158 
159 static CBLSPublicKey ParseBLSPubKey(const std::string& hexKey, const std::string& paramName)
160 {
161  CBLSPublicKey pubKey;
162  if (!pubKey.SetHexStr(hexKey)) {
163  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid BLS public key, not %s", paramName, hexKey));
164  }
165  return pubKey;
166 }
167 
168 static CBLSSecretKey ParseBLSSecretKey(const std::string& hexKey, const std::string& paramName)
169 {
170  CBLSSecretKey secKey;
171  if (!secKey.SetHexStr(hexKey)) {
172  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid BLS secret key", paramName));
173  }
174  return secKey;
175 }
176 
177 #ifdef ENABLE_WALLET
178 
179 template<typename SpecialTxPayload>
180 static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const SpecialTxPayload& payload, const CTxDestination& fundDest)
181 {
182  assert(pwallet != nullptr);
183 
184  // Make sure the results are valid at least up to the most recent block
185  // the user could have gotten from another RPC command prior to now
187 
189  LOCK(pwallet->cs_wallet);
190 
191  CTxDestination nodest = CNoDestination();
192  if (fundDest == nodest) {
193  throw JSONRPCError(RPC_INTERNAL_ERROR, "No source of funds specified");
194  }
195 
197  ds << payload;
198  tx.vExtraPayload.assign(ds.begin(), ds.end());
199 
200  static CTxOut dummyTxOut(0, CScript() << OP_RETURN);
201  std::vector<CRecipient> vecSend;
202  bool dummyTxOutAdded = false;
203 
204  if (tx.vout.empty()) {
205  // add dummy txout as CreateTransaction requires at least one recipient
206  tx.vout.emplace_back(dummyTxOut);
207  dummyTxOutAdded = true;
208  }
209 
210  for (const auto& txOut : tx.vout) {
211  CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
212  vecSend.push_back(recipient);
213  }
214 
215  CCoinControl coinControl;
216  coinControl.destChange = fundDest;
217  coinControl.fRequireAllInputs = false;
218 
219  std::vector<COutput> vecOutputs;
220  pwallet->AvailableCoins(vecOutputs);
221 
222  for (const auto& out : vecOutputs) {
223  CTxDestination txDest;
224  if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, txDest) && txDest == fundDest) {
225  coinControl.Select(COutPoint(out.tx->tx->GetHash(), out.i));
226  }
227  }
228 
229  if (!coinControl.HasSelected()) {
230  throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("No funds at specified address %s", EncodeDestination(fundDest)));
231  }
232 
233  CWalletTx wtx;
234  CReserveKey reservekey(pwallet);
235  CAmount nFee;
236  int nChangePos = -1;
237  std::string strFailReason;
238 
239  if (!pwallet->CreateTransaction(vecSend, wtx, reservekey, nFee, nChangePos, strFailReason, coinControl, false, tx.vExtraPayload.size())) {
240  throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
241  }
242 
243  tx.vin = wtx.tx->vin;
244  tx.vout = wtx.tx->vout;
245 
246  if (dummyTxOutAdded && tx.vout.size() > 1) {
247  // CreateTransaction added a change output, so we don't need the dummy txout anymore.
248  // Removing it results in slight overpayment of fees, but we ignore this for now (as it's a very low amount).
249  auto it = std::find(tx.vout.begin(), tx.vout.end(), dummyTxOut);
250  assert(it != tx.vout.end());
251  tx.vout.erase(it);
252  }
253 }
254 
255 template<typename SpecialTxPayload>
256 static void UpdateSpecialTxInputsHash(const CMutableTransaction& tx, SpecialTxPayload& payload)
257 {
258  payload.inputsHash = CalcTxInputsHash(tx);
259 }
260 
261 template<typename SpecialTxPayload>
262 static void SignSpecialTxPayloadByHash(const CMutableTransaction& tx, SpecialTxPayload& payload, const CKey& key)
263 {
264  UpdateSpecialTxInputsHash(tx, payload);
265  payload.vchSig.clear();
266 
267  uint256 hash = ::SerializeHash(payload);
268  if (!CHashSigner::SignHash(hash, key, payload.vchSig)) {
269  throw JSONRPCError(RPC_INTERNAL_ERROR, "failed to sign special tx");
270  }
271 }
272 
273 template<typename SpecialTxPayload>
274 static void SignSpecialTxPayloadByString(const CMutableTransaction& tx, SpecialTxPayload& payload, const CKey& key)
275 {
276  UpdateSpecialTxInputsHash(tx, payload);
277  payload.vchSig.clear();
278 
279  std::string m = payload.MakeSignString();
280  if (!CMessageSigner::SignMessage(m, payload.vchSig, key)) {
281  throw JSONRPCError(RPC_INTERNAL_ERROR, "failed to sign special tx");
282  }
283 }
284 
285 template<typename SpecialTxPayload>
286 static void SignSpecialTxPayloadByHash(const CMutableTransaction& tx, SpecialTxPayload& payload, const CBLSSecretKey& key)
287 {
288  UpdateSpecialTxInputsHash(tx, payload);
289 
290  uint256 hash = ::SerializeHash(payload);
291  payload.sig = key.Sign(hash);
292 }
293 
294 static std::string SignAndSendSpecialTx(const CMutableTransaction& tx)
295 {
296  {
297  LOCK(cs_main);
298 
299  CValidationState state;
300  if (!CheckSpecialTx(tx, chainActive.Tip(), state)) {
301  throw std::runtime_error(FormatStateMessage(state));
302  }
303  } // cs_main
304 
306  ds << tx;
307 
308  JSONRPCRequest signRequest;
309  signRequest.params.setArray();
310  signRequest.params.push_back(HexStr(ds.begin(), ds.end()));
311  UniValue signResult = signrawtransaction(signRequest);
312 
313  JSONRPCRequest sendRequest;
314  sendRequest.params.setArray();
315  sendRequest.params.push_back(signResult["hex"].get_str());
316  return sendrawtransaction(sendRequest).get_str();
317 }
318 
319 void protx_register_fund_help(CWallet* const pwallet)
320 {
321  throw std::runtime_error(
322  "protx register_fund \"collateralAddress\" \"ipAndPort\" \"ownerAddress\" \"operatorPubKey\" \"votingAddress\" operatorReward \"payoutAddress\" ( \"fundAddress\" )\n"
323  "\nCreates, funds and sends a ProTx to the network. The resulting transaction will move 1000 Dash\n"
324  "to the address specified by collateralAddress and will then function as the collateral of your\n"
325  "masternode.\n"
326  "A few of the limitations you see in the arguments are temporary and might be lifted after DIP3\n"
327  "is fully deployed.\n"
328  + HelpRequiringPassphrase(pwallet) + "\n"
329  "\nArguments:\n"
330  + GetHelpString(1, "collateralAddress")
331  + GetHelpString(2, "ipAndPort")
332  + GetHelpString(3, "ownerAddress")
333  + GetHelpString(4, "operatorPubKey_register")
334  + GetHelpString(5, "votingAddress_register")
335  + GetHelpString(6, "operatorReward")
336  + GetHelpString(7, "payoutAddress_register")
337  + GetHelpString(8, "fundAddress") +
338  "\nResult:\n"
339  "\"txid\" (string) The transaction id.\n"
340  "\nExamples:\n"
341  + HelpExampleCli("protx", "register_fund \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\" \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
342  );
343 }
344 
345 void protx_register_help(CWallet* const pwallet)
346 {
347  throw std::runtime_error(
348  "protx register \"collateralHash\" collateralIndex \"ipAndPort\" \"ownerAddress\" \"operatorPubKey\" \"votingAddress\" operatorReward \"payoutAddress\" ( \"feeSourceAddress\" )\n"
349  "\nSame as \"protx register_fund\", but with an externally referenced collateral.\n"
350  "The collateral is specified through \"collateralHash\" and \"collateralIndex\" and must be an unspent\n"
351  "transaction output spendable by this wallet. It must also not be used by any other masternode.\n"
352  + HelpRequiringPassphrase(pwallet) + "\n"
353  "\nArguments:\n"
354  + GetHelpString(1, "collateralHash")
355  + GetHelpString(2, "collateralIndex")
356  + GetHelpString(3, "ipAndPort")
357  + GetHelpString(4, "ownerAddress")
358  + GetHelpString(5, "operatorPubKey_register")
359  + GetHelpString(6, "votingAddress_register")
360  + GetHelpString(7, "operatorReward")
361  + GetHelpString(8, "payoutAddress_register")
362  + GetHelpString(9, "feeSourceAddress") +
363  "\nResult:\n"
364  "\"txid\" (string) The transaction id.\n"
365  "\nExamples:\n"
366  + HelpExampleCli("protx", "register \"0123456701234567012345670123456701234567012345670123456701234567\" 0 \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
367  );
368 }
369 
370 void protx_register_prepare_help()
371 {
372  throw std::runtime_error(
373  "protx register_prepare \"collateralHash\" collateralIndex \"ipAndPort\" \"ownerAddress\" \"operatorPubKey\" \"votingAddress\" operatorReward \"payoutAddress\" ( \"feeSourceAddress\" )\n"
374  "\nCreates an unsigned ProTx and returns it. The ProTx must be signed externally with the collateral\n"
375  "key and then passed to \"protx register_submit\". The prepared transaction will also contain inputs\n"
376  "and outputs to cover fees.\n"
377  "\nArguments:\n"
378  + GetHelpString(1, "collateralHash")
379  + GetHelpString(2, "collateralIndex")
380  + GetHelpString(3, "ipAndPort")
381  + GetHelpString(4, "ownerAddress")
382  + GetHelpString(5, "operatorPubKey_register")
383  + GetHelpString(6, "votingAddress_register")
384  + GetHelpString(7, "operatorReward")
385  + GetHelpString(8, "payoutAddress_register")
386  + GetHelpString(9, "feeSourceAddress") +
387  "\nResult:\n"
388  "{ (json object)\n"
389  " \"tx\" : (string) The serialized ProTx in hex format.\n"
390  " \"collateralAddress\" : (string) The collateral address.\n"
391  " \"signMessage\" : (string) The string message that needs to be signed with\n"
392  " the collateral key.\n"
393  "}\n"
394  "\nExamples:\n"
395  + HelpExampleCli("protx", "register_prepare \"0123456701234567012345670123456701234567012345670123456701234567\" 0 \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
396  );
397 }
398 
399 void protx_register_submit_help(CWallet* const pwallet)
400 {
401  throw std::runtime_error(
402  "protx register_submit \"tx\" \"sig\"\n"
403  "\nSubmits the specified ProTx to the network. This command will also sign the inputs of the transaction\n"
404  "which were previously added by \"protx register_prepare\" to cover transaction fees\n"
405  + HelpRequiringPassphrase(pwallet) + "\n"
406  "\nArguments:\n"
407  "1. \"tx\" (string, required) The serialized transaction previously returned by \"protx register_prepare\"\n"
408  "2. \"sig\" (string, required) The signature signed with the collateral key. Must be in base64 format.\n"
409  "\nResult:\n"
410  "\"txid\" (string) The transaction id.\n"
411  "\nExamples:\n"
412  + HelpExampleCli("protx", "register_submit \"tx\" \"sig\"")
413  );
414 }
415 
416 // handles register, register_prepare and register_fund in one method
417 UniValue protx_register(const JSONRPCRequest& request)
418 {
419  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
420  bool isExternalRegister = request.params[0].get_str() == "register";
421  bool isFundRegister = request.params[0].get_str() == "register_fund";
422  bool isPrepareRegister = request.params[0].get_str() == "register_prepare";
423 
424  if (isFundRegister && (request.fHelp || (request.params.size() != 8 && request.params.size() != 9))) {
425  protx_register_fund_help(pwallet);
426  } else if (isExternalRegister && (request.fHelp || (request.params.size() != 9 && request.params.size() != 10))) {
427  protx_register_help(pwallet);
428  } else if (isPrepareRegister && (request.fHelp || (request.params.size() != 9 && request.params.size() != 10))) {
429  protx_register_prepare_help();
430  }
431 
432  ObserveSafeMode();
433 
434  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
435  return NullUniValue;
436 
437  if (isExternalRegister || isFundRegister) {
438  EnsureWalletIsUnlocked(pwallet);
439  }
440 
441  size_t paramIdx = 1;
442 
443  CAmount collateralAmount = 1000 * COIN;
444 
446  tx.nVersion = 3;
448 
449  CProRegTx ptx;
451 
452  if (isFundRegister) {
453  CTxDestination collateralDest = DecodeDestination(request.params[paramIdx].get_str());
454  if (!IsValidDestination(collateralDest)) {
455  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid collaterall address: %s", request.params[paramIdx].get_str()));
456  }
457  CScript collateralScript = GetScriptForDestination(collateralDest);
458 
459  CTxOut collateralTxOut(collateralAmount, collateralScript);
460  tx.vout.emplace_back(collateralTxOut);
461 
462  paramIdx++;
463  } else {
464  uint256 collateralHash = ParseHashV(request.params[paramIdx], "collateralHash");
465  int32_t collateralIndex = ParseInt32V(request.params[paramIdx + 1], "collateralIndex");
466  if (collateralHash.IsNull() || collateralIndex < 0) {
467  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid hash or index: %s-%d", collateralHash.ToString(), collateralIndex));
468  }
469 
470  ptx.collateralOutpoint = COutPoint(collateralHash, (uint32_t)collateralIndex);
471  paramIdx += 2;
472 
473  // TODO unlock on failure
474  LOCK(pwallet->cs_wallet);
475  pwallet->LockCoin(ptx.collateralOutpoint);
476  }
477 
478  if (request.params[paramIdx].get_str() != "") {
479  if (!Lookup(request.params[paramIdx].get_str().c_str(), ptx.addr, Params().GetDefaultPort(), false)) {
480  throw std::runtime_error(strprintf("invalid network address %s", request.params[paramIdx].get_str()));
481  }
482  }
483 
484  CKey keyOwner = ParsePrivKey(pwallet, request.params[paramIdx + 1].get_str(), true);
485  CBLSPublicKey pubKeyOperator = ParseBLSPubKey(request.params[paramIdx + 2].get_str(), "operator BLS address");
486  CKeyID keyIDVoting = keyOwner.GetPubKey().GetID();
487  if (request.params[paramIdx + 3].get_str() != "") {
488  keyIDVoting = ParsePubKeyIDFromAddress(request.params[paramIdx + 3].get_str(), "voting address");
489  }
490 
491  int64_t operatorReward;
492  if (!ParseFixedPoint(request.params[paramIdx + 4].getValStr(), 2, &operatorReward)) {
493  throw JSONRPCError(RPC_INVALID_PARAMETER, "operatorReward must be a number");
494  }
495  if (operatorReward < 0 || operatorReward > 10000) {
496  throw JSONRPCError(RPC_INVALID_PARAMETER, "operatorReward must be between 0.00 and 100.00");
497  }
498  ptx.nOperatorReward = operatorReward;
499 
500  CTxDestination payoutDest = DecodeDestination(request.params[paramIdx + 5].get_str());
501  if (!IsValidDestination(payoutDest)) {
502  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid payout address: %s", request.params[paramIdx + 5].get_str()));
503  }
504 
505  ptx.keyIDOwner = keyOwner.GetPubKey().GetID();
506  ptx.pubKeyOperator = pubKeyOperator;
507  ptx.keyIDVoting = keyIDVoting;
508  ptx.scriptPayout = GetScriptForDestination(payoutDest);
509 
510  if (!isFundRegister) {
511  // make sure fee calculation works
512  ptx.vchSig.resize(65);
513  }
514 
515  CTxDestination fundDest = payoutDest;
516  if (!request.params[paramIdx + 6].isNull()) {
517  fundDest = DecodeDestination(request.params[paramIdx + 6].get_str());
518  if (!IsValidDestination(fundDest))
519  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[paramIdx + 6].get_str());
520  }
521 
522  FundSpecialTx(pwallet, tx, ptx, fundDest);
523  UpdateSpecialTxInputsHash(tx, ptx);
524 
525  if (isFundRegister) {
526  uint32_t collateralIndex = (uint32_t) -1;
527  for (uint32_t i = 0; i < tx.vout.size(); i++) {
528  if (tx.vout[i].nValue == collateralAmount) {
529  collateralIndex = i;
530  break;
531  }
532  }
533  assert(collateralIndex != (uint32_t) -1);
534  ptx.collateralOutpoint.n = collateralIndex;
535 
536  SetTxPayload(tx, ptx);
537  return SignAndSendSpecialTx(tx);
538  } else {
539  // referencing external collateral
540 
541  Coin coin;
542  if (!GetUTXOCoin(ptx.collateralOutpoint, coin)) {
543  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral not found: %s", ptx.collateralOutpoint.ToStringShort()));
544  }
545  CTxDestination txDest;
546  ExtractDestination(coin.out.scriptPubKey, txDest);
547  const CKeyID *keyID = boost::get<CKeyID>(&txDest);
548  if (!keyID) {
549  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral type not supported: %s", ptx.collateralOutpoint.ToStringShort()));
550  }
551 
552  if (isPrepareRegister) {
553  // external signing with collateral key
554  ptx.vchSig.clear();
555  SetTxPayload(tx, ptx);
556 
558  ret.push_back(Pair("tx", EncodeHexTx(tx)));
559  ret.push_back(Pair("collateralAddress", EncodeDestination(txDest)));
560  ret.push_back(Pair("signMessage", ptx.MakeSignString()));
561  return ret;
562  } else {
563  // lets prove we own the collateral
564  CKey key;
565  if (!pwallet->GetKey(*keyID, key)) {
566  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral key not in wallet: %s", EncodeDestination(txDest)));
567  }
568  SignSpecialTxPayloadByString(tx, ptx, key);
569  SetTxPayload(tx, ptx);
570  return SignAndSendSpecialTx(tx);
571  }
572  }
573 }
574 
575 UniValue protx_register_submit(const JSONRPCRequest& request)
576 {
577  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
578  if (request.fHelp || request.params.size() != 3) {
579  protx_register_submit_help(pwallet);
580  }
581 
582  ObserveSafeMode();
583 
584  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
585  return NullUniValue;
586 
587  EnsureWalletIsUnlocked(pwallet);
588 
590  if (!DecodeHexTx(tx, request.params[1].get_str())) {
591  throw JSONRPCError(RPC_INVALID_PARAMETER, "transaction not deserializable");
592  }
594  throw JSONRPCError(RPC_INVALID_PARAMETER, "transaction not a ProRegTx");
595  }
596  CProRegTx ptx;
597  if (!GetTxPayload(tx, ptx)) {
598  throw JSONRPCError(RPC_INVALID_PARAMETER, "transaction payload not deserializable");
599  }
600  if (!ptx.vchSig.empty()) {
601  throw JSONRPCError(RPC_INVALID_PARAMETER, "payload signature not empty");
602  }
603 
604  ptx.vchSig = DecodeBase64(request.params[2].get_str().c_str());
605 
606  SetTxPayload(tx, ptx);
607  return SignAndSendSpecialTx(tx);
608 }
609 
610 void protx_update_service_help(CWallet* const pwallet)
611 {
612  throw std::runtime_error(
613  "protx update_service \"proTxHash\" \"ipAndPort\" \"operatorKey\" (\"operatorPayoutAddress\" \"feeSourceAddress\" )\n"
614  "\nCreates and sends a ProUpServTx to the network. This will update the IP address\n"
615  "of a masternode.\n"
616  "If this is done for a masternode that got PoSe-banned, the ProUpServTx will also revive this masternode.\n"
617  + HelpRequiringPassphrase(pwallet) + "\n"
618  "\nArguments:\n"
619  + GetHelpString(1, "proTxHash")
620  + GetHelpString(2, "ipAndPort")
621  + GetHelpString(3, "operatorKey")
622  + GetHelpString(4, "operatorPayoutAddress")
623  + GetHelpString(5, "feeSourceAddress") +
624  "\nResult:\n"
625  "\"txid\" (string) The transaction id.\n"
626  "\nExamples:\n"
627  + HelpExampleCli("protx", "update_service \"0123456701234567012345670123456701234567012345670123456701234567\" \"1.2.3.4:1234\" 5a2e15982e62f1e0b7cf9783c64cf7e3af3f90a52d6c40f6f95d624c0b1621cd")
628  );
629 }
630 
631 UniValue protx_update_service(const JSONRPCRequest& request)
632 {
633  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
634  if (request.fHelp || (request.params.size() < 4 || request.params.size() > 6))
635  protx_update_service_help(pwallet);
636 
637  ObserveSafeMode();
638 
639  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
640  return NullUniValue;
641 
642  EnsureWalletIsUnlocked(pwallet);
643 
644  CProUpServTx ptx;
646  ptx.proTxHash = ParseHashV(request.params[1], "proTxHash");
647 
648  if (!Lookup(request.params[2].get_str().c_str(), ptx.addr, Params().GetDefaultPort(), false)) {
649  throw std::runtime_error(strprintf("invalid network address %s", request.params[2].get_str()));
650  }
651 
652  CBLSSecretKey keyOperator = ParseBLSSecretKey(request.params[3].get_str(), "operatorKey");
653 
654  auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(ptx.proTxHash);
655  if (!dmn) {
656  throw std::runtime_error(strprintf("masternode with proTxHash %s not found", ptx.proTxHash.ToString()));
657  }
658 
659  if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator.Get()) {
660  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key"));
661  }
662 
664  tx.nVersion = 3;
666 
667  // param operatorPayoutAddress
668  if (!request.params[4].isNull()) {
669  if (request.params[4].get_str().empty()) {
670  ptx.scriptOperatorPayout = dmn->pdmnState->scriptOperatorPayout;
671  } else {
672  CTxDestination payoutDest = DecodeDestination(request.params[4].get_str());
673  if (!IsValidDestination(payoutDest)) {
674  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid operator payout address: %s", request.params[4].get_str()));
675  }
677  }
678  } else {
679  ptx.scriptOperatorPayout = dmn->pdmnState->scriptOperatorPayout;
680  }
681 
682  CTxDestination feeSource;
683 
684  // param feeSourceAddress
685  if (!request.params[5].isNull()) {
686  feeSource = DecodeDestination(request.params[5].get_str());
687  if (!IsValidDestination(feeSource))
688  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[5].get_str());
689  } else {
690  if (ptx.scriptOperatorPayout != CScript()) {
691  // use operator reward address as default source for fees
693  } else {
694  // use payout address as default source for fees
695  ExtractDestination(dmn->pdmnState->scriptPayout, feeSource);
696  }
697  }
698 
699  FundSpecialTx(pwallet, tx, ptx, feeSource);
700 
701  SignSpecialTxPayloadByHash(tx, ptx, keyOperator);
702  SetTxPayload(tx, ptx);
703 
704  return SignAndSendSpecialTx(tx);
705 }
706 
707 void protx_update_registrar_help(CWallet* const pwallet)
708 {
709  throw std::runtime_error(
710  "protx update_registrar \"proTxHash\" \"operatorPubKey\" \"votingAddress\" \"payoutAddress\" ( \"feeSourceAddress\" )\n"
711  "\nCreates and sends a ProUpRegTx to the network. This will update the operator key, voting key and payout\n"
712  "address of the masternode specified by \"proTxHash\".\n"
713  "The owner key of the masternode must be known to your wallet.\n"
714  + HelpRequiringPassphrase(pwallet) + "\n"
715  "\nArguments:\n"
716  + GetHelpString(1, "proTxHash")
717  + GetHelpString(2, "operatorPubKey_update")
718  + GetHelpString(3, "votingAddress_update")
719  + GetHelpString(4, "payoutAddress_update")
720  + GetHelpString(5, "feeSourceAddress") +
721  "\nResult:\n"
722  "\"txid\" (string) The transaction id.\n"
723  "\nExamples:\n"
724  + HelpExampleCli("protx", "update_registrar \"0123456701234567012345670123456701234567012345670123456701234567\" \"982eb34b7c7f614f29e5c665bc3605f1beeef85e3395ca12d3be49d2868ecfea5566f11cedfad30c51b2403f2ad95b67\" \"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\"")
725  );
726 }
727 
728 UniValue protx_update_registrar(const JSONRPCRequest& request)
729 {
730  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
731  if (request.fHelp || (request.params.size() != 5 && request.params.size() != 6)) {
732  protx_update_registrar_help(pwallet);
733  }
734 
735  ObserveSafeMode();
736 
737  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
738  return NullUniValue;
739 
740  EnsureWalletIsUnlocked(pwallet);
741 
742  CProUpRegTx ptx;
744  ptx.proTxHash = ParseHashV(request.params[1], "proTxHash");
745 
746  auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(ptx.proTxHash);
747  if (!dmn) {
748  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString()));
749  }
750  ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator.Get();
751  ptx.keyIDVoting = dmn->pdmnState->keyIDVoting;
752  ptx.scriptPayout = dmn->pdmnState->scriptPayout;
753 
754  if (request.params[2].get_str() != "") {
755  ptx.pubKeyOperator = ParseBLSPubKey(request.params[2].get_str(), "operator BLS address");
756  }
757  if (request.params[3].get_str() != "") {
758  ptx.keyIDVoting = ParsePubKeyIDFromAddress(request.params[3].get_str(), "voting address");
759  }
760 
761  CTxDestination payoutDest;
762  ExtractDestination(ptx.scriptPayout, payoutDest);
763  if (request.params[4].get_str() != "") {
764  payoutDest = DecodeDestination(request.params[4].get_str());
765  if (!IsValidDestination(payoutDest)) {
766  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid payout address: %s", request.params[4].get_str()));
767  }
768  ptx.scriptPayout = GetScriptForDestination(payoutDest);
769  }
770 
771  CKey keyOwner;
772  if (!pwallet->GetKey(dmn->pdmnState->keyIDOwner, keyOwner)) {
773  throw std::runtime_error(strprintf("Private key for owner address %s not found in your wallet", EncodeDestination(dmn->pdmnState->keyIDOwner)));
774  }
775 
777  tx.nVersion = 3;
779 
780  // make sure we get anough fees added
781  ptx.vchSig.resize(65);
782 
783  CTxDestination feeSourceDest = payoutDest;
784  if (!request.params[5].isNull()) {
785  feeSourceDest = DecodeDestination(request.params[5].get_str());
786  if (!IsValidDestination(feeSourceDest))
787  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[5].get_str());
788  }
789 
790  FundSpecialTx(pwallet, tx, ptx, feeSourceDest);
791  SignSpecialTxPayloadByHash(tx, ptx, keyOwner);
792  SetTxPayload(tx, ptx);
793 
794  return SignAndSendSpecialTx(tx);
795 }
796 
797 void protx_revoke_help(CWallet* const pwallet)
798 {
799  throw std::runtime_error(
800  "protx revoke \"proTxHash\" \"operatorKey\" ( reason \"feeSourceAddress\")\n"
801  "\nCreates and sends a ProUpRevTx to the network. This will revoke the operator key of the masternode and\n"
802  "put it into the PoSe-banned state. It will also set the service field of the masternode\n"
803  "to zero. Use this in case your operator key got compromised or you want to stop providing your service\n"
804  "to the masternode owner.\n"
805  + HelpRequiringPassphrase(pwallet) + "\n"
806  "\nArguments:\n"
807  + GetHelpString(1, "proTxHash")
808  + GetHelpString(2, "operatorKey")
809  + GetHelpString(3, "reason")
810  + GetHelpString(4, "feeSourceAddress") +
811  "\nResult:\n"
812  "\"txid\" (string) The transaction id.\n"
813  "\nExamples:\n"
814  + HelpExampleCli("protx", "revoke \"0123456701234567012345670123456701234567012345670123456701234567\" \"072f36a77261cdd5d64c32d97bac417540eddca1d5612f416feb07ff75a8e240\"")
815  );
816 }
817 
818 UniValue protx_revoke(const JSONRPCRequest& request)
819 {
820  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
821  if (request.fHelp || (request.params.size() < 3 || request.params.size() > 5)) {
822  protx_revoke_help(pwallet);
823  }
824 
825  ObserveSafeMode();
826 
827  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
828  return NullUniValue;
829 
830  EnsureWalletIsUnlocked(pwallet);
831 
832  CProUpRevTx ptx;
834  ptx.proTxHash = ParseHashV(request.params[1], "proTxHash");
835 
836  CBLSSecretKey keyOperator = ParseBLSSecretKey(request.params[2].get_str(), "operatorKey");
837 
838  if (!request.params[3].isNull()) {
839  int32_t nReason = ParseInt32V(request.params[3], "reason");
840  if (nReason < 0 || nReason > CProUpRevTx::REASON_LAST) {
841  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("invalid reason %d, must be between 0 and %d", nReason, CProUpRevTx::REASON_LAST));
842  }
843  ptx.nReason = (uint16_t)nReason;
844  }
845 
846  auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(ptx.proTxHash);
847  if (!dmn) {
848  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString()));
849  }
850 
851  if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator.Get()) {
852  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key"));
853  }
854 
856  tx.nVersion = 3;
858 
859  if (!request.params[4].isNull()) {
860  CTxDestination feeSourceDest = DecodeDestination(request.params[4].get_str());
861  if (!IsValidDestination(feeSourceDest))
862  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[4].get_str());
863  FundSpecialTx(pwallet, tx, ptx, feeSourceDest);
864  } else if (dmn->pdmnState->scriptOperatorPayout != CScript()) {
865  // Using funds from previousely specified operator payout address
866  CTxDestination txDest;
867  ExtractDestination(dmn->pdmnState->scriptOperatorPayout, txDest);
868  FundSpecialTx(pwallet, tx, ptx, txDest);
869  } else if (dmn->pdmnState->scriptPayout != CScript()) {
870  // Using funds from previousely specified masternode payout address
871  CTxDestination txDest;
872  ExtractDestination(dmn->pdmnState->scriptPayout, txDest);
873  FundSpecialTx(pwallet, tx, ptx, txDest);
874  } else {
875  throw JSONRPCError(RPC_INTERNAL_ERROR, "No payout or fee source addresses found, can't revoke");
876  }
877 
878  SignSpecialTxPayloadByHash(tx, ptx, keyOperator);
879  SetTxPayload(tx, ptx);
880 
881  return SignAndSendSpecialTx(tx);
882 }
883 #endif//ENABLE_WALLET
884 
886 {
887  throw std::runtime_error(
888  "protx list (\"type\" \"detailed\" \"height\")\n"
889  "\nLists all ProTxs in your wallet or on-chain, depending on the given type.\n"
890  "If \"type\" is not specified, it defaults to \"registered\".\n"
891  "If \"detailed\" is not specified, it defaults to \"false\" and only the hashes of the ProTx will be returned.\n"
892  "If \"height\" is not specified, it defaults to the current chain-tip.\n"
893  "\nAvailable types:\n"
894  " registered - List all ProTx which are registered at the given chain height.\n"
895  " This will also include ProTx which failed PoSe verfication.\n"
896  " valid - List only ProTx which are active/valid at the given chain height.\n"
897 #ifdef ENABLE_WALLET
898  " wallet - List only ProTx which are found in your wallet at the given chain height.\n"
899  " This will also include ProTx which failed PoSe verfication.\n"
900 #endif
901  );
902 }
903 
904 static bool CheckWalletOwnsKey(CWallet* pwallet, const CKeyID& keyID) {
905 #ifndef ENABLE_WALLET
906  return false;
907 #else
908  if (!pwallet) {
909  return false;
910  }
911  return pwallet->HaveKey(keyID);
912 #endif
913 }
914 
915 static bool CheckWalletOwnsScript(CWallet* pwallet, const CScript& script) {
916 #ifndef ENABLE_WALLET
917  return false;
918 #else
919  if (!pwallet) {
920  return false;
921  }
922 
923  CTxDestination dest;
924  if (ExtractDestination(script, dest)) {
925  if ((boost::get<CKeyID>(&dest) && pwallet->HaveKey(*boost::get<CKeyID>(&dest))) || (boost::get<CScriptID>(&dest) && pwallet->HaveCScript(*boost::get<CScriptID>(&dest)))) {
926  return true;
927  }
928  }
929  return false;
930 #endif
931 }
932 
933 UniValue BuildDMNListEntry(CWallet* pwallet, const CDeterministicMNCPtr& dmn, bool detailed)
934 {
935  if (!detailed) {
936  return dmn->proTxHash.ToString();
937  }
938 
940 
941  dmn->ToJson(o);
942 
943  int confirmations = GetUTXOConfirmations(dmn->collateralOutpoint);
944  o.push_back(Pair("confirmations", confirmations));
945 
946  bool hasOwnerKey = CheckWalletOwnsKey(pwallet, dmn->pdmnState->keyIDOwner);
947  bool hasOperatorKey = false; //CheckWalletOwnsKey(dmn->pdmnState->keyIDOperator);
948  bool hasVotingKey = CheckWalletOwnsKey(pwallet, dmn->pdmnState->keyIDVoting);
949 
950  bool ownsCollateral = false;
951  CTransactionRef collateralTx;
952  uint256 tmpHashBlock;
953  if (GetTransaction(dmn->collateralOutpoint.hash, collateralTx, Params().GetConsensus(), tmpHashBlock)) {
954  ownsCollateral = CheckWalletOwnsScript(pwallet, collateralTx->vout[dmn->collateralOutpoint.n].scriptPubKey);
955  }
956 
957 #ifdef ENABLE_WALLET
958  if (pwallet) {
959  UniValue walletObj(UniValue::VOBJ);
960  walletObj.push_back(Pair("hasOwnerKey", hasOwnerKey));
961  walletObj.push_back(Pair("hasOperatorKey", hasOperatorKey));
962  walletObj.push_back(Pair("hasVotingKey", hasVotingKey));
963  walletObj.push_back(Pair("ownsCollateral", ownsCollateral));
964  walletObj.push_back(Pair("ownsPayeeScript", CheckWalletOwnsScript(pwallet, dmn->pdmnState->scriptPayout)));
965  walletObj.push_back(Pair("ownsOperatorRewardScript", CheckWalletOwnsScript(pwallet, dmn->pdmnState->scriptOperatorPayout)));
966  o.push_back(Pair("wallet", walletObj));
967  }
968 #endif
969 
970  auto metaInfo = mmetaman.GetMetaInfo(dmn->proTxHash);
971  o.push_back(Pair("metaInfo", metaInfo->ToJson()));
972 
973  return o;
974 }
975 
977 {
978  if (request.fHelp) {
979  protx_list_help();
980  }
981 
982 #ifdef ENABLE_WALLET
983  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
984 #else
985  CWallet* const pwallet = nullptr;
986 #endif
987 
988  std::string type = "registered";
989  if (!request.params[1].isNull()) {
990  type = request.params[1].get_str();
991  }
992 
994 
995  LOCK(cs_main);
996 
997  if (type == "wallet") {
998  if (!pwallet) {
999  throw std::runtime_error("\"protx list wallet\" not supported when wallet is disabled");
1000  }
1001 #ifdef ENABLE_WALLET
1002  LOCK2(cs_main, pwallet->cs_wallet);
1003 
1004  if (request.params.size() > 4) {
1005  protx_list_help();
1006  }
1007 
1008  bool detailed = !request.params[2].isNull() ? ParseBoolV(request.params[2], "detailed") : false;
1009 
1010  int height = !request.params[3].isNull() ? ParseInt32V(request.params[3], "height") : chainActive.Height();
1011  if (height < 1 || height > chainActive.Height()) {
1012  throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid height specified");
1013  }
1014 
1015  std::vector<COutPoint> vOutpts;
1016  pwallet->ListProTxCoins(vOutpts);
1017  std::set<COutPoint> setOutpts;
1018  for (const auto& outpt : vOutpts) {
1019  setOutpts.emplace(outpt);
1020  }
1021 
1022  CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(chainActive[height]);
1023  mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
1024  if (setOutpts.count(dmn->collateralOutpoint) ||
1025  CheckWalletOwnsKey(pwallet, dmn->pdmnState->keyIDOwner) ||
1026  CheckWalletOwnsKey(pwallet, dmn->pdmnState->keyIDVoting) ||
1027  CheckWalletOwnsScript(pwallet, dmn->pdmnState->scriptPayout) ||
1028  CheckWalletOwnsScript(pwallet, dmn->pdmnState->scriptOperatorPayout)) {
1029  ret.push_back(BuildDMNListEntry(pwallet, dmn, detailed));
1030  }
1031  });
1032 #endif
1033  } else if (type == "valid" || type == "registered") {
1034  if (request.params.size() > 4) {
1035  protx_list_help();
1036  }
1037 
1038  LOCK(cs_main);
1039 
1040  bool detailed = !request.params[2].isNull() ? ParseBoolV(request.params[2], "detailed") : false;
1041 
1042  int height = !request.params[3].isNull() ? ParseInt32V(request.params[3], "height") : chainActive.Height();
1043  if (height < 1 || height > chainActive.Height()) {
1044  throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid height specified");
1045  }
1046 
1047  CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(chainActive[height]);
1048  bool onlyValid = type == "valid";
1049  mnList.ForEachMN(onlyValid, [&](const CDeterministicMNCPtr& dmn) {
1050  ret.push_back(BuildDMNListEntry(pwallet, dmn, detailed));
1051  });
1052  } else {
1053  throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid type specified");
1054  }
1055 
1056  return ret;
1057 }
1058 
1060 {
1061  throw std::runtime_error(
1062  "protx info \"proTxHash\"\n"
1063  "\nReturns detailed information about a deterministic masternode.\n"
1064  "\nArguments:\n"
1065  + GetHelpString(1, "proTxHash") +
1066  "\nResult:\n"
1067  "{ (json object) Details about a specific deterministic masternode\n"
1068  "}\n"
1069  "\nExamples:\n"
1070  + HelpExampleCli("protx", "info \"0123456701234567012345670123456701234567012345670123456701234567\"")
1071  );
1072 }
1073 
1075 {
1076  if (request.fHelp || request.params.size() != 2) {
1077  protx_info_help();
1078  }
1079 
1080 #ifdef ENABLE_WALLET
1081  CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
1082 #else
1083  CWallet* const pwallet = nullptr;
1084 #endif
1085 
1086  uint256 proTxHash = ParseHashV(request.params[1], "proTxHash");
1087  auto mnList = deterministicMNManager->GetListAtChainTip();
1088  auto dmn = mnList.GetMN(proTxHash);
1089  if (!dmn) {
1090  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s not found", proTxHash.ToString()));
1091  }
1092  return BuildDMNListEntry(pwallet, dmn, true);
1093 }
1094 
1096 {
1097  throw std::runtime_error(
1098  "protx diff \"baseBlock\" \"block\"\n"
1099  "\nCalculates a diff between two deterministic masternode lists. The result also contains proof data.\n"
1100  "\nArguments:\n"
1101  "1. \"baseBlock\" (numeric, required) The starting block height.\n"
1102  "2. \"block\" (numeric, required) The ending block height.\n"
1103  );
1104 }
1105 
1106 static uint256 ParseBlock(const UniValue& v, std::string strName)
1107 {
1109 
1110  try {
1111  return ParseHashV(v, strName);
1112  } catch (...) {
1113  int h = ParseInt32V(v, strName);
1114  if (h < 1 || h > chainActive.Height())
1115  throw std::runtime_error(strprintf("%s must be a block hash or chain height and not %s", strName, v.getValStr()));
1116  return *chainActive[h]->phashBlock;
1117  }
1118 }
1119 
1121 {
1122  if (request.fHelp || request.params.size() != 3) {
1123  protx_diff_help();
1124  }
1125 
1126  LOCK(cs_main);
1127  uint256 baseBlockHash = ParseBlock(request.params[1], "baseBlock");
1128  uint256 blockHash = ParseBlock(request.params[2], "block");
1129 
1130  CSimplifiedMNListDiff mnListDiff;
1131  std::string strError;
1132  if (!BuildSimplifiedMNListDiff(baseBlockHash, blockHash, mnListDiff, strError)) {
1133  throw std::runtime_error(strError);
1134  }
1135 
1136  UniValue ret;
1137  mnListDiff.ToJson(ret);
1138  return ret;
1139 }
1140 
1141 [[ noreturn ]] void protx_help()
1142 {
1143  throw std::runtime_error(
1144  "protx \"command\" ...\n"
1145  "Set of commands to execute ProTx related actions.\n"
1146  "To get help on individual commands, use \"help protx command\".\n"
1147  "\nArguments:\n"
1148  "1. \"command\" (string, required) The command to execute\n"
1149  "\nAvailable commands:\n"
1150 #ifdef ENABLE_WALLET
1151  " register - Create and send ProTx to network\n"
1152  " register_fund - Fund, create and send ProTx to network\n"
1153  " register_prepare - Create an unsigned ProTx\n"
1154  " register_submit - Sign and submit a ProTx\n"
1155 #endif
1156  " list - List ProTxs\n"
1157  " info - Return information about a ProTx\n"
1158 #ifdef ENABLE_WALLET
1159  " update_service - Create and send ProUpServTx to network\n"
1160  " update_registrar - Create and send ProUpRegTx to network\n"
1161  " revoke - Create and send ProUpRevTx to network\n"
1162 #endif
1163  " diff - Calculate a diff and a proof between two masternode lists\n"
1164  );
1165 }
1166 
1168 {
1169  if (request.fHelp && request.params.empty()) {
1170  protx_help();
1171  }
1172 
1173  std::string command;
1174  if (!request.params[0].isNull()) {
1175  command = request.params[0].get_str();
1176  }
1177 
1178 #ifdef ENABLE_WALLET
1179  if (command == "register" || command == "register_fund" || command == "register_prepare") {
1180  return protx_register(request);
1181  } else if (command == "register_submit") {
1182  return protx_register_submit(request);
1183  } else if (command == "update_service") {
1184  return protx_update_service(request);
1185  } else if (command == "update_registrar") {
1186  return protx_update_registrar(request);
1187  } else if (command == "revoke") {
1188  return protx_revoke(request);
1189  } else
1190 #endif
1191  if (command == "list") {
1192  return protx_list(request);
1193  } else if (command == "info") {
1194  return protx_info(request);
1195  } else if (command == "diff") {
1196  return protx_diff(request);
1197  } else {
1198  protx_help();
1199  }
1200 }
1201 
1203 {
1204  throw std::runtime_error(
1205  "bls generate\n"
1206  "\nReturns a BLS secret/public key pair.\n"
1207  "\nResult:\n"
1208  "{\n"
1209  " \"secret\": \"xxxx\", (string) BLS secret key\n"
1210  " \"public\": \"xxxx\", (string) BLS public key\n"
1211  "}\n"
1212  "\nExamples:\n"
1213  + HelpExampleCli("bls generate", "")
1214  );
1215 }
1216 
1218 {
1219  if (request.fHelp || request.params.size() != 1) {
1221  }
1222 
1223  CBLSSecretKey sk;
1224  sk.MakeNewKey();
1225 
1226  UniValue ret(UniValue::VOBJ);
1227  ret.push_back(Pair("secret", sk.ToString()));
1228  ret.push_back(Pair("public", sk.GetPublicKey().ToString()));
1229  return ret;
1230 }
1231 
1233 {
1234  throw std::runtime_error(
1235  "bls fromsecret \"secret\"\n"
1236  "\nParses a BLS secret key and returns the secret/public key pair.\n"
1237  "\nArguments:\n"
1238  "1. \"secret\" (string, required) The BLS secret key\n"
1239  "\nResult:\n"
1240  "{\n"
1241  " \"secret\": \"xxxx\", (string) BLS secret key\n"
1242  " \"public\": \"xxxx\", (string) BLS public key\n"
1243  "}\n"
1244  "\nExamples:\n"
1245  + HelpExampleCli("bls fromsecret", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
1246  );
1247 }
1248 
1250 {
1251  if (request.fHelp || request.params.size() != 2) {
1253  }
1254 
1255  CBLSSecretKey sk;
1256  if (!sk.SetHexStr(request.params[1].get_str())) {
1257  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Secret key must be a valid hex string of length %d", sk.SerSize*2));
1258  }
1259 
1260  UniValue ret(UniValue::VOBJ);
1261  ret.push_back(Pair("secret", sk.ToString()));
1262  ret.push_back(Pair("public", sk.GetPublicKey().ToString()));
1263  return ret;
1264 }
1265 
1266 [[ noreturn ]] void bls_help()
1267 {
1268  throw std::runtime_error(
1269  "bls \"command\" ...\n"
1270  "Set of commands to execute BLS related actions.\n"
1271  "To get help on individual commands, use \"help bls command\".\n"
1272  "\nArguments:\n"
1273  "1. \"command\" (string, required) The command to execute\n"
1274  "\nAvailable commands:\n"
1275  " generate - Create a BLS secret/public key pair\n"
1276  " fromsecret - Parse a BLS secret key and return the secret/public key pair\n"
1277  );
1278 }
1279 
1281 {
1282  if (request.fHelp && request.params.empty()) {
1283  bls_help();
1284  }
1285 
1286  std::string command;
1287  if (!request.params[0].isNull()) {
1288  command = request.params[0].get_str();
1289  }
1290 
1291  if (command == "generate") {
1292  return bls_generate(request);
1293  } else if (command == "fromsecret") {
1294  return bls_fromsecret(request);
1295  } else {
1296  bls_help();
1297  }
1298 }
1299 
1300 static const CRPCCommand commands[] =
1301 { // category name actor (function)
1302  // --------------------- ------------------------ -----------------------
1303  { "evo", "bls", &_bls, {} },
1304  { "evo", "protx", &protx, {} },
1305 };
1306 
1308 {
1309  for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
1310  tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
1311  }
1312 }
bool GetTxPayload(const std::vector< unsigned char > &payload, T &obj)
Definition: specialtx.h:21
CTxMemPool mempool
uint256 proTxHash
Definition: providertx.h:142
void bls_fromsecret_help()
Definition: rpcevo.cpp:1232
uint256 proTxHash
Definition: providertx.h:95
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:80
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
static uint256 ParseBlock(const UniValue &v, std::string strName)
Definition: rpcevo.cpp:1106
CKeyID keyIDVoting
Definition: providertx.h:145
std::vector< unsigned char > DecodeBase64(const char *p, bool *pfInvalid)
bool BuildSimplifiedMNListDiff(const uint256 &baseBlockHash, const uint256 &blockHash, CSimplifiedMNListDiff &mnListDiffRet, std::string &errorRet)
bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus::Params &consensusParams, uint256 &hashBlock, bool fAllowSlow, CBlockIndex *blockIndex)
Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock...
Definition: validation.cpp:950
Dash RPC command dispatcher.
Definition: server.h:140
static const uint16_t CURRENT_VERSION
Definition: providertx.h:138
CScript scriptPubKey
Definition: transaction.h:148
std::vector< unsigned char > vchSig
Definition: providertx.h:36
void ToJson(UniValue &obj) const
COutPoint collateralOutpoint
Definition: providertx.h:28
CKey GetKey()
Definition: base58.cpp:304
A UTXO entry.
Definition: coins.h:29
void protx_list_help()
Definition: rpcevo.cpp:885
CCriticalSection cs_wallet
Definition: wallet.h:836
UniValue protx_list(const JSONRPCRequest &request)
Definition: rpcevo.cpp:976
#define strprintf
Definition: tinyformat.h:1066
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:179
int32_t ParseInt32V(const UniValue &v, const std::string &strName)
Definition: server.cpp:152
bool EnsureWalletIsAvailable(CWallet *const pwallet, bool avoidException)
Definition: rpcwallet.cpp:66
std::vector< CTxIn > vin
Definition: transaction.h:293
static const CAmount COIN
Definition: amount.h:14
bool HaveCScript(const CScriptID &hash) const override
Definition: keystore.cpp:74
bool SetHexStr(const std::string &str)
Definition: bls.h:157
static bool SignHash(const uint256 &hash, const CKey &key, std::vector< unsigned char > &vchSigRet)
Sign the hash, returns true if successful.
int Height() const
Return the maximal height in the chain.
Definition: chain.h:484
CCriticalSection cs_main
Definition: validation.cpp:213
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:281
CTxOut out
unspent transaction output
Definition: coins.h:33
uint256 CalcTxInputsHash(const CTransaction &tx)
Definition: specialtx.cpp:174
CTxDestination DecodeDestination(const std::string &str)
Definition: base58.cpp:336
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
CScript scriptOperatorPayout
Definition: providertx.h:97
bool HasSelected() const
Definition: coincontrol.h:71
CKeyID keyIDVoting
Definition: providertx.h:32
UniValue protx(const JSONRPCRequest &request)
Definition: rpcevo.cpp:1167
const std::string & get_str() const
bool fRequireAllInputs
If false, only include as many inputs as necessary to fulfill a coin selection request. Only usable together with fAllowOtherInputs.
Definition: coincontrol.h:35
UniValue bls_fromsecret(const JSONRPCRequest &request)
Definition: rpcevo.cpp:1249
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
void bls_generate_help()
Definition: rpcevo.cpp:1202
CBLSPublicKey pubKeyOperator
Definition: providertx.h:144
static const uint16_t CURRENT_VERSION
Definition: providertx.h:91
UniValue protx_diff(const JSONRPCRequest &request)
Definition: rpcevo.cpp:1120
void ForEachMN(bool onlyValid, Callback &&cb) const
static CKeyID ParsePubKeyIDFromAddress(const std::string &strAddress, const std::string &paramName)
Definition: rpcevo.cpp:149
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:345
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
const std::string & getValStr() const
Definition: univalue.h:66
bool appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:353
void MakeNewKey()
Definition: bls.cpp:102
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:90
void BlockUntilSyncedToCurrentChain()
Blocks until the wallet state is up-to-date to /at least/ the current chain at the time this function...
Definition: wallet.cpp:1517
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:149
UniValue BuildDMNListEntry(CWallet *pwallet, const CDeterministicMNCPtr &dmn, bool detailed)
Definition: rpcevo.cpp:933
bool IsNull() const
Definition: uint256.h:33
std::string HelpRequiringPassphrase(CWallet *const pwallet)
Definition: rpcwallet.cpp:59
Coin Control Features.
Definition: coincontrol.h:28
Invalid, missing or duplicate parameter.
Definition: protocol.h:53
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: server.cpp:121
bool SetString(const char *pszSecret)
Definition: base58.cpp:319
CMasternodeMetaMan mmetaman
static bool SignMessage(const std::string &strMessage, std::vector< unsigned char > &vchSigRet, const CKey &key)
Sign the message, returns true if successful.
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
std::string GetHelpString(int nParamNum, std::string strParamName)
Definition: rpcevo.cpp:38
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object&#39;s serialization.
Definition: hash.h:254
bool GetUTXOCoin(const COutPoint &outpoint, Coin &coin)
Definition: validation.cpp:439
#define LOCK2(cs1, cs2)
Definition: sync.h:179
CRPCTable tableRPC
Definition: server.cpp:616
void bls_help()
Definition: rpcevo.cpp:1266
void push_back(const T &value)
Definition: prevector.h:455
void protx_diff_help()
Definition: rpcevo.cpp:1095
static const size_t SerSize
Definition: bls.h:51
static bool CheckWalletOwnsScript(CWallet *pwallet, const CScript &script)
Definition: rpcevo.cpp:915
void protx_help()
Definition: rpcevo.cpp:1141
CScript scriptPubKey
Definition: wallet.h:169
bool push_back(const UniValue &val)
Definition: univalue.cpp:110
UniValue protx_info(const JSONRPCRequest &request)
Definition: rpcevo.cpp:1074
static CBLSPublicKey ParseBLSPubKey(const std::string &hexKey, const std::string &paramName)
Definition: rpcevo.cpp:159
CTransactionRef tx
Definition: wallet.h:210
UniValue params
Definition: server.h:42
std::string ToString() const
Definition: bls.h:210
#define LOCK(cs)
Definition: sync.h:178
const char * name
Definition: rest.cpp:36
A base58-encoded secret key.
Definition: base58.h:101
bool GetKey(const CKeyID &address, CKey &keyOut) const override
GetKey implementation that can derive a HD private key on the fly.
Definition: wallet.cpp:300
void ListProTxCoins(std::vector< COutPoint > &vOutpts)
Definition: wallet.cpp:4838
CService addr
Definition: providertx.h:96
static const uint16_t CURRENT_VERSION
Definition: providertx.h:22
CTxDestination destChange
Definition: coincontrol.h:31
void Select(const COutPoint &output)
Definition: coincontrol.h:81
bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
Parse number as fixed point according to JSON number syntax.
std::string MakeSignString() const
Definition: providertx.cpp:398
uint32_t n
Definition: transaction.h:30
CKeyID keyIDOwner
Definition: providertx.h:30
void RegisterEvoRPCCommands(CRPCTable &tableRPC)
Register Evo RPC commands.
Definition: rpcevo.cpp:1307
uint16_t nVersion
Definition: providertx.h:25
bool empty() const
Definition: univalue.h:67
int GetDefaultPort() const
Definition: chainparams.h:56
An output of a transaction.
Definition: transaction.h:144
std::string ToString() const
Definition: uint256.cpp:62
Invalid address or key.
Definition: protocol.h:51
static CBLSSecretKey ParseBLSSecretKey(const std::string &hexKey, const std::string &paramName)
Definition: rpcevo.cpp:168
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:256
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: server.cpp:578
CScript scriptPayout
Definition: providertx.h:34
static std::pair< std::string, UniValue > Pair(const char *cKey, const char *cVal)
Definition: univalue.h:185
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
std::vector< CTxOut > vout
Definition: transaction.h:294
CScript scriptPayout
Definition: providertx.h:146
bool isNull() const
Definition: univalue.h:78
void LockCoin(const COutPoint &output)
Definition: wallet.cpp:4792
UniValue bls_generate(const JSONRPCRequest &request)
Definition: rpcevo.cpp:1217
CCriticalSection cs
Definition: txmempool.h:488
void AvailableCoins(std::vector< COutput > &vCoins, bool fOnlySafe=true, const CCoinControl *coinControl=nullptr, const CAmount &nMinimumAmount=1, const CAmount &nMaximumAmount=MAX_MONEY, const CAmount &nMinimumSumAmount=MAX_MONEY, const uint64_t nMaximumCount=0, const int nMinDepth=0, const int nMaxDepth=9999999) const
populate vCoins with vector of available COutputs.
Definition: wallet.cpp:2775
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:280
static const CRPCCommand commands[]
Definition: rpcevo.cpp:1300
uint16_t nOperatorReward
Definition: providertx.h:33
std::vector< uint8_t > vExtraPayload
Definition: transaction.h:298
bool fHelp
Definition: server.h:43
Capture information about block/transaction validation.
Definition: validation.h:22
256-bit opaque blob.
Definition: uint256.h:123
std::string EncodeHexTx(const CTransaction &tx)
Definition: core_write.cpp:130
UniValue _bls(const JSONRPCRequest &request)
Definition: rpcevo.cpp:1280
std::string FormatStateMessage(const CValidationState &state)
Convert CValidationState to a human-readable message for logging.
Definition: validation.cpp:513
bool IsValid() const
Definition: base58.cpp:312
static const uint16_t CURRENT_VERSION
Definition: providertx.h:190
#define ARRAYLEN(array)
bool setArray()
Definition: univalue.cpp:96
std::string EncodeDestination(const CTxDestination &dest)
Definition: base58.cpp:329
A key allocated from the key pool.
Definition: wallet.h:1273
const CChainParams & Params()
Return the currently selected parameters.
UniValue sendrawtransaction(const JSONRPCRequest &request)
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:389
void protx_info_help()
Definition: rpcevo.cpp:1059
int GetUTXOConfirmations(const COutPoint &outpoint)
Definition: validation.cpp:456
std::vector< unsigned char > vchSig
Definition: providertx.h:148
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:14
bool Lookup(const char *pszName, std::vector< CService > &vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
Definition: netbase.cpp:140
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:20
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:453
CBLSPublicKey GetPublicKey() const
Definition: bls.cpp:147
bool CreateTransaction(const std::vector< CRecipient > &vecSend, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRet, int &nChangePosInOut, std::string &strFailReason, const CCoinControl &coin_control, bool sign=true, int nExtraPayloadSize=0)
Create a new transaction paying the recipients with a set of coins selected by SelectCoins(); Also cr...
Definition: wallet.cpp:3658
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:715
const UniValue NullUniValue
Definition: univalue.cpp:15
CWallet * GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:45
bool ParseBoolV(const UniValue &v, const std::string &strName)
Definition: server.cpp:179
uint16_t nVersion
Definition: providertx.h:94
uint16_t nReason
Definition: providertx.h:204
void ObserveSafeMode()
Definition: safemode.cpp:7
A mutable version of CTransaction.
Definition: transaction.h:291
static CKey ParsePrivKey(CWallet *pwallet, const std::string &strKeyOrAddress, bool allowAddresses=true)
Definition: rpcevo.cpp:124
UniValue signrawtransaction(const JSONRPCRequest &request)
UniValue JSONRPCError(int code, const std::string &message)
Definition: protocol.cpp:54
size_t size() const
Definition: univalue.h:69
An encapsulated private key.
Definition: key.h:27
uint16_t nVersion
Definition: providertx.h:202
CChain & chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:217
AssertLockHeld(g_cs_orphans)
uint16_t nVersion
Definition: providertx.h:141
void SetTxPayload(CMutableTransaction &tx, const T &payload)
Definition: specialtx.h:43
CBLSPublicKey pubKeyOperator
Definition: providertx.h:31
static bool CheckWalletOwnsKey(CWallet *pwallet, const CKeyID &keyID)
Definition: rpcevo.cpp:904
CMasternodeMetaInfoPtr GetMetaInfo(const uint256 &proTxHash, bool fCreate=true)
uint256 proTxHash
Definition: providertx.h:203
bool HaveKey(const CKeyID &address) const override
HaveKey implementation that also checks the mapHdPubKeys.
Definition: wallet.cpp:328
bool CheckSpecialTx(const CTransaction &tx, const CBlockIndex *pindexPrev, CValidationState &state)
Definition: specialtx.cpp:20
void EnsureWalletIsUnlocked(CWallet *const pwallet)
Definition: rpcwallet.cpp:83
CBLSSignature Sign(const uint256 &hash) const
Definition: bls.cpp:160
CService addr
Definition: providertx.h:29
std::string ToStringShort() const
Definition: transaction.cpp:17
Released under the MIT license